JSX refactor (#7924)
* JSX refactor * Get preact/compat test to pass * Use include config * Remove old astro flavored markdown test * Move babel dep to preact * Remove errant debugger * Update lockfile * Update the multi-framework example * Update e2e tests * Fix nested-in-vue tests * Add back in astro check * Update packages/astro/src/core/create-vite.ts Co-authored-by: Nate Moore <natemoo-re@users.noreply.github.com> * Update packages/astro/src/core/create-vite.ts Co-authored-by: Nate Moore <natemoo-re@users.noreply.github.com> * Update packages/integrations/solid/src/index.ts Co-authored-by: Nate Moore <natemoo-re@users.noreply.github.com> * Update packages/integrations/solid/src/index.ts Co-authored-by: Nate Moore <natemoo-re@users.noreply.github.com> * Update .changeset/perfect-horses-tell.md Co-authored-by: Nate Moore <natemoo-re@users.noreply.github.com> * Move the comment about the include config * Remove redundant alias config * Use react's own preamble code * Use the base for the preamble * Remove solid redundancy * Update .changeset/perfect-horses-tell.md Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca> * Update based on review comments * Oops --------- Co-authored-by: Fred K. Schott <fkschott@gmail.com> Co-authored-by: Nate Moore <natemoo-re@users.noreply.github.com> Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>
This commit is contained in:
parent
2ee418e06a
commit
519a1c4e84
135 changed files with 857 additions and 802 deletions
7
.changeset/cool-feet-rest.md
Normal file
7
.changeset/cool-feet-rest.md
Normal file
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
'@astrojs/solid-js': major
|
||||
---
|
||||
|
||||
New `include` and `exclude` config options
|
||||
|
||||
The Solid integration now has new `include` and `exclude` config options. Use these if you want to use Solid alongside another JSX framework; include specifies files to be compiled for Solid and `exclude` does the opposite.
|
7
.changeset/large-countries-share.md
Normal file
7
.changeset/large-countries-share.md
Normal file
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
'@astrojs/preact': major
|
||||
---
|
||||
|
||||
New `include` and `exclude` config options
|
||||
|
||||
The Preact integration now has new `include` and `exclude` config options. Use these if you want to use Preact alongside another JSX framework; include specifies files to be compiled for Preact and `exclude` does the opposite.
|
27
.changeset/perfect-horses-tell.md
Normal file
27
.changeset/perfect-horses-tell.md
Normal file
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
'astro': major
|
||||
---
|
||||
|
||||
Astro's JSX handling has been refactored with better support for each framework.
|
||||
|
||||
Previously, Astro automatically scanned your components to determine which framework-specific transformations should be used. In practice, supporting advanced features like Fast Refresh with this approach proved difficult.
|
||||
|
||||
Now, Astro determines which framework to use with `include` and `exclude` config options where you can specify files and folders on a per-framework basis. When using multiple JSX frameworks in the same project, users should manually control which files belong to each framework using the `include` and `exclude` options.
|
||||
|
||||
```js
|
||||
export default defineConfig({
|
||||
// The `include` config is only needed in projects that use multiple JSX frameworks;
|
||||
// if only using one no extra config is needed.
|
||||
integrations: [
|
||||
preact({
|
||||
include: ['**/preact/*']
|
||||
}),
|
||||
react({
|
||||
include: ['**/react/*']
|
||||
}),
|
||||
solid({
|
||||
include: ['**/solid/*'],
|
||||
}),
|
||||
]
|
||||
});
|
||||
```
|
9
.changeset/slimy-carrots-sell.md
Normal file
9
.changeset/slimy-carrots-sell.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
'@astrojs/react': major
|
||||
---
|
||||
|
||||
Support for React Refresh
|
||||
|
||||
The React integration now fully supports React Refresh and is backed by `@vitejs/plugin-react`.
|
||||
|
||||
Also included in this change are new `include` and `exclude` config options. Use these if you want to use React alongside another JSX framework; include specifies files to be compiled for React and `exclude` does the opposite.
|
|
@ -8,5 +8,11 @@ import solid from '@astrojs/solid-js';
|
|||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
// Enable many frameworks to support all different kinds of components.
|
||||
integrations: [preact(), react(), svelte(), vue(), solid()],
|
||||
integrations: [
|
||||
preact({ include: ['**/preact/*'] }),
|
||||
solid({ include: ['**/solid/*'] }),
|
||||
react({ include: ['**/react/*'] }),
|
||||
svelte(),
|
||||
vue(),
|
||||
],
|
||||
});
|
||||
|
|
|
@ -4,12 +4,12 @@ import '../styles/global.css';
|
|||
|
||||
// Component Imports
|
||||
// For JSX components, all the common ways of exporting (under a namespace, specific export, default export etc) are supported!
|
||||
import * as react from '../components/ReactCounter';
|
||||
import { PreactCounter } from '../components/PreactCounter';
|
||||
import SolidCounter from '../components/SolidCounter';
|
||||
import * as react from '../components/react/ReactCounter';
|
||||
import { PreactCounter } from '../components/preact/PreactCounter';
|
||||
import SolidCounter from '../components/solid/SolidCounter';
|
||||
|
||||
import VueCounter from '../components/VueCounter.vue';
|
||||
import SvelteCounter from '../components/SvelteCounter.svelte';
|
||||
import VueCounter from '../components/vue/VueCounter.vue';
|
||||
import SvelteCounter from '../components/svelte/SvelteCounter.svelte';
|
||||
|
||||
// Full Astro Component Syntax:
|
||||
// https://docs.astro.build/core-concepts/astro-components/
|
||||
|
|
|
@ -75,7 +75,7 @@ test.describe('Error display', () => {
|
|||
const fileExists = astro.pathExists(absoluteFileUrl);
|
||||
|
||||
expect(fileExists).toBeTruthy();
|
||||
expect(fileLocation).toMatch(/^components\/PreactRuntimeError.jsx/);
|
||||
expect(fileLocation).toMatch(/^preact\/PreactRuntimeError.jsx/);
|
||||
});
|
||||
|
||||
test('shows correct line when a style preprocess has an error', async ({ page, astro }) => {
|
||||
|
@ -105,7 +105,7 @@ test.describe('Error display', () => {
|
|||
// Wait for page reload
|
||||
page.waitForNavigation(),
|
||||
// Edit the component file
|
||||
astro.editFile('./src/components/SvelteSyntaxError.svelte', () => `<h1>No mismatch</h1>`),
|
||||
astro.editFile('./src/components/svelte/SvelteSyntaxError.svelte', () => `<h1>No mismatch</h1>`),
|
||||
]);
|
||||
|
||||
expect(await page.locator('vite-error-overlay').count()).toEqual(0);
|
||||
|
|
|
@ -8,5 +8,11 @@ import solid from '@astrojs/solid-js';
|
|||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
// Enable many frameworks to support all different kinds of components.
|
||||
integrations: [preact(), react(), svelte(), vue(), solid()],
|
||||
integrations: [
|
||||
react({ include: ['**/react/*'] }),
|
||||
preact({ include: ['**/preact/*'] }),
|
||||
solid({ include: ['**/solid/*'] }),
|
||||
svelte(),
|
||||
vue(),
|
||||
],
|
||||
});
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
---
|
||||
import * as react from '../components/ReactCounter.jsx';
|
||||
import { PreactCounter } from '../components/PreactCounter.tsx';
|
||||
import SolidCounter from '../components/SolidCounter.tsx';
|
||||
import VueCounter from '../components/VueCounter.vue';
|
||||
import SvelteCounter from '../components/SvelteCounter.svelte';
|
||||
import * as react from '../components/react/ReactCounter.jsx';
|
||||
import { PreactCounter } from '../components/preact/PreactCounter.jsx';
|
||||
import SolidCounter from '../components/solid/SolidCounter.jsx';
|
||||
import VueCounter from '../components/vue/VueCounter.vue';
|
||||
import SvelteCounter from '../components/svelte/SvelteCounter.svelte';
|
||||
|
||||
// Full Astro Component Syntax:
|
||||
// https://docs.astro.build/core-concepts/astro-components/
|
||||
|
|
|
@ -7,5 +7,11 @@ import vue from '@astrojs/vue';
|
|||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
integrations: [react(), preact(), solid(), svelte(), vue()],
|
||||
});
|
||||
integrations: [
|
||||
react({ include: ['**/react/*'] }),
|
||||
preact({ include: ['**/preact/*'] }),
|
||||
solid({ include: ['**/solid/*'] }),
|
||||
svelte(),
|
||||
vue(),
|
||||
],
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
import SvelteDirectiveError from '../components/SvelteDirectiveError.svelte';
|
||||
import SvelteDirectiveError from '../components/svelte/SvelteDirectiveError.svelte';
|
||||
---
|
||||
|
||||
<div>
|
||||
<SvelteDirectiveError client:media />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
import SvelteDirectiveError from '../components/SvelteDirectiveError.svelte';
|
||||
import SvelteDirectiveError from '../components/svelte/SvelteDirectiveError.svelte';
|
||||
---
|
||||
|
||||
<div>
|
||||
<SvelteDirectiveError client:loadm />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
import PreactRuntimeError from '../components/PreactRuntimeError.jsx';
|
||||
import PreactRuntimeError from '../components/preact/PreactRuntimeError.jsx';
|
||||
---
|
||||
|
||||
<div>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
import PreactSyntaxError from '../components/PreactSyntaxError.jsx';
|
||||
import PreactSyntaxError from '../components/preact/PreactSyntaxError.jsx';
|
||||
---
|
||||
|
||||
<div>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
import ReactRuntimeError from '../components/ReactRuntimeError.jsx';
|
||||
import ReactRuntimeError from '../components/react/ReactRuntimeError.jsx';
|
||||
---
|
||||
|
||||
<div>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
import ReactSyntaxError from '../components/ReactSyntaxError.jsx';
|
||||
import ReactSyntaxError from '../components/react/ReactSyntaxError.jsx';
|
||||
---
|
||||
|
||||
<div>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
import SolidRuntimeError from '../components/SolidRuntimeError.jsx';
|
||||
import SolidRuntimeError from '../components/solid/SolidRuntimeError.jsx';
|
||||
---
|
||||
|
||||
<div>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
import SolidSyntaxError from '../components/SolidSyntaxError.jsx';
|
||||
import SolidSyntaxError from '../components/solid/SolidSyntaxError.jsx';
|
||||
---
|
||||
|
||||
<div>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
import SvelteRuntimeError from '../components/SvelteRuntimeError.svelte';
|
||||
import SvelteRuntimeError from '../components/svelte/SvelteRuntimeError.svelte';
|
||||
---
|
||||
|
||||
<div>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
import SvelteSyntaxError from '../components/SvelteSyntaxError.svelte';
|
||||
import SvelteSyntaxError from '../components/svelte/SvelteSyntaxError.svelte';
|
||||
---
|
||||
|
||||
<div>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
import VueRuntimeError from '../components/VueRuntimeError.vue';
|
||||
import VueRuntimeError from '../components/vue/VueRuntimeError.vue';
|
||||
---
|
||||
|
||||
<div>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
import VueSyntaxError from '../components/VueSyntaxError.vue';
|
||||
import VueSyntaxError from '../components/vue/VueSyntaxError.vue';
|
||||
---
|
||||
|
||||
<div>
|
||||
|
|
|
@ -8,5 +8,11 @@ import solid from '@astrojs/solid-js';
|
|||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
// Enable many frameworks to support all different kinds of components.
|
||||
integrations: [preact(), react(), svelte(), vue(), solid()],
|
||||
integrations: [
|
||||
react({ include: ['**/react/*'] }),
|
||||
preact({ include: ['**/preact/*'] }),
|
||||
solid({ include: ['**/solid/*'] }),
|
||||
svelte(),
|
||||
vue(),
|
||||
],
|
||||
});
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
import '../styles/global.css';
|
||||
// Component Imports
|
||||
import { A, B as Renamed } from '../components';
|
||||
import * as react from '../components/ReactCounter.jsx';
|
||||
import { PreactCounter } from '../components/PreactCounter.tsx';
|
||||
import SolidCounter from '../components/SolidCounter.tsx';
|
||||
import VueCounter from '../components/VueCounter.vue';
|
||||
import SvelteCounter from '../components/SvelteCounter.svelte';
|
||||
import * as react from '../components/react/ReactCounter.jsx';
|
||||
import { PreactCounter } from '../components/preact/PreactCounter.tsx';
|
||||
import SolidCounter from '../components/solid/SolidCounter.tsx';
|
||||
import VueCounter from '../components/vue/VueCounter.vue';
|
||||
import SvelteCounter from '../components/svelte/SvelteCounter.svelte';
|
||||
|
||||
// Full Astro Component Syntax:
|
||||
// https://docs.astro.build/core-concepts/astro-components/
|
||||
|
|
|
@ -8,5 +8,11 @@ import solid from '@astrojs/solid-js';
|
|||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
// Enable many frameworks to support all different kinds of components.
|
||||
integrations: [preact(), react(), svelte(), vue(), solid()],
|
||||
integrations: [
|
||||
react({ include: ['**/react/*'] }),
|
||||
preact({ include: ['**/preact/*'] }),
|
||||
solid({ include: ['**/solid/*'] }),
|
||||
svelte(),
|
||||
vue(),
|
||||
],
|
||||
});
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
---
|
||||
import ReactCounter from '../components/ReactCounter.jsx';
|
||||
import { PreactCounter } from '../components/PreactCounter.tsx';
|
||||
import SolidCounter from '../components/SolidCounter.tsx';
|
||||
import VueCounter from '../components/VueCounter.vue';
|
||||
import SvelteCounter from '../components/SvelteCounter.svelte';
|
||||
import ReactCounter from '../components/react/ReactCounter.jsx';
|
||||
import { PreactCounter } from '../components/preact/PreactCounter.tsx';
|
||||
import SolidCounter from '../components/solid/SolidCounter.tsx';
|
||||
import VueCounter from '../components/vue/VueCounter.vue';
|
||||
import SvelteCounter from '../components/svelte/SvelteCounter.svelte';
|
||||
|
||||
// Full Astro Component Syntax:
|
||||
// https://docs.astro.build/core-concepts/astro-components/
|
||||
|
|
|
@ -8,5 +8,11 @@ import solid from '@astrojs/solid-js';
|
|||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
// Enable many frameworks to support all different kinds of components.
|
||||
integrations: [preact(), react(), svelte(), vue(), solid()],
|
||||
integrations: [
|
||||
react({ include: ['**/react/*'] }),
|
||||
preact({ include: ['**/preact/*'] }),
|
||||
solid({ include: ['**/solid/*'] }),
|
||||
svelte(),
|
||||
vue(),
|
||||
],
|
||||
});
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
---
|
||||
import ReactCounter from '../components/ReactCounter.jsx';
|
||||
import { PreactCounter } from '../components/PreactCounter.tsx';
|
||||
import SolidCounter from '../components/SolidCounter.tsx';
|
||||
import VueCounter from '../components/VueCounter.vue';
|
||||
import SvelteCounter from '../components/SvelteCounter.svelte';
|
||||
import ReactCounter from '../components/react/ReactCounter.jsx';
|
||||
import { PreactCounter } from '../components/preact/PreactCounter.tsx';
|
||||
import SolidCounter from '../components/solid/SolidCounter.tsx';
|
||||
import VueCounter from '../components/vue/VueCounter.vue';
|
||||
import SvelteCounter from '../components/svelte/SvelteCounter.svelte';
|
||||
|
||||
// Full Astro Component Syntax:
|
||||
// https://docs.astro.build/core-concepts/astro-components/
|
||||
|
|
|
@ -8,5 +8,11 @@ import solid from '@astrojs/solid-js';
|
|||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
// Enable many frameworks to support all different kinds of components.
|
||||
integrations: [preact(), react(), svelte(), vue(), solid()],
|
||||
integrations: [
|
||||
react({ include: ['**/react/*'] }),
|
||||
preact({ include: ['**/preact/*'] }),
|
||||
solid({ include: ['**/solid/*'] }),
|
||||
svelte(),
|
||||
vue(),
|
||||
],
|
||||
});
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
---
|
||||
import { Counter as ReactCounter } from '../components/ReactCounter.jsx';
|
||||
import { PreactCounter } from '../components/PreactCounter.tsx';
|
||||
import SolidCounter from '../components/SolidCounter.tsx';
|
||||
import VueCounter from '../components/VueCounter.vue';
|
||||
import SvelteCounter from '../components/SvelteCounter.svelte';
|
||||
import { Counter as ReactCounter } from '../components/react/ReactCounter.jsx';
|
||||
import { PreactCounter } from '../components/preact/PreactCounter.tsx';
|
||||
import SolidCounter from '../components/solid/SolidCounter.tsx';
|
||||
import VueCounter from '../components/vue/VueCounter.vue';
|
||||
import SvelteCounter from '../components/svelte/SvelteCounter.svelte';
|
||||
|
||||
// Full Astro Component Syntax:
|
||||
// https://docs.astro.build/core-concepts/astro-components/
|
||||
|
|
|
@ -8,5 +8,11 @@ import solid from '@astrojs/solid-js';
|
|||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
// Enable many frameworks to support all different kinds of components.
|
||||
integrations: [preact(), react(), svelte(), vue(), solid()],
|
||||
integrations: [
|
||||
react({ include: ['**/react/*'] }),
|
||||
preact({ include: ['**/preact/*'] }),
|
||||
solid({ include: ['**/solid/*'] }),
|
||||
svelte(),
|
||||
vue(),
|
||||
],
|
||||
});
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
---
|
||||
import { Counter as ReactCounter } from '../components/ReactCounter.jsx';
|
||||
import { PreactCounter } from '../components/PreactCounter.tsx';
|
||||
import SolidCounter from '../components/SolidCounter.tsx';
|
||||
import VueCounter from '../components/VueCounter.vue';
|
||||
import SvelteCounter from '../components/SvelteCounter.svelte';
|
||||
import { Counter as ReactCounter } from '../components/react/ReactCounter.jsx';
|
||||
import { PreactCounter } from '../components/preact/PreactCounter.tsx';
|
||||
import SolidCounter from '../components/solid/SolidCounter.tsx';
|
||||
import VueCounter from '../components/vue/VueCounter.vue';
|
||||
import SvelteCounter from '../components/svelte/SvelteCounter.svelte';
|
||||
|
||||
// Full Astro Component Syntax:
|
||||
// https://docs.astro.build/core-concepts/astro-components/
|
||||
|
|
|
@ -8,5 +8,11 @@ import solid from '@astrojs/solid-js';
|
|||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
// Enable many frameworks to support all different kinds of components.
|
||||
integrations: [preact(), react(), svelte(), vue(), solid()],
|
||||
integrations: [
|
||||
react({ include: ['**/react/*'] }),
|
||||
preact({ include: ['**/preact/*'] }),
|
||||
solid({ include: ['**/solid/*'] }),
|
||||
svelte(),
|
||||
vue(),
|
||||
],
|
||||
});
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
---
|
||||
import { Counter as ReactCounter } from '../components/ReactCounter.jsx';
|
||||
import { PreactCounter } from '../components/PreactCounter.tsx';
|
||||
import SolidCounter from '../components/SolidCounter.tsx';
|
||||
import VueCounter from '../components/VueCounter.vue';
|
||||
import SvelteCounter from '../components/SvelteCounter.svelte';
|
||||
import { Counter as ReactCounter } from '../components/react/ReactCounter.jsx';
|
||||
import { PreactCounter } from '../components/preact/PreactCounter.tsx';
|
||||
import SolidCounter from '../components/solid/SolidCounter.tsx';
|
||||
import VueCounter from '../components/vue/VueCounter.vue';
|
||||
import SvelteCounter from '../components/svelte/SvelteCounter.svelte';
|
||||
|
||||
// Full Astro Component Syntax:
|
||||
// https://docs.astro.build/core-concepts/astro-components/
|
||||
|
|
|
@ -8,5 +8,11 @@ import solid from '@astrojs/solid-js';
|
|||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
// Enable many frameworks to support all different kinds of components.
|
||||
integrations: [preact(), react(), svelte(), vue(), solid()],
|
||||
integrations: [
|
||||
react({ include: ['**/react/*'] }),
|
||||
preact({ include: ['**/preact/*'] }),
|
||||
solid({ include: ['**/solid/*'] }),
|
||||
svelte(),
|
||||
vue(),
|
||||
],
|
||||
});
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
---
|
||||
import ReactCounter from '../components/ReactCounter.jsx';
|
||||
import PreactCounter from '../components/PreactCounter.tsx';
|
||||
import SolidCounter from '../components/SolidCounter.tsx';
|
||||
import VueCounter from '../components/VueCounter.vue';
|
||||
import SvelteCounter from '../components/SvelteCounter.svelte';
|
||||
import ReactCounter from '../components/react/ReactCounter.jsx';
|
||||
import PreactCounter from '../components/preact/PreactCounter.tsx';
|
||||
import SolidCounter from '../components/solid/SolidCounter.tsx';
|
||||
import VueCounter from '../components/vue/VueCounter.vue';
|
||||
import SvelteCounter from '../components/svelte/SvelteCounter.svelte';
|
||||
---
|
||||
|
||||
<html lang="en">
|
||||
|
|
|
@ -38,6 +38,8 @@ export function vitePluginRenderers(opts: StaticBuildOptions): VitePlugin {
|
|||
exports.push(`export const renderers = [${rendererItems}];`);
|
||||
|
||||
return `${imports.join('\n')}\n${exports.join('\n')}`;
|
||||
} else {
|
||||
return `export const renderers = [];`;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -3,7 +3,6 @@ import path from 'node:path';
|
|||
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||
import type { AstroConfig, AstroSettings } from '../../@types/astro';
|
||||
import { getContentPaths } from '../../content/index.js';
|
||||
import jsxRenderer from '../../jsx/renderer.js';
|
||||
import { markdownContentEntryType } from '../../vite-plugin-markdown/content-entry-type.js';
|
||||
import { getDefaultClientDirectives } from '../client-directive/index.js';
|
||||
import { AstroError, AstroErrorData } from '../errors/index.js';
|
||||
|
@ -96,7 +95,7 @@ export function createBaseSettings(config: AstroConfig): AstroSettings {
|
|||
},
|
||||
},
|
||||
],
|
||||
renderers: [jsxRenderer],
|
||||
renderers: [],
|
||||
scripts: [],
|
||||
clientDirectives: getDefaultClientDirectives(),
|
||||
watchFiles: [],
|
||||
|
|
|
@ -19,9 +19,9 @@ import configAliasVitePlugin from '../vite-plugin-config-alias/index.js';
|
|||
import envVitePlugin from '../vite-plugin-env/index.js';
|
||||
import astroHeadPlugin from '../vite-plugin-head/index.js';
|
||||
import htmlVitePlugin from '../vite-plugin-html/index.js';
|
||||
import mdxVitePlugin from '../vite-plugin-mdx/index.js';
|
||||
import { astroInjectEnvTsPlugin } from '../vite-plugin-inject-env-ts/index.js';
|
||||
import astroIntegrationsContainerPlugin from '../vite-plugin-integrations-container/index.js';
|
||||
import jsxVitePlugin from '../vite-plugin-jsx/index.js';
|
||||
import astroLoadFallbackPlugin from '../vite-plugin-load-fallback/index.js';
|
||||
import markdownVitePlugin from '../vite-plugin-markdown/index.js';
|
||||
import astroScannerPlugin from '../vite-plugin-scanner/index.js';
|
||||
|
@ -121,7 +121,7 @@ export async function createVite(
|
|||
envVitePlugin({ settings }),
|
||||
markdownVitePlugin({ settings, logging }),
|
||||
htmlVitePlugin(),
|
||||
jsxVitePlugin({ settings, logging }),
|
||||
mdxVitePlugin({ settings, logging }),
|
||||
astroPostprocessVitePlugin(),
|
||||
astroIntegrationsContainerPlugin({ settings, logging }),
|
||||
astroScriptsPageSSRPlugin({ settings }),
|
||||
|
|
|
@ -1,251 +0,0 @@
|
|||
import type { TransformResult } from 'rollup';
|
||||
import {
|
||||
transformWithEsbuild,
|
||||
type EsbuildTransformOptions,
|
||||
type Plugin,
|
||||
type ResolvedConfig,
|
||||
} from 'vite';
|
||||
import type { AstroRenderer, AstroSettings } from '../@types/astro';
|
||||
import type { LogOptions } from '../core/logger/core.js';
|
||||
import type { PluginMetadata } from '../vite-plugin-astro/types';
|
||||
|
||||
import babel from '@babel/core';
|
||||
import * as colors from 'kleur/colors';
|
||||
import path from 'node:path';
|
||||
import { CONTENT_FLAG, PROPAGATED_ASSET_FLAG } from '../content/index.js';
|
||||
import { astroEntryPrefix } from '../core/build/plugins/plugin-component-entry.js';
|
||||
import { error } from '../core/logger/core.js';
|
||||
import { removeQueryString } from '../core/path.js';
|
||||
import { detectImportSource } from './import-source.js';
|
||||
import tagExportsPlugin from './tag.js';
|
||||
|
||||
const JSX_EXTENSIONS = new Set(['.jsx', '.tsx', '.mdx']);
|
||||
const IMPORT_STATEMENTS: Record<string, string> = {
|
||||
react: "import React from 'react'",
|
||||
preact: "import { h } from 'preact'",
|
||||
'solid-js': "import 'solid-js'",
|
||||
astro: "import 'astro/jsx-runtime'",
|
||||
};
|
||||
|
||||
function getEsbuildLoader(filePath: string): EsbuildTransformOptions['loader'] {
|
||||
const fileExt = path.extname(filePath);
|
||||
if (fileExt === '.mdx') return 'jsx';
|
||||
return fileExt.slice(1) as EsbuildTransformOptions['loader'];
|
||||
}
|
||||
|
||||
function collectJSXRenderers(renderers: AstroRenderer[]): Map<string, AstroRenderer> {
|
||||
const renderersWithJSXSupport = renderers.filter((r) => r.jsxImportSource);
|
||||
return new Map(
|
||||
renderersWithJSXSupport.map((r) => [r.jsxImportSource, r] as [string, AstroRenderer])
|
||||
);
|
||||
}
|
||||
|
||||
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;
|
||||
logging: LogOptions;
|
||||
}
|
||||
|
||||
// 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 jsx({ settings, logging }: AstroPluginJSXOptions): Plugin {
|
||||
let viteConfig: ResolvedConfig;
|
||||
const jsxRenderers = new Map<string, AstroRenderer>();
|
||||
const jsxRenderersIntegrationOnly = new Map<string, AstroRenderer>();
|
||||
// A reference to Astro's internal JSX renderer.
|
||||
let astroJSXRenderer: AstroRenderer;
|
||||
// The first JSX renderer provided is considered the default renderer.
|
||||
// This is a useful reference for when the user only gives a single render.
|
||||
let defaultJSXRendererEntry: [string, AstroRenderer] | undefined;
|
||||
|
||||
return {
|
||||
name: 'astro:jsx',
|
||||
enforce: 'pre', // run transforms before other plugins
|
||||
async configResolved(resolvedConfig) {
|
||||
viteConfig = resolvedConfig;
|
||||
const possibleRenderers = collectJSXRenderers(settings.renderers);
|
||||
for (const [importSource, renderer] of possibleRenderers) {
|
||||
jsxRenderers.set(importSource, renderer);
|
||||
if (importSource === 'astro') {
|
||||
astroJSXRenderer = renderer;
|
||||
} else {
|
||||
jsxRenderersIntegrationOnly.set(importSource, renderer);
|
||||
}
|
||||
}
|
||||
defaultJSXRendererEntry = [...jsxRenderersIntegrationOnly.entries()][0];
|
||||
},
|
||||
async transform(code, id, opts) {
|
||||
const ssr = Boolean(opts?.ssr);
|
||||
// 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.
|
||||
if (SPECIAL_QUERY_REGEX.test(id) || id.startsWith(astroEntryPrefix)) {
|
||||
return null;
|
||||
}
|
||||
id = removeQueryString(id);
|
||||
if (!JSX_EXTENSIONS.has(path.extname(id))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { mode } = viteConfig;
|
||||
// Shortcut: only use Astro renderer for MD and MDX files
|
||||
if (id.endsWith('.mdx')) {
|
||||
const { code: jsxCode } = await transformWithEsbuild(code, id, {
|
||||
loader: getEsbuildLoader(id),
|
||||
jsx: 'preserve',
|
||||
sourcemap: 'inline',
|
||||
tsconfigRaw: {
|
||||
compilerOptions: {
|
||||
// Ensure client:only imports are treeshaken
|
||||
verbatimModuleSyntax: false,
|
||||
importsNotUsedAsValues: 'remove',
|
||||
},
|
||||
},
|
||||
});
|
||||
return transformJSX({
|
||||
code: jsxCode,
|
||||
id,
|
||||
renderer: astroJSXRenderer,
|
||||
mode,
|
||||
ssr,
|
||||
root: settings.config.root,
|
||||
});
|
||||
}
|
||||
if (defaultJSXRendererEntry && jsxRenderersIntegrationOnly.size === 1) {
|
||||
// downlevel any non-standard syntax, but preserve JSX
|
||||
const { code: jsxCode } = await transformWithEsbuild(code, id, {
|
||||
loader: getEsbuildLoader(id),
|
||||
jsx: 'preserve',
|
||||
sourcemap: 'inline',
|
||||
});
|
||||
return transformJSX({
|
||||
code: jsxCode,
|
||||
id,
|
||||
renderer: defaultJSXRendererEntry[1],
|
||||
mode,
|
||||
ssr,
|
||||
root: settings.config.root,
|
||||
});
|
||||
}
|
||||
|
||||
const importSource = await detectImportSource(code, jsxRenderers, settings.tsConfig);
|
||||
|
||||
// if we still can’t tell the import source, now is the time to throw an error.
|
||||
if (!importSource && defaultJSXRendererEntry) {
|
||||
const [defaultRendererName] = defaultJSXRendererEntry;
|
||||
error(
|
||||
logging,
|
||||
'renderer',
|
||||
`${colors.yellow(id)}
|
||||
Unable to resolve a renderer that handles this file! With more than one renderer enabled, you should include an import or use a pragma comment.
|
||||
Add ${colors.cyan(
|
||||
IMPORT_STATEMENTS[defaultRendererName] || `import '${defaultRendererName}';`
|
||||
)} or ${colors.cyan(`/** @jsxImportSource: ${defaultRendererName} */`)} to this file.
|
||||
`
|
||||
);
|
||||
return null;
|
||||
} else if (!importSource) {
|
||||
error(
|
||||
logging,
|
||||
'renderer',
|
||||
`${colors.yellow(id)}
|
||||
Unable to find a renderer for JSX. Do you have one configured in your Astro config? See this page to learn how:
|
||||
https://docs.astro.build/en/core-concepts/framework-components/#installing-integrations
|
||||
`
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
const selectedJsxRenderer = jsxRenderers.get(importSource);
|
||||
// if the renderer is not installed for this JSX source, throw error
|
||||
if (!selectedJsxRenderer) {
|
||||
error(
|
||||
logging,
|
||||
'renderer',
|
||||
`${colors.yellow(
|
||||
id
|
||||
)} No renderer installed for ${importSource}. Try adding \`@astrojs/${importSource}\` to your project.`
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
// downlevel any non-standard syntax, but preserve JSX
|
||||
const { code: jsxCode } = await transformWithEsbuild(code, id, {
|
||||
loader: getEsbuildLoader(id),
|
||||
jsx: 'preserve',
|
||||
sourcemap: 'inline',
|
||||
});
|
||||
return await transformJSX({
|
||||
code: jsxCode,
|
||||
id,
|
||||
renderer: selectedJsxRenderer,
|
||||
mode,
|
||||
ssr,
|
||||
root: settings.config.root,
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
|
@ -49,11 +49,6 @@ function safeMatter(source: string, id: string) {
|
|||
}
|
||||
}
|
||||
|
||||
// absolute path of "astro/jsx-runtime"
|
||||
const astroJsxRuntimeModulePath = normalizePath(
|
||||
fileURLToPath(new URL('../jsx-runtime/index.js', import.meta.url))
|
||||
);
|
||||
|
||||
const astroServerRuntimeModulePath = normalizePath(
|
||||
fileURLToPath(new URL('../runtime/server/index.js', import.meta.url))
|
||||
);
|
||||
|
@ -115,8 +110,7 @@ export default function markdown({ settings, logging }: AstroPluginOptions): Plu
|
|||
}
|
||||
|
||||
const code = escapeViteEnvReferences(`
|
||||
import { Fragment, jsx as h } from ${JSON.stringify(astroJsxRuntimeModulePath)};
|
||||
import { spreadAttributes } from ${JSON.stringify(astroServerRuntimeModulePath)};
|
||||
import { unescapeHTML, spreadAttributes, createComponent, render, renderComponent } from ${JSON.stringify(astroServerRuntimeModulePath)};
|
||||
import { AstroError, AstroErrorData } from ${JSON.stringify(astroErrorModulePath)};
|
||||
|
||||
${layout ? `import Layout from ${JSON.stringify(layout)};` : ''}
|
||||
|
@ -167,27 +161,29 @@ export default function markdown({ settings, logging }: AstroPluginOptions): Plu
|
|||
export function getHeadings() {
|
||||
return ${JSON.stringify(headings)};
|
||||
}
|
||||
export async function Content() {
|
||||
|
||||
export const Content = createComponent((result, _props, slots) => {
|
||||
const { layout, ...content } = frontmatter;
|
||||
content.file = file;
|
||||
content.url = url;
|
||||
const contentFragment = h(Fragment, { 'set:html': html });
|
||||
|
||||
return ${
|
||||
layout
|
||||
? `h(Layout, {
|
||||
file,
|
||||
url,
|
||||
content,
|
||||
frontmatter: content,
|
||||
headings: getHeadings(),
|
||||
rawContent,
|
||||
compiledContent,
|
||||
'server:root': true,
|
||||
children: contentFragment
|
||||
})`
|
||||
: `contentFragment`
|
||||
};
|
||||
}
|
||||
? `render\`\${renderComponent(result, 'Layout', Layout, {
|
||||
file,
|
||||
url,
|
||||
content,
|
||||
frontmatter: content,
|
||||
headings: getHeadings(),
|
||||
rawContent,
|
||||
compiledContent,
|
||||
'server:root': true,
|
||||
}, {
|
||||
'default': () => render\`\${unescapeHTML(html)}\`
|
||||
})}\`;`
|
||||
: `render\`\${unescapeHTML(html)}\`;`
|
||||
}
|
||||
});
|
||||
Content[Symbol.for('astro.needsHeadRendering')] = ${layout ? 'false' : 'true'};
|
||||
export default Content;
|
||||
`);
|
||||
|
|
134
packages/astro/src/vite-plugin-mdx/index.ts
Normal file
134
packages/astro/src/vite-plugin-mdx/index.ts
Normal file
|
@ -0,0 +1,134 @@
|
|||
import type { TransformResult } from 'rollup';
|
||||
import {
|
||||
transformWithEsbuild,
|
||||
type Plugin,
|
||||
type ResolvedConfig,
|
||||
} from 'vite';
|
||||
import type { AstroRenderer, AstroSettings } from '../@types/astro';
|
||||
import type { LogOptions } from '../core/logger/core.js';
|
||||
import type { PluginMetadata } from '../vite-plugin-astro/types';
|
||||
|
||||
import babel from '@babel/core';
|
||||
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,
|
||||
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;
|
||||
logging: LogOptions;
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
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.
|
||||
if (SPECIAL_QUERY_REGEX.test(id) || id.startsWith(astroEntryPrefix)) {
|
||||
return null;
|
||||
}
|
||||
id = removeQueryString(id);
|
||||
// Shortcut: only use Astro renderer for MD and MDX files
|
||||
if (!id.endsWith('.mdx')) {
|
||||
return null;
|
||||
}
|
||||
const { code: jsxCode } = await transformWithEsbuild(code, id, {
|
||||
loader: 'jsx',
|
||||
jsx: 'preserve',
|
||||
sourcemap: 'inline',
|
||||
tsconfigRaw: {
|
||||
compilerOptions: {
|
||||
// Ensure client:only imports are treeshaken
|
||||
verbatimModuleSyntax: false,
|
||||
importsNotUsedAsValues: 'remove',
|
||||
},
|
||||
},
|
||||
});
|
||||
return transformJSX({
|
||||
code: jsxCode,
|
||||
id,
|
||||
renderer: astroJSXRenderer,
|
||||
mode: viteConfig.mode,
|
||||
ssr: Boolean(opts?.ssr),
|
||||
root: settings.config.root,
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue