Minor change to jsxTransformOptions, update Renderer API docs (#1630)
This commit is contained in:
parent
b0ef391e57
commit
2c15795607
5 changed files with 53 additions and 29 deletions
11
.changeset/tidy-mirrors-drum.md
Normal file
11
.changeset/tidy-mirrors-drum.md
Normal file
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
'astro': patch
|
||||
'@astrojs/renderer-lit': patch
|
||||
'@astrojs/renderer-preact': patch
|
||||
'@astrojs/renderer-react': patch
|
||||
'@astrojs/renderer-solid': patch
|
||||
'@astrojs/renderer-svelte': patch
|
||||
'@astrojs/renderer-vue': patch
|
||||
---
|
||||
|
||||
Improve renderer APIs for Vite
|
|
@ -49,22 +49,32 @@ This means that Astro users don't need to install the UI framework packages them
|
|||
|
||||
The main entrypoint of a renderer is a simple JS file which exports a manifest for the renderer. The required values are `name`, `server`, and `client`.
|
||||
|
||||
Additionally, this entrypoint can define a [Snowpack plugin](https://www.snowpack.dev/guides/plugins) that should be used to load non-JavaScript files.
|
||||
Additionally, this entrypoint can define a [Vite config object](https://vitejs.dev/config/) that should be used to load non-JavaScript files.
|
||||
|
||||
```js
|
||||
import myVitePlugin from 'vite-plugin-myplugin';
|
||||
|
||||
export default {
|
||||
name: '@astrojs/renderer-xxx', // the renderer name
|
||||
client: './client.js', // relative path to the client entrypoint
|
||||
server: './server.js', // optional, relative path to the server entrypoint
|
||||
snowpackPlugin: '@snowpack/plugin-xxx', // optional, the name of a snowpack plugin to inject
|
||||
snowpackPluginOptions: { example: true }, // optional, any options to be forwarded to the snowpack plugin
|
||||
knownEntrypoints: ['framework'], // optional, entrypoint modules that will be used by compiled source
|
||||
external: ['dep'], // optional, dependencies that should not be built by snowpack
|
||||
polyfills: ['./shadow-dom-polyfill.js'], // optional, module scripts that should be loaded before client hydration.
|
||||
hydrationPolyfills: ['./hydrate-framework.js'], // optional, polyfills that need to run before hydration ever occurs.
|
||||
jsxImportSource: 'preact', // optional, the name of the library from which JSX is imported
|
||||
jsxTransformOptions: async () => {
|
||||
// optional, a function to transform JSX files
|
||||
server: './server.js', // (optional) relative path to the server entrypoint
|
||||
viteConfig(options = { mode: 'development', command: 'serve' }) {
|
||||
// (optional) return config object for Vite (https://vitejs.dev/config/)
|
||||
return {
|
||||
plugins: [myVitePlugin()], // tip: usually this will depend on a Vite plugin
|
||||
optimizeDeps: {
|
||||
include: ['my-client-dep'], // tip: it’s always a good idea to specify any client-side hydration deps here
|
||||
},
|
||||
ssr: {
|
||||
external: ['my-client-dep/node/server.js'], // tip: use ssr.external in case you encounter code meant only for Node
|
||||
},
|
||||
};
|
||||
},
|
||||
polyfills: ['./shadow-dom-polyfill.js'], // (optional) scripts that should be injected on the page for the component
|
||||
hydrationPolyfills: ['./hydrate-framework.js'], // (optional) polyfills that need to run before hydration ever occurs
|
||||
jsxImportSource: 'preact', // (optional) the name of the library from which JSX is imported ("react", "preact", "solid-js", etc.)
|
||||
jsxTransformOptions: async (options = { mode: 'development', ssr: true }) => {
|
||||
// (optional) a function to transform JSX files
|
||||
const {
|
||||
default: { default: jsx },
|
||||
} = await import('@babel/plugin-transform-react-jsx');
|
||||
|
@ -72,7 +82,6 @@ export default {
|
|||
plugins: [jsx({}, { runtime: 'automatic', importSource: 'preact' })],
|
||||
};
|
||||
},
|
||||
vitePlugins: [], // optional, inject Vite plugins here (https://vitejs.dev/plugins/#plugins)
|
||||
};
|
||||
```
|
||||
|
||||
|
@ -92,19 +101,15 @@ This is an `async` function that returns information about how to transform matc
|
|||
|
||||
> Keep in mind that this transform doesn't need to handle TSX separately from JSX, Astro handles that for you!
|
||||
|
||||
The arguments passed to `jsxTransformOptions` follow Snowpack's `load()` plugin hook. These allow you to pass separate Babel configurations for various conditions, like if your files should be compiled differently in SSR mode.
|
||||
`jsxTransformOptions` receives context about whether it’s running in `development` or `production` mode, as well as whether or not it’s running in SSR or client hydration. These allow you to pass separate Babel configurations for various conditions, like if your files should be compiled differently in SSR mode.
|
||||
|
||||
```ts
|
||||
export interface JSXTransformOptions {
|
||||
(context: {
|
||||
/** True if builder is in dev mode (`astro dev`) */
|
||||
isDev: boolean;
|
||||
/** True if HMR is enabled (add any HMR code to the output here). */
|
||||
isHmrEnabled: boolean;
|
||||
/** "development" or "production" */
|
||||
mode: string;
|
||||
/** True if builder is in SSR mode */
|
||||
isSSR: boolean;
|
||||
/** True if file being transformed is inside of a package. */
|
||||
isPackage: boolean;
|
||||
ssr: boolean;
|
||||
}) => {
|
||||
plugins?: any[];
|
||||
presets?: any[];
|
||||
|
|
|
@ -162,7 +162,7 @@ export interface JSXTransformConfig {
|
|||
plugins?: babel.PluginItem[];
|
||||
}
|
||||
|
||||
export type JSXTransformFn = (options: { isSSR: boolean }) => Promise<JSXTransformConfig>;
|
||||
export type JSXTransformFn = (options: { mode: string; ssr: boolean }) => Promise<JSXTransformConfig>;
|
||||
|
||||
export interface ManifestData {
|
||||
routes: RouteData[];
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import type { TransformResult } from 'rollup';
|
||||
import type { Plugin } from '../core/vite';
|
||||
import type { Plugin, ResolvedConfig } from '../core/vite';
|
||||
import type { AstroConfig, Renderer } from '../@types/astro-core';
|
||||
import type { LogOptions } from '../core/logger';
|
||||
|
||||
|
@ -43,15 +43,22 @@ function isSSR(options: undefined | boolean | { ssr: boolean }): boolean {
|
|||
|
||||
/** Use Astro config to allow for alternate or multiple JSX renderers (by default Vite will assume React) */
|
||||
export default function jsx({ config, logging }: AstroPluginJSXOptions): Plugin {
|
||||
let viteConfig: ResolvedConfig;
|
||||
|
||||
return {
|
||||
name: '@astrojs/vite-plugin-jsx',
|
||||
enforce: 'pre', // run transforms before other plugins
|
||||
configResolved(resolvedConfig) {
|
||||
viteConfig = resolvedConfig;
|
||||
},
|
||||
async transform(code, id, ssrOrOptions) {
|
||||
const ssr = isSSR(ssrOrOptions);
|
||||
if (!JSX_EXTENSIONS.has(path.extname(id))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { mode } = viteConfig;
|
||||
|
||||
// load renderers (on first run only)
|
||||
if (JSX_RENDERERS.size === 0) {
|
||||
const jsxRenderers = await loadJSXRenderers(config.renderers);
|
||||
|
@ -76,7 +83,7 @@ export default function jsx({ config, logging }: AstroPluginJSXOptions): Plugin
|
|||
loader: getLoader(path.extname(id)),
|
||||
jsx: 'preserve',
|
||||
});
|
||||
return transformJSX({ code: jsxCode, id, renderer: [...JSX_RENDERERS.values()][0], ssr });
|
||||
return transformJSX({ code: jsxCode, id, renderer: [...JSX_RENDERERS.values()][0], mode, ssr });
|
||||
}
|
||||
|
||||
// Attempt: Multiple JSX renderers
|
||||
|
@ -130,7 +137,7 @@ export default function jsx({ config, logging }: AstroPluginJSXOptions): Plugin
|
|||
loader: getLoader(path.extname(id)),
|
||||
jsx: 'preserve',
|
||||
});
|
||||
return transformJSX({ code: jsxCode, id, renderer: JSX_RENDERERS.get(importSource) as Renderer, ssr });
|
||||
return transformJSX({ code: jsxCode, id, renderer: JSX_RENDERERS.get(importSource) as Renderer, mode, ssr });
|
||||
}
|
||||
|
||||
// if we still can’t tell, throw error
|
||||
|
@ -170,14 +177,15 @@ async function loadJSXRenderers(rendererNames: string[]): Promise<Map<string, Re
|
|||
interface TransformJSXOptions {
|
||||
code: string;
|
||||
id: string;
|
||||
ssr: boolean;
|
||||
mode: string;
|
||||
renderer: Renderer; // note MUST check for JSX beforehand!
|
||||
ssr: boolean;
|
||||
}
|
||||
|
||||
/** Transform JSX with Babel */
|
||||
async function transformJSX({ code, id, ssr, renderer }: TransformJSXOptions): Promise<TransformResult> {
|
||||
async function transformJSX({ code, mode, id, ssr, renderer }: TransformJSXOptions): Promise<TransformResult> {
|
||||
const { jsxTransformOptions } = renderer;
|
||||
const options = await jsxTransformOptions!({ isSSR: ssr || false }); // must filter for this beforehand
|
||||
const options = await jsxTransformOptions!({ mode, ssr }); // must filter for this beforehand
|
||||
const result = await new Promise<babel.BabelFileResult | null>((resolve, reject) => {
|
||||
const plugins = [...(options.plugins || [])];
|
||||
babel.transform(
|
||||
|
|
|
@ -3,14 +3,14 @@ export default {
|
|||
client: './client.js',
|
||||
server: './server.js',
|
||||
jsxImportSource: 'solid-js',
|
||||
jsxTransformOptions: async ({ isSSR }) => {
|
||||
jsxTransformOptions: async ({ ssr }) => {
|
||||
const [{ default: solid }] = await Promise.all([import('babel-preset-solid')]);
|
||||
const options = {
|
||||
presets: [solid({}, { generate: isSSR ? 'ssr' : 'dom', hydratable: true })],
|
||||
plugins: [],
|
||||
};
|
||||
|
||||
if (isSSR) {
|
||||
if (ssr) {
|
||||
options.plugins.push([
|
||||
'babel-plugin-module-resolver',
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue