mirror of
https://github.com/withastro/astro.git
synced 2025-02-03 22:29:08 -05:00
Refactor MDX transformJSX handling (#10688)
This commit is contained in:
parent
4ea042c388
commit
799f6f3f29
10 changed files with 199 additions and 217 deletions
5
.changeset/four-pants-juggle.md
Normal file
5
.changeset/four-pants-juggle.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
"astro": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Marks renderer `jsxImportSource` and `jsxTransformOptions` options as deprecated as they are no longer used since Astro 3.0
|
|
@ -2577,9 +2577,9 @@ export interface AstroRenderer {
|
||||||
clientEntrypoint?: string;
|
clientEntrypoint?: string;
|
||||||
/** Import entrypoint for the server/build/ssr renderer. */
|
/** Import entrypoint for the server/build/ssr renderer. */
|
||||||
serverEntrypoint: string;
|
serverEntrypoint: string;
|
||||||
/** JSX identifier (e.g. 'react' or 'solid-js') */
|
/** @deprecated Vite plugins should transform the JSX instead */
|
||||||
jsxImportSource?: string;
|
jsxImportSource?: string;
|
||||||
/** Babel transform options */
|
/** @deprecated Vite plugins should transform the JSX instead */
|
||||||
jsxTransformOptions?: JSXTransformFn;
|
jsxTransformOptions?: JSXTransformFn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -137,7 +137,7 @@ export async function createVite(
|
||||||
envVitePlugin({ settings }),
|
envVitePlugin({ settings }),
|
||||||
markdownVitePlugin({ settings, logger }),
|
markdownVitePlugin({ settings, logger }),
|
||||||
htmlVitePlugin(),
|
htmlVitePlugin(),
|
||||||
mdxVitePlugin({ settings, logger }),
|
mdxVitePlugin(),
|
||||||
astroPostprocessVitePlugin(),
|
astroPostprocessVitePlugin(),
|
||||||
astroIntegrationsContainerPlugin({ settings, logger }),
|
astroIntegrationsContainerPlugin({ settings, logger }),
|
||||||
astroScriptsPageSSRPlugin({ settings }),
|
astroScriptsPageSSRPlugin({ settings }),
|
||||||
|
|
|
@ -1,19 +1,11 @@
|
||||||
const renderer = {
|
import type { AstroRenderer } from '../@types/astro.js';
|
||||||
|
import { jsxTransformOptions } from './transform-options.js';
|
||||||
|
|
||||||
|
const renderer: AstroRenderer = {
|
||||||
name: 'astro:jsx',
|
name: 'astro:jsx',
|
||||||
serverEntrypoint: 'astro/jsx/server.js',
|
serverEntrypoint: 'astro/jsx/server.js',
|
||||||
jsxImportSource: 'astro',
|
jsxImportSource: 'astro',
|
||||||
jsxTransformOptions: async () => {
|
jsxTransformOptions,
|
||||||
// @ts-expect-error types not found
|
|
||||||
const plugin = await import('@babel/plugin-transform-react-jsx');
|
|
||||||
const jsx = plugin.default?.default ?? plugin.default;
|
|
||||||
const { default: astroJSX } = await import('./babel.js');
|
|
||||||
return {
|
|
||||||
plugins: [
|
|
||||||
astroJSX(),
|
|
||||||
jsx({}, { throwIfNamespace: false, runtime: 'automatic', importSource: 'astro' }),
|
|
||||||
],
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default renderer;
|
export default renderer;
|
||||||
|
|
14
packages/astro/src/jsx/transform-options.ts
Normal file
14
packages/astro/src/jsx/transform-options.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import type { JSXTransformConfig } from '../@types/astro.js';
|
||||||
|
|
||||||
|
export async function jsxTransformOptions(): Promise<JSXTransformConfig> {
|
||||||
|
// @ts-expect-error types not found
|
||||||
|
const plugin = await import('@babel/plugin-transform-react-jsx');
|
||||||
|
const jsx = plugin.default?.default ?? plugin.default;
|
||||||
|
const { default: astroJSX } = await import('./babel.js');
|
||||||
|
return {
|
||||||
|
plugins: [
|
||||||
|
astroJSX(),
|
||||||
|
jsx({}, { throwIfNamespace: false, runtime: 'automatic', importSource: 'astro' }),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,3 +1,3 @@
|
||||||
# vite-plugin-jsx
|
# vite-plugin-mdx
|
||||||
|
|
||||||
Modifies Vite’s built-in JSX behavior to allow for React, Preact, and Solid.js to coexist and all use `.jsx` and `.tsx` extensions.
|
Handles transforming MDX via the `astro:jsx` renderer.
|
||||||
|
|
|
@ -1,99 +1,19 @@
|
||||||
import type { TransformResult } from 'rollup';
|
import { type Plugin, transformWithEsbuild } from 'vite';
|
||||||
import { type Plugin, type ResolvedConfig, transformWithEsbuild } from 'vite';
|
|
||||||
import type { AstroRenderer, AstroSettings } from '../@types/astro.js';
|
|
||||||
import type { Logger } from '../core/logger/core.js';
|
|
||||||
import type { PluginMetadata } from '../vite-plugin-astro/types.js';
|
|
||||||
|
|
||||||
import babel from '@babel/core';
|
|
||||||
import { CONTENT_FLAG, PROPAGATED_ASSET_FLAG } from '../content/index.js';
|
import { CONTENT_FLAG, PROPAGATED_ASSET_FLAG } from '../content/index.js';
|
||||||
import { astroEntryPrefix } from '../core/build/plugins/plugin-component-entry.js';
|
import { astroEntryPrefix } from '../core/build/plugins/plugin-component-entry.js';
|
||||||
import { removeQueryString } from '../core/path.js';
|
import { removeQueryString } from '../core/path.js';
|
||||||
import tagExportsPlugin from './tag.js';
|
import { transformJSX } from './transform-jsx.js';
|
||||||
|
|
||||||
interface TransformJSXOptions {
|
|
||||||
code: string;
|
|
||||||
id: string;
|
|
||||||
mode: string;
|
|
||||||
renderer: AstroRenderer;
|
|
||||||
ssr: boolean;
|
|
||||||
root: URL;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function transformJSX({
|
|
||||||
code,
|
|
||||||
mode,
|
|
||||||
id,
|
|
||||||
ssr,
|
|
||||||
renderer,
|
|
||||||
root,
|
|
||||||
}: TransformJSXOptions): Promise<TransformResult> {
|
|
||||||
const { jsxTransformOptions } = renderer;
|
|
||||||
const options = await jsxTransformOptions!({ mode, ssr });
|
|
||||||
const plugins = [...(options.plugins || [])];
|
|
||||||
if (ssr) {
|
|
||||||
plugins.push(await tagExportsPlugin({ rendererName: renderer.name, root }));
|
|
||||||
}
|
|
||||||
const result = await babel.transformAsync(code, {
|
|
||||||
presets: options.presets,
|
|
||||||
plugins,
|
|
||||||
cwd: process.cwd(),
|
|
||||||
filename: id,
|
|
||||||
ast: false,
|
|
||||||
compact: false,
|
|
||||||
sourceMaps: true,
|
|
||||||
configFile: false,
|
|
||||||
babelrc: false,
|
|
||||||
inputSourceMap: options.inputSourceMap,
|
|
||||||
});
|
|
||||||
// TODO: Be more strict about bad return values here.
|
|
||||||
// Should we throw an error instead? Should we never return `{code: ""}`?
|
|
||||||
if (!result) return null;
|
|
||||||
|
|
||||||
if (renderer.name === 'astro:jsx') {
|
|
||||||
const { astro } = result.metadata as unknown as PluginMetadata;
|
|
||||||
return {
|
|
||||||
code: result.code || '',
|
|
||||||
map: result.map,
|
|
||||||
meta: {
|
|
||||||
astro,
|
|
||||||
vite: {
|
|
||||||
// Setting this vite metadata to `ts` causes Vite to resolve .js
|
|
||||||
// extensions to .ts files.
|
|
||||||
lang: 'ts',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
code: result.code || '',
|
|
||||||
map: result.map,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
interface AstroPluginJSXOptions {
|
|
||||||
settings: AstroSettings;
|
|
||||||
logger: Logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format inspired by https://github.com/vitejs/vite/blob/main/packages/vite/src/node/constants.ts#L54
|
// Format inspired by https://github.com/vitejs/vite/blob/main/packages/vite/src/node/constants.ts#L54
|
||||||
const SPECIAL_QUERY_REGEX = new RegExp(
|
const SPECIAL_QUERY_REGEX = new RegExp(
|
||||||
`[?&](?:worker|sharedworker|raw|url|${CONTENT_FLAG}|${PROPAGATED_ASSET_FLAG})\\b`
|
`[?&](?:worker|sharedworker|raw|url|${CONTENT_FLAG}|${PROPAGATED_ASSET_FLAG})\\b`
|
||||||
);
|
);
|
||||||
|
|
||||||
/** Use Astro config to allow for alternate or multiple JSX renderers (by default Vite will assume React) */
|
// TODO: Move this Vite plugin into `@astrojs/mdx` in Astro 5
|
||||||
export default function mdxVitePlugin({ settings }: AstroPluginJSXOptions): Plugin {
|
export default function mdxVitePlugin(): Plugin {
|
||||||
let viteConfig: ResolvedConfig;
|
|
||||||
// A reference to Astro's internal JSX renderer.
|
|
||||||
let astroJSXRenderer: AstroRenderer;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: 'astro:jsx',
|
name: 'astro:jsx',
|
||||||
enforce: 'pre', // run transforms before other plugins
|
enforce: 'pre', // run transforms before other plugins
|
||||||
async configResolved(resolvedConfig) {
|
|
||||||
viteConfig = resolvedConfig;
|
|
||||||
astroJSXRenderer = settings.renderers.find((r) => r.jsxImportSource === 'astro')!;
|
|
||||||
},
|
|
||||||
async transform(code, id, opts) {
|
async transform(code, id, opts) {
|
||||||
// Skip special queries and astro entries. We skip astro entries here as we know it doesn't contain
|
// Skip special queries and astro entries. We skip astro entries here as we know it doesn't contain
|
||||||
// JSX code, and also because we can't detect the import source to apply JSX transforms.
|
// JSX code, and also because we can't detect the import source to apply JSX transforms.
|
||||||
|
@ -117,14 +37,7 @@ export default function mdxVitePlugin({ settings }: AstroPluginJSXOptions): Plug
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
return transformJSX({
|
return await transformJSX(jsxCode, id, opts?.ssr);
|
||||||
code: jsxCode,
|
|
||||||
id,
|
|
||||||
renderer: astroJSXRenderer,
|
|
||||||
mode: viteConfig.mode,
|
|
||||||
ssr: Boolean(opts?.ssr),
|
|
||||||
root: settings.config.root,
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
import type { PluginObj } from '@babel/core';
|
import type { PluginObj } from '@babel/core';
|
||||||
import * as t from '@babel/types';
|
import * as t from '@babel/types';
|
||||||
|
import astroJsxRenderer from '../jsx/renderer.js';
|
||||||
|
|
||||||
|
const rendererName = astroJsxRenderer.name;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This plugin handles every file that runs through our JSX plugin.
|
* This plugin handles every file that runs through our JSX plugin.
|
||||||
|
@ -9,115 +12,100 @@ import * as t from '@babel/types';
|
||||||
* This plugin crawls each export in the file and "tags" each export with a given `rendererName`.
|
* This plugin crawls each export in the file and "tags" each export with a given `rendererName`.
|
||||||
* This allows us to automatically match a component to a renderer and skip the usual `check()` calls.
|
* This allows us to automatically match a component to a renderer and skip the usual `check()` calls.
|
||||||
*/
|
*/
|
||||||
export default async function tagExportsWithRenderer({
|
export const tagExportsPlugin: PluginObj = {
|
||||||
rendererName,
|
visitor: {
|
||||||
}: {
|
Program: {
|
||||||
rendererName: string;
|
// Inject `import { __astro_tag_component__ } from 'astro/runtime/server/index.js'`
|
||||||
root: URL;
|
enter(path) {
|
||||||
}): Promise<PluginObj> {
|
path.node.body.splice(
|
||||||
return {
|
0,
|
||||||
visitor: {
|
0,
|
||||||
Program: {
|
t.importDeclaration(
|
||||||
// Inject `import { __astro_tag_component__ } from 'astro/runtime/server/index.js'`
|
[
|
||||||
enter(path) {
|
t.importSpecifier(
|
||||||
path.node.body.splice(
|
t.identifier('__astro_tag_component__'),
|
||||||
0,
|
t.identifier('__astro_tag_component__')
|
||||||
0,
|
),
|
||||||
t.importDeclaration(
|
],
|
||||||
[
|
t.stringLiteral('astro/runtime/server/index.js')
|
||||||
t.importSpecifier(
|
)
|
||||||
t.identifier('__astro_tag_component__'),
|
);
|
||||||
t.identifier('__astro_tag_component__')
|
|
||||||
),
|
|
||||||
],
|
|
||||||
t.stringLiteral('astro/runtime/server/index.js')
|
|
||||||
)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
// For each export we found, inject `__astro_tag_component__(exportName, rendererName)`
|
|
||||||
exit(path, state) {
|
|
||||||
const exportedIds = state.get('astro:tags');
|
|
||||||
if (exportedIds) {
|
|
||||||
for (const id of exportedIds) {
|
|
||||||
path.node.body.push(
|
|
||||||
t.expressionStatement(
|
|
||||||
t.callExpression(t.identifier('__astro_tag_component__'), [
|
|
||||||
t.identifier(id),
|
|
||||||
t.stringLiteral(rendererName),
|
|
||||||
])
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
ExportDeclaration: {
|
// For each export we found, inject `__astro_tag_component__(exportName, rendererName)`
|
||||||
/**
|
exit(path, state) {
|
||||||
* For default anonymous function export, we need to give them a unique name
|
const exportedIds = state.get('astro:tags');
|
||||||
* @param path
|
if (exportedIds) {
|
||||||
* @returns
|
for (const id of exportedIds) {
|
||||||
*/
|
path.node.body.push(
|
||||||
enter(path) {
|
t.expressionStatement(
|
||||||
const node = path.node;
|
t.callExpression(t.identifier('__astro_tag_component__'), [
|
||||||
if (!t.isExportDefaultDeclaration(node)) return;
|
t.identifier(id),
|
||||||
|
t.stringLiteral(rendererName),
|
||||||
if (
|
])
|
||||||
t.isArrowFunctionExpression(node.declaration) ||
|
)
|
||||||
t.isCallExpression(node.declaration)
|
|
||||||
) {
|
|
||||||
const varName = t.isArrowFunctionExpression(node.declaration)
|
|
||||||
? '_arrow_function'
|
|
||||||
: '_hoc_function';
|
|
||||||
const uidIdentifier = path.scope.generateUidIdentifier(varName);
|
|
||||||
path.insertBefore(
|
|
||||||
t.variableDeclaration('const', [
|
|
||||||
t.variableDeclarator(uidIdentifier, node.declaration),
|
|
||||||
])
|
|
||||||
);
|
);
|
||||||
node.declaration = uidIdentifier;
|
|
||||||
} else if (t.isFunctionDeclaration(node.declaration) && !node.declaration.id?.name) {
|
|
||||||
const uidIdentifier = path.scope.generateUidIdentifier('_function');
|
|
||||||
node.declaration.id = uidIdentifier;
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
exit(path, state) {
|
|
||||||
const node = path.node;
|
|
||||||
if (node.exportKind === 'type') return;
|
|
||||||
if (t.isExportAllDeclaration(node)) return;
|
|
||||||
const addTag = (id: string) => {
|
|
||||||
const tags = state.get('astro:tags') ?? [];
|
|
||||||
state.set('astro:tags', [...tags, id]);
|
|
||||||
};
|
|
||||||
if (t.isExportNamedDeclaration(node) || t.isExportDefaultDeclaration(node)) {
|
|
||||||
if (t.isIdentifier(node.declaration)) {
|
|
||||||
addTag(node.declaration.name);
|
|
||||||
} else if (t.isFunctionDeclaration(node.declaration) && node.declaration.id?.name) {
|
|
||||||
addTag(node.declaration.id.name);
|
|
||||||
} else if (t.isVariableDeclaration(node.declaration)) {
|
|
||||||
node.declaration.declarations?.forEach((declaration) => {
|
|
||||||
if (
|
|
||||||
t.isArrowFunctionExpression(declaration.init) &&
|
|
||||||
t.isIdentifier(declaration.id)
|
|
||||||
) {
|
|
||||||
addTag(declaration.id.name);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else if (t.isObjectExpression(node.declaration)) {
|
|
||||||
node.declaration.properties?.forEach((property) => {
|
|
||||||
if (t.isProperty(property) && t.isIdentifier(property.key)) {
|
|
||||||
addTag(property.key.name);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else if (t.isExportNamedDeclaration(node) && !node.source) {
|
|
||||||
node.specifiers.forEach((specifier) => {
|
|
||||||
if (t.isExportSpecifier(specifier) && t.isIdentifier(specifier.exported)) {
|
|
||||||
addTag(specifier.local.name);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
ExportDeclaration: {
|
||||||
}
|
/**
|
||||||
|
* For default anonymous function export, we need to give them a unique name
|
||||||
|
* @param path
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
enter(path) {
|
||||||
|
const node = path.node;
|
||||||
|
if (!t.isExportDefaultDeclaration(node)) return;
|
||||||
|
|
||||||
|
if (t.isArrowFunctionExpression(node.declaration) || t.isCallExpression(node.declaration)) {
|
||||||
|
const varName = t.isArrowFunctionExpression(node.declaration)
|
||||||
|
? '_arrow_function'
|
||||||
|
: '_hoc_function';
|
||||||
|
const uidIdentifier = path.scope.generateUidIdentifier(varName);
|
||||||
|
path.insertBefore(
|
||||||
|
t.variableDeclaration('const', [t.variableDeclarator(uidIdentifier, node.declaration)])
|
||||||
|
);
|
||||||
|
node.declaration = uidIdentifier;
|
||||||
|
} else if (t.isFunctionDeclaration(node.declaration) && !node.declaration.id?.name) {
|
||||||
|
const uidIdentifier = path.scope.generateUidIdentifier('_function');
|
||||||
|
node.declaration.id = uidIdentifier;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
exit(path, state) {
|
||||||
|
const node = path.node;
|
||||||
|
if (node.exportKind === 'type') return;
|
||||||
|
if (t.isExportAllDeclaration(node)) return;
|
||||||
|
const addTag = (id: string) => {
|
||||||
|
const tags = state.get('astro:tags') ?? [];
|
||||||
|
state.set('astro:tags', [...tags, id]);
|
||||||
|
};
|
||||||
|
if (t.isExportNamedDeclaration(node) || t.isExportDefaultDeclaration(node)) {
|
||||||
|
if (t.isIdentifier(node.declaration)) {
|
||||||
|
addTag(node.declaration.name);
|
||||||
|
} else if (t.isFunctionDeclaration(node.declaration) && node.declaration.id?.name) {
|
||||||
|
addTag(node.declaration.id.name);
|
||||||
|
} else if (t.isVariableDeclaration(node.declaration)) {
|
||||||
|
node.declaration.declarations?.forEach((declaration) => {
|
||||||
|
if (t.isArrowFunctionExpression(declaration.init) && t.isIdentifier(declaration.id)) {
|
||||||
|
addTag(declaration.id.name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (t.isObjectExpression(node.declaration)) {
|
||||||
|
node.declaration.properties?.forEach((property) => {
|
||||||
|
if (t.isProperty(property) && t.isIdentifier(property.key)) {
|
||||||
|
addTag(property.key.name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (t.isExportNamedDeclaration(node) && !node.source) {
|
||||||
|
node.specifiers.forEach((specifier) => {
|
||||||
|
if (t.isExportSpecifier(specifier) && t.isIdentifier(specifier.exported)) {
|
||||||
|
addTag(specifier.local.name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
69
packages/astro/src/vite-plugin-mdx/transform-jsx.ts
Normal file
69
packages/astro/src/vite-plugin-mdx/transform-jsx.ts
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
import babel from '@babel/core';
|
||||||
|
import type { TransformResult } from 'rollup';
|
||||||
|
import type { JSXTransformConfig } from '../@types/astro.js';
|
||||||
|
import { jsxTransformOptions } from '../jsx/transform-options.js';
|
||||||
|
import type { PluginMetadata } from '../vite-plugin-astro/types.js';
|
||||||
|
import { tagExportsPlugin } from './tag.js';
|
||||||
|
|
||||||
|
export async function transformJSX(
|
||||||
|
code: string,
|
||||||
|
id: string,
|
||||||
|
ssr?: boolean
|
||||||
|
): Promise<TransformResult> {
|
||||||
|
const options = await getJsxTransformOptions();
|
||||||
|
const plugins = ssr ? [...(options.plugins ?? []), tagExportsPlugin] : options.plugins;
|
||||||
|
|
||||||
|
const result = await babel.transformAsync(code, {
|
||||||
|
presets: options.presets,
|
||||||
|
plugins,
|
||||||
|
cwd: process.cwd(),
|
||||||
|
filename: id,
|
||||||
|
ast: false,
|
||||||
|
compact: false,
|
||||||
|
sourceMaps: true,
|
||||||
|
configFile: false,
|
||||||
|
babelrc: false,
|
||||||
|
browserslistConfigFile: false,
|
||||||
|
inputSourceMap: options.inputSourceMap,
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: Be more strict about bad return values here.
|
||||||
|
// Should we throw an error instead? Should we never return `{code: ""}`?
|
||||||
|
if (!result) return null;
|
||||||
|
|
||||||
|
const { astro } = result.metadata as unknown as PluginMetadata;
|
||||||
|
return {
|
||||||
|
code: result.code || '',
|
||||||
|
map: result.map,
|
||||||
|
meta: {
|
||||||
|
astro,
|
||||||
|
vite: {
|
||||||
|
// Setting this vite metadata to `ts` causes Vite to resolve .js
|
||||||
|
// extensions to .ts files.
|
||||||
|
lang: 'ts',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let cachedJsxTransformOptions: Promise<JSXTransformConfig> | JSXTransformConfig | undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the `jsxTransformOptions` with caching
|
||||||
|
*/
|
||||||
|
async function getJsxTransformOptions(): Promise<JSXTransformConfig> {
|
||||||
|
if (cachedJsxTransformOptions) {
|
||||||
|
return cachedJsxTransformOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
const options = jsxTransformOptions();
|
||||||
|
|
||||||
|
// Cache the promise
|
||||||
|
cachedJsxTransformOptions = options;
|
||||||
|
// After the promise is resolved, cache the final resolved options
|
||||||
|
options.then((resolvedOptions) => {
|
||||||
|
cachedJsxTransformOptions = resolvedOptions;
|
||||||
|
});
|
||||||
|
|
||||||
|
return options;
|
||||||
|
}
|
|
@ -15,6 +15,7 @@ import { createBasicPipeline } from '../test-utils.js';
|
||||||
const createAstroModule = (AstroComponent) => ({ default: AstroComponent });
|
const createAstroModule = (AstroComponent) => ({ default: AstroComponent });
|
||||||
const loadJSXRenderer = () => loadRenderer(jsxRenderer, { import: (s) => import(s) });
|
const loadJSXRenderer = () => loadRenderer(jsxRenderer, { import: (s) => import(s) });
|
||||||
|
|
||||||
|
// NOTE: This test may be testing an outdated JSX setup
|
||||||
describe('core/render', () => {
|
describe('core/render', () => {
|
||||||
describe('Astro JSX components', () => {
|
describe('Astro JSX components', () => {
|
||||||
let pipeline;
|
let pipeline;
|
||||||
|
|
Loading…
Add table
Reference in a new issue