Merge remote-tracking branch 'origin/main' into next
This commit is contained in:
commit
14b0626f3e
32 changed files with 467 additions and 86 deletions
5
.changeset/breezy-frogs-learn.md
Normal file
5
.changeset/breezy-frogs-learn.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'@astrojs/cloudflare': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
More efficient \_routes.json
|
|
@ -1,5 +0,0 @@
|
||||||
---
|
|
||||||
'create-astro': patch
|
|
||||||
---
|
|
||||||
|
|
||||||
Add support for more Starlight templates
|
|
|
@ -1,5 +0,0 @@
|
||||||
---
|
|
||||||
'astro': patch
|
|
||||||
---
|
|
||||||
|
|
||||||
Fixed `EndpointOutput` types with `{ encoding: 'binary' }`
|
|
|
@ -1,5 +0,0 @@
|
||||||
---
|
|
||||||
'astro': patch
|
|
||||||
---
|
|
||||||
|
|
||||||
Fix quadratic quote escaping in nested data in island props
|
|
5
.changeset/wild-jobs-tan.md
Normal file
5
.changeset/wild-jobs-tan.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'astro': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Move hoisted script analysis optimization behind the `experimental.optimizeHoistedScript` option
|
|
@ -11,6 +11,6 @@
|
||||||
"astro": "astro"
|
"astro": "astro"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"astro": "^2.10.3"
|
"astro": "^2.10.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,18 +31,44 @@ Itatur? Quiatae cullecum rem ent aut odis in re eossequodi nonsequ idebis ne sap
|
||||||
|
|
||||||
## Images
|
## Images
|
||||||
|
|
||||||
![This is a placeholder image description](/blog-placeholder-1.jpg)
|
#### Syntax
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
![Alt text](./full/or/relative/path/of/image)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Output
|
||||||
|
|
||||||
|
![blog placeholder](../../../public/blog-placeholder-about.jpg)
|
||||||
|
|
||||||
## Blockquotes
|
## Blockquotes
|
||||||
|
|
||||||
The blockquote element represents content that is quoted from another source, optionally with a citation which must be within a `footer` or `cite` element, and optionally with in-line changes such as annotations and abbreviations.
|
The blockquote element represents content that is quoted from another source, optionally with a citation which must be within a `footer` or `cite` element, and optionally with in-line changes such as annotations and abbreviations.
|
||||||
|
|
||||||
#### Blockquote without attribution
|
### Blockquote without attribution
|
||||||
|
|
||||||
|
#### Syntax
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
> Tiam, ad mint andaepu dandae nostion secatur sequo quae.
|
||||||
|
> **Note** that you can use _Markdown syntax_ within a blockquote.
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Output
|
||||||
|
|
||||||
> Tiam, ad mint andaepu dandae nostion secatur sequo quae.
|
> Tiam, ad mint andaepu dandae nostion secatur sequo quae.
|
||||||
> **Note** that you can use _Markdown syntax_ within a blockquote.
|
> **Note** that you can use _Markdown syntax_ within a blockquote.
|
||||||
|
|
||||||
#### Blockquote with attribution
|
### Blockquote with attribution
|
||||||
|
|
||||||
|
#### Syntax
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
> Don't communicate by sharing memory, share memory by communicating.<br>
|
||||||
|
> — <cite>Rob Pike[^1]</cite>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Output
|
||||||
|
|
||||||
> Don't communicate by sharing memory, share memory by communicating.<br>
|
> Don't communicate by sharing memory, share memory by communicating.<br>
|
||||||
> — <cite>Rob Pike[^1]</cite>
|
> — <cite>Rob Pike[^1]</cite>
|
||||||
|
@ -51,12 +77,43 @@ The blockquote element represents content that is quoted from another source, op
|
||||||
|
|
||||||
## Tables
|
## Tables
|
||||||
|
|
||||||
|
#### Syntax
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
| Italics | Bold | Code |
|
||||||
|
| --------- | -------- | ------ |
|
||||||
|
| _italics_ | **bold** | `code` |
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Output
|
||||||
|
|
||||||
| Italics | Bold | Code |
|
| Italics | Bold | Code |
|
||||||
| --------- | -------- | ------ |
|
| --------- | -------- | ------ |
|
||||||
| _italics_ | **bold** | `code` |
|
| _italics_ | **bold** | `code` |
|
||||||
|
|
||||||
## Code Blocks
|
## Code Blocks
|
||||||
|
|
||||||
|
#### Syntax
|
||||||
|
|
||||||
|
we can use 3 backticks ``` in new line and write snippet and close with 3 backticks on new line and to highlight language specific syntac, write one word of language name after first 3 backticks, for eg. html, javascript, css, markdown, typescript, txt, bash
|
||||||
|
|
||||||
|
````markdown
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>Example HTML5 Document</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>Test</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
````
|
||||||
|
|
||||||
|
Output
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
@ -72,19 +129,53 @@ The blockquote element represents content that is quoted from another source, op
|
||||||
|
|
||||||
## List Types
|
## List Types
|
||||||
|
|
||||||
#### Ordered List
|
### Ordered List
|
||||||
|
|
||||||
|
#### Syntax
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
1. First item
|
||||||
|
2. Second item
|
||||||
|
3. Third item
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Output
|
||||||
|
|
||||||
1. First item
|
1. First item
|
||||||
2. Second item
|
2. Second item
|
||||||
3. Third item
|
3. Third item
|
||||||
|
|
||||||
#### Unordered List
|
### Unordered List
|
||||||
|
|
||||||
|
#### Syntax
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
- List item
|
||||||
|
- Another item
|
||||||
|
- And another item
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Output
|
||||||
|
|
||||||
- List item
|
- List item
|
||||||
- Another item
|
- Another item
|
||||||
- And another item
|
- And another item
|
||||||
|
|
||||||
#### Nested list
|
### Nested list
|
||||||
|
|
||||||
|
#### Syntax
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
- Fruit
|
||||||
|
- Apple
|
||||||
|
- Orange
|
||||||
|
- Banana
|
||||||
|
- Dairy
|
||||||
|
- Milk
|
||||||
|
- Cheese
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Output
|
||||||
|
|
||||||
- Fruit
|
- Fruit
|
||||||
- Apple
|
- Apple
|
||||||
|
@ -96,6 +187,22 @@ The blockquote element represents content that is quoted from another source, op
|
||||||
|
|
||||||
## Other Elements — abbr, sub, sup, kbd, mark
|
## Other Elements — abbr, sub, sup, kbd, mark
|
||||||
|
|
||||||
|
#### Syntax
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
<abbr title="Graphics Interchange Format">GIF</abbr> is a bitmap image format.
|
||||||
|
|
||||||
|
H<sub>2</sub>O
|
||||||
|
|
||||||
|
X<sup>n</sup> + Y<sup>n</sup> = Z<sup>n</sup>
|
||||||
|
|
||||||
|
Press <kbd><kbd>CTRL</kbd>+<kbd>ALT</kbd>+<kbd>Delete</kbd></kbd> to end the session.
|
||||||
|
|
||||||
|
Most <mark>salamanders</mark> are nocturnal, and hunt for insects, worms, and other small creatures.
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Output
|
||||||
|
|
||||||
<abbr title="Graphics Interchange Format">GIF</abbr> is a bitmap image format.
|
<abbr title="Graphics Interchange Format">GIF</abbr> is a bitmap image format.
|
||||||
|
|
||||||
H<sub>2</sub>O
|
H<sub>2</sub>O
|
||||||
|
|
|
@ -219,6 +219,16 @@
|
||||||
- @astrojs/internal-helpers@0.2.0-beta.0
|
- @astrojs/internal-helpers@0.2.0-beta.0
|
||||||
- @astrojs/markdown-remark@3.0.0-beta.0
|
- @astrojs/markdown-remark@3.0.0-beta.0
|
||||||
|
|
||||||
|
## 2.10.4
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- [#8003](https://github.com/withastro/astro/pull/8003) [`16161afb2`](https://github.com/withastro/astro/commit/16161afb2b3a04ca7605fcd16de06efe3fabdef2) Thanks [@JuanM04](https://github.com/JuanM04)! - Fixed `EndpointOutput` types with `{ encoding: 'binary' }`
|
||||||
|
|
||||||
|
- [#7995](https://github.com/withastro/astro/pull/7995) [`79376f842`](https://github.com/withastro/astro/commit/79376f842d25edfe4dc2948548e99b59e1c4d24f) Thanks [@belluzj](https://github.com/belluzj)! - Fix quadratic quote escaping in nested data in island props
|
||||||
|
|
||||||
|
- [#8007](https://github.com/withastro/astro/pull/8007) [`58b121d42`](https://github.com/withastro/astro/commit/58b121d42a9f58a5a992f0c378b036f37e9715fc) Thanks [@paperdave](https://github.com/paperdave)! - Support Bun by adjusting how `@babel/plugin-transform-react-jsx` is imported.
|
||||||
|
|
||||||
## 2.10.3
|
## 2.10.3
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|
|
@ -1271,6 +1271,28 @@ export interface AstroUserConfig {
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
viewTransitions?: boolean;
|
viewTransitions?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @docs
|
||||||
|
* @name experimental.optimizeHoistedScript
|
||||||
|
* @type {boolean}
|
||||||
|
* @default `false`
|
||||||
|
* @version 2.10.4
|
||||||
|
* @description
|
||||||
|
* Prevents unused components' scripts from being included in a page unexpectedly.
|
||||||
|
* The optimization is best-effort and may inversely miss including the used scripts. Make sure to double-check your built pages
|
||||||
|
* before publishing.
|
||||||
|
* Enable hoisted script analysis optimization by adding the experimental flag:
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* {
|
||||||
|
* experimental: {
|
||||||
|
* optimizeHoistedScript: true,
|
||||||
|
* },
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
optimizeHoistedScript?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Legacy options to be removed
|
// Legacy options to be removed
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { pluginSSR, pluginSSRSplit } from './plugin-ssr.js';
|
||||||
export function registerAllPlugins({ internals, options, register }: AstroBuildPluginContainer) {
|
export function registerAllPlugins({ internals, options, register }: AstroBuildPluginContainer) {
|
||||||
register(pluginComponentEntry(internals));
|
register(pluginComponentEntry(internals));
|
||||||
register(pluginAliasResolve(internals));
|
register(pluginAliasResolve(internals));
|
||||||
register(pluginAnalyzer(internals));
|
register(pluginAnalyzer(options, internals));
|
||||||
register(pluginInternals(internals));
|
register(pluginInternals(internals));
|
||||||
register(pluginRenderers(options));
|
register(pluginRenderers(options));
|
||||||
register(pluginMiddleware(options, internals));
|
register(pluginMiddleware(options, internals));
|
||||||
|
|
|
@ -6,11 +6,11 @@ import type { BuildInternals } from '../internal.js';
|
||||||
import type { AstroBuildPlugin } from '../plugin.js';
|
import type { AstroBuildPlugin } from '../plugin.js';
|
||||||
|
|
||||||
import type { ExportDefaultDeclaration, ExportNamedDeclaration, ImportDeclaration } from 'estree';
|
import type { ExportDefaultDeclaration, ExportNamedDeclaration, ImportDeclaration } from 'estree';
|
||||||
import { walk } from 'estree-walker';
|
|
||||||
import { PROPAGATED_ASSET_FLAG } from '../../../content/consts.js';
|
import { PROPAGATED_ASSET_FLAG } from '../../../content/consts.js';
|
||||||
import { prependForwardSlash } from '../../../core/path.js';
|
import { prependForwardSlash } from '../../../core/path.js';
|
||||||
import { getTopLevelPages, moduleIsTopLevelPage, walkParentInfos } from '../graph.js';
|
import { getTopLevelPages, moduleIsTopLevelPage, walkParentInfos } from '../graph.js';
|
||||||
import { getPageDataByViteID, trackClientOnlyPageDatas } from '../internal.js';
|
import { getPageDataByViteID, trackClientOnlyPageDatas } from '../internal.js';
|
||||||
|
import type { StaticBuildOptions } from '../types.js';
|
||||||
|
|
||||||
function isPropagatedAsset(id: string) {
|
function isPropagatedAsset(id: string) {
|
||||||
try {
|
try {
|
||||||
|
@ -31,29 +31,28 @@ async function doesParentImportChild(
|
||||||
): Promise<'no' | 'dynamic' | string[]> {
|
): Promise<'no' | 'dynamic' | string[]> {
|
||||||
if (!childInfo || !parentInfo.ast || !childExportNames) return 'no';
|
if (!childInfo || !parentInfo.ast || !childExportNames) return 'no';
|
||||||
|
|
||||||
|
// If we're dynamically importing the child, return `dynamic` directly to opt-out of optimization
|
||||||
if (childExportNames === 'dynamic' || parentInfo.dynamicallyImportedIds?.includes(childInfo.id)) {
|
if (childExportNames === 'dynamic' || parentInfo.dynamicallyImportedIds?.includes(childInfo.id)) {
|
||||||
return 'dynamic';
|
return 'dynamic';
|
||||||
}
|
}
|
||||||
|
|
||||||
const imports: Array<ImportDeclaration> = [];
|
const imports: Array<ImportDeclaration> = [];
|
||||||
const exports: Array<ExportNamedDeclaration | ExportDefaultDeclaration> = [];
|
const exports: Array<ExportNamedDeclaration | ExportDefaultDeclaration> = [];
|
||||||
walk(parentInfo.ast as ESTreeNode, {
|
for (const node of (parentInfo.ast as any).body) {
|
||||||
enter(node) {
|
|
||||||
if (node.type === 'ImportDeclaration') {
|
if (node.type === 'ImportDeclaration') {
|
||||||
imports.push(node as ImportDeclaration);
|
imports.push(node);
|
||||||
} else if (
|
} else if (node.type === 'ExportDefaultDeclaration' || node.type === 'ExportNamedDeclaration') {
|
||||||
node.type === 'ExportDefaultDeclaration' ||
|
exports.push(node);
|
||||||
node.type === 'ExportNamedDeclaration'
|
|
||||||
) {
|
|
||||||
exports.push(node as ExportNamedDeclaration | ExportDefaultDeclaration);
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
});
|
|
||||||
// All of the aliases the current component is imported as
|
// All local import names that could be importing the child component
|
||||||
const importNames: string[] = [];
|
const importNames: string[] = [];
|
||||||
// All of the aliases the child component is exported as
|
// All of the aliases the child component is exported as
|
||||||
const exportNames: string[] = [];
|
const exportNames: string[] = [];
|
||||||
|
|
||||||
|
// Iterate each import, find it they import the child component, if so, check if they
|
||||||
|
// import the child component name specifically. We can verify this with `childExportNames`.
|
||||||
for (const node of imports) {
|
for (const node of imports) {
|
||||||
const resolved = await this.resolve(node.source.value as string, parentInfo.id);
|
const resolved = await this.resolve(node.source.value as string, parentInfo.id);
|
||||||
if (!resolved || resolved.id !== childInfo.id) continue;
|
if (!resolved || resolved.id !== childInfo.id) continue;
|
||||||
|
@ -68,14 +67,17 @@ async function doesParentImportChild(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Iterate each export, find it they re-export the child component, and push the exported name to `exportNames`
|
||||||
for (const node of exports) {
|
for (const node of exports) {
|
||||||
if (node.type === 'ExportDefaultDeclaration') {
|
if (node.type === 'ExportDefaultDeclaration') {
|
||||||
if (node.declaration.type === 'Identifier' && importNames.includes(node.declaration.name)) {
|
if (node.declaration.type === 'Identifier' && importNames.includes(node.declaration.name)) {
|
||||||
exportNames.push('default');
|
exportNames.push('default');
|
||||||
// return
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// handle `export { x } from 'something';`, where the export and import are in the same node
|
// Handle:
|
||||||
|
// export { Component } from './Component.astro'
|
||||||
|
// export { Component as AliasedComponent } from './Component.astro'
|
||||||
if (node.source) {
|
if (node.source) {
|
||||||
const resolved = await this.resolve(node.source.value as string, parentInfo.id);
|
const resolved = await this.resolve(node.source.value as string, parentInfo.id);
|
||||||
if (!resolved || resolved.id !== childInfo.id) continue;
|
if (!resolved || resolved.id !== childInfo.id) continue;
|
||||||
|
@ -86,6 +88,9 @@ async function doesParentImportChild(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Handle:
|
||||||
|
// export const AliasedComponent = Component
|
||||||
|
// export const AliasedComponent = Component, let foo = 'bar'
|
||||||
if (node.declaration) {
|
if (node.declaration) {
|
||||||
if (node.declaration.type !== 'VariableDeclaration') continue;
|
if (node.declaration.type !== 'VariableDeclaration') continue;
|
||||||
for (const declarator of node.declaration.declarations) {
|
for (const declarator of node.declaration.declarations) {
|
||||||
|
@ -96,6 +101,9 @@ async function doesParentImportChild(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Handle:
|
||||||
|
// export { Component }
|
||||||
|
// export { Component as AliasedComponent }
|
||||||
for (const specifier of node.specifiers) {
|
for (const specifier of node.specifiers) {
|
||||||
if (importNames.includes(specifier.local.name)) {
|
if (importNames.includes(specifier.local.name)) {
|
||||||
exportNames.push(specifier.exported.name);
|
exportNames.push(specifier.exported.name);
|
||||||
|
@ -116,7 +124,10 @@ async function doesParentImportChild(
|
||||||
return exportNames;
|
return exportNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function vitePluginAnalyzer(internals: BuildInternals): VitePlugin {
|
export function vitePluginAnalyzer(
|
||||||
|
options: StaticBuildOptions,
|
||||||
|
internals: BuildInternals
|
||||||
|
): VitePlugin {
|
||||||
function hoistedScriptScanner() {
|
function hoistedScriptScanner() {
|
||||||
const uniqueHoistedIds = new Map<string, string>();
|
const uniqueHoistedIds = new Map<string, string>();
|
||||||
const pageScripts = new Map<
|
const pageScripts = new Map<
|
||||||
|
@ -140,6 +151,7 @@ export function vitePluginAnalyzer(internals: BuildInternals): VitePlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hoistedScripts.size) {
|
if (hoistedScripts.size) {
|
||||||
|
// These variables are only used for hoisted script analysis optimization
|
||||||
const depthsToChildren = new Map<number, ModuleInfo>();
|
const depthsToChildren = new Map<number, ModuleInfo>();
|
||||||
const depthsToExportNames = new Map<number, string[] | 'dynamic'>();
|
const depthsToExportNames = new Map<number, string[] | 'dynamic'>();
|
||||||
// The component export from the original component file will always be default.
|
// The component export from the original component file will always be default.
|
||||||
|
@ -148,6 +160,8 @@ export function vitePluginAnalyzer(internals: BuildInternals): VitePlugin {
|
||||||
for (const [parentInfo, depth] of walkParentInfos(from, this, function until(importer) {
|
for (const [parentInfo, depth] of walkParentInfos(from, this, function until(importer) {
|
||||||
return isPropagatedAsset(importer);
|
return isPropagatedAsset(importer);
|
||||||
})) {
|
})) {
|
||||||
|
// If hoisted script analysis optimization is enabled, try to analyse and bail early if possible
|
||||||
|
if (options.settings.config.experimental.optimizeHoistedScript) {
|
||||||
depthsToChildren.set(depth, parentInfo);
|
depthsToChildren.set(depth, parentInfo);
|
||||||
// If at any point
|
// If at any point
|
||||||
if (depth > 0) {
|
if (depth > 0) {
|
||||||
|
@ -168,6 +182,7 @@ export function vitePluginAnalyzer(internals: BuildInternals): VitePlugin {
|
||||||
}
|
}
|
||||||
depthsToExportNames.set(depth, doesImport);
|
depthsToExportNames.set(depth, doesImport);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (isPropagatedAsset(parentInfo.id)) {
|
if (isPropagatedAsset(parentInfo.id)) {
|
||||||
for (const [nestedParentInfo] of walkParentInfos(from, this)) {
|
for (const [nestedParentInfo] of walkParentInfos(from, this)) {
|
||||||
|
@ -311,13 +326,16 @@ export function vitePluginAnalyzer(internals: BuildInternals): VitePlugin {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function pluginAnalyzer(internals: BuildInternals): AstroBuildPlugin {
|
export function pluginAnalyzer(
|
||||||
|
options: StaticBuildOptions,
|
||||||
|
internals: BuildInternals
|
||||||
|
): AstroBuildPlugin {
|
||||||
return {
|
return {
|
||||||
build: 'ssr',
|
build: 'ssr',
|
||||||
hooks: {
|
hooks: {
|
||||||
'build:before': () => {
|
'build:before': () => {
|
||||||
return {
|
return {
|
||||||
vitePlugin: vitePluginAnalyzer(internals),
|
vitePlugin: vitePluginAnalyzer(options, internals),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -46,6 +46,7 @@ const ASTRO_CONFIG_DEFAULTS = {
|
||||||
experimental: {
|
experimental: {
|
||||||
assets: false,
|
assets: false,
|
||||||
viewTransitions: false,
|
viewTransitions: false,
|
||||||
|
optimizeHoistedScript: false,
|
||||||
},
|
},
|
||||||
} satisfies AstroUserConfig & { server: { open: boolean } };
|
} satisfies AstroUserConfig & { server: { open: boolean } };
|
||||||
|
|
||||||
|
@ -245,6 +246,10 @@ export const AstroConfigSchema = z.object({
|
||||||
.boolean()
|
.boolean()
|
||||||
.optional()
|
.optional()
|
||||||
.default(ASTRO_CONFIG_DEFAULTS.experimental.viewTransitions),
|
.default(ASTRO_CONFIG_DEFAULTS.experimental.viewTransitions),
|
||||||
|
optimizeHoistedScript: z
|
||||||
|
.boolean()
|
||||||
|
.optional()
|
||||||
|
.default(ASTRO_CONFIG_DEFAULTS.experimental.optimizeHoistedScript),
|
||||||
})
|
})
|
||||||
.passthrough()
|
.passthrough()
|
||||||
.refine(
|
.refine(
|
||||||
|
|
|
@ -3,10 +3,9 @@ const renderer = {
|
||||||
serverEntrypoint: 'astro/jsx/server.js',
|
serverEntrypoint: 'astro/jsx/server.js',
|
||||||
jsxImportSource: 'astro',
|
jsxImportSource: 'astro',
|
||||||
jsxTransformOptions: async () => {
|
jsxTransformOptions: async () => {
|
||||||
const {
|
// @ts-expect-error types not found
|
||||||
default: { default: jsx },
|
const plugin = await import('@babel/plugin-transform-react-jsx');
|
||||||
// @ts-expect-error
|
const jsx = plugin.default?.default ?? plugin.default;
|
||||||
} = await import('@babel/plugin-transform-react-jsx');
|
|
||||||
const { default: astroJSX } = await import('./babel.js');
|
const { default: astroJSX } = await import('./babel.js');
|
||||||
return {
|
return {
|
||||||
plugins: [
|
plugins: [
|
||||||
|
|
|
@ -8,6 +8,9 @@ describe('Hoisted Imports', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: './fixtures/hoisted-imports/',
|
root: './fixtures/hoisted-imports/',
|
||||||
|
experimental: {
|
||||||
|
optimizeHoistedScript: true,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,12 @@
|
||||||
|
|
||||||
- [`1eae2e3f7`](https://github.com/withastro/astro/commit/1eae2e3f7d693c9dfe91c8ccfbe606d32bf2fb81) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Remove support for Node 16. The lowest supported version by Astro and all integrations is now v18.14.1. As a reminder, Node 16 will be deprecated on the 11th September 2023.
|
- [`1eae2e3f7`](https://github.com/withastro/astro/commit/1eae2e3f7d693c9dfe91c8ccfbe606d32bf2fb81) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Remove support for Node 16. The lowest supported version by Astro and all integrations is now v18.14.1. As a reminder, Node 16 will be deprecated on the 11th September 2023.
|
||||||
|
|
||||||
|
## 3.1.12
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- [#7993](https://github.com/withastro/astro/pull/7993) [`315d58f27`](https://github.com/withastro/astro/commit/315d58f27b022c9d4285cf13f445ed18c26c327e) Thanks [@delucis](https://github.com/delucis)! - Add support for more Starlight templates
|
||||||
|
|
||||||
## 3.1.11
|
## 3.1.11
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|
|
@ -106,7 +106,10 @@ Cloudflare has support for adding custom [headers](https://developers.cloudflare
|
||||||
|
|
||||||
### Custom `_routes.json`
|
### Custom `_routes.json`
|
||||||
|
|
||||||
By default, `@astrojs/cloudflare` will generate a `_routes.json` file that lists all files from your `dist/` folder and redirects from the `_redirects` file in the `exclude` array. This will enable Cloudflare to serve files and process static redirects without a function invocation. Creating a custom `_routes.json` will override this automatic optimization and, if not configured manually, cause function invocations that will count against the request limits of your Cloudflare plan.
|
By default, `@astrojs/cloudflare` will generate a `_routes.json` file with `include` and `exclude` rules based on your applications's dynamic and static routes.
|
||||||
|
This will enable Cloudflare to serve files and process static redirects without a function invocation. Creating a custom `_routes.json` will override this automatic optimization and, if not configured manually, cause function invocations that will count against the request limits of your Cloudflare plan.
|
||||||
|
|
||||||
|
See [Cloudflare's documentation](https://developers.cloudflare.com/pages/platform/functions/routing/#create-a-_routesjson-file) for more details.
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,11 @@ const SHIM = `globalThis.process = {
|
||||||
|
|
||||||
const SERVER_BUILD_FOLDER = '/$server_build/';
|
const SERVER_BUILD_FOLDER = '/$server_build/';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These route types are candiates for being part of the `_routes.json` `include` array.
|
||||||
|
*/
|
||||||
|
const potentialFunctionRouteTypes = ['endpoint', 'page'];
|
||||||
|
|
||||||
export default function createIntegration(args?: Options): AstroIntegration {
|
export default function createIntegration(args?: Options): AstroIntegration {
|
||||||
let _config: AstroConfig;
|
let _config: AstroConfig;
|
||||||
let _buildConfig: BuildConfig;
|
let _buildConfig: BuildConfig;
|
||||||
|
@ -253,6 +258,32 @@ export default function createIntegration(args?: Options): AstroIntegration {
|
||||||
// cloudflare to handle static files and support _redirects configuration
|
// cloudflare to handle static files and support _redirects configuration
|
||||||
// (without calling the function)
|
// (without calling the function)
|
||||||
if (!routesExists) {
|
if (!routesExists) {
|
||||||
|
const functionEndpoints = routes
|
||||||
|
// Certain route types, when their prerender option is set to false, a run on the server as function invocations
|
||||||
|
.filter((route) => potentialFunctionRouteTypes.includes(route.type) && !route.prerender)
|
||||||
|
.map((route) => {
|
||||||
|
const includePattern =
|
||||||
|
'/' +
|
||||||
|
route.segments
|
||||||
|
.flat()
|
||||||
|
.map((segment) => (segment.dynamic ? '*' : segment.content))
|
||||||
|
.join('/');
|
||||||
|
|
||||||
|
const regexp = new RegExp(
|
||||||
|
'^\\/' +
|
||||||
|
route.segments
|
||||||
|
.flat()
|
||||||
|
.map((segment) => (segment.dynamic ? '(.*)' : segment.content))
|
||||||
|
.join('\\/') +
|
||||||
|
'$'
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
includePattern,
|
||||||
|
regexp,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
const staticPathList: Array<string> = (
|
const staticPathList: Array<string> = (
|
||||||
await glob(`${fileURLToPath(_buildConfig.client)}/**/*`, {
|
await glob(`${fileURLToPath(_buildConfig.client)}/**/*`, {
|
||||||
cwd: fileURLToPath(_config.outDir),
|
cwd: fileURLToPath(_config.outDir),
|
||||||
|
@ -260,7 +291,7 @@ export default function createIntegration(args?: Options): AstroIntegration {
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.filter((file: string) => cloudflareSpecialFiles.indexOf(file) < 0)
|
.filter((file: string) => cloudflareSpecialFiles.indexOf(file) < 0)
|
||||||
.map((file: string) => `/${file}`);
|
.map((file: string) => `/${file.replace(/\\/g, '/')}`);
|
||||||
|
|
||||||
for (let page of pages) {
|
for (let page of pages) {
|
||||||
let pagePath = prependForwardSlash(page.pathname);
|
let pagePath = prependForwardSlash(page.pathname);
|
||||||
|
@ -323,13 +354,41 @@ export default function createIntegration(args?: Options): AstroIntegration {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
staticPathList.push(...routes.filter((r) => r.type === 'redirect').map((r) => r.route));
|
||||||
|
|
||||||
|
// In order to product the shortest list of patterns, we first try to
|
||||||
|
// include all function endpoints, and then exclude all static paths
|
||||||
|
let include = deduplicatePatterns(
|
||||||
|
functionEndpoints.map((endpoint) => endpoint.includePattern)
|
||||||
|
);
|
||||||
|
let exclude = deduplicatePatterns(
|
||||||
|
staticPathList.filter((file: string) =>
|
||||||
|
functionEndpoints.some((endpoint) => endpoint.regexp.test(file))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Cloudflare requires at least one include pattern:
|
||||||
|
// https://developers.cloudflare.com/pages/platform/functions/routing/#limits
|
||||||
|
// So we add a pattern that we immediately exclude again
|
||||||
|
if (include.length === 0) {
|
||||||
|
include = ['/'];
|
||||||
|
exclude = ['/'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// If using only an exclude list would produce a shorter list of patterns,
|
||||||
|
// we use that instead
|
||||||
|
if (include.length + exclude.length > staticPathList.length) {
|
||||||
|
include = ['/*'];
|
||||||
|
exclude = deduplicatePatterns(staticPathList);
|
||||||
|
}
|
||||||
|
|
||||||
await fs.promises.writeFile(
|
await fs.promises.writeFile(
|
||||||
new URL('./_routes.json', _config.outDir),
|
new URL('./_routes.json', _config.outDir),
|
||||||
JSON.stringify(
|
JSON.stringify(
|
||||||
{
|
{
|
||||||
version: 1,
|
version: 1,
|
||||||
include: ['/*'],
|
include,
|
||||||
exclude: staticPathList,
|
exclude,
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
2
|
2
|
||||||
|
@ -344,3 +403,28 @@ export default function createIntegration(args?: Options): AstroIntegration {
|
||||||
function prependForwardSlash(path: string) {
|
function prependForwardSlash(path: string) {
|
||||||
return path[0] === '/' ? path : '/' + path;
|
return path[0] === '/' ? path : '/' + path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove duplicates and redundant patterns from an `include` or `exclude` list.
|
||||||
|
* Otherwise Cloudflare will throw an error on deployment. Plus, it saves more entries.
|
||||||
|
* E.g. `['/foo/*', '/foo/*', '/foo/bar'] => ['/foo/*']`
|
||||||
|
* @param patterns a list of `include` or `exclude` patterns
|
||||||
|
* @returns a deduplicated list of patterns
|
||||||
|
*/
|
||||||
|
function deduplicatePatterns(patterns: string[]) {
|
||||||
|
const openPatterns: RegExp[] = [];
|
||||||
|
|
||||||
|
return [...new Set(patterns)]
|
||||||
|
.sort((a, b) => a.length - b.length)
|
||||||
|
.filter((pattern) => {
|
||||||
|
if (openPatterns.some((p) => p.test(pattern))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pattern.endsWith('*')) {
|
||||||
|
openPatterns.push(new RegExp(`^${pattern.replace(/(\*\/)*\*$/g, '.*')}`));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
11
packages/integrations/cloudflare/test/fixtures/routesJson/astro.config.mjs
vendored
Normal file
11
packages/integrations/cloudflare/test/fixtures/routesJson/astro.config.mjs
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import { defineConfig } from 'astro/config';
|
||||||
|
import cloudflare from '@astrojs/cloudflare';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
adapter: cloudflare({ mode: 'directory' }),
|
||||||
|
output: 'hybrid',
|
||||||
|
redirects: {
|
||||||
|
'/a/redirect': '/',
|
||||||
|
},
|
||||||
|
srcDir: process.env.SRC
|
||||||
|
});
|
9
packages/integrations/cloudflare/test/fixtures/routesJson/package.json
vendored
Normal file
9
packages/integrations/cloudflare/test/fixtures/routesJson/package.json
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"name": "@test/astro-cloudflare-routes-json",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@astrojs/cloudflare": "workspace:*",
|
||||||
|
"astro": "workspace:*"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
export const prerender=false;
|
||||||
|
---
|
||||||
|
|
||||||
|
ok
|
5
packages/integrations/cloudflare/test/fixtures/routesJson/src/dynamicOnly/pages/index.astro
vendored
Normal file
5
packages/integrations/cloudflare/test/fixtures/routesJson/src/dynamicOnly/pages/index.astro
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
export const prerender=false;
|
||||||
|
---
|
||||||
|
|
||||||
|
ok
|
5
packages/integrations/cloudflare/test/fixtures/routesJson/src/mixed/pages/a/[...rest].astro
vendored
Normal file
5
packages/integrations/cloudflare/test/fixtures/routesJson/src/mixed/pages/a/[...rest].astro
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
export const prerender=false;
|
||||||
|
---
|
||||||
|
|
||||||
|
ok
|
5
packages/integrations/cloudflare/test/fixtures/routesJson/src/mixed/pages/a/[id].astro
vendored
Normal file
5
packages/integrations/cloudflare/test/fixtures/routesJson/src/mixed/pages/a/[id].astro
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
export const prerender=false;
|
||||||
|
---
|
||||||
|
|
||||||
|
ok
|
1
packages/integrations/cloudflare/test/fixtures/routesJson/src/mixed/pages/a/endpoint.ts
vendored
Normal file
1
packages/integrations/cloudflare/test/fixtures/routesJson/src/mixed/pages/a/endpoint.ts
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export const prerender = false;
|
1
packages/integrations/cloudflare/test/fixtures/routesJson/src/mixed/pages/a/index.astro
vendored
Normal file
1
packages/integrations/cloudflare/test/fixtures/routesJson/src/mixed/pages/a/index.astro
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ok
|
1
packages/integrations/cloudflare/test/fixtures/routesJson/src/mixed/pages/b/index.html
vendored
Normal file
1
packages/integrations/cloudflare/test/fixtures/routesJson/src/mixed/pages/b/index.html
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ok
|
1
packages/integrations/cloudflare/test/fixtures/routesJson/src/mixed/public/public.txt
vendored
Normal file
1
packages/integrations/cloudflare/test/fixtures/routesJson/src/mixed/public/public.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ok
|
1
packages/integrations/cloudflare/test/fixtures/routesJson/src/staticOnly/pages/index.astro
vendored
Normal file
1
packages/integrations/cloudflare/test/fixtures/routesJson/src/staticOnly/pages/index.astro
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ok
|
|
@ -18,13 +18,14 @@ describe('Prerendering', () => {
|
||||||
fixture.clean();
|
fixture.clean();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('includes prerendered routes in the routes.json config', async () => {
|
it('includes non prerendered routes in the routes.json config', async () => {
|
||||||
const foundRoutes = JSON.parse(await fixture.readFile('/_routes.json')).exclude.map((r) =>
|
const foundRoutes = JSON.parse(await fixture.readFile('/_routes.json'));
|
||||||
r.replace(/\\/g, '/')
|
|
||||||
);
|
|
||||||
const expectedExcludedRoutes = ['/_worker.js', '/one/index.html', '/one/'];
|
|
||||||
|
|
||||||
expect(foundRoutes.every((element) => expectedExcludedRoutes.includes(element))).to.be.true;
|
expect(foundRoutes).to.deep.equal({
|
||||||
|
version: 1,
|
||||||
|
include: ['/'],
|
||||||
|
exclude: [],
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -45,12 +46,13 @@ describe('Hybrid rendering', () => {
|
||||||
delete process.env.PRERENDER;
|
delete process.env.PRERENDER;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('includes prerendered routes in the routes.json config', async () => {
|
it('includes non prerendered routes in the routes.json config', async () => {
|
||||||
const foundRoutes = JSON.parse(await fixture.readFile('/_routes.json')).exclude.map((r) =>
|
const foundRoutes = JSON.parse(await fixture.readFile('/_routes.json'));
|
||||||
r.replace(/\\/g, '/')
|
|
||||||
);
|
|
||||||
const expectedExcludedRoutes = ['/_worker.js', '/index.html', '/'];
|
|
||||||
|
|
||||||
expect(foundRoutes.every((element) => expectedExcludedRoutes.includes(element))).to.be.true;
|
expect(foundRoutes).to.deep.equal({
|
||||||
|
version: 1,
|
||||||
|
include: ['/one'],
|
||||||
|
exclude: [],
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
78
packages/integrations/cloudflare/test/routesJson.js
Normal file
78
packages/integrations/cloudflare/test/routesJson.js
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
import { expect } from 'chai';
|
||||||
|
import { loadFixture } from './test-utils.js';
|
||||||
|
|
||||||
|
/** @type {import('./test-utils.js').Fixture} */
|
||||||
|
describe('_routes.json generation', () => {
|
||||||
|
after(() => {
|
||||||
|
delete process.env.SRC;
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('of both functions and static files', () => {
|
||||||
|
let fixture;
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
process.env.SRC = './src/mixed';
|
||||||
|
fixture = await loadFixture({
|
||||||
|
root: './fixtures/routesJson/',
|
||||||
|
});
|
||||||
|
await fixture.build();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('creates `include` for functions and `exclude` for static files where needed', async () => {
|
||||||
|
const _routesJson = await fixture.readFile('/_routes.json');
|
||||||
|
const routes = JSON.parse(_routesJson);
|
||||||
|
|
||||||
|
expect(routes).to.deep.equal({
|
||||||
|
version: 1,
|
||||||
|
include: ['/a/*'],
|
||||||
|
exclude: ['/a/', '/a/redirect', '/a/index.html'],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('of only functions', () => {
|
||||||
|
let fixture;
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
process.env.SRC = './src/dynamicOnly';
|
||||||
|
fixture = await loadFixture({
|
||||||
|
root: './fixtures/routesJson/',
|
||||||
|
});
|
||||||
|
await fixture.build();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('creates a wildcard `include` and `exclude` only for the redirect', async () => {
|
||||||
|
const _routesJson = await fixture.readFile('/_routes.json');
|
||||||
|
const routes = JSON.parse(_routesJson);
|
||||||
|
|
||||||
|
expect(routes).to.deep.equal({
|
||||||
|
version: 1,
|
||||||
|
include: ['/*'],
|
||||||
|
exclude: ['/a/redirect'],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('of only static files', () => {
|
||||||
|
let fixture;
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
process.env.SRC = './src/staticOnly';
|
||||||
|
fixture = await loadFixture({
|
||||||
|
root: './fixtures/routesJson/',
|
||||||
|
});
|
||||||
|
await fixture.build();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('create only one `include` and `exclude` that are supposed to match nothing', async () => {
|
||||||
|
const _routesJson = await fixture.readFile('/_routes.json');
|
||||||
|
const routes = JSON.parse(_routesJson);
|
||||||
|
|
||||||
|
expect(routes).to.deep.equal({
|
||||||
|
version: 1,
|
||||||
|
include: ['/'],
|
||||||
|
exclude: ['/'],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -6,6 +6,12 @@
|
||||||
|
|
||||||
- [`1eae2e3f7`](https://github.com/withastro/astro/commit/1eae2e3f7d693c9dfe91c8ccfbe606d32bf2fb81) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Remove support for Node 16. The lowest supported version by Astro and all integrations is now v18.14.1. As a reminder, Node 16 will be deprecated on the 11th September 2023.
|
- [`1eae2e3f7`](https://github.com/withastro/astro/commit/1eae2e3f7d693c9dfe91c8ccfbe606d32bf2fb81) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Remove support for Node 16. The lowest supported version by Astro and all integrations is now v18.14.1. As a reminder, Node 16 will be deprecated on the 11th September 2023.
|
||||||
|
|
||||||
|
## 2.2.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- [#8007](https://github.com/withastro/astro/pull/8007) [`58b121d42`](https://github.com/withastro/astro/commit/58b121d42a9f58a5a992f0c378b036f37e9715fc) Thanks [@paperdave](https://github.com/paperdave)! - Support Bun by adjusting how `@babel/plugin-transform-react-jsx` is imported.
|
||||||
|
|
||||||
## 2.2.1
|
## 2.2.1
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|
|
@ -7,10 +7,9 @@ function getRenderer(development: boolean): AstroRenderer {
|
||||||
serverEntrypoint: '@astrojs/preact/server.js',
|
serverEntrypoint: '@astrojs/preact/server.js',
|
||||||
jsxImportSource: 'preact',
|
jsxImportSource: 'preact',
|
||||||
jsxTransformOptions: async () => {
|
jsxTransformOptions: async () => {
|
||||||
const {
|
|
||||||
default: { default: jsx },
|
|
||||||
// @ts-expect-error types not found
|
// @ts-expect-error types not found
|
||||||
} = await import('@babel/plugin-transform-react-jsx');
|
const plugin = await import('@babel/plugin-transform-react-jsx');
|
||||||
|
const jsx = plugin.default?.default ?? plugin.default;
|
||||||
return {
|
return {
|
||||||
plugins: [jsx({}, { runtime: 'automatic', importSource: 'preact' })],
|
plugins: [jsx({}, { runtime: 'automatic', importSource: 'preact' })],
|
||||||
};
|
};
|
||||||
|
@ -25,10 +24,9 @@ function getCompatRenderer(development: boolean): AstroRenderer {
|
||||||
serverEntrypoint: '@astrojs/preact/server.js',
|
serverEntrypoint: '@astrojs/preact/server.js',
|
||||||
jsxImportSource: 'react',
|
jsxImportSource: 'react',
|
||||||
jsxTransformOptions: async () => {
|
jsxTransformOptions: async () => {
|
||||||
const {
|
|
||||||
default: { default: jsx },
|
|
||||||
// @ts-expect-error types not found
|
// @ts-expect-error types not found
|
||||||
} = await import('@babel/plugin-transform-react-jsx');
|
const plugin = await import('@babel/plugin-transform-react-jsx');
|
||||||
|
const jsx = plugin.default?.default ?? plugin.default;
|
||||||
return {
|
return {
|
||||||
plugins: [
|
plugins: [
|
||||||
jsx({}, { runtime: 'automatic', importSource: 'preact/compat' }),
|
jsx({}, { runtime: 'automatic', importSource: 'preact/compat' }),
|
||||||
|
|
Loading…
Reference in a new issue