Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor MDX transformJSX handling #10688

Merged
merged 3 commits into from
Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/four-pants-juggle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"astro": patch
---

Marks renderer `jsxImportSource` and `jsxTransformOptions` options as deprecated as they are no longer used since Astro 3.0
4 changes: 2 additions & 2 deletions packages/astro/src/@types/astro.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2577,9 +2577,9 @@ export interface AstroRenderer {
clientEntrypoint?: string;
/** Import entrypoint for the server/build/ssr renderer. */
serverEntrypoint: string;
/** JSX identifier (e.g. 'react' or 'solid-js') */
/** @deprecated Vite plugins should transform the JSX instead */
jsxImportSource?: string;
/** Babel transform options */
/** @deprecated Vite plugins should transform the JSX instead */
jsxTransformOptions?: JSXTransformFn;
}

Expand Down
2 changes: 1 addition & 1 deletion packages/astro/src/core/create-vite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ export async function createVite(
envVitePlugin({ settings }),
markdownVitePlugin({ settings, logger }),
htmlVitePlugin(),
mdxVitePlugin({ settings, logger }),
mdxVitePlugin(),
astroPostprocessVitePlugin(),
astroIntegrationsContainerPlugin({ settings, logger }),
astroScriptsPageSSRPlugin({ settings }),
Expand Down
18 changes: 5 additions & 13 deletions packages/astro/src/jsx/renderer.ts
Original file line number Diff line number Diff line change
@@ -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',
serverEntrypoint: 'astro/jsx/server.js',
jsxImportSource: 'astro',
jsxTransformOptions: async () => {
// @ts-expect-error types not found
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is moved to ./transform-options.js without changes. This allows using the jsxTransformOptions function directly.

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' }),
],
};
},
jsxTransformOptions,
};

export default renderer;
14 changes: 14 additions & 0 deletions packages/astro/src/jsx/transform-options.ts
Original file line number Diff line number Diff line change
@@ -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' }),
],
};
}
4 changes: 2 additions & 2 deletions packages/astro/src/vite-plugin-mdx/README.md
Original file line number Diff line number Diff line change
@@ -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.
97 changes: 5 additions & 92 deletions packages/astro/src/vite-plugin-mdx/index.ts
Original file line number Diff line number Diff line change
@@ -1,99 +1,19 @@
import type { TransformResult } from 'rollup';
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 { type Plugin, transformWithEsbuild } from 'vite';
import { CONTENT_FLAG, PROPAGATED_ASSET_FLAG } from '../content/index.js';
import { astroEntryPrefix } from '../core/build/plugins/plugin-component-entry.js';
import { removeQueryString } from '../core/path.js';
import tagExportsPlugin from './tag.js';

interface TransformJSXOptions {
code: string;
id: string;
mode: string;
renderer: AstroRenderer;
ssr: boolean;
root: URL;
}

async function transformJSX({
code,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is moved to ./transform-jsx.ts and is updated to retrieve the transform options differently.

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;
}
import { transformJSX } from './transform-jsx.js';

// Format inspired by https://github.com/vitejs/vite/blob/main/packages/vite/src/node/constants.ts#L54
const SPECIAL_QUERY_REGEX = new RegExp(
`[?&](?: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) */
export default function mdxVitePlugin({ settings }: AstroPluginJSXOptions): Plugin {
let viteConfig: ResolvedConfig;
// A reference to Astro's internal JSX renderer.
let astroJSXRenderer: AstroRenderer;

// TODO: Move this Vite plugin into `@astrojs/mdx` in Astro 5
export default function mdxVitePlugin(): Plugin {
return {
name: 'astro:jsx',
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) {
// 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.
Expand All @@ -117,14 +37,7 @@ export default function mdxVitePlugin({ settings }: AstroPluginJSXOptions): Plug
},
},
});
return transformJSX({
code: jsxCode,
id,
renderer: astroJSXRenderer,
mode: viteConfig.mode,
ssr: Boolean(opts?.ssr),
root: settings.config.root,
});
return await transformJSX(jsxCode, id, opts?.ssr);
},
};
}
Loading
Loading