summaryrefslogtreecommitdiff
path: root/packages/astro
diff options
context:
space:
mode:
Diffstat (limited to 'packages/astro')
-rw-r--r--packages/astro/CHANGELOG.md327
-rw-r--r--packages/astro/astro-jsx.d.ts2
-rwxr-xr-xpackages/astro/astro.js4
-rw-r--r--packages/astro/client-base.d.ts427
-rw-r--r--packages/astro/client-image.d.ts41
-rw-r--r--packages/astro/client.d.ts450
-rw-r--r--packages/astro/content-types.template.d.ts12
-rw-r--r--packages/astro/e2e/astro-envs.test.js4
-rw-r--r--packages/astro/e2e/css-sourcemaps.test.js4
-rw-r--r--packages/astro/e2e/css.test.js4
-rw-r--r--packages/astro/e2e/errors.test.js7
-rw-r--r--packages/astro/e2e/fixtures/client-only/astro.config.mjs8
-rw-r--r--packages/astro/e2e/fixtures/client-only/src/components/preact/PreactCounter.tsx (renamed from packages/astro/e2e/fixtures/client-only/src/components/PreactCounter.tsx)0
-rw-r--r--packages/astro/e2e/fixtures/client-only/src/components/react/ReactCounter.jsx (renamed from packages/astro/e2e/fixtures/client-only/src/components/ReactCounter.jsx)0
-rw-r--r--packages/astro/e2e/fixtures/client-only/src/components/solid/SolidCounter.tsx (renamed from packages/astro/e2e/fixtures/client-only/src/components/SolidCounter.tsx)0
-rw-r--r--packages/astro/e2e/fixtures/client-only/src/components/svelte/SvelteCounter.svelte (renamed from packages/astro/e2e/fixtures/client-only/src/components/SvelteCounter.svelte)0
-rw-r--r--packages/astro/e2e/fixtures/client-only/src/components/vue/VueCounter.vue (renamed from packages/astro/e2e/fixtures/client-only/src/components/VueCounter.vue)0
-rw-r--r--packages/astro/e2e/fixtures/client-only/src/pages/index.astro10
-rw-r--r--packages/astro/e2e/fixtures/errors/astro.config.mjs10
-rw-r--r--packages/astro/e2e/fixtures/errors/src/components/preact/PreactRuntimeError.jsx (renamed from packages/astro/e2e/fixtures/errors/src/components/PreactRuntimeError.jsx)0
-rw-r--r--packages/astro/e2e/fixtures/errors/src/components/preact/PreactSyntaxError.jsx (renamed from packages/astro/e2e/fixtures/errors/src/components/PreactSyntaxError.jsx)0
-rw-r--r--packages/astro/e2e/fixtures/errors/src/components/react/ReactRuntimeError.jsx (renamed from packages/astro/e2e/fixtures/errors/src/components/ReactRuntimeError.jsx)0
-rw-r--r--packages/astro/e2e/fixtures/errors/src/components/react/ReactSyntaxError.jsx (renamed from packages/astro/e2e/fixtures/errors/src/components/ReactSyntaxError.jsx)0
-rw-r--r--packages/astro/e2e/fixtures/errors/src/components/solid/SolidRuntimeError.jsx (renamed from packages/astro/e2e/fixtures/errors/src/components/SolidRuntimeError.jsx)0
-rw-r--r--packages/astro/e2e/fixtures/errors/src/components/solid/SolidSyntaxError.jsx (renamed from packages/astro/e2e/fixtures/errors/src/components/SolidSyntaxError.jsx)0
-rw-r--r--packages/astro/e2e/fixtures/errors/src/components/svelte/SvelteDirectiveError.svelte (renamed from packages/astro/e2e/fixtures/errors/src/components/SvelteDirectiveError.svelte)0
-rw-r--r--packages/astro/e2e/fixtures/errors/src/components/svelte/SvelteRuntimeError.svelte (renamed from packages/astro/e2e/fixtures/errors/src/components/SvelteRuntimeError.svelte)0
-rw-r--r--packages/astro/e2e/fixtures/errors/src/components/svelte/SvelteSyntaxError.svelte (renamed from packages/astro/e2e/fixtures/errors/src/components/SvelteSyntaxError.svelte)0
-rw-r--r--packages/astro/e2e/fixtures/errors/src/components/vue/VueRuntimeError.vue (renamed from packages/astro/e2e/fixtures/errors/src/components/VueRuntimeError.vue)0
-rw-r--r--packages/astro/e2e/fixtures/errors/src/components/vue/VueSyntaxError.vue (renamed from packages/astro/e2e/fixtures/errors/src/components/VueSyntaxError.vue)0
-rw-r--r--packages/astro/e2e/fixtures/errors/src/pages/astro-client-media-error.astro4
-rw-r--r--packages/astro/e2e/fixtures/errors/src/pages/astro-hydration-error.astro4
-rw-r--r--packages/astro/e2e/fixtures/errors/src/pages/preact-runtime-error.astro2
-rw-r--r--packages/astro/e2e/fixtures/errors/src/pages/preact-syntax-error.astro2
-rw-r--r--packages/astro/e2e/fixtures/errors/src/pages/react-runtime-error.astro2
-rw-r--r--packages/astro/e2e/fixtures/errors/src/pages/react-syntax-error.astro2
-rw-r--r--packages/astro/e2e/fixtures/errors/src/pages/solid-runtime-error.astro2
-rw-r--r--packages/astro/e2e/fixtures/errors/src/pages/solid-syntax-error.astro2
-rw-r--r--packages/astro/e2e/fixtures/errors/src/pages/svelte-runtime-error.astro2
-rw-r--r--packages/astro/e2e/fixtures/errors/src/pages/svelte-syntax-error.astro2
-rw-r--r--packages/astro/e2e/fixtures/errors/src/pages/vue-runtime-error.astro2
-rw-r--r--packages/astro/e2e/fixtures/errors/src/pages/vue-syntax-error.astro2
-rw-r--r--packages/astro/e2e/fixtures/multiple-frameworks/astro.config.mjs8
-rw-r--r--packages/astro/e2e/fixtures/multiple-frameworks/src/components/preact/PreactCounter.tsx (renamed from packages/astro/e2e/fixtures/multiple-frameworks/src/components/PreactCounter.tsx)0
-rw-r--r--packages/astro/e2e/fixtures/multiple-frameworks/src/components/react/ReactCounter.jsx (renamed from packages/astro/e2e/fixtures/multiple-frameworks/src/components/ReactCounter.jsx)0
-rw-r--r--packages/astro/e2e/fixtures/multiple-frameworks/src/components/solid/SolidCounter.tsx (renamed from packages/astro/e2e/fixtures/multiple-frameworks/src/components/SolidCounter.tsx)0
-rw-r--r--packages/astro/e2e/fixtures/multiple-frameworks/src/components/svelte/SvelteCounter.svelte (renamed from packages/astro/e2e/fixtures/multiple-frameworks/src/components/SvelteCounter.svelte)0
-rw-r--r--packages/astro/e2e/fixtures/multiple-frameworks/src/components/vue/VueCounter.vue (renamed from packages/astro/e2e/fixtures/multiple-frameworks/src/components/VueCounter.vue)0
-rw-r--r--packages/astro/e2e/fixtures/multiple-frameworks/src/pages/index.astro10
-rw-r--r--packages/astro/e2e/fixtures/nested-in-preact/astro.config.mjs8
-rw-r--r--packages/astro/e2e/fixtures/nested-in-preact/src/components/preact/PreactCounter.tsx (renamed from packages/astro/e2e/fixtures/nested-in-preact/src/components/PreactCounter.tsx)0
-rw-r--r--packages/astro/e2e/fixtures/nested-in-preact/src/components/react/ReactCounter.jsx (renamed from packages/astro/e2e/fixtures/nested-in-preact/src/components/ReactCounter.jsx)0
-rw-r--r--packages/astro/e2e/fixtures/nested-in-preact/src/components/solid/SolidCounter.tsx (renamed from packages/astro/e2e/fixtures/nested-in-preact/src/components/SolidCounter.tsx)0
-rw-r--r--packages/astro/e2e/fixtures/nested-in-preact/src/components/svelte/SvelteCounter.svelte (renamed from packages/astro/e2e/fixtures/nested-in-preact/src/components/SvelteCounter.svelte)0
-rw-r--r--packages/astro/e2e/fixtures/nested-in-preact/src/components/vue/VueCounter.vue (renamed from packages/astro/e2e/fixtures/nested-in-preact/src/components/VueCounter.vue)0
-rw-r--r--packages/astro/e2e/fixtures/nested-in-preact/src/pages/index.astro10
-rw-r--r--packages/astro/e2e/fixtures/nested-in-react/astro.config.mjs8
-rw-r--r--packages/astro/e2e/fixtures/nested-in-react/src/components/preact/PreactCounter.tsx (renamed from packages/astro/e2e/fixtures/nested-in-react/src/components/PreactCounter.tsx)0
-rw-r--r--packages/astro/e2e/fixtures/nested-in-react/src/components/react/ReactCounter.jsx (renamed from packages/astro/e2e/fixtures/nested-in-react/src/components/ReactCounter.jsx)0
-rw-r--r--packages/astro/e2e/fixtures/nested-in-react/src/components/solid/SolidCounter.tsx (renamed from packages/astro/e2e/fixtures/nested-in-react/src/components/SolidCounter.tsx)0
-rw-r--r--packages/astro/e2e/fixtures/nested-in-react/src/components/svelte/SvelteCounter.svelte (renamed from packages/astro/e2e/fixtures/nested-in-react/src/components/SvelteCounter.svelte)0
-rw-r--r--packages/astro/e2e/fixtures/nested-in-react/src/components/vue/VueCounter.vue (renamed from packages/astro/e2e/fixtures/nested-in-react/src/components/VueCounter.vue)0
-rw-r--r--packages/astro/e2e/fixtures/nested-in-react/src/pages/index.astro10
-rw-r--r--packages/astro/e2e/fixtures/nested-in-solid/astro.config.mjs8
-rw-r--r--packages/astro/e2e/fixtures/nested-in-solid/src/components/preact/PreactCounter.tsx (renamed from packages/astro/e2e/fixtures/nested-in-solid/src/components/PreactCounter.tsx)0
-rw-r--r--packages/astro/e2e/fixtures/nested-in-solid/src/components/react/ReactCounter.jsx (renamed from packages/astro/e2e/fixtures/nested-in-solid/src/components/ReactCounter.jsx)0
-rw-r--r--packages/astro/e2e/fixtures/nested-in-solid/src/components/solid/SolidCounter.tsx (renamed from packages/astro/e2e/fixtures/nested-in-solid/src/components/SolidCounter.tsx)0
-rw-r--r--packages/astro/e2e/fixtures/nested-in-solid/src/components/svelte/SvelteCounter.svelte (renamed from packages/astro/e2e/fixtures/nested-in-solid/src/components/SvelteCounter.svelte)0
-rw-r--r--packages/astro/e2e/fixtures/nested-in-solid/src/components/vue/VueCounter.vue (renamed from packages/astro/e2e/fixtures/nested-in-solid/src/components/VueCounter.vue)0
-rw-r--r--packages/astro/e2e/fixtures/nested-in-solid/src/pages/index.astro10
-rw-r--r--packages/astro/e2e/fixtures/nested-in-svelte/astro.config.mjs8
-rw-r--r--packages/astro/e2e/fixtures/nested-in-svelte/src/components/preact/PreactCounter.tsx (renamed from packages/astro/e2e/fixtures/nested-in-svelte/src/components/PreactCounter.tsx)0
-rw-r--r--packages/astro/e2e/fixtures/nested-in-svelte/src/components/react/ReactCounter.jsx (renamed from packages/astro/e2e/fixtures/nested-in-svelte/src/components/ReactCounter.jsx)0
-rw-r--r--packages/astro/e2e/fixtures/nested-in-svelte/src/components/solid/SolidCounter.tsx (renamed from packages/astro/e2e/fixtures/nested-in-svelte/src/components/SolidCounter.tsx)0
-rw-r--r--packages/astro/e2e/fixtures/nested-in-svelte/src/components/svelte/SvelteCounter.svelte (renamed from packages/astro/e2e/fixtures/nested-in-svelte/src/components/SvelteCounter.svelte)0
-rw-r--r--packages/astro/e2e/fixtures/nested-in-svelte/src/components/vue/VueCounter.vue (renamed from packages/astro/e2e/fixtures/nested-in-svelte/src/components/VueCounter.vue)0
-rw-r--r--packages/astro/e2e/fixtures/nested-in-svelte/src/pages/index.astro10
-rw-r--r--packages/astro/e2e/fixtures/nested-in-vue/astro.config.mjs8
-rw-r--r--packages/astro/e2e/fixtures/nested-in-vue/src/components/preact/PreactCounter.tsx (renamed from packages/astro/e2e/fixtures/nested-in-vue/src/components/PreactCounter.tsx)0
-rw-r--r--packages/astro/e2e/fixtures/nested-in-vue/src/components/react/ReactCounter.jsx (renamed from packages/astro/e2e/fixtures/nested-in-vue/src/components/ReactCounter.jsx)0
-rw-r--r--packages/astro/e2e/fixtures/nested-in-vue/src/components/solid/SolidCounter.tsx (renamed from packages/astro/e2e/fixtures/nested-in-vue/src/components/SolidCounter.tsx)0
-rw-r--r--packages/astro/e2e/fixtures/nested-in-vue/src/components/svelte/SvelteCounter.svelte (renamed from packages/astro/e2e/fixtures/nested-in-vue/src/components/SvelteCounter.svelte)0
-rw-r--r--packages/astro/e2e/fixtures/nested-in-vue/src/components/vue/VueCounter.vue (renamed from packages/astro/e2e/fixtures/nested-in-vue/src/components/VueCounter.vue)0
-rw-r--r--packages/astro/e2e/fixtures/nested-in-vue/src/pages/index.astro10
-rw-r--r--packages/astro/e2e/fixtures/nested-recursive/astro.config.mjs8
-rw-r--r--packages/astro/e2e/fixtures/nested-recursive/src/components/preact/PreactCounter.tsx (renamed from packages/astro/e2e/fixtures/nested-recursive/src/components/PreactCounter.tsx)0
-rw-r--r--packages/astro/e2e/fixtures/nested-recursive/src/components/react/ReactCounter.jsx (renamed from packages/astro/e2e/fixtures/nested-recursive/src/components/ReactCounter.jsx)0
-rw-r--r--packages/astro/e2e/fixtures/nested-recursive/src/components/solid/SolidCounter.tsx (renamed from packages/astro/e2e/fixtures/nested-recursive/src/components/SolidCounter.tsx)0
-rw-r--r--packages/astro/e2e/fixtures/nested-recursive/src/components/svelte/SvelteCounter.svelte (renamed from packages/astro/e2e/fixtures/nested-recursive/src/components/SvelteCounter.svelte)0
-rw-r--r--packages/astro/e2e/fixtures/nested-recursive/src/components/vue/VueCounter.vue (renamed from packages/astro/e2e/fixtures/nested-recursive/src/components/VueCounter.vue)0
-rw-r--r--packages/astro/e2e/fixtures/nested-recursive/src/pages/index.astro10
-rw-r--r--packages/astro/e2e/fixtures/view-transitions/astro.config.mjs1
-rw-r--r--packages/astro/e2e/multiple-frameworks.test.js8
-rw-r--r--packages/astro/env.d.ts4
-rw-r--r--packages/astro/package.json54
-rw-r--r--packages/astro/src/@types/astro.ts139
-rw-r--r--packages/astro/src/assets/image-endpoint.ts11
-rw-r--r--packages/astro/src/assets/internal.ts1
-rw-r--r--packages/astro/src/assets/services/noop.ts17
-rw-r--r--packages/astro/src/assets/services/vendor/squoosh/impl.ts4
-rw-r--r--packages/astro/src/assets/types.ts2
-rw-r--r--packages/astro/src/assets/vite-plugin-assets.ts40
-rw-r--r--packages/astro/src/cli/add/index.ts7
-rw-r--r--packages/astro/src/cli/check/index.ts419
-rw-r--r--packages/astro/src/cli/check/print.ts119
-rw-r--r--packages/astro/src/cli/dev/index.ts2
-rw-r--r--packages/astro/src/cli/flags.ts3
-rw-r--r--packages/astro/src/cli/index.ts16
-rw-r--r--packages/astro/src/cli/install-package.ts124
-rw-r--r--packages/astro/src/content/types-generator.ts3
-rw-r--r--packages/astro/src/content/utils.ts15
-rw-r--r--packages/astro/src/content/vite-plugin-content-imports.ts18
-rw-r--r--packages/astro/src/core/README.md13
-rw-r--r--packages/astro/src/core/app/index.ts71
-rw-r--r--packages/astro/src/core/app/node.ts1
-rw-r--r--packages/astro/src/core/app/ssrPipeline.ts54
-rw-r--r--packages/astro/src/core/app/types.ts2
-rw-r--r--packages/astro/src/core/build/buildPipeline.ts211
-rw-r--r--packages/astro/src/core/build/generate.ts251
-rw-r--r--packages/astro/src/core/build/index.ts4
-rw-r--r--packages/astro/src/core/build/internal.ts11
-rw-r--r--packages/astro/src/core/build/plugins/README.md31
-rw-r--r--packages/astro/src/core/build/plugins/index.ts2
-rw-r--r--packages/astro/src/core/build/plugins/plugin-manifest.ts251
-rw-r--r--packages/astro/src/core/build/plugins/plugin-pages.ts14
-rw-r--r--packages/astro/src/core/build/plugins/plugin-prerender.ts2
-rw-r--r--packages/astro/src/core/build/plugins/plugin-renderers.ts2
-rw-r--r--packages/astro/src/core/build/plugins/plugin-ssr.ts237
-rw-r--r--packages/astro/src/core/build/static-build.ts11
-rw-r--r--packages/astro/src/core/compile/compile.ts2
-rw-r--r--packages/astro/src/core/config/config.ts2
-rw-r--r--packages/astro/src/core/config/schema.ts44
-rw-r--r--packages/astro/src/core/config/settings.ts4
-rw-r--r--packages/astro/src/core/cookies/cookies.ts16
-rw-r--r--packages/astro/src/core/cookies/index.ts2
-rw-r--r--packages/astro/src/core/cookies/response.ts2
-rw-r--r--packages/astro/src/core/create-vite.ts31
-rw-r--r--packages/astro/src/core/dev/container.ts6
-rw-r--r--packages/astro/src/core/endpoint/index.ts10
-rw-r--r--packages/astro/src/core/errors/errors.ts23
-rw-r--r--packages/astro/src/core/errors/index.ts1
-rw-r--r--packages/astro/src/core/errors/userError.ts1
-rw-r--r--packages/astro/src/core/logger/console.ts2
-rw-r--r--packages/astro/src/core/logger/core.ts69
-rw-r--r--packages/astro/src/core/logger/node.ts14
-rw-r--r--packages/astro/src/core/messages.ts9
-rw-r--r--packages/astro/src/core/pipeline.ts165
-rw-r--r--packages/astro/src/core/polyfill.ts23
-rw-r--r--packages/astro/src/core/render/context.ts3
-rw-r--r--packages/astro/src/core/render/core.ts20
-rw-r--r--packages/astro/src/core/render/environment.ts5
-rw-r--r--packages/astro/src/core/render/index.ts2
-rw-r--r--packages/astro/src/core/render/params-and-props.ts1
-rw-r--r--packages/astro/src/core/render/result.ts34
-rw-r--r--packages/astro/src/core/render/route-cache.ts11
-rw-r--r--packages/astro/src/core/routing/manifest/create.ts7
-rw-r--r--packages/astro/src/core/routing/validation.ts19
-rw-r--r--packages/astro/src/core/util.ts1
-rw-r--r--packages/astro/src/integrations/astroFeaturesValidation.ts157
-rw-r--r--packages/astro/src/integrations/index.ts102
-rw-r--r--packages/astro/src/jsx/server.ts20
-rw-r--r--packages/astro/src/prerender/utils.ts13
-rw-r--r--packages/astro/src/runtime/README.md1
-rw-r--r--packages/astro/src/runtime/compiler/index.ts20
-rw-r--r--packages/astro/src/runtime/server/endpoint.ts65
-rw-r--r--packages/astro/src/runtime/server/index.ts2
-rw-r--r--packages/astro/src/runtime/server/render/page.ts3
-rw-r--r--packages/astro/src/runtime/server/render/util.ts4
-rw-r--r--packages/astro/src/runtime/server/response.ts80
-rw-r--r--packages/astro/src/vite-plugin-astro-postprocess/index.ts3
-rw-r--r--packages/astro/src/vite-plugin-astro-server/environment.ts1
-rw-r--r--packages/astro/src/vite-plugin-astro-server/plugin.ts1
-rw-r--r--packages/astro/src/vite-plugin-astro-server/request.ts2
-rw-r--r--packages/astro/src/vite-plugin-astro-server/route.ts18
-rw-r--r--packages/astro/src/vite-plugin-head/index.ts2
-rw-r--r--packages/astro/src/vite-plugin-inject-env-ts/index.ts28
-rw-r--r--packages/astro/src/vite-plugin-jsx/index.ts251
-rw-r--r--packages/astro/src/vite-plugin-markdown/index.ts49
-rw-r--r--packages/astro/src/vite-plugin-mdx/README.md (renamed from packages/astro/src/vite-plugin-jsx/README.md)0
-rw-r--r--packages/astro/src/vite-plugin-mdx/import-source.ts (renamed from packages/astro/src/vite-plugin-jsx/import-source.ts)0
-rw-r--r--packages/astro/src/vite-plugin-mdx/index.ts130
-rw-r--r--packages/astro/src/vite-plugin-mdx/tag.ts (renamed from packages/astro/src/vite-plugin-jsx/tag.ts)4
-rw-r--r--packages/astro/test/0-css.test.js42
-rw-r--r--packages/astro/test/astro-assets-prefix.test.js6
-rw-r--r--packages/astro/test/astro-envs.test.js4
-rw-r--r--packages/astro/test/astro-external-files.test.js24
-rw-r--r--packages/astro/test/astro-get-static-paths.test.js7
-rw-r--r--packages/astro/test/astro-global.test.js6
-rw-r--r--packages/astro/test/astro-partial-html.test.js2
-rw-r--r--packages/astro/test/cli.test.js4
-rw-r--r--packages/astro/test/config-vite-css-target.test.js2
-rw-r--r--packages/astro/test/core-image.test.js21
-rw-r--r--packages/astro/test/custom-elements.test.js70
-rw-r--r--packages/astro/test/dev-routing.test.js8
-rw-r--r--packages/astro/test/featuresSupport.test.js55
-rw-r--r--packages/astro/test/fixtures/api-routes/src/pages/binary.dat.ts2
-rw-r--r--packages/astro/test/fixtures/api-routes/src/pages/context/data/[param].json.js2
-rw-r--r--packages/astro/test/fixtures/astro-assets-prefix/astro.config.mjs5
-rw-r--r--packages/astro/test/fixtures/astro-assets/src/pages/index.astro4
-rw-r--r--packages/astro/test/fixtures/astro-basic/astro.config.mjs2
-rw-r--r--packages/astro/test/fixtures/astro-cookies/src/pages/early-return.astro2
-rw-r--r--packages/astro/test/fixtures/astro-cookies/src/pages/get-json.astro2
-rw-r--r--packages/astro/test/fixtures/astro-cookies/src/pages/set-prefs.js2
-rw-r--r--packages/astro/test/fixtures/astro-get-static-paths/src/pages/data/[slug].json.ts2
-rw-r--r--packages/astro/test/fixtures/astro-get-static-paths/src/pages/nested-arrays/[slug].astro8
-rw-r--r--packages/astro/test/fixtures/astro-markdown-frontmatter-injection/src/pages/glob.json.js2
-rw-r--r--packages/astro/test/fixtures/astro-markdown/src/pages/headings-glob.json.js2
-rw-r--r--packages/astro/test/fixtures/astro-markdown/src/pages/raw-content.json.js2
-rw-r--r--packages/astro/test/fixtures/astro-markdown/src/pages/vite-env-vars-glob.json.js2
-rw-r--r--packages/astro/test/fixtures/astro-pagination/src/pages/posts/[slug]/[page].astro2
-rw-r--r--packages/astro/test/fixtures/astro-slots-nested/astro.config.mjs6
-rw-r--r--packages/astro/test/fixtures/astro-slots-nested/src/components/preact/PassesChildrenP.tsx (renamed from packages/astro/test/fixtures/astro-slots-nested/src/components/PassesChildrenP.tsx)0
-rw-r--r--packages/astro/test/fixtures/astro-slots-nested/src/components/react/Inner.tsx (renamed from packages/astro/test/fixtures/astro-slots-nested/src/components/Inner.tsx)0
-rw-r--r--packages/astro/test/fixtures/astro-slots-nested/src/components/react/Parent.jsx (renamed from packages/astro/test/fixtures/astro-slots-nested/src/components/Parent.jsx)0
-rw-r--r--packages/astro/test/fixtures/astro-slots-nested/src/components/react/PassesChildren.tsx (renamed from packages/astro/test/fixtures/astro-slots-nested/src/components/PassesChildren.tsx)0
-rw-r--r--packages/astro/test/fixtures/astro-slots-nested/src/components/solid/PassesChildrenS.tsx (renamed from packages/astro/test/fixtures/astro-slots-nested/src/components/PassesChildrenS.tsx)0
-rw-r--r--packages/astro/test/fixtures/astro-slots-nested/src/pages/component-slot.astro2
-rw-r--r--packages/astro/test/fixtures/astro-slots-nested/src/pages/hidden-nested.astro4
-rw-r--r--packages/astro/test/fixtures/astro-slots-nested/src/pages/server-component-nested.astro6
-rw-r--r--packages/astro/test/fixtures/content-collection-references/astro.config.mjs3
-rw-r--r--packages/astro/test/fixtures/content-collection-references/src/content/banners/welcome.json2
-rw-r--r--packages/astro/test/fixtures/content-collection-references/src/pages/welcome-data.json.js2
-rw-r--r--packages/astro/test/fixtures/content-collections/src/pages/collections.json.js2
-rw-r--r--packages/astro/test/fixtures/content-collections/src/pages/entries.json.js2
-rw-r--r--packages/astro/test/fixtures/core-image-base/src/content/blog/one.md2
-rw-r--r--packages/astro/test/fixtures/core-image-base/tsconfig.json9
-rw-r--r--packages/astro/test/fixtures/core-image-ssg/tsconfig.json9
-rw-r--r--packages/astro/test/fixtures/core-image-ssr/src/pages/api.ts2
-rw-r--r--packages/astro/test/fixtures/core-image/src/content/blog/one.md6
-rw-r--r--packages/astro/test/fixtures/core-image/tsconfig.json9
-rw-r--r--packages/astro/test/fixtures/custom-elements/astro.config.mjs6
-rw-r--r--packages/astro/test/fixtures/custom-elements/my-component-lib/hydration-polyfill.js1
-rw-r--r--packages/astro/test/fixtures/custom-elements/my-component-lib/index.js31
-rw-r--r--packages/astro/test/fixtures/custom-elements/my-component-lib/package.json13
-rw-r--r--packages/astro/test/fixtures/custom-elements/my-component-lib/polyfill.js2
-rw-r--r--packages/astro/test/fixtures/custom-elements/my-component-lib/server.js30
-rw-r--r--packages/astro/test/fixtures/custom-elements/my-component-lib/shim.js28
-rw-r--r--packages/astro/test/fixtures/custom-elements/package.json9
-rw-r--r--packages/astro/test/fixtures/custom-elements/src/components/my-element.js13
-rw-r--r--packages/astro/test/fixtures/custom-elements/src/pages/ctr.astro16
-rw-r--r--packages/astro/test/fixtures/custom-elements/src/pages/index.astro15
-rw-r--r--packages/astro/test/fixtures/custom-elements/src/pages/nested.astro11
-rw-r--r--packages/astro/test/fixtures/custom-elements/src/pages/nossr.astro14
-rw-r--r--packages/astro/test/fixtures/data-collections/src/pages/authors/[id].json.js2
-rw-r--r--packages/astro/test/fixtures/data-collections/src/pages/authors/all.json.js2
-rw-r--r--packages/astro/test/fixtures/data-collections/src/pages/translations/[lang].json.js2
-rw-r--r--packages/astro/test/fixtures/data-collections/src/pages/translations/all.json.js2
-rw-r--r--packages/astro/test/fixtures/dynamic-endpoint-collision/src/pages/api/catch/[...slug].ts2
-rw-r--r--packages/astro/test/fixtures/jsx/astro.config.mjs19
-rw-r--r--packages/astro/test/fixtures/jsx/package.json1
-rw-r--r--packages/astro/test/fixtures/jsx/src/components/Content.mdx5
-rw-r--r--packages/astro/test/fixtures/jsx/src/components/Frameworks.jsx28
-rw-r--r--packages/astro/test/fixtures/jsx/src/components/preact/PreactCounter.tsx (renamed from packages/astro/test/fixtures/jsx/src/components/PreactCounter.tsx)0
-rw-r--r--packages/astro/test/fixtures/jsx/src/components/react/ReactCounter.jsx (renamed from packages/astro/test/fixtures/jsx/src/components/ReactCounter.jsx)2
-rw-r--r--packages/astro/test/fixtures/jsx/src/components/solid/SolidCounter.jsx (renamed from packages/astro/test/fixtures/jsx/src/components/SolidCounter.jsx)0
-rw-r--r--packages/astro/test/fixtures/jsx/src/pages/frameworks.astro34
-rw-r--r--packages/astro/test/fixtures/middleware-dev/src/pages/api/endpoint.js2
-rw-r--r--packages/astro/test/fixtures/non-html-pages/src/pages/about.json.ts2
-rw-r--r--packages/astro/test/fixtures/non-html-pages/src/pages/placeholder.png.ts2
-rw-r--r--packages/astro/test/fixtures/preact-compat-component/packages/react-lib/index.js2
-rw-r--r--packages/astro/test/fixtures/preact-compat-component/src/components/Counter.jsx1
-rw-r--r--packages/astro/test/fixtures/routing-priority/src/pages/api/catch/[...slug].json.ts2
-rw-r--r--packages/astro/test/fixtures/routing-priority/src/pages/api/catch/[foo]-[bar].json.ts2
-rw-r--r--packages/astro/test/fixtures/ssr-api-route-custom-404/src/pages/api/route.js2
-rw-r--r--packages/astro/test/fixtures/ssr-api-route/src/pages/binary.js2
-rw-r--r--packages/astro/test/fixtures/ssr-api-route/src/pages/context/[param].js2
-rw-r--r--packages/astro/test/fixtures/ssr-api-route/src/pages/food.json.js4
-rw-r--r--packages/astro/test/fixtures/ssr-api-route/src/pages/login.js2
-rw-r--r--packages/astro/test/fixtures/ssr-dynamic/src/pages/api/products/[id].js2
-rw-r--r--packages/astro/test/fixtures/ssr-locals/src/pages/api.js2
-rw-r--r--packages/astro/test/fixtures/ssr-prerender-get-static-paths/src/pages/data/[slug].json.ts2
-rw-r--r--packages/astro/test/fixtures/ssr-prerender-get-static-paths/src/pages/nested-arrays/[slug].astro10
-rw-r--r--packages/astro/test/fixtures/ssr-preview/preview.mjs2
-rw-r--r--packages/astro/test/fixtures/static-build/src/pages/company.json.ts4
-rw-r--r--packages/astro/test/fixtures/static-build/src/pages/data/[slug].json.ts4
-rw-r--r--packages/astro/test/fixtures/static-build/src/pages/posts.json.js2
-rw-r--r--packages/astro/test/fixtures/tailwindcss/src/pages/markdown-page.md11
-rw-r--r--packages/astro/test/fixtures/with-endpoint-routes/src/pages/[slug].json.ts2
-rw-r--r--packages/astro/test/fixtures/with-endpoint-routes/src/pages/data/[slug].json.ts2
-rw-r--r--packages/astro/test/fixtures/with-endpoint-routes/src/pages/home.json.ts2
-rw-r--r--packages/astro/test/fixtures/with-endpoint-routes/src/pages/images/[image].svg.ts2
-rw-r--r--packages/astro/test/fixtures/with-endpoint-routes/src/pages/images/hex.ts2
-rw-r--r--packages/astro/test/fixtures/with-endpoint-routes/src/pages/images/static.svg.ts2
-rw-r--r--packages/astro/test/jsx.test.js28
-rw-r--r--packages/astro/test/preact-compat-component.test.js29
-rw-r--r--packages/astro/test/preview-routing.test.js8
-rw-r--r--packages/astro/test/public-base-404.test.js2
-rw-r--r--packages/astro/test/scoped-style-strategy.test.js34
-rw-r--r--packages/astro/test/ssr-api-route.test.js1
-rw-r--r--packages/astro/test/ssr-hoisted-script.test.js64
-rw-r--r--packages/astro/test/ssr-manifest.test.js1
-rw-r--r--packages/astro/test/ssr-prerender-get-static-paths.test.js12
-rw-r--r--packages/astro/test/ssr-split-manifest.test.js2
-rw-r--r--packages/astro/test/static-build.test.js2
-rw-r--r--packages/astro/test/tailwindcss.test.js9
-rw-r--r--packages/astro/test/test-adapter.js9
-rw-r--r--packages/astro/test/test-utils.js9
-rw-r--r--packages/astro/test/units/content-collections/get-entry-type.test.js21
-rw-r--r--packages/astro/test/units/cookies/delete.test.js2
-rw-r--r--packages/astro/test/units/cookies/get.test.js14
-rw-r--r--packages/astro/test/units/integrations/api.test.js186
-rw-r--r--packages/astro/test/units/render/head.test.js9
-rw-r--r--packages/astro/test/units/render/jsx.test.js9
-rw-r--r--packages/astro/tsconfig.json2
-rw-r--r--packages/astro/tsconfigs/base.json19
-rw-r--r--packages/astro/tsconfigs/strict.json5
306 files changed, 3404 insertions, 2919 deletions
diff --git a/packages/astro/CHANGELOG.md b/packages/astro/CHANGELOG.md
index e3865fe33..e026a0eed 100644
--- a/packages/astro/CHANGELOG.md
+++ b/packages/astro/CHANGELOG.md
@@ -1,5 +1,332 @@
# astro
+## 3.0.0-beta.2
+
+### Patch Changes
+
+- Updated dependencies [[`2aa6d8ace`](https://github.com/withastro/astro/commit/2aa6d8ace398a41c2dec5473521d758816b08191)]:
+ - @astrojs/internal-helpers@0.2.0-beta.1
+
+## 3.0.0-beta.1
+
+### Major Changes
+
+- [#7952](https://github.com/withastro/astro/pull/7952) [`3c3100851`](https://github.com/withastro/astro/commit/3c31008519ce68b5b1b1cb23b71fbe0a2d506882) Thanks [@astrobot-houston](https://github.com/astrobot-houston)! - Remove support for `Astro.__renderMarkdown` which is used by `@astrojs/markdown-component`.
+
+ The `<Markdown />` component was deprecated in Astro v1 and is completely removed in v3. This integration must now be removed from your project.
+
+ As an alternative, you can use community packages that provide a similar component like https://github.com/natemoo-re/astro-remote instead.
+
+- [#8019](https://github.com/withastro/astro/pull/8019) [`34cb20021`](https://github.com/withastro/astro/commit/34cb2002161ba88df6bcb72fecfd12ed867c134b) Thanks [@bluwy](https://github.com/bluwy)! - Remove backwards-compatible kebab-case transform for camelCase CSS variable names passed to the `style` attribute. If you were relying on the kebab-case transform in your styles, make sure to use the camelCase version to prevent missing styles. For example:
+
+ ```astro
+ ---
+ const myValue = 'red';
+ ---
+
+ <!-- input -->
+ <div style={{ '--myValue': myValue }}></div>
+
+ <!-- output (before) -->
+ <div style="--my-value:var(--myValue);--myValue:red"></div>
+
+ <!-- output (after) -->
+ <div style="--myValue:red"></div>
+ ```
+
+ ```diff
+ <style>
+ div {
+ - color: var(--my-value);
+ + color: var(--myValue);
+ }
+ </style>
+ ```
+
+- [#7893](https://github.com/withastro/astro/pull/7893) [`7bd1b86f8`](https://github.com/withastro/astro/commit/7bd1b86f85c06fdde0a1ed9146d01bac69990671) Thanks [@ematipico](https://github.com/ematipico)! - Implements a new scope style strategy called `"attribute"`. When enabled, styles are applied using `data-*` attributes.
+
+ The **default** value of `scopedStyleStrategy` is `"attribute"`.
+
+ If you want to use the previous behaviour, you have to use the `"where"` option:
+
+ ```diff
+ import { defineConfig } from 'astro/config';
+
+ export default defineConfig({
+ + scopedStyleStrategy: 'where',
+ });
+ ```
+
+- [#7924](https://github.com/withastro/astro/pull/7924) [`519a1c4e8`](https://github.com/withastro/astro/commit/519a1c4e8407c7abcb8d879b67a9f4b960652cae) Thanks [@matthewp](https://github.com/matthewp)! - Astro's JSX handling has been refactored with better support for each framework.
+
+ Previously, Astro automatically scanned your components to determine which framework-specific transformations should be used. In practice, supporting advanced features like Fast Refresh with this approach proved difficult.
+
+ Now, Astro determines which framework to use with `include` and `exclude` config options where you can specify files and folders on a per-framework basis. When using multiple JSX frameworks in the same project, users should manually control which files belong to each framework using the `include` and `exclude` options.
+
+ ```js
+ export default defineConfig({
+ // The `include` config is only needed in projects that use multiple JSX frameworks;
+ // if only using one no extra config is needed.
+ integrations: [
+ preact({
+ include: ['**/preact/*'],
+ }),
+ react({
+ include: ['**/react/*'],
+ }),
+ solid({
+ include: ['**/solid/*'],
+ }),
+ ],
+ });
+ ```
+
+- [#7878](https://github.com/withastro/astro/pull/7878) [`0f637c71e`](https://github.com/withastro/astro/commit/0f637c71e511cb4c51712128d217a26c8eee4d40) Thanks [@bluwy](https://github.com/bluwy)! - The value of `import.meta.env.BASE_URL`, which is derived from the `base` option, will no longer have a trailing slash added by default or when `trailingSlash: "ignore"` is set. The existing behavior of `base` in combination with `trailingSlash: "always"` or `trailingSlash: "never"` is unchanged.
+
+ If your `base` already has a trailing slash, no change is needed.
+
+ If your `base` does not have a trailing slash, add one to preserve the previous behaviour:
+
+ ```diff
+ // astro.config.mjs
+ - base: 'my-base',
+ + base: 'my-base/',
+ ```
+
+### Minor Changes
+
+- [#8012](https://github.com/withastro/astro/pull/8012) [`866ed4098`](https://github.com/withastro/astro/commit/866ed4098edffb052239cdb26e076cf8db61b1d9) Thanks [@ematipico](https://github.com/ematipico)! - Add a new `astro/errors` module. Developers can import `AstroUserError`, and provide a `message` and an optional `hint`
+
+### Patch Changes
+
+- [#7998](https://github.com/withastro/astro/pull/7998) [`65c354969`](https://github.com/withastro/astro/commit/65c354969e6fe0ef6d622e8f4c545e2f717ce8c6) Thanks [@bluwy](https://github.com/bluwy)! - Call `astro sync` once before calling `astro check`
+
+- [#7952](https://github.com/withastro/astro/pull/7952) [`70f34f5a3`](https://github.com/withastro/astro/commit/70f34f5a355f42526ee9e5355f3de8e510002ea2) Thanks [@astrobot-houston](https://github.com/astrobot-houston)! - Remove StreamingCompatibleResponse polyfill
+
+- [#8011](https://github.com/withastro/astro/pull/8011) [`5b1e39ef6`](https://github.com/withastro/astro/commit/5b1e39ef6ec6dcebea96584f95d9530bd9aa715d) Thanks [@bluwy](https://github.com/bluwy)! - Move hoisted script analysis optimization behind the `experimental.optimizeHoistedScript` option
+
+- Updated dependencies [[`b675acb2a`](https://github.com/withastro/astro/commit/b675acb2aa820448e9c0d363339a37fbac873215)]:
+ - @astrojs/telemetry@3.0.0-beta.1
+
+## 3.0.0-beta.0
+
+### Major Changes
+
+- [`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.
+
+- [`76ddef19c`](https://github.com/withastro/astro/commit/76ddef19ccab6e5f7d3a5740cd41acf10e334b38) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Removed automatic flattening of `getStaticPaths` result. `.flatMap` and `.flat` should now be used to ensure that you're returning a flat array.
+
+- [`3fdf509b2`](https://github.com/withastro/astro/commit/3fdf509b2731a9b2f972d89291e57cf78d62c769) Thanks [@ematipico](https://github.com/ematipico)! - The `build.split` and `build.excludeMiddleware` configuration options are deprecated and have been replaced by options in the adapter config.
+
+ If your config includes the `build.excludeMiddleware` option, replace it with `edgeMiddleware` in your adapter options:
+
+ ```diff
+ import { defineConfig } from "astro/config";
+ import netlify from "@astrojs/netlify/functions";
+
+ export default defineConfig({
+ build: {
+ - excludeMiddleware: true
+ },
+ adapter: netlify({
+ + edgeMiddleware: true
+ }),
+ });
+ ```
+
+ If your config includes the `build.split` option, replace it with `functionPerRoute` in your adapter options:
+
+ ```diff
+ import { defineConfig } from "astro/config";
+ import netlify from "@astrojs/netlify/functions";
+
+ export default defineConfig({
+ build: {
+ - split: true
+ },
+ adapter: netlify({
+ + functionPerRoute: true
+ }),
+ });
+ ```
+
+- [`2f951cd40`](https://github.com/withastro/astro/commit/2f951cd403dfcc2c3ca6aae618ae3e1409516e32) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Sharp is now the default image service used for `astro:assets`. If you would prefer to still use Squoosh, you can update your config with the following:
+
+ ```ts
+ import { defineConfig, squooshImageService } from 'astro/config';
+
+ // https://astro.build/config
+ export default defineConfig({
+ image: {
+ service: squooshImageService(),
+ },
+ });
+ ```
+
+ However, not only do we recommend using Sharp as it is faster and more reliable, it is also highly likely that the Squoosh service will be removed in a future release.
+
+- [`c022a4217`](https://github.com/withastro/astro/commit/c022a4217a805d223c1494e9eda4e48bbf810388) Thanks [@Princesseuh](https://github.com/Princesseuh)! - When using an adapter that supports neither Squoosh or Sharp, Astro will now automatically use an image service that does not support processing, but still provides the other benefits of `astro:assets` such as enforcing `alt`, no CLS etc to users
+
+- [`67becaa58`](https://github.com/withastro/astro/commit/67becaa580b8f787df58de66b7008b7098f1209c) Thanks [@ematipico](https://github.com/ematipico)! - Removed support for old syntax of the API routes.
+
+- [`dfc2d93e3`](https://github.com/withastro/astro/commit/dfc2d93e3c645995379358fabbdfa9aab99f43d8) Thanks [@bluwy](https://github.com/bluwy)! - Remove MDX plugin re-ordering hack
+
+- [`3dc1ca2fa`](https://github.com/withastro/astro/commit/3dc1ca2fac8d9965cc5085a5d09e72ed87b4281a) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Reduced the amount of polyfills provided by Astro. Astro will no longer provide (no-op) polyfills for several web apis such as HTMLElement, Image or Document. If you need access to those APIs on the server, we recommend using more proper polyfills available on npm.
+
+- [`1be84dfee`](https://github.com/withastro/astro/commit/1be84dfee3ce8e6f5cc624f99aec4e980f6fde37) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Update `tsconfig.json` presets with `moduleResolution: 'bundler'` and other new options from TypeScript 5.0. Astro now assumes that you use TypeScript 5.0 (March 2023), or that your editor includes it, ex: VS Code 1.77
+
+- [`35f01df79`](https://github.com/withastro/astro/commit/35f01df797d23315f2bee2fc3fd795adb0559c58) Thanks [@Princesseuh](https://github.com/Princesseuh)! - The `astro check` command now requires an external package `@astrojs/check` and an install of `typescript` in your project. This was done in order to make the main `astro` package smaller and give more flexibility to users in regard to the version of TypeScript they use.
+
+- [`3fdf509b2`](https://github.com/withastro/astro/commit/3fdf509b2731a9b2f972d89291e57cf78d62c769) Thanks [@ematipico](https://github.com/ematipico)! - The `build.split` and `build.excludeMiddleware` configuration options are deprecated and have been replaced by options in the adapter config.
+
+ If your config includes the `build.excludeMiddleware` option, replace it with `edgeMiddleware` in your adapter options:
+
+ ```diff
+ import { defineConfig } from "astro/config";
+ import vercel from "@astrojs/vercel/serverless";
+
+ export default defineConfig({
+ build: {
+ - excludeMiddleware: true
+ },
+ adapter: vercel({
+ + edgeMiddleware: true
+ }),
+ });
+ ```
+
+ If your config includes the `build.split` option, replace it with `functionPerRoute` in your adapter options:
+
+ ```diff
+ import { defineConfig } from "astro/config";
+ import vercel from "@astrojs/vercel/serverless";
+
+ export default defineConfig({
+ build: {
+ - split: true
+ },
+ adapter: vercel({
+ + functionPerRoute: true
+ }),
+ });
+ ```
+
+- [`78de801f2`](https://github.com/withastro/astro/commit/78de801f21fd4ca1653950027d953bf08614566b) Thanks [@ematipico](https://github.com/ematipico)! - Lowercase names for endpoint functions are now deprecated.
+
+ Rename functions to their uppercase equivalent:
+
+ ```diff
+ - export function get() {
+ + export function GET() {
+ return new Response(JSON.stringify({ "title": "Bob's blog" }));
+ }
+
+ - export function post() {
+ + export function POST() {
+ return new Response(JSON.stringify({ "title": "Bob's blog" }));
+ }
+
+ - export function put() {
+ + export function PUT() {
+ return new Response(JSON.stringify({ "title": "Bob's blog" }));
+ }
+
+ - export function all() {
+ + export function ALL() {
+ return new Response(JSON.stringify({ "title": "Bob's blog" }));
+ }
+
+ // you can use the whole word "DELETE"
+ - export function del() {
+ + export function DELETE() {
+ return new Response(JSON.stringify({ "title": "Bob's blog" }));
+ }
+ ```
+
+- [`59d6e569f`](https://github.com/withastro/astro/commit/59d6e569f63e175c97e82e94aa7974febfb76f7c) Thanks [@matthewp](https://github.com/matthewp)! - Astro.cookies.get(key) returns undefined if cookie doesn't exist
+
+ With this change, Astro.cookies.get(key) no longer always returns a `AstroCookie` object. Instead it now returns `undefined` if the cookie does not exist.
+
+ You should update your code if you assume that all calls to `get()` return a value. When using with `has()` you still need to assert the value, like so:
+
+ ```astro
+ ---
+ if (Astro.cookies.has(id)) {
+ const id = Astro.cookies.get(id)!;
+ }
+ ---
+ ```
+
+- [`7723c4cc9`](https://github.com/withastro/astro/commit/7723c4cc93298c2e6530e55da7afda048f22cf81) Thanks [@ematipico](https://github.com/ematipico)! - The property `compressHTML` is now `true` by default. Setting this value to `true` is no longer required.
+
+ If you do not want to minify your HTML output, you must set this value to `false` in `astro.config.mjs`.
+
+ ```diff
+ import {defineConfig} from "astro/config";
+ export default defineConfig({
+ + compressHTML: false
+ })
+ ```
+
+- [`fb5cd6b56`](https://github.com/withastro/astro/commit/fb5cd6b56dc27a71366ed5e1ab8bfe9b8f96bac5) Thanks [@ematipico](https://github.com/ematipico)! - Astro's default port when running the dev or preview server is now `4321`.
+
+ This will reduce conflicts with ports used by other tools.
+
+- [`631b9c410`](https://github.com/withastro/astro/commit/631b9c410d5d66fa384674027ba95d69ebb5063f) Thanks [@bluwy](https://github.com/bluwy)! - Remove MDX special `components` export handling
+
+### Minor Changes
+
+- [`9b4f70a62`](https://github.com/withastro/astro/commit/9b4f70a629f55e461759ba46f68af7097a2e9215) Thanks [@ematipico](https://github.com/ematipico)! - Introduced the concept of feature map. A feature map is a list of features that are built-in in Astro, and an Adapter
+ can tell Astro if it can support it.
+
+ ```ts
+ import { AstroIntegration } from './astro';
+
+ function myIntegration(): AstroIntegration {
+ return {
+ name: 'astro-awesome-list',
+ // new feature map
+ supportedAstroFeatures: {
+ hybridOutput: 'experimental',
+ staticOutput: 'stable',
+ serverOutput: 'stable',
+ assets: {
+ supportKind: 'stable',
+ isSharpCompatible: false,
+ isSquooshCompatible: false,
+ },
+ },
+ };
+ }
+ ```
+
+- [`bc37331d8`](https://github.com/withastro/astro/commit/bc37331d8154e3e95a8df9131e4e014e78a7a9e7) Thanks [@ematipico](https://github.com/ematipico)! - Integrations can now log messages using Astro’s built-in logger.
+
+ The logger is available to all hooks as an additional parameter:
+
+ ```ts
+ import { AstroIntegration } from './astro';
+
+ // integration.js
+ export function myIntegration(): AstroIntegration {
+ return {
+ name: 'my-integration',
+ hooks: {
+ 'astro:config:done': ({ logger }) => {
+ logger.info('Configure integration...');
+ },
+ },
+ };
+ }
+ ```
+
+### Patch Changes
+
+- Updated dependencies [[`1eae2e3f7`](https://github.com/withastro/astro/commit/1eae2e3f7d693c9dfe91c8ccfbe606d32bf2fb81)]:
+ - @astrojs/telemetry@3.0.0-beta.0
+ - @astrojs/internal-helpers@0.2.0-beta.0
+ - @astrojs/markdown-remark@3.0.0-beta.0
+
## 2.10.9
### Patch Changes
diff --git a/packages/astro/astro-jsx.d.ts b/packages/astro/astro-jsx.d.ts
index a04d755ec..b82de9388 100644
--- a/packages/astro/astro-jsx.d.ts
+++ b/packages/astro/astro-jsx.d.ts
@@ -9,6 +9,8 @@
* Adapted from React’s TypeScript definition from DefinitelyTyped.
* @see https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/index.d.ts
*/
+// BUG! Prettier 3.0 removes `declare`: https://github.com/prettier/prettier/issues/15207
+// prettier-ignore
declare namespace astroHTML.JSX {
export type Child = Node | Node[] | string | number | boolean | null | undefined | unknown;
export type Children = Child | Child[];
diff --git a/packages/astro/astro.js b/packages/astro/astro.js
index 37ea869bc..631a7b9c8 100755
--- a/packages/astro/astro.js
+++ b/packages/astro/astro.js
@@ -13,8 +13,8 @@ const CI_INSTRUCTIONS = {
};
// Hardcode supported Node.js version so we don't have to read differently in CJS & ESM.
-const engines = '>=16.12.0';
-const skipSemverCheckIfAbove = 16;
+const engines = '>=18.14.1';
+const skipSemverCheckIfAbove = 19;
/** `astro *` */
async function main() {
diff --git a/packages/astro/client-base.d.ts b/packages/astro/client-base.d.ts
deleted file mode 100644
index 3b0ee4901..000000000
--- a/packages/astro/client-base.d.ts
+++ /dev/null
@@ -1,427 +0,0 @@
-/// <reference path="./import-meta.d.ts" />
-
-// eslint-disable-next-line @typescript-eslint/no-namespace
-declare namespace App {
- // eslint-disable-next-line @typescript-eslint/no-empty-interface
- export interface Locals {}
-}
-
-interface ImportMetaEnv {
- /**
- * The prefix for Astro-generated asset links if the build.assetsPrefix config option is set. This can be used to create asset links not handled by Astro.
- */
- readonly ASSETS_PREFIX: string;
- /**
- * This is set to the site option specified in your project’s Astro config file.
- */
- readonly SITE: string;
-}
-
-interface ImportMeta {
- /**
- * Astro and Vite expose environment variables through `import.meta.env`. For a complete list of the environment variables available, see the two references below.
- *
- * - [Astro reference](https://docs.astro.build/en/guides/environment-variables/#default-environment-variables)
- * - [Vite reference](https://vitejs.dev/guide/env-and-mode.html#env-variables)
- */
- readonly env: ImportMetaEnv;
-}
-
-declare module 'astro:assets' {
- // Exporting things one by one is a bit cumbersome, not sure if there's a better way - erika, 2023-02-03
- type AstroAssets = {
- // getImage's type here is different from the internal function since the Vite module implicitly pass the service config
- /**
- * Get an optimized image and the necessary attributes to render it.
- *
- * **Example**
- * ```astro
- * ---
- * import { getImage } from 'astro:assets';
- * import originalImage from '../assets/image.png';
- *
- * const optimizedImage = await getImage({src: originalImage, width: 1280 });
- * ---
- * <img src={optimizedImage.src} {...optimizedImage.attributes} />
- * ```
- *
- * This is functionally equivalent to using the `<Image />` component, as the component calls this function internally.
- */
- getImage: (
- options:
- | import('./dist/assets/types.js').ImageTransform
- | import('./dist/assets/types.js').UnresolvedImageTransform
- ) => Promise<import('./dist/assets/types.js').GetImageResult>;
- getConfiguredImageService: typeof import('./dist/assets/index.js').getConfiguredImageService;
- Image: typeof import('./components/Image.astro').default;
- };
-
- type WithRequired<T, K extends keyof T> = T & { [P in K]-?: T[P] };
- type Simplify<T> = { [KeyType in keyof T]: T[KeyType] };
- type ImgAttributes = WithRequired<
- Omit<import('./types').HTMLAttributes<'img'>, 'src' | 'width' | 'height'>,
- 'alt'
- >;
-
- export type LocalImageProps = Simplify<
- import('./dist/assets/types.js').LocalImageProps<ImgAttributes>
- >;
- export type RemoteImageProps = Simplify<
- import('./dist/assets/types.js').RemoteImageProps<ImgAttributes>
- >;
- export const { getImage, getConfiguredImageService, Image }: AstroAssets;
-}
-
-declare module 'astro:transitions' {
- type TransitionModule = typeof import('./dist/transitions/index.js');
- export const slide: TransitionModule['slide'];
- export const fade: TransitionModule['fade'];
-
- type ViewTransitionsModule = typeof import('./components/ViewTransitions.astro');
- export const ViewTransitions: ViewTransitionsModule['default'];
-}
-
-type MD = import('./dist/@types/astro').MarkdownInstance<Record<string, any>>;
-interface ExportedMarkdownModuleEntities {
- frontmatter: MD['frontmatter'];
- file: MD['file'];
- url: MD['url'];
- getHeadings: MD['getHeadings'];
- /** @deprecated Renamed to `getHeadings()` */
- getHeaders: () => void;
- Content: MD['Content'];
- rawContent: MD['rawContent'];
- compiledContent: MD['compiledContent'];
- load: MD['default'];
-}
-
-declare module '*.md' {
- const { load }: ExportedMarkdownModuleEntities;
- export const {
- frontmatter,
- file,
- url,
- getHeadings,
- getHeaders,
- Content,
- rawContent,
- compiledContent,
- }: ExportedMarkdownModuleEntities;
- export default load;
-}
-
-declare module '*.markdown' {
- const { load }: ExportedMarkdownModuleEntities;
- export const {
- frontmatter,
- file,
- url,
- getHeadings,
- getHeaders,
- Content,
- rawContent,
- compiledContent,
- }: ExportedMarkdownModuleEntities;
- export default load;
-}
-
-declare module '*.mkdn' {
- const { load }: ExportedMarkdownModuleEntities;
- export const {
- frontmatter,
- file,
- url,
- getHeadings,
- getHeaders,
- Content,
- rawContent,
- compiledContent,
- }: ExportedMarkdownModuleEntities;
- export default load;
-}
-
-declare module '*.mkd' {
- const { load }: ExportedMarkdownModuleEntities;
- export const {
- frontmatter,
- file,
- url,
- getHeadings,
- getHeaders,
- Content,
- rawContent,
- compiledContent,
- }: ExportedMarkdownModuleEntities;
- export default load;
-}
-
-declare module '*.mdwn' {
- const { load }: ExportedMarkdownModuleEntities;
- export const {
- frontmatter,
- file,
- url,
- getHeadings,
- getHeaders,
- Content,
- rawContent,
- compiledContent,
- }: ExportedMarkdownModuleEntities;
- export default load;
-}
-
-declare module '*.mdown' {
- const { load }: ExportedMarkdownModuleEntities;
- export const {
- frontmatter,
- file,
- url,
- getHeadings,
- getHeaders,
- Content,
- rawContent,
- compiledContent,
- }: ExportedMarkdownModuleEntities;
- export default load;
-}
-
-declare module '*.mdx' {
- type MDX = import('./dist/@types/astro').MDXInstance<Record<string, any>>;
-
- export const frontmatter: MDX['frontmatter'];
- export const file: MDX['file'];
- export const url: MDX['url'];
- export const getHeadings: MDX['getHeadings'];
- export const Content: MDX['Content'];
-
- const load: MDX['default'];
- export default load;
-}
-
-declare module 'astro:ssr-manifest' {
- export const manifest: import('./dist/@types/astro').SSRManifest;
-}
-
-// Everything below are Vite's types (apart from image types, which are in `client.d.ts`)
-
-// CSS modules
-type CSSModuleClasses = { readonly [key: string]: string };
-
-declare module '*.module.css' {
- const classes: CSSModuleClasses;
- export default classes;
-}
-declare module '*.module.scss' {
- const classes: CSSModuleClasses;
- export default classes;
-}
-declare module '*.module.sass' {
- const classes: CSSModuleClasses;
- export default classes;
-}
-declare module '*.module.less' {
- const classes: CSSModuleClasses;
- export default classes;
-}
-declare module '*.module.styl' {
- const classes: CSSModuleClasses;
- export default classes;
-}
-declare module '*.module.stylus' {
- const classes: CSSModuleClasses;
- export default classes;
-}
-declare module '*.module.pcss' {
- const classes: CSSModuleClasses;
- export default classes;
-}
-declare module '*.module.sss' {
- const classes: CSSModuleClasses;
- export default classes;
-}
-
-// CSS
-declare module '*.css' {
- const css: string;
- export default css;
-}
-declare module '*.scss' {
- const css: string;
- export default css;
-}
-declare module '*.sass' {
- const css: string;
- export default css;
-}
-declare module '*.less' {
- const css: string;
- export default css;
-}
-declare module '*.styl' {
- const css: string;
- export default css;
-}
-declare module '*.stylus' {
- const css: string;
- export default css;
-}
-declare module '*.pcss' {
- const css: string;
- export default css;
-}
-declare module '*.sss' {
- const css: string;
- export default css;
-}
-
-// Built-in asset types
-// see `src/node/constants.ts`
-
-// images
-declare module '*.jfif' {
- const src: string;
- export default src;
-}
-declare module '*.pjpeg' {
- const src: string;
- export default src;
-}
-declare module '*.pjp' {
- const src: string;
- export default src;
-}
-declare module '*.ico' {
- const src: string;
- export default src;
-}
-
-// media
-declare module '*.mp4' {
- const src: string;
- export default src;
-}
-declare module '*.webm' {
- const src: string;
- export default src;
-}
-declare module '*.ogg' {
- const src: string;
- export default src;
-}
-declare module '*.mp3' {
- const src: string;
- export default src;
-}
-declare module '*.wav' {
- const src: string;
- export default src;
-}
-declare module '*.flac' {
- const src: string;
- export default src;
-}
-declare module '*.aac' {
- const src: string;
- export default src;
-}
-
-declare module '*.opus' {
- const src: string;
- export default src;
-}
-
-// fonts
-declare module '*.woff' {
- const src: string;
- export default src;
-}
-declare module '*.woff2' {
- const src: string;
- export default src;
-}
-declare module '*.eot' {
- const src: string;
- export default src;
-}
-declare module '*.ttf' {
- const src: string;
- export default src;
-}
-declare module '*.otf' {
- const src: string;
- export default src;
-}
-
-// other
-declare module '*.webmanifest' {
- const src: string;
- export default src;
-}
-declare module '*.pdf' {
- const src: string;
- export default src;
-}
-declare module '*.txt' {
- const src: string;
- export default src;
-}
-
-// wasm?init
-declare module '*.wasm?init' {
- const initWasm: (options: WebAssembly.Imports) => Promise<WebAssembly.Instance>;
- export default initWasm;
-}
-
-// web worker
-declare module '*?worker' {
- const workerConstructor: {
- new (): Worker;
- };
- export default workerConstructor;
-}
-
-declare module '*?worker&inline' {
- const workerConstructor: {
- new (): Worker;
- };
- export default workerConstructor;
-}
-
-declare module '*?worker&url' {
- const src: string;
- export default src;
-}
-
-declare module '*?sharedworker' {
- const sharedWorkerConstructor: {
- new (): SharedWorker;
- };
- export default sharedWorkerConstructor;
-}
-
-declare module '*?sharedworker&inline' {
- const sharedWorkerConstructor: {
- new (): SharedWorker;
- };
- export default sharedWorkerConstructor;
-}
-
-declare module '*?sharedworker&url' {
- const src: string;
- export default src;
-}
-
-declare module '*?raw' {
- const src: string;
- export default src;
-}
-
-declare module '*?url' {
- const src: string;
- export default src;
-}
-
-declare module '*?inline' {
- const src: string;
- export default src;
-}
diff --git a/packages/astro/client-image.d.ts b/packages/astro/client-image.d.ts
deleted file mode 100644
index ffcc1c63c..000000000
--- a/packages/astro/client-image.d.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-/// <reference path="./client-base.d.ts" />
-
-// TODO: Merge this file with `client-base.d.ts` in 3.0, when the `astro:assets` feature isn't under a flag anymore.
-
-type InputFormat = import('./dist/assets/types.js').ImageInputFormat;
-
-interface ImageMetadata {
- src: string;
- width: number;
- height: number;
- format: InputFormat;
-}
-
-declare module '*.gif' {
- const metadata: ImageMetadata;
- export default metadata;
-}
-declare module '*.jpeg' {
- const metadata: ImageMetadata;
- export default metadata;
-}
-declare module '*.jpg' {
- const metadata: ImageMetadata;
- export default metadata;
-}
-declare module '*.png' {
- const metadata: ImageMetadata;
- export default metadata;
-}
-declare module '*.tiff' {
- const metadata: ImageMetadata;
- export default metadata;
-}
-declare module '*.webp' {
- const metadata: ImageMetadata;
- export default metadata;
-}
-declare module '*.svg' {
- const metadata: ImageMetadata;
- export default metadata;
-}
diff --git a/packages/astro/client.d.ts b/packages/astro/client.d.ts
index 96f59d586..7f701b0c0 100644
--- a/packages/astro/client.d.ts
+++ b/packages/astro/client.d.ts
@@ -1,31 +1,465 @@
-/// <reference path="./client-base.d.ts" />
+/// <reference path="./import-meta.d.ts" />
-// images
+// eslint-disable-next-line @typescript-eslint/no-namespace
+declare namespace App {
+ // eslint-disable-next-line @typescript-eslint/no-empty-interface
+ export interface Locals {}
+}
+
+interface ImportMetaEnv {
+ /**
+ * The prefix for Astro-generated asset links if the build.assetsPrefix config option is set. This can be used to create asset links not handled by Astro.
+ */
+ readonly ASSETS_PREFIX: string;
+ /**
+ * This is set to the site option specified in your project’s Astro config file.
+ */
+ readonly SITE: string;
+}
+
+interface ImportMeta {
+ /**
+ * Astro and Vite expose environment variables through `import.meta.env`. For a complete list of the environment variables available, see the two references below.
+ *
+ * - [Astro reference](https://docs.astro.build/en/guides/environment-variables/#default-environment-variables)
+ * - [Vite reference](https://vitejs.dev/guide/env-and-mode.html#env-variables)
+ */
+ readonly env: ImportMetaEnv;
+}
+
+declare module 'astro:assets' {
+ // Exporting things one by one is a bit cumbersome, not sure if there's a better way - erika, 2023-02-03
+ type AstroAssets = {
+ // getImage's type here is different from the internal function since the Vite module implicitly pass the service config
+ /**
+ * Get an optimized image and the necessary attributes to render it.
+ *
+ * **Example**
+ * ```astro
+ * ---
+ * import { getImage } from 'astro:assets';
+ * import originalImage from '../assets/image.png';
+ *
+ * const optimizedImage = await getImage({src: originalImage, width: 1280 });
+ * ---
+ * <img src={optimizedImage.src} {...optimizedImage.attributes} />
+ * ```
+ *
+ * This is functionally equivalent to using the `<Image />` component, as the component calls this function internally.
+ */
+ getImage: (
+ options:
+ | import('./dist/assets/types.js').ImageTransform
+ | import('./dist/assets/types.js').UnresolvedImageTransform
+ ) => Promise<import('./dist/assets/types.js').GetImageResult>;
+ getConfiguredImageService: typeof import('./dist/assets/index.js').getConfiguredImageService;
+ Image: typeof import('./components/Image.astro').default;
+ };
+
+ type WithRequired<T, K extends keyof T> = T & { [P in K]-?: T[P] };
+ type Simplify<T> = { [KeyType in keyof T]: T[KeyType] };
+ type ImgAttributes = WithRequired<
+ Omit<import('./types').HTMLAttributes<'img'>, 'src' | 'width' | 'height'>,
+ 'alt'
+ >;
+
+ export type LocalImageProps = Simplify<
+ import('./dist/assets/types.js').LocalImageProps<ImgAttributes>
+ >;
+ export type RemoteImageProps = Simplify<
+ import('./dist/assets/types.js').RemoteImageProps<ImgAttributes>
+ >;
+ export const { getImage, getConfiguredImageService, Image }: AstroAssets;
+}
+
+type InputFormat = import('./dist/assets/types.js').ImageInputFormat;
+
+interface ImageMetadata {
+ src: string;
+ width: number;
+ height: number;
+ format: InputFormat;
+}
+
+declare module '*.gif' {
+ const metadata: ImageMetadata;
+ export default metadata;
+}
+declare module '*.jpeg' {
+ const metadata: ImageMetadata;
+ export default metadata;
+}
declare module '*.jpg' {
+ const metadata: ImageMetadata;
+ export default metadata;
+}
+declare module '*.png' {
+ const metadata: ImageMetadata;
+ export default metadata;
+}
+declare module '*.tiff' {
+ const metadata: ImageMetadata;
+ export default metadata;
+}
+declare module '*.webp' {
+ const metadata: ImageMetadata;
+ export default metadata;
+}
+declare module '*.svg' {
+ const metadata: ImageMetadata;
+ export default metadata;
+}
+
+declare module 'astro:transitions' {
+ type TransitionModule = typeof import('./dist/transitions/index.js');
+ export const slide: TransitionModule['slide'];
+ export const fade: TransitionModule['fade'];
+
+ type ViewTransitionsModule = typeof import('./components/ViewTransitions.astro');
+ export const ViewTransitions: ViewTransitionsModule['default'];
+}
+
+type MD = import('./dist/@types/astro').MarkdownInstance<Record<string, any>>;
+interface ExportedMarkdownModuleEntities {
+ frontmatter: MD['frontmatter'];
+ file: MD['file'];
+ url: MD['url'];
+ getHeadings: MD['getHeadings'];
+ /** @deprecated Renamed to `getHeadings()` */
+ getHeaders: () => void;
+ Content: MD['Content'];
+ rawContent: MD['rawContent'];
+ compiledContent: MD['compiledContent'];
+ load: MD['default'];
+}
+
+declare module '*.md' {
+ const { load }: ExportedMarkdownModuleEntities;
+ export const {
+ frontmatter,
+ file,
+ url,
+ getHeadings,
+ getHeaders,
+ Content,
+ rawContent,
+ compiledContent,
+ }: ExportedMarkdownModuleEntities;
+ export default load;
+}
+
+declare module '*.markdown' {
+ const { load }: ExportedMarkdownModuleEntities;
+ export const {
+ frontmatter,
+ file,
+ url,
+ getHeadings,
+ getHeaders,
+ Content,
+ rawContent,
+ compiledContent,
+ }: ExportedMarkdownModuleEntities;
+ export default load;
+}
+
+declare module '*.mkdn' {
+ const { load }: ExportedMarkdownModuleEntities;
+ export const {
+ frontmatter,
+ file,
+ url,
+ getHeadings,
+ getHeaders,
+ Content,
+ rawContent,
+ compiledContent,
+ }: ExportedMarkdownModuleEntities;
+ export default load;
+}
+
+declare module '*.mkd' {
+ const { load }: ExportedMarkdownModuleEntities;
+ export const {
+ frontmatter,
+ file,
+ url,
+ getHeadings,
+ getHeaders,
+ Content,
+ rawContent,
+ compiledContent,
+ }: ExportedMarkdownModuleEntities;
+ export default load;
+}
+
+declare module '*.mdwn' {
+ const { load }: ExportedMarkdownModuleEntities;
+ export const {
+ frontmatter,
+ file,
+ url,
+ getHeadings,
+ getHeaders,
+ Content,
+ rawContent,
+ compiledContent,
+ }: ExportedMarkdownModuleEntities;
+ export default load;
+}
+
+declare module '*.mdown' {
+ const { load }: ExportedMarkdownModuleEntities;
+ export const {
+ frontmatter,
+ file,
+ url,
+ getHeadings,
+ getHeaders,
+ Content,
+ rawContent,
+ compiledContent,
+ }: ExportedMarkdownModuleEntities;
+ export default load;
+}
+
+declare module '*.mdx' {
+ type MDX = import('./dist/@types/astro').MDXInstance<Record<string, any>>;
+
+ export const frontmatter: MDX['frontmatter'];
+ export const file: MDX['file'];
+ export const url: MDX['url'];
+ export const getHeadings: MDX['getHeadings'];
+ export const Content: MDX['Content'];
+
+ const load: MDX['default'];
+ export default load;
+}
+
+declare module 'astro:ssr-manifest' {
+ export const manifest: import('./dist/@types/astro').SSRManifest;
+}
+
+// Everything below are Vite's types (apart from image types, which are in `client.d.ts`)
+
+// CSS modules
+type CSSModuleClasses = { readonly [key: string]: string };
+
+declare module '*.module.css' {
+ const classes: CSSModuleClasses;
+ export default classes;
+}
+declare module '*.module.scss' {
+ const classes: CSSModuleClasses;
+ export default classes;
+}
+declare module '*.module.sass' {
+ const classes: CSSModuleClasses;
+ export default classes;
+}
+declare module '*.module.less' {
+ const classes: CSSModuleClasses;
+ export default classes;
+}
+declare module '*.module.styl' {
+ const classes: CSSModuleClasses;
+ export default classes;
+}
+declare module '*.module.stylus' {
+ const classes: CSSModuleClasses;
+ export default classes;
+}
+declare module '*.module.pcss' {
+ const classes: CSSModuleClasses;
+ export default classes;
+}
+declare module '*.module.sss' {
+ const classes: CSSModuleClasses;
+ export default classes;
+}
+
+// CSS
+declare module '*.css' {
+ const css: string;
+ export default css;
+}
+declare module '*.scss' {
+ const css: string;
+ export default css;
+}
+declare module '*.sass' {
+ const css: string;
+ export default css;
+}
+declare module '*.less' {
+ const css: string;
+ export default css;
+}
+declare module '*.styl' {
+ const css: string;
+ export default css;
+}
+declare module '*.stylus' {
+ const css: string;
+ export default css;
+}
+declare module '*.pcss' {
+ const css: string;
+ export default css;
+}
+declare module '*.sss' {
+ const css: string;
+ export default css;
+}
+
+// Built-in asset types
+// see `src/node/constants.ts`
+
+// images
+declare module '*.jfif' {
const src: string;
export default src;
}
-declare module '*.jpeg' {
+declare module '*.pjpeg' {
const src: string;
export default src;
}
-declare module '*.png' {
+declare module '*.pjp' {
const src: string;
export default src;
}
-declare module '*.gif' {
+declare module '*.ico' {
const src: string;
export default src;
}
-declare module '*.svg' {
+
+// media
+declare module '*.mp4' {
const src: string;
export default src;
}
-declare module '*.webp' {
+declare module '*.webm' {
+ const src: string;
+ export default src;
+}
+declare module '*.ogg' {
+ const src: string;
+ export default src;
+}
+declare module '*.mp3' {
+ const src: string;
+ export default src;
+}
+declare module '*.wav' {
+ const src: string;
+ export default src;
+}
+declare module '*.flac' {
+ const src: string;
+ export default src;
+}
+declare module '*.aac' {
+ const src: string;
+ export default src;
+}
+
+declare module '*.opus' {
+ const src: string;
+ export default src;
+}
+
+// fonts
+declare module '*.woff' {
+ const src: string;
+ export default src;
+}
+declare module '*.woff2' {
+ const src: string;
+ export default src;
+}
+declare module '*.eot' {
+ const src: string;
+ export default src;
+}
+declare module '*.ttf' {
+ const src: string;
+ export default src;
+}
+declare module '*.otf' {
const src: string;
export default src;
}
-declare module '*.avif' {
+
+// other
+declare module '*.webmanifest' {
+ const src: string;
+ export default src;
+}
+declare module '*.pdf' {
+ const src: string;
+ export default src;
+}
+declare module '*.txt' {
+ const src: string;
+ export default src;
+}
+
+// wasm?init
+declare module '*.wasm?init' {
+ const initWasm: (options: WebAssembly.Imports) => Promise<WebAssembly.Instance>;
+ export default initWasm;
+}
+
+// web worker
+declare module '*?worker' {
+ const workerConstructor: {
+ new (): Worker;
+ };
+ export default workerConstructor;
+}
+
+declare module '*?worker&inline' {
+ const workerConstructor: {
+ new (): Worker;
+ };
+ export default workerConstructor;
+}
+
+declare module '*?worker&url' {
+ const src: string;
+ export default src;
+}
+
+declare module '*?sharedworker' {
+ const sharedWorkerConstructor: {
+ new (): SharedWorker;
+ };
+ export default sharedWorkerConstructor;
+}
+
+declare module '*?sharedworker&inline' {
+ const sharedWorkerConstructor: {
+ new (): SharedWorker;
+ };
+ export default sharedWorkerConstructor;
+}
+
+declare module '*?sharedworker&url' {
+ const src: string;
+ export default src;
+}
+
+declare module '*?raw' {
+ const src: string;
+ export default src;
+}
+
+declare module '*?url' {
+ const src: string;
+ export default src;
+}
+
+declare module '*?inline' {
const src: string;
export default src;
}
diff --git a/packages/astro/content-types.template.d.ts b/packages/astro/content-types.template.d.ts
index edc50fcc9..cf825c25e 100644
--- a/packages/astro/content-types.template.d.ts
+++ b/packages/astro/content-types.template.d.ts
@@ -46,7 +46,7 @@ declare module 'astro:content' {
import('astro/zod').ZodLiteral<'tiff'>,
import('astro/zod').ZodLiteral<'webp'>,
import('astro/zod').ZodLiteral<'gif'>,
- import('astro/zod').ZodLiteral<'svg'>
+ import('astro/zod').ZodLiteral<'svg'>,
]
>;
}>;
@@ -89,7 +89,7 @@ declare module 'astro:content' {
export function getEntryBySlug<
C extends keyof ContentEntryMap,
- E extends ValidContentEntrySlug<C> | (string & {})
+ E extends ValidContentEntrySlug<C> | (string & {}),
>(
collection: C,
// Note that this has to accept a regular string too, for SSR
@@ -114,7 +114,7 @@ declare module 'astro:content' {
export function getEntry<
C extends keyof ContentEntryMap,
- E extends ValidContentEntrySlug<C> | (string & {})
+ E extends ValidContentEntrySlug<C> | (string & {}),
>(entry: {
collection: C;
slug: E;
@@ -123,7 +123,7 @@ declare module 'astro:content' {
: Promise<CollectionEntry<C> | undefined>;
export function getEntry<
C extends keyof DataEntryMap,
- E extends keyof DataEntryMap[C] | (string & {})
+ E extends keyof DataEntryMap[C] | (string & {}),
>(entry: {
collection: C;
id: E;
@@ -132,7 +132,7 @@ declare module 'astro:content' {
: Promise<CollectionEntry<C> | undefined>;
export function getEntry<
C extends keyof ContentEntryMap,
- E extends ValidContentEntrySlug<C> | (string & {})
+ E extends ValidContentEntrySlug<C> | (string & {}),
>(
collection: C,
slug: E
@@ -141,7 +141,7 @@ declare module 'astro:content' {
: Promise<CollectionEntry<C> | undefined>;
export function getEntry<
C extends keyof DataEntryMap,
- E extends keyof DataEntryMap[C] | (string & {})
+ E extends keyof DataEntryMap[C] | (string & {}),
>(
collection: C,
id: E
diff --git a/packages/astro/e2e/astro-envs.test.js b/packages/astro/e2e/astro-envs.test.js
index 1a4f4a1ca..50cff6e89 100644
--- a/packages/astro/e2e/astro-envs.test.js
+++ b/packages/astro/e2e/astro-envs.test.js
@@ -18,11 +18,11 @@ test.describe('Astro Environment BASE_URL', () => {
await page.goto(astro.resolveUrl('/blog/'));
const astroBaseUrl = page.locator('id=astro-base-url');
- await expect(astroBaseUrl, 'astroBaseUrl equals to /blog/').toHaveText('/blog/');
+ await expect(astroBaseUrl, 'astroBaseUrl equals to /blog').toHaveText('/blog');
const clientComponentBaseUrl = page.locator('id=client-component-base-url');
await expect(clientComponentBaseUrl, 'clientComponentBaseUrl equals to /blog').toHaveText(
- '/blog/'
+ '/blog'
);
});
});
diff --git a/packages/astro/e2e/css-sourcemaps.test.js b/packages/astro/e2e/css-sourcemaps.test.js
index 50b18834f..4ea3fc0e2 100644
--- a/packages/astro/e2e/css-sourcemaps.test.js
+++ b/packages/astro/e2e/css-sourcemaps.test.js
@@ -1,5 +1,5 @@
import { expect } from '@playwright/test';
-import { isWindows, testFactory } from './test-utils.js';
+import { testFactory } from './test-utils.js';
const test = testFactory({
root: './fixtures/css/',
@@ -16,8 +16,6 @@ test.afterAll(async () => {
});
test.describe('CSS Sourcemap HMR', () => {
- test.skip(isWindows, 'TODO: fix css hmr in windows');
-
test('removes Astro-injected CSS once Vite-injected CSS loads', async ({ page, astro }) => {
const html = await astro.fetch('/').then((res) => res.text());
diff --git a/packages/astro/e2e/css.test.js b/packages/astro/e2e/css.test.js
index 7c2527499..184e5dba3 100644
--- a/packages/astro/e2e/css.test.js
+++ b/packages/astro/e2e/css.test.js
@@ -1,5 +1,5 @@
import { expect } from '@playwright/test';
-import { getColor, isWindows, testFactory } from './test-utils.js';
+import { getColor, testFactory } from './test-utils.js';
const test = testFactory({
root: './fixtures/css/',
@@ -16,8 +16,6 @@ test.afterAll(async () => {
});
test.describe('CSS HMR', () => {
- test.skip(isWindows, 'TODO: fix css hmr in windows');
-
test('edit CSS from @import', async ({ page, astro }) => {
await page.goto(astro.resolveUrl('/'));
diff --git a/packages/astro/e2e/errors.test.js b/packages/astro/e2e/errors.test.js
index e23b22c65..4cb1b02fb 100644
--- a/packages/astro/e2e/errors.test.js
+++ b/packages/astro/e2e/errors.test.js
@@ -75,7 +75,7 @@ test.describe('Error display', () => {
const fileExists = astro.pathExists(absoluteFileUrl);
expect(fileExists).toBeTruthy();
- expect(fileLocation).toMatch(/^components\/PreactRuntimeError.jsx/);
+ expect(fileLocation).toMatch(/^preact\/PreactRuntimeError.jsx/);
});
test('shows correct line when a style preprocess has an error', async ({ page, astro }) => {
@@ -105,7 +105,10 @@ test.describe('Error display', () => {
// Wait for page reload
page.waitForNavigation(),
// Edit the component file
- astro.editFile('./src/components/SvelteSyntaxError.svelte', () => `<h1>No mismatch</h1>`),
+ astro.editFile(
+ './src/components/svelte/SvelteSyntaxError.svelte',
+ () => `<h1>No mismatch</h1>`
+ ),
]);
expect(await page.locator('vite-error-overlay').count()).toEqual(0);
diff --git a/packages/astro/e2e/fixtures/client-only/astro.config.mjs b/packages/astro/e2e/fixtures/client-only/astro.config.mjs
index 4b50887cd..0ef8f6e2b 100644
--- a/packages/astro/e2e/fixtures/client-only/astro.config.mjs
+++ b/packages/astro/e2e/fixtures/client-only/astro.config.mjs
@@ -8,5 +8,11 @@ import solid from '@astrojs/solid-js';
// https://astro.build/config
export default defineConfig({
// Enable many frameworks to support all different kinds of components.
- integrations: [preact(), react(), svelte(), vue(), solid()],
+ integrations: [
+ react({ include: ['**/react/*'] }),
+ preact({ include: ['**/preact/*'] }),
+ solid({ include: ['**/solid/*'] }),
+ svelte(),
+ vue(),
+ ],
});
diff --git a/packages/astro/e2e/fixtures/client-only/src/components/PreactCounter.tsx b/packages/astro/e2e/fixtures/client-only/src/components/preact/PreactCounter.tsx
index b0570046c..b0570046c 100644
--- a/packages/astro/e2e/fixtures/client-only/src/components/PreactCounter.tsx
+++ b/packages/astro/e2e/fixtures/client-only/src/components/preact/PreactCounter.tsx
diff --git a/packages/astro/e2e/fixtures/client-only/src/components/ReactCounter.jsx b/packages/astro/e2e/fixtures/client-only/src/components/react/ReactCounter.jsx
index 770f93890..770f93890 100644
--- a/packages/astro/e2e/fixtures/client-only/src/components/ReactCounter.jsx
+++ b/packages/astro/e2e/fixtures/client-only/src/components/react/ReactCounter.jsx
diff --git a/packages/astro/e2e/fixtures/client-only/src/components/SolidCounter.tsx b/packages/astro/e2e/fixtures/client-only/src/components/solid/SolidCounter.tsx
index fbbb9850b..fbbb9850b 100644
--- a/packages/astro/e2e/fixtures/client-only/src/components/SolidCounter.tsx
+++ b/packages/astro/e2e/fixtures/client-only/src/components/solid/SolidCounter.tsx
diff --git a/packages/astro/e2e/fixtures/client-only/src/components/SvelteCounter.svelte b/packages/astro/e2e/fixtures/client-only/src/components/svelte/SvelteCounter.svelte
index cc9fe8c93..cc9fe8c93 100644
--- a/packages/astro/e2e/fixtures/client-only/src/components/SvelteCounter.svelte
+++ b/packages/astro/e2e/fixtures/client-only/src/components/svelte/SvelteCounter.svelte
diff --git a/packages/astro/e2e/fixtures/client-only/src/components/VueCounter.vue b/packages/astro/e2e/fixtures/client-only/src/components/vue/VueCounter.vue
index 906da1944..906da1944 100644
--- a/packages/astro/e2e/fixtures/client-only/src/components/VueCounter.vue
+++ b/packages/astro/e2e/fixtures/client-only/src/components/vue/VueCounter.vue
diff --git a/packages/astro/e2e/fixtures/client-only/src/pages/index.astro b/packages/astro/e2e/fixtures/client-only/src/pages/index.astro
index 708ba1582..0b4299600 100644
--- a/packages/astro/e2e/fixtures/client-only/src/pages/index.astro
+++ b/packages/astro/e2e/fixtures/client-only/src/pages/index.astro
@@ -1,9 +1,9 @@
---
-import * as react from '../components/ReactCounter.jsx';
-import { PreactCounter } from '../components/PreactCounter.tsx';
-import SolidCounter from '../components/SolidCounter.tsx';
-import VueCounter from '../components/VueCounter.vue';
-import SvelteCounter from '../components/SvelteCounter.svelte';
+import * as react from '../components/react/ReactCounter.jsx';
+import { PreactCounter } from '../components/preact/PreactCounter.jsx';
+import SolidCounter from '../components/solid/SolidCounter.jsx';
+import VueCounter from '../components/vue/VueCounter.vue';
+import SvelteCounter from '../components/svelte/SvelteCounter.svelte';
// Full Astro Component Syntax:
// https://docs.astro.build/core-concepts/astro-components/
diff --git a/packages/astro/e2e/fixtures/errors/astro.config.mjs b/packages/astro/e2e/fixtures/errors/astro.config.mjs
index 8f27d8fab..48e8736bd 100644
--- a/packages/astro/e2e/fixtures/errors/astro.config.mjs
+++ b/packages/astro/e2e/fixtures/errors/astro.config.mjs
@@ -7,5 +7,11 @@ import vue from '@astrojs/vue';
// https://astro.build/config
export default defineConfig({
- integrations: [react(), preact(), solid(), svelte(), vue()],
-}); \ No newline at end of file
+ integrations: [
+ react({ include: ['**/react/*'] }),
+ preact({ include: ['**/preact/*'] }),
+ solid({ include: ['**/solid/*'] }),
+ svelte(),
+ vue(),
+ ],
+});
diff --git a/packages/astro/e2e/fixtures/errors/src/components/PreactRuntimeError.jsx b/packages/astro/e2e/fixtures/errors/src/components/preact/PreactRuntimeError.jsx
index 8ee30ccf4..8ee30ccf4 100644
--- a/packages/astro/e2e/fixtures/errors/src/components/PreactRuntimeError.jsx
+++ b/packages/astro/e2e/fixtures/errors/src/components/preact/PreactRuntimeError.jsx
diff --git a/packages/astro/e2e/fixtures/errors/src/components/PreactSyntaxError.jsx b/packages/astro/e2e/fixtures/errors/src/components/preact/PreactSyntaxError.jsx
index f6826c588..f6826c588 100644
--- a/packages/astro/e2e/fixtures/errors/src/components/PreactSyntaxError.jsx
+++ b/packages/astro/e2e/fixtures/errors/src/components/preact/PreactSyntaxError.jsx
diff --git a/packages/astro/e2e/fixtures/errors/src/components/ReactRuntimeError.jsx b/packages/astro/e2e/fixtures/errors/src/components/react/ReactRuntimeError.jsx
index 2ea3d9981..2ea3d9981 100644
--- a/packages/astro/e2e/fixtures/errors/src/components/ReactRuntimeError.jsx
+++ b/packages/astro/e2e/fixtures/errors/src/components/react/ReactRuntimeError.jsx
diff --git a/packages/astro/e2e/fixtures/errors/src/components/ReactSyntaxError.jsx b/packages/astro/e2e/fixtures/errors/src/components/react/ReactSyntaxError.jsx
index ff2798aa4..ff2798aa4 100644
--- a/packages/astro/e2e/fixtures/errors/src/components/ReactSyntaxError.jsx
+++ b/packages/astro/e2e/fixtures/errors/src/components/react/ReactSyntaxError.jsx
diff --git a/packages/astro/e2e/fixtures/errors/src/components/SolidRuntimeError.jsx b/packages/astro/e2e/fixtures/errors/src/components/solid/SolidRuntimeError.jsx
index 70398ddcb..70398ddcb 100644
--- a/packages/astro/e2e/fixtures/errors/src/components/SolidRuntimeError.jsx
+++ b/packages/astro/e2e/fixtures/errors/src/components/solid/SolidRuntimeError.jsx
diff --git a/packages/astro/e2e/fixtures/errors/src/components/SolidSyntaxError.jsx b/packages/astro/e2e/fixtures/errors/src/components/solid/SolidSyntaxError.jsx
index 0e396be43..0e396be43 100644
--- a/packages/astro/e2e/fixtures/errors/src/components/SolidSyntaxError.jsx
+++ b/packages/astro/e2e/fixtures/errors/src/components/solid/SolidSyntaxError.jsx
diff --git a/packages/astro/e2e/fixtures/errors/src/components/SvelteDirectiveError.svelte b/packages/astro/e2e/fixtures/errors/src/components/svelte/SvelteDirectiveError.svelte
index b07b120a2..b07b120a2 100644
--- a/packages/astro/e2e/fixtures/errors/src/components/SvelteDirectiveError.svelte
+++ b/packages/astro/e2e/fixtures/errors/src/components/svelte/SvelteDirectiveError.svelte
diff --git a/packages/astro/e2e/fixtures/errors/src/components/SvelteRuntimeError.svelte b/packages/astro/e2e/fixtures/errors/src/components/svelte/SvelteRuntimeError.svelte
index 54dbab6a7..54dbab6a7 100644
--- a/packages/astro/e2e/fixtures/errors/src/components/SvelteRuntimeError.svelte
+++ b/packages/astro/e2e/fixtures/errors/src/components/svelte/SvelteRuntimeError.svelte
diff --git a/packages/astro/e2e/fixtures/errors/src/components/SvelteSyntaxError.svelte b/packages/astro/e2e/fixtures/errors/src/components/svelte/SvelteSyntaxError.svelte
index 457878396..457878396 100644
--- a/packages/astro/e2e/fixtures/errors/src/components/SvelteSyntaxError.svelte
+++ b/packages/astro/e2e/fixtures/errors/src/components/svelte/SvelteSyntaxError.svelte
diff --git a/packages/astro/e2e/fixtures/errors/src/components/VueRuntimeError.vue b/packages/astro/e2e/fixtures/errors/src/components/vue/VueRuntimeError.vue
index e2e38338b..e2e38338b 100644
--- a/packages/astro/e2e/fixtures/errors/src/components/VueRuntimeError.vue
+++ b/packages/astro/e2e/fixtures/errors/src/components/vue/VueRuntimeError.vue
diff --git a/packages/astro/e2e/fixtures/errors/src/components/VueSyntaxError.vue b/packages/astro/e2e/fixtures/errors/src/components/vue/VueSyntaxError.vue
index bd509b3bc..bd509b3bc 100644
--- a/packages/astro/e2e/fixtures/errors/src/components/VueSyntaxError.vue
+++ b/packages/astro/e2e/fixtures/errors/src/components/vue/VueSyntaxError.vue
diff --git a/packages/astro/e2e/fixtures/errors/src/pages/astro-client-media-error.astro b/packages/astro/e2e/fixtures/errors/src/pages/astro-client-media-error.astro
index 46bb9a2c4..94e124c9a 100644
--- a/packages/astro/e2e/fixtures/errors/src/pages/astro-client-media-error.astro
+++ b/packages/astro/e2e/fixtures/errors/src/pages/astro-client-media-error.astro
@@ -1,7 +1,7 @@
---
-import SvelteDirectiveError from '../components/SvelteDirectiveError.svelte';
+import SvelteDirectiveError from '../components/svelte/SvelteDirectiveError.svelte';
---
<div>
<SvelteDirectiveError client:media />
-</div> \ No newline at end of file
+</div>
diff --git a/packages/astro/e2e/fixtures/errors/src/pages/astro-hydration-error.astro b/packages/astro/e2e/fixtures/errors/src/pages/astro-hydration-error.astro
index 1852539eb..8fcd56bd4 100644
--- a/packages/astro/e2e/fixtures/errors/src/pages/astro-hydration-error.astro
+++ b/packages/astro/e2e/fixtures/errors/src/pages/astro-hydration-error.astro
@@ -1,7 +1,7 @@
---
-import SvelteDirectiveError from '../components/SvelteDirectiveError.svelte';
+import SvelteDirectiveError from '../components/svelte/SvelteDirectiveError.svelte';
---
<div>
<SvelteDirectiveError client:loadm />
-</div> \ No newline at end of file
+</div>
diff --git a/packages/astro/e2e/fixtures/errors/src/pages/preact-runtime-error.astro b/packages/astro/e2e/fixtures/errors/src/pages/preact-runtime-error.astro
index 5c0aa2526..17ad92808 100644
--- a/packages/astro/e2e/fixtures/errors/src/pages/preact-runtime-error.astro
+++ b/packages/astro/e2e/fixtures/errors/src/pages/preact-runtime-error.astro
@@ -1,5 +1,5 @@
---
-import PreactRuntimeError from '../components/PreactRuntimeError.jsx';
+import PreactRuntimeError from '../components/preact/PreactRuntimeError.jsx';
---
<div>
diff --git a/packages/astro/e2e/fixtures/errors/src/pages/preact-syntax-error.astro b/packages/astro/e2e/fixtures/errors/src/pages/preact-syntax-error.astro
index 6748b0366..b0f709b9d 100644
--- a/packages/astro/e2e/fixtures/errors/src/pages/preact-syntax-error.astro
+++ b/packages/astro/e2e/fixtures/errors/src/pages/preact-syntax-error.astro
@@ -1,5 +1,5 @@
---
-import PreactSyntaxError from '../components/PreactSyntaxError.jsx';
+import PreactSyntaxError from '../components/preact/PreactSyntaxError.jsx';
---
<div>
diff --git a/packages/astro/e2e/fixtures/errors/src/pages/react-runtime-error.astro b/packages/astro/e2e/fixtures/errors/src/pages/react-runtime-error.astro
index f1df8ec99..18490518e 100644
--- a/packages/astro/e2e/fixtures/errors/src/pages/react-runtime-error.astro
+++ b/packages/astro/e2e/fixtures/errors/src/pages/react-runtime-error.astro
@@ -1,5 +1,5 @@
---
-import ReactRuntimeError from '../components/ReactRuntimeError.jsx';
+import ReactRuntimeError from '../components/react/ReactRuntimeError.jsx';
---
<div>
diff --git a/packages/astro/e2e/fixtures/errors/src/pages/react-syntax-error.astro b/packages/astro/e2e/fixtures/errors/src/pages/react-syntax-error.astro
index 6e61ae31d..c11b49ae0 100644
--- a/packages/astro/e2e/fixtures/errors/src/pages/react-syntax-error.astro
+++ b/packages/astro/e2e/fixtures/errors/src/pages/react-syntax-error.astro
@@ -1,5 +1,5 @@
---
-import ReactSyntaxError from '../components/ReactSyntaxError.jsx';
+import ReactSyntaxError from '../components/react/ReactSyntaxError.jsx';
---
<div>
diff --git a/packages/astro/e2e/fixtures/errors/src/pages/solid-runtime-error.astro b/packages/astro/e2e/fixtures/errors/src/pages/solid-runtime-error.astro
index 51a2608bd..7d4160126 100644
--- a/packages/astro/e2e/fixtures/errors/src/pages/solid-runtime-error.astro
+++ b/packages/astro/e2e/fixtures/errors/src/pages/solid-runtime-error.astro
@@ -1,5 +1,5 @@
---
-import SolidRuntimeError from '../components/SolidRuntimeError.jsx';
+import SolidRuntimeError from '../components/solid/SolidRuntimeError.jsx';
---
<div>
diff --git a/packages/astro/e2e/fixtures/errors/src/pages/solid-syntax-error.astro b/packages/astro/e2e/fixtures/errors/src/pages/solid-syntax-error.astro
index 0fdbad25b..028ab9ede 100644
--- a/packages/astro/e2e/fixtures/errors/src/pages/solid-syntax-error.astro
+++ b/packages/astro/e2e/fixtures/errors/src/pages/solid-syntax-error.astro
@@ -1,5 +1,5 @@
---
-import SolidSyntaxError from '../components/SolidSyntaxError.jsx';
+import SolidSyntaxError from '../components/solid/SolidSyntaxError.jsx';
---
<div>
diff --git a/packages/astro/e2e/fixtures/errors/src/pages/svelte-runtime-error.astro b/packages/astro/e2e/fixtures/errors/src/pages/svelte-runtime-error.astro
index ec499f6db..662a48f0e 100644
--- a/packages/astro/e2e/fixtures/errors/src/pages/svelte-runtime-error.astro
+++ b/packages/astro/e2e/fixtures/errors/src/pages/svelte-runtime-error.astro
@@ -1,5 +1,5 @@
---
-import SvelteRuntimeError from '../components/SvelteRuntimeError.svelte';
+import SvelteRuntimeError from '../components/svelte/SvelteRuntimeError.svelte';
---
<div>
diff --git a/packages/astro/e2e/fixtures/errors/src/pages/svelte-syntax-error.astro b/packages/astro/e2e/fixtures/errors/src/pages/svelte-syntax-error.astro
index 26c14c15e..e275251a4 100644
--- a/packages/astro/e2e/fixtures/errors/src/pages/svelte-syntax-error.astro
+++ b/packages/astro/e2e/fixtures/errors/src/pages/svelte-syntax-error.astro
@@ -1,5 +1,5 @@
---
-import SvelteSyntaxError from '../components/SvelteSyntaxError.svelte';
+import SvelteSyntaxError from '../components/svelte/SvelteSyntaxError.svelte';
---
<div>
diff --git a/packages/astro/e2e/fixtures/errors/src/pages/vue-runtime-error.astro b/packages/astro/e2e/fixtures/errors/src/pages/vue-runtime-error.astro
index b63f85e63..698da561f 100644
--- a/packages/astro/e2e/fixtures/errors/src/pages/vue-runtime-error.astro
+++ b/packages/astro/e2e/fixtures/errors/src/pages/vue-runtime-error.astro
@@ -1,5 +1,5 @@
---
-import VueRuntimeError from '../components/VueRuntimeError.vue';
+import VueRuntimeError from '../components/vue/VueRuntimeError.vue';
---
<div>
diff --git a/packages/astro/e2e/fixtures/errors/src/pages/vue-syntax-error.astro b/packages/astro/e2e/fixtures/errors/src/pages/vue-syntax-error.astro
index 8db897fe1..c76ed16fe 100644
--- a/packages/astro/e2e/fixtures/errors/src/pages/vue-syntax-error.astro
+++ b/packages/astro/e2e/fixtures/errors/src/pages/vue-syntax-error.astro
@@ -1,5 +1,5 @@
---
-import VueSyntaxError from '../components/VueSyntaxError.vue';
+import VueSyntaxError from '../components/vue/VueSyntaxError.vue';
---
<div>
diff --git a/packages/astro/e2e/fixtures/multiple-frameworks/astro.config.mjs b/packages/astro/e2e/fixtures/multiple-frameworks/astro.config.mjs
index 4b50887cd..0ef8f6e2b 100644
--- a/packages/astro/e2e/fixtures/multiple-frameworks/astro.config.mjs
+++ b/packages/astro/e2e/fixtures/multiple-frameworks/astro.config.mjs
@@ -8,5 +8,11 @@ import solid from '@astrojs/solid-js';
// https://astro.build/config
export default defineConfig({
// Enable many frameworks to support all different kinds of components.
- integrations: [preact(), react(), svelte(), vue(), solid()],
+ integrations: [
+ react({ include: ['**/react/*'] }),
+ preact({ include: ['**/preact/*'] }),
+ solid({ include: ['**/solid/*'] }),
+ svelte(),
+ vue(),
+ ],
});
diff --git a/packages/astro/e2e/fixtures/multiple-frameworks/src/components/PreactCounter.tsx b/packages/astro/e2e/fixtures/multiple-frameworks/src/components/preact/PreactCounter.tsx
index af2258fdf..af2258fdf 100644
--- a/packages/astro/e2e/fixtures/multiple-frameworks/src/components/PreactCounter.tsx
+++ b/packages/astro/e2e/fixtures/multiple-frameworks/src/components/preact/PreactCounter.tsx
diff --git a/packages/astro/e2e/fixtures/multiple-frameworks/src/components/ReactCounter.jsx b/packages/astro/e2e/fixtures/multiple-frameworks/src/components/react/ReactCounter.jsx
index 02eb19539..02eb19539 100644
--- a/packages/astro/e2e/fixtures/multiple-frameworks/src/components/ReactCounter.jsx
+++ b/packages/astro/e2e/fixtures/multiple-frameworks/src/components/react/ReactCounter.jsx
diff --git a/packages/astro/e2e/fixtures/multiple-frameworks/src/components/SolidCounter.tsx b/packages/astro/e2e/fixtures/multiple-frameworks/src/components/solid/SolidCounter.tsx
index 689c5222c..689c5222c 100644
--- a/packages/astro/e2e/fixtures/multiple-frameworks/src/components/SolidCounter.tsx
+++ b/packages/astro/e2e/fixtures/multiple-frameworks/src/components/solid/SolidCounter.tsx
diff --git a/packages/astro/e2e/fixtures/multiple-frameworks/src/components/SvelteCounter.svelte b/packages/astro/e2e/fixtures/multiple-frameworks/src/components/svelte/SvelteCounter.svelte
index d6870af3c..d6870af3c 100644
--- a/packages/astro/e2e/fixtures/multiple-frameworks/src/components/SvelteCounter.svelte
+++ b/packages/astro/e2e/fixtures/multiple-frameworks/src/components/svelte/SvelteCounter.svelte
diff --git a/packages/astro/e2e/fixtures/multiple-frameworks/src/components/VueCounter.vue b/packages/astro/e2e/fixtures/multiple-frameworks/src/components/vue/VueCounter.vue
index 4861511c8..4861511c8 100644
--- a/packages/astro/e2e/fixtures/multiple-frameworks/src/components/VueCounter.vue
+++ b/packages/astro/e2e/fixtures/multiple-frameworks/src/components/vue/VueCounter.vue
diff --git a/packages/astro/e2e/fixtures/multiple-frameworks/src/pages/index.astro b/packages/astro/e2e/fixtures/multiple-frameworks/src/pages/index.astro
index a30688bca..747744852 100644
--- a/packages/astro/e2e/fixtures/multiple-frameworks/src/pages/index.astro
+++ b/packages/astro/e2e/fixtures/multiple-frameworks/src/pages/index.astro
@@ -3,11 +3,11 @@
import '../styles/global.css';
// Component Imports
import { A, B as Renamed } from '../components';
-import * as react from '../components/ReactCounter.jsx';
-import { PreactCounter } from '../components/PreactCounter.tsx';
-import SolidCounter from '../components/SolidCounter.tsx';
-import VueCounter from '../components/VueCounter.vue';
-import SvelteCounter from '../components/SvelteCounter.svelte';
+import * as react from '../components/react/ReactCounter.jsx';
+import { PreactCounter } from '../components/preact/PreactCounter.tsx';
+import SolidCounter from '../components/solid/SolidCounter.tsx';
+import VueCounter from '../components/vue/VueCounter.vue';
+import SvelteCounter from '../components/svelte/SvelteCounter.svelte';
// Full Astro Component Syntax:
// https://docs.astro.build/core-concepts/astro-components/
diff --git a/packages/astro/e2e/fixtures/nested-in-preact/astro.config.mjs b/packages/astro/e2e/fixtures/nested-in-preact/astro.config.mjs
index 4b50887cd..0ef8f6e2b 100644
--- a/packages/astro/e2e/fixtures/nested-in-preact/astro.config.mjs
+++ b/packages/astro/e2e/fixtures/nested-in-preact/astro.config.mjs
@@ -8,5 +8,11 @@ import solid from '@astrojs/solid-js';
// https://astro.build/config
export default defineConfig({
// Enable many frameworks to support all different kinds of components.
- integrations: [preact(), react(), svelte(), vue(), solid()],
+ integrations: [
+ react({ include: ['**/react/*'] }),
+ preact({ include: ['**/preact/*'] }),
+ solid({ include: ['**/solid/*'] }),
+ svelte(),
+ vue(),
+ ],
});
diff --git a/packages/astro/e2e/fixtures/nested-in-preact/src/components/PreactCounter.tsx b/packages/astro/e2e/fixtures/nested-in-preact/src/components/preact/PreactCounter.tsx
index 5f20f560d..5f20f560d 100644
--- a/packages/astro/e2e/fixtures/nested-in-preact/src/components/PreactCounter.tsx
+++ b/packages/astro/e2e/fixtures/nested-in-preact/src/components/preact/PreactCounter.tsx
diff --git a/packages/astro/e2e/fixtures/nested-in-preact/src/components/ReactCounter.jsx b/packages/astro/e2e/fixtures/nested-in-preact/src/components/react/ReactCounter.jsx
index 0dc0deb47..0dc0deb47 100644
--- a/packages/astro/e2e/fixtures/nested-in-preact/src/components/ReactCounter.jsx
+++ b/packages/astro/e2e/fixtures/nested-in-preact/src/components/react/ReactCounter.jsx
diff --git a/packages/astro/e2e/fixtures/nested-in-preact/src/components/SolidCounter.tsx b/packages/astro/e2e/fixtures/nested-in-preact/src/components/solid/SolidCounter.tsx
index afabe43b9..afabe43b9 100644
--- a/packages/astro/e2e/fixtures/nested-in-preact/src/components/SolidCounter.tsx
+++ b/packages/astro/e2e/fixtures/nested-in-preact/src/components/solid/SolidCounter.tsx
diff --git a/packages/astro/e2e/fixtures/nested-in-preact/src/components/SvelteCounter.svelte b/packages/astro/e2e/fixtures/nested-in-preact/src/components/svelte/SvelteCounter.svelte
index 733f58076..733f58076 100644
--- a/packages/astro/e2e/fixtures/nested-in-preact/src/components/SvelteCounter.svelte
+++ b/packages/astro/e2e/fixtures/nested-in-preact/src/components/svelte/SvelteCounter.svelte
diff --git a/packages/astro/e2e/fixtures/nested-in-preact/src/components/VueCounter.vue b/packages/astro/e2e/fixtures/nested-in-preact/src/components/vue/VueCounter.vue
index d404cc965..d404cc965 100644
--- a/packages/astro/e2e/fixtures/nested-in-preact/src/components/VueCounter.vue
+++ b/packages/astro/e2e/fixtures/nested-in-preact/src/components/vue/VueCounter.vue
diff --git a/packages/astro/e2e/fixtures/nested-in-preact/src/pages/index.astro b/packages/astro/e2e/fixtures/nested-in-preact/src/pages/index.astro
index 619e8cccd..7512b86f4 100644
--- a/packages/astro/e2e/fixtures/nested-in-preact/src/pages/index.astro
+++ b/packages/astro/e2e/fixtures/nested-in-preact/src/pages/index.astro
@@ -1,9 +1,9 @@
---
-import ReactCounter from '../components/ReactCounter.jsx';
-import { PreactCounter } from '../components/PreactCounter.tsx';
-import SolidCounter from '../components/SolidCounter.tsx';
-import VueCounter from '../components/VueCounter.vue';
-import SvelteCounter from '../components/SvelteCounter.svelte';
+import ReactCounter from '../components/react/ReactCounter.jsx';
+import { PreactCounter } from '../components/preact/PreactCounter.tsx';
+import SolidCounter from '../components/solid/SolidCounter.tsx';
+import VueCounter from '../components/vue/VueCounter.vue';
+import SvelteCounter from '../components/svelte/SvelteCounter.svelte';
// Full Astro Component Syntax:
// https://docs.astro.build/core-concepts/astro-components/
diff --git a/packages/astro/e2e/fixtures/nested-in-react/astro.config.mjs b/packages/astro/e2e/fixtures/nested-in-react/astro.config.mjs
index 4b50887cd..0ef8f6e2b 100644
--- a/packages/astro/e2e/fixtures/nested-in-react/astro.config.mjs
+++ b/packages/astro/e2e/fixtures/nested-in-react/astro.config.mjs
@@ -8,5 +8,11 @@ import solid from '@astrojs/solid-js';
// https://astro.build/config
export default defineConfig({
// Enable many frameworks to support all different kinds of components.
- integrations: [preact(), react(), svelte(), vue(), solid()],
+ integrations: [
+ react({ include: ['**/react/*'] }),
+ preact({ include: ['**/preact/*'] }),
+ solid({ include: ['**/solid/*'] }),
+ svelte(),
+ vue(),
+ ],
});
diff --git a/packages/astro/e2e/fixtures/nested-in-react/src/components/PreactCounter.tsx b/packages/astro/e2e/fixtures/nested-in-react/src/components/preact/PreactCounter.tsx
index 5f20f560d..5f20f560d 100644
--- a/packages/astro/e2e/fixtures/nested-in-react/src/components/PreactCounter.tsx
+++ b/packages/astro/e2e/fixtures/nested-in-react/src/components/preact/PreactCounter.tsx
diff --git a/packages/astro/e2e/fixtures/nested-in-react/src/components/ReactCounter.jsx b/packages/astro/e2e/fixtures/nested-in-react/src/components/react/ReactCounter.jsx
index 0dc0deb47..0dc0deb47 100644
--- a/packages/astro/e2e/fixtures/nested-in-react/src/components/ReactCounter.jsx
+++ b/packages/astro/e2e/fixtures/nested-in-react/src/components/react/ReactCounter.jsx
diff --git a/packages/astro/e2e/fixtures/nested-in-react/src/components/SolidCounter.tsx b/packages/astro/e2e/fixtures/nested-in-react/src/components/solid/SolidCounter.tsx
index afabe43b9..afabe43b9 100644
--- a/packages/astro/e2e/fixtures/nested-in-react/src/components/SolidCounter.tsx
+++ b/packages/astro/e2e/fixtures/nested-in-react/src/components/solid/SolidCounter.tsx
diff --git a/packages/astro/e2e/fixtures/nested-in-react/src/components/SvelteCounter.svelte b/packages/astro/e2e/fixtures/nested-in-react/src/components/svelte/SvelteCounter.svelte
index 733f58076..733f58076 100644
--- a/packages/astro/e2e/fixtures/nested-in-react/src/components/SvelteCounter.svelte
+++ b/packages/astro/e2e/fixtures/nested-in-react/src/components/svelte/SvelteCounter.svelte
diff --git a/packages/astro/e2e/fixtures/nested-in-react/src/components/VueCounter.vue b/packages/astro/e2e/fixtures/nested-in-react/src/components/vue/VueCounter.vue
index d404cc965..d404cc965 100644
--- a/packages/astro/e2e/fixtures/nested-in-react/src/components/VueCounter.vue
+++ b/packages/astro/e2e/fixtures/nested-in-react/src/components/vue/VueCounter.vue
diff --git a/packages/astro/e2e/fixtures/nested-in-react/src/pages/index.astro b/packages/astro/e2e/fixtures/nested-in-react/src/pages/index.astro
index 0b3b23d9d..fe18a3151 100644
--- a/packages/astro/e2e/fixtures/nested-in-react/src/pages/index.astro
+++ b/packages/astro/e2e/fixtures/nested-in-react/src/pages/index.astro
@@ -1,9 +1,9 @@
---
-import ReactCounter from '../components/ReactCounter.jsx';
-import { PreactCounter } from '../components/PreactCounter.tsx';
-import SolidCounter from '../components/SolidCounter.tsx';
-import VueCounter from '../components/VueCounter.vue';
-import SvelteCounter from '../components/SvelteCounter.svelte';
+import ReactCounter from '../components/react/ReactCounter.jsx';
+import { PreactCounter } from '../components/preact/PreactCounter.tsx';
+import SolidCounter from '../components/solid/SolidCounter.tsx';
+import VueCounter from '../components/vue/VueCounter.vue';
+import SvelteCounter from '../components/svelte/SvelteCounter.svelte';
// Full Astro Component Syntax:
// https://docs.astro.build/core-concepts/astro-components/
diff --git a/packages/astro/e2e/fixtures/nested-in-solid/astro.config.mjs b/packages/astro/e2e/fixtures/nested-in-solid/astro.config.mjs
index 4b50887cd..0ef8f6e2b 100644
--- a/packages/astro/e2e/fixtures/nested-in-solid/astro.config.mjs
+++ b/packages/astro/e2e/fixtures/nested-in-solid/astro.config.mjs
@@ -8,5 +8,11 @@ import solid from '@astrojs/solid-js';
// https://astro.build/config
export default defineConfig({
// Enable many frameworks to support all different kinds of components.
- integrations: [preact(), react(), svelte(), vue(), solid()],
+ integrations: [
+ react({ include: ['**/react/*'] }),
+ preact({ include: ['**/preact/*'] }),
+ solid({ include: ['**/solid/*'] }),
+ svelte(),
+ vue(),
+ ],
});
diff --git a/packages/astro/e2e/fixtures/nested-in-solid/src/components/PreactCounter.tsx b/packages/astro/e2e/fixtures/nested-in-solid/src/components/preact/PreactCounter.tsx
index 5f20f560d..5f20f560d 100644
--- a/packages/astro/e2e/fixtures/nested-in-solid/src/components/PreactCounter.tsx
+++ b/packages/astro/e2e/fixtures/nested-in-solid/src/components/preact/PreactCounter.tsx
diff --git a/packages/astro/e2e/fixtures/nested-in-solid/src/components/ReactCounter.jsx b/packages/astro/e2e/fixtures/nested-in-solid/src/components/react/ReactCounter.jsx
index c7197a072..c7197a072 100644
--- a/packages/astro/e2e/fixtures/nested-in-solid/src/components/ReactCounter.jsx
+++ b/packages/astro/e2e/fixtures/nested-in-solid/src/components/react/ReactCounter.jsx
diff --git a/packages/astro/e2e/fixtures/nested-in-solid/src/components/SolidCounter.tsx b/packages/astro/e2e/fixtures/nested-in-solid/src/components/solid/SolidCounter.tsx
index afabe43b9..afabe43b9 100644
--- a/packages/astro/e2e/fixtures/nested-in-solid/src/components/SolidCounter.tsx
+++ b/packages/astro/e2e/fixtures/nested-in-solid/src/components/solid/SolidCounter.tsx
diff --git a/packages/astro/e2e/fixtures/nested-in-solid/src/components/SvelteCounter.svelte b/packages/astro/e2e/fixtures/nested-in-solid/src/components/svelte/SvelteCounter.svelte
index 733f58076..733f58076 100644
--- a/packages/astro/e2e/fixtures/nested-in-solid/src/components/SvelteCounter.svelte
+++ b/packages/astro/e2e/fixtures/nested-in-solid/src/components/svelte/SvelteCounter.svelte
diff --git a/packages/astro/e2e/fixtures/nested-in-solid/src/components/VueCounter.vue b/packages/astro/e2e/fixtures/nested-in-solid/src/components/vue/VueCounter.vue
index d404cc965..d404cc965 100644
--- a/packages/astro/e2e/fixtures/nested-in-solid/src/components/VueCounter.vue
+++ b/packages/astro/e2e/fixtures/nested-in-solid/src/components/vue/VueCounter.vue
diff --git a/packages/astro/e2e/fixtures/nested-in-solid/src/pages/index.astro b/packages/astro/e2e/fixtures/nested-in-solid/src/pages/index.astro
index 0feb5ba60..7b2c8da8d 100644
--- a/packages/astro/e2e/fixtures/nested-in-solid/src/pages/index.astro
+++ b/packages/astro/e2e/fixtures/nested-in-solid/src/pages/index.astro
@@ -1,9 +1,9 @@
---
-import { Counter as ReactCounter } from '../components/ReactCounter.jsx';
-import { PreactCounter } from '../components/PreactCounter.tsx';
-import SolidCounter from '../components/SolidCounter.tsx';
-import VueCounter from '../components/VueCounter.vue';
-import SvelteCounter from '../components/SvelteCounter.svelte';
+import { Counter as ReactCounter } from '../components/react/ReactCounter.jsx';
+import { PreactCounter } from '../components/preact/PreactCounter.tsx';
+import SolidCounter from '../components/solid/SolidCounter.tsx';
+import VueCounter from '../components/vue/VueCounter.vue';
+import SvelteCounter from '../components/svelte/SvelteCounter.svelte';
// Full Astro Component Syntax:
// https://docs.astro.build/core-concepts/astro-components/
diff --git a/packages/astro/e2e/fixtures/nested-in-svelte/astro.config.mjs b/packages/astro/e2e/fixtures/nested-in-svelte/astro.config.mjs
index 4b50887cd..0ef8f6e2b 100644
--- a/packages/astro/e2e/fixtures/nested-in-svelte/astro.config.mjs
+++ b/packages/astro/e2e/fixtures/nested-in-svelte/astro.config.mjs
@@ -8,5 +8,11 @@ import solid from '@astrojs/solid-js';
// https://astro.build/config
export default defineConfig({
// Enable many frameworks to support all different kinds of components.
- integrations: [preact(), react(), svelte(), vue(), solid()],
+ integrations: [
+ react({ include: ['**/react/*'] }),
+ preact({ include: ['**/preact/*'] }),
+ solid({ include: ['**/solid/*'] }),
+ svelte(),
+ vue(),
+ ],
});
diff --git a/packages/astro/e2e/fixtures/nested-in-svelte/src/components/PreactCounter.tsx b/packages/astro/e2e/fixtures/nested-in-svelte/src/components/preact/PreactCounter.tsx
index 5f20f560d..5f20f560d 100644
--- a/packages/astro/e2e/fixtures/nested-in-svelte/src/components/PreactCounter.tsx
+++ b/packages/astro/e2e/fixtures/nested-in-svelte/src/components/preact/PreactCounter.tsx
diff --git a/packages/astro/e2e/fixtures/nested-in-svelte/src/components/ReactCounter.jsx b/packages/astro/e2e/fixtures/nested-in-svelte/src/components/react/ReactCounter.jsx
index c7197a072..c7197a072 100644
--- a/packages/astro/e2e/fixtures/nested-in-svelte/src/components/ReactCounter.jsx
+++ b/packages/astro/e2e/fixtures/nested-in-svelte/src/components/react/ReactCounter.jsx
diff --git a/packages/astro/e2e/fixtures/nested-in-svelte/src/components/SolidCounter.tsx b/packages/astro/e2e/fixtures/nested-in-svelte/src/components/solid/SolidCounter.tsx
index afabe43b9..afabe43b9 100644
--- a/packages/astro/e2e/fixtures/nested-in-svelte/src/components/SolidCounter.tsx
+++ b/packages/astro/e2e/fixtures/nested-in-svelte/src/components/solid/SolidCounter.tsx
diff --git a/packages/astro/e2e/fixtures/nested-in-svelte/src/components/SvelteCounter.svelte b/packages/astro/e2e/fixtures/nested-in-svelte/src/components/svelte/SvelteCounter.svelte
index 733f58076..733f58076 100644
--- a/packages/astro/e2e/fixtures/nested-in-svelte/src/components/SvelteCounter.svelte
+++ b/packages/astro/e2e/fixtures/nested-in-svelte/src/components/svelte/SvelteCounter.svelte
diff --git a/packages/astro/e2e/fixtures/nested-in-svelte/src/components/VueCounter.vue b/packages/astro/e2e/fixtures/nested-in-svelte/src/components/vue/VueCounter.vue
index d404cc965..d404cc965 100644
--- a/packages/astro/e2e/fixtures/nested-in-svelte/src/components/VueCounter.vue
+++ b/packages/astro/e2e/fixtures/nested-in-svelte/src/components/vue/VueCounter.vue
diff --git a/packages/astro/e2e/fixtures/nested-in-svelte/src/pages/index.astro b/packages/astro/e2e/fixtures/nested-in-svelte/src/pages/index.astro
index 764ebfaf7..aa11de7fd 100644
--- a/packages/astro/e2e/fixtures/nested-in-svelte/src/pages/index.astro
+++ b/packages/astro/e2e/fixtures/nested-in-svelte/src/pages/index.astro
@@ -1,9 +1,9 @@
---
-import { Counter as ReactCounter } from '../components/ReactCounter.jsx';
-import { PreactCounter } from '../components/PreactCounter.tsx';
-import SolidCounter from '../components/SolidCounter.tsx';
-import VueCounter from '../components/VueCounter.vue';
-import SvelteCounter from '../components/SvelteCounter.svelte';
+import { Counter as ReactCounter } from '../components/react/ReactCounter.jsx';
+import { PreactCounter } from '../components/preact/PreactCounter.tsx';
+import SolidCounter from '../components/solid/SolidCounter.tsx';
+import VueCounter from '../components/vue/VueCounter.vue';
+import SvelteCounter from '../components/svelte/SvelteCounter.svelte';
// Full Astro Component Syntax:
// https://docs.astro.build/core-concepts/astro-components/
diff --git a/packages/astro/e2e/fixtures/nested-in-vue/astro.config.mjs b/packages/astro/e2e/fixtures/nested-in-vue/astro.config.mjs
index 4b50887cd..0ef8f6e2b 100644
--- a/packages/astro/e2e/fixtures/nested-in-vue/astro.config.mjs
+++ b/packages/astro/e2e/fixtures/nested-in-vue/astro.config.mjs
@@ -8,5 +8,11 @@ import solid from '@astrojs/solid-js';
// https://astro.build/config
export default defineConfig({
// Enable many frameworks to support all different kinds of components.
- integrations: [preact(), react(), svelte(), vue(), solid()],
+ integrations: [
+ react({ include: ['**/react/*'] }),
+ preact({ include: ['**/preact/*'] }),
+ solid({ include: ['**/solid/*'] }),
+ svelte(),
+ vue(),
+ ],
});
diff --git a/packages/astro/e2e/fixtures/nested-in-vue/src/components/PreactCounter.tsx b/packages/astro/e2e/fixtures/nested-in-vue/src/components/preact/PreactCounter.tsx
index 5f20f560d..5f20f560d 100644
--- a/packages/astro/e2e/fixtures/nested-in-vue/src/components/PreactCounter.tsx
+++ b/packages/astro/e2e/fixtures/nested-in-vue/src/components/preact/PreactCounter.tsx
diff --git a/packages/astro/e2e/fixtures/nested-in-vue/src/components/ReactCounter.jsx b/packages/astro/e2e/fixtures/nested-in-vue/src/components/react/ReactCounter.jsx
index c7197a072..c7197a072 100644
--- a/packages/astro/e2e/fixtures/nested-in-vue/src/components/ReactCounter.jsx
+++ b/packages/astro/e2e/fixtures/nested-in-vue/src/components/react/ReactCounter.jsx
diff --git a/packages/astro/e2e/fixtures/nested-in-vue/src/components/SolidCounter.tsx b/packages/astro/e2e/fixtures/nested-in-vue/src/components/solid/SolidCounter.tsx
index afabe43b9..afabe43b9 100644
--- a/packages/astro/e2e/fixtures/nested-in-vue/src/components/SolidCounter.tsx
+++ b/packages/astro/e2e/fixtures/nested-in-vue/src/components/solid/SolidCounter.tsx
diff --git a/packages/astro/e2e/fixtures/nested-in-vue/src/components/SvelteCounter.svelte b/packages/astro/e2e/fixtures/nested-in-vue/src/components/svelte/SvelteCounter.svelte
index 733f58076..733f58076 100644
--- a/packages/astro/e2e/fixtures/nested-in-vue/src/components/SvelteCounter.svelte
+++ b/packages/astro/e2e/fixtures/nested-in-vue/src/components/svelte/SvelteCounter.svelte
diff --git a/packages/astro/e2e/fixtures/nested-in-vue/src/components/VueCounter.vue b/packages/astro/e2e/fixtures/nested-in-vue/src/components/vue/VueCounter.vue
index d404cc965..d404cc965 100644
--- a/packages/astro/e2e/fixtures/nested-in-vue/src/components/VueCounter.vue
+++ b/packages/astro/e2e/fixtures/nested-in-vue/src/components/vue/VueCounter.vue
diff --git a/packages/astro/e2e/fixtures/nested-in-vue/src/pages/index.astro b/packages/astro/e2e/fixtures/nested-in-vue/src/pages/index.astro
index 5e4d47d76..e89554755 100644
--- a/packages/astro/e2e/fixtures/nested-in-vue/src/pages/index.astro
+++ b/packages/astro/e2e/fixtures/nested-in-vue/src/pages/index.astro
@@ -1,9 +1,9 @@
---
-import { Counter as ReactCounter } from '../components/ReactCounter.jsx';
-import { PreactCounter } from '../components/PreactCounter.tsx';
-import SolidCounter from '../components/SolidCounter.tsx';
-import VueCounter from '../components/VueCounter.vue';
-import SvelteCounter from '../components/SvelteCounter.svelte';
+import { Counter as ReactCounter } from '../components/react/ReactCounter.jsx';
+import { PreactCounter } from '../components/preact/PreactCounter.tsx';
+import SolidCounter from '../components/solid/SolidCounter.tsx';
+import VueCounter from '../components/vue/VueCounter.vue';
+import SvelteCounter from '../components/svelte/SvelteCounter.svelte';
// Full Astro Component Syntax:
// https://docs.astro.build/core-concepts/astro-components/
diff --git a/packages/astro/e2e/fixtures/nested-recursive/astro.config.mjs b/packages/astro/e2e/fixtures/nested-recursive/astro.config.mjs
index 4b50887cd..0ef8f6e2b 100644
--- a/packages/astro/e2e/fixtures/nested-recursive/astro.config.mjs
+++ b/packages/astro/e2e/fixtures/nested-recursive/astro.config.mjs
@@ -8,5 +8,11 @@ import solid from '@astrojs/solid-js';
// https://astro.build/config
export default defineConfig({
// Enable many frameworks to support all different kinds of components.
- integrations: [preact(), react(), svelte(), vue(), solid()],
+ integrations: [
+ react({ include: ['**/react/*'] }),
+ preact({ include: ['**/preact/*'] }),
+ solid({ include: ['**/solid/*'] }),
+ svelte(),
+ vue(),
+ ],
});
diff --git a/packages/astro/e2e/fixtures/nested-recursive/src/components/PreactCounter.tsx b/packages/astro/e2e/fixtures/nested-recursive/src/components/preact/PreactCounter.tsx
index 32200f41f..32200f41f 100644
--- a/packages/astro/e2e/fixtures/nested-recursive/src/components/PreactCounter.tsx
+++ b/packages/astro/e2e/fixtures/nested-recursive/src/components/preact/PreactCounter.tsx
diff --git a/packages/astro/e2e/fixtures/nested-recursive/src/components/ReactCounter.jsx b/packages/astro/e2e/fixtures/nested-recursive/src/components/react/ReactCounter.jsx
index 6b3a1de5f..6b3a1de5f 100644
--- a/packages/astro/e2e/fixtures/nested-recursive/src/components/ReactCounter.jsx
+++ b/packages/astro/e2e/fixtures/nested-recursive/src/components/react/ReactCounter.jsx
diff --git a/packages/astro/e2e/fixtures/nested-recursive/src/components/SolidCounter.tsx b/packages/astro/e2e/fixtures/nested-recursive/src/components/solid/SolidCounter.tsx
index afabe43b9..afabe43b9 100644
--- a/packages/astro/e2e/fixtures/nested-recursive/src/components/SolidCounter.tsx
+++ b/packages/astro/e2e/fixtures/nested-recursive/src/components/solid/SolidCounter.tsx
diff --git a/packages/astro/e2e/fixtures/nested-recursive/src/components/SvelteCounter.svelte b/packages/astro/e2e/fixtures/nested-recursive/src/components/svelte/SvelteCounter.svelte
index 733f58076..733f58076 100644
--- a/packages/astro/e2e/fixtures/nested-recursive/src/components/SvelteCounter.svelte
+++ b/packages/astro/e2e/fixtures/nested-recursive/src/components/svelte/SvelteCounter.svelte
diff --git a/packages/astro/e2e/fixtures/nested-recursive/src/components/VueCounter.vue b/packages/astro/e2e/fixtures/nested-recursive/src/components/vue/VueCounter.vue
index d404cc965..d404cc965 100644
--- a/packages/astro/e2e/fixtures/nested-recursive/src/components/VueCounter.vue
+++ b/packages/astro/e2e/fixtures/nested-recursive/src/components/vue/VueCounter.vue
diff --git a/packages/astro/e2e/fixtures/nested-recursive/src/pages/index.astro b/packages/astro/e2e/fixtures/nested-recursive/src/pages/index.astro
index 685c7fb5e..a17337c89 100644
--- a/packages/astro/e2e/fixtures/nested-recursive/src/pages/index.astro
+++ b/packages/astro/e2e/fixtures/nested-recursive/src/pages/index.astro
@@ -1,9 +1,9 @@
---
-import ReactCounter from '../components/ReactCounter.jsx';
-import PreactCounter from '../components/PreactCounter.tsx';
-import SolidCounter from '../components/SolidCounter.tsx';
-import VueCounter from '../components/VueCounter.vue';
-import SvelteCounter from '../components/SvelteCounter.svelte';
+import ReactCounter from '../components/react/ReactCounter.jsx';
+import PreactCounter from '../components/preact/PreactCounter.tsx';
+import SolidCounter from '../components/solid/SolidCounter.tsx';
+import VueCounter from '../components/vue/VueCounter.vue';
+import SvelteCounter from '../components/svelte/SvelteCounter.svelte';
---
<html lang="en">
diff --git a/packages/astro/e2e/fixtures/view-transitions/astro.config.mjs b/packages/astro/e2e/fixtures/view-transitions/astro.config.mjs
index 8a9f43bcc..78c248963 100644
--- a/packages/astro/e2e/fixtures/view-transitions/astro.config.mjs
+++ b/packages/astro/e2e/fixtures/view-transitions/astro.config.mjs
@@ -9,7 +9,6 @@ export default defineConfig({
integrations: [react()],
experimental: {
viewTransitions: true,
- assets: true,
},
vite: {
build: {
diff --git a/packages/astro/e2e/multiple-frameworks.test.js b/packages/astro/e2e/multiple-frameworks.test.js
index b9bc85576..e067b0357 100644
--- a/packages/astro/e2e/multiple-frameworks.test.js
+++ b/packages/astro/e2e/multiple-frameworks.test.js
@@ -154,9 +154,7 @@ test.skip('Multiple frameworks', () => {
await expect(count, 'initial count updated to 5').toHaveText('5');
});
- // TODO: re-enable this test when #3559 is fixed
- // https://github.com/withastro/astro/issues/3559
- test.skip('Vue component', async ({ astro, page }) => {
+ test('Vue component', async ({ astro, page }) => {
await page.goto(astro.resolveUrl('/'));
const count = page.locator('#vue-counter pre');
@@ -169,9 +167,7 @@ test.skip('Multiple frameworks', () => {
await expect(count, 'initial count updated to 5').toHaveText('5');
});
- // TODO: track down a reliability issue in this test
- // It seems to lost connection to the vite server in CI
- test.skip('Svelte component', async ({ astro, page }) => {
+ test('Svelte component', async ({ astro, page }) => {
await page.goto(astro.resolveUrl('/'));
const count = page.locator('#svelte-counter pre');
diff --git a/packages/astro/env.d.ts b/packages/astro/env.d.ts
index 079370bec..876a29c60 100644
--- a/packages/astro/env.d.ts
+++ b/packages/astro/env.d.ts
@@ -1,8 +1,8 @@
-/// <reference path="./client-base.d.ts" />
+/// <reference path="./client.d.ts" />
// Caution! The types here are only available inside Astro files (injected automatically by our language server)
// As such, if the typings you're trying to add should be available inside ex: React components, they should instead
-// be inside `client-base.d.ts`
+// be inside `client.d.ts`
type Astro = import('./dist/@types/astro.js').AstroGlobal;
diff --git a/packages/astro/package.json b/packages/astro/package.json
index c79eccc60..7739b7ee4 100644
--- a/packages/astro/package.json
+++ b/packages/astro/package.json
@@ -1,6 +1,6 @@
{
"name": "astro",
- "version": "2.10.9",
+ "version": "3.0.0-beta.2",
"description": "Astro is a modern site builder with web best practices, performance, and DX front-of-mind.",
"type": "module",
"author": "withastro",
@@ -34,14 +34,14 @@
"./env": "./env.d.ts",
"./types": "./types.d.ts",
"./client": "./client.d.ts",
- "./client-base": "./client-base.d.ts",
- "./client-image": "./client-image.d.ts",
"./import-meta": "./import-meta.d.ts",
"./astro-jsx": "./astro-jsx.d.ts",
"./tsconfigs/*.json": "./tsconfigs/*",
"./tsconfigs/*": "./tsconfigs/*.json",
"./jsx/*": "./dist/jsx/*",
"./jsx-runtime": "./dist/jsx-runtime/index.js",
+ "./compiler-runtime": "./dist/runtime/compiler/index.js",
+ "./runtime/*": "./dist/runtime/*",
"./config": {
"types": "./config.d.ts",
"default": "./config.mjs"
@@ -56,18 +56,16 @@
"./assets/image-endpoint": "./dist/assets/image-endpoint.js",
"./assets/services/sharp": "./dist/assets/services/sharp.js",
"./assets/services/squoosh": "./dist/assets/services/squoosh.js",
+ "./assets/services/noop": "./dist/assets/services/noop.js",
"./content/runtime": "./dist/content/runtime.js",
"./content/runtime-assets": "./dist/content/runtime-assets.js",
"./debug": "./components/Debug.astro",
- "./internal/*": "./dist/runtime/server/*",
"./package.json": "./package.json",
- "./runtime/*": "./dist/runtime/*",
- "./server/*": "./dist/runtime/server/*",
- "./dist/jsx/*": "./dist/jsx/*",
"./zod": {
"types": "./zod.d.ts",
"default": "./zod.mjs"
},
+ "./errors": "./dist/core/errors/userError.js",
"./middleware": {
"types": "./dist/core/middleware/index.d.ts",
"default": "./dist/core/middleware/index.js"
@@ -91,8 +89,6 @@
"zod.mjs",
"env.d.ts",
"client.d.ts",
- "client-base.d.ts",
- "client-image.d.ts",
"content-types.template.d.ts",
"content-module.template.mjs",
"import-meta.d.ts",
@@ -115,12 +111,10 @@
"test:e2e:match": "playwright test -g"
},
"dependencies": {
- "@astrojs/compiler": "^1.8.0",
- "@astrojs/internal-helpers": "^0.1.2",
- "@astrojs/language-server": "^1.0.0",
- "@astrojs/markdown-remark": "^2.2.1",
- "@astrojs/telemetry": "^2.1.1",
- "@astrojs/webapi": "^2.2.0",
+ "@astrojs/compiler": "^1.8.1",
+ "@astrojs/internal-helpers": "workspace:*",
+ "@astrojs/markdown-remark": "workspace:*",
+ "@astrojs/telemetry": "workspace:*",
"@babel/core": "^7.22.5",
"@babel/generator": "^7.22.5",
"@babel/parser": "^7.22.5",
@@ -128,8 +122,6 @@
"@babel/traverse": "^7.22.5",
"@babel/types": "^7.22.5",
"@types/babel__core": "^7.20.1",
- "@types/dom-view-transitions": "^1.0.1",
- "@types/yargs-parser": "^21.0.0",
"acorn": "^8.9.0",
"boxen": "^6.2.1",
"chokidar": "^3.5.3",
@@ -137,22 +129,21 @@
"common-ancestor-path": "^1.0.1",
"cookie": "^0.5.0",
"debug": "^4.3.4",
+ "deepmerge-ts": "^4.3.0",
"devalue": "^4.3.2",
"diff": "^5.1.0",
"es-module-lexer": "^1.3.0",
- "esbuild": "^0.17.19",
- "estree-walker": "3.0.0",
+ "esbuild": "^0.18.16",
+ "estree-walker": "^3.0.3",
"execa": "^6.1.0",
"fast-glob": "^3.2.12",
"github-slugger": "^2.0.0",
"gray-matter": "^4.0.3",
"html-escaper": "^3.0.3",
- "http-cache-semantics": "^4.1.1",
"js-yaml": "^4.1.0",
"kleur": "^4.1.4",
"magic-string": "^0.30.2",
"mime": "^3.0.0",
- "network-information-types": "^0.1.1",
"ora": "^6.3.1",
"p-limit": "^4.0.0",
"path-to-regexp": "^6.2.1",
@@ -161,11 +152,11 @@
"rehype": "^12.0.1",
"semver": "^7.5.3",
"server-destroy": "^1.0.1",
+ "sharp": "^0.32.1",
"shiki": "^0.14.1",
"string-width": "^5.1.2",
"strip-ansi": "^7.1.0",
"tsconfig-resolver": "^3.0.1",
- "typescript": "*",
"unist-util-visit": "^4.1.2",
"vfile": "^5.3.7",
"vite": "^4.4.6",
@@ -175,6 +166,7 @@
"zod": "^3.20.6"
},
"devDependencies": {
+ "@astrojs/check": "^0.1.0",
"@playwright/test": "^1.29.2",
"@types/babel__generator": "^7.6.4",
"@types/babel__traverse": "^7.20.1",
@@ -184,26 +176,26 @@
"@types/cookie": "^0.5.1",
"@types/debug": "^4.1.8",
"@types/diff": "^5.0.3",
+ "@types/dom-view-transitions": "^1.0.1",
"@types/estree": "^0.0.51",
"@types/hast": "^2.3.4",
"@types/html-escaper": "^3.0.0",
- "@types/http-cache-semantics": "^4.0.1",
"@types/js-yaml": "^4.0.5",
"@types/mime": "^2.0.3",
"@types/mocha": "^9.1.1",
"@types/prettier": "^2.7.3",
"@types/prompts": "^2.4.4",
- "@types/resolve": "^1.20.2",
- "@types/rimraf": "^3.0.2",
"@types/send": "^0.17.1",
"@types/server-destroy": "^1.0.1",
"@types/unist": "^2.0.6",
+ "@types/yargs-parser": "^21.0.0",
"astro-scripts": "workspace:*",
"chai": "^4.3.7",
"cheerio": "1.0.0-rc.12",
"eol": "^0.9.1",
"memfs": "^3.5.3",
"mocha": "^9.2.2",
+ "network-information-types": "^0.1.1",
"node-mocks-http": "^1.12.2",
"rehype-autolink-headings": "^6.1.1",
"rehype-slug": "^5.0.1",
@@ -211,21 +203,11 @@
"remark-code-titles": "^0.1.2",
"rollup": "^3.25.1",
"sass": "^1.63.4",
- "sharp": "^0.32.1",
"srcset-parse": "^1.1.0",
- "undici": "^5.22.1",
"unified": "^10.1.2"
},
- "peerDependencies": {
- "sharp": ">=0.31.0"
- },
- "peerDependenciesMeta": {
- "sharp": {
- "optional": true
- }
- },
"engines": {
- "node": ">=16.12.0",
+ "node": ">=18.14.1",
"npm": ">=6.14.0"
}
}
diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts
index cc5ddea7f..f9568d417 100644
--- a/packages/astro/src/@types/astro.ts
+++ b/packages/astro/src/@types/astro.ts
@@ -20,8 +20,10 @@ import type { AstroConfigType } from '../core/config';
import type { AstroTimer } from '../core/config/timer';
import type { AstroCookies } from '../core/cookies';
import type { LogOptions, LoggerLevel } from '../core/logger/core';
+import type { AstroIntegrationLogger } from '../core/logger/core';
import type { AstroComponentFactory, AstroComponentInstance } from '../runtime/server';
import type { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from './../core/constants.js';
+
export type {
MarkdownHeading,
MarkdownMetadata,
@@ -132,7 +134,6 @@ export interface CLIFlags {
config?: string;
drafts?: boolean;
open?: boolean;
- experimentalAssets?: boolean;
}
/**
@@ -329,7 +330,7 @@ type ServerConfig = {
/**
* @name server.port
* @type {number}
- * @default `3000`
+ * @default `4321`
* @description
* Set which port the dev server should listen on.
*
@@ -543,14 +544,14 @@ export interface AstroUserConfig {
* @docs
* @name compressHTML
* @type {boolean}
- * @default `false`
+ * @default `true`
* @description
- * This is an option to minify your HTML output and reduce the size of your HTML files. When enabled, Astro removes all whitespace from your HTML, including line breaks, from `.astro` components. This occurs both in development mode and in the final build.
- * To enable this, set the `compressHTML` flag to `true`.
+ * This is an option to minify your HTML output and reduce the size of your HTML files. By default, Astro removes all whitespace from your HTML, including line breaks, from `.astro` components. This occurs both in development mode and in the final build.
+ * To disable HTML compression, set the `compressHTML` flag to `false`.
*
* ```js
* {
- * compressHTML: true
+ * compressHTML: false
* }
* ```
*/
@@ -573,12 +574,7 @@ export interface AstroUserConfig {
*
* When using this option, all of your static asset imports and URLs should add the base as a prefix. You can access this value via `import.meta.env.BASE_URL`.
*
- * By default, the value of `import.meta.env.BASE_URL` includes a trailing slash. If you have the [`trailingSlash`](https://docs.astro.build/en/reference/configuration-reference/#trailingslash) option set to `'never'`, you will need to add it manually in your static asset imports and URLs.
- *
- * ```astro
- * <a href="/docs/about/">About</a>
- * <img src=`${import.meta.env.BASE_URL}image.png`>
- * ```
+ * The value of `import.meta.env.BASE_URL` respects your `trailingSlash` config and will include a trailing slash if you explicitly include one or if `trailingSlash: "always"` is set. If `trailingSlash: "never"` is set, `BASE_URL` will not include a trailing slash, even if `base` includes one.
*/
base?: string;
@@ -611,19 +607,21 @@ export interface AstroUserConfig {
/**
* @docs
* @name scopedStyleStrategy
- * @type {('where' | 'class')}
+ * @type {('where' | 'class' | 'attribute')}
* @default `'where'`
* @version 2.4
* @description
*
* Specify the strategy used for scoping styles within Astro components. Choose from:
- * - `'where'` - Use `:where` selectors, causing no specifity increase.
- * - `'class'` - Use class-based selectors, causing a +1 specifity increase.
+ * - `'where'` - Use `:where` selectors, causing no specifity increase.
+ * - `'class'` - Use class-based selectors, causing a +1 specifity increase.
+ * - `'attribute'` - Use `data-` attributes, causing no specifity increase.
*
* Using `'class'` is helpful when you want to ensure that element selectors within an Astro component override global style defaults (e.g. from a global stylesheet).
* Using `'where'` gives you more control over specifity, but requires that you use higher-specifity selectors, layers, and other tools to control which selectors are applied.
+ * Using `'attribute'` is useful in case there's manipulation of the class attributes, so the styling emitted by Astro doesn't go in conflict with the user's business logic.
*/
- scopedStyleStrategy?: 'where' | 'class';
+ scopedStyleStrategy?: 'where' | 'class' | 'attribute';
/**
* @docs
@@ -921,7 +919,7 @@ export interface AstroUserConfig {
* ```js
* {
* // Example: Use the function syntax to customize based on command
- * server: ({ command }) => ({ port: command === 'dev' ? 3000 : 4000 })
+ * server: ({ command }) => ({ port: command === 'dev' ? 4321 : 4000 })
* }
* ```
*/
@@ -943,7 +941,7 @@ export interface AstroUserConfig {
* @docs
* @name server.port
* @type {number}
- * @default `3000`
+ * @default `4321`
* @description
* Set which port the server should listen on.
*
@@ -993,7 +991,7 @@ export interface AstroUserConfig {
* @docs
* @name image.service (Experimental)
* @type {{entrypoint: 'astro/assets/services/sharp' | 'astro/assets/services/squoosh' | string, config: Record<string, any>}}
- * @default `{entrypoint: 'astro/assets/services/squoosh', config?: {}}`
+ * @default `{entrypoint: 'astro/assets/services/sharp', config?: {}}`
* @version 2.1.0
* @description
* Set which image service is used for Astro’s experimental assets support.
@@ -1302,27 +1300,6 @@ export interface AstroUserConfig {
experimental?: {
/**
* @docs
- * @name experimental.assets
- * @type {boolean}
- * @default `false`
- * @version 2.1.0
- * @description
- * Enable experimental support for optimizing and resizing images. With this enabled, a new `astro:assets` module will be exposed.
- *
- * To enable this feature, set `experimental.assets` to `true` in your Astro config:
- *
- * ```js
- * {
- * experimental: {
- * assets: true,
- * },
- * }
- * ```
- */
- assets?: boolean;
-
- /**
- * @docs
* @name experimental.viewTransitions
* @type {boolean}
* @default `false`
@@ -1505,6 +1482,17 @@ export interface DataEntryType {
export type GetDataEntryInfoReturnType = { data: Record<string, unknown>; rawData?: string };
+export interface AstroAdapterFeatures {
+ /**
+ * Creates and edge function that will communiate with the Astro middleware
+ */
+ edgeMiddleware: boolean;
+ /**
+ * SSR only. Each route becomes its own function/file.
+ */
+ functionPerRoute: boolean;
+}
+
export interface AstroSettings {
config: AstroConfig;
adapter: AstroAdapter | undefined;
@@ -1621,10 +1609,7 @@ export type GetStaticPathsResultKeyed = GetStaticPathsResult & {
*/
export type GetStaticPaths = (
options: GetStaticPathsOptions
-) =>
- | Promise<GetStaticPathsResult | GetStaticPathsResult[]>
- | GetStaticPathsResult
- | GetStaticPathsResult[];
+) => Promise<GetStaticPathsResult> | GetStaticPathsResult;
/**
* Infers the shape of the `params` property returned by `getStaticPaths()`.
@@ -1767,12 +1752,52 @@ export type PaginateFunction = (data: any[], args?: PaginateOptions) => GetStati
export type Params = Record<string, string | undefined>;
+export type SupportsKind = 'unsupported' | 'stable' | 'experimental' | 'deprecated';
+
+export type AstroFeatureMap = {
+ /**
+ * The adapter is able serve static pages
+ */
+ staticOutput?: SupportsKind;
+ /**
+ * The adapter is able to serve pages that are static or rendered via server
+ */
+ hybridOutput?: SupportsKind;
+ /**
+ * The adapter is able to serve SSR pages
+ */
+ serverOutput?: SupportsKind;
+ /**
+ * The adapter can emit static assets
+ */
+ assets?: AstroAssetsFeature;
+};
+
+export interface AstroAssetsFeature {
+ supportKind?: SupportsKind;
+ /**
+ * Whether if this adapter deploys files in an enviroment that is compatible with the library `sharp`
+ */
+ isSharpCompatible?: boolean;
+ /**
+ * Whether if this adapter deploys files in an enviroment that is compatible with the library `squoosh`
+ */
+ isSquooshCompatible?: boolean;
+}
+
export interface AstroAdapter {
name: string;
serverEntrypoint?: string;
previewEntrypoint?: string;
exports?: string[];
args?: any;
+ adapterFeatures?: AstroAdapterFeatures;
+ /**
+ * List of features supported by an adapter.
+ *
+ * If the adapter is not able to handle certain configurations, Astro will throw an error.
+ */
+ supportedAstroFeatures?: AstroFeatureMap;
}
type Body = string;
@@ -1960,7 +1985,7 @@ export interface SSRLoadedRenderer extends AstroRenderer {
export type HookParameters<
Hook extends keyof AstroIntegration['hooks'],
- Fn = AstroIntegration['hooks'][Hook]
+ Fn = AstroIntegration['hooks'][Hook],
> = Fn extends (...args: any) => any ? Parameters<Fn>[0] : never;
export interface AstroIntegration {
@@ -1978,6 +2003,7 @@ export interface AstroIntegration {
injectScript: (stage: InjectedScriptStage, content: string) => void;
injectRoute: (injectRoute: InjectedRoute) => void;
addClientDirective: (directive: ClientDirectiveConfig) => void;
+ logger: AstroIntegrationLogger;
// TODO: Add support for `injectElement()` for full HTML element injection, not just scripts.
// This may require some refactoring of `scripts`, `styles`, and `links` into something
// more generalized. Consider the SSR use-case as well.
@@ -1986,10 +2012,17 @@ export interface AstroIntegration {
'astro:config:done'?: (options: {
config: AstroConfig;
setAdapter: (adapter: AstroAdapter) => void;
+ logger: AstroIntegrationLogger;
+ }) => void | Promise<void>;
+ 'astro:server:setup'?: (options: {
+ server: vite.ViteDevServer;
+ logger: AstroIntegrationLogger;
}) => void | Promise<void>;
- 'astro:server:setup'?: (options: { server: vite.ViteDevServer }) => void | Promise<void>;
- 'astro:server:start'?: (options: { address: AddressInfo }) => void | Promise<void>;
- 'astro:server:done'?: () => void | Promise<void>;
+ 'astro:server:start'?: (options: {
+ address: AddressInfo;
+ logger: AstroIntegrationLogger;
+ }) => void | Promise<void>;
+ 'astro:server:done'?: (options: { logger: AstroIntegrationLogger }) => void | Promise<void>;
'astro:build:ssr'?: (options: {
manifest: SerializedSSRManifest;
/**
@@ -2001,19 +2034,25 @@ export interface AstroIntegration {
* File path of the emitted middleware
*/
middlewareEntryPoint: URL | undefined;
+ logger: AstroIntegrationLogger;
}) => void | Promise<void>;
- 'astro:build:start'?: () => void | Promise<void>;
+ 'astro:build:start'?: (options: { logger: AstroIntegrationLogger }) => void | Promise<void>;
'astro:build:setup'?: (options: {
vite: vite.InlineConfig;
pages: Map<string, PageBuildData>;
target: 'client' | 'server';
updateConfig: (newConfig: vite.InlineConfig) => void;
+ logger: AstroIntegrationLogger;
+ }) => void | Promise<void>;
+ 'astro:build:generated'?: (options: {
+ dir: URL;
+ logger: AstroIntegrationLogger;
}) => void | Promise<void>;
- 'astro:build:generated'?: (options: { dir: URL }) => void | Promise<void>;
'astro:build:done'?: (options: {
pages: { pathname: string }[];
dir: URL;
routes: RouteData[];
+ logger: AstroIntegrationLogger;
}) => void | Promise<void>;
};
}
diff --git a/packages/astro/src/assets/image-endpoint.ts b/packages/astro/src/assets/image-endpoint.ts
index fa62cbdd1..d83517379 100644
--- a/packages/astro/src/assets/image-endpoint.ts
+++ b/packages/astro/src/assets/image-endpoint.ts
@@ -1,9 +1,8 @@
import mime from 'mime/lite.js';
import type { APIRoute } from '../@types/astro.js';
+import { etag } from './utils/etag.js';
import { isRemotePath } from '../core/path.js';
import { getConfiguredImageService, isRemoteAllowed } from './internal.js';
-import { isLocalService } from './services/service.js';
-import { etag } from './utils/etag.js';
// @ts-expect-error
import { imageConfig } from 'astro:assets';
@@ -24,11 +23,11 @@ async function loadRemoteImage(src: URL) {
/**
* Endpoint used in dev and SSR to serve optimized images by the base image services
*/
-export const get: APIRoute = async ({ request }) => {
+export const GET: APIRoute = async ({ request }) => {
try {
const imageService = await getConfiguredImageService();
- if (!isLocalService(imageService)) {
+ if (!('transform' in imageService)) {
throw new Error('Configured image service is not a local service');
}
@@ -71,3 +70,7 @@ export const get: APIRoute = async ({ request }) => {
return new Response(`Server Error: ${err}`, { status: 500 });
}
};
+
+function isRemotePath(src: string) {
+ return /^(http|ftp|https|ws):?\/\//.test(src) || src.startsWith('data:');
+}
diff --git a/packages/astro/src/assets/internal.ts b/packages/astro/src/assets/internal.ts
index ffc27333f..dd5e427f6 100644
--- a/packages/astro/src/assets/internal.ts
+++ b/packages/astro/src/assets/internal.ts
@@ -11,6 +11,7 @@ import type {
import { matchHostname, matchPattern } from './utils/remotePattern.js';
export function injectImageEndpoint(settings: AstroSettings) {
+ // TODO: Add a setting to disable the image endpoint
settings.injectedRoutes.push({
pattern: '/_image',
entryPoint: 'astro/assets/image-endpoint',
diff --git a/packages/astro/src/assets/services/noop.ts b/packages/astro/src/assets/services/noop.ts
new file mode 100644
index 000000000..d57ffeb27
--- /dev/null
+++ b/packages/astro/src/assets/services/noop.ts
@@ -0,0 +1,17 @@
+import { baseService, type LocalImageService } from './service.js';
+
+// Empty service used for platforms that neither support Squoosh or Sharp.
+const noopService: LocalImageService = {
+ validateOptions: baseService.validateOptions,
+ getURL: baseService.getURL,
+ parseURL: baseService.parseURL,
+ getHTMLAttributes: baseService.getHTMLAttributes,
+ async transform(inputBuffer, transformOptions) {
+ return {
+ data: inputBuffer,
+ format: transformOptions.format,
+ };
+ },
+};
+
+export default noopService;
diff --git a/packages/astro/src/assets/services/vendor/squoosh/impl.ts b/packages/astro/src/assets/services/vendor/squoosh/impl.ts
index 7bb9aeeea..273957e4b 100644
--- a/packages/astro/src/assets/services/vendor/squoosh/impl.ts
+++ b/packages/astro/src/assets/services/vendor/squoosh/impl.ts
@@ -33,7 +33,7 @@ export async function decodeBuffer(
.join('')
// TODO (future PR): support more formats
if (firstChunkString.includes('GIF')) {
- throw Error(`GIF images are not supported, please install the @astrojs/image/sharp plugin`)
+ throw Error(`GIF images are not supported, please use the Sharp image service`)
}
const key = Object.entries(supportedFormats).find(([, { detectors }]) =>
detectors.some((detector) => detector.exec(firstChunkString))
@@ -78,7 +78,7 @@ export async function encodeJpeg(
opts: { quality?: number }
): Promise<Uint8Array> {
image = ImageData.from(image)
-
+
const e = supportedFormats['mozjpeg']
const m = await e.enc()
await maybeDelay()
diff --git a/packages/astro/src/assets/types.ts b/packages/astro/src/assets/types.ts
index 9c5990cb7..ae74fc692 100644
--- a/packages/astro/src/assets/types.ts
+++ b/packages/astro/src/assets/types.ts
@@ -90,7 +90,7 @@ export type LocalImageProps<T> = ImageSharedProps<T> & {
*
* **Example**:
* ```js
- * import myImage from "~/assets/my_image.png";
+ * import myImage from "../assets/my_image.png";
* ```
* And then refer to the image, like so:
* ```astro
diff --git a/packages/astro/src/assets/vite-plugin-assets.ts b/packages/astro/src/assets/vite-plugin-assets.ts
index 0f00e0ecb..f194e5288 100644
--- a/packages/astro/src/assets/vite-plugin-assets.ts
+++ b/packages/astro/src/assets/vite-plugin-assets.ts
@@ -1,10 +1,7 @@
-import { bold } from 'kleur/colors';
import MagicString from 'magic-string';
-import { fileURLToPath } from 'node:url';
import type * as vite from 'vite';
import { normalizePath } from 'vite';
import type { AstroPluginOptions, ImageTransform } from '../@types/astro';
-import { error } from '../core/logger/core.js';
import {
appendForwardSlash,
joinPaths,
@@ -22,53 +19,16 @@ const urlRE = /(\?|&)url(?:&|$)/;
export default function assets({
settings,
- logging,
mode,
}: AstroPluginOptions & { mode: string }): vite.Plugin[] {
let resolvedConfig: vite.ResolvedConfig;
globalThis.astroAsset = {};
- const UNSUPPORTED_ADAPTERS = new Set([
- '@astrojs/cloudflare',
- '@astrojs/deno',
- '@astrojs/netlify/edge-functions',
- '@astrojs/vercel/edge',
- ]);
-
- const adapterName = settings.config.adapter?.name;
- if (
- ['astro/assets/services/sharp', 'astro/assets/services/squoosh'].includes(
- settings.config.image.service.entrypoint
- ) &&
- adapterName &&
- UNSUPPORTED_ADAPTERS.has(adapterName)
- ) {
- error(
- logging,
- 'assets',
- `The currently selected adapter \`${adapterName}\` does not run on Node, however the currently used image service depends on Node built-ins. ${bold(
- 'Your project will NOT be able to build.'
- )}`
- );
- }
-
return [
// Expose the components and different utilities from `astro:assets` and handle serving images from `/_image` in dev
{
name: 'astro:assets',
- config() {
- return {
- resolve: {
- alias: [
- {
- find: /^~\/assets\/(.+)$/,
- replacement: fileURLToPath(new URL('./assets/$1', settings.config.srcDir)),
- },
- ],
- },
- };
- },
async resolveId(id) {
if (id === VIRTUAL_SERVICE_ID) {
return await this.resolve(settings.config.image.service.entrypoint);
diff --git a/packages/astro/src/cli/add/index.ts b/packages/astro/src/cli/add/index.ts
index 82f590c25..fcaeb07c7 100644
--- a/packages/astro/src/cli/add/index.ts
+++ b/packages/astro/src/cli/add/index.ts
@@ -216,12 +216,6 @@ export async function add(names: string[], { flags }: AddOptions) {
await fs.writeFile(fileURLToPath(configURL), ASTRO_CONFIG_STUB, { encoding: 'utf-8' });
}
- // TODO: improve error handling for invalid configs
- if (configURL?.pathname.endsWith('package.json')) {
- throw new Error(
- `Unable to use "astro add" with package.json configuration. Try migrating to \`astro.config.mjs\` and try again.`
- );
- }
let ast: t.File | null = null;
try {
ast = await parseAstroConfig(configURL);
@@ -709,6 +703,7 @@ async function tryToInstallIntegrations({
} catch (err) {
spinner.fail();
debug('add', 'Error installing dependencies', err);
+ // eslint-disable-next-line no-console
console.error('\n', (err as any).stdout, '\n');
return UpdateResult.failure;
}
diff --git a/packages/astro/src/cli/check/index.ts b/packages/astro/src/cli/check/index.ts
index 96bee308d..428027154 100644
--- a/packages/astro/src/cli/check/index.ts
+++ b/packages/astro/src/cli/check/index.ts
@@ -1,396 +1,43 @@
-import {
- AstroCheck,
- DiagnosticSeverity,
- type GetDiagnosticsResult,
-} from '@astrojs/language-server';
-import type { FSWatcher } from 'chokidar';
-import glob from 'fast-glob';
-import { bold, dim, red, yellow } from 'kleur/colors';
-import { createRequire } from 'module';
-import fs from 'node:fs';
-import { join } from 'node:path';
-import { fileURLToPath, pathToFileURL } from 'node:url';
-import ora from 'ora';
-import type { Arguments as Flags } from 'yargs-parser';
-import type { AstroSettings } from '../../@types/astro';
-import { resolveConfig } from '../../core/config/config.js';
-import { createNodeLogging } from '../../core/config/logging.js';
-import { createSettings } from '../../core/config/settings.js';
-import type { LogOptions } from '../../core/logger/core.js';
-import { debug, info } from '../../core/logger/core.js';
-import { printHelp } from '../../core/messages.js';
-import type { syncInternal } from '../../core/sync';
-import { eventCliSession, telemetry } from '../../events/index.js';
-import { runHookConfigSetup } from '../../integrations/index.js';
-import { flagsToAstroInlineConfig } from '../flags.js';
-import { printDiagnostic } from './print.js';
-
-type DiagnosticResult = {
- errors: number;
- warnings: number;
- hints: number;
-};
-
-export type CheckPayload = {
- /**
- * Flags passed via CLI
- */
- flags: Flags;
-};
-
-type CheckFlags = {
- /**
- * Whether the `check` command should watch for `.astro` and report errors
- * @default {false}
- */
- watch: boolean;
-};
-
-/**
- *
- * Types of response emitted by the checker
- */
-export enum CheckResult {
- /**
- * Operation finished without errors
- */
- ExitWithSuccess,
- /**
- * Operation finished with errors
- */
- ExitWithError,
- /**
- * The consumer should not terminate the operation
- */
- Listen,
-}
-
-const ASTRO_GLOB_PATTERN = '**/*.astro';
-
-/**
- * Checks `.astro` files for possible errors.
- *
- * If the `--watch` flag is provided, the command runs indefinitely and provides diagnostics
- * when `.astro` files are modified.
- *
- * Every time an astro files is modified, content collections are also generated.
- *
- * @param {CheckPayload} options Options passed {@link AstroChecker}
- * @param {Flags} options.flags Flags coming from the CLI
- */
-export async function check({ flags }: CheckPayload): Promise<AstroChecker | undefined> {
- if (flags.help || flags.h) {
- printHelp({
- commandName: 'astro check',
- usage: '[...flags]',
- tables: {
- Flags: [
- ['--watch', 'Watch Astro files for changes and re-run checks.'],
- ['--help (-h)', 'See all available flags.'],
- ],
- },
- description: `Runs diagnostics against your project and reports errors to the console.`,
- });
- return;
- }
-
- // Load settings
- const inlineConfig = flagsToAstroInlineConfig(flags);
- const logging = createNodeLogging(inlineConfig);
- const { userConfig, astroConfig } = await resolveConfig(inlineConfig, 'check');
- telemetry.record(eventCliSession('check', userConfig, flags));
- const settings = createSettings(astroConfig, fileURLToPath(astroConfig.root));
-
- const checkFlags = parseFlags(flags);
- if (checkFlags.watch) {
- info(logging, 'check', 'Checking files in watch mode');
- } else {
- info(logging, 'check', 'Checking files');
- }
-
- const { syncInternal } = await import('../../core/sync/index.js');
- const root = settings.config.root;
- const require = createRequire(import.meta.url);
- const diagnosticChecker = new AstroCheck(
- root.toString(),
- require.resolve('typescript/lib/tsserverlibrary.js', {
- paths: [root.toString()],
- })
- );
-
- return new AstroChecker({
- syncInternal,
- settings,
- fileSystem: fs,
+import path from 'node:path';
+import type { Arguments } from 'yargs-parser';
+import { error, info } from '../../core/logger/core.js';
+import { createLoggingFromFlags, flagsToAstroInlineConfig } from '../flags.js';
+import { getPackage } from '../install-package.js';
+
+export async function check(flags: Arguments) {
+ const logging = createLoggingFromFlags(flags);
+ const getPackageOpts = { skipAsk: flags.yes || flags.y, cwd: flags.root };
+ const checkPackage = await getPackage<typeof import('@astrojs/check')>(
+ '@astrojs/check',
logging,
- diagnosticChecker,
- isWatchMode: checkFlags.watch,
- });
-}
-
-type CheckerConstructor = {
- diagnosticChecker: AstroCheck;
-
- isWatchMode: boolean;
-
- syncInternal: typeof syncInternal;
-
- settings: Readonly<AstroSettings>;
-
- logging: Readonly<LogOptions>;
-
- fileSystem: typeof fs;
-};
-
-/**
- * Responsible to check files - classic or watch mode - and report diagnostics.
- *
- * When in watch mode, the class does a whole check pass, and then starts watching files.
- * When a change occurs to an `.astro` file, the checker builds content collections again and lint all the `.astro` files.
- */
-export class AstroChecker {
- readonly #diagnosticsChecker: AstroCheck;
- readonly #shouldWatch: boolean;
- readonly #syncInternal: CheckerConstructor['syncInternal'];
-
- readonly #settings: AstroSettings;
-
- readonly #logging: LogOptions;
- readonly #fs: typeof fs;
- #watcher?: FSWatcher;
-
- #filesCount: number;
- #updateDiagnostics: NodeJS.Timeout | undefined;
-
- constructor({
- diagnosticChecker,
- isWatchMode,
- syncInternal,
- settings,
- fileSystem,
- logging,
- }: CheckerConstructor) {
- this.#diagnosticsChecker = diagnosticChecker;
- this.#shouldWatch = isWatchMode;
- this.#syncInternal = syncInternal;
- this.#logging = logging;
- this.#settings = settings;
- this.#fs = fileSystem;
- this.#filesCount = 0;
- }
-
- /**
- * Check all `.astro` files once and then finishes the operation.
- */
- public async check(): Promise<CheckResult> {
- return await this.#checkAllFiles(true);
- }
-
- /**
- * Check all `.astro` files and then start watching for changes.
- */
- public async watch(): Promise<CheckResult> {
- await this.#checkAllFiles(true);
- await this.#watch();
- return CheckResult.Listen;
- }
-
- /**
- * Stops the watch. It terminates the inner server.
- */
- public async stop() {
- await this.#watcher?.close();
- }
-
- /**
- * Whether the checker should run in watch mode
- */
- public get isWatchMode(): boolean {
- return this.#shouldWatch;
- }
-
- async #openDocuments() {
- this.#filesCount = await openAllDocuments(
- this.#settings.config.root,
- [],
- this.#diagnosticsChecker
- );
- }
-
- /**
- * Lint all `.astro` files, and report the result in console. Operations executed, in order:
- * 1. Compile content collections.
- * 2. Optionally, traverse the file system for `.astro` files and saves their paths.
- * 3. Get diagnostics for said files and print the result in console.
- *
- * @param openDocuments Whether the operation should open all `.astro` files
- */
- async #checkAllFiles(openDocuments: boolean): Promise<CheckResult> {
- // Run `astro:config:setup` before syncing to initialize integrations.
- // We do this manually as we're calling `syncInternal` directly.
- const syncSettings = await runHookConfigSetup({
- settings: this.#settings,
- logging: this.#logging,
- command: 'build',
- });
- const processExit = await this.#syncInternal(syncSettings, {
- logging: this.#logging,
- fs: this.#fs,
- });
- // early exit on sync failure
- if (processExit === 1) return processExit;
-
- let spinner = ora(
- ` Getting diagnostics for Astro files in ${fileURLToPath(this.#settings.config.root)}…`
- ).start();
-
- if (openDocuments) {
- await this.#openDocuments();
- }
-
- let diagnostics = await this.#diagnosticsChecker.getDiagnostics();
-
- spinner.succeed();
-
- let brokenDownDiagnostics = this.#breakDownDiagnostics(diagnostics);
- this.#logDiagnosticsSeverity(brokenDownDiagnostics);
- return brokenDownDiagnostics.errors > 0
- ? CheckResult.ExitWithError
- : CheckResult.ExitWithSuccess;
- }
-
- #checkForDiagnostics() {
- clearTimeout(this.#updateDiagnostics);
- // @ematipico: I am not sure of `setTimeout`. I would rather use a debounce but let's see if this works.
- // Inspiration from `svelte-check`.
- this.#updateDiagnostics = setTimeout(async () => await this.#checkAllFiles(false), 500);
- }
-
- /**
- * This function is responsible to attach events to the server watcher
- */
- async #watch() {
- const { default: chokidar } = await import('chokidar');
- this.#watcher = chokidar.watch(
- join(fileURLToPath(this.#settings.config.root), ASTRO_GLOB_PATTERN),
- {
- ignored: ['**/node_modules/**'],
- ignoreInitial: true,
- }
- );
-
- this.#watcher.on('add', (file) => {
- this.#addDocument(file);
- this.#filesCount += 1;
- this.#checkForDiagnostics();
- });
- this.#watcher.on('change', (file) => {
- this.#addDocument(file);
- this.#checkForDiagnostics();
- });
- this.#watcher.on('unlink', (file) => {
- this.#diagnosticsChecker.removeDocument(file);
- this.#filesCount -= 1;
- this.#checkForDiagnostics();
- });
- }
-
- /**
- * Add a document to the diagnostics checker
- * @param filePath Path to the file
- */
- #addDocument(filePath: string) {
- const text = fs.readFileSync(filePath, 'utf-8');
- this.#diagnosticsChecker.upsertDocument({
- uri: pathToFileURL(filePath).toString(),
- text,
- });
- }
+ getPackageOpts,
+ ['typescript']
+ );
+ const typescript = await getPackage('typescript', logging, getPackageOpts);
- /**
- * Logs the result of the various diagnostics
- *
- * @param result Result emitted by AstroChecker.#breakDownDiagnostics
- */
- #logDiagnosticsSeverity(result: Readonly<DiagnosticResult>) {
- info(
- this.#logging,
- 'diagnostics',
- [
- bold(`Result (${this.#filesCount} file${this.#filesCount === 1 ? '' : 's'}): `),
- bold(red(`${result.errors} ${result.errors === 1 ? 'error' : 'errors'}`)),
- bold(yellow(`${result.warnings} ${result.warnings === 1 ? 'warning' : 'warnings'}`)),
- dim(`${result.hints} ${result.hints === 1 ? 'hint' : 'hints'}\n`),
- ].join(`\n${dim('-')} `)
+ if (!checkPackage || !typescript) {
+ error(
+ logging,
+ 'check',
+ 'The `@astrojs/check` and `typescript` packages are required for this command to work. Please manually install them into your project and try again.'
);
+ return;
}
- /**
- * It loops through all diagnostics and break down diagnostics that are errors, warnings or hints.
- */
- #breakDownDiagnostics(diagnostics: Readonly<GetDiagnosticsResult[]>): DiagnosticResult {
- let result: DiagnosticResult = {
- errors: 0,
- warnings: 0,
- hints: 0,
- };
-
- diagnostics.forEach((diag) => {
- diag.diagnostics.forEach((d) => {
- info(this.#logging, 'diagnostics', `\n ${printDiagnostic(diag.fileUri, diag.text, d)}`);
-
- switch (d.severity) {
- case DiagnosticSeverity.Error: {
- result.errors++;
- break;
- }
- case DiagnosticSeverity.Warning: {
- result.warnings++;
- break;
- }
- case DiagnosticSeverity.Hint: {
- result.hints++;
- break;
- }
- }
- });
- });
-
- return result;
+ // Run sync before check to make sure types are generated.
+ // NOTE: In the future, `@astrojs/check` can expose a `before lint` hook so that this works during `astro check --watch` too.
+ // For now, we run this once as usually `astro check --watch` is ran alongside `astro dev` which also calls `astro sync`.
+ const { sync } = await import('../../core/sync/index.js');
+ const inlineConfig = flagsToAstroInlineConfig(flags);
+ const exitCode = await sync(inlineConfig);
+ if (exitCode !== 0) {
+ process.exit(exitCode);
}
-}
-
-/**
- * Open all Astro files in the given directory and return the number of files found.
- */
-async function openAllDocuments(
- workspaceUri: URL,
- filePathsToIgnore: string[],
- checker: AstroCheck
-): Promise<number> {
- const files = await glob(ASTRO_GLOB_PATTERN, {
- cwd: fileURLToPath(workspaceUri),
- ignore: ['node_modules/**'].concat(filePathsToIgnore.map((ignore) => `${ignore}/**`)),
- absolute: true,
- });
- for (const file of files) {
- debug('check', `Adding file ${file} to the list of files to check.`);
- const text = fs.readFileSync(file, 'utf-8');
- checker.upsertDocument({
- uri: pathToFileURL(file).toString(),
- text,
- });
- }
+ const { check: checker, parseArgsAsCheckConfig } = checkPackage;
- return files.length;
-}
+ const config = parseArgsAsCheckConfig(process.argv);
-/**
- * Parse flags and sets defaults
- */
-function parseFlags(flags: Flags): CheckFlags {
- return {
- watch: flags.watch ?? false,
- };
+ info(logging, 'check', `Getting diagnostics for Astro files in ${path.resolve(config.root)}...`);
+ return await checker(config);
}
diff --git a/packages/astro/src/cli/check/print.ts b/packages/astro/src/cli/check/print.ts
deleted file mode 100644
index bd8de2ddb..000000000
--- a/packages/astro/src/cli/check/print.ts
+++ /dev/null
@@ -1,119 +0,0 @@
-import { DiagnosticSeverity, offsetAt, type Diagnostic } from '@astrojs/language-server';
-import {
- bgRed,
- bgWhite,
- bgYellow,
- black,
- bold,
- cyan,
- gray,
- red,
- white,
- yellow,
-} from 'kleur/colors';
-import { fileURLToPath } from 'node:url';
-import stringWidth from 'string-width';
-
-export function printDiagnostic(filePath: string, text: string, diag: Diagnostic): string {
- let result = [];
-
- // Lines and characters are 0-indexed, so we need to add 1 to the offset to get the actual line and character
- const realStartLine = diag.range.start.line + 1;
- const realStartCharacter = diag.range.start.character + 1;
-
- // IDE friendly path that user can CTRL+Click to open the file at a specific line / character
- const IDEFilePath = `${bold(cyan(fileURLToPath(filePath)))}:${bold(yellow(realStartLine))}:${bold(
- yellow(realStartCharacter)
- )}`;
- result.push(
- `${IDEFilePath} ${bold(getColorForSeverity(diag, getStringForSeverity(diag)))}: ${diag.message}`
- );
-
- // Optionally add the line before the error to add context if not empty
- const previousLine = getLine(diag.range.start.line - 1, text);
- if (previousLine) {
- result.push(`${getPrintableLineNumber(realStartLine - 1)} ${gray(previousLine)}`);
- }
-
- // Add the line with the error
- const str = getLine(diag.range.start.line, text);
- const lineNumStr = realStartLine.toString().padStart(2, '0');
- const lineNumLen = lineNumStr.length;
- result.push(`${getBackgroundForSeverity(diag, lineNumStr)} ${str}`);
-
- // Adds tildes under the specific range where the diagnostic is
- const tildes = generateString('~', diag.range.end.character - diag.range.start.character);
-
- // NOTE: This is not perfect, if the line include any characters that is made of multiple characters, for example
- // regionals flags, but the terminal can't display it, then the number of spaces will be wrong. Not sure how to fix.
- const beforeChars = stringWidth(str.substring(0, diag.range.start.character));
- const spaces = generateString(' ', beforeChars + lineNumLen - 1);
- result.push(` ${spaces}${bold(getColorForSeverity(diag, tildes))}`);
-
- const nextLine = getLine(diag.range.start.line + 1, text);
- if (nextLine) {
- result.push(`${getPrintableLineNumber(realStartLine + 1)} ${gray(nextLine)}`);
- }
-
- // Force a new line at the end
- result.push('');
-
- return result.join('\n');
-}
-
-function generateString(str: string, len: number): string {
- return Array.from({ length: len }, () => str).join('');
-}
-
-function getStringForSeverity(diag: Diagnostic): string {
- switch (diag.severity) {
- case DiagnosticSeverity.Error:
- return 'Error';
- case DiagnosticSeverity.Warning:
- return 'Warning';
- case DiagnosticSeverity.Hint:
- return 'Hint';
- default:
- return 'Unknown';
- }
-}
-
-function getColorForSeverity(diag: Diagnostic, text: string): string {
- switch (diag.severity) {
- case DiagnosticSeverity.Error:
- return red(text);
- case DiagnosticSeverity.Warning:
- return yellow(text);
- case DiagnosticSeverity.Hint:
- return gray(text);
- default:
- return text;
- }
-}
-
-function getBackgroundForSeverity(diag: Diagnostic, text: string): string {
- switch (diag.severity) {
- case DiagnosticSeverity.Error:
- return bgRed(white(text));
- case DiagnosticSeverity.Warning:
- return bgYellow(white(text));
- case DiagnosticSeverity.Hint:
- return bgWhite(black(text));
- default:
- return text;
- }
-}
-
-function getPrintableLineNumber(line: number): string {
- return bgWhite(black(line.toString().padStart(2, '0')));
-}
-
-function getLine(line: number, text: string): string {
- return text
- .substring(
- offsetAt({ line, character: 0 }, text),
- offsetAt({ line, character: Number.MAX_SAFE_INTEGER }, text)
- )
- .replace(/\t/g, ' ')
- .trimEnd();
-}
diff --git a/packages/astro/src/cli/dev/index.ts b/packages/astro/src/cli/dev/index.ts
index e55496c4a..5db47fb97 100644
--- a/packages/astro/src/cli/dev/index.ts
+++ b/packages/astro/src/cli/dev/index.ts
@@ -15,7 +15,7 @@ export async function dev({ flags }: DevOptions) {
usage: '[...flags]',
tables: {
Flags: [
- ['--port', `Specify which port to run on. Defaults to 3000.`],
+ ['--port', `Specify which port to run on. Defaults to 4321.`],
['--host', `Listen on all addresses, including LAN and public addresses.`],
['--host <custom-address>', `Expose on a network IP address at <custom-address>`],
['--open', 'Automatically open the app in the browser on server start'],
diff --git a/packages/astro/src/cli/flags.ts b/packages/astro/src/cli/flags.ts
index 703422d50..3d7360a29 100644
--- a/packages/astro/src/cli/flags.ts
+++ b/packages/astro/src/cli/flags.ts
@@ -23,9 +23,6 @@ export function flagsToAstroInlineConfig(flags: Flags): AstroInlineConfig {
typeof flags.host === 'string' || typeof flags.host === 'boolean' ? flags.host : undefined,
open: typeof flags.open === 'boolean' ? flags.open : undefined,
},
- experimental: {
- assets: typeof flags.experimentalAssets === 'boolean' ? flags.experimentalAssets : undefined,
- },
};
}
diff --git a/packages/astro/src/cli/index.ts b/packages/astro/src/cli/index.ts
index d16ea91e2..fdf43201f 100644
--- a/packages/astro/src/cli/index.ts
+++ b/packages/astro/src/cli/index.ts
@@ -154,18 +154,12 @@ async function runCommand(cmd: string, flags: yargs.Arguments) {
}
case 'check': {
const { check } = await import('./check/index.js');
- // We create a server to start doing our operations
- const checkServer = await check({ flags });
- if (checkServer) {
- if (checkServer.isWatchMode) {
- await checkServer.watch();
- return await new Promise(() => {}); // lives forever
- } else {
- const checkResult = await checkServer.check();
- return process.exit(checkResult);
- }
+ const checkServer = await check(flags);
+ if (flags.watch) {
+ return await new Promise(() => {}); // lives forever
+ } else {
+ return process.exit(checkServer ? 1 : 0);
}
- return;
}
case 'sync': {
const { sync } = await import('./sync/index.js');
diff --git a/packages/astro/src/cli/install-package.ts b/packages/astro/src/cli/install-package.ts
new file mode 100644
index 000000000..8793d9985
--- /dev/null
+++ b/packages/astro/src/cli/install-package.ts
@@ -0,0 +1,124 @@
+import boxen from 'boxen';
+import { execa } from 'execa';
+import { bold, cyan, dim, magenta } from 'kleur/colors';
+import { createRequire } from 'node:module';
+import ora from 'ora';
+import prompts from 'prompts';
+import whichPm from 'which-pm';
+import { debug, info, type LogOptions } from '../core/logger/core.js';
+
+type GetPackageOptions = {
+ skipAsk?: boolean;
+ cwd?: string;
+};
+
+export async function getPackage<T>(
+ packageName: string,
+ logging: LogOptions,
+ options: GetPackageOptions,
+ otherDeps: string[] = []
+): Promise<T | undefined> {
+ const require = createRequire(options.cwd ?? process.cwd());
+
+ let packageImport;
+ try {
+ require.resolve(packageName);
+
+ // The `require.resolve` is required as to avoid Node caching the failed `import`
+ packageImport = await import(packageName);
+ } catch (e) {
+ info(
+ logging,
+ '',
+ `To continue, Astro requires the following dependency to be installed: ${bold(packageName)}.`
+ );
+ const result = await installPackage([packageName, ...otherDeps], options, logging);
+
+ if (result) {
+ packageImport = await import(packageName);
+ } else {
+ return undefined;
+ }
+ }
+
+ return packageImport as T;
+}
+
+function getInstallCommand(packages: string[], packageManager: string) {
+ switch (packageManager) {
+ case 'npm':
+ return { pm: 'npm', command: 'install', flags: [], dependencies: packages };
+ case 'yarn':
+ return { pm: 'yarn', command: 'add', flags: [], dependencies: packages };
+ case 'pnpm':
+ return { pm: 'pnpm', command: 'add', flags: [], dependencies: packages };
+ default:
+ return null;
+ }
+}
+
+async function installPackage(
+ packageNames: string[],
+ options: GetPackageOptions,
+ logging: LogOptions
+): Promise<boolean> {
+ const cwd = options.cwd ?? process.cwd();
+ const packageManager = (await whichPm(cwd)).name ?? 'npm';
+ const installCommand = getInstallCommand(packageNames, packageManager);
+
+ if (!installCommand) {
+ return false;
+ }
+
+ const coloredOutput = `${bold(installCommand.pm)} ${installCommand.command}${[
+ '',
+ ...installCommand.flags,
+ ].join(' ')} ${cyan(installCommand.dependencies.join(' '))}`;
+ const message = `\n${boxen(coloredOutput, {
+ margin: 0.5,
+ padding: 0.5,
+ borderStyle: 'round',
+ })}\n`;
+ info(
+ logging,
+ null,
+ `\n ${magenta('Astro will run the following command:')}\n ${dim(
+ 'If you skip this step, you can always run it yourself later'
+ )}\n${message}`
+ );
+
+ let response;
+ if (options.skipAsk) {
+ response = true;
+ } else {
+ response = (
+ await prompts({
+ type: 'confirm',
+ name: 'askToContinue',
+ message: 'Continue?',
+ initial: true,
+ })
+ ).askToContinue;
+ }
+
+ if (Boolean(response)) {
+ const spinner = ora('Installing dependencies...').start();
+ try {
+ await execa(
+ installCommand.pm,
+ [installCommand.command, ...installCommand.flags, ...installCommand.dependencies],
+ { cwd: cwd }
+ );
+ spinner.succeed();
+
+ return true;
+ } catch (err) {
+ debug('add', 'Error installing dependencies', err);
+ spinner.fail();
+
+ return false;
+ }
+ } else {
+ return false;
+ }
+}
diff --git a/packages/astro/src/content/types-generator.ts b/packages/astro/src/content/types-generator.ts
index 238e32c5f..078197cd0 100644
--- a/packages/astro/src/content/types-generator.ts
+++ b/packages/astro/src/content/types-generator.ts
@@ -155,8 +155,7 @@ export async function createContentTypesGenerator({
fileURLToPath(event.entry),
contentPaths,
contentEntryExts,
- dataEntryExts,
- settings.config.experimental.assets
+ dataEntryExts
);
if (fileType === 'ignored') {
return { shouldGenerateTypes: false };
diff --git a/packages/astro/src/content/utils.ts b/packages/astro/src/content/utils.ts
index d273dc105..369e187a8 100644
--- a/packages/astro/src/content/utils.ts
+++ b/packages/astro/src/content/utils.ts
@@ -93,8 +93,7 @@ export async function getEntryData(
_internal: EntryInternal;
},
collectionConfig: CollectionConfig,
- pluginContext: PluginContext,
- config: AstroConfig
+ pluginContext: PluginContext
) {
let data;
if (collectionConfig.type === 'data') {
@@ -106,12 +105,6 @@ export async function getEntryData(
let schema = collectionConfig.schema;
if (typeof schema === 'function') {
- if (!config.experimental.assets) {
- throw new Error(
- 'The function shape for schema can only be used when `experimental.assets` is enabled.'
- );
- }
-
schema = schema({
image: createImage(pluginContext, entry._internal.filePath),
});
@@ -250,9 +243,7 @@ export function getEntryType(
entryPath: string,
paths: Pick<ContentPaths, 'config' | 'contentDir'>,
contentFileExts: string[],
- dataFileExts: string[],
- // TODO: Unflag this when we're ready to release assets - erika, 2023-04-12
- experimentalAssets = false
+ dataFileExts: string[]
): 'content' | 'data' | 'config' | 'ignored' | 'unsupported' {
const { ext, base } = path.parse(entryPath);
const fileUrl = pathToFileURL(entryPath);
@@ -260,7 +251,7 @@ export function getEntryType(
if (
hasUnderscoreBelowContentDirectoryPath(fileUrl, paths.contentDir) ||
isOnIgnoreList(base) ||
- (experimentalAssets && isImageAsset(ext))
+ isImageAsset(ext)
) {
return 'ignored';
} else if (contentFileExts.includes(ext)) {
diff --git a/packages/astro/src/content/vite-plugin-content-imports.ts b/packages/astro/src/content/vite-plugin-content-imports.ts
index a659dd4a0..4643e0922 100644
--- a/packages/astro/src/content/vite-plugin-content-imports.ts
+++ b/packages/astro/src/content/vite-plugin-content-imports.ts
@@ -131,13 +131,7 @@ export const _internal = {
configureServer(viteServer) {
viteServer.watcher.on('all', async (event, entry) => {
if (CHOKIDAR_MODIFIED_EVENTS.includes(event)) {
- const entryType = getEntryType(
- entry,
- contentPaths,
- contentEntryExts,
- dataEntryExts,
- settings.config.experimental.assets
- );
+ const entryType = getEntryType(entry, contentPaths, contentEntryExts, dataEntryExts);
if (!COLLECTION_TYPES_TO_INVALIDATE_ON.includes(entryType)) return;
// The content config could depend on collection entries via `reference()`.
@@ -194,7 +188,7 @@ type GetEntryModuleParams<TEntryType extends ContentEntryType | DataEntryType> =
async function getContentEntryModule(
params: GetEntryModuleParams<ContentEntryType>
): Promise<ContentEntryModule> {
- const { fileId, contentDir, pluginContext, config } = params;
+ const { fileId, contentDir, pluginContext } = params;
const { collectionConfig, entryConfig, entry, rawContents, collection } =
await getEntryModuleBaseInfo(params);
@@ -221,8 +215,7 @@ async function getContentEntryModule(
? await getEntryData(
{ id, collection, _internal, unvalidatedData },
collectionConfig,
- pluginContext,
- config
+ pluginContext
)
: unvalidatedData;
@@ -241,7 +234,7 @@ async function getContentEntryModule(
async function getDataEntryModule(
params: GetEntryModuleParams<DataEntryType>
): Promise<DataEntryModule> {
- const { fileId, contentDir, pluginContext, config } = params;
+ const { fileId, contentDir, pluginContext } = params;
const { collectionConfig, entryConfig, entry, rawContents, collection } =
await getEntryModuleBaseInfo(params);
@@ -256,8 +249,7 @@ async function getDataEntryModule(
? await getEntryData(
{ id, collection, _internal, unvalidatedData },
collectionConfig,
- pluginContext,
- config
+ pluginContext
)
: unvalidatedData;
diff --git a/packages/astro/src/core/README.md b/packages/astro/src/core/README.md
index 7f5e4f89c..74f55a0bb 100644
--- a/packages/astro/src/core/README.md
+++ b/packages/astro/src/core/README.md
@@ -3,3 +3,16 @@
Code that executes within the top-level Node context. Contains the main Astro logic for the `build` and `dev` commands, and also manages the Vite server and SSR.
[See CONTRIBUTING.md](../../../../CONTRIBUTING.md) for a code overview.
+
+## Pipeline
+
+The pipeline is an internal concept that describes how Astro pages are eventually created and rendered to the user.
+
+Each pipeline has different requirements, criteria and quirks. Although, each pipeline must use the same underline functions, because
+the core of the pipeline is the same.
+
+The core of the pipeline is rendering a generic route (page, endpoint or redirect) and returning a `Response`.
+When rendering a route, a pipeline must pass a `RenderContext` and `ComponentInstance`. The way these two information are
+computed doesn't concern the core of a pipeline. In fact, these types will be computed in different manner based on the type of pipeline.
+
+Each consumer will decide how to handle a `Response`.
diff --git a/packages/astro/src/core/app/index.ts b/packages/astro/src/core/app/index.ts
index 76958a549..92f671b85 100644
--- a/packages/astro/src/core/app/index.ts
+++ b/packages/astro/src/core/app/index.ts
@@ -1,13 +1,13 @@
-import mime from 'mime';
import type {
EndpointHandler,
ManifestData,
+ MiddlewareEndpointHandler,
RouteData,
SSRElement,
SSRManifest,
} from '../../@types/astro';
import type { SinglePageBuiltModule } from '../build/types';
-import { attachToResponse, getSetCookiesFromResponse } from '../cookies/index.js';
+import { getSetCookiesFromResponse } from '../cookies/index.js';
import { consoleLogDestination } from '../logger/console.js';
import { error, type LogOptions } from '../logger/core.js';
import {
@@ -16,12 +16,10 @@ import {
removeTrailingForwardSlash,
} from '../path.js';
import { RedirectSinglePageBuiltModule } from '../redirects/index.js';
-import { isResponse } from '../render/core.js';
import {
createEnvironment,
createRenderContext,
tryRenderRoute,
- type Environment,
type RenderContext,
} from '../render/index.js';
import { RouteCache } from '../render/route-cache.js';
@@ -32,6 +30,7 @@ import {
} from '../render/ssr-element.js';
import { matchRoute } from '../routing/match.js';
import type { RouteInfo } from './types';
+import { EndpointNotFoundError, SSRRoutePipeline } from './ssrPipeline.js';
export { deserializeManifest } from './common.js';
const clientLocalsSymbol = Symbol.for('astro.locals');
@@ -53,16 +52,15 @@ export class App {
/**
* The current environment of the application
*/
- #env: Environment;
#manifest: SSRManifest;
#manifestData: ManifestData;
#routeDataToRouteInfo: Map<RouteData, RouteInfo>;
- #encoder = new TextEncoder();
#logging: LogOptions = {
dest: consoleLogDestination,
level: 'info',
};
#baseWithoutTrailingSlash: string;
+ #pipeline: SSRRoutePipeline;
constructor(manifest: SSRManifest, streaming = true) {
this.#manifest = manifest;
@@ -71,7 +69,7 @@ export class App {
};
this.#routeDataToRouteInfo = new Map(manifest.routes.map((route) => [route.routeData, route]));
this.#baseWithoutTrailingSlash = removeTrailingForwardSlash(this.#manifest.base);
- this.#env = this.#createEnvironment(streaming);
+ this.#pipeline = new SSRRoutePipeline(this.#createEnvironment(streaming));
}
set setManifest(newManifest: SSRManifest) {
@@ -88,7 +86,6 @@ export class App {
return createEnvironment({
adapterName: this.#manifest.adapterName,
logging: this.#logging,
- markdown: this.#manifest.markdown,
mode: 'production',
compressHTML: this.#manifest.compressHTML,
renderers: this.#manifest.renderers,
@@ -164,19 +161,21 @@ export class App {
);
let response;
try {
- response = await tryRenderRoute(
- routeData.type,
- renderContext,
- this.#env,
- pageModule,
- mod.onRequest
- );
+ // NOTE: ideally we could set the middleware function just once, but we don't have the infrastructure to that yet
+ if (mod.onRequest) {
+ this.#pipeline.setMiddlewareFunction(mod.onRequest as MiddlewareEndpointHandler);
+ }
+ response = await this.#pipeline.renderRoute(renderContext, pageModule);
} catch (err: any) {
- error(this.#logging, 'ssr', err.stack || err.message || String(err));
- return this.#renderError(request, { status: 500 });
+ if (err instanceof EndpointNotFoundError) {
+ return this.#renderError(request, { status: 404, response: err.originalResponse });
+ } else {
+ error(this.#logging, 'ssr', err.stack || err.message || String(err));
+ return this.#renderError(request, { status: 500 });
+ }
}
- if (isResponse(response, routeData.type)) {
+ if (SSRRoutePipeline.isResponse(response, routeData.type)) {
if (STATUS_CODES.has(response.status)) {
return this.#renderError(request, {
response,
@@ -185,35 +184,8 @@ export class App {
}
Reflect.set(response, responseSentSymbol, true);
return response;
- } else {
- if (response.type === 'response') {
- if (response.response.headers.get('X-Astro-Response') === 'Not-Found') {
- return this.#renderError(request, {
- response: response.response,
- status: 404,
- });
- }
- return response.response;
- } else {
- const headers = new Headers();
- const mimeType = mime.getType(url.pathname);
- if (mimeType) {
- headers.set('Content-Type', `${mimeType};charset=utf-8`);
- } else {
- headers.set('Content-Type', 'text/plain;charset=utf-8');
- }
- const bytes =
- response.encoding !== 'binary' ? this.#encoder.encode(response.body) : response.body;
- headers.set('Content-Length', bytes.byteLength.toString());
-
- const newResponse = new Response(bytes, {
- status: 200,
- headers,
- });
- attachToResponse(newResponse, response.cookies);
- return newResponse;
- }
}
+ return response;
}
setCookieHeaders(response: Response) {
@@ -239,7 +211,7 @@ export class App {
pathname,
route: routeData,
status,
- env: this.#env,
+ env: this.#pipeline.env,
mod: handler as any,
});
} else {
@@ -273,7 +245,7 @@ export class App {
route: routeData,
status,
mod,
- env: this.#env,
+ env: this.#pipeline.env,
});
}
}
@@ -311,9 +283,8 @@ export class App {
);
const page = (await mod.page()) as any;
const response = (await tryRenderRoute(
- 'page', // this is hardcoded to ensure proper behavior for missing endpoints
newRenderContext,
- this.#env,
+ this.#pipeline.env,
page
)) as Response;
return this.#mergeResponses(response, originalResponse);
diff --git a/packages/astro/src/core/app/node.ts b/packages/astro/src/core/app/node.ts
index 4ae6e98a9..054064a08 100644
--- a/packages/astro/src/core/app/node.ts
+++ b/packages/astro/src/core/app/node.ts
@@ -6,6 +6,7 @@ import { IncomingMessage } from 'node:http';
import { TLSSocket } from 'node:tls';
import { deserializeManifest } from './common.js';
import { App, type MatchOptions } from './index.js';
+export { apply as applyPolyfills } from '../polyfill.js';
const clientAddressSymbol = Symbol.for('astro.clientAddress');
diff --git a/packages/astro/src/core/app/ssrPipeline.ts b/packages/astro/src/core/app/ssrPipeline.ts
new file mode 100644
index 000000000..5f135e42d
--- /dev/null
+++ b/packages/astro/src/core/app/ssrPipeline.ts
@@ -0,0 +1,54 @@
+import type { Environment } from '../render';
+import type { EndpointCallResult } from '../endpoint/index.js';
+import mime from 'mime';
+import { attachCookiesToResponse } from '../cookies/index.js';
+import { Pipeline } from '../pipeline.js';
+
+/**
+ * Thrown when an endpoint contains a response with the header "X-Astro-Response" === 'Not-Found'
+ */
+export class EndpointNotFoundError extends Error {
+ originalResponse: Response;
+ constructor(originalResponse: Response) {
+ super();
+ this.originalResponse = originalResponse;
+ }
+}
+
+export class SSRRoutePipeline extends Pipeline {
+ #encoder = new TextEncoder();
+
+ constructor(env: Environment) {
+ super(env);
+ this.setEndpointHandler(this.#ssrEndpointHandler);
+ }
+
+ // This function is responsible for handling the result coming from an endpoint.
+ async #ssrEndpointHandler(request: Request, response: EndpointCallResult): Promise<Response> {
+ if (response.type === 'response') {
+ if (response.response.headers.get('X-Astro-Response') === 'Not-Found') {
+ throw new EndpointNotFoundError(response.response);
+ }
+ return response.response;
+ } else {
+ const url = new URL(request.url);
+ const headers = new Headers();
+ const mimeType = mime.getType(url.pathname);
+ if (mimeType) {
+ headers.set('Content-Type', `${mimeType};charset=utf-8`);
+ } else {
+ headers.set('Content-Type', 'text/plain;charset=utf-8');
+ }
+ const bytes =
+ response.encoding !== 'binary' ? this.#encoder.encode(response.body) : response.body;
+ headers.set('Content-Length', bytes.byteLength.toString());
+
+ const newResponse = new Response(bytes, {
+ status: 200,
+ headers,
+ });
+ attachCookiesToResponse(newResponse, response.cookies);
+ return newResponse;
+ }
+ }
+}
diff --git a/packages/astro/src/core/app/types.ts b/packages/astro/src/core/app/types.ts
index 67d16d457..8812d2c44 100644
--- a/packages/astro/src/core/app/types.ts
+++ b/packages/astro/src/core/app/types.ts
@@ -1,4 +1,3 @@
-import type { MarkdownRenderingOptions } from '@astrojs/markdown-remark';
import type {
RouteData,
SerializedRouteData,
@@ -40,7 +39,6 @@ export type SSRManifest = {
base: string;
compressHTML: boolean;
assetsPrefix?: string;
- markdown: MarkdownRenderingOptions;
renderers: SSRLoadedRenderer[];
/**
* Map of directive name (e.g. `load`) to the directive script code
diff --git a/packages/astro/src/core/build/buildPipeline.ts b/packages/astro/src/core/build/buildPipeline.ts
new file mode 100644
index 000000000..4ebf48a9a
--- /dev/null
+++ b/packages/astro/src/core/build/buildPipeline.ts
@@ -0,0 +1,211 @@
+import { Pipeline } from '../pipeline.js';
+import type { BuildInternals } from './internal';
+import type { PageBuildData, StaticBuildOptions } from './types';
+import { ASTRO_PAGE_RESOLVED_MODULE_ID } from './plugins/plugin-pages.js';
+import { RESOLVED_SPLIT_MODULE_ID } from './plugins/plugin-ssr.js';
+import { ASTRO_PAGE_EXTENSION_POST_PATTERN } from './plugins/util.js';
+import type { SSRManifest } from '../app/types';
+import type { AstroConfig, AstroSettings, RouteType, SSRLoadedRenderer } from '../../@types/astro';
+import { getOutputDirectory, isServerLikeOutput } from '../../prerender/utils.js';
+import type { EndpointCallResult } from '../endpoint';
+import { createEnvironment } from '../render/index.js';
+import { BEFORE_HYDRATION_SCRIPT_ID } from '../../vite-plugin-scripts/index.js';
+import { createAssetLink } from '../render/ssr-element.js';
+import type { BufferEncoding } from 'vfile';
+
+/**
+ * This pipeline is responsible to gather the files emitted by the SSR build and generate the pages by executing these files.
+ */
+export class BuildPipeline extends Pipeline {
+ #internals: BuildInternals;
+ #staticBuildOptions: StaticBuildOptions;
+ #manifest: SSRManifest;
+ #currentEndpointBody?: {
+ body: string | Uint8Array;
+ encoding: BufferEncoding;
+ };
+
+ constructor(
+ staticBuildOptions: StaticBuildOptions,
+ internals: BuildInternals,
+ manifest: SSRManifest
+ ) {
+ const ssr = isServerLikeOutput(staticBuildOptions.settings.config);
+ super(
+ createEnvironment({
+ adapterName: manifest.adapterName,
+ logging: staticBuildOptions.logging,
+ mode: staticBuildOptions.mode,
+ renderers: manifest.renderers,
+ clientDirectives: manifest.clientDirectives,
+ compressHTML: manifest.compressHTML,
+ async resolve(specifier: string) {
+ const hashedFilePath = manifest.entryModules[specifier];
+ if (typeof hashedFilePath !== 'string') {
+ // If no "astro:scripts/before-hydration.js" script exists in the build,
+ // then we can assume that no before-hydration scripts are needed.
+ if (specifier === BEFORE_HYDRATION_SCRIPT_ID) {
+ return '';
+ }
+ throw new Error(`Cannot find the built path for ${specifier}`);
+ }
+ return createAssetLink(hashedFilePath, manifest.base, manifest.assetsPrefix);
+ },
+ routeCache: staticBuildOptions.routeCache,
+ site: manifest.site,
+ ssr,
+ streaming: true,
+ })
+ );
+ this.#internals = internals;
+ this.#staticBuildOptions = staticBuildOptions;
+ this.#manifest = manifest;
+ this.setEndpointHandler(this.#handleEndpointResult);
+ }
+
+ getInternals(): Readonly<BuildInternals> {
+ return this.#internals;
+ }
+
+ getSettings(): Readonly<AstroSettings> {
+ return this.#staticBuildOptions.settings;
+ }
+
+ getStaticBuildOptions(): Readonly<StaticBuildOptions> {
+ return this.#staticBuildOptions;
+ }
+
+ getConfig(): AstroConfig {
+ return this.#staticBuildOptions.settings.config;
+ }
+
+ getManifest(): SSRManifest {
+ return this.#manifest;
+ }
+
+ /**
+ * The SSR build emits two important files:
+ * - dist/server/manifest.mjs
+ * - dist/renderers.mjs
+ *
+ * These two files, put together, will be used to generate the pages.
+ *
+ * ## Errors
+ *
+ * It will throw errors if the previous files can't be found in the file system.
+ *
+ * @param staticBuildOptions
+ */
+ static async retrieveManifest(
+ staticBuildOptions: StaticBuildOptions,
+ internals: BuildInternals
+ ): Promise<SSRManifest> {
+ const config = staticBuildOptions.settings.config;
+ const baseDirectory = getOutputDirectory(config);
+ const manifestEntryUrl = new URL(
+ `${internals.manifestFileName}?time=${Date.now()}`,
+ baseDirectory
+ );
+ const { manifest } = await import(manifestEntryUrl.toString());
+ if (!manifest) {
+ throw new Error(
+ "Astro couldn't find the emitted manifest. This is an internal error, please file an issue."
+ );
+ }
+
+ const renderersEntryUrl = new URL(`renderers.mjs?time=${Date.now()}`, baseDirectory);
+ const renderers = await import(renderersEntryUrl.toString());
+ if (!renderers) {
+ throw new Error(
+ "Astro couldn't find the emitted renderers. This is an internal error, please file an issue."
+ );
+ }
+ return {
+ ...manifest,
+ renderers: renderers.renderers as SSRLoadedRenderer[],
+ };
+ }
+
+ /**
+ * It collects the routes to generate during the build.
+ *
+ * It returns a map of page information and their relative entry point as a string.
+ */
+ retrieveRoutesToGenerate(): Map<PageBuildData, string> {
+ const pages = new Map<PageBuildData, string>();
+
+ for (const [entryPoint, filePath] of this.#internals.entrySpecifierToBundleMap) {
+ // virtual pages can be emitted with different prefixes:
+ // - the classic way are pages emitted with prefix ASTRO_PAGE_RESOLVED_MODULE_ID -> plugin-pages
+ // - pages emitted using `build.split`, in this case pages are emitted with prefix RESOLVED_SPLIT_MODULE_ID
+ if (
+ entryPoint.includes(ASTRO_PAGE_RESOLVED_MODULE_ID) ||
+ entryPoint.includes(RESOLVED_SPLIT_MODULE_ID)
+ ) {
+ const [, pageName] = entryPoint.split(':');
+ const pageData = this.#internals.pagesByComponent.get(
+ `${pageName.replace(ASTRO_PAGE_EXTENSION_POST_PATTERN, '.')}`
+ );
+ if (!pageData) {
+ throw new Error(
+ "Build failed. Astro couldn't find the emitted page from " + pageName + ' pattern'
+ );
+ }
+
+ pages.set(pageData, filePath);
+ }
+ }
+ for (const [path, pageData] of this.#internals.pagesByComponent.entries()) {
+ if (pageData.route.type === 'redirect') {
+ pages.set(pageData, path);
+ }
+ }
+ return pages;
+ }
+
+ async #handleEndpointResult(request: Request, response: EndpointCallResult): Promise<Response> {
+ if (response.type === 'response') {
+ if (!response.response.body) {
+ return new Response(null);
+ }
+ const ab = await response.response.arrayBuffer();
+ const body = new Uint8Array(ab);
+ this.#currentEndpointBody = {
+ body: body,
+ encoding: 'utf-8',
+ };
+ return response.response;
+ } else {
+ if (response.encoding) {
+ this.#currentEndpointBody = {
+ body: response.body,
+ encoding: response.encoding,
+ };
+ const headers = new Headers();
+ headers.set('X-Astro-Encoding', response.encoding);
+ return new Response(response.body, {
+ headers,
+ });
+ } else {
+ return new Response(response.body);
+ }
+ }
+ }
+
+ async computeBodyAndEncoding(
+ routeType: RouteType,
+ response: Response
+ ): Promise<{
+ body: string | Uint8Array;
+ encoding: BufferEncoding;
+ }> {
+ const encoding = response.headers.get('X-Astro-Encoding') ?? 'utf-8';
+ if (this.#currentEndpointBody) {
+ const currentEndpointBody = this.#currentEndpointBody;
+ this.#currentEndpointBody = undefined;
+ return currentEndpointBody;
+ } else {
+ return { body: await response.text(), encoding: encoding as BufferEncoding };
+ }
+ }
+}
diff --git a/packages/astro/src/core/build/generate.ts b/packages/astro/src/core/build/generate.ts
index a78a46883..4e89dfb61 100644
--- a/packages/astro/src/core/build/generate.ts
+++ b/packages/astro/src/core/build/generate.ts
@@ -9,7 +9,7 @@ import type {
ComponentInstance,
GetStaticPathsItem,
ImageTransform,
- MiddlewareHandler,
+ MiddlewareEndpointHandler,
RouteData,
RouteType,
SSRError,
@@ -20,26 +20,21 @@ import {
generateImage as generateImageInternal,
getStaticImageList,
} from '../../assets/build/generate.js';
-import {
- eachPageDataFromEntryPoint,
- eachRedirectPageData,
- hasPrerenderedPages,
- type BuildInternals,
-} from '../../core/build/internal.js';
+import { hasPrerenderedPages, type BuildInternals } from '../../core/build/internal.js';
import {
isRelativePath,
+ joinPaths,
prependForwardSlash,
removeLeadingForwardSlash,
removeTrailingForwardSlash,
} from '../../core/path.js';
import { runHookBuildGenerated } from '../../integrations/index.js';
-import { isServerLikeOutput } from '../../prerender/utils.js';
-import { BEFORE_HYDRATION_SCRIPT_ID, PAGE_SCRIPT_ID } from '../../vite-plugin-scripts/index.js';
+import { getOutputDirectory, isServerLikeOutput } from '../../prerender/utils.js';
+import { PAGE_SCRIPT_ID } from '../../vite-plugin-scripts/index.js';
import { AstroError, AstroErrorData } from '../errors/index.js';
-import { debug, info } from '../logger/core.js';
+import { debug, info, Logger } from '../logger/core.js';
import { RedirectSinglePageBuiltModule, getRedirectLocationOrThrow } from '../redirects/index.js';
-import { isEndpointResult } from '../render/core.js';
-import { createEnvironment, createRenderContext, tryRenderRoute } from '../render/index.js';
+import { createRenderContext } from '../render/index.js';
import { callGetStaticPaths } from '../render/route-cache.js';
import {
createAssetLink,
@@ -63,6 +58,8 @@ import type {
StylesheetAsset,
} from './types';
import { getTimeStat } from './util.js';
+import { BuildPipeline } from './buildPipeline.js';
+import type { BufferEncoding } from 'vfile';
function createEntryURL(filePath: string, outFolder: URL) {
return new URL('./' + filePath + `?time=${Date.now()}`, outFolder);
@@ -124,8 +121,23 @@ export function chunkIsPage(
}
export async function generatePages(opts: StaticBuildOptions, internals: BuildInternals) {
+ const logger = new Logger(opts.logging);
const timer = performance.now();
const ssr = isServerLikeOutput(opts.settings.config);
+ let manifest: SSRManifest;
+ if (ssr) {
+ manifest = await BuildPipeline.retrieveManifest(opts, internals);
+ } else {
+ const baseDirectory = getOutputDirectory(opts.settings.config);
+ const renderersEntryUrl = new URL('renderers.mjs', baseDirectory);
+ const renderers = await import(renderersEntryUrl.toString());
+ manifest = createBuildManifest(
+ opts.settings,
+ internals,
+ renderers.renderers as SSRLoadedRenderer[]
+ );
+ }
+ const buildPipeline = new BuildPipeline(opts, internals, manifest);
const outFolder = ssr
? opts.settings.config.build.server
: getOutDirWithinCwd(opts.settings.config.outDir);
@@ -139,20 +151,18 @@ export async function generatePages(opts: StaticBuildOptions, internals: BuildIn
const verb = ssr ? 'prerendering' : 'generating';
info(opts.logging, null, `\n${bgGreen(black(` ${verb} static routes `))}`);
-
const builtPaths = new Set<string>();
-
+ const pagesToGenerate = buildPipeline.retrieveRoutesToGenerate();
if (ssr) {
- for (const [pageData, filePath] of eachPageDataFromEntryPoint(internals)) {
+ for (const [pageData, filePath] of pagesToGenerate) {
if (pageData.route.prerender) {
const ssrEntryURLPage = createEntryURL(filePath, outFolder);
const ssrEntryPage = await import(ssrEntryURLPage.toString());
if (opts.settings.config.build.split) {
// forcing to use undefined, so we fail in an expected way if the module is not even there.
- const manifest: SSRManifest | undefined = ssrEntryPage.manifest;
- const ssrEntry = manifest?.pageModule;
+ const ssrEntry = ssrEntryPage?.manifest?.pageModule;
if (ssrEntry) {
- await generatePage(opts, internals, pageData, ssrEntry, builtPaths, manifest);
+ await generatePage(pageData, ssrEntry, builtPaths, buildPipeline, logger);
} else {
throw new Error(
`Unable to find the manifest for the module ${ssrEntryURLPage.toString()}. This is unexpected and likely a bug in Astro, please report.`
@@ -160,40 +170,35 @@ export async function generatePages(opts: StaticBuildOptions, internals: BuildIn
}
} else {
const ssrEntry = ssrEntryPage as SinglePageBuiltModule;
- const manifest = createBuildManifest(opts.settings, internals, ssrEntry.renderers);
- await generatePage(opts, internals, pageData, ssrEntry, builtPaths, manifest);
+ await generatePage(pageData, ssrEntry, builtPaths, buildPipeline, logger);
}
}
- }
- for (const pageData of eachRedirectPageData(internals)) {
- const entry = await getEntryForRedirectRoute(pageData.route, internals, outFolder);
- const manifest = createBuildManifest(opts.settings, internals, entry.renderers);
- await generatePage(opts, internals, pageData, entry, builtPaths, manifest);
+ if (pageData.route.type === 'redirect') {
+ const entry = await getEntryForRedirectRoute(pageData.route, internals, outFolder);
+ await generatePage(pageData, entry, builtPaths, buildPipeline, logger);
+ }
}
} else {
- for (const [pageData, filePath] of eachPageDataFromEntryPoint(internals)) {
- const ssrEntryURLPage = createEntryURL(filePath, outFolder);
- const entry: SinglePageBuiltModule = await import(ssrEntryURLPage.toString());
- const manifest = createBuildManifest(opts.settings, internals, entry.renderers);
+ for (const [pageData, filePath] of pagesToGenerate) {
+ if (pageData.route.type === 'redirect') {
+ const entry = await getEntryForRedirectRoute(pageData.route, internals, outFolder);
+ await generatePage(pageData, entry, builtPaths, buildPipeline, logger);
+ } else {
+ const ssrEntryURLPage = createEntryURL(filePath, outFolder);
+ const entry: SinglePageBuiltModule = await import(ssrEntryURLPage.toString());
- await generatePage(opts, internals, pageData, entry, builtPaths, manifest);
- }
- for (const pageData of eachRedirectPageData(internals)) {
- const entry = await getEntryForRedirectRoute(pageData.route, internals, outFolder);
- const manifest = createBuildManifest(opts.settings, internals, entry.renderers);
- await generatePage(opts, internals, pageData, entry, builtPaths, manifest);
+ await generatePage(pageData, entry, builtPaths, buildPipeline, logger);
+ }
}
}
- if (opts.settings.config.experimental.assets) {
- info(opts.logging, null, `\n${bgGreen(black(` generating optimized images `))}`);
- for (const imageData of getStaticImageList()) {
- await generateImage(opts, imageData[1].options, imageData[1].path);
- }
-
- delete globalThis?.astroAsset?.addStaticImage;
+ info(opts.logging, null, `\n${bgGreen(black(` generating optimized images `))}`);
+ for (const imageData of getStaticImageList()) {
+ await generateImage(opts, imageData[1].options, imageData[1].path);
}
+ delete globalThis?.astroAsset?.addStaticImage;
+
await runHookBuildGenerated({
config: opts.settings.config,
logging: opts.logging,
@@ -220,16 +225,15 @@ async function generateImage(opts: StaticBuildOptions, transform: ImageTransform
}
async function generatePage(
- opts: StaticBuildOptions,
- internals: BuildInternals,
pageData: PageBuildData,
ssrEntry: SinglePageBuiltModule,
builtPaths: Set<string>,
- manifest: SSRManifest
+ pipeline: BuildPipeline,
+ logger: Logger
) {
let timeStart = performance.now();
- const pageInfo = getPageDataByComponent(internals, pageData.route.component);
+ const pageInfo = getPageDataByComponent(pipeline.getInternals(), pageData.route.component);
// may be used in the future for handling rel=modulepreload, rel=icon, rel=manifest etc.
const linkIds: [] = [];
@@ -241,6 +245,9 @@ async function generatePage(
const pageModulePromise = ssrEntry.page;
const onRequest = ssrEntry.onRequest;
+ if (onRequest) {
+ pipeline.setMiddlewareFunction(onRequest as MiddlewareEndpointHandler);
+ }
if (!pageModulePromise) {
throw new Error(
@@ -248,14 +255,13 @@ async function generatePage(
);
}
const pageModule = await pageModulePromise();
- if (shouldSkipDraft(pageModule, opts.settings)) {
- info(opts.logging, null, `${magenta('⚠️')} Skipping draft ${pageData.route.component}`);
+ if (shouldSkipDraft(pageModule, pipeline.getSettings())) {
+ logger.info(null, `${magenta('⚠️')} Skipping draft ${pageData.route.component}`);
return;
}
const generationOptions: Readonly<GeneratePathOptions> = {
pageData,
- internals,
linkIds,
scripts,
styles,
@@ -264,23 +270,28 @@ async function generatePage(
const icon = pageData.route.type === 'page' ? green('▶') : magenta('λ');
if (isRelativePath(pageData.route.component)) {
- info(opts.logging, null, `${icon} ${pageData.route.route}`);
+ logger.info(null, `${icon} ${pageData.route.route}`);
} else {
- info(opts.logging, null, `${icon} ${pageData.route.component}`);
+ logger.info(null, `${icon} ${pageData.route.component}`);
}
// Get paths for the route, calling getStaticPaths if needed.
- const paths = await getPathsForRoute(pageData, pageModule, opts, builtPaths);
+ const paths = await getPathsForRoute(
+ pageData,
+ pageModule,
+ pipeline.getStaticBuildOptions(),
+ builtPaths
+ );
for (let i = 0; i < paths.length; i++) {
const path = paths[i];
- await generatePath(path, opts, generationOptions, manifest, onRequest);
+ await generatePath(path, generationOptions, pipeline);
const timeEnd = performance.now();
const timeChange = getTimeStat(timeStart, timeEnd);
const timeIncrease = `(+${timeChange})`;
- const filePath = getOutputFilename(opts.settings.config, path, pageData.route.type);
+ const filePath = getOutputFilename(pipeline.getConfig(), path, pageData.route.type);
const lineIcon = i === paths.length - 1 ? '└─' : '├─';
- info(opts.logging, null, ` ${cyan(lineIcon)} ${dim(filePath)} ${dim(timeIncrease)}`);
+ logger.info(null, ` ${cyan(lineIcon)} ${dim(filePath)} ${dim(timeIncrease)}`);
}
}
@@ -300,7 +311,6 @@ async function getPathsForRoute(
mod,
route,
routeCache: opts.routeCache,
- isValidate: false,
logging: opts.logging,
ssr: isServerLikeOutput(opts.settings.config),
}).catch((err) => {
@@ -384,7 +394,6 @@ function getInvalidRouteSegmentError(
interface GeneratePathOptions {
pageData: PageBuildData;
- internals: BuildInternals;
linkIds: string[];
scripts: { type: 'inline' | 'external'; value: string } | null;
styles: StylesheetAsset[];
@@ -438,29 +447,23 @@ function getUrlForPath(
buildPathname = base;
} else if (routeType === 'endpoint') {
const buildPathRelative = removeLeadingForwardSlash(pathname);
- buildPathname = base + buildPathRelative;
+ buildPathname = joinPaths(base, buildPathRelative);
} else {
const buildPathRelative =
removeTrailingForwardSlash(removeLeadingForwardSlash(pathname)) + ending;
- buildPathname = base + buildPathRelative;
+ buildPathname = joinPaths(base, buildPathRelative);
}
const url = new URL(buildPathname, origin);
return url;
}
-async function generatePath(
- pathname: string,
- opts: StaticBuildOptions,
- gopts: GeneratePathOptions,
- manifest: SSRManifest,
- onRequest?: MiddlewareHandler<unknown>
-) {
- const { settings, logging, origin, routeCache } = opts;
- const { mod, internals, scripts: hoistedScripts, styles: _styles, pageData } = gopts;
+async function generatePath(pathname: string, gopts: GeneratePathOptions, pipeline: BuildPipeline) {
+ const manifest = pipeline.getManifest();
+ const { mod, scripts: hoistedScripts, styles: _styles, pageData } = gopts;
// This adds the page name to the array so it can be shown as part of stats.
if (pageData.route.type === 'page') {
- addPageName(pathname, opts);
+ addPageName(pathname, pipeline.getStaticBuildOptions());
}
debug('build', `Generating: ${pathname}`);
@@ -474,8 +477,8 @@ async function generatePath(
);
const styles = createStylesheetElementSet(_styles, manifest.base, manifest.assetsPrefix);
- if (settings.scripts.some((script) => script.stage === 'page')) {
- const hashedFilePath = internals.entrySpecifierToBundleMap.get(PAGE_SCRIPT_ID);
+ if (pipeline.getSettings().scripts.some((script) => script.stage === 'page')) {
+ const hashedFilePath = pipeline.getInternals().entrySpecifierToBundleMap.get(PAGE_SCRIPT_ID);
if (typeof hashedFilePath !== 'string') {
throw new Error(`Cannot find the built path for ${PAGE_SCRIPT_ID}`);
}
@@ -487,7 +490,7 @@ async function generatePath(
}
// Add all injected scripts to the page.
- for (const script of settings.scripts) {
+ for (const script of pipeline.getSettings().scripts) {
if (script.stage === 'head-inline') {
scripts.add({
props: {},
@@ -496,59 +499,38 @@ async function generatePath(
}
}
- const ssr = isServerLikeOutput(settings.config);
+ const ssr = isServerLikeOutput(pipeline.getConfig());
const url = getUrlForPath(
pathname,
- opts.settings.config.base,
- origin,
- opts.settings.config.build.format,
+ pipeline.getConfig().base,
+ pipeline.getStaticBuildOptions().origin,
+ pipeline.getConfig().build.format,
pageData.route.type
);
- const env = createEnvironment({
- adapterName: manifest.adapterName,
- logging,
- markdown: manifest.markdown,
- mode: opts.mode,
- renderers: manifest.renderers,
- clientDirectives: manifest.clientDirectives,
- compressHTML: manifest.compressHTML,
- async resolve(specifier: string) {
- const hashedFilePath = manifest.entryModules[specifier];
- if (typeof hashedFilePath !== 'string') {
- // If no "astro:scripts/before-hydration.js" script exists in the build,
- // then we can assume that no before-hydration scripts are needed.
- if (specifier === BEFORE_HYDRATION_SCRIPT_ID) {
- return '';
- }
- throw new Error(`Cannot find the built path for ${specifier}`);
- }
- return createAssetLink(hashedFilePath, manifest.base, manifest.assetsPrefix);
- },
- routeCache,
- site: manifest.site,
- ssr,
- streaming: true,
- });
-
const renderContext = await createRenderContext({
pathname,
- request: createRequest({ url, headers: new Headers(), logging, ssr }),
+ request: createRequest({
+ url,
+ headers: new Headers(),
+ logging: pipeline.getStaticBuildOptions().logging,
+ ssr,
+ }),
componentMetadata: manifest.componentMetadata,
scripts,
styles,
links,
route: pageData.route,
- env,
+ env: pipeline.getEnvironment(),
mod,
});
let body: string | Uint8Array;
let encoding: BufferEncoding | undefined;
- let response;
+ let response: Response;
try {
- response = await tryRenderRoute(pageData.route.type, renderContext, env, mod, onRequest);
+ response = await pipeline.renderRoute(renderContext, mod);
} catch (err) {
if (!AstroError.is(err) && !(err as SSRError).id && typeof err === 'object') {
(err as SSRError).id = pageData.component;
@@ -556,28 +538,17 @@ async function generatePath(
throw err;
}
- if (isEndpointResult(response, pageData.route.type)) {
- if (response.type === 'response') {
- // If there's no body, do nothing
- if (!response.response.body) return;
- const ab = await response.response.arrayBuffer();
- body = new Uint8Array(ab);
- } else {
- body = response.body;
- encoding = response.encoding;
+ if (response.status >= 300 && response.status < 400) {
+ // If redirects is set to false, don't output the HTML
+ if (!pipeline.getConfig().build.redirects) {
+ return;
}
- } else {
- if (response.status >= 300 && response.status < 400) {
- // If redirects is set to false, don't output the HTML
- if (!opts.settings.config.build.redirects) {
- return;
- }
- const location = getRedirectLocationOrThrow(response.headers);
- const fromPath = new URL(renderContext.request.url).pathname;
- // A short delay causes Google to interpret the redirect as temporary.
- // https://developers.google.com/search/docs/crawling-indexing/301-redirects#metarefresh
- const delay = response.status === 302 ? 2 : 0;
- body = `<!doctype html>
+ const location = getRedirectLocationOrThrow(response.headers);
+ const fromPath = new URL(renderContext.request.url).pathname;
+ // A short delay causes Google to interpret the redirect as temporary.
+ // https://developers.google.com/search/docs/crawling-indexing/301-redirects#metarefresh
+ const delay = response.status === 302 ? 2 : 0;
+ body = `<!doctype html>
<title>Redirecting to: ${location}</title>
<meta http-equiv="refresh" content="${delay};url=${location}">
<meta name="robots" content="noindex">
@@ -585,20 +556,25 @@ async function generatePath(
<body>
<a href="${location}">Redirecting from <code>${fromPath}</code> to <code>${location}</code></a>
</body>`;
- // A dynamic redirect, set the location so that integrations know about it.
- if (pageData.route.type !== 'redirect') {
- pageData.route.redirect = location;
- }
- } else {
- // If there's no body, do nothing
- if (!response.body) return;
- body = await response.text();
+ // A dynamic redirect, set the location so that integrations know about it.
+ if (pageData.route.type !== 'redirect') {
+ pageData.route.redirect = location;
}
+ } else {
+ // If there's no body, do nothing
+ if (!response.body) return;
+ const result = await pipeline.computeBodyAndEncoding(renderContext.route.type, response);
+ body = result.body;
+ encoding = result.encoding;
}
- const outFolder = getOutFolder(settings.config, pathname, pageData.route.type);
- const outFile = getOutFile(settings.config, outFolder, pathname, pageData.route.type);
+ const outFolder = getOutFolder(pipeline.getConfig(), pathname, pageData.route.type);
+ const outFile = getOutFile(pipeline.getConfig(), outFolder, pathname, pageData.route.type);
pageData.route.distURL = outFile;
+ const possibleEncoding = response.headers.get('X-Astro-Encoding');
+ if (possibleEncoding) {
+ encoding = possibleEncoding as BufferEncoding;
+ }
await fs.promises.mkdir(outFolder, { recursive: true });
await fs.promises.writeFile(outFile, body, encoding ?? 'utf-8');
}
@@ -620,7 +596,6 @@ export function createBuildManifest(
entryModules: Object.fromEntries(internals.entrySpecifierToBundleMap.entries()),
routes: [],
adapterName: '',
- markdown: settings.config.markdown,
clientDirectives: settings.clientDirectives,
compressHTML: settings.config.compressHTML,
renderers,
diff --git a/packages/astro/src/core/build/index.ts b/packages/astro/src/core/build/index.ts
index 5b1ecf404..07b9b2f7c 100644
--- a/packages/astro/src/core/build/index.ts
+++ b/packages/astro/src/core/build/index.ts
@@ -102,9 +102,7 @@ class AstroBuilder {
logging,
});
- // HACK: Since we only inject the endpoint if `experimental.assets` is on and it's possible for an integration to
- // add that flag, we need to only check and inject the endpoint after running the config setup hook.
- if (this.settings.config.experimental.assets && isServerLikeOutput(this.settings.config)) {
+ if (isServerLikeOutput(this.settings.config)) {
this.settings = injectImageEndpoint(this.settings);
}
diff --git a/packages/astro/src/core/build/internal.ts b/packages/astro/src/core/build/internal.ts
index 5dff6f3dd..c1123e36b 100644
--- a/packages/astro/src/core/build/internal.ts
+++ b/packages/astro/src/core/build/internal.ts
@@ -85,6 +85,9 @@ export interface BuildInternals {
staticFiles: Set<string>;
// The SSR entry chunk. Kept in internals to share between ssr/client build steps
ssrEntryChunk?: Rollup.OutputChunk;
+ // The SSR manifest entry chunk.
+ manifestEntryChunk?: Rollup.OutputChunk;
+ manifestFileName?: string;
entryPoints: Map<RouteData, URL>;
ssrSplitEntryChunks: Map<string, Rollup.OutputChunk>;
componentMetadata: SSRResult['componentMetadata'];
@@ -227,14 +230,6 @@ export function* eachPageData(internals: BuildInternals) {
yield* internals.pagesByComponent.values();
}
-export function* eachRedirectPageData(internals: BuildInternals) {
- for (const pageData of eachPageData(internals)) {
- if (pageData.route.type === 'redirect') {
- yield pageData;
- }
- }
-}
-
export function* eachPageDataFromEntryPoint(
internals: BuildInternals
): Generator<[PageBuildData, string]> {
diff --git a/packages/astro/src/core/build/plugins/README.md b/packages/astro/src/core/build/plugins/README.md
index 145158163..ef73b9e50 100644
--- a/packages/astro/src/core/build/plugins/README.md
+++ b/packages/astro/src/core/build/plugins/README.md
@@ -125,10 +125,13 @@ will look like this:
Of course, all these files will be deleted by Astro at the end build.
-## `plugin-ssr` (WIP)
+## `plugin-ssr`
-This plugin is responsible to create a single `entry.mjs` file that will be used
-in SSR.
+This plugin is responsible to create the JS files that will be executed in SSR.
+
+### Classic mode
+
+The plugin will emit a single entry point called `entry.mjs`.
This plugin **will emit code** only when building an **SSR** site.
@@ -146,4 +149,24 @@ const pageMap = new Map([
```
It will also import the [`renderers`](#plugin-renderers) virtual module
-and the [`middleware`](#plugin-middleware) virtual module.
+and the [`manifest`](#plugin-manifest) virtual module.
+
+### Split mode
+
+The plugin will emit various entry points. Each route will be an entry point.
+
+Each entry point will contain the necessary code to **render one single route**.
+
+Each entry point will also import the [`renderers`](#plugin-renderers) virtual module
+and the [`manifest`](#plugin-manifest) virtual module.
+
+## `plugin-manifest`
+
+This plugin is responsible to create a file called `manifest.mjs`. In SSG, the file is saved
+in `config.outDir`, in SSR the file is saved in `config.build.server`.
+
+This file is important to do two things:
+- generate the pages during the SSG;
+- render the pages in SSR;
+
+The file contains all the information needed to Astro to accomplish the operations mentioned above.
diff --git a/packages/astro/src/core/build/plugins/index.ts b/packages/astro/src/core/build/plugins/index.ts
index decfefd04..19c952660 100644
--- a/packages/astro/src/core/build/plugins/index.ts
+++ b/packages/astro/src/core/build/plugins/index.ts
@@ -12,12 +12,14 @@ import { pluginPages } from './plugin-pages.js';
import { pluginPrerender } from './plugin-prerender.js';
import { pluginRenderers } from './plugin-renderers.js';
import { pluginSSR, pluginSSRSplit } from './plugin-ssr.js';
+import { pluginManifest } from './plugin-manifest.js';
export function registerAllPlugins({ internals, options, register }: AstroBuildPluginContainer) {
register(pluginComponentEntry(internals));
register(pluginAliasResolve(internals));
register(pluginAnalyzer(options, internals));
register(pluginInternals(internals));
+ register(pluginManifest(options, internals));
register(pluginRenderers(options));
register(pluginMiddleware(options, internals));
register(pluginPages(options, internals));
diff --git a/packages/astro/src/core/build/plugins/plugin-manifest.ts b/packages/astro/src/core/build/plugins/plugin-manifest.ts
new file mode 100644
index 000000000..2c2ceb7e1
--- /dev/null
+++ b/packages/astro/src/core/build/plugins/plugin-manifest.ts
@@ -0,0 +1,251 @@
+import { type BuildInternals, cssOrder, mergeInlineCss } from '../internal.js';
+import type { AstroBuildPlugin } from '../plugin';
+import { type Plugin as VitePlugin } from 'vite';
+import { runHookBuildSsr } from '../../../integrations/index.js';
+import { addRollupInput } from '../add-rollup-input.js';
+import glob from 'fast-glob';
+import { fileURLToPath } from 'node:url';
+import type { OutputChunk } from 'rollup';
+import { getOutFile, getOutFolder } from '../common.js';
+import { BEFORE_HYDRATION_SCRIPT_ID, PAGE_SCRIPT_ID } from '../../../vite-plugin-scripts/index.js';
+import { joinPaths, prependForwardSlash } from '../../path.js';
+import { serializeRouteData } from '../../routing/index.js';
+import type { SerializedRouteInfo, SerializedSSRManifest } from '../../app/types';
+import type { StaticBuildOptions } from '../types';
+
+const manifestReplace = '@@ASTRO_MANIFEST_REPLACE@@';
+const replaceExp = new RegExp(`['"](${manifestReplace})['"]`, 'g');
+
+export const SSR_MANIFEST_VIRTUAL_MODULE_ID = '@astrojs-manifest';
+export const RESOLVED_SSR_MANIFEST_VIRTUAL_MODULE_ID = '\0' + SSR_MANIFEST_VIRTUAL_MODULE_ID;
+
+function vitePluginManifest(options: StaticBuildOptions, internals: BuildInternals): VitePlugin {
+ return {
+ name: '@astro/plugin-build-manifest',
+ enforce: 'post',
+ options(opts) {
+ return addRollupInput(opts, [SSR_MANIFEST_VIRTUAL_MODULE_ID]);
+ },
+ resolveId(id) {
+ if (id === SSR_MANIFEST_VIRTUAL_MODULE_ID) {
+ return RESOLVED_SSR_MANIFEST_VIRTUAL_MODULE_ID;
+ }
+ },
+ augmentChunkHash(chunkInfo) {
+ if (chunkInfo.facadeModuleId === RESOLVED_SSR_MANIFEST_VIRTUAL_MODULE_ID) {
+ return Date.now().toString();
+ }
+ },
+ async load(id) {
+ if (id === RESOLVED_SSR_MANIFEST_VIRTUAL_MODULE_ID) {
+ const imports = [];
+ const contents = [];
+ const exports = [];
+ imports.push(
+ `import { deserializeManifest as _deserializeManifest } from 'astro/app'`,
+ `import { _privateSetManifestDontUseThis } from 'astro:ssr-manifest'`
+ );
+
+ contents.push(`
+const manifest = _deserializeManifest('${manifestReplace}');
+_privateSetManifestDontUseThis(manifest);
+`);
+
+ exports.push('export { manifest }');
+
+ return `${imports.join('\n')}${contents.join('\n')}${exports.join('\n')}`;
+ }
+ },
+
+ async generateBundle(_opts, bundle) {
+ for (const [chunkName, chunk] of Object.entries(bundle)) {
+ if (chunk.type === 'asset') {
+ continue;
+ }
+ if (chunk.modules[RESOLVED_SSR_MANIFEST_VIRTUAL_MODULE_ID]) {
+ internals.manifestEntryChunk = chunk;
+ delete bundle[chunkName];
+ }
+ if (chunkName.startsWith('manifest')) {
+ internals.manifestFileName = chunkName;
+ }
+ }
+ },
+ };
+}
+
+export function pluginManifest(
+ options: StaticBuildOptions,
+ internals: BuildInternals
+): AstroBuildPlugin {
+ return {
+ build: 'ssr',
+ hooks: {
+ 'build:before': () => {
+ return {
+ vitePlugin: vitePluginManifest(options, internals),
+ };
+ },
+
+ 'build:post': async ({ mutate }) => {
+ if (!internals.manifestEntryChunk) {
+ throw new Error(`Did not generate an entry chunk for SSR`);
+ }
+
+ const manifest = await createManifest(options, internals);
+ await runHookBuildSsr({
+ config: options.settings.config,
+ manifest,
+ logging: options.logging,
+ entryPoints: internals.entryPoints,
+ middlewareEntryPoint: internals.middlewareEntryPoint,
+ });
+ // TODO: use the manifest entry chunk instead
+ const code = injectManifest(manifest, internals.manifestEntryChunk);
+ mutate(internals.manifestEntryChunk, 'server', code);
+ },
+ },
+ };
+}
+
+export async function createManifest(
+ buildOpts: StaticBuildOptions,
+ internals: BuildInternals
+): Promise<SerializedSSRManifest> {
+ if (!internals.manifestEntryChunk) {
+ throw new Error(`Did not generate an entry chunk for SSR`);
+ }
+
+ // Add assets from the client build.
+ const clientStatics = new Set(
+ await glob('**/*', {
+ cwd: fileURLToPath(buildOpts.settings.config.build.client),
+ })
+ );
+ for (const file of clientStatics) {
+ internals.staticFiles.add(file);
+ }
+
+ const staticFiles = internals.staticFiles;
+ return buildManifest(buildOpts, internals, Array.from(staticFiles));
+}
+
+/**
+ * It injects the manifest in the given output rollup chunk. It returns the new emitted code
+ * @param buildOpts
+ * @param internals
+ * @param chunk
+ */
+export function injectManifest(manifest: SerializedSSRManifest, chunk: Readonly<OutputChunk>) {
+ const code = chunk.code;
+
+ return code.replace(replaceExp, () => {
+ return JSON.stringify(manifest);
+ });
+}
+
+function buildManifest(
+ opts: StaticBuildOptions,
+ internals: BuildInternals,
+ staticFiles: string[]
+): SerializedSSRManifest {
+ const { settings } = opts;
+
+ const routes: SerializedRouteInfo[] = [];
+ const entryModules = Object.fromEntries(internals.entrySpecifierToBundleMap.entries());
+ if (settings.scripts.some((script) => script.stage === 'page')) {
+ staticFiles.push(entryModules[PAGE_SCRIPT_ID]);
+ }
+
+ const prefixAssetPath = (pth: string) => {
+ if (settings.config.build.assetsPrefix) {
+ return joinPaths(settings.config.build.assetsPrefix, pth);
+ } else {
+ return prependForwardSlash(joinPaths(settings.config.base, pth));
+ }
+ };
+
+ for (const route of opts.manifest.routes) {
+ if (!route.prerender) continue;
+ if (!route.pathname) continue;
+
+ const outFolder = getOutFolder(opts.settings.config, route.pathname, route.type);
+ const outFile = getOutFile(opts.settings.config, outFolder, route.pathname, route.type);
+ const file = outFile.toString().replace(opts.settings.config.build.client.toString(), '');
+ routes.push({
+ file,
+ links: [],
+ scripts: [],
+ styles: [],
+ routeData: serializeRouteData(route, settings.config.trailingSlash),
+ });
+ staticFiles.push(file);
+ }
+
+ for (const route of opts.manifest.routes) {
+ const pageData = internals.pagesByComponent.get(route.component);
+ if (route.prerender || !pageData) continue;
+ const scripts: SerializedRouteInfo['scripts'] = [];
+ if (pageData.hoistedScript) {
+ const hoistedValue = pageData.hoistedScript.value;
+ const value = hoistedValue.endsWith('.js') ? prefixAssetPath(hoistedValue) : hoistedValue;
+ scripts.unshift(
+ Object.assign({}, pageData.hoistedScript, {
+ value,
+ })
+ );
+ }
+ if (settings.scripts.some((script) => script.stage === 'page')) {
+ const src = entryModules[PAGE_SCRIPT_ID];
+
+ scripts.push({
+ type: 'external',
+ value: prefixAssetPath(src),
+ });
+ }
+
+ // may be used in the future for handling rel=modulepreload, rel=icon, rel=manifest etc.
+ const links: [] = [];
+
+ const styles = pageData.styles
+ .sort(cssOrder)
+ .map(({ sheet }) => sheet)
+ .map((s) => (s.type === 'external' ? { ...s, src: prefixAssetPath(s.src) } : s))
+ .reduce(mergeInlineCss, []);
+
+ routes.push({
+ file: '',
+ links,
+ scripts: [
+ ...scripts,
+ ...settings.scripts
+ .filter((script) => script.stage === 'head-inline')
+ .map(({ stage, content }) => ({ stage, children: content })),
+ ],
+ styles,
+ routeData: serializeRouteData(route, settings.config.trailingSlash),
+ });
+ }
+
+ // HACK! Patch this special one.
+ if (!(BEFORE_HYDRATION_SCRIPT_ID in entryModules)) {
+ // Set this to an empty string so that the runtime knows not to try and load this.
+ entryModules[BEFORE_HYDRATION_SCRIPT_ID] = '';
+ }
+
+ const ssrManifest: SerializedSSRManifest = {
+ adapterName: opts.settings.adapter?.name ?? '',
+ routes,
+ site: settings.config.site,
+ base: settings.config.base,
+ compressHTML: settings.config.compressHTML,
+ assetsPrefix: settings.config.build.assetsPrefix,
+ componentMetadata: Array.from(internals.componentMetadata),
+ renderers: [],
+ clientDirectives: Array.from(settings.clientDirectives),
+ entryModules,
+ assets: staticFiles.map(prefixAssetPath),
+ };
+
+ return ssrManifest;
+}
diff --git a/packages/astro/src/core/build/plugins/plugin-pages.ts b/packages/astro/src/core/build/plugins/plugin-pages.ts
index 2ee438a6a..ff63acd74 100644
--- a/packages/astro/src/core/build/plugins/plugin-pages.ts
+++ b/packages/astro/src/core/build/plugins/plugin-pages.ts
@@ -8,6 +8,7 @@ import type { StaticBuildOptions } from '../types';
import { MIDDLEWARE_MODULE_ID } from './plugin-middleware.js';
import { RENDERERS_MODULE_ID } from './plugin-renderers.js';
import { ASTRO_PAGE_EXTENSION_POST_PATTERN, getPathFromVirtualModulePageName } from './util.js';
+import type { AstroSettings } from '../../../@types/astro';
export const ASTRO_PAGE_MODULE_ID = '@astro-page:';
export const ASTRO_PAGE_RESOLVED_MODULE_ID = '\0' + ASTRO_PAGE_MODULE_ID;
@@ -74,7 +75,7 @@ function vitePluginPages(opts: StaticBuildOptions, internals: BuildInternals): V
exports.push(`export { renderers };`);
// The middleware should not be imported by the pages
- if (!opts.settings.config.build.excludeMiddleware) {
+ if (shouldBundleMiddleware(opts.settings)) {
const middlewareModule = await this.resolve(MIDDLEWARE_MODULE_ID);
if (middlewareModule) {
imports.push(`import { onRequest } from "${middlewareModule.id}";`);
@@ -90,6 +91,17 @@ function vitePluginPages(opts: StaticBuildOptions, internals: BuildInternals): V
};
}
+export function shouldBundleMiddleware(settings: AstroSettings) {
+ // TODO: Remove in Astro 4.0
+ if (settings.config.build.excludeMiddleware === true) {
+ return false;
+ }
+ if (settings.adapter?.adapterFeatures?.edgeMiddleware === true) {
+ return false;
+ }
+ return true;
+}
+
export function pluginPages(opts: StaticBuildOptions, internals: BuildInternals): AstroBuildPlugin {
return {
build: 'ssr',
diff --git a/packages/astro/src/core/build/plugins/plugin-prerender.ts b/packages/astro/src/core/build/plugins/plugin-prerender.ts
index a0d6a9c7b..402264c6e 100644
--- a/packages/astro/src/core/build/plugins/plugin-prerender.ts
+++ b/packages/astro/src/core/build/plugins/plugin-prerender.ts
@@ -14,7 +14,7 @@ function vitePluginPrerender(opts: StaticBuildOptions, internals: BuildInternals
extendManualChunks(outputOptions, {
after(id, meta) {
// Split the Astro runtime into a separate chunk for readability
- if (id.includes('astro/dist')) {
+ if (id.includes('astro/dist/runtime')) {
return 'astro';
}
const pageInfo = internals.pagesByViteID.get(id);
diff --git a/packages/astro/src/core/build/plugins/plugin-renderers.ts b/packages/astro/src/core/build/plugins/plugin-renderers.ts
index 912df4241..f0cdf8983 100644
--- a/packages/astro/src/core/build/plugins/plugin-renderers.ts
+++ b/packages/astro/src/core/build/plugins/plugin-renderers.ts
@@ -38,6 +38,8 @@ export function vitePluginRenderers(opts: StaticBuildOptions): VitePlugin {
exports.push(`export const renderers = [${rendererItems}];`);
return `${imports.join('\n')}\n${exports.join('\n')}`;
+ } else {
+ return `export const renderers = [];`;
}
}
},
diff --git a/packages/astro/src/core/build/plugins/plugin-ssr.ts b/packages/astro/src/core/build/plugins/plugin-ssr.ts
index 514fe2409..098b9dee8 100644
--- a/packages/astro/src/core/build/plugins/plugin-ssr.ts
+++ b/packages/astro/src/core/build/plugins/plugin-ssr.ts
@@ -1,28 +1,21 @@
-import glob from 'fast-glob';
import { join } from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';
import type { Plugin as VitePlugin } from 'vite';
import type { AstroAdapter, AstroConfig } from '../../../@types/astro';
-import { runHookBuildSsr } from '../../../integrations/index.js';
+import { isFunctionPerRouteEnabled } from '../../../integrations/index.js';
import { isServerLikeOutput } from '../../../prerender/utils.js';
-import { BEFORE_HYDRATION_SCRIPT_ID, PAGE_SCRIPT_ID } from '../../../vite-plugin-scripts/index.js';
-import type { SerializedRouteInfo, SerializedSSRManifest } from '../../app/types';
-import { joinPaths, prependForwardSlash } from '../../path.js';
import { routeIsRedirect } from '../../redirects/index.js';
-import { serializeRouteData } from '../../routing/index.js';
import { addRollupInput } from '../add-rollup-input.js';
-import { getOutFile, getOutFolder } from '../common.js';
-import { cssOrder, mergeInlineCss, type BuildInternals } from '../internal.js';
+import type { BuildInternals } from '../internal.js';
import type { AstroBuildPlugin } from '../plugin';
-import type { OutputChunk, StaticBuildOptions } from '../types';
+import type { StaticBuildOptions } from '../types';
import { ASTRO_PAGE_MODULE_ID } from './plugin-pages.js';
import { RENDERERS_MODULE_ID } from './plugin-renderers.js';
import { getPathFromVirtualModulePageName, getVirtualModulePageNameFromPath } from './util.js';
+import { SSR_MANIFEST_VIRTUAL_MODULE_ID } from './plugin-manifest.js';
export const SSR_VIRTUAL_MODULE_ID = '@astrojs-ssr-virtual-entry';
-const RESOLVED_SSR_VIRTUAL_MODULE_ID = '\0' + SSR_VIRTUAL_MODULE_ID;
-const manifestReplace = '@@ASTRO_MANIFEST_REPLACE@@';
-const replaceExp = new RegExp(`['"](${manifestReplace})['"]`, 'g');
+export const RESOLVED_SSR_VIRTUAL_MODULE_ID = '\0' + SSR_VIRTUAL_MODULE_ID;
function vitePluginSSR(
internals: BuildInternals,
@@ -85,13 +78,12 @@ function vitePluginSSR(
}
}
- for (const [chunkName, chunk] of Object.entries(bundle)) {
+ for (const [, chunk] of Object.entries(bundle)) {
if (chunk.type === 'asset') {
continue;
}
if (chunk.modules[RESOLVED_SSR_VIRTUAL_MODULE_ID]) {
internals.ssrEntryChunk = chunk;
- delete bundle[chunkName];
}
}
},
@@ -103,12 +95,16 @@ export function pluginSSR(
internals: BuildInternals
): AstroBuildPlugin {
const ssr = isServerLikeOutput(options.settings.config);
+ const functionPerRouteEnabled = isFunctionPerRouteEnabled(options.settings.adapter);
return {
build: 'ssr',
hooks: {
'build:before': () => {
let vitePlugin =
- ssr && !options.settings.config.build.split
+ ssr &&
+ // TODO: Remove in Astro 4.0
+ options.settings.config.build.split === false &&
+ functionPerRouteEnabled === false
? vitePluginSSR(internals, options.settings.adapter!, options)
: undefined;
@@ -117,12 +113,12 @@ export function pluginSSR(
vitePlugin,
};
},
- 'build:post': async ({ mutate }) => {
+ 'build:post': async () => {
if (!ssr) {
return;
}
- if (options.settings.config.build.split) {
+ if (options.settings.config.build.split || functionPerRouteEnabled) {
return;
}
@@ -131,17 +127,6 @@ export function pluginSSR(
}
// Mutate the filename
internals.ssrEntryChunk.fileName = options.settings.config.build.serverEntry;
-
- const manifest = await createManifest(options, internals);
- await runHookBuildSsr({
- config: options.settings.config,
- manifest,
- logging: options.logging,
- entryPoints: internals.entryPoints,
- middlewareEntryPoint: internals.middlewareEntryPoint,
- });
- const code = injectManifest(manifest, internals.ssrEntryChunk);
- mutate(internals.ssrEntryChunk, 'server', code);
},
},
};
@@ -155,11 +140,12 @@ function vitePluginSSRSplit(
adapter: AstroAdapter,
options: StaticBuildOptions
): VitePlugin {
+ const functionPerRouteEnabled = isFunctionPerRouteEnabled(options.settings.adapter);
return {
name: '@astrojs/vite-plugin-astro-ssr-split',
enforce: 'post',
options(opts) {
- if (options.settings.config.build.split) {
+ if (options.settings.config.build.split || functionPerRouteEnabled) {
const inputs = new Set<string>();
for (const path of Object.keys(options.allPages)) {
@@ -204,21 +190,16 @@ function vitePluginSSRSplit(
}
}
- for (const [chunkName, chunk] of Object.entries(bundle)) {
+ for (const [, chunk] of Object.entries(bundle)) {
if (chunk.type === 'asset') {
continue;
}
- let shouldDeleteBundle = false;
for (const moduleKey of Object.keys(chunk.modules)) {
if (moduleKey.startsWith(RESOLVED_SPLIT_MODULE_ID)) {
internals.ssrSplitEntryChunks.set(moduleKey, chunk);
storeEntryPoint(moduleKey, options, internals, chunk.fileName);
- shouldDeleteBundle = true;
}
}
- if (shouldDeleteBundle) {
- delete bundle[chunkName];
- }
}
},
};
@@ -229,12 +210,14 @@ export function pluginSSRSplit(
internals: BuildInternals
): AstroBuildPlugin {
const ssr = isServerLikeOutput(options.settings.config);
+ const functionPerRouteEnabled = isFunctionPerRouteEnabled(options.settings.adapter);
+
return {
build: 'ssr',
hooks: {
'build:before': () => {
let vitePlugin =
- ssr && options.settings.config.build.split
+ ssr && (options.settings.config.build.split || functionPerRouteEnabled)
? vitePluginSSRSplit(internals, options.settings.adapter!, options)
: undefined;
@@ -243,31 +226,6 @@ export function pluginSSRSplit(
vitePlugin,
};
},
- 'build:post': async ({ mutate }) => {
- if (!ssr) {
- return;
- }
- if (!options.settings.config.build.split) {
- return;
- }
-
- if (internals.ssrSplitEntryChunks.size === 0) {
- throw new Error(`Did not generate an entry chunk for SSR serverless`);
- }
-
- const manifest = await createManifest(options, internals);
- await runHookBuildSsr({
- config: options.settings.config,
- manifest,
- logging: options.logging,
- entryPoints: internals.entryPoints,
- middlewareEntryPoint: internals.middlewareEntryPoint,
- });
- for (const [, chunk] of internals.ssrSplitEntryChunks) {
- const code = injectManifest(manifest, chunk);
- mutate(chunk, 'server', code);
- }
- },
},
};
}
@@ -276,7 +234,7 @@ function generateSSRCode(config: AstroConfig, adapter: AstroAdapter) {
const imports: string[] = [];
const contents: string[] = [];
let pageMap;
- if (config.build.split) {
+ if (config.build.split || isFunctionPerRouteEnabled(adapter)) {
pageMap = 'pageModule';
} else {
pageMap = 'pageMap';
@@ -284,13 +242,11 @@ function generateSSRCode(config: AstroConfig, adapter: AstroAdapter) {
contents.push(`import * as adapter from '${adapter.serverEntrypoint}';
import { renderers } from '${RENDERERS_MODULE_ID}';
-import { deserializeManifest as _deserializeManifest } from 'astro/app';
-import { _privateSetManifestDontUseThis } from 'astro:ssr-manifest';
-const _manifest = Object.assign(_deserializeManifest('${manifestReplace}'), {
+import { manifest as defaultManifest} from '${SSR_MANIFEST_VIRTUAL_MODULE_ID}';
+const _manifest = Object.assign(defaultManifest, {
${pageMap},
renderers,
});
-_privateSetManifestDontUseThis(_manifest);
const _args = ${adapter.args ? JSON.stringify(adapter.args) : 'undefined'};
${
@@ -320,48 +276,6 @@ if(_start in adapter) {
}
/**
- * It injects the manifest in the given output rollup chunk. It returns the new emitted code
- * @param buildOpts
- * @param internals
- * @param chunk
- */
-export function injectManifest(manifest: SerializedSSRManifest, chunk: Readonly<OutputChunk>) {
- const code = chunk.code;
-
- return code.replace(replaceExp, () => {
- return JSON.stringify(manifest);
- });
-}
-
-export async function createManifest(
- buildOpts: StaticBuildOptions,
- internals: BuildInternals
-): Promise<SerializedSSRManifest> {
- if (buildOpts.settings.config.build.split) {
- if (internals.ssrSplitEntryChunks.size === 0) {
- throw new Error(`Did not generate an entry chunk for SSR in serverless mode`);
- }
- } else {
- if (!internals.ssrEntryChunk) {
- throw new Error(`Did not generate an entry chunk for SSR`);
- }
- }
-
- // Add assets from the client build.
- const clientStatics = new Set(
- await glob('**/*', {
- cwd: fileURLToPath(buildOpts.settings.config.build.client),
- })
- );
- for (const file of clientStatics) {
- internals.staticFiles.add(file);
- }
-
- const staticFiles = internals.staticFiles;
- return buildManifest(buildOpts, internals, Array.from(staticFiles));
-}
-
-/**
* Because we delete the bundle from rollup at the end of this function,
* we can't use `writeBundle` hook to get the final file name of the entry point written on disk.
* We use this hook instead.
@@ -382,110 +296,3 @@ function storeEntryPoint(
}
}
}
-
-function buildManifest(
- opts: StaticBuildOptions,
- internals: BuildInternals,
- staticFiles: string[]
-): SerializedSSRManifest {
- const { settings } = opts;
-
- const routes: SerializedRouteInfo[] = [];
- const entryModules = Object.fromEntries(internals.entrySpecifierToBundleMap.entries());
- if (settings.scripts.some((script) => script.stage === 'page')) {
- staticFiles.push(entryModules[PAGE_SCRIPT_ID]);
- }
-
- const prefixAssetPath = (pth: string) => {
- if (settings.config.build.assetsPrefix) {
- return joinPaths(settings.config.build.assetsPrefix, pth);
- } else {
- return prependForwardSlash(joinPaths(settings.config.base, pth));
- }
- };
-
- for (const route of opts.manifest.routes) {
- if (!route.prerender) continue;
- if (!route.pathname) continue;
-
- const outFolder = getOutFolder(opts.settings.config, route.pathname, route.type);
- const outFile = getOutFile(opts.settings.config, outFolder, route.pathname, route.type);
- const file = outFile.toString().replace(opts.settings.config.build.client.toString(), '');
- routes.push({
- file,
- links: [],
- scripts: [],
- styles: [],
- routeData: serializeRouteData(route, settings.config.trailingSlash),
- });
- staticFiles.push(file);
- }
-
- for (const route of opts.manifest.routes) {
- const pageData = internals.pagesByComponent.get(route.component);
- if (route.prerender || !pageData) continue;
- const scripts: SerializedRouteInfo['scripts'] = [];
- if (pageData.hoistedScript) {
- const hoistedValue = pageData.hoistedScript.value;
- const value = hoistedValue.endsWith('.js') ? prefixAssetPath(hoistedValue) : hoistedValue;
- scripts.unshift(
- Object.assign({}, pageData.hoistedScript, {
- value,
- })
- );
- }
- if (settings.scripts.some((script) => script.stage === 'page')) {
- const src = entryModules[PAGE_SCRIPT_ID];
-
- scripts.push({
- type: 'external',
- value: prefixAssetPath(src),
- });
- }
-
- // may be used in the future for handling rel=modulepreload, rel=icon, rel=manifest etc.
- const links: [] = [];
-
- const styles = pageData.styles
- .sort(cssOrder)
- .map(({ sheet }) => sheet)
- .map((s) => (s.type === 'external' ? { ...s, src: prefixAssetPath(s.src) } : s))
- .reduce(mergeInlineCss, []);
-
- routes.push({
- file: '',
- links,
- scripts: [
- ...scripts,
- ...settings.scripts
- .filter((script) => script.stage === 'head-inline')
- .map(({ stage, content }) => ({ stage, children: content })),
- ],
- styles,
- routeData: serializeRouteData(route, settings.config.trailingSlash),
- });
- }
-
- // HACK! Patch this special one.
- if (!(BEFORE_HYDRATION_SCRIPT_ID in entryModules)) {
- // Set this to an empty string so that the runtime knows not to try and load this.
- entryModules[BEFORE_HYDRATION_SCRIPT_ID] = '';
- }
-
- const ssrManifest: SerializedSSRManifest = {
- adapterName: opts.settings.adapter!.name,
- routes,
- site: settings.config.site,
- base: settings.config.base,
- compressHTML: settings.config.compressHTML,
- assetsPrefix: settings.config.build.assetsPrefix,
- markdown: settings.config.markdown,
- componentMetadata: Array.from(internals.componentMetadata),
- renderers: [],
- clientDirectives: Array.from(settings.clientDirectives),
- entryModules,
- assets: staticFiles.map(prefixAssetPath),
- };
-
- return ssrManifest;
-}
diff --git a/packages/astro/src/core/build/static-build.ts b/packages/astro/src/core/build/static-build.ts
index fb16b433d..a1c7c3e56 100644
--- a/packages/astro/src/core/build/static-build.ts
+++ b/packages/astro/src/core/build/static-build.ts
@@ -16,7 +16,7 @@ import { emptyDir, removeEmptyDirs } from '../../core/fs/index.js';
import { appendForwardSlash, prependForwardSlash } from '../../core/path.js';
import { isModeServerWithNoAdapter } from '../../core/util.js';
import { runHookBuildSetup } from '../../integrations/index.js';
-import { isServerLikeOutput } from '../../prerender/utils.js';
+import { getOutputDirectory, isServerLikeOutput } from '../../prerender/utils.js';
import { PAGE_SCRIPT_ID } from '../../vite-plugin-scripts/index.js';
import { AstroError, AstroErrorData } from '../errors/index.js';
import { info } from '../logger/core.js';
@@ -28,10 +28,11 @@ import { createPluginContainer, type AstroBuildPluginContainer } from './plugin.
import { registerAllPlugins } from './plugins/index.js';
import { ASTRO_PAGE_RESOLVED_MODULE_ID } from './plugins/plugin-pages.js';
import { RESOLVED_RENDERERS_MODULE_ID } from './plugins/plugin-renderers.js';
-import { RESOLVED_SPLIT_MODULE_ID, SSR_VIRTUAL_MODULE_ID } from './plugins/plugin-ssr.js';
+import { RESOLVED_SPLIT_MODULE_ID, RESOLVED_SSR_VIRTUAL_MODULE_ID } from './plugins/plugin-ssr.js';
import { ASTRO_PAGE_EXTENSION_POST_PATTERN } from './plugins/util.js';
import type { PageBuildData, StaticBuildOptions } from './types';
import { getTimeStat } from './util.js';
+import { RESOLVED_SSR_MANIFEST_VIRTUAL_MODULE_ID } from './plugins/plugin-manifest.js';
export async function viteBuild(opts: StaticBuildOptions) {
const { allPages, settings } = opts;
@@ -147,7 +148,7 @@ async function ssrBuild(
) {
const { allPages, settings, viteConfig } = opts;
const ssr = isServerLikeOutput(settings.config);
- const out = ssr ? settings.config.build.server : getOutDirWithinCwd(settings.config.outDir);
+ const out = getOutputDirectory(settings.config);
const routes = Object.values(allPages).map((pd) => pd.route);
const { lastVitePlugins, vitePlugins } = container.runBeforeHook('ssr', input);
@@ -184,10 +185,12 @@ async function ssrBuild(
);
} else if (chunkInfo.facadeModuleId?.startsWith(RESOLVED_SPLIT_MODULE_ID)) {
return makeSplitEntryPointFileName(chunkInfo.facadeModuleId, routes);
- } else if (chunkInfo.facadeModuleId === SSR_VIRTUAL_MODULE_ID) {
+ } else if (chunkInfo.facadeModuleId === RESOLVED_SSR_VIRTUAL_MODULE_ID) {
return opts.settings.config.build.serverEntry;
} else if (chunkInfo.facadeModuleId === RESOLVED_RENDERERS_MODULE_ID) {
return 'renderers.mjs';
+ } else if (chunkInfo.facadeModuleId === RESOLVED_SSR_MANIFEST_VIRTUAL_MODULE_ID) {
+ return 'manifest.[hash].mjs';
} else {
return '[name].mjs';
}
diff --git a/packages/astro/src/core/compile/compile.ts b/packages/astro/src/core/compile/compile.ts
index f266c0b16..bd069611d 100644
--- a/packages/astro/src/core/compile/compile.ts
+++ b/packages/astro/src/core/compile/compile.ts
@@ -41,7 +41,7 @@ export async function compile({
filename,
normalizedFilename: normalizeFilename(filename, astroConfig.root),
sourcemap: 'both',
- internalURL: 'astro/server/index.js',
+ internalURL: 'astro/compiler-runtime',
astroGlobalArgs: JSON.stringify(astroConfig.site),
scopedStyleStrategy: astroConfig.scopedStyleStrategy,
resultScopedSlot: true,
diff --git a/packages/astro/src/core/config/config.ts b/packages/astro/src/core/config/config.ts
index 29b0bb23a..ba089c9a7 100644
--- a/packages/astro/src/core/config/config.ts
+++ b/packages/astro/src/core/config/config.ts
@@ -124,8 +124,6 @@ export function resolveFlags(flags: Partial<Flags>): CLIFlags {
host:
typeof flags.host === 'string' || typeof flags.host === 'boolean' ? flags.host : undefined,
drafts: typeof flags.drafts === 'boolean' ? flags.drafts : undefined,
- experimentalAssets:
- typeof flags.experimentalAssets === 'boolean' ? flags.experimentalAssets : undefined,
};
}
diff --git a/packages/astro/src/core/config/schema.ts b/packages/astro/src/core/config/schema.ts
index 87ff7ba9f..bff55b392 100644
--- a/packages/astro/src/core/config/schema.ts
+++ b/packages/astro/src/core/config/schema.ts
@@ -8,7 +8,7 @@ import path from 'node:path';
import { pathToFileURL } from 'node:url';
import { BUNDLED_THEMES } from 'shiki';
import { z } from 'zod';
-import { appendForwardSlash, prependForwardSlash, trimSlashes } from '../path.js';
+import { appendForwardSlash, prependForwardSlash, removeTrailingForwardSlash } from '../path.js';
const ASTRO_CONFIG_DEFAULTS = {
root: '.',
@@ -29,10 +29,10 @@ const ASTRO_CONFIG_DEFAULTS = {
split: false,
excludeMiddleware: false,
},
- compressHTML: false,
+ compressHTML: true,
server: {
host: false,
- port: 3000,
+ port: 4321,
open: false,
},
integrations: [],
@@ -44,7 +44,6 @@ const ASTRO_CONFIG_DEFAULTS = {
legacy: {},
redirects: {},
experimental: {
- assets: false,
viewTransitions: false,
optimizeHoistedScript: false,
},
@@ -88,9 +87,9 @@ export const AstroConfigSchema = z.object({
.optional()
.default('static'),
scopedStyleStrategy: z
- .union([z.literal('where'), z.literal('class')])
+ .union([z.literal('where'), z.literal('class'), z.literal('attribute')])
.optional()
- .default('where'),
+ .default('attribute'),
adapter: z.object({ name: z.string(), hooks: z.object({}).passthrough().default({}) }).optional(),
integrations: z.preprocess(
// preprocess
@@ -125,7 +124,15 @@ export const AstroConfigSchema = z.object({
.optional()
.default(ASTRO_CONFIG_DEFAULTS.build.inlineStylesheets),
+ /**
+ * @deprecated
+ * Use the adapter feature instead
+ */
split: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.build.split),
+ /**
+ * @deprecated
+ * Use the adapter feature instead
+ */
excludeMiddleware: z
.boolean()
.optional()
@@ -208,9 +215,7 @@ export const AstroConfigSchema = z.object({
.default([]),
})
.default({
- service: { entrypoint: 'astro/assets/services/squoosh', config: {} },
- domains: [],
- remotePatterns: [],
+ service: { entrypoint: 'astro/assets/services/sharp', config: {} },
}),
markdown: z
.object({
@@ -259,7 +264,6 @@ export const AstroConfigSchema = z.object({
.default(ASTRO_CONFIG_DEFAULTS.vite),
experimental: z
.object({
- assets: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.assets),
viewTransitions: z
.boolean()
.optional()
@@ -391,22 +395,14 @@ export function createRelativeSchema(cmd: string, fileProtocolRoot: string) {
) {
config.build.client = new URL('./dist/client/', config.outDir);
}
- const trimmedBase = trimSlashes(config.base);
- // If there is no base but there is a base for site config, warn.
- const sitePathname = config.site && new URL(config.site).pathname;
- if (!trimmedBase.length && sitePathname && sitePathname !== '/') {
- config.base = sitePathname;
- /* eslint-disable no-console */
- console.warn(`The site configuration value includes a pathname of ${sitePathname} but there is no base configuration.
-
-A future version of Astro will stop using the site pathname when producing <link> and <script> tags. Set your site's base with the base configuration.`);
- }
-
- if (trimmedBase.length && config.trailingSlash === 'never') {
- config.base = prependForwardSlash(trimmedBase);
+ // Handle `base` trailing slash based on `trailingSlash` config
+ if (config.trailingSlash === 'never') {
+ config.base = prependForwardSlash(removeTrailingForwardSlash(config.base));
+ } else if (config.trailingSlash === 'always') {
+ config.base = prependForwardSlash(appendForwardSlash(config.base));
} else {
- config.base = prependForwardSlash(appendForwardSlash(trimmedBase));
+ config.base = prependForwardSlash(config.base);
}
return config;
diff --git a/packages/astro/src/core/config/settings.ts b/packages/astro/src/core/config/settings.ts
index c0274f602..30ca7c4c2 100644
--- a/packages/astro/src/core/config/settings.ts
+++ b/packages/astro/src/core/config/settings.ts
@@ -3,7 +3,6 @@ import path from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';
import type { AstroConfig, AstroSettings } from '../../@types/astro';
import { getContentPaths } from '../../content/index.js';
-import jsxRenderer from '../../jsx/renderer.js';
import { markdownContentEntryType } from '../../vite-plugin-markdown/content-entry-type.js';
import { getDefaultClientDirectives } from '../client-directive/index.js';
import { AstroError, AstroErrorData } from '../errors/index.js';
@@ -18,7 +17,6 @@ export function createBaseSettings(config: AstroConfig): AstroSettings {
config,
tsConfig: undefined,
tsConfigPath: undefined,
-
adapter: undefined,
injectedRoutes: [],
resolvedInjectedRoutes: [],
@@ -96,7 +94,7 @@ export function createBaseSettings(config: AstroConfig): AstroSettings {
},
},
],
- renderers: [jsxRenderer],
+ renderers: [],
scripts: [],
clientDirectives: getDefaultClientDirectives(),
watchFiles: [],
diff --git a/packages/astro/src/core/cookies/cookies.ts b/packages/astro/src/core/cookies/cookies.ts
index 013357f32..604f30e63 100644
--- a/packages/astro/src/core/cookies/cookies.ts
+++ b/packages/astro/src/core/cookies/cookies.ts
@@ -15,14 +15,14 @@ interface AstroCookieSetOptions {
type AstroCookieDeleteOptions = Pick<AstroCookieSetOptions, 'domain' | 'path'>;
interface AstroCookieInterface {
- value: string | undefined;
+ value: string;
json(): Record<string, any>;
number(): number;
boolean(): boolean;
}
interface AstroCookiesInterface {
- get(key: string): AstroCookieInterface;
+ get(key: string): AstroCookieInterface | undefined;
has(key: string): boolean;
set(
key: string,
@@ -37,7 +37,7 @@ const DELETED_VALUE = 'deleted';
const responseSentSymbol = Symbol.for('astro.responseSent');
class AstroCookie implements AstroCookieInterface {
- constructor(public value: string | undefined) {}
+ constructor(public value: string) {}
json() {
if (this.value === undefined) {
throw new Error(`Cannot convert undefined to an object.`);
@@ -97,20 +97,22 @@ class AstroCookies implements AstroCookiesInterface {
* @param key The cookie to get.
* @returns An object containing the cookie value as well as convenience methods for converting its value.
*/
- get(key: string): AstroCookie {
+ get(key: string): AstroCookie | undefined {
// Check for outgoing Set-Cookie values first
if (this.#outgoing?.has(key)) {
let [serializedValue, , isSetValue] = this.#outgoing.get(key)!;
if (isSetValue) {
return new AstroCookie(serializedValue);
} else {
- return new AstroCookie(undefined);
+ return undefined;
}
}
const values = this.#ensureParsed();
- const value = values[key];
- return new AstroCookie(value);
+ if (key in values) {
+ const value = values[key];
+ return new AstroCookie(value);
+ }
}
/**
diff --git a/packages/astro/src/core/cookies/index.ts b/packages/astro/src/core/cookies/index.ts
index 1b0c6b7a0..f3c7b6d61 100644
--- a/packages/astro/src/core/cookies/index.ts
+++ b/packages/astro/src/core/cookies/index.ts
@@ -1,2 +1,2 @@
export { AstroCookies } from './cookies.js';
-export { attachToResponse, getSetCookiesFromResponse } from './response.js';
+export { attachCookiesToResponse, getSetCookiesFromResponse } from './response.js';
diff --git a/packages/astro/src/core/cookies/response.ts b/packages/astro/src/core/cookies/response.ts
index 18d72ab1c..668bd265f 100644
--- a/packages/astro/src/core/cookies/response.ts
+++ b/packages/astro/src/core/cookies/response.ts
@@ -2,7 +2,7 @@ import type { AstroCookies } from './cookies';
const astroCookiesSymbol = Symbol.for('astro.cookies');
-export function attachToResponse(response: Response, cookies: AstroCookies) {
+export function attachCookiesToResponse(response: Response, cookies: AstroCookies) {
Reflect.set(response, astroCookiesSymbol, cookies);
}
diff --git a/packages/astro/src/core/create-vite.ts b/packages/astro/src/core/create-vite.ts
index 0fb64ef69..5b2ebfa21 100644
--- a/packages/astro/src/core/create-vite.ts
+++ b/packages/astro/src/core/create-vite.ts
@@ -19,9 +19,9 @@ import configAliasVitePlugin from '../vite-plugin-config-alias/index.js';
import envVitePlugin from '../vite-plugin-env/index.js';
import astroHeadPlugin from '../vite-plugin-head/index.js';
import htmlVitePlugin from '../vite-plugin-html/index.js';
+import mdxVitePlugin from '../vite-plugin-mdx/index.js';
import { astroInjectEnvTsPlugin } from '../vite-plugin-inject-env-ts/index.js';
import astroIntegrationsContainerPlugin from '../vite-plugin-integrations-container/index.js';
-import jsxVitePlugin from '../vite-plugin-jsx/index.js';
import astroLoadFallbackPlugin from '../vite-plugin-load-fallback/index.js';
import markdownVitePlugin from '../vite-plugin-markdown/index.js';
import astroScannerPlugin from '../vite-plugin-scanner/index.js';
@@ -121,7 +121,7 @@ export async function createVite(
envVitePlugin({ settings }),
markdownVitePlugin({ settings, logging }),
htmlVitePlugin(),
- jsxVitePlugin({ settings, logging }),
+ mdxVitePlugin({ settings, logging }),
astroPostprocessVitePlugin(),
astroIntegrationsContainerPlugin({ settings, logging }),
astroScriptsPageSSRPlugin({ settings }),
@@ -132,7 +132,7 @@ export async function createVite(
astroContentImportPlugin({ fs, settings }),
astroContentAssetPropagationPlugin({ mode, settings }),
vitePluginSSRManifest(),
- settings.config.experimental.assets ? [astroAssetsPlugin({ settings, logging, mode })] : [],
+ astroAssetsPlugin({ settings, logging, mode }),
astroTransitions({ config: settings.config }),
],
publicDir: fileURLToPath(settings.config.publicDir),
@@ -234,37 +234,12 @@ export async function createVite(
result = vite.mergeConfig(result, settings.config.vite || {});
}
result = vite.mergeConfig(result, commandConfig);
- if (result.plugins) {
- sortPlugins(result.plugins);
- }
result.customLogger = vite.createLogger(result.logLevel ?? 'warn');
return result;
}
-function isVitePlugin(plugin: vite.PluginOption): plugin is vite.Plugin {
- return Boolean(plugin?.hasOwnProperty('name'));
-}
-
-function findPluginIndexByName(pluginOptions: vite.PluginOption[], name: string): number {
- return pluginOptions.findIndex(function (pluginOption) {
- // Use isVitePlugin to ignore nulls, booleans, promises, and arrays
- // CAUTION: could be a problem if a plugin we're searching for becomes async!
- return isVitePlugin(pluginOption) && pluginOption.name === name;
- });
-}
-
-function sortPlugins(pluginOptions: vite.PluginOption[]) {
- // HACK: move mdxPlugin to top because it needs to run before internal JSX plugin
- const mdxPluginIndex = findPluginIndexByName(pluginOptions, '@mdx-js/rollup');
- if (mdxPluginIndex === -1) return;
- const jsxPluginIndex = findPluginIndexByName(pluginOptions, 'astro:jsx');
- const mdxPlugin = pluginOptions[mdxPluginIndex];
- pluginOptions.splice(mdxPluginIndex, 1);
- pluginOptions.splice(jsxPluginIndex, 0, mdxPlugin);
-}
-
const COMMON_DEPENDENCIES_NOT_ASTRO = [
'autoprefixer',
'react',
diff --git a/packages/astro/src/core/dev/container.ts b/packages/astro/src/core/dev/container.ts
index d4e41e96d..4aeb35f3a 100644
--- a/packages/astro/src/core/dev/container.ts
+++ b/packages/astro/src/core/dev/container.ts
@@ -50,11 +50,7 @@ export async function createContainer({
isRestart,
});
- // HACK: Since we only inject the endpoint if `experimental.assets` is on and it's possible for an integration to
- // add that flag, we need to only check and inject the endpoint after running the config setup hook.
- if (settings.config.experimental.assets) {
- settings = injectImageEndpoint(settings);
- }
+ settings = injectImageEndpoint(settings);
const { host, headers, open } = settings.config.server;
diff --git a/packages/astro/src/core/endpoint/index.ts b/packages/astro/src/core/endpoint/index.ts
index 485190e47..9298e7cbe 100644
--- a/packages/astro/src/core/endpoint/index.ts
+++ b/packages/astro/src/core/endpoint/index.ts
@@ -7,13 +7,13 @@ import type {
Params,
} from '../../@types/astro';
import type { Environment, RenderContext } from '../render/index';
-
import { renderEndpoint } from '../../runtime/server/index.js';
import { ASTRO_VERSION } from '../constants.js';
-import { AstroCookies, attachToResponse } from '../cookies/index.js';
+import { AstroCookies, attachCookiesToResponse } from '../cookies/index.js';
import { AstroError, AstroErrorData } from '../errors/index.js';
import { warn } from '../logger/core.js';
import { callMiddleware } from '../middleware/callMiddleware.js';
+
const clientAddressSymbol = Symbol.for('astro.clientAddress');
const clientLocalsSymbol = Symbol.for('astro.locals');
@@ -117,15 +117,15 @@ export async function callEndpoint<MiddlewareResult = Response | EndpointOutput>
onRequest as MiddlewareEndpointHandler,
context,
async () => {
- return await renderEndpoint(mod, context, env.ssr);
+ return await renderEndpoint(mod, context, env.ssr, env.logging);
}
);
} else {
- response = await renderEndpoint(mod, context, env.ssr);
+ response = await renderEndpoint(mod, context, env.ssr, env.logging);
}
if (response instanceof Response) {
- attachToResponse(response, context.cookies);
+ attachCookiesToResponse(response, context.cookies);
return {
type: 'response',
response,
diff --git a/packages/astro/src/core/errors/errors.ts b/packages/astro/src/core/errors/errors.ts
index 1960bac4a..faf365686 100644
--- a/packages/astro/src/core/errors/errors.ts
+++ b/packages/astro/src/core/errors/errors.ts
@@ -19,6 +19,7 @@ export interface ErrorLocation {
type ErrorTypes =
| 'AstroError'
+ | 'AstroUserError'
| 'CompilerError'
| 'CSSError'
| 'MarkdownError'
@@ -171,3 +172,25 @@ export interface ErrorWithMetadata {
};
cause?: any;
}
+
+/**
+ * Special error that is exposed to users.
+ * Compared to AstroError, it contains a subset of information.
+ */
+export class AstroUserError extends Error {
+ type: ErrorTypes = 'AstroUserError';
+ /**
+ * A message that explains to the user how they can fix the error.
+ */
+ hint: string | undefined;
+ name = 'AstroUserError';
+ constructor(message: string, hint?: string) {
+ super();
+ this.message = message;
+ this.hint = hint;
+ }
+
+ static is(err: unknown): err is AstroUserError {
+ return (err as AstroUserError).type === 'AstroUserError';
+ }
+}
diff --git a/packages/astro/src/core/errors/index.ts b/packages/astro/src/core/errors/index.ts
index e09225af4..5a796a0b3 100644
--- a/packages/astro/src/core/errors/index.ts
+++ b/packages/astro/src/core/errors/index.ts
@@ -7,6 +7,7 @@ export {
CompilerError,
MarkdownError,
isAstroError,
+ AstroUserError,
} from './errors.js';
export { codeFrame } from './printer.js';
export { createSafeError, positionAt } from './utils.js';
diff --git a/packages/astro/src/core/errors/userError.ts b/packages/astro/src/core/errors/userError.ts
new file mode 100644
index 000000000..663549314
--- /dev/null
+++ b/packages/astro/src/core/errors/userError.ts
@@ -0,0 +1 @@
+export { AstroUserError as AstroError } from './errors.js';
diff --git a/packages/astro/src/core/logger/console.ts b/packages/astro/src/core/logger/console.ts
index dfe732bd7..f39f6b74d 100644
--- a/packages/astro/src/core/logger/console.ts
+++ b/packages/astro/src/core/logger/console.ts
@@ -15,7 +15,7 @@ export const consoleLogDestination = {
function getPrefix() {
let prefix = '';
- let type = event.type;
+ let type = event.label;
if (type) {
// hide timestamp when type is undefined
prefix += dim(dateTimeFormat.format(new Date()) + ' ');
diff --git a/packages/astro/src/core/logger/core.ts b/packages/astro/src/core/logger/core.ts
index 4f0c281e0..c92cdbb24 100644
--- a/packages/astro/src/core/logger/core.ts
+++ b/packages/astro/src/core/logger/core.ts
@@ -6,7 +6,6 @@ interface LogWritable<T> {
}
export type LoggerLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent'; // same as Pino
-export type LoggerEvent = 'info' | 'warn' | 'error';
export interface LogOptions {
dest: LogWritable<LogMessage>;
@@ -29,7 +28,7 @@ export const dateTimeFormat = new Intl.DateTimeFormat([], {
});
export interface LogMessage {
- type: string | null;
+ label: string | null;
level: LoggerLevel;
message: string;
}
@@ -43,11 +42,11 @@ export const levels: Record<LoggerLevel, number> = {
};
/** Full logging API */
-export function log(opts: LogOptions, level: LoggerLevel, type: string | null, message: string) {
+export function log(opts: LogOptions, level: LoggerLevel, label: string | null, message: string) {
const logLevel = opts.level;
const dest = opts.dest;
const event: LogMessage = {
- type,
+ label,
level,
message,
};
@@ -61,18 +60,18 @@ export function log(opts: LogOptions, level: LoggerLevel, type: string | null, m
}
/** Emit a user-facing message. Useful for UI and other console messages. */
-export function info(opts: LogOptions, type: string | null, message: string) {
- return log(opts, 'info', type, message);
+export function info(opts: LogOptions, label: string | null, message: string) {
+ return log(opts, 'info', label, message);
}
/** Emit a warning message. Useful for high-priority messages that aren't necessarily errors. */
-export function warn(opts: LogOptions, type: string | null, message: string) {
- return log(opts, 'warn', type, message);
+export function warn(opts: LogOptions, label: string | null, message: string) {
+ return log(opts, 'warn', label, message);
}
/** Emit a error message, Useful when Astro can't recover from some error. */
-export function error(opts: LogOptions, type: string | null, message: string) {
- return log(opts, 'error', type, message);
+export function error(opts: LogOptions, label: string | null, message: string) {
+ return log(opts, 'error', label, message);
}
type LogFn = typeof info | typeof warn | typeof error;
@@ -127,3 +126,53 @@ export function timerMessage(message: string, startTime: number = Date.now()) {
timeDiff < 750 ? `${Math.round(timeDiff)}ms` : `${(timeDiff / 1000).toFixed(1)}s`;
return `${message} ${dim(timeDisplay)}`;
}
+
+export class Logger {
+ options: LogOptions;
+ constructor(options: LogOptions) {
+ this.options = options;
+ }
+
+ info(label: string | null, message: string) {
+ info(this.options, label, message);
+ }
+ warn(label: string | null, message: string) {
+ warn(this.options, label, message);
+ }
+ error(label: string | null, message: string) {
+ error(this.options, label, message);
+ }
+ debug(label: string | null, message: string) {
+ debug(this.options, label, message);
+ }
+}
+
+export class AstroIntegrationLogger {
+ options: LogOptions;
+ label: string;
+
+ constructor(logging: LogOptions, label: string) {
+ this.options = logging;
+ this.label = label;
+ }
+
+ /**
+ * Creates a new logger instance with a new label, but the same log options.
+ */
+ fork(label: string): AstroIntegrationLogger {
+ return new AstroIntegrationLogger(this.options, label);
+ }
+
+ info(message: string) {
+ info(this.options, this.label, message);
+ }
+ warn(message: string) {
+ warn(this.options, this.label, message);
+ }
+ error(message: string) {
+ error(this.options, this.label, message);
+ }
+ debug(message: string) {
+ debug(this.options, this.label, message);
+ }
+}
diff --git a/packages/astro/src/core/logger/node.ts b/packages/astro/src/core/logger/node.ts
index 513ba257e..aeef4bd84 100644
--- a/packages/astro/src/core/logger/node.ts
+++ b/packages/astro/src/core/logger/node.ts
@@ -21,19 +21,19 @@ export const nodeLogDestination = new Writable({
function getPrefix() {
let prefix = '';
- let type = event.type;
- if (type) {
+ let label = event.label;
+ if (label) {
// hide timestamp when type is undefined
prefix += dim(dateTimeFormat.format(new Date()) + ' ');
if (event.level === 'info') {
- type = bold(cyan(`[${type}]`));
+ label = bold(cyan(`[${label}]`));
} else if (event.level === 'warn') {
- type = bold(yellow(`[${type}]`));
+ label = bold(yellow(`[${label}]`));
} else if (event.level === 'error') {
- type = bold(red(`[${type}]`));
+ label = bold(red(`[${label}]`));
}
- prefix += `${type} `;
+ prefix += `${label} `;
}
return reset(prefix);
}
@@ -87,7 +87,7 @@ export const nodeLogOptions: Required<LogOptions> = {
};
export interface LogMessage {
- type: string | null;
+ label: string | null;
level: LoggerLevel;
message: string;
}
diff --git a/packages/astro/src/core/messages.ts b/packages/astro/src/core/messages.ts
index 51ec39ad9..4fc3ca02a 100644
--- a/packages/astro/src/core/messages.ts
+++ b/packages/astro/src/core/messages.ts
@@ -17,7 +17,12 @@ import {
import type { ResolvedServerUrls } from 'vite';
import type { ZodError } from 'zod';
import { renderErrorMarkdown } from './errors/dev/utils.js';
-import { AstroError, CompilerError, type ErrorWithMetadata } from './errors/index.js';
+import {
+ AstroError,
+ CompilerError,
+ type ErrorWithMetadata,
+ AstroUserError,
+} from './errors/index.js';
import { emoji, padMultilineString } from './util.js';
const PREFIX_PADDING = 6;
@@ -198,7 +203,7 @@ export function formatConfigErrorMessage(err: ZodError) {
}
export function formatErrorMessage(err: ErrorWithMetadata, args: string[] = []): string {
- const isOurError = AstroError.is(err) || CompilerError.is(err);
+ const isOurError = AstroError.is(err) || CompilerError.is(err) || AstroUserError.is(err);
args.push(
`${bgRed(black(` error `))}${red(
diff --git a/packages/astro/src/core/pipeline.ts b/packages/astro/src/core/pipeline.ts
new file mode 100644
index 000000000..b5c66517a
--- /dev/null
+++ b/packages/astro/src/core/pipeline.ts
@@ -0,0 +1,165 @@
+import { type RenderContext, type Environment } from './render/index.js';
+import { type EndpointCallResult, callEndpoint, createAPIContext } from './endpoint/index.js';
+import type {
+ MiddlewareHandler,
+ MiddlewareResponseHandler,
+ ComponentInstance,
+ MiddlewareEndpointHandler,
+ RouteType,
+ EndpointHandler,
+} from '../@types/astro';
+import { callMiddleware } from './middleware/callMiddleware.js';
+import { renderPage } from './render/core.js';
+
+type EndpointResultHandler = (
+ originalRequest: Request,
+ result: EndpointCallResult
+) => Promise<Response> | Response;
+
+/**
+ * This is the basic class of a pipeline.
+ *
+ * Check the {@link ./README.md|README} for more information about the pipeline.
+ */
+export class Pipeline {
+ env: Environment;
+ #onRequest?: MiddlewareEndpointHandler;
+ /**
+ * The handler accepts the *original* `Request` and result returned by the endpoint.
+ * It must return a `Response`.
+ */
+ #endpointHandler?: EndpointResultHandler;
+
+ /**
+ * When creating a pipeline, an environment is mandatory.
+ * The environment won't change for the whole lifetime of the pipeline.
+ */
+ constructor(env: Environment) {
+ this.env = env;
+ }
+
+ setEnvironment() {}
+
+ /**
+ * When rendering a route, an "endpoint" will a type that needs to be handled and transformed into a `Response`.
+ *
+ * Each consumer might have different needs; use this function to set up the handler.
+ */
+ setEndpointHandler(handler: EndpointResultHandler) {
+ this.#endpointHandler = handler;
+ }
+
+ /**
+ * A middleware function that will be called before each request.
+ */
+ setMiddlewareFunction(onRequest: MiddlewareEndpointHandler) {
+ this.#onRequest = onRequest;
+ }
+
+ /**
+ * Returns the current environment
+ */
+ getEnvironment() {
+ return this.env;
+ }
+
+ /**
+ * The main function of the pipeline. Use this function to render any route known to Astro;
+ */
+ async renderRoute(
+ renderContext: RenderContext,
+ componentInstance: ComponentInstance
+ ): Promise<Response> {
+ const result = await this.#tryRenderRoute(
+ renderContext,
+ this.env,
+ componentInstance,
+ this.#onRequest
+ );
+ if (Pipeline.isEndpointResult(result, renderContext.route.type)) {
+ if (!this.#endpointHandler) {
+ throw new Error(
+ 'You created a pipeline that does not know how to handle the result coming from an endpoint.'
+ );
+ }
+ return this.#endpointHandler(renderContext.request, result);
+ } else {
+ return result;
+ }
+ }
+
+ /**
+ * It attempts to render a route. A route can be a:
+ * - page
+ * - redirect
+ * - endpoint
+ *
+ * ## Errors
+ *
+ * It throws an error if the page can't be rendered.
+ */
+ async #tryRenderRoute<MiddlewareReturnType = Response>(
+ renderContext: Readonly<RenderContext>,
+ env: Readonly<Environment>,
+ mod: Readonly<ComponentInstance>,
+ onRequest?: MiddlewareHandler<MiddlewareReturnType>
+ ): Promise<Response | EndpointCallResult> {
+ const apiContext = createAPIContext({
+ request: renderContext.request,
+ params: renderContext.params,
+ props: renderContext.props,
+ site: env.site,
+ adapterName: env.adapterName,
+ });
+
+ switch (renderContext.route.type) {
+ case 'page':
+ case 'redirect': {
+ if (onRequest) {
+ return await callMiddleware<Response>(
+ env.logging,
+ onRequest as MiddlewareResponseHandler,
+ apiContext,
+ () => {
+ return renderPage({
+ mod,
+ renderContext,
+ env,
+ cookies: apiContext.cookies,
+ });
+ }
+ );
+ } else {
+ return await renderPage({
+ mod,
+ renderContext,
+ env,
+ cookies: apiContext.cookies,
+ });
+ }
+ }
+ case 'endpoint': {
+ const result = await callEndpoint(
+ mod as any as EndpointHandler,
+ env,
+ renderContext,
+ onRequest
+ );
+ return result;
+ }
+ default:
+ throw new Error(`Couldn't find route of type [${renderContext.route.type}]`);
+ }
+ }
+
+ /**
+ * Use this function
+ */
+ static isEndpointResult(result: any, routeType: RouteType): result is EndpointCallResult {
+ return !(result instanceof Response) && routeType === 'endpoint';
+ }
+
+ static isResponse(result: any, routeType: RouteType): result is Response {
+ return result instanceof Response && (routeType === 'page' || routeType === 'redirect');
+ }
+}
diff --git a/packages/astro/src/core/polyfill.ts b/packages/astro/src/core/polyfill.ts
index 99e0d5cc5..daceb53e2 100644
--- a/packages/astro/src/core/polyfill.ts
+++ b/packages/astro/src/core/polyfill.ts
@@ -1,8 +1,21 @@
-import { polyfill } from '@astrojs/webapi';
+import { File } from 'node:buffer';
+import crypto from 'node:crypto';
+
+// NOTE: This file does not intend to polyfill everything that exists, its main goal is to make life easier
+// for users deploying to runtime that do support these features. In the future, we hope for this file to disappear.
export function apply() {
- // polyfill WebAPIs for Node.js runtime
- polyfill(globalThis, {
- exclude: 'window document',
- });
+ // Remove when Node 18 is dropped for Node 20
+ if (!globalThis.crypto) {
+ Object.defineProperty(globalThis, 'crypto', {
+ value: crypto.webcrypto,
+ });
+ }
+
+ // Remove when Node 18 is dropped for Node 20
+ if (!globalThis.File) {
+ Object.defineProperty(globalThis, 'File', {
+ value: File,
+ });
+ }
}
diff --git a/packages/astro/src/core/render/context.ts b/packages/astro/src/core/render/context.ts
index 5b26eda18..d767d7910 100644
--- a/packages/astro/src/core/render/context.ts
+++ b/packages/astro/src/core/render/context.ts
@@ -22,7 +22,7 @@ export interface RenderContext {
links?: Set<SSRElement>;
styles?: Set<SSRElement>;
componentMetadata?: SSRResult['componentMetadata'];
- route?: RouteData;
+ route: RouteData;
status?: number;
params: Params;
props: Props;
@@ -32,6 +32,7 @@ export interface RenderContext {
export type CreateRenderContextArgs = Partial<
Omit<RenderContext, 'params' | 'props' | 'locals'>
> & {
+ route: RouteData;
request: RenderContext['request'];
mod: ComponentInstance;
env: Environment;
diff --git a/packages/astro/src/core/render/core.ts b/packages/astro/src/core/render/core.ts
index d6228fbbe..9de046278 100644
--- a/packages/astro/src/core/render/core.ts
+++ b/packages/astro/src/core/render/core.ts
@@ -7,7 +7,7 @@ import type {
RouteType,
} from '../../@types/astro';
import { renderPage as runtimeRenderPage } from '../../runtime/server/index.js';
-import { attachToResponse } from '../cookies/index.js';
+import { attachCookiesToResponse } from '../cookies/index.js';
import { callEndpoint, createAPIContext, type EndpointCallResult } from '../endpoint/index.js';
import { callMiddleware } from '../middleware/callMiddleware.js';
import { redirectRouteGenerate, redirectRouteStatus, routeIsRedirect } from '../redirects/index.js';
@@ -22,7 +22,7 @@ export type RenderPage = {
cookies: AstroCookies;
};
-async function renderPage({ mod, renderContext, env, cookies }: RenderPage) {
+export async function renderPage({ mod, renderContext, env, cookies }: RenderPage) {
if (routeIsRedirect(renderContext.route)) {
return new Response(null, {
status: redirectRouteStatus(renderContext.route, renderContext.request.method),
@@ -42,7 +42,6 @@ async function renderPage({ mod, renderContext, env, cookies }: RenderPage) {
links: renderContext.links,
styles: renderContext.styles,
logging: env.logging,
- markdown: env.markdown,
params: renderContext.params,
pathname: renderContext.pathname,
componentMetadata: renderContext.componentMetadata,
@@ -59,12 +58,7 @@ async function renderPage({ mod, renderContext, env, cookies }: RenderPage) {
locals: renderContext.locals ?? {},
});
- // Support `export const components` for `MDX` pages
- if (typeof (mod as any).components === 'object') {
- Object.assign(renderContext.props, { components: (mod as any).components });
- }
-
- let response = await runtimeRenderPage(
+ const response = await runtimeRenderPage(
result,
Component,
renderContext.props,
@@ -76,7 +70,7 @@ async function renderPage({ mod, renderContext, env, cookies }: RenderPage) {
// If there is an Astro.cookies instance, attach it to the response so that
// adapters can grab the Set-Cookie headers.
if (result.cookies) {
- attachToResponse(response, result.cookies);
+ attachCookiesToResponse(response, result.cookies);
}
return response;
@@ -91,9 +85,9 @@ async function renderPage({ mod, renderContext, env, cookies }: RenderPage) {
* ## Errors
*
* It throws an error if the page can't be rendered.
+ * @deprecated Use the pipeline instead
*/
export async function tryRenderRoute<MiddlewareReturnType = Response>(
- routeType: RouteType,
renderContext: Readonly<RenderContext>,
env: Readonly<Environment>,
mod: Readonly<ComponentInstance>,
@@ -107,7 +101,7 @@ export async function tryRenderRoute<MiddlewareReturnType = Response>(
adapterName: env.adapterName,
});
- switch (routeType) {
+ switch (renderContext.route.type) {
case 'page':
case 'redirect': {
if (onRequest) {
@@ -143,7 +137,7 @@ export async function tryRenderRoute<MiddlewareReturnType = Response>(
return result;
}
default:
- throw new Error(`Couldn't find route of type [${routeType}]`);
+ throw new Error(`Couldn't find route of type [${renderContext.route.type}]`);
}
}
diff --git a/packages/astro/src/core/render/environment.ts b/packages/astro/src/core/render/environment.ts
index de7cbe6a8..32dfb454b 100644
--- a/packages/astro/src/core/render/environment.ts
+++ b/packages/astro/src/core/render/environment.ts
@@ -1,4 +1,3 @@
-import type { MarkdownRenderingOptions } from '@astrojs/markdown-remark';
import type { AstroSettings, RuntimeMode, SSRLoadedRenderer } from '../../@types/astro';
import type { LogOptions } from '../logger/core.js';
import type { ModuleLoader } from '../module-loader';
@@ -16,10 +15,6 @@ export interface Environment {
adapterName?: string;
/** logging options */
logging: LogOptions;
- /**
- * Used to support `Astro.__renderMarkdown` for legacy `<Markdown />` component
- */
- markdown: MarkdownRenderingOptions;
/** "development" or "production" */
mode: RuntimeMode;
compressHTML: boolean;
diff --git a/packages/astro/src/core/render/index.ts b/packages/astro/src/core/render/index.ts
index a82c5699e..20b964fa7 100644
--- a/packages/astro/src/core/render/index.ts
+++ b/packages/astro/src/core/render/index.ts
@@ -22,7 +22,7 @@ export interface SSROptions {
/** Request */
request: Request;
/** optional, in case we need to render something outside of a dev server */
- route?: RouteData;
+ route: RouteData;
/**
* Optional middlewares
*/
diff --git a/packages/astro/src/core/render/params-and-props.ts b/packages/astro/src/core/render/params-and-props.ts
index a5e4fa222..fc08c495e 100644
--- a/packages/astro/src/core/render/params-and-props.ts
+++ b/packages/astro/src/core/render/params-and-props.ts
@@ -33,7 +33,6 @@ export async function getParamsAndProps(opts: GetParamsAndPropsOptions): Promise
mod,
route,
routeCache,
- isValidate: true,
logging,
ssr,
});
diff --git a/packages/astro/src/core/render/result.ts b/packages/astro/src/core/render/result.ts
index 968b232d4..72fa4ddcf 100644
--- a/packages/astro/src/core/render/result.ts
+++ b/packages/astro/src/core/render/result.ts
@@ -1,4 +1,3 @@
-import type { MarkdownRenderingOptions } from '@astrojs/markdown-remark';
import type {
AstroGlobal,
AstroGlobalPartial,
@@ -27,10 +26,6 @@ export interface CreateResultArgs {
*/
ssr: boolean;
logging: LogOptions;
- /**
- * Used to support `Astro.__renderMarkdown` for legacy `<Markdown />` component
- */
- markdown: MarkdownRenderingOptions;
params: Params;
pathname: string;
renderers: SSRLoadedRenderer[];
@@ -128,10 +123,8 @@ class Slots {
}
}
-let renderMarkdown: any = null;
-
export function createResult(args: CreateResultArgs): SSRResult {
- const { markdown, params, request, resolve, locals } = args;
+ const { params, request, resolve, locals } = args;
const url = new URL(request.url);
const headers = new Headers();
@@ -222,31 +215,6 @@ export function createResult(args: CreateResultArgs): SSRResult {
slots: astroSlots as unknown as AstroGlobal['slots'],
};
- Object.defineProperty(Astro, '__renderMarkdown', {
- // Ensure this API is not exposed to users
- enumerable: false,
- writable: false,
- // TODO: Remove this hole "Deno" logic once our plugin gets Deno support
- value: async function (content: string, opts: MarkdownRenderingOptions) {
- // @ts-expect-error
- if (typeof Deno !== 'undefined') {
- throw new Error('Markdown is not supported in Deno SSR');
- }
-
- if (!renderMarkdown) {
- // The package is saved in this variable because Vite is too smart
- // and will try to inline it in buildtime
- let astroRemark = '@astrojs/';
- astroRemark += 'markdown-remark';
-
- renderMarkdown = (await import(astroRemark)).renderMarkdown;
- }
-
- const { code } = await renderMarkdown(content, { ...markdown, ...(opts ?? {}) });
- return code;
- },
- });
-
return Astro;
},
resolve,
diff --git a/packages/astro/src/core/render/route-cache.ts b/packages/astro/src/core/render/route-cache.ts
index 7ad247ef8..804f09183 100644
--- a/packages/astro/src/core/render/route-cache.ts
+++ b/packages/astro/src/core/render/route-cache.ts
@@ -18,7 +18,6 @@ interface CallGetStaticPathsOptions {
mod: ComponentInstance;
route: RouteData;
routeCache: RouteCache;
- isValidate: boolean;
logging: LogOptions;
ssr: boolean;
}
@@ -27,7 +26,6 @@ export async function callGetStaticPaths({
mod,
route,
routeCache,
- isValidate,
logging,
ssr,
}: CallGetStaticPathsOptions): Promise<GetStaticPathsResultKeyed> {
@@ -58,14 +56,7 @@ export async function callGetStaticPaths({
},
});
- // Flatten the array before validating the content, otherwise users using `.map` will run into errors
- if (Array.isArray(staticPaths)) {
- staticPaths = staticPaths.flat();
- }
-
- if (isValidate) {
- validateGetStaticPathsResult(staticPaths, logging, route);
- }
+ validateGetStaticPathsResult(staticPaths, logging, route);
const keyedStaticPaths = staticPaths as GetStaticPathsResultKeyed;
keyedStaticPaths.keyed = new Map<string, GetStaticPathsItem>();
diff --git a/packages/astro/src/core/routing/manifest/create.ts b/packages/astro/src/core/routing/manifest/create.ts
index e669f293b..124d870d9 100644
--- a/packages/astro/src/core/routing/manifest/create.ts
+++ b/packages/astro/src/core/routing/manifest/create.ts
@@ -185,7 +185,12 @@ function injectedRouteToItem(
{ config, cwd }: { config: AstroConfig; cwd?: string },
{ pattern, entryPoint }: InjectedRoute
): Item {
- const resolved = require.resolve(entryPoint, { paths: [cwd || fileURLToPath(config.root)] });
+ let resolved: string;
+ try {
+ resolved = require.resolve(entryPoint, { paths: [cwd || fileURLToPath(config.root)] });
+ } catch (e) {
+ resolved = fileURLToPath(new URL(entryPoint, config.root));
+ }
const ext = path.extname(pattern);
diff --git a/packages/astro/src/core/routing/validation.ts b/packages/astro/src/core/routing/validation.ts
index 9a562c044..b5c29b16e 100644
--- a/packages/astro/src/core/routing/validation.ts
+++ b/packages/astro/src/core/routing/validation.ts
@@ -54,6 +54,15 @@ export function validateGetStaticPathsResult(
}
result.forEach((pathObject) => {
+ if ((typeof pathObject === 'object' && Array.isArray(pathObject)) || pathObject === null) {
+ throw new AstroError({
+ ...AstroErrorData.InvalidGetStaticPathsEntry,
+ message: AstroErrorData.InvalidGetStaticPathsEntry.message(
+ Array.isArray(pathObject) ? 'array' : typeof pathObject
+ ),
+ });
+ }
+
if (
pathObject.params === undefined ||
pathObject.params === null ||
@@ -67,16 +76,6 @@ export function validateGetStaticPathsResult(
});
}
- if (typeof pathObject.params !== 'object') {
- throw new AstroError({
- ...AstroErrorData.InvalidGetStaticPathParam,
- message: AstroErrorData.InvalidGetStaticPathParam.message(typeof pathObject.params),
- location: {
- file: route.component,
- },
- });
- }
-
// TODO: Replace those with errors? They technically don't crash the build, but users might miss the warning. - erika, 2022-11-07
for (const [key, val] of Object.entries(pathObject.params)) {
if (!(typeof val === 'undefined' || typeof val === 'string' || typeof val === 'number')) {
diff --git a/packages/astro/src/core/util.ts b/packages/astro/src/core/util.ts
index ff41a5ed6..d442e5811 100644
--- a/packages/astro/src/core/util.ts
+++ b/packages/astro/src/core/util.ts
@@ -189,7 +189,6 @@ export function emoji(char: string, fallback: string) {
* through a script tag or a dynamic import as-is.
*/
// NOTE: `/@id/` should only be used when the id is fully resolved
-// TODO: Export a helper util from Vite
export async function resolveIdToUrl(loader: ModuleLoader, id: string, root?: URL) {
let resultId = await loader.resolveId(id, undefined);
// Try resolve jsx to tsx
diff --git a/packages/astro/src/integrations/astroFeaturesValidation.ts b/packages/astro/src/integrations/astroFeaturesValidation.ts
new file mode 100644
index 000000000..c494b35f4
--- /dev/null
+++ b/packages/astro/src/integrations/astroFeaturesValidation.ts
@@ -0,0 +1,157 @@
+import type {
+ AstroAssetsFeature,
+ AstroConfig,
+ AstroFeatureMap,
+ SupportsKind,
+} from '../@types/astro';
+import { error, warn, type LogOptions } from '../core/logger/core.js';
+
+const STABLE = 'stable';
+const DEPRECATED = 'deprecated';
+const UNSUPPORTED = 'unsupported';
+const EXPERIMENTAL = 'experimental';
+
+const UNSUPPORTED_ASSETS_FEATURE: AstroAssetsFeature = {
+ supportKind: UNSUPPORTED,
+ isSquooshCompatible: false,
+ isSharpCompatible: false,
+};
+
+// NOTE: remove for Astro 4.0
+const ALL_UNSUPPORTED: Required<AstroFeatureMap> = {
+ serverOutput: UNSUPPORTED,
+ staticOutput: UNSUPPORTED,
+ hybridOutput: UNSUPPORTED,
+ assets: UNSUPPORTED_ASSETS_FEATURE,
+};
+
+type ValidationResult = {
+ [Property in keyof AstroFeatureMap]: boolean;
+};
+
+/**
+ * Checks whether an adapter supports certain features that are enabled via Astro configuration.
+ *
+ * If a configuration is enabled and "unlocks" a feature, but the adapter doesn't support, the function
+ * will throw a runtime error.
+ *
+ */
+export function validateSupportedFeatures(
+ adapterName: string,
+ featureMap: AstroFeatureMap = ALL_UNSUPPORTED,
+ config: AstroConfig,
+ logging: LogOptions
+): ValidationResult {
+ const {
+ assets = UNSUPPORTED_ASSETS_FEATURE,
+ serverOutput = UNSUPPORTED,
+ staticOutput = UNSUPPORTED,
+ hybridOutput = UNSUPPORTED,
+ } = featureMap;
+ const validationResult: ValidationResult = {};
+
+ validationResult.staticOutput = validateSupportKind(
+ staticOutput,
+ adapterName,
+ logging,
+ 'staticOutput',
+ () => config?.output === 'static'
+ );
+
+ validationResult.hybridOutput = validateSupportKind(
+ hybridOutput,
+ adapterName,
+ logging,
+ 'hybridOutput',
+ () => config?.output === 'hybrid'
+ );
+
+ validationResult.serverOutput = validateSupportKind(
+ serverOutput,
+ adapterName,
+ logging,
+ 'serverOutput',
+ () => config?.output === 'server'
+ );
+ validationResult.assets = validateAssetsFeature(assets, adapterName, config, logging);
+
+ return validationResult;
+}
+
+function validateSupportKind(
+ supportKind: SupportsKind,
+ adapterName: string,
+ logging: LogOptions,
+ featureName: string,
+ hasCorrectConfig: () => boolean
+): boolean {
+ if (supportKind === STABLE) {
+ return true;
+ } else if (supportKind === DEPRECATED) {
+ featureIsDeprecated(adapterName, logging);
+ } else if (supportKind === EXPERIMENTAL) {
+ featureIsExperimental(adapterName, logging);
+ }
+
+ if (hasCorrectConfig() && supportKind === UNSUPPORTED) {
+ featureIsUnsupported(adapterName, logging, featureName);
+ return false;
+ } else {
+ return true;
+ }
+}
+
+function featureIsUnsupported(adapterName: string, logging: LogOptions, featureName: string) {
+ error(
+ logging,
+ `${adapterName}`,
+ `The feature ${featureName} is not supported by the adapter ${adapterName}.`
+ );
+}
+
+function featureIsExperimental(adapterName: string, logging: LogOptions) {
+ warn(logging, `${adapterName}`, 'The feature is experimental and subject to issues or changes.');
+}
+
+function featureIsDeprecated(adapterName: string, logging: LogOptions) {
+ warn(
+ logging,
+ `${adapterName}`,
+ 'The feature is deprecated and will be moved in the next release.'
+ );
+}
+
+const SHARP_SERVICE = 'astro/assets/services/sharp';
+const SQUOOSH_SERVICE = 'astro/assets/services/squoosh';
+
+function validateAssetsFeature(
+ assets: AstroAssetsFeature,
+ adapterName: string,
+ config: AstroConfig,
+ logging: LogOptions
+): boolean {
+ const {
+ supportKind = UNSUPPORTED,
+ isSharpCompatible = false,
+ isSquooshCompatible = false,
+ } = assets;
+ if (config?.image?.service?.entrypoint === SHARP_SERVICE && !isSharpCompatible) {
+ error(
+ logging,
+ 'astro',
+ `The currently selected adapter \`${adapterName}\` is not compatible with the image service "Sharp".`
+ );
+ return false;
+ }
+
+ if (config?.image?.service?.entrypoint === SQUOOSH_SERVICE && !isSquooshCompatible) {
+ error(
+ logging,
+ 'astro',
+ `The currently selected adapter \`${adapterName}\` is not compatible with the image service "Squoosh".`
+ );
+ return false;
+ }
+
+ return validateSupportKind(supportKind, adapterName, logging, 'assets', () => true);
+}
diff --git a/packages/astro/src/integrations/index.ts b/packages/astro/src/integrations/index.ts
index cf50df0e1..71c5a5e63 100644
--- a/packages/astro/src/integrations/index.ts
+++ b/packages/astro/src/integrations/index.ts
@@ -4,7 +4,9 @@ import type { AddressInfo } from 'node:net';
import { fileURLToPath } from 'node:url';
import type { InlineConfig, ViteDevServer } from 'vite';
import type {
+ AstroAdapter,
AstroConfig,
+ AstroIntegration,
AstroRenderer,
AstroSettings,
ContentEntryType,
@@ -16,8 +18,9 @@ import type { SerializedSSRManifest } from '../core/app/types';
import type { PageBuildData } from '../core/build/types';
import { buildClientDirectiveEntrypoint } from '../core/client-directive/index.js';
import { mergeConfig } from '../core/config/index.js';
-import { info, type LogOptions } from '../core/logger/core.js';
+import { AstroIntegrationLogger, error, info, warn, type LogOptions } from '../core/logger/core.js';
import { isServerLikeOutput } from '../prerender/utils.js';
+import { validateSupportedFeatures } from './astroFeaturesValidation.js';
async function withTakingALongTimeMsg<T>({
name,
@@ -38,6 +41,19 @@ async function withTakingALongTimeMsg<T>({
return result;
}
+// Used internally to store instances of loggers.
+const Loggers = new WeakMap<AstroIntegration, AstroIntegrationLogger>();
+
+function getLogger(integration: AstroIntegration, logging: LogOptions) {
+ if (Loggers.has(integration)) {
+ // SAFETY: we check the existence in the if block
+ return Loggers.get(integration)!;
+ }
+ const logger = new AstroIntegrationLogger(logging, integration.name);
+ Loggers.set(integration, logger);
+ return logger;
+}
+
export async function runHookConfigSetup({
settings,
command,
@@ -72,6 +88,8 @@ export async function runHookConfigSetup({
* ```
*/
if (integration.hooks?.['astro:config:setup']) {
+ const logger = getLogger(integration, logging);
+
const hooks: HookParameters<'astro:config:setup'> = {
config: updatedConfig,
command,
@@ -107,6 +125,7 @@ export async function runHookConfigSetup({
}
addedClientDirectives.set(name, buildClientDirectiveEntrypoint(name, entrypoint));
},
+ logger,
};
// ---
@@ -167,6 +186,7 @@ export async function runHookConfigDone({
logging: LogOptions;
}) {
for (const integration of settings.config.integrations) {
+ const logger = getLogger(integration, logging);
if (integration?.hooks?.['astro:config:done']) {
await withTakingALongTimeMsg({
name: integration.name,
@@ -178,8 +198,44 @@ export async function runHookConfigDone({
`Integration "${integration.name}" conflicts with "${settings.adapter.name}". You can only configure one deployment integration.`
);
}
+ if (!adapter.supportedAstroFeatures) {
+ // NOTE: throw an error in Astro 4.0
+ warn(
+ logging,
+ 'astro',
+ `The adapter ${adapter.name} doesn't provide a feature map. From Astro 3.0, an adapter can provide a feature map. Not providing a feature map will cause an error in Astro 4.0.`
+ );
+ } else {
+ const validationResult = validateSupportedFeatures(
+ adapter.name,
+ adapter.supportedAstroFeatures,
+ settings.config,
+ logging
+ );
+ for (const [featureName, supported] of Object.entries(validationResult)) {
+ if (!supported) {
+ error(
+ logging,
+ 'astro',
+ `The adapter ${adapter.name} doesn't support the feature ${featureName}. Your project won't be built. You should not use it.`
+ );
+ }
+ }
+ if (!validationResult.assets) {
+ info(
+ logging,
+ 'astro',
+ `The selected adapter ${adapter.name} does not support Sharp or Squoosh for image processing. To ensure your project is still able to build, image processing has been disabled.`
+ );
+ settings.config.image.service = {
+ entrypoint: 'astro/assets/services/noop',
+ config: {},
+ };
+ }
+ }
settings.adapter = adapter;
},
+ logger,
}),
logging,
});
@@ -198,9 +254,10 @@ export async function runHookServerSetup({
}) {
for (const integration of config.integrations) {
if (integration?.hooks?.['astro:server:setup']) {
+ const logger = getLogger(integration, logging);
await withTakingALongTimeMsg({
name: integration.name,
- hookResult: integration.hooks['astro:server:setup']({ server }),
+ hookResult: integration.hooks['astro:server:setup']({ server, logger }),
logging,
});
}
@@ -217,10 +274,12 @@ export async function runHookServerStart({
logging: LogOptions;
}) {
for (const integration of config.integrations) {
+ const logger = getLogger(integration, logging);
+
if (integration?.hooks?.['astro:server:start']) {
await withTakingALongTimeMsg({
name: integration.name,
- hookResult: integration.hooks['astro:server:start']({ address }),
+ hookResult: integration.hooks['astro:server:start']({ address, logger }),
logging,
});
}
@@ -235,10 +294,12 @@ export async function runHookServerDone({
logging: LogOptions;
}) {
for (const integration of config.integrations) {
+ const logger = getLogger(integration, logging);
+
if (integration?.hooks?.['astro:server:done']) {
await withTakingALongTimeMsg({
name: integration.name,
- hookResult: integration.hooks['astro:server:done'](),
+ hookResult: integration.hooks['astro:server:done']({ logger }),
logging,
});
}
@@ -254,9 +315,11 @@ export async function runHookBuildStart({
}) {
for (const integration of config.integrations) {
if (integration?.hooks?.['astro:build:start']) {
+ const logger = getLogger(integration, logging);
+
await withTakingALongTimeMsg({
name: integration.name,
- hookResult: integration.hooks['astro:build:start'](),
+ hookResult: integration.hooks['astro:build:start']({ logger }),
logging,
});
}
@@ -280,6 +343,8 @@ export async function runHookBuildSetup({
for (const integration of config.integrations) {
if (integration?.hooks?.['astro:build:setup']) {
+ const logger = getLogger(integration, logging);
+
await withTakingALongTimeMsg({
name: integration.name,
hookResult: integration.hooks['astro:build:setup']({
@@ -289,6 +354,7 @@ export async function runHookBuildSetup({
updateConfig: (newConfig) => {
updatedConfig = mergeConfig(updatedConfig, newConfig);
},
+ logger,
}),
logging,
});
@@ -315,12 +381,15 @@ export async function runHookBuildSsr({
}: RunHookBuildSsr) {
for (const integration of config.integrations) {
if (integration?.hooks?.['astro:build:ssr']) {
+ const logger = getLogger(integration, logging);
+
await withTakingALongTimeMsg({
name: integration.name,
hookResult: integration.hooks['astro:build:ssr']({
manifest,
entryPoints,
middlewareEntryPoint,
+ logger,
}),
logging,
});
@@ -338,10 +407,12 @@ export async function runHookBuildGenerated({
const dir = isServerLikeOutput(config) ? config.build.client : config.outDir;
for (const integration of config.integrations) {
+ const logger = getLogger(integration, logging);
+
if (integration?.hooks?.['astro:build:generated']) {
await withTakingALongTimeMsg({
name: integration.name,
- hookResult: integration.hooks['astro:build:generated']({ dir }),
+ hookResult: integration.hooks['astro:build:generated']({ dir, logger }),
logging,
});
}
@@ -361,15 +432,34 @@ export async function runHookBuildDone({ config, pages, routes, logging }: RunHo
for (const integration of config.integrations) {
if (integration?.hooks?.['astro:build:done']) {
+ const logger = getLogger(integration, logging);
+
await withTakingALongTimeMsg({
name: integration.name,
hookResult: integration.hooks['astro:build:done']({
pages: pages.map((p) => ({ pathname: p })),
dir,
routes,
+ logger,
}),
logging,
});
}
}
}
+
+export function isFunctionPerRouteEnabled(adapter: AstroAdapter | undefined): boolean {
+ if (adapter?.adapterFeatures?.functionPerRoute === true) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+export function isEdgeMiddlewareEnabled(adapter: AstroAdapter | undefined): boolean {
+ if (adapter?.adapterFeatures?.edgeMiddleware === true) {
+ return true;
+ } else {
+ return false;
+ }
+}
diff --git a/packages/astro/src/jsx/server.ts b/packages/astro/src/jsx/server.ts
index 6374b1ebd..d445ee3a5 100644
--- a/packages/astro/src/jsx/server.ts
+++ b/packages/astro/src/jsx/server.ts
@@ -1,3 +1,4 @@
+import { AstroError } from '../core/errors/errors.js';
import { AstroJSX, jsx } from '../jsx-runtime/index.js';
import { renderJSX } from '../runtime/server/jsx.js';
@@ -22,7 +23,7 @@ export async function check(
// if the exception is from an mdx component
// throw an error
if (Component[Symbol.for('mdx-component')]) {
- throw createFormattedError({
+ throw new AstroError({
message: error.message,
title: error.name,
hint: `This issue often occurs when your MDX component encounters runtime errors.`,
@@ -51,23 +52,6 @@ export async function renderToStaticMarkup(
return { html };
}
-type FormatErrorOptions = {
- message: string;
- name: string;
- stack?: string;
- hint: string;
- title: string;
-};
-// TODO: Remove this function and use `AstroError` when we refactor it to be usable without error codes
-function createFormattedError({ message, name, stack, hint }: FormatErrorOptions) {
- const error = new Error(message);
- error.name = name;
- error.stack = stack;
- // @ts-expect-error - hint is not part of the Error interface but it will be picked up by the error overlay
- error.hint = hint;
- return error;
-}
-
export default {
check,
renderToStaticMarkup,
diff --git a/packages/astro/src/prerender/utils.ts b/packages/astro/src/prerender/utils.ts
index bd6e367ad..a3655eead 100644
--- a/packages/astro/src/prerender/utils.ts
+++ b/packages/astro/src/prerender/utils.ts
@@ -1,4 +1,5 @@
import type { AstroConfig } from '../@types/astro';
+import { getOutDirWithinCwd } from '../core/build/common.js';
export function isServerLikeOutput(config: AstroConfig) {
return config.output === 'server' || config.output === 'hybrid';
@@ -7,3 +8,15 @@ export function isServerLikeOutput(config: AstroConfig) {
export function getPrerenderDefault(config: AstroConfig) {
return config.output === 'hybrid';
}
+
+/**
+ * Returns the correct output directory of hte SSR build based on the configuration
+ */
+export function getOutputDirectory(config: AstroConfig): URL {
+ const ssr = isServerLikeOutput(config);
+ if (ssr) {
+ return config.build.server;
+ } else {
+ return getOutDirWithinCwd(config.outDir);
+ }
+}
diff --git a/packages/astro/src/runtime/README.md b/packages/astro/src/runtime/README.md
index a11a98d8c..68225fed1 100644
--- a/packages/astro/src/runtime/README.md
+++ b/packages/astro/src/runtime/README.md
@@ -4,5 +4,6 @@ Code that executes within isolated contexts:
- `client/`: executes within the browser. Astro’s client-side partial hydration code lives here, and only browser-compatible code can be used.
- `server/`: executes inside Vite SSR. Though also a Node context, this is isolated from code in `core/`.
+- `compiler/`: same as `server/`, but only used by the Astro compiler `internalURL` option.
[See CONTRIBUTING.md](../../../../CONTRIBUTING.md) for a code overview.
diff --git a/packages/astro/src/runtime/compiler/index.ts b/packages/astro/src/runtime/compiler/index.ts
new file mode 100644
index 000000000..a5c238b68
--- /dev/null
+++ b/packages/astro/src/runtime/compiler/index.ts
@@ -0,0 +1,20 @@
+// NOTE: Although this entrypoint is exported, it is internal API and may change at any time.
+
+export {
+ Fragment,
+ render,
+ createAstro,
+ createComponent,
+ renderComponent,
+ renderHead,
+ maybeRenderHead,
+ unescapeHTML,
+ renderSlot,
+ mergeSlots,
+ addAttribute,
+ renderTransition,
+ createTransitionScope,
+ spreadAttributes,
+ defineStyleVars,
+ defineScriptVars,
+} from '../server/index.js';
diff --git a/packages/astro/src/runtime/server/endpoint.ts b/packages/astro/src/runtime/server/endpoint.ts
index c56ab7646..89c35957c 100644
--- a/packages/astro/src/runtime/server/endpoint.ts
+++ b/packages/astro/src/runtime/server/endpoint.ts
@@ -1,28 +1,56 @@
import type { APIContext, EndpointHandler, Params } from '../../@types/astro';
+import { type LogOptions, warn } from '../../core/logger/core.js';
-function getHandlerFromModule(mod: EndpointHandler, method: string) {
+function getHandlerFromModule(mod: EndpointHandler, method: string, logging: LogOptions) {
+ const lowerCaseMethod = method.toLowerCase();
+
+ // TODO: remove in Astro 4.0
+ if (mod[lowerCaseMethod]) {
+ warn(
+ logging,
+ 'astro',
+ `Lower case endpoint names are deprecated and will not be supported in Astro 4.0. Rename the endpoint ${lowerCaseMethod} to ${method}.`
+ );
+ }
// If there was an exact match on `method`, return that function.
if (mod[method]) {
return mod[method];
}
+
+ // TODO: remove in Astro 4.0
+ if (mod[lowerCaseMethod]) {
+ return mod[lowerCaseMethod];
+ }
+ // TODO: remove in Astro 4.0
// Handle `del` instead of `delete`, since `delete` is a reserved word in JS.
if (method === 'delete' && mod['del']) {
return mod['del'];
}
+ // TODO: remove in Astro 4.0
// If a single `all` handler was used, return that function.
if (mod['all']) {
return mod['all'];
}
+ if (mod['ALL']) {
+ return mod['ALL'];
+ }
// Otherwise, no handler found.
return undefined;
}
/** Renders an endpoint request to completion, returning the body. */
-export async function renderEndpoint(mod: EndpointHandler, context: APIContext, ssr: boolean) {
- const { request, params } = context;
- const chosenMethod = request.method?.toLowerCase();
- const handler = getHandlerFromModule(mod, chosenMethod);
- if (!ssr && ssr === false && chosenMethod && chosenMethod !== 'get') {
+export async function renderEndpoint(
+ mod: EndpointHandler,
+ context: APIContext,
+ ssr: boolean,
+ logging: LogOptions
+) {
+ const { request } = context;
+
+ const chosenMethod = request.method?.toUpperCase();
+ const handler = getHandlerFromModule(mod, chosenMethod, logging);
+ // TODO: remove the 'get' check in Astro 4.0
+ if (!ssr && ssr === false && chosenMethod && chosenMethod !== 'GET' && chosenMethod !== 'get') {
// eslint-disable-next-line no-console
console.warn(`
${chosenMethod} requests are not available when building a static site. Update your config to \`output: 'server'\` or \`output: 'hybrid'\` with an \`export const prerender = false\` to handle ${chosenMethod} requests.`);
@@ -40,35 +68,10 @@ ${chosenMethod} requests are not available when building a static site. Update y
return response;
}
- // TODO: Remove support for old API in Astro 3.0
- if (handler.length > 1) {
- // eslint-disable-next-line no-console
- console.warn(`
-API routes with 2 arguments have been deprecated. Instead they take a single argument in the form of:
-
-export function get({ params, request }) {
- //...
-}
-
-Update your code to remove this warning.`);
- }
-
const proxy = new Proxy(context, {
get(target, prop) {
if (prop in target) {
return Reflect.get(target, prop);
- } else if (prop in params) {
- // TODO: Remove support for old API in Astro 3.0
- // eslint-disable-next-line no-console
- console.warn(`
-API routes no longer pass params as the first argument. Instead an object containing a params property is provided in the form of:
-
-export function get({ params }) {
- // ...
-}
-
-Update your code to remove this warning.`);
- return Reflect.get(params, prop);
} else {
return undefined;
}
diff --git a/packages/astro/src/runtime/server/index.ts b/packages/astro/src/runtime/server/index.ts
index 5d4697bc7..81d05987a 100644
--- a/packages/astro/src/runtime/server/index.ts
+++ b/packages/astro/src/runtime/server/index.ts
@@ -1,3 +1,5 @@
+// NOTE: Although this entrypoint is exported, it is internal API and may change at any time.
+
export { createComponent } from './astro-component.js';
export { createAstro } from './astro-global.js';
export { renderEndpoint } from './endpoint.js';
diff --git a/packages/astro/src/runtime/server/render/page.ts b/packages/astro/src/runtime/server/render/page.ts
index cabbe8dae..74e8a45b7 100644
--- a/packages/astro/src/runtime/server/render/page.ts
+++ b/packages/astro/src/runtime/server/render/page.ts
@@ -2,7 +2,6 @@ import type { RouteData, SSRResult } from '../../../@types/astro';
import { renderComponentToString, type NonAstroPageComponent } from './component.js';
import type { AstroComponentFactory } from './index';
-import { createResponse } from '../response.js';
import { isAstroComponentFactory } from './astro/index.js';
import { renderToReadableStream, renderToString } from './astro/render.js';
import { encoder } from './common.js';
@@ -64,6 +63,6 @@ export async function renderPage(
body = encoder.encode(body);
headers.set('Content-Length', body.byteLength.toString());
}
- const response = createResponse(body, { ...init, headers });
+ const response = new Response(body, { ...init, headers });
return response;
}
diff --git a/packages/astro/src/runtime/server/render/util.ts b/packages/astro/src/runtime/server/render/util.ts
index e007fe6f1..f6a3f4191 100644
--- a/packages/astro/src/runtime/server/render/util.ts
+++ b/packages/astro/src/runtime/server/render/util.ts
@@ -29,10 +29,6 @@ const toStyleString = (obj: Record<string, any>) =>
Object.entries(obj)
.map(([k, v]) => {
if (k[0] !== '-' && k[1] !== '-') return `${kebab(k)}:${v}`;
- // TODO: Remove in v3! See #6264
- // We need to emit --kebab-case AND --camelCase for backwards-compat in v2,
- // but we should be able to remove this workaround in v3.
- if (kebab(k) !== k) return `${kebab(k)}:var(${k});${k}:${v}`;
return `${k}:${v}`;
})
.join(';');
diff --git a/packages/astro/src/runtime/server/response.ts b/packages/astro/src/runtime/server/response.ts
deleted file mode 100644
index bcfda19aa..000000000
--- a/packages/astro/src/runtime/server/response.ts
+++ /dev/null
@@ -1,80 +0,0 @@
-import { streamAsyncIterator } from './util.js';
-
-const isNodeJS =
- typeof process === 'object' && Object.prototype.toString.call(process) === '[object process]';
-
-let StreamingCompatibleResponse: typeof Response | undefined;
-
-function createResponseClass() {
- StreamingCompatibleResponse = class extends Response {
- #isStream: boolean;
- #body: any;
- constructor(body?: BodyInit | null, init?: ResponseInit) {
- let isStream = body instanceof ReadableStream;
- super(isStream ? null : body, init);
- this.#isStream = isStream;
- this.#body = body;
- }
-
- get body() {
- return this.#body;
- }
-
- async text(): Promise<string> {
- if (this.#isStream && isNodeJS) {
- let decoder = new TextDecoder();
- let body = this.#body;
- let out = '';
- for await (let chunk of streamAsyncIterator(body)) {
- out += decoder.decode(chunk);
- }
- return out;
- }
- return super.text();
- }
-
- async arrayBuffer(): Promise<ArrayBuffer> {
- if (this.#isStream && isNodeJS) {
- let body = this.#body;
- let chunks: Uint8Array[] = [];
- let len = 0;
- for await (let chunk of streamAsyncIterator(body)) {
- chunks.push(chunk);
- len += chunk.length;
- }
- let ab = new Uint8Array(len);
- let offset = 0;
- for (const chunk of chunks) {
- ab.set(chunk, offset);
- offset += chunk.length;
- }
- return ab;
- }
- return super.arrayBuffer();
- }
-
- clone() {
- return new StreamingCompatibleResponse!(this.#body, {
- status: this.status,
- statusText: this.statusText,
- headers: this.headers,
- });
- }
- };
-
- return StreamingCompatibleResponse;
-}
-
-type CreateResponseFn = (body?: BodyInit | null, init?: ResponseInit) => Response;
-
-export const createResponse: CreateResponseFn = isNodeJS
- ? (body, init) => {
- if (typeof body === 'string' || ArrayBuffer.isView(body)) {
- return new Response(body, init);
- }
- if (typeof StreamingCompatibleResponse === 'undefined') {
- return new (createResponseClass())(body, init);
- }
- return new StreamingCompatibleResponse(body, init);
- }
- : (body, init) => new Response(body, init);
diff --git a/packages/astro/src/vite-plugin-astro-postprocess/index.ts b/packages/astro/src/vite-plugin-astro-postprocess/index.ts
index 9a2e185af..39acd000c 100644
--- a/packages/astro/src/vite-plugin-astro-postprocess/index.ts
+++ b/packages/astro/src/vite-plugin-astro-postprocess/index.ts
@@ -1,4 +1,5 @@
import { parse } from 'acorn';
+import type { Node as ESTreeNode } from 'estree-walker';
import { walk } from 'estree-walker';
import MagicString from 'magic-string';
import type { Plugin } from 'vite';
@@ -28,7 +29,7 @@ export default function astro(): Plugin {
sourceType: 'module',
});
- walk(ast, {
+ walk(ast as ESTreeNode, {
enter(node: any) {
// Transform `Astro.glob("./pages/*.astro")` to `Astro.glob(import.meta.glob("./pages/*.astro"), () => "./pages/*.astro")`
// Also handle for `Astro2.glob()`
diff --git a/packages/astro/src/vite-plugin-astro-server/environment.ts b/packages/astro/src/vite-plugin-astro-server/environment.ts
index bcf783bf2..ce7b92662 100644
--- a/packages/astro/src/vite-plugin-astro-server/environment.ts
+++ b/packages/astro/src/vite-plugin-astro-server/environment.ts
@@ -17,7 +17,6 @@ export function createDevelopmentEnvironment(
let env = createEnvironment({
adapterName: manifest.adapterName,
logging,
- markdown: manifest.markdown,
mode,
// This will be overridden in the dev server
renderers: [],
diff --git a/packages/astro/src/vite-plugin-astro-server/plugin.ts b/packages/astro/src/vite-plugin-astro-server/plugin.ts
index 8f74bd47a..dfaf976bf 100644
--- a/packages/astro/src/vite-plugin-astro-server/plugin.ts
+++ b/packages/astro/src/vite-plugin-astro-server/plugin.ts
@@ -91,7 +91,6 @@ export function createDevelopmentManifest(settings: AstroSettings): SSRManifest
entryModules: {},
routes: [],
adapterName: '',
- markdown: settings.config.markdown,
clientDirectives: settings.clientDirectives,
renderers: [],
base: settings.config.base,
diff --git a/packages/astro/src/vite-plugin-astro-server/request.ts b/packages/astro/src/vite-plugin-astro-server/request.ts
index b641503a6..ae476f9be 100644
--- a/packages/astro/src/vite-plugin-astro-server/request.ts
+++ b/packages/astro/src/vite-plugin-astro-server/request.ts
@@ -48,7 +48,7 @@ export async function handleRequest({
// Add config.base back to url before passing it to SSR
url.pathname = removeTrailingForwardSlash(config.base) + url.pathname;
- // HACK! @astrojs/image uses query params for the injected route in `dev`
+ // HACK! astro:assets uses query params for the injected route in `dev`
if (!buildingToSSR && pathname !== '/_image') {
// Prevent user from depending on search params when not doing SSR.
// NOTE: Create an array copy here because deleting-while-iterating
diff --git a/packages/astro/src/vite-plugin-astro-server/route.ts b/packages/astro/src/vite-plugin-astro-server/route.ts
index f58d248a3..0bbaacbe2 100644
--- a/packages/astro/src/vite-plugin-astro-server/route.ts
+++ b/packages/astro/src/vite-plugin-astro-server/route.ts
@@ -8,7 +8,7 @@ import type {
SSRElement,
SSRManifest,
} from '../@types/astro';
-import { attachToResponse } from '../core/cookies/index.js';
+import { attachCookiesToResponse } from '../core/cookies/index.js';
import { AstroErrorData, isAstroError } from '../core/errors/index.js';
import { warn } from '../core/logger/core.js';
import { loadMiddleware } from '../core/middleware/loadMiddleware.js';
@@ -49,18 +49,18 @@ export interface MatchedRoute {
mod: ComponentInstance;
}
-function getCustom404Route(manifest: ManifestData): RouteData | undefined {
+function getCustom404Route(manifestData: ManifestData): RouteData | undefined {
const route404 = /^\/404\/?$/;
- return manifest.routes.find((r) => route404.test(r.route));
+ return manifestData.routes.find((r) => route404.test(r.route));
}
export async function matchRoute(
pathname: string,
env: DevelopmentEnvironment,
- manifest: ManifestData
+ manifestData: ManifestData
): Promise<MatchedRoute | undefined> {
const { logging, settings, routeCache } = env;
- const matches = matchAllRoutes(pathname, manifest);
+ const matches = matchAllRoutes(pathname, manifestData);
const preloadedMatches = await getSortedPreloadedMatches({ env, matches, settings });
for await (const { preloadedComponent, route: maybeRoute, filePath } of preloadedMatches) {
@@ -96,7 +96,7 @@ export async function matchRoute(
// build formats, and is necessary based on how the manifest tracks build targets.
const altPathname = pathname.replace(/(index)?\.html$/, '');
if (altPathname !== pathname) {
- return await matchRoute(altPathname, env, manifest);
+ return await matchRoute(altPathname, env, manifestData);
}
if (matches.length) {
@@ -112,7 +112,7 @@ export async function matchRoute(
}
log404(logging, pathname);
- const custom404 = getCustom404Route(manifest);
+ const custom404 = getCustom404Route(manifestData);
if (custom404) {
const filePath = new URL(`./${custom404.component}`, settings.config.root);
@@ -216,7 +216,7 @@ export async function handleRoute({
});
const onRequest = options.middleware?.onRequest as MiddlewareResponseHandler | undefined;
- const result = await tryRenderRoute(route.type, renderContext, env, mod, onRequest);
+ const result = await tryRenderRoute(renderContext, env, mod, onRequest);
if (isEndpointResult(result, route.type)) {
if (result.type === 'response') {
if (result.response.headers.get('X-Astro-Response') === 'Not-Found') {
@@ -255,7 +255,7 @@ export async function handleRoute({
},
}
);
- attachToResponse(response, result.cookies);
+ attachCookiesToResponse(response, result.cookies);
await writeWebResponse(incomingResponse, response);
}
} else {
diff --git a/packages/astro/src/vite-plugin-head/index.ts b/packages/astro/src/vite-plugin-head/index.ts
index 9cfdc739f..ca95a334e 100644
--- a/packages/astro/src/vite-plugin-head/index.ts
+++ b/packages/astro/src/vite-plugin-head/index.ts
@@ -16,7 +16,7 @@ export default function configHeadVitePlugin(): vite.Plugin {
function propagateMetadata<
P extends keyof PluginMetadata['astro'],
- V extends PluginMetadata['astro'][P]
+ V extends PluginMetadata['astro'][P],
>(
this: { getModuleInfo(id: string): ModuleInfo | null },
id: string,
diff --git a/packages/astro/src/vite-plugin-inject-env-ts/index.ts b/packages/astro/src/vite-plugin-inject-env-ts/index.ts
index 9c2874fb9..0f0fbb86d 100644
--- a/packages/astro/src/vite-plugin-inject-env-ts/index.ts
+++ b/packages/astro/src/vite-plugin-inject-env-ts/index.ts
@@ -50,26 +50,6 @@ export async function setUpEnvTs({
if (fs.existsSync(envTsPath)) {
let typesEnvContents = await fs.promises.readFile(envTsPath, 'utf-8');
- // TODO: Remove this logic in 3.0, as `astro/client-image` will be merged into `astro/client`
- if (settings.config.experimental.assets && typesEnvContents.includes('types="astro/client"')) {
- typesEnvContents = typesEnvContents.replace(
- 'types="astro/client"',
- 'types="astro/client-image"'
- );
- await fs.promises.writeFile(envTsPath, typesEnvContents, 'utf-8');
- info(logging, 'assets', `Added ${bold(envTsPathRelativetoRoot)} types`);
- } else if (
- !settings.config.experimental.assets &&
- typesEnvContents.includes('types="astro/client-image"')
- ) {
- typesEnvContents = typesEnvContents.replace(
- 'types="astro/client-image"',
- 'types="astro/client"'
- );
- await fs.promises.writeFile(envTsPath, typesEnvContents, 'utf-8');
- info(logging, 'assets', `Removed ${bold(envTsPathRelativetoRoot)} types`);
- }
-
if (!fs.existsSync(dotAstroDir))
// Add `.astro` types reference if none exists
return;
@@ -83,13 +63,7 @@ export async function setUpEnvTs({
} else {
// Otherwise, inject the `env.d.ts` file
let referenceDefs: string[] = [];
- if (settings.config.experimental.assets) {
- referenceDefs.push('/// <reference types="astro/client-image" />');
- } else if (settings.config.integrations.find((i) => i.name === '@astrojs/image')) {
- referenceDefs.push('/// <reference types="@astrojs/image/client" />');
- } else {
- referenceDefs.push('/// <reference types="astro/client" />');
- }
+ referenceDefs.push('/// <reference types="astro/client" />');
if (fs.existsSync(dotAstroDir)) {
referenceDefs.push(dotAstroTypeReference);
diff --git a/packages/astro/src/vite-plugin-jsx/index.ts b/packages/astro/src/vite-plugin-jsx/index.ts
deleted file mode 100644
index 7aa7e7b16..000000000
--- a/packages/astro/src/vite-plugin-jsx/index.ts
+++ /dev/null
@@ -1,251 +0,0 @@
-import type { TransformResult } from 'rollup';
-import {
- transformWithEsbuild,
- type EsbuildTransformOptions,
- type Plugin,
- type ResolvedConfig,
-} from 'vite';
-import type { AstroRenderer, AstroSettings } from '../@types/astro';
-import type { LogOptions } from '../core/logger/core.js';
-import type { PluginMetadata } from '../vite-plugin-astro/types';
-
-import babel from '@babel/core';
-import * as colors from 'kleur/colors';
-import path from 'node:path';
-import { CONTENT_FLAG, PROPAGATED_ASSET_FLAG } from '../content/index.js';
-import { astroEntryPrefix } from '../core/build/plugins/plugin-component-entry.js';
-import { error } from '../core/logger/core.js';
-import { removeQueryString } from '../core/path.js';
-import { detectImportSource } from './import-source.js';
-import tagExportsPlugin from './tag.js';
-
-const JSX_EXTENSIONS = new Set(['.jsx', '.tsx', '.mdx']);
-const IMPORT_STATEMENTS: Record<string, string> = {
- react: "import React from 'react'",
- preact: "import { h } from 'preact'",
- 'solid-js': "import 'solid-js'",
- astro: "import 'astro/jsx-runtime'",
-};
-
-function getEsbuildLoader(filePath: string): EsbuildTransformOptions['loader'] {
- const fileExt = path.extname(filePath);
- if (fileExt === '.mdx') return 'jsx';
- return fileExt.slice(1) as EsbuildTransformOptions['loader'];
-}
-
-function collectJSXRenderers(renderers: AstroRenderer[]): Map<string, AstroRenderer> {
- const renderersWithJSXSupport = renderers.filter((r) => r.jsxImportSource);
- return new Map(
- renderersWithJSXSupport.map((r) => [r.jsxImportSource, r] as [string, AstroRenderer])
- );
-}
-
-interface TransformJSXOptions {
- code: string;
- id: string;
- mode: string;
- renderer: AstroRenderer;
- ssr: boolean;
- root: URL;
-}
-
-async function transformJSX({
- code,
- mode,
- id,
- ssr,
- renderer,
- root,
-}: TransformJSXOptions): Promise<TransformResult> {
- const { jsxTransformOptions } = renderer;
- const options = await jsxTransformOptions!({ mode, ssr });
- const plugins = [...(options.plugins || [])];
- if (ssr) {
- plugins.push(await tagExportsPlugin({ rendererName: renderer.name, root }));
- }
- const result = await babel.transformAsync(code, {
- presets: options.presets,
- plugins,
- cwd: process.cwd(),
- filename: id,
- ast: false,
- compact: false,
- sourceMaps: true,
- configFile: false,
- babelrc: false,
- inputSourceMap: options.inputSourceMap,
- });
- // TODO: Be more strict about bad return values here.
- // Should we throw an error instead? Should we never return `{code: ""}`?
- if (!result) return null;
-
- if (renderer.name === 'astro:jsx') {
- const { astro } = result.metadata as unknown as PluginMetadata;
- return {
- code: result.code || '',
- map: result.map,
- meta: {
- astro,
- vite: {
- // Setting this vite metadata to `ts` causes Vite to resolve .js
- // extensions to .ts files.
- lang: 'ts',
- },
- },
- };
- }
-
- return {
- code: result.code || '',
- map: result.map,
- };
-}
-
-interface AstroPluginJSXOptions {
- settings: AstroSettings;
- logging: LogOptions;
-}
-
-// Format inspired by https://github.com/vitejs/vite/blob/main/packages/vite/src/node/constants.ts#L54
-const SPECIAL_QUERY_REGEX = new RegExp(
- `[?&](?:worker|sharedworker|raw|url|${CONTENT_FLAG}|${PROPAGATED_ASSET_FLAG})\\b`
-);
-
-/** Use Astro config to allow for alternate or multiple JSX renderers (by default Vite will assume React) */
-export default function jsx({ settings, logging }: AstroPluginJSXOptions): Plugin {
- let viteConfig: ResolvedConfig;
- const jsxRenderers = new Map<string, AstroRenderer>();
- const jsxRenderersIntegrationOnly = new Map<string, AstroRenderer>();
- // A reference to Astro's internal JSX renderer.
- let astroJSXRenderer: AstroRenderer;
- // The first JSX renderer provided is considered the default renderer.
- // This is a useful reference for when the user only gives a single render.
- let defaultJSXRendererEntry: [string, AstroRenderer] | undefined;
-
- return {
- name: 'astro:jsx',
- enforce: 'pre', // run transforms before other plugins
- async configResolved(resolvedConfig) {
- viteConfig = resolvedConfig;
- const possibleRenderers = collectJSXRenderers(settings.renderers);
- for (const [importSource, renderer] of possibleRenderers) {
- jsxRenderers.set(importSource, renderer);
- if (importSource === 'astro') {
- astroJSXRenderer = renderer;
- } else {
- jsxRenderersIntegrationOnly.set(importSource, renderer);
- }
- }
- defaultJSXRendererEntry = [...jsxRenderersIntegrationOnly.entries()][0];
- },
- async transform(code, id, opts) {
- const ssr = Boolean(opts?.ssr);
- // Skip special queries and astro entries. We skip astro entries here as we know it doesn't contain
- // JSX code, and also because we can't detect the import source to apply JSX transforms.
- if (SPECIAL_QUERY_REGEX.test(id) || id.startsWith(astroEntryPrefix)) {
- return null;
- }
- id = removeQueryString(id);
- if (!JSX_EXTENSIONS.has(path.extname(id))) {
- return null;
- }
-
- const { mode } = viteConfig;
- // Shortcut: only use Astro renderer for MD and MDX files
- if (id.endsWith('.mdx')) {
- const { code: jsxCode } = await transformWithEsbuild(code, id, {
- loader: getEsbuildLoader(id),
- jsx: 'preserve',
- sourcemap: 'inline',
- tsconfigRaw: {
- compilerOptions: {
- // Ensure client:only imports are treeshaken
- verbatimModuleSyntax: false,
- importsNotUsedAsValues: 'remove',
- },
- },
- });
- return transformJSX({
- code: jsxCode,
- id,
- renderer: astroJSXRenderer,
- mode,
- ssr,
- root: settings.config.root,
- });
- }
- if (defaultJSXRendererEntry && jsxRenderersIntegrationOnly.size === 1) {
- // downlevel any non-standard syntax, but preserve JSX
- const { code: jsxCode } = await transformWithEsbuild(code, id, {
- loader: getEsbuildLoader(id),
- jsx: 'preserve',
- sourcemap: 'inline',
- });
- return transformJSX({
- code: jsxCode,
- id,
- renderer: defaultJSXRendererEntry[1],
- mode,
- ssr,
- root: settings.config.root,
- });
- }
-
- const importSource = await detectImportSource(code, jsxRenderers, settings.tsConfig);
-
- // if we still can’t tell the import source, now is the time to throw an error.
- if (!importSource && defaultJSXRendererEntry) {
- const [defaultRendererName] = defaultJSXRendererEntry;
- error(
- logging,
- 'renderer',
- `${colors.yellow(id)}
-Unable to resolve a renderer that handles this file! With more than one renderer enabled, you should include an import or use a pragma comment.
-Add ${colors.cyan(
- IMPORT_STATEMENTS[defaultRendererName] || `import '${defaultRendererName}';`
- )} or ${colors.cyan(`/** @jsxImportSource: ${defaultRendererName} */`)} to this file.
-`
- );
- return null;
- } else if (!importSource) {
- error(
- logging,
- 'renderer',
- `${colors.yellow(id)}
-Unable to find a renderer for JSX. Do you have one configured in your Astro config? See this page to learn how:
-https://docs.astro.build/en/core-concepts/framework-components/#installing-integrations
-`
- );
- return null;
- }
-
- const selectedJsxRenderer = jsxRenderers.get(importSource);
- // if the renderer is not installed for this JSX source, throw error
- if (!selectedJsxRenderer) {
- error(
- logging,
- 'renderer',
- `${colors.yellow(
- id
- )} No renderer installed for ${importSource}. Try adding \`@astrojs/${importSource}\` to your project.`
- );
- return null;
- }
-
- // downlevel any non-standard syntax, but preserve JSX
- const { code: jsxCode } = await transformWithEsbuild(code, id, {
- loader: getEsbuildLoader(id),
- jsx: 'preserve',
- sourcemap: 'inline',
- });
- return await transformJSX({
- code: jsxCode,
- id,
- renderer: selectedJsxRenderer,
- mode,
- ssr,
- root: settings.config.root,
- });
- },
- };
-}
diff --git a/packages/astro/src/vite-plugin-markdown/index.ts b/packages/astro/src/vite-plugin-markdown/index.ts
index dd2cbcd85..ae26bfb42 100644
--- a/packages/astro/src/vite-plugin-markdown/index.ts
+++ b/packages/astro/src/vite-plugin-markdown/index.ts
@@ -49,11 +49,6 @@ function safeMatter(source: string, id: string) {
}
}
-// absolute path of "astro/jsx-runtime"
-const astroJsxRuntimeModulePath = normalizePath(
- fileURLToPath(new URL('../jsx-runtime/index.js', import.meta.url))
-);
-
const astroServerRuntimeModulePath = normalizePath(
fileURLToPath(new URL('../runtime/server/index.js', import.meta.url))
);
@@ -80,7 +75,6 @@ export default function markdown({ settings, logging }: AstroPluginOptions): Plu
...settings.config.markdown,
fileURL: new URL(`file://${fileId}`),
frontmatter: raw.data,
- experimentalAssets: settings.config.experimental.assets,
});
let html = renderResult.code;
@@ -88,7 +82,7 @@ export default function markdown({ settings, logging }: AstroPluginOptions): Plu
// Resolve all the extracted images from the content
let imagePaths: { raw: string; resolved: string }[] = [];
- if (settings.config.experimental.assets && renderResult.vfile.data.imagePaths) {
+ if (renderResult.vfile.data.imagePaths) {
for (let imagePath of renderResult.vfile.data.imagePaths.values()) {
imagePaths.push({
raw: imagePath,
@@ -115,12 +109,13 @@ export default function markdown({ settings, logging }: AstroPluginOptions): Plu
}
const code = escapeViteEnvReferences(`
- import { Fragment, jsx as h } from ${JSON.stringify(astroJsxRuntimeModulePath)};
- import { spreadAttributes } from ${JSON.stringify(astroServerRuntimeModulePath)};
+ import { unescapeHTML, spreadAttributes, createComponent, render, renderComponent } from ${JSON.stringify(
+ astroServerRuntimeModulePath
+ )};
import { AstroError, AstroErrorData } from ${JSON.stringify(astroErrorModulePath)};
${layout ? `import Layout from ${JSON.stringify(layout)};` : ''}
- ${settings.config.experimental.assets ? 'import { getImage } from "astro:assets";' : ''}
+ import { getImage } from "astro:assets";
export const images = {
${imagePaths.map(
@@ -167,27 +162,29 @@ export default function markdown({ settings, logging }: AstroPluginOptions): Plu
export function getHeadings() {
return ${JSON.stringify(headings)};
}
- export async function Content() {
+
+ export const Content = createComponent((result, _props, slots) => {
const { layout, ...content } = frontmatter;
content.file = file;
content.url = url;
- const contentFragment = h(Fragment, { 'set:html': html });
+
return ${
layout
- ? `h(Layout, {
- file,
- url,
- content,
- frontmatter: content,
- headings: getHeadings(),
- rawContent,
- compiledContent,
- 'server:root': true,
- children: contentFragment
- })`
- : `contentFragment`
- };
- }
+ ? `render\`\${renderComponent(result, 'Layout', Layout, {
+ file,
+ url,
+ content,
+ frontmatter: content,
+ headings: getHeadings(),
+ rawContent,
+ compiledContent,
+ 'server:root': true,
+ }, {
+ 'default': () => render\`\${unescapeHTML(html)}\`
+ })}\`;`
+ : `render\`\${unescapeHTML(html)}\`;`
+ }
+ });
Content[Symbol.for('astro.needsHeadRendering')] = ${layout ? 'false' : 'true'};
export default Content;
`);
diff --git a/packages/astro/src/vite-plugin-jsx/README.md b/packages/astro/src/vite-plugin-mdx/README.md
index 554651869..554651869 100644
--- a/packages/astro/src/vite-plugin-jsx/README.md
+++ b/packages/astro/src/vite-plugin-mdx/README.md
diff --git a/packages/astro/src/vite-plugin-jsx/import-source.ts b/packages/astro/src/vite-plugin-mdx/import-source.ts
index c1f9ea6dc..c1f9ea6dc 100644
--- a/packages/astro/src/vite-plugin-jsx/import-source.ts
+++ b/packages/astro/src/vite-plugin-mdx/import-source.ts
diff --git a/packages/astro/src/vite-plugin-mdx/index.ts b/packages/astro/src/vite-plugin-mdx/index.ts
new file mode 100644
index 000000000..f2b068068
--- /dev/null
+++ b/packages/astro/src/vite-plugin-mdx/index.ts
@@ -0,0 +1,130 @@
+import type { TransformResult } from 'rollup';
+import { transformWithEsbuild, type Plugin, type ResolvedConfig } from 'vite';
+import type { AstroRenderer, AstroSettings } from '../@types/astro';
+import type { LogOptions } from '../core/logger/core.js';
+import type { PluginMetadata } from '../vite-plugin-astro/types';
+
+import babel from '@babel/core';
+import { CONTENT_FLAG, PROPAGATED_ASSET_FLAG } from '../content/index.js';
+import { astroEntryPrefix } from '../core/build/plugins/plugin-component-entry.js';
+import { removeQueryString } from '../core/path.js';
+import tagExportsPlugin from './tag.js';
+
+interface TransformJSXOptions {
+ code: string;
+ id: string;
+ mode: string;
+ renderer: AstroRenderer;
+ ssr: boolean;
+ root: URL;
+}
+
+async function transformJSX({
+ code,
+ mode,
+ id,
+ ssr,
+ renderer,
+ root,
+}: TransformJSXOptions): Promise<TransformResult> {
+ const { jsxTransformOptions } = renderer;
+ const options = await jsxTransformOptions!({ mode, ssr });
+ const plugins = [...(options.plugins || [])];
+ if (ssr) {
+ plugins.push(await tagExportsPlugin({ rendererName: renderer.name, root }));
+ }
+ const result = await babel.transformAsync(code, {
+ presets: options.presets,
+ plugins,
+ cwd: process.cwd(),
+ filename: id,
+ ast: false,
+ compact: false,
+ sourceMaps: true,
+ configFile: false,
+ babelrc: false,
+ inputSourceMap: options.inputSourceMap,
+ });
+ // TODO: Be more strict about bad return values here.
+ // Should we throw an error instead? Should we never return `{code: ""}`?
+ if (!result) return null;
+
+ if (renderer.name === 'astro:jsx') {
+ const { astro } = result.metadata as unknown as PluginMetadata;
+ return {
+ code: result.code || '',
+ map: result.map,
+ meta: {
+ astro,
+ vite: {
+ // Setting this vite metadata to `ts` causes Vite to resolve .js
+ // extensions to .ts files.
+ lang: 'ts',
+ },
+ },
+ };
+ }
+
+ return {
+ code: result.code || '',
+ map: result.map,
+ };
+}
+
+interface AstroPluginJSXOptions {
+ settings: AstroSettings;
+ logging: LogOptions;
+}
+
+// Format inspired by https://github.com/vitejs/vite/blob/main/packages/vite/src/node/constants.ts#L54
+const SPECIAL_QUERY_REGEX = new RegExp(
+ `[?&](?:worker|sharedworker|raw|url|${CONTENT_FLAG}|${PROPAGATED_ASSET_FLAG})\\b`
+);
+
+/** Use Astro config to allow for alternate or multiple JSX renderers (by default Vite will assume React) */
+export default function mdxVitePlugin({ settings }: AstroPluginJSXOptions): Plugin {
+ let viteConfig: ResolvedConfig;
+ // A reference to Astro's internal JSX renderer.
+ let astroJSXRenderer: AstroRenderer;
+
+ return {
+ name: 'astro:jsx',
+ enforce: 'pre', // run transforms before other plugins
+ async configResolved(resolvedConfig) {
+ viteConfig = resolvedConfig;
+ astroJSXRenderer = settings.renderers.find((r) => r.jsxImportSource === 'astro')!;
+ },
+ async transform(code, id, opts) {
+ // Skip special queries and astro entries. We skip astro entries here as we know it doesn't contain
+ // JSX code, and also because we can't detect the import source to apply JSX transforms.
+ if (SPECIAL_QUERY_REGEX.test(id) || id.startsWith(astroEntryPrefix)) {
+ return null;
+ }
+ id = removeQueryString(id);
+ // Shortcut: only use Astro renderer for MD and MDX files
+ if (!id.endsWith('.mdx')) {
+ return null;
+ }
+ const { code: jsxCode } = await transformWithEsbuild(code, id, {
+ loader: 'jsx',
+ jsx: 'preserve',
+ sourcemap: 'inline',
+ tsconfigRaw: {
+ compilerOptions: {
+ // Ensure client:only imports are treeshaken
+ verbatimModuleSyntax: false,
+ importsNotUsedAsValues: 'remove',
+ },
+ },
+ });
+ return transformJSX({
+ code: jsxCode,
+ id,
+ renderer: astroJSXRenderer,
+ mode: viteConfig.mode,
+ ssr: Boolean(opts?.ssr),
+ root: settings.config.root,
+ });
+ },
+ };
+}
diff --git a/packages/astro/src/vite-plugin-jsx/tag.ts b/packages/astro/src/vite-plugin-mdx/tag.ts
index 5efc4c41f..b7ae1f2c4 100644
--- a/packages/astro/src/vite-plugin-jsx/tag.ts
+++ b/packages/astro/src/vite-plugin-mdx/tag.ts
@@ -18,7 +18,7 @@ export default async function tagExportsWithRenderer({
return {
visitor: {
Program: {
- // Inject `import { __astro_tag_component__ } from 'astro/server/index.js'`
+ // Inject `import { __astro_tag_component__ } from 'astro/runtime/server/index.js'`
enter(path) {
path.node.body.splice(
0,
@@ -30,7 +30,7 @@ export default async function tagExportsWithRenderer({
t.identifier('__astro_tag_component__')
),
],
- t.stringLiteral('astro/server/index.js')
+ t.stringLiteral('astro/runtime/server/index.js')
)
);
},
diff --git a/packages/astro/test/0-css.test.js b/packages/astro/test/0-css.test.js
index 76bfba296..9a05074fb 100644
--- a/packages/astro/test/0-css.test.js
+++ b/packages/astro/test/0-css.test.js
@@ -39,15 +39,27 @@ describe('CSS', function () {
it('HTML and CSS scoped correctly', async () => {
const el1 = $('#dynamic-class');
const el2 = $('#dynamic-vis');
- const classes = $('#class').attr('class').split(' ');
- const scopedClass = classes.find((name) => /^astro-[A-Za-z0-9-]+/.test(name));
+ const classes = $('#class');
+ let scopedAttribute;
+ for (const [key] of Object.entries(classes[0].attribs)) {
+ if (/^data-astro-cid-[A-Za-z0-9-]+/.test(key)) {
+ // Ema: this is ugly, but for reasons that I don't want to explore, cheerio
+ // lower case the hash of the attribute
+ scopedAttribute = key
+ .toUpperCase()
+ .replace('data-astro-cid-'.toUpperCase(), 'data-astro-cid-');
+ }
+ }
+ if (!scopedAttribute) {
+ throw new Error("Couldn't find scoped attribute");
+ }
// 1. check HTML
- expect(el1.attr('class')).to.equal(`blue ${scopedClass}`);
- expect(el2.attr('class')).to.equal(`visible ${scopedClass}`);
+ expect(el1.attr('class')).to.equal(`blue`);
+ expect(el2.attr('class')).to.equal(`visible`);
// 2. check CSS
- const expected = `.blue:where(.${scopedClass}){color:#b0e0e6}.color\\:blue:where(.${scopedClass}){color:#b0e0e6}.visible:where(.${scopedClass}){display:block}`;
+ const expected = `.blue[${scopedAttribute}],.color\\:blue[${scopedAttribute}]{color:#b0e0e6}.visible[${scopedAttribute}]{display:block}`;
expect(bundledCSS).to.include(expected);
});
@@ -60,8 +72,12 @@ describe('CSS', function () {
expect($('#no-scope').attr('class')).to.equal(undefined);
});
- it('Child inheritance', async () => {
- expect($('#passed-in').attr('class')).to.match(/outer astro-[A-Z0-9]+ astro-[A-Z0-9]+/);
+ it('Child inheritance', (done) => {
+ for (const [key] of Object.entries($('#passed-in')[0].attribs)) {
+ if (/^data-astro-cid-[A-Za-z0-9-]+/.test(key)) {
+ done();
+ }
+ }
});
it('Using hydrated components adds astro-island styles', async () => {
@@ -70,11 +86,11 @@ describe('CSS', function () {
});
it('<style lang="sass">', async () => {
- expect(bundledCSS).to.match(new RegExp('h1\\:where\\(.astro-[^{]*{color:#90ee90}'));
+ expect(bundledCSS).to.match(new RegExp('h1\\[data-astro-cid-[^{]*{color:#90ee90}'));
});
it('<style lang="scss">', async () => {
- expect(bundledCSS).to.match(new RegExp('h1\\:where\\(.astro-[^{]*{color:#ff69b4}'));
+ expect(bundledCSS).to.match(new RegExp('h1\\[data-astro-cid-[^{]*{color:#ff69b4}'));
});
});
@@ -331,10 +347,10 @@ describe('CSS', function () {
it('resolves Astro styles', async () => {
const allInjectedStyles = $('style').text();
- expect(allInjectedStyles).to.contain('.linked-css:where(.astro-');
- expect(allInjectedStyles).to.contain('.linked-sass:where(.astro-');
- expect(allInjectedStyles).to.contain('.linked-scss:where(.astro-');
- expect(allInjectedStyles).to.contain('.wrapper:where(.astro-');
+ expect(allInjectedStyles).to.contain('.linked-css[data-astro-cid-');
+ expect(allInjectedStyles).to.contain('.linked-sass[data-astro-cid-');
+ expect(allInjectedStyles).to.contain('.linked-scss[data-astro-cid-');
+ expect(allInjectedStyles).to.contain('.wrapper[data-astro-cid-');
});
it('resolves Styles from React', async () => {
diff --git a/packages/astro/test/astro-assets-prefix.test.js b/packages/astro/test/astro-assets-prefix.test.js
index 40562afd4..ab42439ae 100644
--- a/packages/astro/test/astro-assets-prefix.test.js
+++ b/packages/astro/test/astro-assets-prefix.test.js
@@ -63,7 +63,7 @@ describe('Assets Prefix - Static', () => {
});
});
-describe('Assets Prefix - Static with path prefix', () => {
+describe('Assets Prefix - with path prefix', () => {
let fixture;
before(async () => {
@@ -86,7 +86,7 @@ describe('Assets Prefix - Static with path prefix', () => {
});
});
-describe('Assets Prefix - Server', () => {
+describe('Assets Prefix, server', () => {
let app;
before(async () => {
@@ -143,7 +143,7 @@ describe('Assets Prefix - Server', () => {
});
});
-describe('Assets Prefix - Server with path prefix', () => {
+describe('Assets Prefix, with path prefix', () => {
let app;
before(async () => {
diff --git a/packages/astro/test/astro-envs.test.js b/packages/astro/test/astro-envs.test.js
index 402878da5..c923ae065 100644
--- a/packages/astro/test/astro-envs.test.js
+++ b/packages/astro/test/astro-envs.test.js
@@ -109,7 +109,7 @@ describe('Environment Variables', () => {
expect(res.status).to.equal(200);
let indexHtml = await res.text();
let $ = cheerio.load(indexHtml);
- expect($('#base-url').text()).to.equal('/blog/');
+ expect($('#base-url').text()).to.equal('/blog');
});
it('does render destructured builtin SITE env', async () => {
@@ -117,7 +117,7 @@ describe('Environment Variables', () => {
expect(res.status).to.equal(200);
let indexHtml = await res.text();
let $ = cheerio.load(indexHtml);
- expect($('#base-url').text()).to.equal('/blog/');
+ expect($('#base-url').text()).to.equal('/blog');
});
});
});
diff --git a/packages/astro/test/astro-external-files.test.js b/packages/astro/test/astro-external-files.test.js
index 397f31785..7aaf04c80 100644
--- a/packages/astro/test/astro-external-files.test.js
+++ b/packages/astro/test/astro-external-files.test.js
@@ -1,22 +1,18 @@
-/**
- * UNCOMMENT: add support for smarter "external" scripts in Rollup
import { expect } from 'chai';
import { loadFixture } from './test-utils.js';
-let fixture;
+describe('External file references', () => {
+ let fixture;
-before(async () => {
- fixture = await loadFixture({ root: './fixtures/astro-external-files/' });
- await fixture.build();
-});
+ before(async () => {
+ fixture = await loadFixture({ root: './fixtures/astro-external-files/' });
+ await fixture.build();
+ });
-// TODO: Vite error: fix external files
-describe('Externeal file references', () => {
- it('Build with externeal reference', async () => {
- let rss = await fixture.readFile('/index.html');
- expect(rss).to.be(''); // TODO: inline snapshot
- });
+ it('Build with externeal reference', async () => {
+ const html = await fixture.readFile('/index.html');
+ expect(html).to.include('<script src="/external-file.js"');
+ });
});
-*/
it.skip('is skipped', () => {});
diff --git a/packages/astro/test/astro-get-static-paths.test.js b/packages/astro/test/astro-get-static-paths.test.js
index 784ff1718..66aa5b94d 100644
--- a/packages/astro/test/astro-get-static-paths.test.js
+++ b/packages/astro/test/astro-get-static-paths.test.js
@@ -1,6 +1,6 @@
import { expect } from 'chai';
-import { loadFixture } from './test-utils.js';
import * as cheerio from 'cheerio';
+import { loadFixture } from './test-utils.js';
describe('getStaticPaths - build calls', () => {
/** @type {import('./test-utils').Fixture} */
@@ -92,11 +92,6 @@ describe('getStaticPaths - dev calls', () => {
});
describe('route params type validation', () => {
- it('resolves 200 on nested array parameters', async () => {
- const res = await fixture.fetch('/nested-arrays/slug1');
- expect(res.status).to.equal(200);
- });
-
it('resolves 200 on matching static path - string params', async () => {
// route provided with { params: { year: "2022", slug: "post-2" }}
const res = await fixture.fetch('/blog/2022/post-1');
diff --git a/packages/astro/test/astro-global.test.js b/packages/astro/test/astro-global.test.js
index d49868584..f003bc035 100644
--- a/packages/astro/test/astro-global.test.js
+++ b/packages/astro/test/astro-global.test.js
@@ -54,10 +54,10 @@ describe('Astro Global', () => {
const html = await fixture.readFile('/index.html');
const $ = cheerio.load(html);
- expect($('#pathname').text()).to.equal('/blog/');
+ expect($('#pathname').text()).to.equal('/blog');
expect($('#searchparams').text()).to.equal('{}');
- expect($('#child-pathname').text()).to.equal('/blog/');
- expect($('#nested-child-pathname').text()).to.equal('/blog/');
+ expect($('#child-pathname').text()).to.equal('/blog');
+ expect($('#nested-child-pathname').text()).to.equal('/blog');
});
it('Astro.site', async () => {
diff --git a/packages/astro/test/astro-partial-html.test.js b/packages/astro/test/astro-partial-html.test.js
index 6073f1bd1..162c6985d 100644
--- a/packages/astro/test/astro-partial-html.test.js
+++ b/packages/astro/test/astro-partial-html.test.js
@@ -26,7 +26,7 @@ describe('Partial HTML', async () => {
// test 2: correct CSS present
const allInjectedStyles = $('style').text();
- expect(allInjectedStyles).to.match(/\:where\(\.astro-[^{]+{color:red}/);
+ expect(allInjectedStyles).to.match(/\[data-astro-cid-[^{]+{color:red}/);
});
it('injects framework styles', async () => {
diff --git a/packages/astro/test/cli.test.js b/packages/astro/test/cli.test.js
index 7626cc495..82cf7a12d 100644
--- a/packages/astro/test/cli.test.js
+++ b/packages/astro/test/cli.test.js
@@ -131,8 +131,8 @@ describe('astro cli', () => {
// Note: our tests run in parallel so this could be 3000+!
expect(Number.parseInt(localURL.port)).to.be.greaterThanOrEqual(
- 3000,
- `Expected Port to be >= 3000`
+ 4321,
+ `Expected Port to be >= 4321`
);
expect(networkURL.port).to.be.equal(
localURL.port,
diff --git a/packages/astro/test/config-vite-css-target.test.js b/packages/astro/test/config-vite-css-target.test.js
index 1dc2cce32..cb9fa8de2 100644
--- a/packages/astro/test/config-vite-css-target.test.js
+++ b/packages/astro/test/config-vite-css-target.test.js
@@ -32,7 +32,7 @@ describe('CSS', function () {
it('vite.build.cssTarget is respected', async () => {
expect(bundledCSS).to.match(
- new RegExp('.class\\:where\\(.astro-[^{]*{top:0;right:0;bottom:0;left:0}')
+ new RegExp('.class\\[data-astro-[^{]*{top:0;right:0;bottom:0;left:0}')
);
});
});
diff --git a/packages/astro/test/core-image.test.js b/packages/astro/test/core-image.test.js
index 5d656a6f6..26fafe41a 100644
--- a/packages/astro/test/core-image.test.js
+++ b/packages/astro/test/core-image.test.js
@@ -20,9 +20,6 @@ describe('astro:image', () => {
before(async () => {
fixture = await loadFixture({
root: './fixtures/core-image/',
- experimental: {
- assets: true,
- },
image: {
service: testImageService({ foo: 'bar' }),
domains: ['avatars.githubusercontent.com'],
@@ -444,9 +441,6 @@ describe('astro:image', () => {
before(async () => {
fixture = await loadFixture({
root: './fixtures/core-image-errors/',
- experimental: {
- assets: true,
- },
image: {
service: testImageService(),
},
@@ -512,9 +506,6 @@ describe('astro:image', () => {
before(async () => {
fixture = await loadFixture({
root: './fixtures/core-image-base/',
- experimental: {
- assets: true,
- },
image: {
service: testImageService(),
},
@@ -568,9 +559,6 @@ describe('astro:image', () => {
root: './fixtures/core-image-ssr/',
output: 'server',
adapter: testAdapter(),
- experimental: {
- assets: true,
- },
image: {
service: testImageService(),
},
@@ -592,9 +580,6 @@ describe('astro:image', () => {
before(async () => {
fixture = await loadFixture({
root: './fixtures/core-image-ssg/',
- experimental: {
- assets: true,
- },
image: {
service: testImageService(),
domains: ['astro.build'],
@@ -771,9 +756,6 @@ describe('astro:image', () => {
root: './fixtures/core-image-ssr/',
output: 'server',
adapter: testAdapter(),
- experimental: {
- assets: true,
- },
image: {
service: testImageService(),
},
@@ -798,9 +780,6 @@ describe('astro:image', () => {
root: './fixtures/core-image-ssr/',
output: 'server',
adapter: testAdapter(),
- experimental: {
- assets: true,
- },
image: {
service: testImageService(),
},
diff --git a/packages/astro/test/custom-elements.test.js b/packages/astro/test/custom-elements.test.js
deleted file mode 100644
index 53a13b478..000000000
--- a/packages/astro/test/custom-elements.test.js
+++ /dev/null
@@ -1,70 +0,0 @@
-import { expect } from 'chai';
-import { load as cheerioLoad } from 'cheerio';
-import { loadFixture } from './test-utils.js';
-
-describe('Custom Elements', () => {
- let fixture;
-
- before(async () => {
- fixture = await loadFixture({
- root: './fixtures/custom-elements/',
- });
- await fixture.build();
- });
-
- it('Work as constructors', async () => {
- const html = await fixture.readFile('/ctr/index.html');
- const $ = cheerioLoad(html);
-
- // test 1: Element rendered
- expect($('my-element')).to.have.lengthOf(1);
-
- // test 2: shadow rendered
- expect($('my-element template[shadowroot=open][shadowrootmode=open]')).to.have.lengthOf(1);
- });
-
- it('Works with exported tagName', async () => {
- const html = await fixture.readFile('/index.html');
- const $ = cheerioLoad(html);
-
- // test 1: Element rendered
- expect($('my-element')).to.have.lengthOf(1);
-
- // test 2: shadow rendered
- expect($('my-element template[shadowroot=open][shadowrootmode=open]')).to.have.lengthOf(1);
- });
-
- it.skip('Hydration works with exported tagName', async () => {
- const html = await fixture.readFile('/load/index.html');
- const $ = cheerioLoad(html);
-
- // SSR
- // test 1: Element rendered
- expect($('my-element')).to.have.lengthOf(1);
-
- // test 2: shadow rendered
- expect($('my-element template[shadowroot=open][shadowrootmode=open]')).to.have.lengthOf(1);
-
- // Hydration
- // test 3: Component and polyfill scripts bundled separately
- expect($('script')).to.have.lengthOf(2);
- });
-
- it('Custom elements not claimed by renderer are rendered as regular HTML', async () => {
- const html = await fixture.readFile('/nossr/index.html');
- const $ = cheerioLoad(html);
-
- // test 1: Rendered the client-only element
- expect($('client-element')).to.have.lengthOf(1);
- // No children
- expect($('client-element').text()).to.equal('');
- });
-
- it('Can import a client-only element that is nested in JSX', async () => {
- const html = await fixture.readFile('/nested/index.html');
- const $ = cheerioLoad(html);
-
- // test 1: Element rendered
- expect($('client-only-element')).to.have.lengthOf(1);
- });
-});
diff --git a/packages/astro/test/dev-routing.test.js b/packages/astro/test/dev-routing.test.js
index 186355b43..ff5f3a75d 100644
--- a/packages/astro/test/dev-routing.test.js
+++ b/packages/astro/test/dev-routing.test.js
@@ -113,9 +113,9 @@ describe('Development Routing', () => {
expect(response.status).to.equal(200);
});
- it('404 when loading subpath root without trailing slash', async () => {
+ it('200 when loading subpath root without trailing slash', async () => {
const response = await fixture.fetch('/blog');
- expect(response.status).to.equal(404);
+ expect(response.status).to.equal(200);
});
it('200 when loading another page with subpath used', async () => {
@@ -163,9 +163,9 @@ describe('Development Routing', () => {
expect(response.status).to.equal(200);
});
- it('404 when loading subpath root without trailing slash', async () => {
+ it('200 when loading subpath root without trailing slash', async () => {
const response = await fixture.fetch('/blog');
- expect(response.status).to.equal(404);
+ expect(response.status).to.equal(200);
});
it('200 when loading another page with subpath used', async () => {
diff --git a/packages/astro/test/featuresSupport.test.js b/packages/astro/test/featuresSupport.test.js
new file mode 100644
index 000000000..fba8da475
--- /dev/null
+++ b/packages/astro/test/featuresSupport.test.js
@@ -0,0 +1,55 @@
+import { loadFixture } from './test-utils.js';
+import { expect } from 'chai';
+import testAdapter from './test-adapter.js';
+
+describe('Adapter', () => {
+ let fixture;
+
+ it("should error if the adapter doesn't support edge middleware", async () => {
+ try {
+ fixture = await loadFixture({
+ root: './fixtures/middleware-dev/',
+ output: 'server',
+ build: {
+ excludeMiddleware: true,
+ },
+ adapter: testAdapter({
+ extendAdapter: {
+ supportsFeatures: {
+ edgeMiddleware: 'Unsupported',
+ },
+ },
+ }),
+ });
+ await fixture.build();
+ } catch (e) {
+ expect(e.toString()).to.contain(
+ "The adapter my-ssr-adapter doesn't support the feature build.excludeMiddleware."
+ );
+ }
+ });
+
+ it("should error if the adapter doesn't support split build", async () => {
+ try {
+ fixture = await loadFixture({
+ root: './fixtures/middleware-dev/',
+ output: 'server',
+ build: {
+ split: true,
+ },
+ adapter: testAdapter({
+ extendAdapter: {
+ supportsFeatures: {
+ functionPerPage: 'Unsupported',
+ },
+ },
+ }),
+ });
+ await fixture.build();
+ } catch (e) {
+ expect(e.toString()).to.contain(
+ "The adapter my-ssr-adapter doesn't support the feature build.split."
+ );
+ }
+ });
+});
diff --git a/packages/astro/test/fixtures/api-routes/src/pages/binary.dat.ts b/packages/astro/test/fixtures/api-routes/src/pages/binary.dat.ts
index c73589633..cbd382fc3 100644
--- a/packages/astro/test/fixtures/api-routes/src/pages/binary.dat.ts
+++ b/packages/astro/test/fixtures/api-routes/src/pages/binary.dat.ts
@@ -1,5 +1,5 @@
import type { APIRoute } from 'astro';
-export const get: APIRoute = async function () {
+export const GET: APIRoute = async function () {
return new Response(new Uint8Array([0xff]));
};
diff --git a/packages/astro/test/fixtures/api-routes/src/pages/context/data/[param].json.js b/packages/astro/test/fixtures/api-routes/src/pages/context/data/[param].json.js
index 2ed42a5ec..d18eb086f 100644
--- a/packages/astro/test/fixtures/api-routes/src/pages/context/data/[param].json.js
+++ b/packages/astro/test/fixtures/api-routes/src/pages/context/data/[param].json.js
@@ -14,7 +14,7 @@ export function getStaticPaths() {
]
}
-export function get({ params, request }) {
+export function GET({ params, request }) {
return {
body: JSON.stringify({
param: params.param,
diff --git a/packages/astro/test/fixtures/astro-assets-prefix/astro.config.mjs b/packages/astro/test/fixtures/astro-assets-prefix/astro.config.mjs
index 7393b72b8..a5c3c5532 100644
--- a/packages/astro/test/fixtures/astro-assets-prefix/astro.config.mjs
+++ b/packages/astro/test/fixtures/astro-assets-prefix/astro.config.mjs
@@ -1,5 +1,5 @@
-import { defineConfig } from 'astro/config';
import react from '@astrojs/react';
+import { defineConfig } from 'astro/config';
import { testImageService } from '../../test-image-service.js';
// https://astro.build/config
@@ -10,9 +10,6 @@ export default defineConfig({
build: {
assetsPrefix: 'http://localhost:4321',
},
- experimental: {
- assets: true,
- },
image: {
service: testImageService(),
},
diff --git a/packages/astro/test/fixtures/astro-assets/src/pages/index.astro b/packages/astro/test/fixtures/astro-assets/src/pages/index.astro
index 341f2744c..8da7feb0c 100644
--- a/packages/astro/test/fixtures/astro-assets/src/pages/index.astro
+++ b/packages/astro/test/fixtures/astro-assets/src/pages/index.astro
@@ -9,7 +9,7 @@ import p2Url from '../images/penguin2.jpg?url';
</style>
<body>
<h1>Icons</h1>
- <img src={(await import('../images/twitter.png')).default} srcset={`${(await import('../images/twitter.png')).default} 1x, ${(await import('../images/twitter@2x.png')).default} 2x, ${(await import('../images/twitter@3x.png')).default} 3x`} />
+ <img src={(await import('../images/twitter.png')).default.src} srcset={`${(await import('../images/twitter.png')).default.src} 1x, ${(await import('../images/twitter@2x.png')).default.src} 2x, ${(await import('../images/twitter@3x.png')).default.src} 3x`} />
<img srcset="https://ik.imagekit.io/demo/tr:w-300,h-300/medium_cafe_B1iTdD0C.jpg, https://ik.imagekit.io/demo/tr:w-450,h-450/medium_cafe_B1iTdD0C.jpg 600w, https://ik.imagekit.io/demo/tr:w-600,h-600/medium_cafe_B1iTdD0C.jpg 800w">
<img srcset="https://ik.imagekit.io/demo/tr:w-300,h-300/medium_cafe_B1iTdD0C.jpg, https://ik.imagekit.io/demo/tr:w-450,h-450/medium_cafe_B1iTdD0C.jpg 1.5x, https://ik.imagekit.io/demo/tr:w-600,h-600/medium_cafe_B1iTdD0C.jpg 2x">
<!--
@@ -20,7 +20,7 @@ import p2Url from '../images/penguin2.jpg?url';
<source srcset="https://ik.imagekit.io/demo/tr:w-300,h-300/medium_cafe_B1iTdD0C.jpg, https://ik.imagekit.io/demo/tr:w-450,h-450/medium_cafe_B1iTdD0C.jpg 600w, https://ik.imagekit.io/demo/tr:w-600,h-600/medium_cafe_B1iTdD0C.jpg 800w">
</picture>
- <img src={p1Url} id="import-no-url" />
+ <img src={p1Url.src} id="import-no-url" />
<img src={p2Url} id="import-url" />
</body>
</html>
diff --git a/packages/astro/test/fixtures/astro-basic/astro.config.mjs b/packages/astro/test/fixtures/astro-basic/astro.config.mjs
index b7b7dafe6..1b2eb163d 100644
--- a/packages/astro/test/fixtures/astro-basic/astro.config.mjs
+++ b/packages/astro/test/fixtures/astro-basic/astro.config.mjs
@@ -5,5 +5,5 @@ import preact from '@astrojs/preact';
export default defineConfig({
integrations: [preact()],
// make sure CLI flags have precedence
- server: () => ({ port: 3000 })
+ server: () => ({ port: 4321 })
});
diff --git a/packages/astro/test/fixtures/astro-cookies/src/pages/early-return.astro b/packages/astro/test/fixtures/astro-cookies/src/pages/early-return.astro
index 2796b3989..1457cb882 100644
--- a/packages/astro/test/fixtures/astro-cookies/src/pages/early-return.astro
+++ b/packages/astro/test/fixtures/astro-cookies/src/pages/early-return.astro
@@ -1,5 +1,5 @@
---
-const mode = Astro.cookies.get('prefs').json().mode;
+const mode = Astro.cookies.get('prefs')!.json().mode;
Astro.cookies.set('prefs', {
mode: mode === 'light' ? 'dark' : 'light'
diff --git a/packages/astro/test/fixtures/astro-cookies/src/pages/get-json.astro b/packages/astro/test/fixtures/astro-cookies/src/pages/get-json.astro
index 034881d22..44ee024ae 100644
--- a/packages/astro/test/fixtures/astro-cookies/src/pages/get-json.astro
+++ b/packages/astro/test/fixtures/astro-cookies/src/pages/get-json.astro
@@ -1,5 +1,5 @@
---
-const cookie = Astro.cookies.get('prefs');
+const cookie = Astro.cookies.get('prefs')!;
const prefs = cookie.json();
---
<html>
diff --git a/packages/astro/test/fixtures/astro-cookies/src/pages/set-prefs.js b/packages/astro/test/fixtures/astro-cookies/src/pages/set-prefs.js
index ccbdceff6..93a6a96de 100644
--- a/packages/astro/test/fixtures/astro-cookies/src/pages/set-prefs.js
+++ b/packages/astro/test/fixtures/astro-cookies/src/pages/set-prefs.js
@@ -1,5 +1,5 @@
-export function post({ cookies }) {
+export function POST({ cookies }) {
const mode = cookies.get('prefs').json().mode;
cookies.set('prefs', {
diff --git a/packages/astro/test/fixtures/astro-get-static-paths/src/pages/data/[slug].json.ts b/packages/astro/test/fixtures/astro-get-static-paths/src/pages/data/[slug].json.ts
index 3c7cc63ba..32a0fd140 100644
--- a/packages/astro/test/fixtures/astro-get-static-paths/src/pages/data/[slug].json.ts
+++ b/packages/astro/test/fixtures/astro-get-static-paths/src/pages/data/[slug].json.ts
@@ -5,7 +5,7 @@ export async function getStaticPaths() {
];
}
-export async function get() {
+export async function GET() {
return {
body: JSON.stringify({
title: '[slug]'
diff --git a/packages/astro/test/fixtures/astro-get-static-paths/src/pages/nested-arrays/[slug].astro b/packages/astro/test/fixtures/astro-get-static-paths/src/pages/nested-arrays/[slug].astro
deleted file mode 100644
index 9bd7b4f41..000000000
--- a/packages/astro/test/fixtures/astro-get-static-paths/src/pages/nested-arrays/[slug].astro
+++ /dev/null
@@ -1,8 +0,0 @@
----
- export function getStaticPaths() {
- return [
- [ { params: {slug: "slug1"} } ],
- [ { params: {slug: "slug2"} } ],
- ]
- }
----
diff --git a/packages/astro/test/fixtures/astro-markdown-frontmatter-injection/src/pages/glob.json.js b/packages/astro/test/fixtures/astro-markdown-frontmatter-injection/src/pages/glob.json.js
index a56f5306f..3aae6d89a 100644
--- a/packages/astro/test/fixtures/astro-markdown-frontmatter-injection/src/pages/glob.json.js
+++ b/packages/astro/test/fixtures/astro-markdown-frontmatter-injection/src/pages/glob.json.js
@@ -1,4 +1,4 @@
-export async function get() {
+export async function GET() {
const docs = await import.meta.glob('./*.md', { eager: true });
return {
body: JSON.stringify(Object.values(docs).map(doc => doc.frontmatter)),
diff --git a/packages/astro/test/fixtures/astro-markdown/src/pages/headings-glob.json.js b/packages/astro/test/fixtures/astro-markdown/src/pages/headings-glob.json.js
index 631250c33..b2c9ea6ea 100644
--- a/packages/astro/test/fixtures/astro-markdown/src/pages/headings-glob.json.js
+++ b/packages/astro/test/fixtures/astro-markdown/src/pages/headings-glob.json.js
@@ -1,6 +1,6 @@
import { getHeadings } from './with-layout.md';
-export async function get() {
+export async function GET() {
return {
body: JSON.stringify({
headings: getHeadings(),
diff --git a/packages/astro/test/fixtures/astro-markdown/src/pages/raw-content.json.js b/packages/astro/test/fixtures/astro-markdown/src/pages/raw-content.json.js
index ef933a373..82977443d 100644
--- a/packages/astro/test/fixtures/astro-markdown/src/pages/raw-content.json.js
+++ b/packages/astro/test/fixtures/astro-markdown/src/pages/raw-content.json.js
@@ -1,6 +1,6 @@
import { rawContent, compiledContent } from './basic.md';
-export async function get() {
+export async function GET() {
return {
body: JSON.stringify({
raw: rawContent(),
diff --git a/packages/astro/test/fixtures/astro-markdown/src/pages/vite-env-vars-glob.json.js b/packages/astro/test/fixtures/astro-markdown/src/pages/vite-env-vars-glob.json.js
index 4a7e4dd78..7a5d00f47 100644
--- a/packages/astro/test/fixtures/astro-markdown/src/pages/vite-env-vars-glob.json.js
+++ b/packages/astro/test/fixtures/astro-markdown/src/pages/vite-env-vars-glob.json.js
@@ -1,6 +1,6 @@
import { frontmatter } from './vite-env-vars.md';
-export async function get() {
+export async function GET() {
return {
body: JSON.stringify(frontmatter),
}
diff --git a/packages/astro/test/fixtures/astro-pagination/src/pages/posts/[slug]/[page].astro b/packages/astro/test/fixtures/astro-pagination/src/pages/posts/[slug]/[page].astro
index c4cc39739..33df98cf5 100644
--- a/packages/astro/test/fixtures/astro-pagination/src/pages/posts/[slug]/[page].astro
+++ b/packages/astro/test/fixtures/astro-pagination/src/pages/posts/[slug]/[page].astro
@@ -1,7 +1,7 @@
---
export async function getStaticPaths({paginate}) {
const allPosts = await Astro.glob('../../post/*.md');
- return ['red', 'blue'].map((filter) => {
+ return ['red', 'blue'].flatMap((filter) => {
const filteredPosts = allPosts.filter((post) => post.frontmatter.tag === filter);
return paginate(filteredPosts, {
params: { slug: filter },
diff --git a/packages/astro/test/fixtures/astro-slots-nested/astro.config.mjs b/packages/astro/test/fixtures/astro-slots-nested/astro.config.mjs
index 4a8807ed0..6f37285c6 100644
--- a/packages/astro/test/fixtures/astro-slots-nested/astro.config.mjs
+++ b/packages/astro/test/fixtures/astro-slots-nested/astro.config.mjs
@@ -7,9 +7,9 @@ import vue from '@astrojs/vue';
export default defineConfig({
integrations: [
- react(),
- preact(),
- solid(),
+ preact({ include: ['**/preact/*'] }),
+ solid({ include: ['**/solid/*'] }),
+ react({ include: ['**/react/*'] }),
svelte(),
vue()
]
diff --git a/packages/astro/test/fixtures/astro-slots-nested/src/components/PassesChildrenP.tsx b/packages/astro/test/fixtures/astro-slots-nested/src/components/preact/PassesChildrenP.tsx
index ec89ed15c..ec89ed15c 100644
--- a/packages/astro/test/fixtures/astro-slots-nested/src/components/PassesChildrenP.tsx
+++ b/packages/astro/test/fixtures/astro-slots-nested/src/components/preact/PassesChildrenP.tsx
diff --git a/packages/astro/test/fixtures/astro-slots-nested/src/components/Inner.tsx b/packages/astro/test/fixtures/astro-slots-nested/src/components/react/Inner.tsx
index b7cfe16a2..b7cfe16a2 100644
--- a/packages/astro/test/fixtures/astro-slots-nested/src/components/Inner.tsx
+++ b/packages/astro/test/fixtures/astro-slots-nested/src/components/react/Inner.tsx
diff --git a/packages/astro/test/fixtures/astro-slots-nested/src/components/Parent.jsx b/packages/astro/test/fixtures/astro-slots-nested/src/components/react/Parent.jsx
index 340dacab3..340dacab3 100644
--- a/packages/astro/test/fixtures/astro-slots-nested/src/components/Parent.jsx
+++ b/packages/astro/test/fixtures/astro-slots-nested/src/components/react/Parent.jsx
diff --git a/packages/astro/test/fixtures/astro-slots-nested/src/components/PassesChildren.tsx b/packages/astro/test/fixtures/astro-slots-nested/src/components/react/PassesChildren.tsx
index e764d5867..e764d5867 100644
--- a/packages/astro/test/fixtures/astro-slots-nested/src/components/PassesChildren.tsx
+++ b/packages/astro/test/fixtures/astro-slots-nested/src/components/react/PassesChildren.tsx
diff --git a/packages/astro/test/fixtures/astro-slots-nested/src/components/PassesChildrenS.tsx b/packages/astro/test/fixtures/astro-slots-nested/src/components/solid/PassesChildrenS.tsx
index d539c55dc..d539c55dc 100644
--- a/packages/astro/test/fixtures/astro-slots-nested/src/components/PassesChildrenS.tsx
+++ b/packages/astro/test/fixtures/astro-slots-nested/src/components/solid/PassesChildrenS.tsx
diff --git a/packages/astro/test/fixtures/astro-slots-nested/src/pages/component-slot.astro b/packages/astro/test/fixtures/astro-slots-nested/src/pages/component-slot.astro
index b9a03f887..d803f3ff7 100644
--- a/packages/astro/test/fixtures/astro-slots-nested/src/pages/component-slot.astro
+++ b/packages/astro/test/fixtures/astro-slots-nested/src/pages/component-slot.astro
@@ -1,6 +1,6 @@
---
import SlotRender from '../components/SlotRender.astro'
-import Inner from '../components/Inner'
+import Inner from '../components/react/Inner'
---
<html lang="en">
diff --git a/packages/astro/test/fixtures/astro-slots-nested/src/pages/hidden-nested.astro b/packages/astro/test/fixtures/astro-slots-nested/src/pages/hidden-nested.astro
index e51ce00a0..dcb3ebcba 100644
--- a/packages/astro/test/fixtures/astro-slots-nested/src/pages/hidden-nested.astro
+++ b/packages/astro/test/fixtures/astro-slots-nested/src/pages/hidden-nested.astro
@@ -1,6 +1,6 @@
---
-import Parent from '../components/Parent'
-import Inner from '../components/Inner'
+import Parent from '../components/react/Parent'
+import Inner from '../components/react/Inner'
---
<html lang="en">
diff --git a/packages/astro/test/fixtures/astro-slots-nested/src/pages/server-component-nested.astro b/packages/astro/test/fixtures/astro-slots-nested/src/pages/server-component-nested.astro
index b5a3d72a0..ec4ae3158 100644
--- a/packages/astro/test/fixtures/astro-slots-nested/src/pages/server-component-nested.astro
+++ b/packages/astro/test/fixtures/astro-slots-nested/src/pages/server-component-nested.astro
@@ -1,7 +1,7 @@
---
-import PassesChildren from '../components/PassesChildren.jsx';
-import PassesChildrenP from '../components/PassesChildrenP.jsx';
-import PassesChildrenS from '../components/PassesChildrenS.jsx';
+import PassesChildren from '../components/react/PassesChildren.jsx';
+import PassesChildrenP from '../components/preact/PassesChildrenP.jsx';
+import PassesChildrenS from '../components/solid/PassesChildrenS.jsx';
import PassesChildrenSv from '../components/PassesChildrenSv.svelte';
import PassesChildrenV from '../components/PassesChildrenV.vue';
---
diff --git a/packages/astro/test/fixtures/content-collection-references/astro.config.mjs b/packages/astro/test/fixtures/content-collection-references/astro.config.mjs
index 7287a1259..409407db3 100644
--- a/packages/astro/test/fixtures/content-collection-references/astro.config.mjs
+++ b/packages/astro/test/fixtures/content-collection-references/astro.config.mjs
@@ -3,9 +3,6 @@ import { testImageService } from '../../test-image-service.js';
// https://astro.build/config
export default defineConfig({
- experimental: {
- assets: true,
- },
image: {
service: testImageService(),
},
diff --git a/packages/astro/test/fixtures/content-collection-references/src/content/banners/welcome.json b/packages/astro/test/fixtures/content-collection-references/src/content/banners/welcome.json
index c62d06aab..8ab06ff1f 100644
--- a/packages/astro/test/fixtures/content-collection-references/src/content/banners/welcome.json
+++ b/packages/astro/test/fixtures/content-collection-references/src/content/banners/welcome.json
@@ -1,4 +1,4 @@
{
"alt": "Futuristic landscape with chrome buildings and blue skies",
- "src": "~/assets/the-future.jpg"
+ "src": "../../assets/the-future.jpg"
}
diff --git a/packages/astro/test/fixtures/content-collection-references/src/pages/welcome-data.json.js b/packages/astro/test/fixtures/content-collection-references/src/pages/welcome-data.json.js
index 4f529dac6..a461a1a65 100644
--- a/packages/astro/test/fixtures/content-collection-references/src/pages/welcome-data.json.js
+++ b/packages/astro/test/fixtures/content-collection-references/src/pages/welcome-data.json.js
@@ -1,6 +1,6 @@
import { getEntry, getEntries } from 'astro:content';
-export async function get() {
+export async function GET() {
const welcomePost = await getEntry('blog', 'welcome');
if (!welcomePost?.data) {
diff --git a/packages/astro/test/fixtures/content-collections/src/pages/collections.json.js b/packages/astro/test/fixtures/content-collections/src/pages/collections.json.js
index e74d03ad9..e335d2b05 100644
--- a/packages/astro/test/fixtures/content-collections/src/pages/collections.json.js
+++ b/packages/astro/test/fixtures/content-collections/src/pages/collections.json.js
@@ -2,7 +2,7 @@ import { getCollection } from 'astro:content';
import * as devalue from 'devalue';
import { stripAllRenderFn } from '../utils.js';
-export async function get() {
+export async function GET() {
const withoutConfig = stripAllRenderFn(await getCollection('without-config'));
const withSchemaConfig = stripAllRenderFn(await getCollection('with-schema-config'));
const withSlugConfig = stripAllRenderFn(await getCollection('with-custom-slugs'));
diff --git a/packages/astro/test/fixtures/content-collections/src/pages/entries.json.js b/packages/astro/test/fixtures/content-collections/src/pages/entries.json.js
index 0d7d22d08..311b76cc8 100644
--- a/packages/astro/test/fixtures/content-collections/src/pages/entries.json.js
+++ b/packages/astro/test/fixtures/content-collections/src/pages/entries.json.js
@@ -2,7 +2,7 @@ import { getEntryBySlug } from 'astro:content';
import * as devalue from 'devalue';
import { stripRenderFn } from '../utils.js';
-export async function get() {
+export async function GET() {
const columbiaWithoutConfig = stripRenderFn(await getEntryBySlug('without-config', 'columbia'));
const oneWithSchemaConfig = stripRenderFn(await getEntryBySlug('with-schema-config', 'one'));
const twoWithSlugConfig = stripRenderFn(await getEntryBySlug('with-custom-slugs', 'interesting-two'));
diff --git a/packages/astro/test/fixtures/core-image-base/src/content/blog/one.md b/packages/astro/test/fixtures/core-image-base/src/content/blog/one.md
index 59a5b77ba..d449290ef 100644
--- a/packages/astro/test/fixtures/core-image-base/src/content/blog/one.md
+++ b/packages/astro/test/fixtures/core-image-base/src/content/blog/one.md
@@ -1,6 +1,6 @@
---
title: One
-image: ~/assets/penguin2.jpg
+image: ../../assets/penguin2.jpg
cover:
image: ../../assets/penguin1.jpg
---
diff --git a/packages/astro/test/fixtures/core-image-base/tsconfig.json b/packages/astro/test/fixtures/core-image-base/tsconfig.json
new file mode 100644
index 000000000..b5bf6a715
--- /dev/null
+++ b/packages/astro/test/fixtures/core-image-base/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "extends": "astro/tsconfigs/base",
+ "compilerOptions": {
+ "baseUrl": ".",
+ "paths": {
+ "~/assets/*": ["src/assets/*"]
+ },
+ }
+}
diff --git a/packages/astro/test/fixtures/core-image-ssg/tsconfig.json b/packages/astro/test/fixtures/core-image-ssg/tsconfig.json
new file mode 100644
index 000000000..b5bf6a715
--- /dev/null
+++ b/packages/astro/test/fixtures/core-image-ssg/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "extends": "astro/tsconfigs/base",
+ "compilerOptions": {
+ "baseUrl": ".",
+ "paths": {
+ "~/assets/*": ["src/assets/*"]
+ },
+ }
+}
diff --git a/packages/astro/test/fixtures/core-image-ssr/src/pages/api.ts b/packages/astro/test/fixtures/core-image-ssr/src/pages/api.ts
index c10946318..7847baf62 100644
--- a/packages/astro/test/fixtures/core-image-ssr/src/pages/api.ts
+++ b/packages/astro/test/fixtures/core-image-ssr/src/pages/api.ts
@@ -1,6 +1,6 @@
import type { APIRoute } from "../../../../../src/@types/astro";
-export const get = (async ({ params, request }) => {
+export const GET = (async ({ params, request }) => {
const url = new URL(request.url);
const src = url.searchParams.get("src");
diff --git a/packages/astro/test/fixtures/core-image/src/content/blog/one.md b/packages/astro/test/fixtures/core-image/src/content/blog/one.md
index ef0993f63..8c6522534 100644
--- a/packages/astro/test/fixtures/core-image/src/content/blog/one.md
+++ b/packages/astro/test/fixtures/core-image/src/content/blog/one.md
@@ -1,11 +1,11 @@
---
title: One
-image: ~/assets/penguin2.jpg
+image: ../../assets/penguin2.jpg
cover:
image: ../../assets/penguin1.jpg
arrayOfImages:
- - ~/assets/penguin2.jpg
- - ~/assets/penguin1.jpg
+ - ../../assets/penguin2.jpg
+ - ../../assets/penguin1.jpg
refinedImage: ../../assets/penguin1.jpg
---
diff --git a/packages/astro/test/fixtures/core-image/tsconfig.json b/packages/astro/test/fixtures/core-image/tsconfig.json
new file mode 100644
index 000000000..b5bf6a715
--- /dev/null
+++ b/packages/astro/test/fixtures/core-image/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "extends": "astro/tsconfigs/base",
+ "compilerOptions": {
+ "baseUrl": ".",
+ "paths": {
+ "~/assets/*": ["src/assets/*"]
+ },
+ }
+}
diff --git a/packages/astro/test/fixtures/custom-elements/astro.config.mjs b/packages/astro/test/fixtures/custom-elements/astro.config.mjs
deleted file mode 100644
index 439334f8f..000000000
--- a/packages/astro/test/fixtures/custom-elements/astro.config.mjs
+++ /dev/null
@@ -1,6 +0,0 @@
-import { defineConfig } from 'astro/config';
-import ceIntegration from '@test/custom-element-renderer';
-
-export default defineConfig({
- integrations: [ceIntegration()],
-})
diff --git a/packages/astro/test/fixtures/custom-elements/my-component-lib/hydration-polyfill.js b/packages/astro/test/fixtures/custom-elements/my-component-lib/hydration-polyfill.js
deleted file mode 100644
index 665844481..000000000
--- a/packages/astro/test/fixtures/custom-elements/my-component-lib/hydration-polyfill.js
+++ /dev/null
@@ -1 +0,0 @@
-globalThis.somePolyfillHere = '';
diff --git a/packages/astro/test/fixtures/custom-elements/my-component-lib/index.js b/packages/astro/test/fixtures/custom-elements/my-component-lib/index.js
deleted file mode 100644
index 5b9bba7e6..000000000
--- a/packages/astro/test/fixtures/custom-elements/my-component-lib/index.js
+++ /dev/null
@@ -1,31 +0,0 @@
-function getViteConfiguration() {
- return {
- optimizeDeps: {
- include: ['@test/custom-element-renderer/polyfill.js', '@test/custom-element-renderer/hydration-polyfill.js'],
- exclude: ['@test/custom-element-renderer/server.js']
- },
- };
-}
-
-export default function () {
- return {
- name: '@test/custom-element-renderer',
- hooks: {
- 'astro:config:setup': ({ updateConfig, addRenderer, injectScript }) => {
- // Inject the necessary polyfills on every page
- injectScript('head-inline', `import('@test/custom-element-renderer/polyfill.js');`);
- // Inject the hydration code, before a component is hydrated.
- injectScript('before-hydration', `import('@test/custom-element-renderer/hydration-polyfill.js');`);
- // Add the lit renderer so that Astro can understand lit components.
- addRenderer({
- name: '@test/custom-element-renderer',
- serverEntrypoint: '@test/custom-element-renderer/server.js',
- });
- // Update the vite configuration.
- updateConfig({
- vite: getViteConfiguration(),
- });
- },
- },
- };
-}
diff --git a/packages/astro/test/fixtures/custom-elements/my-component-lib/package.json b/packages/astro/test/fixtures/custom-elements/my-component-lib/package.json
deleted file mode 100644
index f1d53b985..000000000
--- a/packages/astro/test/fixtures/custom-elements/my-component-lib/package.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "name": "@test/custom-element-renderer",
- "version": "0.1.0",
- "private": true,
- "main": "index.js",
- "type": "module",
- "exports": {
- ".": "./index.js",
- "./server.js": "./server.js",
- "./polyfill.js": "./polyfill.js",
- "./hydration-polyfill.js": "./hydration-polyfill.js"
- }
-}
diff --git a/packages/astro/test/fixtures/custom-elements/my-component-lib/polyfill.js b/packages/astro/test/fixtures/custom-elements/my-component-lib/polyfill.js
deleted file mode 100644
index 92788352b..000000000
--- a/packages/astro/test/fixtures/custom-elements/my-component-lib/polyfill.js
+++ /dev/null
@@ -1,2 +0,0 @@
-console.log('this is a polyfill');
-export default {};
diff --git a/packages/astro/test/fixtures/custom-elements/my-component-lib/server.js b/packages/astro/test/fixtures/custom-elements/my-component-lib/server.js
deleted file mode 100644
index 688923159..000000000
--- a/packages/astro/test/fixtures/custom-elements/my-component-lib/server.js
+++ /dev/null
@@ -1,30 +0,0 @@
-function getConstructor(Component) {
- if (typeof Component === 'string') {
- const tagName = Component;
- Component = customElements.get(tagName);
- }
- return Component;
-}
-
-function check(component) {
- const Component = getConstructor(component);
- if (typeof Component === 'function' && globalThis.HTMLElement.isPrototypeOf(Component)) {
- return true;
- }
- return false;
-}
-
-function renderToStaticMarkup(component, props, innerHTML) {
- const Component = getConstructor(component);
- const el = new Component();
- el.connectedCallback();
- const html = `<${el.localName}><template shadowroot="open" shadowrootmode="open">${el.shadowRoot.innerHTML}</template>${el.innerHTML}</${el.localName}>`
- return {
- html
- };
-}
-
-export default {
- check,
- renderToStaticMarkup
-};
diff --git a/packages/astro/test/fixtures/custom-elements/my-component-lib/shim.js b/packages/astro/test/fixtures/custom-elements/my-component-lib/shim.js
deleted file mode 100644
index eb969e528..000000000
--- a/packages/astro/test/fixtures/custom-elements/my-component-lib/shim.js
+++ /dev/null
@@ -1,28 +0,0 @@
-globalThis.customElements = {
- _elements: new Map(),
- define(name, ctr) {
- ctr.tagName = name;
- this._elements.set(name, ctr);
- },
- get(name) {
- return this._elements.get(name);
- }
-};
-
-globalThis.HTMLElement = class {
- attachShadow() {
- this.shadowRoot = new HTMLElement();
- }
-
- get localName() {
- return this.constructor.tagName;
- }
-
- get innerHTML() {
- return this._innerHTML;
- }
-
- set innerHTML(val) {
- this._innerHTML = val;
- }
-};
diff --git a/packages/astro/test/fixtures/custom-elements/package.json b/packages/astro/test/fixtures/custom-elements/package.json
deleted file mode 100644
index 80246a3b0..000000000
--- a/packages/astro/test/fixtures/custom-elements/package.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "name": "@test/custom-elements",
- "version": "0.0.0",
- "private": true,
- "dependencies": {
- "astro": "workspace:*",
- "@test/custom-element-renderer": "workspace:*"
- }
-}
diff --git a/packages/astro/test/fixtures/custom-elements/src/components/my-element.js b/packages/astro/test/fixtures/custom-elements/src/components/my-element.js
deleted file mode 100644
index ffc5e6ffb..000000000
--- a/packages/astro/test/fixtures/custom-elements/src/components/my-element.js
+++ /dev/null
@@ -1,13 +0,0 @@
-export const tagName = 'my-element';
-
-class MyElement extends HTMLElement {
- connectedCallback() {
- this.attachShadow({ mode: 'open' });
- this.shadowRoot.innerHTML = `<span id="custom">Hello from a custom element!</span>`;
- this.innerHTML = `<div id="custom-light">Light dom!</div>`
- }
-}
-
-customElements.define(tagName, MyElement);
-
-export default MyElement;
diff --git a/packages/astro/test/fixtures/custom-elements/src/pages/ctr.astro b/packages/astro/test/fixtures/custom-elements/src/pages/ctr.astro
deleted file mode 100644
index 8b1c83512..000000000
--- a/packages/astro/test/fixtures/custom-elements/src/pages/ctr.astro
+++ /dev/null
@@ -1,16 +0,0 @@
----
-import MyElement from '../components/my-element.js';
-
-const title = 'My App';
----
-
-<html>
-<head>
- <title>{title}</title>
-</head>
-<body>
- <h1>{title}</h1>
-
- <MyElement />
-</body>
-</html> \ No newline at end of file
diff --git a/packages/astro/test/fixtures/custom-elements/src/pages/index.astro b/packages/astro/test/fixtures/custom-elements/src/pages/index.astro
deleted file mode 100644
index b7380624a..000000000
--- a/packages/astro/test/fixtures/custom-elements/src/pages/index.astro
+++ /dev/null
@@ -1,15 +0,0 @@
----
-import '../components/my-element.js';
-const title = 'My App';
----
-
-<html>
-<head>
- <title>{title}</title>
-</head>
-<body>
- <h1>{title}</h1>
-
- <my-element></my-element>
-</body>
-</html> \ No newline at end of file
diff --git a/packages/astro/test/fixtures/custom-elements/src/pages/nested.astro b/packages/astro/test/fixtures/custom-elements/src/pages/nested.astro
deleted file mode 100644
index f23e3b6bc..000000000
--- a/packages/astro/test/fixtures/custom-elements/src/pages/nested.astro
+++ /dev/null
@@ -1,11 +0,0 @@
----
-let show = true
----
-<html>
-<head>
- <title>Custom element not imported but nested</title>
-</head>
-<body>
- {show && <client-only-element></client-only-element>}
-</body>
-</html> \ No newline at end of file
diff --git a/packages/astro/test/fixtures/custom-elements/src/pages/nossr.astro b/packages/astro/test/fixtures/custom-elements/src/pages/nossr.astro
deleted file mode 100644
index 53e580afb..000000000
--- a/packages/astro/test/fixtures/custom-elements/src/pages/nossr.astro
+++ /dev/null
@@ -1,14 +0,0 @@
----
-const title = 'My App';
----
-
-<html>
-<head>
- <title>{title}</title>
-</head>
-<body>
- <h1>{title}</h1>
-
- <client-element></client-element>
-</body>
-</html> \ No newline at end of file
diff --git a/packages/astro/test/fixtures/data-collections/src/pages/authors/[id].json.js b/packages/astro/test/fixtures/data-collections/src/pages/authors/[id].json.js
index 1cc26fb73..76f4d5760 100644
--- a/packages/astro/test/fixtures/data-collections/src/pages/authors/[id].json.js
+++ b/packages/astro/test/fixtures/data-collections/src/pages/authors/[id].json.js
@@ -7,7 +7,7 @@ export function getStaticPaths() {
}
/** @param {import('astro').APIContext} params */
-export async function get({ params }) {
+export async function GET({ params }) {
const { id } = params;
const author = await getEntry('authors-without-config', id);
if (!author) {
diff --git a/packages/astro/test/fixtures/data-collections/src/pages/authors/all.json.js b/packages/astro/test/fixtures/data-collections/src/pages/authors/all.json.js
index e4c804064..5b5007fed 100644
--- a/packages/astro/test/fixtures/data-collections/src/pages/authors/all.json.js
+++ b/packages/astro/test/fixtures/data-collections/src/pages/authors/all.json.js
@@ -1,6 +1,6 @@
import { getCollection } from 'astro:content';
-export async function get() {
+export async function GET() {
const authors = await getCollection('authors-without-config');
return {
diff --git a/packages/astro/test/fixtures/data-collections/src/pages/translations/[lang].json.js b/packages/astro/test/fixtures/data-collections/src/pages/translations/[lang].json.js
index 73c90354d..ab8cc764e 100644
--- a/packages/astro/test/fixtures/data-collections/src/pages/translations/[lang].json.js
+++ b/packages/astro/test/fixtures/data-collections/src/pages/translations/[lang].json.js
@@ -7,7 +7,7 @@ export function getStaticPaths() {
}
/** @param {import('astro').APIContext} params */
-export async function get({ params }) {
+export async function GET({ params }) {
const { lang } = params;
const translations = await getEntry('i18n', lang);
if (!translations) {
diff --git a/packages/astro/test/fixtures/data-collections/src/pages/translations/all.json.js b/packages/astro/test/fixtures/data-collections/src/pages/translations/all.json.js
index 7d953838f..e8a1fee92 100644
--- a/packages/astro/test/fixtures/data-collections/src/pages/translations/all.json.js
+++ b/packages/astro/test/fixtures/data-collections/src/pages/translations/all.json.js
@@ -1,6 +1,6 @@
import { getCollection } from 'astro:content';
-export async function get() {
+export async function GET() {
const translations = await getCollection('i18n');
return {
diff --git a/packages/astro/test/fixtures/dynamic-endpoint-collision/src/pages/api/catch/[...slug].ts b/packages/astro/test/fixtures/dynamic-endpoint-collision/src/pages/api/catch/[...slug].ts
index 8f64c2401..8fccd6695 100644
--- a/packages/astro/test/fixtures/dynamic-endpoint-collision/src/pages/api/catch/[...slug].ts
+++ b/packages/astro/test/fixtures/dynamic-endpoint-collision/src/pages/api/catch/[...slug].ts
@@ -2,7 +2,7 @@ import type { APIRoute } from "astro";
const slugs = ["one", undefined];
-export const get: APIRoute = ({ params }) => {
+export const GET: APIRoute = ({ params }) => {
return {
body: JSON.stringify({
slug: params.slug || "index",
diff --git a/packages/astro/test/fixtures/jsx/astro.config.mjs b/packages/astro/test/fixtures/jsx/astro.config.mjs
index 5b84d23a8..61d0d075e 100644
--- a/packages/astro/test/fixtures/jsx/astro.config.mjs
+++ b/packages/astro/test/fixtures/jsx/astro.config.mjs
@@ -1,13 +1,27 @@
import { defineConfig } from 'astro/config';
import renderer from 'astro/jsx/renderer.js';
+import mdx from '@astrojs/mdx';
import preact from '@astrojs/preact';
import react from '@astrojs/react';
import svelte from '@astrojs/svelte';
import vue from '@astrojs/vue';
import solid from '@astrojs/solid-js';
+
export default defineConfig({
integrations: [
+ preact({
+ include: ['**/preact/*']
+ }),
+ react({
+ include: ['**/react/*']
+ }),
+ solid({
+ include: ['**/solid/*'],
+ }),
+ mdx(),
+ svelte(),
+ vue(),
{
name: '@astrojs/test-jsx',
hooks: {
@@ -16,10 +30,5 @@ export default defineConfig({
}
}
},
- preact(),
- react(),
- svelte(),
- vue(),
- solid(),
]
})
diff --git a/packages/astro/test/fixtures/jsx/package.json b/packages/astro/test/fixtures/jsx/package.json
index 1e7001b47..e5b12ece4 100644
--- a/packages/astro/test/fixtures/jsx/package.json
+++ b/packages/astro/test/fixtures/jsx/package.json
@@ -3,6 +3,7 @@
"version": "0.0.0",
"private": true,
"devDependencies": {
+ "@astrojs/mdx": "workspace:*",
"@astrojs/preact": "workspace:*",
"@astrojs/react": "workspace:*",
"@astrojs/solid-js": "workspace:*",
diff --git a/packages/astro/test/fixtures/jsx/src/components/Content.mdx b/packages/astro/test/fixtures/jsx/src/components/Content.mdx
new file mode 100644
index 000000000..7a8bbc0f4
--- /dev/null
+++ b/packages/astro/test/fixtures/jsx/src/components/Content.mdx
@@ -0,0 +1,5 @@
+import ReactCounter from './react/ReactCounter.jsx'
+
+# Hello world
+
+<ReactCounter />
diff --git a/packages/astro/test/fixtures/jsx/src/components/Frameworks.jsx b/packages/astro/test/fixtures/jsx/src/components/Frameworks.jsx
deleted file mode 100644
index 2cc175964..000000000
--- a/packages/astro/test/fixtures/jsx/src/components/Frameworks.jsx
+++ /dev/null
@@ -1,28 +0,0 @@
-import 'astro/jsx-runtime';
-import { Test } from "./Test";
-
-import PreactCounter from "./PreactCounter";
-import ReactCounter from "./ReactCounter";
-import SolidCounter from "./SolidCounter";
-import SvelteCounter from "./SvelteCounter.svelte";
-import VueCounter from "./VueCounter.vue";
-
-export function Preact() {
- return <Test case="has-preact"><PreactCounter /></Test>
-}
-
-export function React() {
- return <Test case="has-react"><ReactCounter /></Test>
-}
-
-export function Solid() {
- return <Test case="has-solid"><SolidCounter /></Test>
-}
-
-export function Svelte() {
- return <Test case="has-svelte"><SvelteCounter /></Test>
-}
-
-export function Vue() {
- return <Test case="has-vue"><VueCounter /></Test>
-}
diff --git a/packages/astro/test/fixtures/jsx/src/components/PreactCounter.tsx b/packages/astro/test/fixtures/jsx/src/components/preact/PreactCounter.tsx
index cdb368377..cdb368377 100644
--- a/packages/astro/test/fixtures/jsx/src/components/PreactCounter.tsx
+++ b/packages/astro/test/fixtures/jsx/src/components/preact/PreactCounter.tsx
diff --git a/packages/astro/test/fixtures/jsx/src/components/ReactCounter.jsx b/packages/astro/test/fixtures/jsx/src/components/react/ReactCounter.jsx
index 5c5a001e8..7404d45bc 100644
--- a/packages/astro/test/fixtures/jsx/src/components/ReactCounter.jsx
+++ b/packages/astro/test/fixtures/jsx/src/components/react/ReactCounter.jsx
@@ -6,6 +6,8 @@ export default function ReactCounter() {
const add = () => setCount((i) => i + 1);
const subtract = () => setCount((i) => i - 1);
+ debugger;
+
return (
<div id="react">
<div className="counter">
diff --git a/packages/astro/test/fixtures/jsx/src/components/SolidCounter.jsx b/packages/astro/test/fixtures/jsx/src/components/solid/SolidCounter.jsx
index 9cfd85d02..9cfd85d02 100644
--- a/packages/astro/test/fixtures/jsx/src/components/SolidCounter.jsx
+++ b/packages/astro/test/fixtures/jsx/src/components/solid/SolidCounter.jsx
diff --git a/packages/astro/test/fixtures/jsx/src/pages/frameworks.astro b/packages/astro/test/fixtures/jsx/src/pages/frameworks.astro
index ede0f542c..cfd28a3d4 100644
--- a/packages/astro/test/fixtures/jsx/src/pages/frameworks.astro
+++ b/packages/astro/test/fixtures/jsx/src/pages/frameworks.astro
@@ -1,13 +1,27 @@
---
-import * as Framework from '../components/Frameworks'
+import FrameworkSolid from '../components/solid/SolidCounter.jsx'
+import FrameworkPreact from '../components/preact/PreactCounter.jsx'
+import FrameworkReact from '../components/react/ReactCounter.jsx'
+import FrameworkSvelte from '../components/SvelteCounter.svelte'
+import FrameworkVue from '../components/VueCounter.vue'
+import FrameworkMDX from '../components/Content.mdx'
---
-<Framework.Preact />
-
-<Framework.React />
-
-<Framework.Solid />
-
-<Framework.Svelte />
-
-<Framework.Vue />
+<div id="preact-wrapper">
+ <FrameworkPreact />
+</div>
+<div id="rreact-wrapper">
+ <FrameworkReact />
+</div>
+<div id="solid-wrapper">
+ <FrameworkSolid />
+</div>
+<div id="svelte-wrapper">
+ <FrameworkSvelte />
+</div>
+<div id="vue-wrapper">
+ <FrameworkVue />
+</div>
+<div id="mdx-wrapper">
+ <FrameworkMDX />
+</div>
diff --git a/packages/astro/test/fixtures/middleware-dev/src/pages/api/endpoint.js b/packages/astro/test/fixtures/middleware-dev/src/pages/api/endpoint.js
index dadff6edb..69d989bc0 100644
--- a/packages/astro/test/fixtures/middleware-dev/src/pages/api/endpoint.js
+++ b/packages/astro/test/fixtures/middleware-dev/src/pages/api/endpoint.js
@@ -1,4 +1,4 @@
-export function get() {
+export function GET() {
const object = {
name: 'Endpoint!!',
};
diff --git a/packages/astro/test/fixtures/non-html-pages/src/pages/about.json.ts b/packages/astro/test/fixtures/non-html-pages/src/pages/about.json.ts
index af61847f3..0c3ec18ea 100644
--- a/packages/astro/test/fixtures/non-html-pages/src/pages/about.json.ts
+++ b/packages/astro/test/fixtures/non-html-pages/src/pages/about.json.ts
@@ -1,7 +1,7 @@
// Returns the file body for this non-HTML file.
// The content type is based off of the extension in the filename,
// in this case: about.json.
-export async function get() {
+export async function GET() {
return {
body: JSON.stringify({
name: 'Astro',
diff --git a/packages/astro/test/fixtures/non-html-pages/src/pages/placeholder.png.ts b/packages/astro/test/fixtures/non-html-pages/src/pages/placeholder.png.ts
index 0c2d3806b..3ee26f0bf 100644
--- a/packages/astro/test/fixtures/non-html-pages/src/pages/placeholder.png.ts
+++ b/packages/astro/test/fixtures/non-html-pages/src/pages/placeholder.png.ts
@@ -2,7 +2,7 @@ import { promises as fs } from 'node:fs';
import type { APIRoute } from 'astro';
-export const get: APIRoute = async function get() {
+export const GET: APIRoute = async function get() {
try {
// Image is in the public domain. Sourced from
// https://en.wikipedia.org/wiki/File:Portrait_placeholder.png
diff --git a/packages/astro/test/fixtures/preact-compat-component/packages/react-lib/index.js b/packages/astro/test/fixtures/preact-compat-component/packages/react-lib/index.js
index 22fb55f10..4f15bdac1 100644
--- a/packages/astro/test/fixtures/preact-compat-component/packages/react-lib/index.js
+++ b/packages/astro/test/fixtures/preact-compat-component/packages/react-lib/index.js
@@ -2,4 +2,4 @@ import { useState } from "react";
export function useSpecialState(initialState) {
return useState(initialState);
-} \ No newline at end of file
+}
diff --git a/packages/astro/test/fixtures/preact-compat-component/src/components/Counter.jsx b/packages/astro/test/fixtures/preact-compat-component/src/components/Counter.jsx
index bfdf5bed1..7ee876f2c 100644
--- a/packages/astro/test/fixtures/preact-compat-component/src/components/Counter.jsx
+++ b/packages/astro/test/fixtures/preact-compat-component/src/components/Counter.jsx
@@ -1,4 +1,3 @@
-/** @jsxImportSource preact */
import { useSpecialState } from '@test/react-lib'
export default function Counter({ children }) {
diff --git a/packages/astro/test/fixtures/routing-priority/src/pages/api/catch/[...slug].json.ts b/packages/astro/test/fixtures/routing-priority/src/pages/api/catch/[...slug].json.ts
index 142b11711..bc7e1b774 100644
--- a/packages/astro/test/fixtures/routing-priority/src/pages/api/catch/[...slug].json.ts
+++ b/packages/astro/test/fixtures/routing-priority/src/pages/api/catch/[...slug].json.ts
@@ -1,6 +1,6 @@
import type { APIRoute } from 'astro';
-export const get: APIRoute = async ({ params }) => {
+export const GET: APIRoute = async ({ params }) => {
return {
body: JSON.stringify({
path: params.slug,
diff --git a/packages/astro/test/fixtures/routing-priority/src/pages/api/catch/[foo]-[bar].json.ts b/packages/astro/test/fixtures/routing-priority/src/pages/api/catch/[foo]-[bar].json.ts
index 2e66a22ae..b06efff6f 100644
--- a/packages/astro/test/fixtures/routing-priority/src/pages/api/catch/[foo]-[bar].json.ts
+++ b/packages/astro/test/fixtures/routing-priority/src/pages/api/catch/[foo]-[bar].json.ts
@@ -1,6 +1,6 @@
import type { APIRoute } from 'astro';
-export const get: APIRoute = async ({ params }) => {
+export const GET: APIRoute = async ({ params }) => {
return {
body: JSON.stringify({
foo: params.foo,
diff --git a/packages/astro/test/fixtures/ssr-api-route-custom-404/src/pages/api/route.js b/packages/astro/test/fixtures/ssr-api-route-custom-404/src/pages/api/route.js
index c44461be9..5a1cacc11 100644
--- a/packages/astro/test/fixtures/ssr-api-route-custom-404/src/pages/api/route.js
+++ b/packages/astro/test/fixtures/ssr-api-route-custom-404/src/pages/api/route.js
@@ -1,5 +1,5 @@
-export function post() {
+export function POST() {
return {
body: JSON.stringify({ ok: true })
};
diff --git a/packages/astro/test/fixtures/ssr-api-route/src/pages/binary.js b/packages/astro/test/fixtures/ssr-api-route/src/pages/binary.js
index 3e1c70c81..407c45666 100644
--- a/packages/astro/test/fixtures/ssr-api-route/src/pages/binary.js
+++ b/packages/astro/test/fixtures/ssr-api-route/src/pages/binary.js
@@ -1,6 +1,6 @@
import fs from 'node:fs';
-export function get() {
+export function GET() {
return {
body: 'ok'
};
diff --git a/packages/astro/test/fixtures/ssr-api-route/src/pages/context/[param].js b/packages/astro/test/fixtures/ssr-api-route/src/pages/context/[param].js
index 0ff1f625a..ba110ee13 100644
--- a/packages/astro/test/fixtures/ssr-api-route/src/pages/context/[param].js
+++ b/packages/astro/test/fixtures/ssr-api-route/src/pages/context/[param].js
@@ -1,7 +1,7 @@
/**
* @param {import('astro').APIContext} api
*/
-export function get(ctx) {
+export function GET(ctx) {
return {
body: JSON.stringify({
cookiesExist: !!ctx.cookies,
diff --git a/packages/astro/test/fixtures/ssr-api-route/src/pages/food.json.js b/packages/astro/test/fixtures/ssr-api-route/src/pages/food.json.js
index 1f9ea5f29..f4021c9e5 100644
--- a/packages/astro/test/fixtures/ssr-api-route/src/pages/food.json.js
+++ b/packages/astro/test/fixtures/ssr-api-route/src/pages/food.json.js
@@ -1,5 +1,5 @@
-export function get() {
+export function GET() {
return {
body: JSON.stringify([
{ name: 'lettuce' },
@@ -9,7 +9,7 @@ export function get() {
};
}
-export async function post({ params, request }) {
+export async function POST({ params, request }) {
const body = await request.text();
return new Response(body === `some data` ? `ok` : `not ok`, {
status: 200,
diff --git a/packages/astro/test/fixtures/ssr-api-route/src/pages/login.js b/packages/astro/test/fixtures/ssr-api-route/src/pages/login.js
index dfce0b5d6..0e851df74 100644
--- a/packages/astro/test/fixtures/ssr-api-route/src/pages/login.js
+++ b/packages/astro/test/fixtures/ssr-api-route/src/pages/login.js
@@ -1,5 +1,5 @@
/** @type {import('astro').APIRoute} */
-export function post({ cookies }) {
+export function POST({ cookies }) {
cookies.set('foo', 'foo', {
httpOnly: true
});
diff --git a/packages/astro/test/fixtures/ssr-dynamic/src/pages/api/products/[id].js b/packages/astro/test/fixtures/ssr-dynamic/src/pages/api/products/[id].js
index 4d96b62a5..8c7c39302 100644
--- a/packages/astro/test/fixtures/ssr-dynamic/src/pages/api/products/[id].js
+++ b/packages/astro/test/fixtures/ssr-dynamic/src/pages/api/products/[id].js
@@ -1,5 +1,5 @@
-export function get({ params }) {
+export function GET({ params }) {
return {
body: JSON.stringify(params)
};
diff --git a/packages/astro/test/fixtures/ssr-locals/src/pages/api.js b/packages/astro/test/fixtures/ssr-locals/src/pages/api.js
index d4f7386fb..366f26aae 100644
--- a/packages/astro/test/fixtures/ssr-locals/src/pages/api.js
+++ b/packages/astro/test/fixtures/ssr-locals/src/pages/api.js
@@ -1,5 +1,5 @@
-export async function get({ locals }) {
+export async function GET({ locals }) {
let out = { ...locals };
return new Response(JSON.stringify(out), {
diff --git a/packages/astro/test/fixtures/ssr-prerender-get-static-paths/src/pages/data/[slug].json.ts b/packages/astro/test/fixtures/ssr-prerender-get-static-paths/src/pages/data/[slug].json.ts
index 16e2a90ca..d969873c5 100644
--- a/packages/astro/test/fixtures/ssr-prerender-get-static-paths/src/pages/data/[slug].json.ts
+++ b/packages/astro/test/fixtures/ssr-prerender-get-static-paths/src/pages/data/[slug].json.ts
@@ -7,7 +7,7 @@ export async function getStaticPaths() {
];
}
-export async function get() {
+export async function GET() {
return {
body: JSON.stringify({
title: '[slug]'
diff --git a/packages/astro/test/fixtures/ssr-prerender-get-static-paths/src/pages/nested-arrays/[slug].astro b/packages/astro/test/fixtures/ssr-prerender-get-static-paths/src/pages/nested-arrays/[slug].astro
deleted file mode 100644
index 25d1bfff4..000000000
--- a/packages/astro/test/fixtures/ssr-prerender-get-static-paths/src/pages/nested-arrays/[slug].astro
+++ /dev/null
@@ -1,10 +0,0 @@
----
- export function getStaticPaths() {
- return [
- [ { params: {slug: "slug1"} } ],
- [ { params: {slug: "slug2"} } ],
- ]
- }
-
- export const prerender = true;
----
diff --git a/packages/astro/test/fixtures/ssr-preview/preview.mjs b/packages/astro/test/fixtures/ssr-preview/preview.mjs
index 745f22624..d8d57afa8 100644
--- a/packages/astro/test/fixtures/ssr-preview/preview.mjs
+++ b/packages/astro/test/fixtures/ssr-preview/preview.mjs
@@ -1,7 +1,7 @@
export default () => {
// noop
return {
- port: 3000,
+ port: 4321,
closed() {},
stop() {}
}
diff --git a/packages/astro/test/fixtures/static-build/src/pages/company.json.ts b/packages/astro/test/fixtures/static-build/src/pages/company.json.ts
index ee3f2f1ad..08f45a7b8 100644
--- a/packages/astro/test/fixtures/static-build/src/pages/company.json.ts
+++ b/packages/astro/test/fixtures/static-build/src/pages/company.json.ts
@@ -1,8 +1,8 @@
-export async function get() {
+export async function GET() {
return {
body: JSON.stringify({
name: 'Astro Technology Company',
url: 'https://astro.build/'
})
}
-} \ No newline at end of file
+}
diff --git a/packages/astro/test/fixtures/static-build/src/pages/data/[slug].json.ts b/packages/astro/test/fixtures/static-build/src/pages/data/[slug].json.ts
index 2bcfe50a1..2fa13ac18 100644
--- a/packages/astro/test/fixtures/static-build/src/pages/data/[slug].json.ts
+++ b/packages/astro/test/fixtures/static-build/src/pages/data/[slug].json.ts
@@ -5,7 +5,7 @@ export async function getStaticPaths() {
]
}
-export async function get({ params }) {
+export async function GET({ params }) {
return {
body: JSON.stringify({
slug: params.slug,
@@ -13,4 +13,4 @@ export async function get({ params }) {
url: 'https://astro.build/'
})
}
-} \ No newline at end of file
+}
diff --git a/packages/astro/test/fixtures/static-build/src/pages/posts.json.js b/packages/astro/test/fixtures/static-build/src/pages/posts.json.js
index 6463fdbad..aefbbffff 100644
--- a/packages/astro/test/fixtures/static-build/src/pages/posts.json.js
+++ b/packages/astro/test/fixtures/static-build/src/pages/posts.json.js
@@ -13,7 +13,7 @@ async function fetchPosts() {
return posts.sort((a, b) => a.title.localeCompare(b.title));
}
-export async function get() {
+export async function GET() {
const posts = await fetchPosts();
return {
diff --git a/packages/astro/test/fixtures/tailwindcss/src/pages/markdown-page.md b/packages/astro/test/fixtures/tailwindcss/src/pages/markdown-page.md
deleted file mode 100644
index e4c6b6bc9..000000000
--- a/packages/astro/test/fixtures/tailwindcss/src/pages/markdown-page.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-title: "Markdown + Tailwind"
-setup: |
- import Button from '../components/Button.astro';
- import Complex from '../components/Complex.astro';
----
-
-<div class="grid place-items-center h-screen content-center">
- <Button>Tailwind Button in Markdown!</Button>
- <Complex />
-</div> \ No newline at end of file
diff --git a/packages/astro/test/fixtures/with-endpoint-routes/src/pages/[slug].json.ts b/packages/astro/test/fixtures/with-endpoint-routes/src/pages/[slug].json.ts
index 364c886e3..783031605 100644
--- a/packages/astro/test/fixtures/with-endpoint-routes/src/pages/[slug].json.ts
+++ b/packages/astro/test/fixtures/with-endpoint-routes/src/pages/[slug].json.ts
@@ -5,7 +5,7 @@ export async function getStaticPaths() {
];
}
-export async function get({ params }) {
+export async function GET({ params }) {
return {
body: JSON.stringify({
slug: params.slug,
diff --git a/packages/astro/test/fixtures/with-endpoint-routes/src/pages/data/[slug].json.ts b/packages/astro/test/fixtures/with-endpoint-routes/src/pages/data/[slug].json.ts
index 4392c7ee7..707c39fa9 100644
--- a/packages/astro/test/fixtures/with-endpoint-routes/src/pages/data/[slug].json.ts
+++ b/packages/astro/test/fixtures/with-endpoint-routes/src/pages/data/[slug].json.ts
@@ -5,7 +5,7 @@ export async function getStaticPaths() {
];
}
-export async function get({ params }) {
+export async function GET({ params }) {
return {
body: JSON.stringify({
slug: params.slug,
diff --git a/packages/astro/test/fixtures/with-endpoint-routes/src/pages/home.json.ts b/packages/astro/test/fixtures/with-endpoint-routes/src/pages/home.json.ts
index 8046af6df..5eaac42f1 100644
--- a/packages/astro/test/fixtures/with-endpoint-routes/src/pages/home.json.ts
+++ b/packages/astro/test/fixtures/with-endpoint-routes/src/pages/home.json.ts
@@ -1,4 +1,4 @@
-export async function get() {
+export async function GET() {
return {
body: JSON.stringify({
title: 'home'
diff --git a/packages/astro/test/fixtures/with-endpoint-routes/src/pages/images/[image].svg.ts b/packages/astro/test/fixtures/with-endpoint-routes/src/pages/images/[image].svg.ts
index e728394f4..c6fa88711 100644
--- a/packages/astro/test/fixtures/with-endpoint-routes/src/pages/images/[image].svg.ts
+++ b/packages/astro/test/fixtures/with-endpoint-routes/src/pages/images/[image].svg.ts
@@ -5,7 +5,7 @@ export async function getStaticPaths() {
];
}
-export async function get({ params }) {
+export async function GET({ params }) {
return {
body: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 200">
<title>${params.image}</title>
diff --git a/packages/astro/test/fixtures/with-endpoint-routes/src/pages/images/hex.ts b/packages/astro/test/fixtures/with-endpoint-routes/src/pages/images/hex.ts
index 546796fed..84dd6dcaa 100644
--- a/packages/astro/test/fixtures/with-endpoint-routes/src/pages/images/hex.ts
+++ b/packages/astro/test/fixtures/with-endpoint-routes/src/pages/images/hex.ts
@@ -1,6 +1,6 @@
import { readFileSync } from "node:fs";
-export async function get({ params, request }) {
+export async function GET({ params, request }) {
const buffer = readFileSync(new URL('../../astro.png', import.meta.url));
return {
body: buffer.toString('hex'),
diff --git a/packages/astro/test/fixtures/with-endpoint-routes/src/pages/images/static.svg.ts b/packages/astro/test/fixtures/with-endpoint-routes/src/pages/images/static.svg.ts
index 727a0eae8..93fcf4022 100644
--- a/packages/astro/test/fixtures/with-endpoint-routes/src/pages/images/static.svg.ts
+++ b/packages/astro/test/fixtures/with-endpoint-routes/src/pages/images/static.svg.ts
@@ -1,4 +1,4 @@
-export async function get() {
+export async function GET() {
return {
body: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 200">
<title>Static SVG</title>
diff --git a/packages/astro/test/jsx.test.js b/packages/astro/test/jsx.test.js
index 41671699c..b19074817 100644
--- a/packages/astro/test/jsx.test.js
+++ b/packages/astro/test/jsx.test.js
@@ -20,43 +20,51 @@ describe('jsx-runtime', () => {
expect($('#named').text()).to.equal('Named');
});
- it('Can load Preact component inside Astro JSX', async () => {
+ it('Can load Preact component inside Astro', async () => {
const html = await fixture.readFile('/frameworks/index.html');
const $ = cheerio.load(html);
- expect($('#has-preact #preact').length).to.equal(1);
+ expect($('#has-preact #preact').length).to.equal(0);
expect($('#preact').text()).to.include('Preact');
});
- it('Can load React component inside Astro JSX', async () => {
+ it('Can load React component inside Astro', async () => {
const html = await fixture.readFile('/frameworks/index.html');
const $ = cheerio.load(html);
- expect($('#has-react #react').length).to.equal(1);
+ expect($('#has-react #react').length).to.equal(0);
expect($('#react').text()).to.include('React');
});
- it('Can load Solid component inside Astro JSX', async () => {
+ it('Can load Solid component inside Astro', async () => {
const html = await fixture.readFile('/frameworks/index.html');
const $ = cheerio.load(html);
- expect($('#has-solid #solid').length).to.equal(1);
+ expect($('#has-solid #solid').length).to.equal(0);
expect($('#solid').text()).to.include('Solid');
});
- it('Can load Svelte component inside Astro JSX', async () => {
+ it('Can load Svelte component inside Astro', async () => {
const html = await fixture.readFile('/frameworks/index.html');
const $ = cheerio.load(html);
- expect($('#has-svelte #svelte').length).to.equal(1);
+ expect($('#has-svelte #svelte').length).to.equal(0);
expect($('#svelte').text()).to.include('Svelte');
});
- it('Can load Vue component inside Astro JSX', async () => {
+ it('Can load Vue component inside Astro', async () => {
const html = await fixture.readFile('/frameworks/index.html');
const $ = cheerio.load(html);
- expect($('#has-vue #vue').length).to.equal(1);
+ expect($('#has-vue #vue').length).to.equal(0);
expect($('#vue').text()).to.include('Vue');
});
+
+ it('Can load MDX component inside Astro', async () => {
+ const html = await fixture.readFile('/frameworks/index.html');
+ const $ = cheerio.load(html);
+
+ expect($('#mdx-wrapper #hello-world')).to.have.a.lengthOf(1, 'md content rendered');
+ expect($('#mdx-wrapper #react')).to.have.a.lengthOf(1, 'React component rendered');
+ });
});
diff --git a/packages/astro/test/preact-compat-component.test.js b/packages/astro/test/preact-compat-component.test.js
index f0cd9e45f..0c1991f12 100644
--- a/packages/astro/test/preact-compat-component.test.js
+++ b/packages/astro/test/preact-compat-component.test.js
@@ -3,18 +3,30 @@ import * as cheerio from 'cheerio';
import { loadFixture } from './test-utils.js';
describe('Preact compat component', () => {
+ /** @type {import('./test-utils.js').Fixture} */
+ let fixture;
+
+ before(async () => {
+ fixture = await loadFixture({
+ root: './fixtures/preact-compat-component/',
+ });
+ });
+
describe('Development', () => {
- let fixture;
+ /** @type {import('./test-utils.js').DevServer} */
+ let devServer;
before(async () => {
- fixture = await loadFixture({
- root: './fixtures/preact-compat-component/',
- });
- await fixture.startDevServer();
+ devServer = await fixture.startDevServer();
+ });
+
+ after(async () => {
+ await devServer.stop();
});
it('Can load Counter', async () => {
- const html = await fixture.fetch('/').then((res) => res.text());
+ const res = await fixture.fetch('/');
+ const html = await res.text();
const $ = cheerio.load(html);
expect($('#counter-text').text()).to.be.eq('0');
@@ -22,12 +34,7 @@ describe('Preact compat component', () => {
});
describe('Build', () => {
- let fixture;
-
before(async () => {
- fixture = await loadFixture({
- root: './fixtures/preact-compat-component/',
- });
await fixture.build();
});
diff --git a/packages/astro/test/preview-routing.test.js b/packages/astro/test/preview-routing.test.js
index 5c365b07c..4c99881b6 100644
--- a/packages/astro/test/preview-routing.test.js
+++ b/packages/astro/test/preview-routing.test.js
@@ -157,9 +157,9 @@ describe('Preview Routing', () => {
expect(response.status).to.equal(200);
});
- it('404 when loading subpath root without trailing slash', async () => {
+ it('200 when loading subpath root without trailing slash', async () => {
const response = await fixture.fetch('/blog');
- expect(response.status).to.equal(404);
+ expect(response.status).to.equal(200);
});
it('200 when loading another page with subpath used', async () => {
@@ -345,9 +345,9 @@ describe('Preview Routing', () => {
expect(response.status).to.equal(200);
});
- it('404 when loading subpath root without trailing slash', async () => {
+ it('200 when loading subpath root without trailing slash', async () => {
const response = await fixture.fetch('/blog');
- expect(response.status).to.equal(404);
+ expect(response.status).to.equal(200);
});
it('200 when loading another page with subpath used', async () => {
diff --git a/packages/astro/test/public-base-404.test.js b/packages/astro/test/public-base-404.test.js
index c8d58471d..969e2a952 100644
--- a/packages/astro/test/public-base-404.test.js
+++ b/packages/astro/test/public-base-404.test.js
@@ -44,7 +44,7 @@ describe('Public dev with base', () => {
expect(response.status).to.equal(404);
const html = await response.text();
$ = cheerio.load(html);
- expect($('a').first().text()).to.equal('/blog/');
+ expect($('a').first().text()).to.equal('/blog');
});
it('default 404 page when loading /none/', async () => {
diff --git a/packages/astro/test/scoped-style-strategy.test.js b/packages/astro/test/scoped-style-strategy.test.js
index 022ef3d6f..a59f227ad 100644
--- a/packages/astro/test/scoped-style-strategy.test.js
+++ b/packages/astro/test/scoped-style-strategy.test.js
@@ -3,7 +3,7 @@ import * as cheerio from 'cheerio';
import { loadFixture } from './test-utils.js';
describe('scopedStyleStrategy', () => {
- describe('default', () => {
+ describe('scopedStyleStrategy: "where"', () => {
/** @type {import('./test-utils').Fixture} */
let fixture;
let stylesheet;
@@ -11,6 +11,7 @@ describe('scopedStyleStrategy', () => {
before(async () => {
fixture = await loadFixture({
root: './fixtures/scoped-style-strategy/',
+ scopedStyleStrategy: 'where',
});
await fixture.build();
@@ -57,4 +58,35 @@ describe('scopedStyleStrategy', () => {
expect(stylesheet).to.match(/h1\.astro/);
});
});
+
+ describe('default', () => {
+ /** @type {import('./test-utils').Fixture} */
+ let fixture;
+ let stylesheet;
+
+ before(async () => {
+ fixture = await loadFixture({
+ root: './fixtures/scoped-style-strategy/',
+ });
+ await fixture.build();
+
+ const html = await fixture.readFile('/index.html');
+ const $ = cheerio.load(html);
+ const $link = $('link[rel=stylesheet]');
+ const href = $link.attr('href');
+ stylesheet = await fixture.readFile(href);
+ });
+
+ it('does not include :where pseudo-selector', () => {
+ expect(stylesheet).to.not.match(/:where/);
+ });
+
+ it('does not include the class name directly in the selector', () => {
+ expect(stylesheet).to.not.match(/h1\.astro/);
+ });
+
+ it('includes the data attribute hash', () => {
+ expect(stylesheet).to.include('h1[data-astro-cid-');
+ });
+ });
});
diff --git a/packages/astro/test/ssr-api-route.test.js b/packages/astro/test/ssr-api-route.test.js
index 3e2d5c327..899404b1e 100644
--- a/packages/astro/test/ssr-api-route.test.js
+++ b/packages/astro/test/ssr-api-route.test.js
@@ -1,6 +1,5 @@
import { expect } from 'chai';
import net from 'node:net';
-import { File, FormData } from 'undici';
import testAdapter from './test-adapter.js';
import { loadFixture } from './test-utils.js';
diff --git a/packages/astro/test/ssr-hoisted-script.test.js b/packages/astro/test/ssr-hoisted-script.test.js
index 49e1e7b2f..e9549151e 100644
--- a/packages/astro/test/ssr-hoisted-script.test.js
+++ b/packages/astro/test/ssr-hoisted-script.test.js
@@ -3,50 +3,54 @@ import { load as cheerioLoad } from 'cheerio';
import { loadFixture } from './test-utils.js';
import testAdapter from './test-adapter.js';
+async function fetchHTML(fixture, path) {
+ const app = await fixture.loadTestAdapterApp();
+ const request = new Request('http://example.com' + path);
+ const response = await app.render(request);
+ const html = await response.text();
+ return html;
+}
+
describe('Hoisted scripts in SSR', () => {
/** @type {import('./test-utils').Fixture} */
let fixture;
- before(async () => {
- fixture = await loadFixture({
- root: './fixtures/ssr-hoisted-script/',
- output: 'server',
- adapter: testAdapter(),
- });
- await fixture.build();
- });
-
- async function fetchHTML(path) {
- const app = await fixture.loadTestAdapterApp();
- const request = new Request('http://example.com' + path);
- const response = await app.render(request);
- const html = await response.text();
- return html;
- }
-
- it('Inlined scripts get included', async () => {
- const html = await fetchHTML('/');
- const $ = cheerioLoad(html);
- expect($('script').length).to.equal(1);
- });
-
- describe('base path', () => {
- const base = '/hello';
-
+ describe('without base path', () => {
before(async () => {
fixture = await loadFixture({
root: './fixtures/ssr-hoisted-script/',
output: 'server',
adapter: testAdapter(),
- base,
});
await fixture.build();
});
- it('Inlined scripts get included without base path in the script', async () => {
- const html = await fetchHTML('/hello/');
+ it('Inlined scripts get included', async () => {
+ const html = await fetchHTML(fixture, '/');
const $ = cheerioLoad(html);
- expect($('script').html()).to.equal('console.log("hello world");\n');
+ expect($('script').length).to.equal(1);
});
});
});
+
+describe('Hoisted scripts in SSR with base path', () => {
+ /** @type {import('./test-utils').Fixture} */
+ let fixture;
+ const base = '/hello';
+
+ before(async () => {
+ fixture = await loadFixture({
+ root: './fixtures/ssr-hoisted-script/',
+ output: 'server',
+ adapter: testAdapter(),
+ base,
+ });
+ await fixture.build();
+ });
+
+ it('Inlined scripts get included without base path in the script', async () => {
+ const html = await fetchHTML(fixture, '/hello/');
+ const $ = cheerioLoad(html);
+ expect($('script').html()).to.equal('console.log("hello world");\n');
+ });
+});
diff --git a/packages/astro/test/ssr-manifest.test.js b/packages/astro/test/ssr-manifest.test.js
index 4e5521220..bd9483505 100644
--- a/packages/astro/test/ssr-manifest.test.js
+++ b/packages/astro/test/ssr-manifest.test.js
@@ -11,7 +11,6 @@ describe('astro:ssr-manifest', () => {
fixture = await loadFixture({
root: './fixtures/ssr-manifest/',
output: 'server',
- compressHTML: true,
adapter: testAdapter(),
});
await fixture.build();
diff --git a/packages/astro/test/ssr-prerender-get-static-paths.test.js b/packages/astro/test/ssr-prerender-get-static-paths.test.js
index 391e7485d..3fe2950cb 100644
--- a/packages/astro/test/ssr-prerender-get-static-paths.test.js
+++ b/packages/astro/test/ssr-prerender-get-static-paths.test.js
@@ -1,7 +1,7 @@
import { expect } from 'chai';
-import { loadFixture } from './test-utils.js';
import * as cheerio from 'cheerio';
import testAdapter from './test-adapter.js';
+import { loadFixture } from './test-utils.js';
describe('Prerender', () => {
/** @type {import('./test-utils').Fixture} */
@@ -102,11 +102,6 @@ describe('Prerender', () => {
});
describe('route params type validation', () => {
- it('resolves 200 on nested array parameters', async () => {
- const res = await fixture.fetch('/blog/nested-arrays/slug1');
- expect(res.status).to.equal(200);
- });
-
it('resolves 200 on matching static path - string params', async () => {
// route provided with { params: { year: "2022", slug: "post-2" }}
const res = await fixture.fetch('/blog/blog/2022/post-1');
@@ -234,11 +229,6 @@ describe('Prerender', () => {
});
describe('route params type validation', () => {
- it('resolves 200 on nested array parameters', async () => {
- const res = await fixture.fetch('/blog/nested-arrays/slug1');
- expect(res.status).to.equal(200);
- });
-
it('resolves 200 on matching static path - string params', async () => {
// route provided with { params: { year: "2022", slug: "post-2" }}
const res = await fixture.fetch('/blog/blog/2022/post-1');
diff --git a/packages/astro/test/ssr-split-manifest.test.js b/packages/astro/test/ssr-split-manifest.test.js
index 394740395..d7c1f32c5 100644
--- a/packages/astro/test/ssr-split-manifest.test.js
+++ b/packages/astro/test/ssr-split-manifest.test.js
@@ -43,7 +43,7 @@ describe('astro:ssr-manifest, split', () => {
it('should give access to entry points that exists on file system', async () => {
// number of the pages inside src/
- expect(entryPoints.size).to.equal(5);
+ expect(entryPoints.size).to.equal(6);
for (const fileUrl of entryPoints.values()) {
let filePath = fileURLToPath(fileUrl);
expect(existsSync(filePath)).to.be.true;
diff --git a/packages/astro/test/static-build.test.js b/packages/astro/test/static-build.test.js
index d4a687a5d..0552c353f 100644
--- a/packages/astro/test/static-build.test.js
+++ b/packages/astro/test/static-build.test.js
@@ -175,7 +175,7 @@ describe('Static build', () => {
let found = false;
for (const log of logs) {
if (
- log.type === 'ssg' &&
+ log.label === 'ssg' &&
/[hH]eaders are not exposed in static \(SSG\) output mode/.test(log.message)
) {
found = true;
diff --git a/packages/astro/test/tailwindcss.test.js b/packages/astro/test/tailwindcss.test.js
index 2a37c6572..3c249cc2c 100644
--- a/packages/astro/test/tailwindcss.test.js
+++ b/packages/astro/test/tailwindcss.test.js
@@ -3,6 +3,7 @@ import * as cheerio from 'cheerio';
import { loadFixture } from './test-utils.js';
describe('Tailwind', () => {
+ /** @type {import('./test-utils.js').Fixture} */
let fixture;
before(async () => {
@@ -58,14 +59,6 @@ describe('Tailwind', () => {
expect(button.hasClass('2xl:w-[80%]'), 'complex class').to.be.true;
});
- it('handles Markdown pages', async () => {
- const html = await fixture.readFile('/markdown-page/index.html');
- const $md = cheerio.load(html);
- const bundledCSSHREF = $md('link[rel=stylesheet][href^=/_astro/]').attr('href');
- const mdBundledCSS = await fixture.readFile(bundledCSSHREF.replace(/^\/?/, '/'));
- expect(mdBundledCSS, 'includes used component classes').to.match(/\.bg-purple-600{/);
- });
-
it('handles MDX pages (with integration)', async () => {
const html = await fixture.readFile('/mdx-page/index.html');
const $md = cheerio.load(html);
diff --git a/packages/astro/test/test-adapter.js b/packages/astro/test/test-adapter.js
index 85b4d69c0..67058023d 100644
--- a/packages/astro/test/test-adapter.js
+++ b/packages/astro/test/test-adapter.js
@@ -71,6 +71,15 @@ export default function (
name: 'my-ssr-adapter',
serverEntrypoint: '@my-ssr',
exports: ['manifest', 'createApp'],
+ supportedFeatures: {
+ assets: {
+ supportKind: 'Stable',
+ isNodeCompatible: true,
+ },
+ serverOutput: 'Stable',
+ staticOutput: 'Stable',
+ hybridOutput: 'Stable',
+ },
...extendAdapter,
});
},
diff --git a/packages/astro/test/test-utils.js b/packages/astro/test/test-utils.js
index 27f5d83f7..0b336698f 100644
--- a/packages/astro/test/test-utils.js
+++ b/packages/astro/test/test-utils.js
@@ -1,4 +1,3 @@
-import { polyfill } from '@astrojs/webapi';
import { execa } from 'execa';
import fastGlob from 'fast-glob';
import fs from 'node:fs';
@@ -17,17 +16,11 @@ import { nodeLogDestination } from '../dist/core/logger/node.js';
import preview from '../dist/core/preview/index.js';
import { sync } from '../dist/core/sync/index.js';
-// polyfill WebAPIs to globalThis for Node v12, Node v14, and Node v16
-polyfill(globalThis, {
- exclude: 'window document',
-});
-
// Disable telemetry when running tests
process.env.ASTRO_TELEMETRY_DISABLED = true;
/**
- * @typedef {import('undici').Response} Response
- * @typedef {import('../src/core/dev/dev').DedvServer} DevServer
+ * @typedef {import('../src/core/dev/dev').DevServer} DevServer
* @typedef {import('../src/@types/astro').AstroInlineConfig & { root?: string | URL }} AstroInlineConfig
* @typedef {import('../src/core/preview/index').PreviewServer} PreviewServer
* @typedef {import('../src/core/app/index').App} App
diff --git a/packages/astro/test/units/content-collections/get-entry-type.test.js b/packages/astro/test/units/content-collections/get-entry-type.test.js
index e7effa52f..a953d0c8f 100644
--- a/packages/astro/test/units/content-collections/get-entry-type.test.js
+++ b/packages/astro/test/units/content-collections/get-entry-type.test.js
@@ -28,14 +28,13 @@ const fixtures = [
const contentFileExts = ['.md', '.mdx'];
const dataFileExts = ['.yaml', '.yml', '.json'];
-// TODO: Remove `getEntryType` last parameter once `experimental.assets` is no longer experimental
describe('Content Collections - getEntryType', () => {
fixtures.forEach(({ title, contentPaths }) => {
describe(title, () => {
it('Returns "content" for Markdown files', () => {
for (const entryPath of ['blog/first-post.md', 'blog/first-post.mdx']) {
const entry = fileURLToPath(new URL(entryPath, contentPaths.contentDir));
- const type = getEntryType(entry, contentPaths, contentFileExts, dataFileExts, false);
+ const type = getEntryType(entry, contentPaths, contentFileExts, dataFileExts);
expect(type).to.equal('content');
}
});
@@ -47,7 +46,7 @@ describe('Content Collections - getEntryType', () => {
'banners/welcome.yml',
]) {
const entry = fileURLToPath(new URL(entryPath, contentPaths.contentDir));
- const type = getEntryType(entry, contentPaths, contentFileExts, dataFileExts, false);
+ const type = getEntryType(entry, contentPaths, contentFileExts, dataFileExts);
expect(type).to.equal('data');
}
});
@@ -55,50 +54,50 @@ describe('Content Collections - getEntryType', () => {
it('Returns "content" for Markdown files in nested directories', () => {
for (const entryPath of ['blog/2021/01/01/index.md', 'blog/2021/01/01/index.mdx']) {
const entry = fileURLToPath(new URL(entryPath, contentPaths.contentDir));
- const type = getEntryType(entry, contentPaths, contentFileExts, dataFileExts, false);
+ const type = getEntryType(entry, contentPaths, contentFileExts, dataFileExts);
expect(type).to.equal('content');
}
});
it('Returns "config" for config files', () => {
const entry = fileURLToPath(contentPaths.config.url);
- const type = getEntryType(entry, contentPaths, contentFileExts, dataFileExts, false);
+ const type = getEntryType(entry, contentPaths, contentFileExts, dataFileExts);
expect(type).to.equal('config');
});
it('Returns "unsupported" for non-Markdown files', () => {
const entry = fileURLToPath(new URL('blog/robots.txt', contentPaths.contentDir));
- const type = getEntryType(entry, contentPaths, contentFileExts, dataFileExts, false);
+ const type = getEntryType(entry, contentPaths, contentFileExts, dataFileExts);
expect(type).to.equal('unsupported');
});
it('Returns "ignored" for .DS_Store', () => {
const entry = fileURLToPath(new URL('blog/.DS_Store', contentPaths.contentDir));
- const type = getEntryType(entry, contentPaths, contentFileExts, dataFileExts, false);
+ const type = getEntryType(entry, contentPaths, contentFileExts, dataFileExts);
expect(type).to.equal('ignored');
});
it('Returns "ignored" for unsupported files using an underscore', () => {
const entry = fileURLToPath(new URL('blog/_draft-robots.txt', contentPaths.contentDir));
- const type = getEntryType(entry, contentPaths, contentFileExts, dataFileExts, false);
+ const type = getEntryType(entry, contentPaths, contentFileExts, dataFileExts);
expect(type).to.equal('ignored');
});
it('Returns "ignored" when using underscore on file name', () => {
const entry = fileURLToPath(new URL('blog/_first-post.md', contentPaths.contentDir));
- const type = getEntryType(entry, contentPaths, contentFileExts, dataFileExts, false);
+ const type = getEntryType(entry, contentPaths, contentFileExts, dataFileExts);
expect(type).to.equal('ignored');
});
it('Returns "ignored" when using underscore on directory name', () => {
const entry = fileURLToPath(new URL('blog/_draft/first-post.md', contentPaths.contentDir));
- const type = getEntryType(entry, contentPaths, contentFileExts, dataFileExts, false);
+ const type = getEntryType(entry, contentPaths, contentFileExts, dataFileExts);
expect(type).to.equal('ignored');
});
it('Returns "ignored" for images', () => {
const entry = fileURLToPath(new URL('blog/first-post.png', contentPaths.contentDir));
- const type = getEntryType(entry, contentPaths, contentFileExts, dataFileExts, true);
+ const type = getEntryType(entry, contentPaths, contentFileExts, dataFileExts);
expect(type).to.equal('ignored');
});
});
diff --git a/packages/astro/test/units/cookies/delete.test.js b/packages/astro/test/units/cookies/delete.test.js
index 67fa1306b..f4c9fab53 100644
--- a/packages/astro/test/units/cookies/delete.test.js
+++ b/packages/astro/test/units/cookies/delete.test.js
@@ -30,7 +30,7 @@ describe('astro/src/core/cookies', () => {
expect(cookies.get('foo').value).to.equal('bar');
cookies.delete('foo');
- expect(cookies.get('foo').value).to.equal(undefined);
+ expect(cookies.get('foo')).to.equal(undefined);
});
it('calling cookies.has() after returns false', () => {
diff --git a/packages/astro/test/units/cookies/get.test.js b/packages/astro/test/units/cookies/get.test.js
index f044d715a..216128907 100644
--- a/packages/astro/test/units/cookies/get.test.js
+++ b/packages/astro/test/units/cookies/get.test.js
@@ -16,6 +16,13 @@ describe('astro/src/core/cookies', () => {
expect(cookies.get('foo').value).to.equal('bar');
});
+ it("Returns undefined is the value doesn't exist", () => {
+ const req = new Request('http://example.com/');
+ let cookies = new AstroCookies(req);
+ let cookie = cookies.get('foo');
+ expect(cookie).to.equal(undefined);
+ });
+
describe('.json()', () => {
it('returns a JavaScript object', () => {
const req = new Request('http://example.com/', {
@@ -29,13 +36,6 @@ describe('astro/src/core/cookies', () => {
expect(json).to.be.an('object');
expect(json.key).to.equal('value');
});
-
- it('throws if the value is undefined', () => {
- const req = new Request('http://example.com/');
- let cookies = new AstroCookies(req);
- let cookie = cookies.get('foo');
- expect(() => cookie.json()).to.throw('Cannot convert undefined to an object.');
- });
});
describe('.number()', () => {
diff --git a/packages/astro/test/units/integrations/api.test.js b/packages/astro/test/units/integrations/api.test.js
index 919628da2..a420dd6c9 100644
--- a/packages/astro/test/units/integrations/api.test.js
+++ b/packages/astro/test/units/integrations/api.test.js
@@ -1,5 +1,7 @@
import { expect } from 'chai';
import { runHookBuildSetup } from '../../../dist/integrations/index.js';
+import { validateSupportedFeatures } from '../../../dist/integrations/astroFeaturesValidation.js';
+import { defaultLogging } from '../test-utils.js';
describe('Integration API', () => {
it('runHookBuildSetup should work', async () => {
@@ -28,3 +30,187 @@ describe('Integration API', () => {
expect(updatedViteConfig).to.haveOwnProperty('define');
});
});
+
+describe('Astro feature map', function () {
+ it('should support the feature when stable', () => {
+ let result = validateSupportedFeatures(
+ 'test',
+ {
+ hybridOutput: 'stable',
+ },
+ {
+ output: 'hybrid',
+ },
+ defaultLogging
+ );
+ expect(result['hybridOutput']).to.be.true;
+ });
+
+ it('should not support the feature when not provided', () => {
+ let result = validateSupportedFeatures(
+ 'test',
+ undefined,
+ {
+ output: 'hybrid',
+ },
+ defaultLogging
+ );
+ expect(result['hybridOutput']).to.be.false;
+ });
+
+ it('should not support the feature when an empty object is provided', () => {
+ let result = validateSupportedFeatures(
+ 'test',
+ {},
+ {
+ output: 'hybrid',
+ },
+ defaultLogging
+ );
+ expect(result['hybridOutput']).to.be.false;
+ });
+
+ describe('static output', function () {
+ it('should be supported with the correct config', () => {
+ let result = validateSupportedFeatures(
+ 'test',
+ { staticOutput: 'stable' },
+ {
+ output: 'static',
+ },
+ defaultLogging
+ );
+ expect(result['staticOutput']).to.be.true;
+ });
+
+ it("should not be valid if the config is correct, but the it's unsupported", () => {
+ let result = validateSupportedFeatures(
+ 'test',
+ { staticOutput: 'unsupported' },
+ {
+ output: 'static',
+ },
+ defaultLogging
+ );
+ expect(result['staticOutput']).to.be.false;
+ });
+ });
+ describe('hybrid output', function () {
+ it('should be supported with the correct config', () => {
+ let result = validateSupportedFeatures(
+ 'test',
+ { hybridOutput: 'stable' },
+ {
+ output: 'hybrid',
+ },
+ defaultLogging
+ );
+ expect(result['hybridOutput']).to.be.true;
+ });
+
+ it("should not be valid if the config is correct, but the it's unsupported", () => {
+ let result = validateSupportedFeatures(
+ 'test',
+ {
+ hybridOutput: 'unsupported',
+ },
+ {
+ output: 'hybrid',
+ },
+ defaultLogging
+ );
+ expect(result['hybridOutput']).to.be.false;
+ });
+ });
+ describe('server output', function () {
+ it('should be supported with the correct config', () => {
+ let result = validateSupportedFeatures(
+ 'test',
+ { serverOutput: 'stable' },
+ {
+ output: 'server',
+ },
+ defaultLogging
+ );
+ expect(result['serverOutput']).to.be.true;
+ });
+
+ it("should not be valid if the config is correct, but the it's unsupported", () => {
+ let result = validateSupportedFeatures(
+ 'test',
+ {
+ serverOutput: 'unsupported',
+ },
+ {
+ output: 'server',
+ },
+ defaultLogging
+ );
+ expect(result['serverOutput']).to.be.false;
+ });
+ });
+
+ describe('assets', function () {
+ it('should be supported when it is sharp compatible', () => {
+ let result = validateSupportedFeatures(
+ 'test',
+ {
+ assets: {
+ supportKind: 'stable',
+ isSharpCompatible: true,
+ },
+ },
+ {
+ image: {
+ service: {
+ entrypoint: 'astro/assets/services/sharp',
+ },
+ },
+ },
+ defaultLogging
+ );
+ expect(result['assets']).to.be.true;
+ });
+ it('should be supported when it is squoosh compatible', () => {
+ let result = validateSupportedFeatures(
+ 'test',
+ {
+ assets: {
+ supportKind: 'stable',
+ isSquooshCompatible: true,
+ },
+ },
+ {
+ image: {
+ service: {
+ entrypoint: 'astro/assets/services/squoosh',
+ },
+ },
+ },
+ defaultLogging
+ );
+ expect(result['assets']).to.be.true;
+ });
+
+ it("should not be valid if the config is correct, but the it's unsupported", () => {
+ let result = validateSupportedFeatures(
+ 'test',
+ {
+ assets: {
+ supportKind: 'unsupported',
+ isNodeCompatible: false,
+ },
+ },
+ {
+ image: {
+ service: {
+ entrypoint: 'astro/assets/services/sharp',
+ },
+ },
+ },
+ defaultLogging
+ );
+ expect(result['assets']).to.be.false;
+ });
+ });
+});
diff --git a/packages/astro/test/units/render/head.test.js b/packages/astro/test/units/render/head.test.js
index fbd16be31..d2580e30d 100644
--- a/packages/astro/test/units/render/head.test.js
+++ b/packages/astro/test/units/render/head.test.js
@@ -90,13 +90,14 @@ describe('core/render', () => {
const PageModule = createAstroModule(Page);
const ctx = await createRenderContext({
+ route: { type: 'page', pathname: '/index' },
request: new Request('http://example.com/'),
links: [{ name: 'link', props: { rel: 'stylesheet', href: '/main.css' }, children: '' }],
mod: PageModule,
env,
});
- const response = await tryRenderRoute('page', ctx, env, PageModule);
+ const response = await tryRenderRoute(ctx, env, PageModule);
const html = await response.text();
const $ = cheerio.load(html);
@@ -170,13 +171,14 @@ describe('core/render', () => {
const PageModule = createAstroModule(Page);
const ctx = await createRenderContext({
+ route: { type: 'page', pathname: '/index' },
request: new Request('http://example.com/'),
links: [{ name: 'link', props: { rel: 'stylesheet', href: '/main.css' }, children: '' }],
env,
mod: PageModule,
});
- const response = await tryRenderRoute('page', ctx, env, PageModule);
+ const response = await tryRenderRoute(ctx, env, PageModule);
const html = await response.text();
const $ = cheerio.load(html);
@@ -216,13 +218,14 @@ describe('core/render', () => {
const PageModule = createAstroModule(Page);
const ctx = await createRenderContext({
+ route: { type: 'page', pathname: '/index' },
request: new Request('http://example.com/'),
links: [{ name: 'link', props: { rel: 'stylesheet', href: '/main.css' }, children: '' }],
env,
mod: PageModule,
});
- const response = await tryRenderRoute('page', ctx, env, PageModule);
+ const response = await tryRenderRoute(ctx, env, PageModule);
const html = await response.text();
const $ = cheerio.load(html);
diff --git a/packages/astro/test/units/render/jsx.test.js b/packages/astro/test/units/render/jsx.test.js
index 9be135fc0..1464b5b0c 100644
--- a/packages/astro/test/units/render/jsx.test.js
+++ b/packages/astro/test/units/render/jsx.test.js
@@ -45,12 +45,13 @@ describe('core/render', () => {
const mod = createAstroModule(Page);
const ctx = await createRenderContext({
+ route: { type: 'page', pathname: '/index' },
request: new Request('http://example.com/'),
env,
mod,
});
- const response = await tryRenderRoute('page', ctx, env, mod);
+ const response = await tryRenderRoute(ctx, env, mod);
expect(response.status).to.equal(200);
@@ -90,11 +91,12 @@ describe('core/render', () => {
const mod = createAstroModule(Page);
const ctx = await createRenderContext({
+ route: { type: 'page', pathname: '/index' },
request: new Request('http://example.com/'),
env,
mod,
});
- const response = await tryRenderRoute('page', ctx, env, mod);
+ const response = await tryRenderRoute(ctx, env, mod);
expect(response.status).to.equal(200);
@@ -115,12 +117,13 @@ describe('core/render', () => {
const mod = createAstroModule(Page);
const ctx = await createRenderContext({
+ route: { type: 'page', pathname: '/index' },
request: new Request('http://example.com/'),
env,
mod,
});
- const response = await tryRenderRoute('page', ctx, env, mod);
+ const response = await tryRenderRoute(ctx, env, mod);
try {
await response.text();
diff --git a/packages/astro/tsconfig.json b/packages/astro/tsconfig.json
index 839239eaf..63854a31d 100644
--- a/packages/astro/tsconfig.json
+++ b/packages/astro/tsconfig.json
@@ -6,7 +6,7 @@
"declarationDir": "./dist",
"module": "ES2022",
"outDir": "./dist",
- "target": "ES2021",
+ "target": "ES2022",
"jsx": "preserve",
"types": ["@types/dom-view-transitions", "network-information-types"]
}
diff --git a/packages/astro/tsconfigs/base.json b/packages/astro/tsconfigs/base.json
index aa1f17543..578693195 100644
--- a/packages/astro/tsconfigs/base.json
+++ b/packages/astro/tsconfigs/base.json
@@ -5,27 +5,24 @@
"target": "ESNext",
"module": "ESNext",
// Enable node-style module resolution, for things like npm package imports.
- "moduleResolution": "node",
+ "moduleResolution": "Bundler",
+ // Allow importing TypeScript files using their native extension (.ts(x)).
+ "allowImportingTsExtensions": true,
// Enable JSON imports.
"resolveJsonModule": true,
- // Enable stricter transpilation for better output.
+ // Enforce the usage of type-only imports when needed, which helps avoiding bundling issues.
+ "verbatimModuleSyntax": true,
+ // Ensure that each file can be transpiled without relying on other imports.
+ // This is redundant with the previous option, however it ensures that it's on even if someone disable `verbatimModuleSyntax`
"isolatedModules": true,
// Astro directly run TypeScript code, no transpilation needed.
"noEmit": true,
- // Report an error when importing a file using a casing different from the casing on disk.
+ // Report an error when importing a file using a casing different from another import of the same file.
"forceConsistentCasingInFileNames": true,
// Properly support importing CJS modules in ESM
"esModuleInterop": true,
// Skip typechecking libraries and .d.ts files
"skipLibCheck": true,
- // Add alias for assets folder for easy reference to assets
- "baseUrl": ".",
- "paths": {
- "~/assets/*": ["src/assets/*"]
- },
- // TypeScript 5.0 changed how `isolatedModules` and `importsNotUsedAsValues` works, deprecating the later
- // Until the majority of users are on TypeScript 5.0, we'll have to supress those deprecation errors
- "ignoreDeprecations": "5.0",
// Allow JavaScript files to be imported
"allowJs": true
}
diff --git a/packages/astro/tsconfigs/strict.json b/packages/astro/tsconfigs/strict.json
index bc87a68e0..3064440a5 100644
--- a/packages/astro/tsconfigs/strict.json
+++ b/packages/astro/tsconfigs/strict.json
@@ -2,8 +2,7 @@
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "./base.json",
"compilerOptions": {
- "strict": true,
- // Error when a value import is only used as a type.
- "importsNotUsedAsValues": "error"
+ // Enable strict mode. This enables a few options at a time, see https://www.typescriptlang.org/tsconfig#strict for a list.
+ "strict": true
}
}