From 63141f3f3e4a57d2f55ccfebd7e506ea1033a1ab Mon Sep 17 00:00:00 2001
From: Erika <3019731+Princesseuh@users.noreply.github.com>
Date: Fri, 22 Sep 2023 14:28:03 +0200
Subject: [PATCH 01/90] fix: properly generate code for multiple images in same
markdown file (#8633)
---
.changeset/mean-forks-ring.md | 5 +++++
packages/astro/src/vite-plugin-markdown/index.ts | 6 ++++--
packages/astro/test/core-image.test.js | 2 +-
packages/astro/test/fixtures/core-image/src/pages/post.md | 1 +
4 files changed, 11 insertions(+), 3 deletions(-)
create mode 100644 .changeset/mean-forks-ring.md
diff --git a/.changeset/mean-forks-ring.md b/.changeset/mean-forks-ring.md
new file mode 100644
index 000000000..1aa40a6b5
--- /dev/null
+++ b/.changeset/mean-forks-ring.md
@@ -0,0 +1,5 @@
+---
+'astro': patch
+---
+
+Fix build not working when having multiple images in the same Markdown file
diff --git a/packages/astro/src/vite-plugin-markdown/index.ts b/packages/astro/src/vite-plugin-markdown/index.ts
index 7d4a97392..dfc0bc0e0 100644
--- a/packages/astro/src/vite-plugin-markdown/index.ts
+++ b/packages/astro/src/vite-plugin-markdown/index.ts
@@ -120,13 +120,15 @@ export default function markdown({ settings, logger }: AstroPluginOptions): Plug
${layout ? `import Layout from ${JSON.stringify(layout)};` : ''}
import { getImage } from "astro:assets";
- ${imagePaths.map((entry) => `import Astro__${entry.safeName} from ${JSON.stringify(entry.raw)};`)}
+ ${imagePaths
+ .map((entry) => `import Astro__${entry.safeName} from ${JSON.stringify(entry.raw)};`)
+ .join('\n')}
const images = async function() {
return {
${imagePaths
.map((entry) => `"${entry.raw}": await getImage({src: Astro__${entry.safeName}})`)
- .join('\n')}
+ .join(',\n')}
}
}
diff --git a/packages/astro/test/core-image.test.js b/packages/astro/test/core-image.test.js
index 7a0a46822..a6ee4342c 100644
--- a/packages/astro/test/core-image.test.js
+++ b/packages/astro/test/core-image.test.js
@@ -310,7 +310,7 @@ describe('astro:image', () => {
it('Adds the
tag', () => {
let $img = $('img');
- expect($img).to.have.a.lengthOf(1);
+ expect($img).to.have.a.lengthOf(2);
// Verbose test for the full URL to make sure the image went through the full pipeline
expect(
diff --git a/packages/astro/test/fixtures/core-image/src/pages/post.md b/packages/astro/test/fixtures/core-image/src/pages/post.md
index 98da01ce4..822ed6189 100644
--- a/packages/astro/test/fixtures/core-image/src/pages/post.md
+++ b/packages/astro/test/fixtures/core-image/src/pages/post.md
@@ -1,3 +1,4 @@

+
Image worked
From bd00ad776db9d6d3bde323d0ecf8065f186b3a57 Mon Sep 17 00:00:00 2001
From: Yan Thomas <61414485+Yan-Thomas@users.noreply.github.com>
Date: Fri, 22 Sep 2023 09:57:27 -0300
Subject: [PATCH 02/90] Fix subheading inconsistency (#8623)
---
packages/integrations/node/README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/packages/integrations/node/README.md b/packages/integrations/node/README.md
index 5b49a2716..ecc4eb02f 100644
--- a/packages/integrations/node/README.md
+++ b/packages/integrations/node/README.md
@@ -2,7 +2,7 @@
This adapter allows Astro to deploy your SSR site to Node targets.
-- [Why Astro Node](#why-astro-node)
+- [Why Astro Node.js](#why-astro-nodejs)
- [Installation](#installation)
- [Configuration](#configuration)
- [Usage](#usage)
@@ -10,7 +10,7 @@ This adapter allows Astro to deploy your SSR site to Node targets.
- [Contributing](#contributing)
- [Changelog](#changelog)
-## Why @astrojs/node
+## Why Astro Node.js
If you're using Astro as a static site builder—its behavior out of the box—you don't need an adapter.
From b64dd45c0d641f9f2ed997e2cbdf8a6b0193195f Mon Sep 17 00:00:00 2001
From: Reuben Tier <64310361+TheOtterlord@users.noreply.github.com>
Date: Fri, 22 Sep 2023 14:18:46 +0100
Subject: [PATCH 03/90] Fix behaviour regression in create-astro (#8634)
---
.changeset/neat-islands-wink.md | 5 +++++
packages/create-astro/src/actions/template.ts | 11 +++++------
packages/create-astro/test/template.test.js | 7 +++++++
3 files changed, 17 insertions(+), 6 deletions(-)
create mode 100644 .changeset/neat-islands-wink.md
diff --git a/.changeset/neat-islands-wink.md b/.changeset/neat-islands-wink.md
new file mode 100644
index 000000000..fff9012ad
--- /dev/null
+++ b/.changeset/neat-islands-wink.md
@@ -0,0 +1,5 @@
+---
+'create-astro': patch
+---
+
+Fix `--yes` behaviour to prevent it overriding `--template`
diff --git a/packages/create-astro/src/actions/template.ts b/packages/create-astro/src/actions/template.ts
index 253c9fab1..eaebe2360 100644
--- a/packages/create-astro/src/actions/template.ts
+++ b/packages/create-astro/src/actions/template.ts
@@ -9,10 +9,11 @@ import { error, info, spinner, title } from '../messages.js';
export async function template(
ctx: Pick
) {
- if (ctx.yes) {
- ctx.template = 'basics';
- await info('tmpl', `Using ${color.reset(ctx.template)}${color.dim(' as project template')}`);
- } else if (!ctx.template) {
+ if (!ctx.template && ctx.yes) ctx.template = 'basics';
+
+ if (ctx.template) {
+ await info('tmpl', `Using ${color.reset(ctx.template)}${color.dim(' as project template')}`);
+ } else {
const { template: tmpl } = await ctx.prompt({
name: 'template',
type: 'select',
@@ -26,8 +27,6 @@ export async function template(
],
});
ctx.template = tmpl;
- } else {
- await info('tmpl', `Using ${color.reset(ctx.template)}${color.dim(' as project template')}`);
}
if (ctx.dryRun) {
diff --git a/packages/create-astro/test/template.test.js b/packages/create-astro/test/template.test.js
index 66c7f5446..cf6b45f77 100644
--- a/packages/create-astro/test/template.test.js
+++ b/packages/create-astro/test/template.test.js
@@ -33,4 +33,11 @@ describe('template', () => {
expect(fixture.hasMessage('Using blog as project template')).to.be.true;
});
+
+ it('minimal (--yes)', async () => {
+ const context = { template: 'minimal', cwd: '', dryRun: true, yes: true, prompt: () => {} };
+ await template(context);
+
+ expect(fixture.hasMessage('Using minimal as project template')).to.be.true;
+ })
});
From f35a55bd4f5c722a82326f351e1adb448b6f9476 Mon Sep 17 00:00:00 2001
From: bluwy
Date: Fri, 22 Sep 2023 13:20:50 +0000
Subject: [PATCH 04/90] [ci] format
---
packages/create-astro/src/actions/template.ts | 8 ++++----
packages/create-astro/test/template.test.js | 10 +++++-----
2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/packages/create-astro/src/actions/template.ts b/packages/create-astro/src/actions/template.ts
index eaebe2360..8d22e95b1 100644
--- a/packages/create-astro/src/actions/template.ts
+++ b/packages/create-astro/src/actions/template.ts
@@ -9,11 +9,11 @@ import { error, info, spinner, title } from '../messages.js';
export async function template(
ctx: Pick
) {
- if (!ctx.template && ctx.yes) ctx.template = 'basics';
+ if (!ctx.template && ctx.yes) ctx.template = 'basics';
- if (ctx.template) {
- await info('tmpl', `Using ${color.reset(ctx.template)}${color.dim(' as project template')}`);
- } else {
+ if (ctx.template) {
+ await info('tmpl', `Using ${color.reset(ctx.template)}${color.dim(' as project template')}`);
+ } else {
const { template: tmpl } = await ctx.prompt({
name: 'template',
type: 'select',
diff --git a/packages/create-astro/test/template.test.js b/packages/create-astro/test/template.test.js
index cf6b45f77..aef7e1944 100644
--- a/packages/create-astro/test/template.test.js
+++ b/packages/create-astro/test/template.test.js
@@ -34,10 +34,10 @@ describe('template', () => {
expect(fixture.hasMessage('Using blog as project template')).to.be.true;
});
- it('minimal (--yes)', async () => {
- const context = { template: 'minimal', cwd: '', dryRun: true, yes: true, prompt: () => {} };
- await template(context);
+ it('minimal (--yes)', async () => {
+ const context = { template: 'minimal', cwd: '', dryRun: true, yes: true, prompt: () => {} };
+ await template(context);
- expect(fixture.hasMessage('Using minimal as project template')).to.be.true;
- })
+ expect(fixture.hasMessage('Using minimal as project template')).to.be.true;
+ });
});
From a3bee1477efe1da2107ea961095212f94ba45962 Mon Sep 17 00:00:00 2001
From: Paul Valladares <85648028+dreyfus92@users.noreply.github.com>
Date: Fri, 22 Sep 2023 08:47:40 -0600
Subject: [PATCH 05/90] Update: Improve manual install guide of
`@astrojs/tailwind` integration (#8619)
---
packages/integrations/tailwind/README.md | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/packages/integrations/tailwind/README.md b/packages/integrations/tailwind/README.md
index 8634d4b16..269931e1e 100644
--- a/packages/integrations/tailwind/README.md
+++ b/packages/integrations/tailwind/README.md
@@ -61,6 +61,26 @@ export default defineConfig({
});
```
+Then, create a `tailwind.config.cjs` file in your project's root directory. You can use the following command to generate a basic configuration file for you:
+
+```sh
+npx tailwindcss init
+```
+
+Finally, add this basic configuration to your `tailwind.config.cjs` file:
+
+```js ins={4} "content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}']"
+// tailwind.config.cjs
+/** @type {import('tailwindcss').Config} */
+module.exports = {
+ content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],
+ theme: {
+ extend: {},
+ },
+ plugins: [],
+}
+```
+
## Usage
When you install the integration, Tailwind's utility classes should be ready to go right away. Head to the [Tailwind docs](https://tailwindcss.com/docs/utility-first) to learn how to use Tailwind, and if you see a utility class you want to try, add it to any HTML element to your project!
From b1310e6f13c029e880145cc08a7f31129412a06c Mon Sep 17 00:00:00 2001
From: bluwy
Date: Fri, 22 Sep 2023 14:49:43 +0000
Subject: [PATCH 06/90] [ci] format
---
packages/integrations/tailwind/README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/integrations/tailwind/README.md b/packages/integrations/tailwind/README.md
index 269931e1e..a0225db77 100644
--- a/packages/integrations/tailwind/README.md
+++ b/packages/integrations/tailwind/README.md
@@ -78,7 +78,7 @@ module.exports = {
extend: {},
},
plugins: [],
-}
+};
```
## Usage
From faeead42325f378f9edac4e081eb7d6d50905136 Mon Sep 17 00:00:00 2001
From: Adrian Lyjak
Date: Fri, 22 Sep 2023 10:58:00 -0400
Subject: [PATCH 07/90] feat(@astrojs/cloudflare): Add support for wasm module
imports (#8542)
Co-authored-by: Sarah Rainsberger
---
.changeset/shy-cycles-obey.md | 5 +
packages/astro/test/test-utils.js | 1 +
packages/integrations/cloudflare/README.md | 43 +++++
packages/integrations/cloudflare/package.json | 4 +-
packages/integrations/cloudflare/src/index.ts | 144 ++++++++++++----
.../cloudflare/src/wasm-module-loader.ts | 119 +++++++++++++
.../cloudflare/test/basics.test.js | 16 +-
.../integrations/cloudflare/test/cf.test.js | 18 +-
.../cloudflare/test/directory.test.js | 1 +
.../fixtures/wasm-directory/astro.config.mjs | 10 ++
.../test/fixtures/wasm-directory/package.json | 9 +
.../wasm-directory/src/pages/index.ts | 18 ++
.../fixtures/wasm-directory/src/util/add.wasm | Bin 0 -> 41 bytes
.../wasm-function-per-route/astro.config.mjs | 12 ++
.../wasm-function-per-route/package.json | 9 +
.../src/pages/deeply/nested/route.ts | 14 ++
.../src/pages/index.ts | 14 ++
.../wasm-function-per-route/src/util/add.ts | 6 +
.../wasm-function-per-route/src/util/add.wasm | Bin 0 -> 41 bytes
.../src/util/indirection.ts | 9 +
.../test/fixtures/wasm/astro.config.mjs | 9 +
.../test/fixtures/wasm/package.json | 9 +
.../fixtures/wasm/src/pages/add/[a]/[b].ts | 20 +++
.../test/fixtures/wasm/src/pages/hybrid.ts | 16 ++
.../test/fixtures/wasm/src/util/add.wasm | Bin 0 -> 41 bytes
.../test/function-per-route.test.js | 3 +-
.../cloudflare/test/runtime.test.js | 16 +-
.../cloudflare/test/test-utils.js | 157 +++++++++++++-----
.../cloudflare/test/wasm-directory.test.js | 36 ++++
.../test/wasm-function-per-route.test.js | 41 +++++
.../integrations/cloudflare/test/wasm.test.js | 85 ++++++++++
.../cloudflare/test/with-solid-js.test.js | 16 +-
pnpm-lock.yaml | 49 +++---
33 files changed, 787 insertions(+), 122 deletions(-)
create mode 100644 .changeset/shy-cycles-obey.md
create mode 100644 packages/integrations/cloudflare/src/wasm-module-loader.ts
create mode 100644 packages/integrations/cloudflare/test/fixtures/wasm-directory/astro.config.mjs
create mode 100644 packages/integrations/cloudflare/test/fixtures/wasm-directory/package.json
create mode 100644 packages/integrations/cloudflare/test/fixtures/wasm-directory/src/pages/index.ts
create mode 100644 packages/integrations/cloudflare/test/fixtures/wasm-directory/src/util/add.wasm
create mode 100644 packages/integrations/cloudflare/test/fixtures/wasm-function-per-route/astro.config.mjs
create mode 100644 packages/integrations/cloudflare/test/fixtures/wasm-function-per-route/package.json
create mode 100644 packages/integrations/cloudflare/test/fixtures/wasm-function-per-route/src/pages/deeply/nested/route.ts
create mode 100644 packages/integrations/cloudflare/test/fixtures/wasm-function-per-route/src/pages/index.ts
create mode 100644 packages/integrations/cloudflare/test/fixtures/wasm-function-per-route/src/util/add.ts
create mode 100644 packages/integrations/cloudflare/test/fixtures/wasm-function-per-route/src/util/add.wasm
create mode 100644 packages/integrations/cloudflare/test/fixtures/wasm-function-per-route/src/util/indirection.ts
create mode 100644 packages/integrations/cloudflare/test/fixtures/wasm/astro.config.mjs
create mode 100644 packages/integrations/cloudflare/test/fixtures/wasm/package.json
create mode 100644 packages/integrations/cloudflare/test/fixtures/wasm/src/pages/add/[a]/[b].ts
create mode 100644 packages/integrations/cloudflare/test/fixtures/wasm/src/pages/hybrid.ts
create mode 100644 packages/integrations/cloudflare/test/fixtures/wasm/src/util/add.wasm
create mode 100644 packages/integrations/cloudflare/test/wasm-directory.test.js
create mode 100644 packages/integrations/cloudflare/test/wasm-function-per-route.test.js
create mode 100644 packages/integrations/cloudflare/test/wasm.test.js
diff --git a/.changeset/shy-cycles-obey.md b/.changeset/shy-cycles-obey.md
new file mode 100644
index 000000000..2c79702ae
--- /dev/null
+++ b/.changeset/shy-cycles-obey.md
@@ -0,0 +1,5 @@
+---
+'@astrojs/cloudflare': minor
+---
+
+Add support for loading wasm modules in the cloudflare adapter
diff --git a/packages/astro/test/test-utils.js b/packages/astro/test/test-utils.js
index fafd3046c..e71daa9ba 100644
--- a/packages/astro/test/test-utils.js
+++ b/packages/astro/test/test-utils.js
@@ -30,6 +30,7 @@ process.env.ASTRO_TELEMETRY_DISABLED = true;
* @typedef {Object} Fixture
* @property {typeof build} build
* @property {(url: string) => string} resolveUrl
+ * @property {(path: string) => Promise} pathExists
* @property {(url: string, opts: Parameters[1]) => Promise} fetch
* @property {(path: string) => Promise} readFile
* @property {(path: string, updater: (content: string) => string) => Promise} writeFile
diff --git a/packages/integrations/cloudflare/README.md b/packages/integrations/cloudflare/README.md
index 719a5688c..1a1419cff 100644
--- a/packages/integrations/cloudflare/README.md
+++ b/packages/integrations/cloudflare/README.md
@@ -191,6 +191,49 @@ export default defineConfig({
});
```
+## Wasm module imports
+
+`wasmModuleImports: boolean`
+
+default: `false`
+
+Whether or not to import `.wasm` files [directly as ES modules](https://github.com/WebAssembly/esm-integration/tree/main/proposals/esm-integration).
+
+Add `wasmModuleImports: true` to `astro.config.mjs` to enable in both the Cloudflare build and the Astro dev server.
+
+```diff
+// astro.config.mjs
+import {defineConfig} from "astro/config";
+import cloudflare from '@astrojs/cloudflare';
+
+export default defineConfig({
+ adapter: cloudflare({
++ wasmModuleImports: true
+ }),
+ output: 'server'
+})
+```
+
+Once enabled, you can import a web assembly module in Astro with a `.wasm?module` import.
+
+The following is an example of importing a Wasm module that then responds to requests by adding the request's number parameters together.
+
+```javascript
+// pages/add/[a]/[b].js
+import mod from '../util/add.wasm?module';
+
+// instantiate ahead of time to share module
+const addModule: any = new WebAssembly.Instance(mod);
+
+export async function GET(context) {
+ const a = Number.parseInt(context.params.a);
+ const b = Number.parseInt(context.params.b);
+ return new Response(`${addModule.exports.add(a, b)}`);
+}
+```
+
+While this example is trivial, Wasm can be used to accelerate computationally intensive operations which do not involve significant I/O such as embedding an image processing library.
+
## Headers, Redirects and function invocation routes
Cloudflare has support for adding custom [headers](https://developers.cloudflare.com/pages/platform/headers/), configuring static [redirects](https://developers.cloudflare.com/pages/platform/redirects/) and defining which routes should [invoke functions](https://developers.cloudflare.com/pages/platform/functions/routing/#function-invocation-routes). Cloudflare looks for `_headers`, `_redirects`, and `_routes.json` files in your build output directory to configure these features. This means they should be placed in your Astro project’s `public/` directory.
diff --git a/packages/integrations/cloudflare/package.json b/packages/integrations/cloudflare/package.json
index 644b36bc7..ea175e438 100644
--- a/packages/integrations/cloudflare/package.json
+++ b/packages/integrations/cloudflare/package.json
@@ -48,7 +48,8 @@
"dotenv": "^16.3.1",
"esbuild": "^0.19.2",
"find-up": "^6.3.0",
- "tiny-glob": "^0.2.9"
+ "tiny-glob": "^0.2.9",
+ "vite": "^4.4.9"
},
"peerDependencies": {
"astro": "workspace:^3.1.2"
@@ -59,7 +60,6 @@
"astro-scripts": "workspace:*",
"chai": "^4.3.7",
"cheerio": "1.0.0-rc.12",
- "kill-port": "^2.0.1",
"mocha": "^10.2.0",
"wrangler": "^3.5.1"
}
diff --git a/packages/integrations/cloudflare/src/index.ts b/packages/integrations/cloudflare/src/index.ts
index 24c22d8f1..4ae43a110 100644
--- a/packages/integrations/cloudflare/src/index.ts
+++ b/packages/integrations/cloudflare/src/index.ts
@@ -9,10 +9,11 @@ import { AstroError } from 'astro/errors';
import esbuild from 'esbuild';
import * as fs from 'node:fs';
import * as os from 'node:os';
-import { sep } from 'node:path';
+import { basename, dirname, relative, sep } from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';
import glob from 'tiny-glob';
import { getEnvVars } from './parser.js';
+import { wasmModuleLoader } from './wasm-module-loader.js';
export type { AdvancedRuntime } from './server.advanced.js';
export type { DirectoryRuntime } from './server.directory.js';
@@ -26,11 +27,13 @@ type Options = {
* 'remote': use a dynamic real-live req.cf object, and env vars defined in wrangler.toml & .dev.vars (astro dev is enough)
*/
runtime?: 'off' | 'local' | 'remote';
+ wasmModuleImports?: boolean;
};
interface BuildConfig {
server: URL;
client: URL;
+ assets: string;
serverEntry: string;
split?: boolean;
}
@@ -189,6 +192,15 @@ export default function createIntegration(args?: Options): AstroIntegration {
serverEntry: '_worker.mjs',
redirects: false,
},
+ vite: {
+ // load .wasm files as WebAssembly modules
+ plugins: [
+ wasmModuleLoader({
+ disabled: !args?.wasmModuleImports,
+ assetsDirectory: config.build.assets,
+ }),
+ ],
+ },
});
},
'astro:config:done': ({ setAdapter, config }) => {
@@ -280,6 +292,7 @@ export default function createIntegration(args?: Options): AstroIntegration {
},
'astro:build:done': async ({ pages, routes, dir }) => {
const functionsUrl = new URL('functions/', _config.root);
+ const assetsUrl = new URL(_buildConfig.assets, _buildConfig.client);
if (isModeDirectory) {
await fs.promises.mkdir(functionsUrl, { recursive: true });
@@ -291,36 +304,71 @@ export default function createIntegration(args?: Options): AstroIntegration {
const entryPaths = entryPointsURL.map((entry) => fileURLToPath(entry));
const outputUrl = new URL('$astro', _buildConfig.server);
const outputDir = fileURLToPath(outputUrl);
+ //
+ // Sadly, when wasmModuleImports is enabled, this needs to build esbuild for each depth of routes/entrypoints
+ // independently so that relative import paths to the assets are the correct depth of '../' traversals
+ // This is inefficient, so wasmModuleImports is opt-in. This could potentially be improved in the future by
+ // taking advantage of the esbuild "onEnd" hook to rewrite import code per entry point relative to where the final
+ // destination of the entrypoint is
+ const entryPathsGroupedByDepth = !args.wasmModuleImports
+ ? [entryPaths]
+ : entryPaths
+ .reduce((sum, thisPath) => {
+ const depthFromRoot = thisPath.split(sep).length;
+ sum.set(depthFromRoot, (sum.get(depthFromRoot) || []).concat(thisPath));
+ return sum;
+ }, new Map())
+ .values();
- await esbuild.build({
- target: 'es2020',
- platform: 'browser',
- conditions: ['workerd', 'worker', 'browser'],
- external: [
- 'node:assert',
- 'node:async_hooks',
- 'node:buffer',
- 'node:diagnostics_channel',
- 'node:events',
- 'node:path',
- 'node:process',
- 'node:stream',
- 'node:string_decoder',
- 'node:util',
- ],
- entryPoints: entryPaths,
- outdir: outputDir,
- allowOverwrite: true,
- format: 'esm',
- bundle: true,
- minify: _config.vite?.build?.minify !== false,
- banner: {
- js: SHIM,
- },
- logOverride: {
- 'ignored-bare-import': 'silent',
- },
- });
+ for (const pathsGroup of entryPathsGroupedByDepth) {
+ // for some reason this exports to "entry.pages" on windows instead of "pages" on unix environments.
+ // This deduces the name of the "pages" build directory
+ const pagesDirname = relative(fileURLToPath(_buildConfig.server), pathsGroup[0]).split(
+ sep
+ )[0];
+ const absolutePagesDirname = fileURLToPath(new URL(pagesDirname, _buildConfig.server));
+ const urlWithinFunctions = new URL(
+ relative(absolutePagesDirname, pathsGroup[0]),
+ functionsUrl
+ );
+ const relativePathToAssets = relative(
+ dirname(fileURLToPath(urlWithinFunctions)),
+ fileURLToPath(assetsUrl)
+ );
+ await esbuild.build({
+ target: 'es2020',
+ platform: 'browser',
+ conditions: ['workerd', 'worker', 'browser'],
+ external: [
+ 'node:assert',
+ 'node:async_hooks',
+ 'node:buffer',
+ 'node:diagnostics_channel',
+ 'node:events',
+ 'node:path',
+ 'node:process',
+ 'node:stream',
+ 'node:string_decoder',
+ 'node:util',
+ ],
+ entryPoints: pathsGroup,
+ outbase: absolutePagesDirname,
+ outdir: outputDir,
+ allowOverwrite: true,
+ format: 'esm',
+ bundle: true,
+ minify: _config.vite?.build?.minify !== false,
+ banner: {
+ js: SHIM,
+ },
+ logOverride: {
+ 'ignored-bare-import': 'silent',
+ },
+ plugins: !args?.wasmModuleImports
+ ? []
+ : [rewriteWasmImportPath({ relativePathToAssets })],
+ });
+ }
const outputFiles: Array = await glob(`**/*`, {
cwd: outputDir,
@@ -393,6 +441,15 @@ export default function createIntegration(args?: Options): AstroIntegration {
logOverride: {
'ignored-bare-import': 'silent',
},
+ plugins: !args?.wasmModuleImports
+ ? []
+ : [
+ rewriteWasmImportPath({
+ relativePathToAssets: isModeDirectory
+ ? relative(fileURLToPath(functionsUrl), fileURLToPath(assetsUrl))
+ : relative(fileURLToPath(_buildConfig.client), fileURLToPath(assetsUrl)),
+ }),
+ ],
});
// Rename to worker.js
@@ -602,3 +659,30 @@ function deduplicatePatterns(patterns: string[]) {
return true;
});
}
+
+/**
+ *
+ * @param relativePathToAssets - relative path from the final location for the current esbuild output bundle, to the assets directory.
+ */
+function rewriteWasmImportPath({
+ relativePathToAssets,
+}: {
+ relativePathToAssets: string;
+}): esbuild.Plugin {
+ return {
+ name: 'wasm-loader',
+ setup(build) {
+ build.onResolve({ filter: /.*\.wasm.mjs$/ }, (args) => {
+ const updatedPath = [
+ relativePathToAssets.replaceAll('\\', '/'),
+ basename(args.path).replace(/\.mjs$/, ''),
+ ].join('/');
+
+ return {
+ path: updatedPath, // change the reference to the changed module
+ external: true, // mark it as external in the bundle
+ };
+ });
+ },
+ };
+}
diff --git a/packages/integrations/cloudflare/src/wasm-module-loader.ts b/packages/integrations/cloudflare/src/wasm-module-loader.ts
new file mode 100644
index 000000000..7d34d48c3
--- /dev/null
+++ b/packages/integrations/cloudflare/src/wasm-module-loader.ts
@@ -0,0 +1,119 @@
+import * as fs from 'node:fs';
+import * as path from 'node:path';
+import { type Plugin } from 'vite';
+
+/**
+ * Loads '*.wasm?module' imports as WebAssembly modules, which is the only way to load WASM in cloudflare workers.
+ * Current proposal for WASM modules: https://github.com/WebAssembly/esm-integration/tree/main/proposals/esm-integration
+ * Cloudflare worker WASM from javascript support: https://developers.cloudflare.com/workers/runtime-apis/webassembly/javascript/
+ * @param disabled - if true throws a helpful error message if wasm is encountered and wasm imports are not enabled,
+ * otherwise it will error obscurely in the esbuild and vite builds
+ * @param assetsDirectory - the folder name for the assets directory in the build directory. Usually '_astro'
+ * @returns Vite plugin to load WASM tagged with '?module' as a WASM modules
+ */
+export function wasmModuleLoader({
+ disabled,
+ assetsDirectory,
+}: {
+ disabled: boolean;
+ assetsDirectory: string;
+}): Plugin {
+ const postfix = '.wasm?module';
+ let isDev = false;
+
+ return {
+ name: 'vite:wasm-module-loader',
+ enforce: 'pre',
+ configResolved(config) {
+ isDev = config.command === 'serve';
+ },
+ config(_, __) {
+ // let vite know that file format and the magic import string is intentional, and will be handled in this plugin
+ return {
+ assetsInclude: ['**/*.wasm?module'],
+ build: { rollupOptions: { external: /^__WASM_ASSET__.+\.wasm\.mjs$/i } },
+ };
+ },
+
+ load(id, _) {
+ if (!id.endsWith(postfix)) {
+ return;
+ }
+ if (disabled) {
+ throw new Error(
+ `WASM module's cannot be loaded unless you add \`wasmModuleImports: true\` to your astro config.`
+ );
+ }
+
+ const filePath = id.slice(0, -1 * '?module'.length);
+
+ const data = fs.readFileSync(filePath);
+ const base64 = data.toString('base64');
+
+ const base64Module = `
+const wasmModule = new WebAssembly.Module(Uint8Array.from(atob("${base64}"), c => c.charCodeAt(0)));
+export default wasmModule
+`;
+ if (isDev) {
+ // no need to wire up the assets in dev mode, just rewrite
+ return base64Module;
+ } else {
+ // just some shared ID
+ let hash = hashString(base64);
+ // emit the wasm binary as an asset file, to be picked up later by the esbuild bundle for the worker.
+ // give it a shared deterministic name to make things easy for esbuild to switch on later
+ const assetName = path.basename(filePath).split('.')[0] + '.' + hash + '.wasm';
+ this.emitFile({
+ type: 'asset',
+ // put it explicitly in the _astro assets directory with `fileName` rather than `name` so that
+ // vite doesn't give it a random id in its name. We need to be able to easily rewrite from
+ // the .mjs loader and the actual wasm asset later in the ESbuild for the worker
+ fileName: path.join(assetsDirectory, assetName),
+ source: fs.readFileSync(filePath),
+ });
+
+ // however, by default, the SSG generator cannot import the .wasm as a module, so embed as a base64 string
+ const chunkId = this.emitFile({
+ type: 'prebuilt-chunk',
+ fileName: assetName + '.mjs',
+ code: base64Module,
+ });
+
+ return `
+import wasmModule from "__WASM_ASSET__${chunkId}.wasm.mjs";
+export default wasmModule;
+ `;
+ }
+ },
+
+ // output original wasm file relative to the chunk
+ renderChunk(code, chunk, _) {
+ if (isDev) return;
+
+ if (!/__WASM_ASSET__/g.test(code)) return;
+
+ const final = code.replaceAll(/__WASM_ASSET__([a-z\d]+).wasm.mjs/g, (s, assetId) => {
+ const fileName = this.getFileName(assetId);
+ const relativePath = path
+ .relative(path.dirname(chunk.fileName), fileName)
+ .replaceAll('\\', '/'); // fix windows paths for import
+ return `./${relativePath}`;
+ });
+
+ return { code: final };
+ },
+ };
+}
+
+/**
+ * Returns a deterministic 32 bit hash code from a string
+ */
+function hashString(str: string): string {
+ let hash = 0;
+ for (let i = 0; i < str.length; i++) {
+ const char = str.charCodeAt(i);
+ hash = (hash << 5) - hash + char;
+ hash &= hash; // Convert to 32bit integer
+ }
+ return new Uint32Array([hash])[0].toString(36);
+}
diff --git a/packages/integrations/cloudflare/test/basics.test.js b/packages/integrations/cloudflare/test/basics.test.js
index 726a19fc6..eb4509da1 100644
--- a/packages/integrations/cloudflare/test/basics.test.js
+++ b/packages/integrations/cloudflare/test/basics.test.js
@@ -14,20 +14,22 @@ describe('Basic app', () => {
});
await fixture.build();
- cli = await runCLI('./fixtures/basics/', { silent: true, port: 8789 });
- await cli.ready.catch((e) => {
- console.log(e);
- // if fail to start, skip for now as it's very flaky
- this.skip();
+ cli = await runCLI('./fixtures/basics/', {
+ silent: true,
+ onTimeout: (ex) => {
+ console.log(ex);
+ // if fail to start, skip for now as it's very flaky
+ this.skip();
+ },
});
});
after(async () => {
- await cli.stop();
+ await cli?.stop();
});
it('can render', async () => {
- let res = await fetch(`http://127.0.0.1:8789/`);
+ let res = await fetch(`http://127.0.0.1:${cli.port}/`);
expect(res.status).to.equal(200);
let html = await res.text();
let $ = cheerio.load(html);
diff --git a/packages/integrations/cloudflare/test/cf.test.js b/packages/integrations/cloudflare/test/cf.test.js
index 53b1bbf2c..78a18dcdf 100644
--- a/packages/integrations/cloudflare/test/cf.test.js
+++ b/packages/integrations/cloudflare/test/cf.test.js
@@ -17,20 +17,22 @@ describe('Wrangler Cloudflare Runtime', () => {
});
await fixture.build();
- cli = await runCLI('./fixtures/cf/', { silent: true, port: 8786 });
- await cli.ready.catch((e) => {
- console.log(e);
- // if fail to start, skip for now as it's very flaky
- this.skip();
+ cli = await runCLI('./fixtures/cf/', {
+ silent: true,
+ onTimeout: (ex) => {
+ console.log(ex);
+ // if fail to start, skip for now as it's very flaky
+ this.skip();
+ },
});
});
after(async () => {
- await cli.stop();
+ await cli?.stop();
});
it('Load cf and caches API', async () => {
- let res = await fetch(`http://127.0.0.1:8786/`);
+ let res = await fetch(`http://127.0.0.1:${cli.port}/`);
expect(res.status).to.equal(200);
let html = await res.text();
let $ = cheerio.load(html);
@@ -63,7 +65,7 @@ describe('Astro Cloudflare Runtime', () => {
});
after(async () => {
- await devServer.stop();
+ await devServer?.stop();
});
it('Populates CF, Vars & Bindings', async () => {
diff --git a/packages/integrations/cloudflare/test/directory.test.js b/packages/integrations/cloudflare/test/directory.test.js
index a252b03e9..8390699e3 100644
--- a/packages/integrations/cloudflare/test/directory.test.js
+++ b/packages/integrations/cloudflare/test/directory.test.js
@@ -4,6 +4,7 @@ import cloudflare from '../dist/index.js';
/** @type {import('./test-utils').Fixture} */
describe('mode: "directory"', () => {
+ /** @type {import('./test-utils').Fixture} */
let fixture;
before(async () => {
diff --git a/packages/integrations/cloudflare/test/fixtures/wasm-directory/astro.config.mjs b/packages/integrations/cloudflare/test/fixtures/wasm-directory/astro.config.mjs
new file mode 100644
index 000000000..a30cd2086
--- /dev/null
+++ b/packages/integrations/cloudflare/test/fixtures/wasm-directory/astro.config.mjs
@@ -0,0 +1,10 @@
+import { defineConfig } from 'astro/config';
+import cloudflare from '@astrojs/cloudflare';
+
+export default defineConfig({
+ adapter: cloudflare({
+ mode: 'directory',
+ wasmModuleImports: true
+ }),
+ output: 'server'
+});
diff --git a/packages/integrations/cloudflare/test/fixtures/wasm-directory/package.json b/packages/integrations/cloudflare/test/fixtures/wasm-directory/package.json
new file mode 100644
index 000000000..859aa4f40
--- /dev/null
+++ b/packages/integrations/cloudflare/test/fixtures/wasm-directory/package.json
@@ -0,0 +1,9 @@
+{
+ "name": "@test/astro-cloudflare-wasm-function-per-route",
+ "version": "0.0.0",
+ "private": true,
+ "dependencies": {
+ "@astrojs/cloudflare": "workspace:*",
+ "astro": "workspace:*"
+ }
+}
diff --git a/packages/integrations/cloudflare/test/fixtures/wasm-directory/src/pages/index.ts b/packages/integrations/cloudflare/test/fixtures/wasm-directory/src/pages/index.ts
new file mode 100644
index 000000000..2c9ff6d44
--- /dev/null
+++ b/packages/integrations/cloudflare/test/fixtures/wasm-directory/src/pages/index.ts
@@ -0,0 +1,18 @@
+import { type APIContext, type EndpointOutput } from 'astro';
+// @ts-ignore
+import mod from '../util/add.wasm?module';
+
+const addModule: any = new WebAssembly.Instance(mod);
+
+
+export async function GET(
+ context: APIContext
+): Promise {
+
+ return new Response(JSON.stringify({ answer: addModule.exports.add(40, 2) }), {
+ status: 200,
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ });
+}
diff --git a/packages/integrations/cloudflare/test/fixtures/wasm-directory/src/util/add.wasm b/packages/integrations/cloudflare/test/fixtures/wasm-directory/src/util/add.wasm
new file mode 100644
index 0000000000000000000000000000000000000000..357f72da7a0db8add83699082fd51d46bf3352fb
GIT binary patch
literal 41
wcmZQbEY4+QU|?WmXG~zKuV<`hW@2PuXJ=$iOi5v2;NoOtXHZ~JV9eqM0DJxgJ^%m!
literal 0
HcmV?d00001
diff --git a/packages/integrations/cloudflare/test/fixtures/wasm-function-per-route/astro.config.mjs b/packages/integrations/cloudflare/test/fixtures/wasm-function-per-route/astro.config.mjs
new file mode 100644
index 000000000..7f741d884
--- /dev/null
+++ b/packages/integrations/cloudflare/test/fixtures/wasm-function-per-route/astro.config.mjs
@@ -0,0 +1,12 @@
+import { defineConfig } from 'astro/config';
+import cloudflare from '@astrojs/cloudflare';
+
+export default defineConfig({
+ adapter: cloudflare({
+ mode: 'directory',
+ functionPerRoute: true,
+ wasmModuleImports: true
+ }),
+ output: 'server',
+ vite: { build: { minify: false } }
+});
diff --git a/packages/integrations/cloudflare/test/fixtures/wasm-function-per-route/package.json b/packages/integrations/cloudflare/test/fixtures/wasm-function-per-route/package.json
new file mode 100644
index 000000000..238c1e313
--- /dev/null
+++ b/packages/integrations/cloudflare/test/fixtures/wasm-function-per-route/package.json
@@ -0,0 +1,9 @@
+{
+ "name": "@test/astro-cloudflare-wasm-directory",
+ "version": "0.0.0",
+ "private": true,
+ "dependencies": {
+ "@astrojs/cloudflare": "workspace:*",
+ "astro": "workspace:*"
+ }
+}
diff --git a/packages/integrations/cloudflare/test/fixtures/wasm-function-per-route/src/pages/deeply/nested/route.ts b/packages/integrations/cloudflare/test/fixtures/wasm-function-per-route/src/pages/deeply/nested/route.ts
new file mode 100644
index 000000000..20797c0c6
--- /dev/null
+++ b/packages/integrations/cloudflare/test/fixtures/wasm-function-per-route/src/pages/deeply/nested/route.ts
@@ -0,0 +1,14 @@
+import { type APIContext, type EndpointOutput } from 'astro';
+import { add } from '../../../util/add';
+
+export async function GET(
+ context: APIContext
+): Promise {
+
+ return new Response(JSON.stringify({ answer: add(80, 4) }), {
+ status: 200,
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ });
+}
diff --git a/packages/integrations/cloudflare/test/fixtures/wasm-function-per-route/src/pages/index.ts b/packages/integrations/cloudflare/test/fixtures/wasm-function-per-route/src/pages/index.ts
new file mode 100644
index 000000000..b6417dde9
--- /dev/null
+++ b/packages/integrations/cloudflare/test/fixtures/wasm-function-per-route/src/pages/index.ts
@@ -0,0 +1,14 @@
+import { type APIContext, type EndpointOutput } from 'astro';
+import { add } from '../util/add';
+
+export async function GET(
+ context: APIContext
+): Promise {
+
+ return new Response(JSON.stringify({ answer: add(40, 2) }), {
+ status: 200,
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ });
+}
diff --git a/packages/integrations/cloudflare/test/fixtures/wasm-function-per-route/src/util/add.ts b/packages/integrations/cloudflare/test/fixtures/wasm-function-per-route/src/util/add.ts
new file mode 100644
index 000000000..ee336277b
--- /dev/null
+++ b/packages/integrations/cloudflare/test/fixtures/wasm-function-per-route/src/util/add.ts
@@ -0,0 +1,6 @@
+// extra layer of indirection to stress the esbuild
+import { addImpl } from "./indirection";
+
+export function add(a: number, b: number): number {
+ return addImpl(a, b);
+}
diff --git a/packages/integrations/cloudflare/test/fixtures/wasm-function-per-route/src/util/add.wasm b/packages/integrations/cloudflare/test/fixtures/wasm-function-per-route/src/util/add.wasm
new file mode 100644
index 0000000000000000000000000000000000000000..357f72da7a0db8add83699082fd51d46bf3352fb
GIT binary patch
literal 41
wcmZQbEY4+QU|?WmXG~zKuV<`hW@2PuXJ=$iOi5v2;NoOtXHZ~JV9eqM0DJxgJ^%m!
literal 0
HcmV?d00001
diff --git a/packages/integrations/cloudflare/test/fixtures/wasm-function-per-route/src/util/indirection.ts b/packages/integrations/cloudflare/test/fixtures/wasm-function-per-route/src/util/indirection.ts
new file mode 100644
index 000000000..6fbb04c49
--- /dev/null
+++ b/packages/integrations/cloudflare/test/fixtures/wasm-function-per-route/src/util/indirection.ts
@@ -0,0 +1,9 @@
+// extra layer of indirection to stress the esbuild
+// @ts-ignore
+import mod from './add.wasm?module';
+
+const addModule: any = new WebAssembly.Instance(mod);
+
+export function addImpl(a: number, b: number): number {
+ return addModule.exports.add(a, b);
+}
diff --git a/packages/integrations/cloudflare/test/fixtures/wasm/astro.config.mjs b/packages/integrations/cloudflare/test/fixtures/wasm/astro.config.mjs
new file mode 100644
index 000000000..b5e68667e
--- /dev/null
+++ b/packages/integrations/cloudflare/test/fixtures/wasm/astro.config.mjs
@@ -0,0 +1,9 @@
+import { defineConfig } from 'astro/config';
+import cloudflare from '@astrojs/cloudflare';
+
+export default defineConfig({
+ adapter: cloudflare({
+ wasmModuleImports: true
+ }),
+ output: 'server'
+});
diff --git a/packages/integrations/cloudflare/test/fixtures/wasm/package.json b/packages/integrations/cloudflare/test/fixtures/wasm/package.json
new file mode 100644
index 000000000..4abd8513c
--- /dev/null
+++ b/packages/integrations/cloudflare/test/fixtures/wasm/package.json
@@ -0,0 +1,9 @@
+{
+ "name": "@test/astro-cloudflare-wasm",
+ "version": "0.0.0",
+ "private": true,
+ "dependencies": {
+ "@astrojs/cloudflare": "workspace:*",
+ "astro": "workspace:*"
+ }
+}
diff --git a/packages/integrations/cloudflare/test/fixtures/wasm/src/pages/add/[a]/[b].ts b/packages/integrations/cloudflare/test/fixtures/wasm/src/pages/add/[a]/[b].ts
new file mode 100644
index 000000000..130b2b2a4
--- /dev/null
+++ b/packages/integrations/cloudflare/test/fixtures/wasm/src/pages/add/[a]/[b].ts
@@ -0,0 +1,20 @@
+import { type APIContext, type EndpointOutput } from 'astro';
+// @ts-ignore
+import mod from '../../../util/add.wasm?module';
+
+const addModule: any = new WebAssembly.Instance(mod);
+
+export const prerender = false;
+
+export async function GET(
+ context: APIContext
+): Promise {
+ const a = Number.parseInt(context.params.a!);
+ const b = Number.parseInt(context.params.b!);
+ return new Response(JSON.stringify({ answer: addModule.exports.add(a, b) }), {
+ status: 200,
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ });
+}
diff --git a/packages/integrations/cloudflare/test/fixtures/wasm/src/pages/hybrid.ts b/packages/integrations/cloudflare/test/fixtures/wasm/src/pages/hybrid.ts
new file mode 100644
index 000000000..7bb470dff
--- /dev/null
+++ b/packages/integrations/cloudflare/test/fixtures/wasm/src/pages/hybrid.ts
@@ -0,0 +1,16 @@
+import { type APIContext, type EndpointOutput } from 'astro';
+// @ts-ignore
+import mod from '../util/add.wasm?module';
+
+const addModule: any = new WebAssembly.Instance(mod);
+
+export async function GET(
+ context: APIContext
+): Promise {
+ return new Response(JSON.stringify({ answer: addModule.exports.add(20, 1) }), {
+ status: 200,
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ });
+}
diff --git a/packages/integrations/cloudflare/test/fixtures/wasm/src/util/add.wasm b/packages/integrations/cloudflare/test/fixtures/wasm/src/util/add.wasm
new file mode 100644
index 0000000000000000000000000000000000000000..357f72da7a0db8add83699082fd51d46bf3352fb
GIT binary patch
literal 41
wcmZQbEY4+QU|?WmXG~zKuV<`hW@2PuXJ=$iOi5v2;NoOtXHZ~JV9eqM0DJxgJ^%m!
literal 0
HcmV?d00001
diff --git a/packages/integrations/cloudflare/test/function-per-route.test.js b/packages/integrations/cloudflare/test/function-per-route.test.js
index d20b0fa7c..f0287c717 100644
--- a/packages/integrations/cloudflare/test/function-per-route.test.js
+++ b/packages/integrations/cloudflare/test/function-per-route.test.js
@@ -3,6 +3,7 @@ import { expect } from 'chai';
/** @type {import('./test-utils.js').Fixture} */
describe('Cloudflare SSR functionPerRoute', () => {
+ /** @type {import('./test-utils').Fixture} */
let fixture;
before(async () => {
@@ -13,7 +14,7 @@ describe('Cloudflare SSR functionPerRoute', () => {
});
after(() => {
- fixture.clean();
+ fixture?.clean();
});
it('generates functions folders inside the project root, and checks that each page is emitted by astro', async () => {
diff --git a/packages/integrations/cloudflare/test/runtime.test.js b/packages/integrations/cloudflare/test/runtime.test.js
index 8bb38d7e5..e0d77d5c6 100644
--- a/packages/integrations/cloudflare/test/runtime.test.js
+++ b/packages/integrations/cloudflare/test/runtime.test.js
@@ -17,20 +17,22 @@ describe('Runtime Locals', () => {
});
await fixture.build();
- cli = await runCLI('./fixtures/runtime/', { silent: true, port: 8793 });
- await cli.ready.catch((e) => {
- console.log(e);
- // if fail to start, skip for now as it's very flaky
- this.skip();
+ cli = await runCLI('./fixtures/runtime/', {
+ silent: true,
+ onTimeout: (ex) => {
+ console.log(ex);
+ // if fail to start, skip for now as it's very flaky
+ this.skip();
+ },
});
});
after(async () => {
- await cli.stop();
+ await cli?.stop();
});
it('has CF and Caches', async () => {
- let res = await fetch(`http://127.0.0.1:8793/`);
+ let res = await fetch(`http://127.0.0.1:${cli.port}/`);
expect(res.status).to.equal(200);
let html = await res.text();
let $ = cheerio.load(html);
diff --git a/packages/integrations/cloudflare/test/test-utils.js b/packages/integrations/cloudflare/test/test-utils.js
index 36515f831..50226c0c1 100644
--- a/packages/integrations/cloudflare/test/test-utils.js
+++ b/packages/integrations/cloudflare/test/test-utils.js
@@ -1,12 +1,10 @@
import { spawn } from 'node:child_process';
import { fileURLToPath } from 'node:url';
-import kill from 'kill-port';
import { loadFixture as baseLoadFixture } from '../../../astro/test/test-utils.js';
-
+import * as net from 'node:net';
export { fixLineEndings } from '../../../astro/test/test-utils.js';
-
/**
- * @typedef {{ ready: Promise, stop: Promise }} WranglerCLI
+ * @typedef {{ stop: Promise, port: number }} WranglerCLI
* @typedef {import('../../../astro/test/test-utils').Fixture} Fixture
*/
@@ -21,70 +19,147 @@ const wranglerPath = fileURLToPath(
new URL('../node_modules/wrangler/bin/wrangler.js', import.meta.url)
);
+let lastPort = 8788;
+
/**
* @returns {Promise}
*/
-export async function runCLI(basePath, { silent, port }) {
- // Hack: force existing process on port to be killed
- try {
- await kill(port, 'tcp');
- } catch {
- // Will throw if port is not in use, but that's fine
+export async function runCLI(
+ basePath,
+ {
+ silent,
+ maxAttempts = 3,
+ timeoutMillis = 2500, // really short because it often seems to just hang on the first try, but work subsequently, no matter the wait
+ backoffFactor = 2, // | - 2.5s -- 5s ---- 10s -> onTimeout
+ onTimeout = (ex) => {
+ new Error(`Timed out starting the wrangler CLI after ${maxAttempts} tries.`, { cause: ex });
+ },
}
+) {
+ let triesRemaining = maxAttempts;
+ let timeout = timeoutMillis;
+ let cli;
+ let lastErr;
+ while (triesRemaining > 0) {
+ cli = await tryRunCLI(basePath, { silent, timeout, forceRotatePort: triesRemaining !== maxAttempts });
+ try {
+ await cli.ready;
+ return cli;
+ } catch (err) {
+ lastErr = err;
+ console.error((err.message || err.name || err) + ' after ' + timeout + 'ms');
+ cli.stop();
+ triesRemaining -= 1;
+ timeout *= backoffFactor;
+ }
+ }
+ onTimeout(lastErr);
+ return cli;
+}
- const script = fileURLToPath(new URL(`${basePath}/dist/_worker.js`, import.meta.url));
- const p = spawn('node', [
- wranglerPath,
- 'dev',
- script,
- '--port',
- port,
- '--log-level',
- 'info',
- '--persist-to',
- `${basePath}/.wrangler/state`,
- ]);
+async function tryRunCLI(basePath, { silent, timeout, forceRotatePort = false }) {
+ const port = await getNextOpenPort(lastPort + (forceRotatePort ? 1 : 0));
+ lastPort = port;
+
+ const fixtureDir = fileURLToPath(new URL(`${basePath}`, import.meta.url));
+ const p = spawn(
+ 'node',
+ [
+ wranglerPath,
+ 'pages',
+ 'dev',
+ 'dist',
+ '--port',
+ port,
+ '--log-level',
+ 'info',
+ '--persist-to',
+ '.wrangler/state',
+ ],
+ {
+ cwd: fixtureDir,
+ }
+ );
p.stderr.setEncoding('utf-8');
p.stdout.setEncoding('utf-8');
- const timeout = 20_000;
-
const ready = new Promise(async (resolve, reject) => {
const failed = setTimeout(() => {
- p.kill();
+ p.kill('SIGKILL');
reject(new Error(`Timed out starting the wrangler CLI`));
}, timeout);
- (async function () {
- for (const msg of p.stderr) {
- if (!silent) {
- console.error(msg);
- }
- }
- })();
+ const success = () => {
+ clearTimeout(failed);
+ resolve();
+ };
- for await (const msg of p.stdout) {
+ p.on('exit', (code) => reject(`wrangler terminated unexpectedly with exit code ${code}`));
+
+ p.stderr.on('data', (data) => {
if (!silent) {
- console.log(msg);
+ process.stdout.write(data);
}
- if (msg.includes(`[mf:inf] Ready on`)) {
- break;
+ });
+ let allData = '';
+ p.stdout.on('data', (data) => {
+ if (!silent) {
+ process.stdout.write(data);
}
- }
-
- clearTimeout(failed);
- resolve();
+ allData += data;
+ if (allData.includes(`[mf:inf] Ready on`)) {
+ success();
+ }
+ });
});
return {
+ port,
ready,
stop() {
return new Promise((resolve, reject) => {
- p.on('close', () => resolve());
+ const timer = setTimeout(() => {
+ p.kill('SIGKILL');
+ }, 1000);
+ p.on('close', () => {
+ clearTimeout(timer);
+ resolve();
+ });
p.on('error', (err) => reject(err));
p.kill();
});
},
};
}
+
+const isPortOpen = async (port) => {
+ return new Promise((resolve, reject) => {
+ let s = net.createServer();
+ s.once('error', (err) => {
+ s.close();
+ if (err['code'] == 'EADDRINUSE') {
+ resolve(false);
+ } else {
+ reject(err);
+ }
+ });
+ s.once('listening', () => {
+ resolve(true);
+ s.close();
+ });
+ s.listen(port, "0.0.0.0");
+ });
+};
+
+const getNextOpenPort = async (startFrom) => {
+ let openPort = null;
+ while (startFrom < 65535 || !!openPort) {
+ if (await isPortOpen(startFrom)) {
+ openPort = startFrom;
+ break;
+ }
+ startFrom++;
+ }
+ return openPort;
+};
diff --git a/packages/integrations/cloudflare/test/wasm-directory.test.js b/packages/integrations/cloudflare/test/wasm-directory.test.js
new file mode 100644
index 000000000..0f387a660
--- /dev/null
+++ b/packages/integrations/cloudflare/test/wasm-directory.test.js
@@ -0,0 +1,36 @@
+import { loadFixture, runCLI } from './test-utils.js';
+import { expect } from 'chai';
+
+describe('Wasm directory mode import', () => {
+ /** @type {import('./test-utils.js').Fixture} */
+ let fixture;
+ /** @type {import('./test-utils.js').WranglerCLI} */
+ let cli;
+
+ before(async function () {
+ fixture = await loadFixture({
+ root: './fixtures/wasm-directory/',
+ });
+ await fixture.build();
+
+ cli = await runCLI('./fixtures/wasm-directory/', {
+ silent: true,
+ onTimeout: (ex) => {
+ console.log(ex);
+ // if fail to start, skip for now as it's very flaky
+ this.skip();
+ },
+ });
+ });
+
+ after(async () => {
+ await cli?.stop();
+ });
+
+ it('can render', async () => {
+ let res = await fetch(`http://127.0.0.1:${cli.port}/`);
+ expect(res.status).to.equal(200);
+ const json = await res.json();
+ expect(json).to.deep.equal({ answer: 42 });
+ });
+});
diff --git a/packages/integrations/cloudflare/test/wasm-function-per-route.test.js b/packages/integrations/cloudflare/test/wasm-function-per-route.test.js
new file mode 100644
index 000000000..f751f1ff4
--- /dev/null
+++ b/packages/integrations/cloudflare/test/wasm-function-per-route.test.js
@@ -0,0 +1,41 @@
+import { loadFixture, runCLI } from './test-utils.js';
+import { expect } from 'chai';
+
+describe('Wasm function per route import', () => {
+ /** @type {import('./test-utils.js').Fixture} */
+ let fixture;
+ /** @type {import('./test-utils.js').WranglerCLI} */
+ let cli;
+
+ before(async function () {
+ fixture = await loadFixture({
+ root: './fixtures/wasm-function-per-route/',
+ });
+ await fixture.build();
+
+ cli = await runCLI('./fixtures/wasm-function-per-route/', {
+ silent: true,
+ onTimeout: (ex) => {
+ console.log(ex);
+ // if fail to start, skip for now as it's very flaky
+ this.skip();
+ },
+ });
+ });
+
+ after(async () => {
+ await cli?.stop();
+ });
+
+ it('can render', async () => {
+ let res = await fetch(`http://127.0.0.1:${cli.port}/`);
+ expect(res.status).to.equal(200);
+ let json = await res.json();
+ expect(json).to.deep.equal({ answer: 42 });
+
+ res = await fetch(`http://127.0.0.1:${cli.port}/deeply/nested/route`);
+ expect(res.status).to.equal(200);
+ json = await res.json();
+ expect(json).to.deep.equal({ answer: 84 });
+ });
+});
diff --git a/packages/integrations/cloudflare/test/wasm.test.js b/packages/integrations/cloudflare/test/wasm.test.js
new file mode 100644
index 000000000..279a00cd1
--- /dev/null
+++ b/packages/integrations/cloudflare/test/wasm.test.js
@@ -0,0 +1,85 @@
+import { loadFixture, runCLI } from './test-utils.js';
+import { expect } from 'chai';
+import cloudflare from '../dist/index.js';
+
+describe('Wasm import', () => {
+ describe('in cloudflare workerd', () => {
+ /** @type {import('./test-utils.js').Fixture} */
+ let fixture;
+ /** @type {import('./test-utils.js').WranglerCLI} */
+ let cli;
+
+ before(async function () {
+ fixture = await loadFixture({
+ root: './fixtures/wasm/',
+ });
+ await fixture.build();
+
+ cli = await runCLI('./fixtures/wasm/', {
+ silent: true,
+ onTimeout: (ex) => {
+ console.log(ex);
+ // if fail to start, skip for now as it's very flaky
+ this.skip();
+ },
+ });
+ });
+
+ after(async () => {
+ await cli?.stop();
+ });
+
+ it('can render', async () => {
+ let res = await fetch(`http://127.0.0.1:${cli.port}/add/40/2`);
+ expect(res.status).to.equal(200);
+ const json = await res.json();
+ expect(json).to.deep.equal({ answer: 42 });
+ });
+ });
+ describe('astro dev server', () => {
+ /** @type {import('./test-utils').Fixture} */
+ let fixture;
+ let devServer;
+
+ before(async () => {
+ fixture = await loadFixture({
+ root: './fixtures/wasm/',
+ });
+ devServer = undefined;
+ });
+
+ after(async () => {
+ await devServer?.stop();
+ });
+
+ it('can serve wasm', async () => {
+ devServer = await fixture.startDevServer();
+ let res = await fetch(`http://localhost:${devServer.address.port}/add/60/3`);
+ expect(res.status).to.equal(200);
+ const json = await res.json();
+ expect(json).to.deep.equal({ answer: 63 });
+ });
+
+ it('fails to build intelligently when wasm is disabled', async () => {
+ let ex;
+ try {
+ await fixture.build({
+ adapter: cloudflare({
+ wasmModuleImports: false,
+ }),
+ });
+ } catch (err) {
+ ex = err;
+ }
+ expect(ex?.message).to.have.string('add `wasmModuleImports: true` to your astro config');
+ });
+
+ it('can import wasm in both SSR and SSG pages', async () => {
+ await fixture.build({ output: 'hybrid' });
+ const staticContents = await fixture.readFile('./hybrid');
+ expect(staticContents).to.be.equal('{"answer":21}');
+ const assets = await fixture.readdir('./_astro');
+ expect(assets.map((x) => x.slice(x.lastIndexOf('.')))).to.contain('.wasm');
+ });
+ });
+});
diff --git a/packages/integrations/cloudflare/test/with-solid-js.test.js b/packages/integrations/cloudflare/test/with-solid-js.test.js
index c644163b0..501a947d0 100644
--- a/packages/integrations/cloudflare/test/with-solid-js.test.js
+++ b/packages/integrations/cloudflare/test/with-solid-js.test.js
@@ -14,20 +14,22 @@ describe('With SolidJS', () => {
});
await fixture.build();
- cli = await runCLI('./fixtures/with-solid-js/', { silent: true, port: 8790 });
- await cli.ready.catch((e) => {
- console.log(e);
- // if fail to start, skip for now as it's very flaky
- this.skip();
+ cli = await runCLI('./fixtures/with-solid-js/', {
+ silent: true,
+ onTimeout: (ex) => {
+ console.log(ex);
+ // if fail to start, skip for now as it's very flaky
+ this.skip();
+ },
});
});
after(async () => {
- await cli.stop();
+ await cli?.stop();
});
it('renders the solid component', async () => {
- let res = await fetch(`http://127.0.0.1:8790/`);
+ let res = await fetch(`http://127.0.0.1:${cli.port}/`);
expect(res.status).to.equal(200);
let html = await res.text();
let $ = cheerio.load(html);
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index dceb985fa..0e2fbd876 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -3649,6 +3649,9 @@ importers:
tiny-glob:
specifier: ^0.2.9
version: 0.2.9
+ vite:
+ specifier: ^4.4.9
+ version: 4.4.9(@types/node@18.17.8)(sass@1.66.1)
devDependencies:
'@types/iarna__toml':
specifier: ^2.0.2
@@ -3665,9 +3668,6 @@ importers:
cheerio:
specifier: 1.0.0-rc.12
version: 1.0.0-rc.12
- kill-port:
- specifier: ^2.0.1
- version: 2.0.1
mocha:
specifier: ^10.2.0
version: 10.2.0
@@ -3738,6 +3738,33 @@ importers:
specifier: workspace:*
version: link:../../../../../astro
+ packages/integrations/cloudflare/test/fixtures/wasm:
+ dependencies:
+ '@astrojs/cloudflare':
+ specifier: workspace:*
+ version: link:../../..
+ astro:
+ specifier: workspace:*
+ version: link:../../../../../astro
+
+ packages/integrations/cloudflare/test/fixtures/wasm-directory:
+ dependencies:
+ '@astrojs/cloudflare':
+ specifier: workspace:*
+ version: link:../../..
+ astro:
+ specifier: workspace:*
+ version: link:../../../../../astro
+
+ packages/integrations/cloudflare/test/fixtures/wasm-function-per-route:
+ dependencies:
+ '@astrojs/cloudflare':
+ specifier: workspace:*
+ version: link:../../..
+ astro:
+ specifier: workspace:*
+ version: link:../../../../../astro
+
packages/integrations/cloudflare/test/fixtures/with-solid-js:
dependencies:
'@astrojs/cloudflare':
@@ -12043,10 +12070,6 @@ packages:
call-bind: 1.0.2
get-intrinsic: 1.2.1
- /get-them-args@1.3.2:
- resolution: {integrity: sha512-LRn8Jlk+DwZE4GTlDbT3Hikd1wSHgLMme/+7ddlqKd7ldwR6LjJgTVWzBnR01wnYGe4KgrXjg287RaI22UHmAw==}
- dev: true
-
/giget@1.1.2:
resolution: {integrity: sha512-HsLoS07HiQ5oqvObOI+Qb2tyZH4Gj5nYGfF9qQcZNrPw+uEFhdXtgJr01aO2pWadGHucajYDLxxbtQkm97ON2A==}
hasBin: true
@@ -13165,14 +13188,6 @@ packages:
commander: 8.3.0
dev: true
- /kill-port@2.0.1:
- resolution: {integrity: sha512-e0SVOV5jFo0mx8r7bS29maVWp17qGqLBZ5ricNSajON6//kmb7qqqNnml4twNE8Dtj97UQD+gNFOaipS/q1zzQ==}
- hasBin: true
- dependencies:
- get-them-args: 1.3.2
- shell-exec: 1.0.2
- dev: true
-
/kind-of@6.0.3:
resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
engines: {node: '>=0.10.0'}
@@ -16320,10 +16335,6 @@ packages:
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
engines: {node: '>=8'}
- /shell-exec@1.0.2:
- resolution: {integrity: sha512-jyVd+kU2X+mWKMmGhx4fpWbPsjvD53k9ivqetutVW/BQ+WIZoDoP4d8vUMGezV6saZsiNoW2f9GIhg9Dondohg==}
- dev: true
-
/shell-quote@1.8.1:
resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==}
dev: true
From 0352dec47b955699d91efa5d499420ca56f67e80 Mon Sep 17 00:00:00 2001
From: ematipico
Date: Fri, 22 Sep 2023 15:00:18 +0000
Subject: [PATCH 08/90] [ci] format
---
packages/integrations/cloudflare/README.md | 8 ++++----
packages/integrations/cloudflare/src/index.ts | 2 +-
packages/integrations/cloudflare/test/test-utils.js | 8 ++++++--
3 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/packages/integrations/cloudflare/README.md b/packages/integrations/cloudflare/README.md
index 1a1419cff..8789109df 100644
--- a/packages/integrations/cloudflare/README.md
+++ b/packages/integrations/cloudflare/README.md
@@ -197,9 +197,9 @@ export default defineConfig({
default: `false`
-Whether or not to import `.wasm` files [directly as ES modules](https://github.com/WebAssembly/esm-integration/tree/main/proposals/esm-integration).
+Whether or not to import `.wasm` files [directly as ES modules](https://github.com/WebAssembly/esm-integration/tree/main/proposals/esm-integration).
-Add `wasmModuleImports: true` to `astro.config.mjs` to enable in both the Cloudflare build and the Astro dev server.
+Add `wasmModuleImports: true` to `astro.config.mjs` to enable in both the Cloudflare build and the Astro dev server.
```diff
// astro.config.mjs
@@ -214,9 +214,9 @@ export default defineConfig({
})
```
-Once enabled, you can import a web assembly module in Astro with a `.wasm?module` import.
+Once enabled, you can import a web assembly module in Astro with a `.wasm?module` import.
-The following is an example of importing a Wasm module that then responds to requests by adding the request's number parameters together.
+The following is an example of importing a Wasm module that then responds to requests by adding the request's number parameters together.
```javascript
// pages/add/[a]/[b].js
diff --git a/packages/integrations/cloudflare/src/index.ts b/packages/integrations/cloudflare/src/index.ts
index 4ae43a110..6a2b5c343 100644
--- a/packages/integrations/cloudflare/src/index.ts
+++ b/packages/integrations/cloudflare/src/index.ts
@@ -350,7 +350,7 @@ export default function createIntegration(args?: Options): AstroIntegration {
'node:stream',
'node:string_decoder',
'node:util',
- ],
+ ],
entryPoints: pathsGroup,
outbase: absolutePagesDirname,
outdir: outputDir,
diff --git a/packages/integrations/cloudflare/test/test-utils.js b/packages/integrations/cloudflare/test/test-utils.js
index 50226c0c1..5e0c698f4 100644
--- a/packages/integrations/cloudflare/test/test-utils.js
+++ b/packages/integrations/cloudflare/test/test-utils.js
@@ -41,7 +41,11 @@ export async function runCLI(
let cli;
let lastErr;
while (triesRemaining > 0) {
- cli = await tryRunCLI(basePath, { silent, timeout, forceRotatePort: triesRemaining !== maxAttempts });
+ cli = await tryRunCLI(basePath, {
+ silent,
+ timeout,
+ forceRotatePort: triesRemaining !== maxAttempts,
+ });
try {
await cli.ready;
return cli;
@@ -148,7 +152,7 @@ const isPortOpen = async (port) => {
resolve(true);
s.close();
});
- s.listen(port, "0.0.0.0");
+ s.listen(port, '0.0.0.0');
});
};
From 974d5117abc8b47f8225e455b9285c88e305272f Mon Sep 17 00:00:00 2001
From: Martin Trapp <94928215+martrapp@users.noreply.github.com>
Date: Fri, 22 Sep 2023 18:01:22 +0200
Subject: [PATCH 09/90] fix: no deletion of scripts during view transition
(#8636)
---
.changeset/short-cougars-worry.md | 5 +++++
packages/astro/components/ViewTransitions.astro | 10 +++++-----
2 files changed, 10 insertions(+), 5 deletions(-)
create mode 100644 .changeset/short-cougars-worry.md
diff --git a/.changeset/short-cougars-worry.md b/.changeset/short-cougars-worry.md
new file mode 100644
index 000000000..05c1c20b5
--- /dev/null
+++ b/.changeset/short-cougars-worry.md
@@ -0,0 +1,5 @@
+---
+'astro': patch
+---
+
+fix: no deletion of scripts during view transition
diff --git a/packages/astro/components/ViewTransitions.astro b/packages/astro/components/ViewTransitions.astro
index aa266af13..230b2f302 100644
--- a/packages/astro/components/ViewTransitions.astro
+++ b/packages/astro/components/ViewTransitions.astro
@@ -219,13 +219,13 @@ const { fallback = 'animate' } = Astro.props as Props;
for (const s2 of newDocument.scripts) {
if (
// Inline
- (s1.textContent && s1.textContent === s2.textContent) ||
+ (!s1.src && s1.textContent === s2.textContent) ||
// External
- (s1.type === s2.type && s1.src === s2.src)
+ (s1.src && s1.type === s2.type && s1.src === s2.src)
) {
- s2.remove();
- } else {
- s1.remove();
+ // the old script is in the new document: we mark it as executed to prevent re-execution
+ s2.dataset.astroExec = '';
+ break;
}
}
}
From f36c4295be1ef2bcfa4aecb3c59551388419c53d Mon Sep 17 00:00:00 2001
From: Matthew Phillips
Date: Sat, 23 Sep 2023 02:12:36 +0800
Subject: [PATCH 10/90] Warn on empty content collections (#8640)
* Warn on empty content collections
* Update packages/astro/src/core/errors/errors-data.ts
Co-authored-by: Reuben Tier <64310361+TheOtterlord@users.noreply.github.com>
---------
Co-authored-by: Reuben Tier <64310361+TheOtterlord@users.noreply.github.com>
---
.changeset/spotty-jokes-arrive.md | 5 +++++
packages/astro/src/content/runtime.ts | 18 +++---------------
packages/astro/src/core/errors/errors-data.ts | 1 +
3 files changed, 9 insertions(+), 15 deletions(-)
create mode 100644 .changeset/spotty-jokes-arrive.md
diff --git a/.changeset/spotty-jokes-arrive.md b/.changeset/spotty-jokes-arrive.md
new file mode 100644
index 000000000..8638f8b8b
--- /dev/null
+++ b/.changeset/spotty-jokes-arrive.md
@@ -0,0 +1,5 @@
+---
+'astro': patch
+---
+
+Warn on empty content collections
diff --git a/packages/astro/src/content/runtime.ts b/packages/astro/src/content/runtime.ts
index eeaa60e6c..2c5a120ca 100644
--- a/packages/astro/src/content/runtime.ts
+++ b/packages/astro/src/content/runtime.ts
@@ -1,6 +1,5 @@
import type { MarkdownHeading } from '@astrojs/markdown-remark';
import { ZodIssueCode, string as zodString } from 'zod';
-import type { AstroIntegration } from '../@types/astro.js';
import { AstroError, AstroErrorData } from '../core/errors/index.js';
import { prependForwardSlash } from '../core/path.js';
import {
@@ -56,7 +55,9 @@ export function createGetCollection({
} else if (collection in dataCollectionToEntryMap) {
type = 'data';
} else {
- return warnOfEmptyCollection(collection);
+ // eslint-disable-next-line no-console
+ console.warn(`The collection **${collection}** does not exist or is empty. Ensure a collection directory with this name exists.`);
+ return;
}
const lazyImports = Object.values(
type === 'content'
@@ -390,16 +391,3 @@ type PropagatedAssetsModule = {
function isPropagatedAssetsModule(module: any): module is PropagatedAssetsModule {
return typeof module === 'object' && module != null && '__astroPropagation' in module;
}
-
-function warnOfEmptyCollection(collection: string): AstroIntegration {
- return {
- name: 'astro-collection',
- hooks: {
- 'astro:server:start': ({ logger }) => {
- logger.warn(
- `The collection **${collection}** does not exist or is empty. Ensure a collection directory with this name exists.`
- );
- },
- },
- };
-}
diff --git a/packages/astro/src/core/errors/errors-data.ts b/packages/astro/src/core/errors/errors-data.ts
index e4fe35540..ace362cef 100644
--- a/packages/astro/src/core/errors/errors-data.ts
+++ b/packages/astro/src/core/errors/errors-data.ts
@@ -1158,6 +1158,7 @@ export const ContentSchemaContainsSlugError = {
/**
* @docs
* @message A collection queried via `getCollection()` does not exist.
+ * @deprecated Collections that do not exist no longer result in an error. A warning is omitted instead.
* @description
* When querying a collection, ensure a collection directory with the requested name exists under `src/content/`.
*/
From 4f2bf2156f3fa1508d61f0b3f4a6f25399d0bd4e Mon Sep 17 00:00:00 2001
From: matthewp
Date: Fri, 22 Sep 2023 18:15:46 +0000
Subject: [PATCH 11/90] [ci] format
---
packages/astro/src/content/runtime.ts | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/packages/astro/src/content/runtime.ts b/packages/astro/src/content/runtime.ts
index 2c5a120ca..96d6c1141 100644
--- a/packages/astro/src/content/runtime.ts
+++ b/packages/astro/src/content/runtime.ts
@@ -56,7 +56,9 @@ export function createGetCollection({
type = 'data';
} else {
// eslint-disable-next-line no-console
- console.warn(`The collection **${collection}** does not exist or is empty. Ensure a collection directory with this name exists.`);
+ console.warn(
+ `The collection **${collection}** does not exist or is empty. Ensure a collection directory with this name exists.`
+ );
return;
}
const lazyImports = Object.values(
From 139b0f54d9ad92059c4bca55a08c70c3c563a4e7 Mon Sep 17 00:00:00 2001
From: Jacob Lamb
Date: Fri, 22 Sep 2023 14:00:38 -0700
Subject: [PATCH 12/90] Refine CLI flag descriptions for clarity (#8545)
* Refine CLI flag descriptions for clarity
* Update README.md
* Update README.md
* Update README.md
* Update help.ts
* Update packages/create-astro/src/actions/help.ts
Co-authored-by: Sarah Rainsberger
* Update packages/create-astro/README.md
Co-authored-by: Sarah Rainsberger
* Update packages/create-astro/README.md
Co-authored-by: Sarah Rainsberger
* Update README.md
---------
Co-authored-by: Nate Moore
Co-authored-by: Sarah Rainsberger
---
packages/create-astro/README.md | 23 +++++++++++++----------
packages/create-astro/src/actions/help.ts | 6 +++---
2 files changed, 16 insertions(+), 13 deletions(-)
diff --git a/packages/create-astro/README.md b/packages/create-astro/README.md
index ba406d942..0f9fbde5a 100644
--- a/packages/create-astro/README.md
+++ b/packages/create-astro/README.md
@@ -45,16 +45,19 @@ npm create astro@latest my-astro-project -- --template cassidoo/shopify-react-as
May be provided in place of prompts
-| Name | Description |
-| :--------------------------- | :----------------------------------------------------- |
-| `--template ` | Specify your template. |
-| `--install` / `--no-install` | Install dependencies (or not). |
-| `--git` / `--no-git` | Initialize git repo (or not). |
-| `--yes` (`-y`) | Skip all prompt by accepting defaults. |
-| `--no` (`-n`) | Skip all prompt by declining defaults. |
-| `--dry-run` | Walk through steps without executing. |
-| `--skip-houston` | Skip Houston animation. |
-| `--typescript