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
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
// Enable many frameworks to support all different kinds of components.
|
// 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
|
// Component Imports
|
||||||
// For JSX components, all the common ways of exporting (under a namespace, specific export, default export etc) are supported!
|
// 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 * as react from '../components/react/ReactCounter';
|
||||||
import { PreactCounter } from '../components/PreactCounter';
|
import { PreactCounter } from '../components/preact/PreactCounter';
|
||||||
import SolidCounter from '../components/SolidCounter';
|
import SolidCounter from '../components/solid/SolidCounter';
|
||||||
|
|
||||||
import VueCounter from '../components/VueCounter.vue';
|
import VueCounter from '../components/vue/VueCounter.vue';
|
||||||
import SvelteCounter from '../components/SvelteCounter.svelte';
|
import SvelteCounter from '../components/svelte/SvelteCounter.svelte';
|
||||||
|
|
||||||
// Full Astro Component Syntax:
|
// Full Astro Component Syntax:
|
||||||
// https://docs.astro.build/core-concepts/astro-components/
|
// https://docs.astro.build/core-concepts/astro-components/
|
||||||
|
|
|
@ -75,7 +75,7 @@ test.describe('Error display', () => {
|
||||||
const fileExists = astro.pathExists(absoluteFileUrl);
|
const fileExists = astro.pathExists(absoluteFileUrl);
|
||||||
|
|
||||||
expect(fileExists).toBeTruthy();
|
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 }) => {
|
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
|
// Wait for page reload
|
||||||
page.waitForNavigation(),
|
page.waitForNavigation(),
|
||||||
// Edit the component file
|
// 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);
|
expect(await page.locator('vite-error-overlay').count()).toEqual(0);
|
||||||
|
|
|
@ -8,5 +8,11 @@ import solid from '@astrojs/solid-js';
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
// Enable many frameworks to support all different kinds of components.
|
// 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 * as react from '../components/react/ReactCounter.jsx';
|
||||||
import { PreactCounter } from '../components/PreactCounter.tsx';
|
import { PreactCounter } from '../components/preact/PreactCounter.jsx';
|
||||||
import SolidCounter from '../components/SolidCounter.tsx';
|
import SolidCounter from '../components/solid/SolidCounter.jsx';
|
||||||
import VueCounter from '../components/VueCounter.vue';
|
import VueCounter from '../components/vue/VueCounter.vue';
|
||||||
import SvelteCounter from '../components/SvelteCounter.svelte';
|
import SvelteCounter from '../components/svelte/SvelteCounter.svelte';
|
||||||
|
|
||||||
// Full Astro Component Syntax:
|
// Full Astro Component Syntax:
|
||||||
// https://docs.astro.build/core-concepts/astro-components/
|
// https://docs.astro.build/core-concepts/astro-components/
|
||||||
|
|
|
@ -7,5 +7,11 @@ import vue from '@astrojs/vue';
|
||||||
|
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
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>
|
<div>
|
||||||
<SvelteDirectiveError client:media />
|
<SvelteDirectiveError client:media />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
import SvelteDirectiveError from '../components/SvelteDirectiveError.svelte';
|
import SvelteDirectiveError from '../components/svelte/SvelteDirectiveError.svelte';
|
||||||
---
|
---
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<SvelteDirectiveError client:loadm />
|
<SvelteDirectiveError client:loadm />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
import PreactRuntimeError from '../components/PreactRuntimeError.jsx';
|
import PreactRuntimeError from '../components/preact/PreactRuntimeError.jsx';
|
||||||
---
|
---
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
import PreactSyntaxError from '../components/PreactSyntaxError.jsx';
|
import PreactSyntaxError from '../components/preact/PreactSyntaxError.jsx';
|
||||||
---
|
---
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
import ReactRuntimeError from '../components/ReactRuntimeError.jsx';
|
import ReactRuntimeError from '../components/react/ReactRuntimeError.jsx';
|
||||||
---
|
---
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
import ReactSyntaxError from '../components/ReactSyntaxError.jsx';
|
import ReactSyntaxError from '../components/react/ReactSyntaxError.jsx';
|
||||||
---
|
---
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
import SolidRuntimeError from '../components/SolidRuntimeError.jsx';
|
import SolidRuntimeError from '../components/solid/SolidRuntimeError.jsx';
|
||||||
---
|
---
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
import SolidSyntaxError from '../components/SolidSyntaxError.jsx';
|
import SolidSyntaxError from '../components/solid/SolidSyntaxError.jsx';
|
||||||
---
|
---
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
import SvelteRuntimeError from '../components/SvelteRuntimeError.svelte';
|
import SvelteRuntimeError from '../components/svelte/SvelteRuntimeError.svelte';
|
||||||
---
|
---
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
import SvelteSyntaxError from '../components/SvelteSyntaxError.svelte';
|
import SvelteSyntaxError from '../components/svelte/SvelteSyntaxError.svelte';
|
||||||
---
|
---
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
import VueRuntimeError from '../components/VueRuntimeError.vue';
|
import VueRuntimeError from '../components/vue/VueRuntimeError.vue';
|
||||||
---
|
---
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
import VueSyntaxError from '../components/VueSyntaxError.vue';
|
import VueSyntaxError from '../components/vue/VueSyntaxError.vue';
|
||||||
---
|
---
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -8,5 +8,11 @@ import solid from '@astrojs/solid-js';
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
// Enable many frameworks to support all different kinds of components.
|
// 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';
|
import '../styles/global.css';
|
||||||
// Component Imports
|
// Component Imports
|
||||||
import { A, B as Renamed } from '../components';
|
import { A, B as Renamed } from '../components';
|
||||||
import * as react from '../components/ReactCounter.jsx';
|
import * as react from '../components/react/ReactCounter.jsx';
|
||||||
import { PreactCounter } from '../components/PreactCounter.tsx';
|
import { PreactCounter } from '../components/preact/PreactCounter.tsx';
|
||||||
import SolidCounter from '../components/SolidCounter.tsx';
|
import SolidCounter from '../components/solid/SolidCounter.tsx';
|
||||||
import VueCounter from '../components/VueCounter.vue';
|
import VueCounter from '../components/vue/VueCounter.vue';
|
||||||
import SvelteCounter from '../components/SvelteCounter.svelte';
|
import SvelteCounter from '../components/svelte/SvelteCounter.svelte';
|
||||||
|
|
||||||
// Full Astro Component Syntax:
|
// Full Astro Component Syntax:
|
||||||
// https://docs.astro.build/core-concepts/astro-components/
|
// https://docs.astro.build/core-concepts/astro-components/
|
||||||
|
|
|
@ -8,5 +8,11 @@ import solid from '@astrojs/solid-js';
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
// Enable many frameworks to support all different kinds of components.
|
// 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 ReactCounter from '../components/react/ReactCounter.jsx';
|
||||||
import { PreactCounter } from '../components/PreactCounter.tsx';
|
import { PreactCounter } from '../components/preact/PreactCounter.tsx';
|
||||||
import SolidCounter from '../components/SolidCounter.tsx';
|
import SolidCounter from '../components/solid/SolidCounter.tsx';
|
||||||
import VueCounter from '../components/VueCounter.vue';
|
import VueCounter from '../components/vue/VueCounter.vue';
|
||||||
import SvelteCounter from '../components/SvelteCounter.svelte';
|
import SvelteCounter from '../components/svelte/SvelteCounter.svelte';
|
||||||
|
|
||||||
// Full Astro Component Syntax:
|
// Full Astro Component Syntax:
|
||||||
// https://docs.astro.build/core-concepts/astro-components/
|
// https://docs.astro.build/core-concepts/astro-components/
|
||||||
|
|
|
@ -8,5 +8,11 @@ import solid from '@astrojs/solid-js';
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
// Enable many frameworks to support all different kinds of components.
|
// 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 ReactCounter from '../components/react/ReactCounter.jsx';
|
||||||
import { PreactCounter } from '../components/PreactCounter.tsx';
|
import { PreactCounter } from '../components/preact/PreactCounter.tsx';
|
||||||
import SolidCounter from '../components/SolidCounter.tsx';
|
import SolidCounter from '../components/solid/SolidCounter.tsx';
|
||||||
import VueCounter from '../components/VueCounter.vue';
|
import VueCounter from '../components/vue/VueCounter.vue';
|
||||||
import SvelteCounter from '../components/SvelteCounter.svelte';
|
import SvelteCounter from '../components/svelte/SvelteCounter.svelte';
|
||||||
|
|
||||||
// Full Astro Component Syntax:
|
// Full Astro Component Syntax:
|
||||||
// https://docs.astro.build/core-concepts/astro-components/
|
// https://docs.astro.build/core-concepts/astro-components/
|
||||||
|
|
|
@ -8,5 +8,11 @@ import solid from '@astrojs/solid-js';
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
// Enable many frameworks to support all different kinds of components.
|
// 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 { Counter as ReactCounter } from '../components/react/ReactCounter.jsx';
|
||||||
import { PreactCounter } from '../components/PreactCounter.tsx';
|
import { PreactCounter } from '../components/preact/PreactCounter.tsx';
|
||||||
import SolidCounter from '../components/SolidCounter.tsx';
|
import SolidCounter from '../components/solid/SolidCounter.tsx';
|
||||||
import VueCounter from '../components/VueCounter.vue';
|
import VueCounter from '../components/vue/VueCounter.vue';
|
||||||
import SvelteCounter from '../components/SvelteCounter.svelte';
|
import SvelteCounter from '../components/svelte/SvelteCounter.svelte';
|
||||||
|
|
||||||
// Full Astro Component Syntax:
|
// Full Astro Component Syntax:
|
||||||
// https://docs.astro.build/core-concepts/astro-components/
|
// https://docs.astro.build/core-concepts/astro-components/
|
||||||
|
|
|
@ -8,5 +8,11 @@ import solid from '@astrojs/solid-js';
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
// Enable many frameworks to support all different kinds of components.
|
// 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 { Counter as ReactCounter } from '../components/react/ReactCounter.jsx';
|
||||||
import { PreactCounter } from '../components/PreactCounter.tsx';
|
import { PreactCounter } from '../components/preact/PreactCounter.tsx';
|
||||||
import SolidCounter from '../components/SolidCounter.tsx';
|
import SolidCounter from '../components/solid/SolidCounter.tsx';
|
||||||
import VueCounter from '../components/VueCounter.vue';
|
import VueCounter from '../components/vue/VueCounter.vue';
|
||||||
import SvelteCounter from '../components/SvelteCounter.svelte';
|
import SvelteCounter from '../components/svelte/SvelteCounter.svelte';
|
||||||
|
|
||||||
// Full Astro Component Syntax:
|
// Full Astro Component Syntax:
|
||||||
// https://docs.astro.build/core-concepts/astro-components/
|
// https://docs.astro.build/core-concepts/astro-components/
|
||||||
|
|
|
@ -8,5 +8,11 @@ import solid from '@astrojs/solid-js';
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
// Enable many frameworks to support all different kinds of components.
|
// 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 { Counter as ReactCounter } from '../components/react/ReactCounter.jsx';
|
||||||
import { PreactCounter } from '../components/PreactCounter.tsx';
|
import { PreactCounter } from '../components/preact/PreactCounter.tsx';
|
||||||
import SolidCounter from '../components/SolidCounter.tsx';
|
import SolidCounter from '../components/solid/SolidCounter.tsx';
|
||||||
import VueCounter from '../components/VueCounter.vue';
|
import VueCounter from '../components/vue/VueCounter.vue';
|
||||||
import SvelteCounter from '../components/SvelteCounter.svelte';
|
import SvelteCounter from '../components/svelte/SvelteCounter.svelte';
|
||||||
|
|
||||||
// Full Astro Component Syntax:
|
// Full Astro Component Syntax:
|
||||||
// https://docs.astro.build/core-concepts/astro-components/
|
// https://docs.astro.build/core-concepts/astro-components/
|
||||||
|
|
|
@ -8,5 +8,11 @@ import solid from '@astrojs/solid-js';
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
// Enable many frameworks to support all different kinds of components.
|
// 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 ReactCounter from '../components/react/ReactCounter.jsx';
|
||||||
import PreactCounter from '../components/PreactCounter.tsx';
|
import PreactCounter from '../components/preact/PreactCounter.tsx';
|
||||||
import SolidCounter from '../components/SolidCounter.tsx';
|
import SolidCounter from '../components/solid/SolidCounter.tsx';
|
||||||
import VueCounter from '../components/VueCounter.vue';
|
import VueCounter from '../components/vue/VueCounter.vue';
|
||||||
import SvelteCounter from '../components/SvelteCounter.svelte';
|
import SvelteCounter from '../components/svelte/SvelteCounter.svelte';
|
||||||
---
|
---
|
||||||
|
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
|
@ -38,6 +38,8 @@ export function vitePluginRenderers(opts: StaticBuildOptions): VitePlugin {
|
||||||
exports.push(`export const renderers = [${rendererItems}];`);
|
exports.push(`export const renderers = [${rendererItems}];`);
|
||||||
|
|
||||||
return `${imports.join('\n')}\n${exports.join('\n')}`;
|
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 { fileURLToPath, pathToFileURL } from 'node:url';
|
||||||
import type { AstroConfig, AstroSettings } from '../../@types/astro';
|
import type { AstroConfig, AstroSettings } from '../../@types/astro';
|
||||||
import { getContentPaths } from '../../content/index.js';
|
import { getContentPaths } from '../../content/index.js';
|
||||||
import jsxRenderer from '../../jsx/renderer.js';
|
|
||||||
import { markdownContentEntryType } from '../../vite-plugin-markdown/content-entry-type.js';
|
import { markdownContentEntryType } from '../../vite-plugin-markdown/content-entry-type.js';
|
||||||
import { getDefaultClientDirectives } from '../client-directive/index.js';
|
import { getDefaultClientDirectives } from '../client-directive/index.js';
|
||||||
import { AstroError, AstroErrorData } from '../errors/index.js';
|
import { AstroError, AstroErrorData } from '../errors/index.js';
|
||||||
|
@ -96,7 +95,7 @@ export function createBaseSettings(config: AstroConfig): AstroSettings {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
renderers: [jsxRenderer],
|
renderers: [],
|
||||||
scripts: [],
|
scripts: [],
|
||||||
clientDirectives: getDefaultClientDirectives(),
|
clientDirectives: getDefaultClientDirectives(),
|
||||||
watchFiles: [],
|
watchFiles: [],
|
||||||
|
|
|
@ -19,9 +19,9 @@ import configAliasVitePlugin from '../vite-plugin-config-alias/index.js';
|
||||||
import envVitePlugin from '../vite-plugin-env/index.js';
|
import envVitePlugin from '../vite-plugin-env/index.js';
|
||||||
import astroHeadPlugin from '../vite-plugin-head/index.js';
|
import astroHeadPlugin from '../vite-plugin-head/index.js';
|
||||||
import htmlVitePlugin from '../vite-plugin-html/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 { astroInjectEnvTsPlugin } from '../vite-plugin-inject-env-ts/index.js';
|
||||||
import astroIntegrationsContainerPlugin from '../vite-plugin-integrations-container/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 astroLoadFallbackPlugin from '../vite-plugin-load-fallback/index.js';
|
||||||
import markdownVitePlugin from '../vite-plugin-markdown/index.js';
|
import markdownVitePlugin from '../vite-plugin-markdown/index.js';
|
||||||
import astroScannerPlugin from '../vite-plugin-scanner/index.js';
|
import astroScannerPlugin from '../vite-plugin-scanner/index.js';
|
||||||
|
@ -121,7 +121,7 @@ export async function createVite(
|
||||||
envVitePlugin({ settings }),
|
envVitePlugin({ settings }),
|
||||||
markdownVitePlugin({ settings, logging }),
|
markdownVitePlugin({ settings, logging }),
|
||||||
htmlVitePlugin(),
|
htmlVitePlugin(),
|
||||||
jsxVitePlugin({ settings, logging }),
|
mdxVitePlugin({ settings, logging }),
|
||||||
astroPostprocessVitePlugin(),
|
astroPostprocessVitePlugin(),
|
||||||
astroIntegrationsContainerPlugin({ settings, logging }),
|
astroIntegrationsContainerPlugin({ settings, logging }),
|
||||||
astroScriptsPageSSRPlugin({ settings }),
|
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(
|
const astroServerRuntimeModulePath = normalizePath(
|
||||||
fileURLToPath(new URL('../runtime/server/index.js', import.meta.url))
|
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(`
|
const code = escapeViteEnvReferences(`
|
||||||
import { Fragment, jsx as h } from ${JSON.stringify(astroJsxRuntimeModulePath)};
|
import { unescapeHTML, spreadAttributes, createComponent, render, renderComponent } from ${JSON.stringify(astroServerRuntimeModulePath)};
|
||||||
import { spreadAttributes } from ${JSON.stringify(astroServerRuntimeModulePath)};
|
|
||||||
import { AstroError, AstroErrorData } from ${JSON.stringify(astroErrorModulePath)};
|
import { AstroError, AstroErrorData } from ${JSON.stringify(astroErrorModulePath)};
|
||||||
|
|
||||||
${layout ? `import Layout from ${JSON.stringify(layout)};` : ''}
|
${layout ? `import Layout from ${JSON.stringify(layout)};` : ''}
|
||||||
|
@ -167,27 +161,29 @@ export default function markdown({ settings, logging }: AstroPluginOptions): Plu
|
||||||
export function getHeadings() {
|
export function getHeadings() {
|
||||||
return ${JSON.stringify(headings)};
|
return ${JSON.stringify(headings)};
|
||||||
}
|
}
|
||||||
export async function Content() {
|
|
||||||
|
export const Content = createComponent((result, _props, slots) => {
|
||||||
const { layout, ...content } = frontmatter;
|
const { layout, ...content } = frontmatter;
|
||||||
content.file = file;
|
content.file = file;
|
||||||
content.url = url;
|
content.url = url;
|
||||||
const contentFragment = h(Fragment, { 'set:html': html });
|
|
||||||
return ${
|
return ${
|
||||||
layout
|
layout
|
||||||
? `h(Layout, {
|
? `render\`\${renderComponent(result, 'Layout', Layout, {
|
||||||
file,
|
file,
|
||||||
url,
|
url,
|
||||||
content,
|
content,
|
||||||
frontmatter: content,
|
frontmatter: content,
|
||||||
headings: getHeadings(),
|
headings: getHeadings(),
|
||||||
rawContent,
|
rawContent,
|
||||||
compiledContent,
|
compiledContent,
|
||||||
'server:root': true,
|
'server:root': true,
|
||||||
children: contentFragment
|
}, {
|
||||||
})`
|
'default': () => render\`\${unescapeHTML(html)}\`
|
||||||
: `contentFragment`
|
})}\`;`
|
||||||
};
|
: `render\`\${unescapeHTML(html)}\`;`
|
||||||
}
|
}
|
||||||
|
});
|
||||||
Content[Symbol.for('astro.needsHeadRendering')] = ${layout ? 'false' : 'true'};
|
Content[Symbol.for('astro.needsHeadRendering')] = ${layout ? 'false' : 'true'};
|
||||||
export default Content;
|
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