diff options
author | 2022-04-02 13:29:59 -0500 | |
---|---|---|
committer | 2022-04-02 12:29:59 -0600 | |
commit | 17c02925c52027246000305cea1f9a7b6f484b00 (patch) | |
tree | 687b8ca9e7b89b06dad65ae195619ea2ea50f57b | |
parent | 76f6643dddb9343218020cf7585be92a1fe45d3a (diff) | |
download | astro-17c02925c52027246000305cea1f9a7b6f484b00.tar.gz astro-17c02925c52027246000305cea1f9a7b6f484b00.tar.zst astro-17c02925c52027246000305cea1f9a7b6f484b00.zip |
Migrate to new config (#2962)
* wip: config migration
* fix: formatting
* refactor: projectRoot -> root
* refactor: pageUrlFormat -> format
* refactor: buildOptions.site -> site
* refactor: public -> publicDir
* refactor: dist -> outDir
* refactor: styleOptions -> style
* fix: some dist tests -> outDir
* refactor: remove legacyBuild (with TODOs)
* refactor: more legacyBuild cleanup
* refactor: server host and port
* fix: remove experimentalStaticBuild CLI flag
* refactor: src -> srcDir
* refactor: devOptions.trailing -> trailing
* refactor: remove sitemap + related flags
* refactor: experimentalSSR -> experimental.ssr
* fix: last devOptions
* refactor: drafts -> markdown.drafts
* fix: TS error on port as const
* refactor: remove pages
* refactor: more --project-root updates
* refactor: markdownOptions -> markdown
* fix: remaining type errors
* feat: update AstroUserConfig
* refactor: update CLI flag mapper + server mapper
* fix: loadFixture projectRoot
* fix: merge CLI flags before validating / transforming
* wip: attempt to fix bad createRouteManifest config
* refactor: combine config.base and config.site
* fix: skip route manifest test for now
* fix: site and base handling
* refactor: update failing config testes
* fix: build failure
* feat: update config types with migration help
* chore: update types
* fix(deno): update deno fixture
* chore: remove config migration logic
* chore: remove logLevel
* chore: clean-up config types
* chore: update config warning
* chore: add changeset
* Sitemap Integration (#2965)
* feat: add sitemap filter config option
* feat: add canonicalURL sitemap config option
* docs: update sitemap README
* fix: update for new config
* fix: filter not being applied
* chore: changeset
Co-authored-by: bholmesdev <hey@bholmes.dev>
* fred pass
* fix: Astro.resolve typo
* fix: public => publicDir
Co-authored-by: bholmesdev <hey@bholmes.dev>
Co-authored-by: Fred K. Schott <fkschott@gmail.com>
137 files changed, 1208 insertions, 1360 deletions
diff --git a/.changeset/tall-cooks-begin.md b/.changeset/tall-cooks-begin.md new file mode 100644 index 000000000..d1bff3790 --- /dev/null +++ b/.changeset/tall-cooks-begin.md @@ -0,0 +1,7 @@ +--- +'@astrojs/sitemap': patch +--- + +Add new sitemap configuration options: +- `filter`: filter pages to include in your sitemap +- `canonicalURL`: override your astro.config `site` with a custom base URL diff --git a/.changeset/wicked-toes-flow.md b/.changeset/wicked-toes-flow.md new file mode 100644 index 000000000..aca2d3b64 --- /dev/null +++ b/.changeset/wicked-toes-flow.md @@ -0,0 +1,11 @@ +--- +'astro': minor +'@astrojs/deno': minor +'@astrojs/netlify': minor +'@astrojs/partytown': minor +'@astrojs/sitemap': minor +'@astrojs/tailwind': minor +'@astrojs/markdown-remark': minor +--- + +Update config options to resepect [RFC0019](https://github.com/withastro/rfcs/blob/main/proposals/0019-config-finalization.md) diff --git a/examples/blog-multiple-authors/src/pages/posts/[...page].astro b/examples/blog-multiple-authors/src/pages/posts/[...page].astro index 7711a940c..f770aadb2 100644 --- a/examples/blog-multiple-authors/src/pages/posts/[...page].astro +++ b/examples/blog-multiple-authors/src/pages/posts/[...page].astro @@ -10,7 +10,7 @@ export async function getStaticPaths({ paginate, rss }) { const sortedPosts = allPosts.sort((a, b) => new Date(b.frontmatter.date).valueOf() - new Date(a.frontmatter.date).valueOf()); // Generate an RSS feed from this collection of posts. - // NOTE: This is disabled by default, since it requires `buildOptions.site` to be set in your "astro.config.mjs" file. + // NOTE: This is disabled by default, since it requires `site` to be set in your "astro.config.mjs" file. // rss({ // title: 'Don’s Blog', // description: 'An example blog on Astro', diff --git a/examples/blog/astro.config.mjs b/examples/blog/astro.config.mjs index e8f14324a..be7ee7079 100644 --- a/examples/blog/astro.config.mjs +++ b/examples/blog/astro.config.mjs @@ -4,7 +4,6 @@ import preact from '@astrojs/preact'; // https://astro.build/config export default defineConfig({ integrations: [preact()], - buildOptions: { - site: 'https://example.com/', - }, + site: 'https://example.com', + base: '/subpath', }); diff --git a/examples/component/package.json b/examples/component/package.json index e7e63cb83..5bf96a6a0 100644 --- a/examples/component/package.json +++ b/examples/component/package.json @@ -3,9 +3,9 @@ "version": "0.0.1", "private": true, "scripts": { - "start": "astro --project-root demo dev", - "build": "astro --project-root demo build", - "serve": "astro --project-root demo preview" + "start": "astro --root demo dev", + "build": "astro --root demo build", + "serve": "astro --root demo preview" }, "devDependencies": { "astro": "^0.25.4" diff --git a/examples/subpath/astro.config.mjs b/examples/subpath/astro.config.mjs index bb680d762..02b050efc 100644 --- a/examples/subpath/astro.config.mjs +++ b/examples/subpath/astro.config.mjs @@ -4,7 +4,5 @@ import react from '@astrojs/react'; // https://astro.build/config export default defineConfig({ integrations: [react()], - buildOptions: { - site: 'http://example.com/blog', - }, + site: 'http://example.com/blog', }); diff --git a/examples/with-markdown-plugins/astro.config.mjs b/examples/with-markdown-plugins/astro.config.mjs index 0e112712a..114cbbd0a 100644 --- a/examples/with-markdown-plugins/astro.config.mjs +++ b/examples/with-markdown-plugins/astro.config.mjs @@ -1,17 +1,11 @@ import { defineConfig } from 'astro/config'; -import astroRemark from '@astrojs/markdown-remark'; import addClasses from './add-classes.mjs'; // https://astro.build/config export default defineConfig({ // Enable Custom Markdown options, plugins, etc. - markdownOptions: { - render: [ - astroRemark, - { - remarkPlugins: ['remark-code-titles'], - rehypePlugins: [['rehype-autolink-headings', { behavior: 'prepend' }], ['rehype-toc', { headings: ['h2', 'h3'] }], [addClasses, { 'h1,h2,h3': 'title' }], 'rehype-slug'], - }, - ], + markdown: { + remarkPlugins: ['remark-code-titles'], + rehypePlugins: [['rehype-autolink-headings', { behavior: 'prepend' }], ['rehype-toc', { headings: ['h2', 'h3'] }], [addClasses, { 'h1,h2,h3': 'title' }], 'rehype-slug'], }, }); diff --git a/examples/with-markdown-shiki/astro.config.mjs b/examples/with-markdown-shiki/astro.config.mjs index 7a0b4f0f2..0a928c898 100644 --- a/examples/with-markdown-shiki/astro.config.mjs +++ b/examples/with-markdown-shiki/astro.config.mjs @@ -1,20 +1,14 @@ import { defineConfig } from 'astro/config'; -import astroRemark from '@astrojs/markdown-remark'; // https://astro.build/config export default defineConfig({ // Enable Custom Markdown options, plugins, etc. - markdownOptions: { - render: [ - astroRemark, - { - syntaxHighlight: 'shiki', - shikiConfig: { - theme: 'dracula', - // Learn more about this configuration here: - // https://docs.astro.build/en/guides/markdown-content/#syntax-highlighting - }, - }, - ], - }, + markdown: { + syntaxHighlight: 'shiki', + shikiConfig: { + theme: 'dracula', + // Learn more about this configuration here: + // https://docs.astro.build/en/guides/markdown-content/#syntax-highlighting + }, + } }); diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index 0f1e48e13..98b76757c 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -2,6 +2,7 @@ import type { AddressInfo } from 'net'; import type * as babel from '@babel/core'; import type * as vite from 'vite'; import { z } from 'zod'; +import type { ShikiConfig, Plugin } from '@astrojs/markdown-remark'; import type { AstroConfigSchema } from '../core/config'; import type { AstroComponentFactory, Metadata } from '../runtime/server'; import type { ViteConfigWithSSR } from '../core/create-vite'; @@ -24,18 +25,13 @@ export interface AstroComponentMetadata { /** The flags supported by the Astro CLI */ export interface CLIFlags { - projectRoot?: string; + root?: string; site?: string; - sitemap?: boolean; host?: string | boolean; - hostname?: string; port?: number; config?: string; - /** @deprecated */ - experimentalStaticBuild?: boolean; experimentalSsr?: boolean; experimentalIntegrations?: boolean; - legacyBuild?: boolean; drafts?: boolean; } @@ -76,6 +72,32 @@ export interface AstroGlobalPartial { site: URL; } +type ServerConfig = { + /** + * @name server.host + * @type {string | boolean} + * @default `false` + * @version 0.24.0 + * @description + * Set which network IP addresses the dev server should listen on (i.e. non-localhost IPs). + * - `false` - do not expose on a network IP address + * - `true` - listen on all addresses, including LAN and public addresses + * - `[custom-address]` - expose on a network IP address at `[custom-address]` + */ + host?: string | boolean; + + /** + * @name server.port + * @type {number} + * @default `3000` + * @description + * Set which port the dev server should listen on. + * + * If the given port is already in use, Astro will automatically try the next available port. + */ + port?: number; +}; + /** * Astro User Config * Docs: https://docs.astro.build/reference/configuration-reference/ @@ -89,50 +111,50 @@ export interface AstroUserConfig { /** * @docs - * @name projectRoot - * @cli --project-root + * @name root + * @cli --root * @type {string} * @default `"."` (current working directory) * @summary Set the project root. The project root is the directory where your Astro project (and all `src`, `public` and `package.json` files) live. * @description You should only provide this option if you run the `astro` CLI commands in a directory other than the project root directory. Usually, this option is provided via the CLI instead of the `astro.config.js` file, since Astro needs to know your project root before it can locate your config file. * - * If you provide a relative path (ex: `--project-root: './my-project'`) Astro will resolve it against your current working directory. + * If you provide a relative path (ex: `--root: './my-project'`) Astro will resolve it against your current working directory. * * #### Examples * * ```js * { - * projectRoot: './my-project-directory' + * root: './my-project-directory' * } * ``` * ```bash - * $ astro build --project-root ./my-project-directory + * $ astro build --root ./my-project-directory * ``` */ - projectRoot?: string; + root?: string; /** * @docs - * @name dist + * @name srcDir * @type {string} - * @default `"./dist"` - * @description Set the directory that `astro build` writes your final build to. + * @default `"./src"` + * @description Set the directory that Astro will read your site from. * * The value can be either an absolute file system path or a path relative to the project root. * * ```js * { - * dist: './my-custom-build-directory' + * srcDir: './www' * } * ``` */ - dist?: string; + srcDir?: string; /** * @docs - * @name public + * @name publicDir * @type {string} - * @default `"./public"` + * @default `"./publicDir"` * @description * Set the directory for your static assets. Files in this directory are served at `/` during dev and copied to your build directory during build. These files are always served or copied as-is, without transform or bundling. * @@ -140,162 +162,95 @@ export interface AstroUserConfig { * * ```js * { - * public: './my-custom-public-directory' + * publicDir: './my-custom-publicDir-directory' * } * ``` */ - public?: string; + publicDir?: string; /** * @docs - * @name integrations - * @type {AstroIntegration[]} - * @default `[]` - * @description - * Add Integrations to your project to extend Astro. - * - * Integrations are your one-stop shop to add new frameworks (like Solid.js), new features (like sitemaps), and new libraries (like Partytown and Turbolinks). - * - * Setting this configuration will disable Astro's default integration, so it is recommended to provide a renderer for every framework that you use: + * @name outDir + * @type {string} + * @default `"./outDir"` + * @description Set the directory that `astro build` writes your final build to. * - * Note: Integrations are currently under active development, and only first-party integrations are supported. In the future, 3rd-party integrations will be allowed. + * The value can be either an absolute file system path or a path relative to the project root. * * ```js - * import react from '@astrojs/react'; - * import vue from '@astrojs/vue'; * { - * // Example: Use Astro with Vue + React, and no other frameworks. - * integrations: [react(), vue()] + * outDir: './my-custom-build-directory' * } * ``` */ - integrations?: Array<AstroIntegration | AstroIntegration[]>; + outDir?: string; /** - * @name adapter - * @type {AstroIntegration} - * @default `undefined` + * @docs + * @name site + * @type {string} * @description - * Add an adapter to build for SSR (server-side rendering). An adapter makes it easy to connect a deployed Astro app to a hosting provider or runtime environment. + * Your final, deployed URL. Astro uses this full URL to generate your sitemap and canonical URLs in your final build. It is strongly recommended that you set this configuration to get the most out of Astro. + * + * ```js + * { + * site: 'https://www.my-site.dev' + * } + * ``` */ - adapter?: AstroIntegration; - - /** @deprecated - Use "integrations" instead. Run Astro to learn more about migrating. */ - renderers?: string[]; + site?: string; /** * @docs - * @name markdownOptions - * @type {{render: MarkdownRenderOptions}} - * @see [Markdown guide](/en/guides/markdown-content/) + * @name base + * @type {string} * @description - * Configure how markdown files (`.md`) are rendered. + * The base path you're deploying to. Astro will match this pathname during development so that your development experience matches your build environment as closely as possible. In the example below, `astro dev` will start your server at `/docs`. * * ```js - * import { defineConfig } from "astro/config"; - * import astroRemark from "@astrojs/markdown-remark"; - * import customRehypePlugin from "/path/to/rehypePlugin.mjs"; + * { + * base: '/docs' + * } + * ``` + */ + base?: string; + + /** + * @docs + * @name trailingSlash + * @type {('always' | 'never' | 'ignore')} + * @default `'always'` + * @see buildOptions.pageUrlFormat + * @description + * + * Set the route matching behavior of the dev server. Choose from the following options: + * - `'always'` - Only match URLs that include a trailing slash (ex: "/foo/") + * - `'never'` - Never match URLs that include a trailing slash (ex: "/foo") + * - `'ignore'` - Match URLs regardless of whether a trailing "/" exists + * + * Use this configuration option if your production host has strict handling of how trailing slashes work or do not work. * - * export default defineConfig({ - * // Enable Custom Markdown options, plugins, etc. - * markdownOptions: { - * render: [ - * // The Remark parser to parse Markdown content - * astroRemark, - * { - * // Add a Remark plugin to your project. - * remarkPlugins: ["remark-code-titles"], + * You can also set this if you prefer to be more strict yourself, so that URLs with or without trailing slashes won't work during development. * - * // Add a Rehype plugin to your project. - * rehypePlugins: [ - * "rehype-slug", - * [customRehypePlugin, { configKey: "value" }], - * ["rehype-autolink-headings", { behavior: "prepend" }], - * ], - * }, - * ], - * }, - * }); + * ```js + * { + * // Example: Require a trailing slash during development + * trailingSlash: 'always' + * } * ``` */ - markdownOptions?: { - render?: MarkdownRenderOptions; - }; + trailingSlash?: 'always' | 'never' | 'ignore'; /** * @docs * @kind heading * @name Build Options */ - buildOptions?: { - /** - * @docs - * @name buildOptions.site - * @type {string} - * @description - * Your final, deployed URL. Astro uses this full URL to generate your sitemap and canonical URLs in your final build. It is strongly recommended that you set this configuration to get the most out of Astro. - * - * Astro will match the site pathname during development so that your development experience matches your build environment as closely as possible. In the example below, `astro dev` will start your server at `http://localhost:3000/docs`. - * - * ```js - * { - * buildOptions: { - * // Example: Tell Astro the final URL of your deployed website. - * site: 'https://www.my-site.dev/docs' - * } - * } - * ``` - */ - site?: string; - - /** - * @docs - * @name buildOptions.sitemap - * @type {boolean} - * @default `true` - * @description - * Generate a sitemap for your build. Set to false to disable. - * - * Astro will automatically generate a sitemap including all generated pages on your site. If you need more control over your sitemap, consider generating it yourself using a [Non-HTML Page](/en/core-concepts/astro-pages/#non-html-pages). - * - * ```js - * { - * buildOptions: { - * // Example: Disable automatic sitemap generation - * sitemap: false - * } - * } - * ``` - */ - sitemap?: boolean; - - /** - * @docs - * @name buildOptions.sitemapFilter - * @typeraw {(page: string) => boolean} - * @see buildOptions.sitemap - * @description - * By default, all pages are included in your generated sitemap. - * You can filter included pages by URL using `buildOptions.sitemapFilter`. - * - * The `page` function parameter is the full URL of your rendered page, including your `buildOptions.site` domain. - * Return `true` to include a page in your sitemap, and `false` to remove it. - * - * ```js - * { - * buildOptions: { - * sitemap: true - * sitemapFilter: (page) => page !== 'http://example.com/secret-page') - * } - * } - * ``` - */ - sitemapFilter?: (page: string) => boolean; - + build?: { /** * @docs - * @name buildOptions.pageUrlFormat - * @type {('file' | 'directory')} + * @name build.format + * @typeraw {('file' | 'directory')} * @default `'directory'` * @description * Control the output file format of each page. @@ -304,18 +259,75 @@ export interface AstroUserConfig { * * ```js * { - * buildOptions: { + * build: { * // Example: Generate `page.html` instead of `page/index.html` during build. - * pageUrlFormat: 'file' + * format: 'file' * } * } * ``` */ - pageUrlFormat?: 'file' | 'directory'; + format?: 'file' | 'directory'; + }; + + /** + * @docs + * @kind heading + * @name Server Options + * @description + * + * Customize the Astro dev server, used by both `astro dev` and `astro serve`. + * + * ```js + * { + * server: {port: 1234, host: true} + * } + * ``` + * + * To set different configuration based on the command run ("dev", "preview") a function can also be passed to this configuration option. + * + * ```js + * { + * // Example: Use the function syntax to customize based on command + * server: (command) => ({port: command === 'dev' ? 3000 : 4000}) + * } + * ``` + */ + + /** + * @docs + * @name server.host + * @type {string | boolean} + * @default `false` + * @version 0.24.0 + * @description + * Set which network IP addresses the dev server should listen on (i.e. non-localhost IPs). + * - `false` - do not expose on a network IP address + * - `true` - listen on all addresses, including LAN and public addresses + * - `[custom-address]` - expose on a network IP address at `[custom-address]` + */ + + /** + * @docs + * @name server.port + * @type {number} + * @default `3000` + * @description + * Set which port the dev server should listen on. + * + * If the given port is already in use, Astro will automatically try the next available port. + */ + + server?: ServerConfig | ((options: { command: 'dev' | 'preview' }) => ServerConfig); + /** + * @docs + * @kind heading + * @name Markdown Options + */ + markdown?: { /** * @docs - * @name buildOptions.drafts + * @name markdown.drafts * @type {boolean} * @default `false` * @description @@ -325,117 +337,121 @@ export interface AstroUserConfig { * * ```js * { - * buildOptions: { + * markdown: { * // Example: Include all drafts in your final build - * drafts: true, + * drafts: true, * } * } * ``` */ drafts?: boolean; - /** - * Enables "legacy build mode" for compatibility with older Astro versions. - * Default: false - */ - legacyBuild?: boolean; - /** - * @deprecated - * Experimental: Enables "static build mode" for faster builds. - * Default: true - */ - experimentalStaticBuild?: boolean; - /** - * Enable SSR support for 3rd-party adapters. - * Not required when using a built-in adapter. - * Default: false - */ - experimentalSsr?: boolean; - }; - /** - * @docs - * @kind heading - * @name Dev Options - */ - devOptions?: { /** * @docs - * @name devOptions.host - * @type {string | boolean} - * @default `false` - * @version 0.24.0 + * @name markdown.shikiConfig + * @type {ShikiConfig} * @description - * Set which network IP addresses the dev server should listen on (i.e. non-localhost IPs). - * - `false` - do not expose on a network IP address - * - `true` - listen on all addresses, including LAN and public addresses - * - `[custom-address]` - expose on a network IP address at `[custom-address]` + * Shiki configuration options. See [the markdown configuration docs](https://docs.astro.build/en/guides/markdown-content/#shiki-configuration) for usage. */ - host?: string | boolean; + shikiConfig?: ShikiConfig; /** * @docs - * @name devOptions.hostname - * @type {string} - * @default `'localhost'` - * @deprecated Use `host` instead + * @name markdown.syntaxHighlight + * @type {'shiki' | 'prism' | false} + * @default `shiki` * @description - * > **This option is deprecated.** Consider using `host` instead. - * - * Set which IP addresses the dev server should listen on. Set this to 0.0.0.0 to listen on all addresses, including LAN and public addresses. + * Which syntax highlighter to use, if any. + * - `shiki` - use the [Shiki](https://github.com/shikijs/shiki) highlighter + * - `prism` - use the [Prism](https://prismjs.com/) highlighter + * - `false` - do not apply syntax highlighting. + * + * ```js + * { + * markdown: { + * // Example: Switch to use prism for syntax highlighting in Markdown + * syntaxHighlight: 'prism', + * } + * } + * ``` */ - hostname?: string; + syntaxHighlight?: 'shiki' | 'prism' | false; /** * @docs - * @name devOptions.port - * @type {number} - * @default `3000` + * @name markdown.remarkPlugins + * @type {Plugin[]} * @description - * Set which port the dev server should listen on. - * - * If the given port is already in use, Astro will automatically try the next available port. + * Pass a custom [Remark](https://github.com/remarkjs/remark) plugin to customize how your Markdown is built. + * + * **Note:** Enabling custom `remarkPlugins` or `rehypePlugins` removes Astro's built-in support for [GitHub-flavored Markdown](https://github.github.com/gfm/) support, [Footnotes](https://github.com/remarkjs/remark-footnotes) syntax, [Smartypants](https://github.com/silvenon/remark-smartypants). You must explicitly add these plugins to your `astro.config.mjs` file, if desired. + * + * ```js + * { + * markdown: { + * // Example: The default set of remark plugins used by Astro + * remarkPlugins: ['remark-code-titles', ['rehype-autolink-headings', { behavior: 'prepend' }]], + * }, + * }; + * ``` */ - port?: number; - + remarkPlugins?: Plugin[]; /** * @docs - * @name devOptions.trailingSlash - * @type {('always' | 'never' | 'ignore')} - * @default `'always'` - * @see buildOptions.pageUrlFormat + * @name markdown.rehypePlugins + * @type {Plugin[]} * @description - * - * Set the route matching behavior of the dev server. Choose from the following options: - * - 'always' - Only match URLs that include a trailing slash (ex: "/foo/") - * - 'never' - Never match URLs that include a trailing slash (ex: "/foo") - * - 'ignore' - Match URLs regardless of whether a trailing "/" exists - * - * Use this configuration option if your production host has strict handling of how trailing slashes work or do not work. - * - * You can also set this if you prefer to be more strict yourself, so that URLs with or without trailing slashes won't work during development. - * - * ```js - * { - * devOptions: { - * // Example: Require a trailing slash during development - * trailingSlash: 'always' - * } - * } - * ``` + * Pass a custom [Rehype](https://github.com/remarkjs/remark-rehype) plugin to customize how your Markdown is built. + * + * **Note:** Enabling custom `remarkPlugins` or `rehypePlugins` removes Astro's built-in support for [GitHub-flavored Markdown](https://github.github.com/gfm/) support, [Footnotes](https://github.com/remarkjs/remark-footnotes) syntax, [Smartypants](https://github.com/silvenon/remark-smartypants). You must explicitly add these plugins to your `astro.config.mjs` file, if desired. + * + * ```js + * { + * markdown: { + * // Example: The default set of rehype plugins used by Astro + * rehypePlugins: [['rehype-toc', { headings: ['h2', 'h3'] }], [addClasses, { 'h1,h2,h3': 'title' }], 'rehype-slug'], + * }, + * }; + * ``` */ - trailingSlash?: 'always' | 'never' | 'ignore'; + rehypePlugins?: Plugin[]; }; /** - * Enable experimental support for 3rd-party integrations. - * Default: false + * @name adapter + * @type {AstroIntegration} + * @default `undefined` + * @description + * Add an adapter to build for SSR (server-side rendering). An adapter makes it easy to connect a deployed Astro app to a hosting provider or runtime environment. */ - experimentalIntegrations?: boolean; + adapter?: AstroIntegration; + + /** + * @docs + * @kind heading + * @name Integrations + * @description + * + * Extend Astro with custom integrations. Integrations are your one-stop-shop for adding framework support (like Solid.js), new features (like sitemaps), and new libraries (like Partytown and Turbolinks). + * + * Read our [Integrations Guide](/en/guides/integrations-guide/) for help getting started with Astro Integrations. + * + * ```js + * import react from '@astrojs/react'; + * import tailwind from '@astrojs/tailwind'; + * { + * // Example: Add React + Tailwind support to Astro + * integrations: [react(), tailwind()] + * } + * ``` + */ + integrations?: Array<AstroIntegration | AstroIntegration[]>; + /** * @docs - * @name vite - * @type {vite.UserConfig} + * @kind heading + * @name Vite * @description * * Pass additional configuration options to Vite. Useful when Astro doesn't support some advanced configuration that you may need. @@ -447,9 +463,9 @@ export interface AstroUserConfig { * ```js * { * vite: { - * ssr: { - * // Example: Force a broken package to skip SSR processing, if needed - * external: ['broken-npm-package'], + * ssr: { + * // Example: Force a broken package to skip SSR processing, if needed + * external: ['broken-npm-package'], * } * } * } @@ -459,12 +475,54 @@ export interface AstroUserConfig { * { * vite: { * // Example: Add custom vite plugins directly to your Astro project - * plugins: [myPlugin()], + * plugins: [myPlugin()], * } * } * ``` */ vite?: vite.UserConfig & { ssr?: vite.SSROptions }; + + experimental?: { + /** + * Enable experimental support for 3rd-party integrations. + * Default: false + */ + integrations?: boolean; + + /** + * Enable a build for SSR support. + * Default: false + */ + ssr?: boolean; + }; + + + + + // Legacy options to be removed + + /** @deprecated - Use "integrations" instead. Run Astro to learn more about migrating. */ + renderers?: never; + /** @deprecated `projectRoot` has been renamed to `root` */ + projectRoot?: never; + /** @deprecated `src` has been renamed to `srcDir` */ + src?: never; + /** @deprecated `pages` has been removed. It is no longer configurable. */ + pages?: never; + /** @deprecated `public` has been renamed to `publicDir` */ + public?: never; + /** @deprecated `dist` has been renamed to `outDir` */ + dist?: never; + /** @deprecated `styleOptions` has been renamed to `style` */ + styleOptions?: never; + /** @deprecated `markdownOptions` has been renamed to `markdown` */ + markdownOptions?: never; + /** @deprecated `buildOptions` has been renamed to `build` */ + buildOptions?: never; + /** @deprecated `devOptions` has been renamed to `server` */ + devOptions?: never; + /** @deprecated `experimentalIntegrations` has been renamed to `experimental: { integrations: true }` */ + experimentalIntegrations?: never; } // NOTE(fks): We choose to keep our hand-generated AstroUserConfig interface so that diff --git a/packages/astro/src/cli/check.ts b/packages/astro/src/cli/check.ts index ffdc246df..c691a33a3 100644 --- a/packages/astro/src/cli/check.ts +++ b/packages/astro/src/cli/check.ts @@ -64,7 +64,7 @@ function generateString(str: string, len: number) { export async function run() {} export async function check(astroConfig: AstroConfig) { - const root = astroConfig.projectRoot; + const root = astroConfig.root; let checker = new AstroCheck(root.toString()); await openAllDocuments(root, [], checker); diff --git a/packages/astro/src/cli/index.ts b/packages/astro/src/cli/index.ts index c68a97a74..50ef47531 100644 --- a/packages/astro/src/cli/index.ts +++ b/packages/astro/src/cli/index.ts @@ -36,8 +36,7 @@ function printAstroHelp() { flags: [ ['--host [optional IP]', 'Expose server on network'], ['--config <path>', 'Specify the path to the Astro config file.'], - ['--project-root <path>', 'Specify the path to the project root folder.'], - ['--no-sitemap', 'Disable sitemap generation (build only).'], + ['--root <path>', 'Specify the path to the project root folder.'], ['--legacy-build', 'Use the build strategy prior to 0.24.0'], ['--experimental-ssr', 'Enable SSR compilation fot 3rd-party adapters.'], ['--drafts', 'Include markdown draft pages in the build.'], @@ -74,7 +73,7 @@ function resolveCommand(flags: Arguments): CLICommand { export async function cli(args: string[]) { const flags = yargs(args); const cmd = resolveCommand(flags); - const projectRoot = flags.projectRoot; + const root = flags.root; switch (cmd) { case 'help': @@ -101,7 +100,7 @@ export async function cli(args: string[]) { try { // Note: ideally, `loadConfig` would return the config AND its filePath // For now, `add` has to resolve the config again internally - config = await loadConfig({ cwd: projectRoot, flags }); + config = await loadConfig({ cwd: root, flags, cmd }); } catch (err) { return throwAndExit(err); } @@ -110,7 +109,7 @@ export async function cli(args: string[]) { case 'add': { try { const packages = flags._.slice(3) as string[]; - return await add(packages, { cwd: projectRoot, flags, logging }); + return await add(packages, { cwd: root, flags, logging }); } catch (err) { return throwAndExit(err); } diff --git a/packages/astro/src/core/build/common.ts b/packages/astro/src/core/build/common.ts index a29aa356c..32c206fd6 100644 --- a/packages/astro/src/core/build/common.ts +++ b/packages/astro/src/core/build/common.ts @@ -5,7 +5,7 @@ import { appendForwardSlash } from '../../core/path.js'; const STATUS_CODE_PAGES = new Set(['/404', '/500']); function getOutRoot(astroConfig: AstroConfig): URL { - return new URL('./', astroConfig.dist); + return new URL('./', astroConfig.outDir); } export function getOutFolder(astroConfig: AstroConfig, pathname: string, routeType: RouteType): URL { @@ -16,7 +16,7 @@ export function getOutFolder(astroConfig: AstroConfig, pathname: string, routeTy case 'endpoint': return new URL('.' + appendForwardSlash(npath.dirname(pathname)), outRoot); case 'page': - switch (astroConfig.buildOptions.pageUrlFormat) { + switch (astroConfig.build.format) { case 'directory': { if (STATUS_CODE_PAGES.has(pathname)) { return new URL('.' + appendForwardSlash(npath.dirname(pathname)), outRoot); @@ -35,7 +35,7 @@ export function getOutFile(astroConfig: AstroConfig, outFolder: URL, pathname: s case 'endpoint': return new URL(npath.basename(pathname), outFolder); case 'page': - switch (astroConfig.buildOptions.pageUrlFormat) { + switch (astroConfig.build.format) { case 'directory': { if (STATUS_CODE_PAGES.has(pathname)) { const baseName = npath.basename(pathname); diff --git a/packages/astro/src/core/build/generate.ts b/packages/astro/src/core/build/generate.ts index 5d0c70a41..109aa0904 100644 --- a/packages/astro/src/core/build/generate.ts +++ b/packages/astro/src/core/build/generate.ts @@ -1,12 +1,13 @@ +import astroRemark from '@astrojs/markdown-remark'; import fs from 'fs'; -import { bgGreen, bgMagenta, black, cyan, dim, green, magenta } from 'kleur/colors'; +import { bgGreen, black, cyan, dim, green, magenta } from 'kleur/colors'; import npath from 'path'; import type { OutputAsset, OutputChunk, RollupOutput } from 'rollup'; import { fileURLToPath } from 'url'; import type { AstroConfig, ComponentInstance, EndpointHandler, SSRLoadedRenderer } from '../../@types/astro'; import type { BuildInternals } from '../../core/build/internal.js'; import { debug, info } from '../logger/core.js'; -import { appendForwardSlash, prependForwardSlash } from '../../core/path.js'; +import { prependForwardSlash } from '../../core/path.js'; import type { RenderOptions } from '../../core/render/core'; import { BEFORE_HYDRATION_SCRIPT_ID } from '../../vite-plugin-scripts/index.js'; import { call as callEndpoint } from '../endpoint/index.js'; @@ -51,7 +52,7 @@ function* throttle(max: number, inPaths: string[]) { // Gives back a facadeId that is relative to the root. // ie, src/pages/index.astro instead of /Users/name..../src/pages/index.astro export function rootRelativeFacadeId(facadeId: string, astroConfig: AstroConfig): string { - return facadeId.slice(fileURLToPath(astroConfig.projectRoot).length); + return facadeId.slice(fileURLToPath(astroConfig.root).length); } // Determines of a Rollup chunk is an entrypoint page. @@ -73,7 +74,7 @@ export async function generatePages(result: RollupOutput, opts: StaticBuildOptio const ssr = isBuildingToSSR(opts.astroConfig); const serverEntry = opts.buildConfig.serverEntry; - const outFolder = ssr ? opts.buildConfig.server : opts.astroConfig.dist; + const outFolder = ssr ? opts.buildConfig.server : opts.astroConfig.outDir; const ssrEntryURL = new URL('./' + serverEntry + `?time=${Date.now()}`, outFolder); const ssrEntry = await import(ssrEntryURL.toString()); @@ -151,7 +152,7 @@ async function generatePath(pathname: string, opts: StaticBuildOptions, gopts: G debug('build', `Generating: ${pathname}`); - const site = astroConfig.buildOptions.site; + const site = astroConfig.site; const links = createLinkStylesheetElementSet(linkIds.reverse(), site); const scripts = createModuleScriptElementWithSrcSet(hoistedId ? [hoistedId] : [], site); @@ -170,7 +171,7 @@ async function generatePath(pathname: string, opts: StaticBuildOptions, gopts: G legacyBuild: false, links, logging, - markdownRender: astroConfig.markdownOptions.render, + markdownRender: [astroRemark, astroConfig.markdown], mod, origin, pathname, @@ -196,7 +197,7 @@ async function generatePath(pathname: string, opts: StaticBuildOptions, gopts: G request: createRequest({ url, headers: new Headers(), logging }), route: pageData.route, routeCache, - site: astroConfig.buildOptions.site, + site: astroConfig.site ? new URL(astroConfig.base, astroConfig.site).toString() : astroConfig.site, ssr: isBuildingToSSR(opts.astroConfig), }; diff --git a/packages/astro/src/core/build/index.ts b/packages/astro/src/core/build/index.ts index db876176a..c206bc1ba 100644 --- a/packages/astro/src/core/build/index.ts +++ b/packages/astro/src/core/build/index.ts @@ -10,9 +10,7 @@ import { createVite, ViteConfigWithSSR } from '../create-vite.js'; import { debug, info, levels, timerMessage, warn, warnIfUsingExperimentalSSR } from '../logger/core.js'; import { nodeLogOptions } from '../logger/node.js'; import { createRouteManifest } from '../routing/index.js'; -import { generateSitemap } from '../render/sitemap.js'; import { collectPagesData } from './page-data.js'; -import { build as scanBasedBuild } from './scan-based-build.js'; import { staticBuild } from './static-build.js'; import { RouteCache } from '../render/route-cache.js'; import { runHookBuildDone, runHookBuildStart, runHookConfigDone, runHookConfigSetup } from '../../integrations/index.js'; @@ -42,17 +40,13 @@ class AstroBuilder { private timer: Record<string, number>; constructor(config: AstroConfig, options: BuildOptions) { - if (!config.buildOptions.site && config.buildOptions.sitemap !== false) { - warn(options.logging, 'config', `Set "buildOptions.site" to generate correct canonical URLs and sitemap`); - } if (options.mode) { this.mode = options.mode; } this.config = config; - const port = config.devOptions.port; // no need to save this (don’t rely on port in builder) this.logging = options.logging; this.routeCache = new RouteCache(this.logging); - this.origin = config.buildOptions.site ? new URL(config.buildOptions.site).origin : `http://localhost:${port}`; + this.origin = config.site ? new URL(config.site).origin : `http://localhost:${config.server.port}`; this.manifest = createRouteManifest({ config }, this.logging); this.timer = {}; } @@ -85,8 +79,8 @@ class AstroBuilder { private async build({ viteConfig, viteServer }: { viteConfig: ViteConfigWithSSR; viteServer: vite.ViteDevServer }) { const { origin } = this; const buildConfig: BuildConfig = { - client: new URL('./client/', this.config.dist), - server: new URL('./server/', this.config.dist), + client: new URL('./client/', this.config.outDir), + server: new URL('./server/', this.config.outDir), serverEntry: 'entry.mjs', staticMode: undefined, }; @@ -109,7 +103,7 @@ class AstroBuilder { if ('frontmatter' in data.preload[1]) { // TODO: add better type inference to data.preload[1] const frontmatter = (data.preload[1] as any).frontmatter; - if (Boolean(frontmatter.draft) && !this.config.buildOptions.drafts) { + if (Boolean(frontmatter.draft) && !this.config.markdown.drafts) { debug('build', timerMessage(`Skipping draft page ${page}`, this.timer.loadStart)); delete allPages[page]; } @@ -126,31 +120,17 @@ class AstroBuilder { this.timer.buildStart = performance.now(); info(this.logging, 'build', colors.dim(`Completed in ${getTimeStat(this.timer.init, performance.now())}.`)); - // Use the new faster static based build. - if (!this.config.buildOptions.legacyBuild) { - await staticBuild({ - allPages, - astroConfig: this.config, - logging: this.logging, - manifest: this.manifest, - origin: this.origin, - pageNames, - routeCache: this.routeCache, - viteConfig, - buildConfig, - }); - } else { - await scanBasedBuild({ - allPages, - astroConfig: this.config, - logging: this.logging, - origin: this.origin, - pageNames, - routeCache: this.routeCache, - viteConfig, - viteServer, - }); - } + await staticBuild({ + allPages, + astroConfig: this.config, + logging: this.logging, + manifest: this.manifest, + origin: this.origin, + pageNames, + routeCache: this.routeCache, + viteConfig, + buildConfig, + }); // Write any additionally generated assets to disk. this.timer.assetsStart = performance.now(); @@ -163,20 +143,6 @@ class AstroBuilder { }); debug('build', timerMessage('Additional assets copied', this.timer.assetsStart)); - // Build your final sitemap. - if (this.config.buildOptions.sitemap && this.config.buildOptions.site) { - this.timer.sitemapStart = performance.now(); - const sitemapFilter = this.config.buildOptions.sitemapFilter ? (this.config.buildOptions.sitemapFilter as (page: string) => boolean) : undefined; - const sitemap = generateSitemap( - pageNames.map((pageName) => new URL(pageName, this.config.buildOptions.site).href), - sitemapFilter - ); - const sitemapPath = new URL('./sitemap.xml', this.config.dist); - await fs.promises.mkdir(new URL('./', sitemapPath), { recursive: true }); - await fs.promises.writeFile(sitemapPath, sitemap, 'utf8'); - debug('build', timerMessage('Sitemap built', this.timer.sitemapStart)); - } - // You're done! Time to clean up. await viteServer.close(); await runHookBuildDone({ config: this.config, pages: pageNames, routes: Object.values(allPages).map((pd) => pd.route) }); diff --git a/packages/astro/src/core/build/page-data.ts b/packages/astro/src/core/build/page-data.ts index c84e29588..60afee834 100644 --- a/packages/astro/src/core/build/page-data.ts +++ b/packages/astro/src/core/build/page-data.ts @@ -68,7 +68,7 @@ export async function collectPagesData(opts: CollectPagesDataOptions): Promise<C scripts: new Set(), preload: await ssrPreload({ astroConfig, - filePath: new URL(`./${route.component}`, astroConfig.projectRoot), + filePath: new URL(`./${route.component}`, astroConfig.root), viteServer, }) .then((routes) => { @@ -100,13 +100,13 @@ export async function collectPagesData(opts: CollectPagesDataOptions): Promise<C debug('build', `├── ${colors.bold(colors.red('✗'))} ${route.component}`); throw err; }); - const rssFn = generateRssFunction(astroConfig.buildOptions.site, route); + const rssFn = generateRssFunction(astroConfig.site, route); for (const rssCallArg of result.rss) { const rssResult = rssFn(rssCallArg); if (rssResult.xml) { const { url, content } = rssResult.xml; if (content) { - const rssFile = new URL(url.replace(/^\/?/, './'), astroConfig.dist); + const rssFile = new URL(url.replace(/^\/?/, './'), astroConfig.outDir); if (assets[fileURLToPath(rssFile)]) { throw new Error(`[getStaticPaths] RSS feed ${url} already exists.\nUse \`rss(data, {url: '...'})\` to choose a unique, custom URL. (${route.component})`); } @@ -115,7 +115,7 @@ export async function collectPagesData(opts: CollectPagesDataOptions): Promise<C } if (rssResult.xsl?.content) { const { url, content } = rssResult.xsl; - const stylesheetFile = new URL(url.replace(/^\/?/, './'), astroConfig.dist); + const stylesheetFile = new URL(url.replace(/^\/?/, './'), astroConfig.outDir); if (assets[fileURLToPath(stylesheetFile)]) { throw new Error( `[getStaticPaths] RSS feed stylesheet ${url} already exists.\nUse \`rss(data, {stylesheet: '...'})\` to choose a unique, custom URL. (${route.component})` @@ -135,7 +135,7 @@ export async function collectPagesData(opts: CollectPagesDataOptions): Promise<C scripts: new Set(), preload: await ssrPreload({ astroConfig, - filePath: new URL(`./${route.component}`, astroConfig.projectRoot), + filePath: new URL(`./${route.component}`, astroConfig.root), viteServer, }), }; @@ -149,7 +149,7 @@ export async function collectPagesData(opts: CollectPagesDataOptions): Promise<C async function getStaticPathsForRoute(opts: CollectPagesDataOptions, route: RouteData): Promise<RouteCacheEntry> { const { astroConfig, logging, routeCache, ssr, viteServer } = opts; if (!viteServer) throw new Error(`vite.createServer() not called!`); - const filePath = new URL(`./${route.component}`, astroConfig.projectRoot); + const filePath = new URL(`./${route.component}`, astroConfig.root); const mod = (await viteServer.ssrLoadModule(fileURLToPath(filePath))) as ComponentInstance; const result = await callGetStaticPaths({ mod, route, isValidate: false, logging, ssr }); routeCache.set(route, result); diff --git a/packages/astro/src/core/build/scan-based-build.ts b/packages/astro/src/core/build/scan-based-build.ts deleted file mode 100644 index a4e9009e9..000000000 --- a/packages/astro/src/core/build/scan-based-build.ts +++ /dev/null @@ -1,89 +0,0 @@ -import type { ViteDevServer } from 'vite'; -import type { RollupOutput, RollupWatcher } from 'rollup'; -import type { AstroConfig, RouteType } from '../../@types/astro'; -import type { AllPagesData, PageBuildData } from './types'; -import type { LogOptions } from '../logger/core'; -import type { ViteConfigWithSSR } from '../create-vite.js'; - -import { fileURLToPath } from 'url'; -import * as vite from 'vite'; -import { createBuildInternals } from '../../core/build/internal.js'; -import { rollupPluginAstroScanHTML } from '../../vite-plugin-build-html/index.js'; -import { rollupPluginAstroBuildCSS } from '../../vite-plugin-build-css/index.js'; -import { RouteCache } from '../render/route-cache.js'; - -export interface ScanBasedBuildOptions { - allPages: AllPagesData; - astroConfig: AstroConfig; - logging: LogOptions; - origin: string; - pageNames: string[]; - routeCache: RouteCache; - viteConfig: ViteConfigWithSSR; - viteServer: ViteDevServer; -} - -// Returns a filter predicate to filter AllPagesData entries by RouteType -function entryIsType(type: RouteType) { - return function withPage([_, pageData]: [string, PageBuildData]) { - return pageData.route.type === type; - }; -} - -// Reducer to combine AllPageData entries back into an object keyed by filepath -function reduceEntries<U>(acc: { [key: string]: U }, [key, value]: [string, U]) { - acc[key] = value; - return acc; -} - -// Filters an AllPagesData object to only include routes of a specific RouteType -function routesOfType(type: RouteType, allPages: AllPagesData) { - return Object.entries(allPages).filter(entryIsType(type)).reduce(reduceEntries, {}); -} - -export async function build(opts: ScanBasedBuildOptions): Promise<RollupOutput | RollupOutput[] | RollupWatcher> { - const { allPages, astroConfig, logging, origin, pageNames, routeCache, viteConfig, viteServer } = opts; - - // Internal maps used to coordinate the HTML and CSS plugins. - const internals = createBuildInternals(); - - return await vite.build({ - logLevel: 'warn', - mode: 'production', - build: { - emptyOutDir: true, - minify: 'esbuild', // significantly faster than "terser" but may produce slightly-bigger bundles - outDir: fileURLToPath(astroConfig.dist), - rollupOptions: { - // The `input` will be populated in the build rollup plugin. - input: [], - output: { - format: 'esm', - }, - }, - target: 'es2020', // must match an esbuild target - }, - plugins: [ - rollupPluginAstroScanHTML({ - astroConfig, - internals, - logging, - origin, - allPages: routesOfType('page', allPages), - pageNames, - routeCache, - viteServer, - }), - rollupPluginAstroBuildCSS({ - internals, - legacy: true, - }), - ...(viteConfig.plugins || []), - ], - publicDir: viteConfig.publicDir, - root: viteConfig.root, - envPrefix: 'PUBLIC_', - server: viteConfig.server, - base: astroConfig.buildOptions.site ? new URL(astroConfig.buildOptions.site).pathname : '/', - }); -} diff --git a/packages/astro/src/core/build/static-build.ts b/packages/astro/src/core/build/static-build.ts index afe41a01e..583183f2c 100644 --- a/packages/astro/src/core/build/static-build.ts +++ b/packages/astro/src/core/build/static-build.ts @@ -44,7 +44,7 @@ export async function staticBuild(opts: StaticBuildOptions) { timer.buildStart = performance.now(); for (const [component, pageData] of Object.entries(allPages)) { - const astroModuleURL = new URL('./' + component, astroConfig.projectRoot); + const astroModuleURL = new URL('./' + component, astroConfig.root); const astroModuleId = prependForwardSlash(component); // Track the page data in internals @@ -87,7 +87,7 @@ export async function staticBuild(opts: StaticBuildOptions) { // Empty out the dist folder, if needed. Vite has a config for doing this // but because we are running 2 vite builds in parallel, that would cause a race // condition, so we are doing it ourselves - emptyDir(astroConfig.dist, new Set('.git')); + emptyDir(astroConfig.outDir, new Set('.git')); timer.clientBuild = performance.now(); // Run client build first, so the assets can be fed into the SSR rendered version. @@ -112,7 +112,7 @@ export async function staticBuild(opts: StaticBuildOptions) { async function ssrBuild(opts: StaticBuildOptions, internals: BuildInternals, input: Set<string>) { const { astroConfig, viteConfig } = opts; const ssr = isBuildingToSSR(astroConfig); - const out = ssr ? opts.buildConfig.server : astroConfig.dist; + const out = ssr ? opts.buildConfig.server : astroConfig.outDir; const viteBuildConfig = { logLevel: 'error', @@ -155,7 +155,7 @@ async function ssrBuild(opts: StaticBuildOptions, internals: BuildInternals, inp root: viteConfig.root, envPrefix: 'PUBLIC_', server: viteConfig.server, - base: astroConfig.buildOptions.site ? new URL(astroConfig.buildOptions.site).pathname : '/', + base: astroConfig.site ? new URL(astroConfig.site).pathname : '/', ssr: viteConfig.ssr, resolve: viteConfig.resolve, } as ViteConfigWithSSR; @@ -170,13 +170,13 @@ async function clientBuild(opts: StaticBuildOptions, internals: BuildInternals, const { astroConfig, viteConfig } = opts; const timer = performance.now(); const ssr = isBuildingToSSR(astroConfig); - const out = ssr ? opts.buildConfig.client : astroConfig.dist; + const out = ssr ? opts.buildConfig.client : astroConfig.outDir; // Nothing to do if there is no client-side JS. if (!input.size) { // If SSR, copy public over if (ssr) { - await copyFiles(astroConfig.public, out); + await copyFiles(astroConfig.publicDir, out); } return null; @@ -184,7 +184,7 @@ async function clientBuild(opts: StaticBuildOptions, internals: BuildInternals, // TODO: use vite.mergeConfig() here? info(opts.logging, null, `\n${bgGreen(black(' building client '))}`); - + const viteBuildConfig = { logLevel: 'info', mode: 'production', @@ -218,7 +218,7 @@ async function clientBuild(opts: StaticBuildOptions, internals: BuildInternals, root: viteConfig.root, envPrefix: 'PUBLIC_', server: viteConfig.server, - base: appendForwardSlash(astroConfig.buildOptions.site ? new URL(astroConfig.buildOptions.site).pathname : '/'), + base: astroConfig.base, } as ViteConfigWithSSR; await runHookBuildSetup({ config: astroConfig, vite: viteBuildConfig, target: 'client' }); @@ -231,11 +231,11 @@ async function clientBuild(opts: StaticBuildOptions, internals: BuildInternals, async function cleanSsrOutput(opts: StaticBuildOptions) { // The SSR output is all .mjs files, the client output is not. const files = await glob('**/*.mjs', { - cwd: fileURLToPath(opts.astroConfig.dist), + cwd: fileURLToPath(opts.astroConfig.outDir), }); await Promise.all( files.map(async (filename) => { - const url = new URL(filename, opts.astroConfig.dist); + const url = new URL(filename, opts.astroConfig.outDir); await fs.promises.rm(url); }) ); diff --git a/packages/astro/src/core/build/vite-plugin-hoisted-scripts.ts b/packages/astro/src/core/build/vite-plugin-hoisted-scripts.ts index 8f2480a63..1dafef0b4 100644 --- a/packages/astro/src/core/build/vite-plugin-hoisted-scripts.ts +++ b/packages/astro/src/core/build/vite-plugin-hoisted-scripts.ts @@ -39,7 +39,7 @@ export function vitePluginHoistedScripts(astroConfig: AstroConfig, internals: Bu const facadeId = output.facadeModuleId!; const pathname = facadeId.slice(0, facadeId.length - '/hoisted.js'.length); - const vid = viteID(new URL('.' + pathname, astroConfig.projectRoot)); + const vid = viteID(new URL('.' + pathname, astroConfig.root)); const pageInfo = getPageDataByViteID(internals, vid); if (pageInfo) { pageInfo.hoistedScript = id; diff --git a/packages/astro/src/core/build/vite-plugin-ssr.ts b/packages/astro/src/core/build/vite-plugin-ssr.ts index f057dc2ce..367341f23 100644 --- a/packages/astro/src/core/build/vite-plugin-ssr.ts +++ b/packages/astro/src/core/build/vite-plugin-ssr.ts @@ -1,4 +1,4 @@ -import type { OutputBundle, OutputChunk } from 'rollup'; +import astroRemark from '@astrojs/markdown-remark'; import type { Plugin as VitePlugin } from 'vite'; import type { BuildInternals } from './internal.js'; import type { AstroAdapter } from '../../@types/astro'; @@ -95,9 +95,9 @@ function buildManifest(opts: StaticBuildOptions, internals: BuildInternals): Ser const ssrManifest: SerializedSSRManifest = { routes, - site: astroConfig.buildOptions.site, + site: astroConfig.site, markdown: { - render: astroConfig.markdownOptions.render, + render: [astroRemark, astroConfig.markdown], }, pageMap: null as any, renderers: [], diff --git a/packages/astro/src/core/config.ts b/packages/astro/src/core/config.ts index b676fc727..19ac9d66d 100644 --- a/packages/astro/src/core/config.ts +++ b/packages/astro/src/core/config.ts @@ -11,6 +11,7 @@ import load from '@proload/core'; import loadTypeScript from '@proload/plugin-tsm'; import postcssrc from 'postcss-load-config'; import { arraify, isObject } from './util.js'; +import { appendForwardSlash, trimSlashes } from './path.js' load.use([loadTypeScript]); @@ -43,40 +44,88 @@ async function resolvePostcssConfig(inlineOptions: any, root: URL): Promise<Post } } +export const LegacyAstroConfigKeys = new Set([ + 'projectRoot', + 'src', + 'pages', + 'public', + 'dist', + 'styleOptions', + 'markdownOptions', + 'buildOptions', + 'devOptions', + 'experimentalIntegrations' +]); + export const AstroConfigSchema = z.object({ - projectRoot: z + adapter: z.object({ name: z.string(), hooks: z.object({}).passthrough().default({}) }).optional(), + root: z .string() .optional() .default('.') .transform((val) => new URL(val)), - src: z + srcDir: z .string() .optional() .default('./src') .transform((val) => new URL(val)), - pages: z - .string() - .optional() - .default('./src/pages') - .transform((val) => new URL(val)), - public: z + publicDir: z .string() .optional() .default('./public') .transform((val) => new URL(val)), - dist: z + outDir: z .string() .optional() .default('./dist') .transform((val) => new URL(val)), + site: z + .string() + .url() + .optional() + .transform((val) => (val ? appendForwardSlash(val) : val)) + .refine((val) => !val || new URL(val).pathname.length <= 1, { + message: '"site" must be a valid URL origin (ex: "https://example.com") but cannot contain a URL path (ex: "https://example.com/blog"). Use "base" to configure your deployed URL path', + + }), + base: z + .string() + .optional() + .default('./') + .transform((val) => (val ? appendForwardSlash(trimSlashes(val)) : val)), + trailingSlash: z + .union([z.literal('always'), z.literal('never'), z.literal('ignore')]) + .optional() + .default('ignore'), + build: z + .object({ + format: z + .union([z.literal('file'), z.literal('directory')]) + .optional() + .default('directory'), + }) + .optional() + .default({}), + server: z.preprocess( + // preprocess + // NOTE: Uses the "error" command here because this is overwritten by the + // individualized schema parser with the correct command. + (val) => (typeof val === 'function' ? val({ command: 'error' }) : val), + // validate + z.object({ + host: z.union([z.string(), z.boolean()]).optional().default(false), + port: z.number().optional().default(3000), + }) + .optional() + .default({}), + ), integrations: z.preprocess( // preprocess (val) => (Array.isArray(val) ? val.flat(Infinity).filter(Boolean) : val), // validate z.array(z.object({ name: z.string(), hooks: z.object({}).passthrough().default({}) })).default([]) ), - adapter: z.object({ name: z.string(), hooks: z.object({}).passthrough().default({}) }).optional(), - styleOptions: z + style: z .object({ postcss: z .object({ @@ -88,50 +137,37 @@ export const AstroConfigSchema = z.object({ }) .optional() .default({}), - markdownOptions: z - .object({ - render: z.any().optional().default(['@astrojs/markdown-remark', {}]), - }) - .strict() - .optional() - .default({}), - buildOptions: z + markdown: z .object({ - site: z - .string() + drafts: z.boolean().optional().default(false), + mode: z + .union([z.literal('md'), z.literal('mdx')]) .optional() - .transform((val) => (val ? addTrailingSlash(val) : val)), - sitemapFilter: z.function().optional(), - sitemap: z.boolean().optional().default(true), - pageUrlFormat: z - .union([z.literal('file'), z.literal('directory')]) + .default('md'), + syntaxHighlight: z + .union([z.literal('shiki'), z.literal('prism'), z.literal(false)]) .optional() - .default('directory'), - legacyBuild: z.boolean().optional().default(false), - experimentalStaticBuild: z.boolean().optional().default(true), - experimentalSsr: z.boolean().optional().default(false), - drafts: z.boolean().optional().default(false), + .default('shiki'), + // TODO: add better type checking + shikiConfig: z.any().optional().default({}), + remarkPlugins: z.array(z.any()).optional().default([]), + rehypePlugins: z.array(z.any()).optional().default([]), }) + .passthrough() .optional() .default({}), - devOptions: z + vite: z.any().optional().default({}), + experimental: z .object({ - host: z.union([z.string(), z.boolean()]).optional().default(false), - hostname: z.string().optional().default('localhost'), - port: z.number().optional().default(3000), - trailingSlash: z - .union([z.literal('always'), z.literal('never'), z.literal('ignore')]) - .optional() - .default('ignore'), + ssr: z.boolean().optional().default(false), + integrations: z.boolean().optional().default(false), }) .optional() .default({}), - experimentalIntegrations: z.boolean().optional().default(false), - vite: z.any().optional().default({}), // TODO: we don’t need validation, but can we get better type inference? }); /** Turn raw config values into normalized values */ -export async function validateConfig(userConfig: any, root: string): Promise<AstroConfig> { +export async function validateConfig(userConfig: any, root: string, cmd: string): Promise<AstroConfig> { const fileProtocolRoot = pathToFileURL(root + path.sep); // Manual deprecation checks /* eslint-disable no-console */ @@ -162,32 +198,50 @@ export async function validateConfig(userConfig: any, root: string): Promise<Ast } process.exit(1); } + + let oldConfig = false; + for (const key of Object.keys(userConfig)) { + if (LegacyAstroConfigKeys.has(key)) { + oldConfig = true; + break; + } + } + if (oldConfig) { + throw new Error(`Legacy configuration detected. Please update your configuration to the new format!\nSee https://astro.build/config for more information.`) + } /* eslint-enable no-console */ // We need to extend the global schema to add transforms that are relative to root. // This is type checked against the global schema to make sure we still match. const AstroConfigRelativeSchema = AstroConfigSchema.extend({ - projectRoot: z + root: z .string() .default('.') - .transform((val) => new URL(addTrailingSlash(val), fileProtocolRoot)), - src: z + .transform((val) => new URL(appendForwardSlash(val), fileProtocolRoot)), + srcDir: z .string() .default('./src') - .transform((val) => new URL(addTrailingSlash(val), fileProtocolRoot)), - pages: z - .string() - .default('./src/pages') - .transform((val) => new URL(addTrailingSlash(val), fileProtocolRoot)), - public: z + .transform((val) => new URL(appendForwardSlash(val), fileProtocolRoot)), + publicDir: z .string() .default('./public') - .transform((val) => new URL(addTrailingSlash(val), fileProtocolRoot)), - dist: z + .transform((val) => new URL(appendForwardSlash(val), fileProtocolRoot)), + outDir: z .string() .default('./dist') - .transform((val) => new URL(addTrailingSlash(val), fileProtocolRoot)), - styleOptions: z + .transform((val) => new URL(appendForwardSlash(val), fileProtocolRoot)), + server: z.preprocess( + // preprocess + (val) => (typeof val === 'function' ? val({ command: cmd === 'dev' ? 'dev' : 'preview' }) : val), + // validate + z.object({ + host: z.union([z.string(), z.boolean()]).optional().default(false), + port: z.number().optional().default(3000), + }) + .optional() + .default({}), + ), + style: z .object({ postcss: z.preprocess( (val) => resolvePostcssConfig(val, fileProtocolRoot), @@ -209,7 +263,7 @@ export async function validateConfig(userConfig: any, root: string): Promise<Ast _ctx: { scripts: [], renderers: [], adapter: undefined }, }; // Final-Pass Validation (perform checks that require the full config object) - if (!result.experimentalIntegrations && !result.integrations.every((int) => int.name.startsWith('@astrojs/'))) { + if (!result.experimental?.integrations && !result.integrations.every((int) => int.name.startsWith('@astrojs/'))) { throw new Error( [ `Astro integrations are still experimental.`, @@ -225,51 +279,43 @@ export async function validateConfig(userConfig: any, root: string): Promise<Ast return result; } -/** Adds '/' to end of string but doesn’t double-up */ -function addTrailingSlash(str: string): string { - return str.replace(/\/*$/, '/'); -} - /** Convert the generic "yargs" flag object into our own, custom TypeScript object. */ function resolveFlags(flags: Partial<Flags>): CLIFlags { - if (flags.experimentalStaticBuild) { - // eslint-disable-next-line no-console - console.warn(`Passing --experimental-static-build is no longer necessary and is now the default. The flag will be removed in a future version of Astro.`); - } return { - projectRoot: typeof flags.projectRoot === 'string' ? flags.projectRoot : undefined, + root: typeof flags.root === 'string' ? flags.root : undefined, site: typeof flags.site === 'string' ? flags.site : undefined, - sitemap: typeof flags.sitemap === 'boolean' ? flags.sitemap : undefined, port: typeof flags.port === 'number' ? flags.port : undefined, config: typeof flags.config === 'string' ? flags.config : undefined, - hostname: typeof flags.hostname === 'string' ? flags.hostname : undefined, host: typeof flags.host === 'string' || typeof flags.host === 'boolean' ? flags.host : undefined, - legacyBuild: typeof flags.legacyBuild === 'boolean' ? flags.legacyBuild : undefined, - experimentalSsr: typeof flags.experimentalSsr === 'boolean' ? flags.experimentalSsr : undefined, - experimentalIntegrations: typeof flags.experimentalIntegrations === 'boolean' ? flags.experimentalIntegrations : undefined, - drafts: typeof flags.drafts === 'boolean' ? flags.drafts : undefined, + experimentalSsr: typeof flags.experimentalSsr === 'boolean' ? flags.experimentalSsr : false, + experimentalIntegrations: typeof flags.experimentalIntegrations === 'boolean' ? flags.experimentalIntegrations : false, + drafts: typeof flags.drafts === 'boolean' ? flags.drafts : false, }; } /** Merge CLI flags & user config object (CLI flags take priority) */ -function mergeCLIFlags(astroConfig: AstroUserConfig, flags: CLIFlags) { - astroConfig.buildOptions = astroConfig.buildOptions || {}; - astroConfig.devOptions = astroConfig.devOptions || {}; - if (typeof flags.sitemap === 'boolean') astroConfig.buildOptions.sitemap = flags.sitemap; - if (typeof flags.site === 'string') astroConfig.buildOptions.site = flags.site; - if (typeof flags.port === 'number') astroConfig.devOptions.port = flags.port; - if (typeof flags.host === 'string' || typeof flags.host === 'boolean') astroConfig.devOptions.host = flags.host; - if (typeof flags.hostname === 'string') astroConfig.devOptions.hostname = flags.hostname; - if (typeof flags.legacyBuild === 'boolean') astroConfig.buildOptions.legacyBuild = flags.legacyBuild; - if (typeof flags.experimentalSsr === 'boolean') astroConfig.buildOptions.experimentalSsr = flags.experimentalSsr; - if (typeof flags.experimentalIntegrations === 'boolean') astroConfig.experimentalIntegrations = flags.experimentalIntegrations; - if (typeof flags.drafts === 'boolean') astroConfig.buildOptions.drafts = flags.drafts; +function mergeCLIFlags(astroConfig: AstroUserConfig, flags: CLIFlags, cmd: string) { + astroConfig.server = astroConfig.server || {}; + astroConfig.experimental = astroConfig.experimental || {}; + astroConfig.markdown = astroConfig.markdown || {}; + if (typeof flags.site === 'string') astroConfig.site = flags.site; + if (typeof flags.experimentalSsr === 'boolean') astroConfig.experimental.ssr = flags.experimentalSsr; + if (typeof flags.experimentalIntegrations === 'boolean') astroConfig.experimental.integrations = flags.experimentalIntegrations; + if (typeof flags.drafts === 'boolean') astroConfig.markdown.drafts = flags.drafts; + // @ts-expect-error astroConfig.server may be a function, but TS doesn't like attaching properties to a function. + // TODO: Come back here and refactor to remove this expected error. + if (typeof flags.port === 'number') astroConfig.server.port = flags.port; + // @ts-expect-error astroConfig.server may be a function, but TS doesn't like attaching properties to a function. + // TODO: Come back here and refactor to remove this expected error. + if (typeof flags.host === 'string' || typeof flags.host === 'boolean') astroConfig.server.host = flags.host; return astroConfig; } interface LoadConfigOptions { cwd?: string; flags?: Flags; + cmd: string; + validate?: boolean; } /** @@ -277,7 +323,7 @@ interface LoadConfigOptions { * Note: currently the same as loadConfig but only returns the `filePath` * instead of the resolved config */ -export async function resolveConfigURL(configOptions: LoadConfigOptions): Promise<URL | undefined> { +export async function resolveConfigURL(configOptions: Pick<LoadConfigOptions, 'cwd' | 'flags'>): Promise<URL | undefined> { const root = configOptions.cwd ? path.resolve(configOptions.cwd) : process.cwd(); const flags = resolveFlags(configOptions.flags || {}); let userConfigPath: string | undefined; @@ -311,13 +357,13 @@ export async function loadConfig(configOptions: LoadConfigOptions): Promise<Astr if (config) { userConfig = config.value; } - return resolveConfig(userConfig, root, flags); + return resolveConfig(userConfig, root, flags, configOptions.cmd); } /** Attempt to resolve an Astro configuration object. Normalize, validate, and return. */ -export async function resolveConfig(userConfig: AstroUserConfig, root: string, flags: CLIFlags = {}): Promise<AstroConfig> { - const mergedConfig = mergeCLIFlags(userConfig, flags); - const validatedConfig = await validateConfig(mergedConfig, root); +export async function resolveConfig(userConfig: AstroUserConfig, root: string, flags: CLIFlags = {}, cmd: string): Promise<AstroConfig> { + const mergedConfig = mergeCLIFlags(userConfig, flags, cmd); + const validatedConfig = await validateConfig(mergedConfig, root, cmd); return validatedConfig; } diff --git a/packages/astro/src/core/create-vite.ts b/packages/astro/src/core/create-vite.ts index 8564290e2..47a79b84b 100644 --- a/packages/astro/src/core/create-vite.ts +++ b/packages/astro/src/core/create-vite.ts @@ -48,7 +48,7 @@ export async function createVite(commandConfig: ViteConfigWithSSR, { astroConfig const astroPackages = await getAstroPackages(astroConfig); // Start with the Vite configuration that Astro core needs const commonConfig: ViteConfigWithSSR = { - cacheDir: fileURLToPath(new URL('./node_modules/.vite/', astroConfig.projectRoot)), // using local caches allows Astro to be used in monorepos, etc. + cacheDir: fileURLToPath(new URL('./node_modules/.vite/', astroConfig.root)), // using local caches allows Astro to be used in monorepos, etc. clearScreen: false, // we want to control the output, not Vite logLevel: 'warn', // log warnings and errors only optimizeDeps: { @@ -67,8 +67,8 @@ export async function createVite(commandConfig: ViteConfigWithSSR, { astroConfig astroPostprocessVitePlugin({ config: astroConfig }), astroIntegrationsContainerPlugin({ config: astroConfig }), ], - publicDir: fileURLToPath(astroConfig.public), - root: fileURLToPath(astroConfig.projectRoot), + publicDir: fileURLToPath(astroConfig.publicDir), + root: fileURLToPath(astroConfig.root), envPrefix: 'PUBLIC_', server: { force: true, // force dependency rebuild (TODO: enabled only while next is unstable; eventually only call in "production" mode?) @@ -79,7 +79,7 @@ export async function createVite(commandConfig: ViteConfigWithSSR, { astroConfig }, }, css: { - postcss: astroConfig.styleOptions.postcss || {}, + postcss: astroConfig.style.postcss || {}, }, resolve: { alias: { @@ -109,8 +109,8 @@ export async function createVite(commandConfig: ViteConfigWithSSR, { astroConfig // Scans `projectRoot` for third-party Astro packages that could export an `.astro` file // `.astro` files need to be built by Vite, so these should use `noExternal` -async function getAstroPackages({ projectRoot }: AstroConfig): Promise<string[]> { - const pkgUrl = new URL('./package.json', projectRoot); +async function getAstroPackages({ root }: AstroConfig): Promise<string[]> { + const pkgUrl = new URL('./package.json', root); const pkgPath = fileURLToPath(pkgUrl); if (!fs.existsSync(pkgPath)) return []; @@ -123,7 +123,7 @@ async function getAstroPackages({ projectRoot }: AstroConfig): Promise<string[]> if (isCommonNotAstro(dep)) return false; // Attempt: package is named `astro-something`. ✅ Likely a community package if (/^astro\-/.test(dep)) return true; - const depPkgUrl = new URL(`./node_modules/${dep}/package.json`, projectRoot); + const depPkgUrl = new URL(`./node_modules/${dep}/package.json`, root); const depPkgPath = fileURLToPath(depPkgUrl); if (!fs.existsSync(depPkgPath)) return false; diff --git a/packages/astro/src/core/dev/index.ts b/packages/astro/src/core/dev/index.ts index dcb4a333b..b46d1abab 100644 --- a/packages/astro/src/core/dev/index.ts +++ b/packages/astro/src/core/dev/index.ts @@ -8,7 +8,6 @@ import { info, LogOptions, warn, warnIfUsingExperimentalSSR } from '../logger/co import { nodeLogOptions } from '../logger/node.js'; import * as msg from '../messages.js'; import { apply as applyPolyfill } from '../polyfill.js'; -import { getResolvedHostForVite } from '../util.js'; export interface DevOptions { logging: LogOptions; @@ -24,11 +23,11 @@ export default async function dev(config: AstroConfig, options: DevOptions = { l const devStart = performance.now(); applyPolyfill(); config = await runHookConfigSetup({ config, command: 'dev' }); + const { host, port } = config.server; const viteConfig = await createVite( { mode: 'development', - // TODO: remove call once --hostname is baselined - server: { host: getResolvedHostForVite(config) }, + server: { host }, }, { astroConfig: config, logging: options.logging, mode: 'dev' } ); @@ -36,10 +35,10 @@ export default async function dev(config: AstroConfig, options: DevOptions = { l warnIfUsingExperimentalSSR(options.logging, config); const viteServer = await vite.createServer(viteConfig); runHookServerSetup({ config, server: viteServer }); - await viteServer.listen(config.devOptions.port); + await viteServer.listen(port); const devServerAddressInfo = viteServer.httpServer!.address() as AddressInfo; - const site = config.buildOptions.site ? new URL(config.buildOptions.site) : undefined; + const site = config.site ? new URL(config.base, config.site) : undefined; info(options.logging, null, msg.devStart({ startupTime: performance.now() - devStart, config, devServerAddressInfo, site, https: !!viteConfig.server?.https })); const currentVersion = process.env.PACKAGE_VERSION ?? '0.0.0'; diff --git a/packages/astro/src/core/messages.ts b/packages/astro/src/core/messages.ts index 888e6fcf4..248bc1823 100644 --- a/packages/astro/src/core/messages.ts +++ b/packages/astro/src/core/messages.ts @@ -8,7 +8,7 @@ import type { AddressInfo } from 'net'; import type { AstroConfig } from '../@types/astro'; import { collectErrorMetadata, cleanErrorStack } from './errors.js'; import { ZodError } from 'zod'; -import { emoji, getLocalAddress, getResolvedHostForVite, padMultilineString } from './util.js'; +import { emoji, getLocalAddress, padMultilineString } from './util.js'; const PREFIX_PADDING = 6; @@ -51,8 +51,8 @@ export function devStart({ const networkPrefix = `${dim('┃')} Network `; const { address: networkAddress, port } = devServerAddressInfo; - const localAddress = getLocalAddress(networkAddress, config); - const networkLogging = getNetworkLogging(config); + const localAddress = getLocalAddress(networkAddress, config.server.host); + const networkLogging = getNetworkLogging(config.server.host); const toDisplayUrl = (hostname: string) => `${https ? 'https' : 'http'}://${hostname}:${port}${rootPath}`; let addresses = []; @@ -125,10 +125,7 @@ export function portInUse({ port }: { port: number }): string { const LOCAL_IP_HOSTS = new Set(['localhost', '127.0.0.1']); -export function getNetworkLogging(config: AstroConfig): 'none' | 'host-to-expose' | 'visible' { - // TODO: remove once --hostname is baselined - const host = getResolvedHostForVite(config); - +export function getNetworkLogging(host: string | boolean): 'none' | 'host-to-expose' | 'visible' { if (host === false) { return 'host-to-expose'; } else if (typeof host === 'string' && LOCAL_IP_HOSTS.has(host)) { diff --git a/packages/astro/src/core/preview/index.ts b/packages/astro/src/core/preview/index.ts index 48d077800..b4fd2c0ea 100644 --- a/packages/astro/src/core/preview/index.ts +++ b/packages/astro/src/core/preview/index.ts @@ -27,10 +27,10 @@ const HAS_FILE_EXTENSION_REGEXP = /^.*\.[^\\]+$/; export default async function preview(config: AstroConfig, { logging }: PreviewOptions): Promise<PreviewServer> { const startServerTime = performance.now(); const defaultOrigin = 'http://localhost'; - const trailingSlash = config.devOptions.trailingSlash; + const trailingSlash = config.trailingSlash; /** Base request URL. */ - let baseURL = new URL(config.buildOptions.site || '/', defaultOrigin); - const staticFileServer = sirv(fileURLToPath(config.dist), { + let baseURL = new URL(config.base, new URL(config.site || '/', defaultOrigin)); + const staticFileServer = sirv(fileURLToPath(config.outDir), { dev: true, etag: true, maxAge: 0, @@ -59,10 +59,10 @@ export default async function preview(config: AstroConfig, { logging }: PreviewO switch (true) { case hasTrailingSlash && trailingSlash == 'never' && !isRoot: - sendError('Not Found (devOptions.trailingSlash is set to "never")'); + sendError('Not Found (trailingSlash is set to "never")'); return; case !hasTrailingSlash && trailingSlash == 'always' && !isRoot && !HAS_FILE_EXTENSION_REGEXP.test(pathname): - sendError('Not Found (devOptions.trailingSlash is set to "always")'); + sendError('Not Found (trailingSlash is set to "always")'); return; default: { // HACK: rewrite req.url so that sirv finds the file @@ -73,8 +73,8 @@ export default async function preview(config: AstroConfig, { logging }: PreviewO } }); - let { port } = config.devOptions; - const host = getResolvedHostForHttpServer(config); + let { port } = config.server; + const host = getResolvedHostForHttpServer(config.server.host); let httpServer: http.Server; diff --git a/packages/astro/src/core/preview/util.ts b/packages/astro/src/core/preview/util.ts index 90c42ec32..87c1bfdf8 100644 --- a/packages/astro/src/core/preview/util.ts +++ b/packages/astro/src/core/preview/util.ts @@ -1,17 +1,13 @@ import type { AstroConfig } from '../../@types/astro'; -export function getResolvedHostForHttpServer(config: AstroConfig) { - const { host, hostname } = config.devOptions; - - if (host === false && hostname === 'localhost') { +export function getResolvedHostForHttpServer(host: string | boolean) { + if (host === false) { // Use a secure default return '127.0.0.1'; } else if (host === true) { // If passed --host in the CLI without arguments return undefined; // undefined typically means 0.0.0.0 or :: (listen on all IPs) - } else if (typeof host === 'string') { - return host; } else { - return hostname; + return host; } } diff --git a/packages/astro/src/core/render/core.ts b/packages/astro/src/core/render/core.ts index 383128ad0..ca0de3ae6 100644 --- a/packages/astro/src/core/render/core.ts +++ b/packages/astro/src/core/render/core.ts @@ -126,7 +126,7 @@ export async function render(opts: RenderOptions): Promise<{ type: 'html'; html: html = html.replace('<!--astro:head:injected-->', ''); // inject <!doctype html> if missing (TODO: is a more robust check needed for comments, etc.?) - if (!legacyBuild && !/<!doctype html/i.test(html)) { + if (!/<!doctype html/i.test(html)) { html = '<!DOCTYPE html>\n' + html; } diff --git a/packages/astro/src/core/render/dev/index.ts b/packages/astro/src/core/render/dev/index.ts index b81ef6863..d2d3642da 100644 --- a/packages/astro/src/core/render/dev/index.ts +++ b/packages/astro/src/core/render/dev/index.ts @@ -1,3 +1,4 @@ +import astroRemark from '@astrojs/markdown-remark'; import { fileURLToPath } from 'url'; import type * as vite from 'vite'; import type { AstroConfig, AstroRenderer, ComponentInstance, RouteData, RuntimeMode, SSRElement, SSRLoadedRenderer } from '../../../@types/astro'; @@ -20,7 +21,7 @@ export interface SSROptions { logging: LogOptions; /** "development" or "production" */ mode: RuntimeMode; - /** production website, needed for some RSS & Sitemap functions */ + /** production website, needed for some RSS functions */ origin: string; /** the web request (needed for dynamic routes) */ pathname: string; @@ -65,13 +66,14 @@ export async function preload({ astroConfig, filePath, viteServer }: Pick<SSROpt /** use Vite to SSR */ export async function render(renderers: SSRLoadedRenderer[], mod: ComponentInstance, ssrOpts: SSROptions): Promise<RenderResponse> { const { astroConfig, filePath, logging, mode, origin, pathname, request, route, routeCache, viteServer } = ssrOpts; - const legacy = astroConfig.buildOptions.legacyBuild; + // TODO: clean up "legacy" flag passed through helper functions + const isLegacyBuild = false; // Add hoisted script tags - const scripts = createModuleScriptElementWithSrcSet(!legacy && mod.hasOwnProperty('$$metadata') ? Array.from(mod.$$metadata.hoistedScriptPaths()) : []); + const scripts = createModuleScriptElementWithSrcSet(!isLegacyBuild && mod.hasOwnProperty('$$metadata') ? Array.from(mod.$$metadata.hoistedScriptPaths()) : []); // Inject HMR scripts - if (mod.hasOwnProperty('$$metadata') && mode === 'development' && !legacy) { + if (mod.hasOwnProperty('$$metadata') && mode === 'development' && !isLegacyBuild) { scripts.add({ props: { type: 'module', src: '/@vite/client' }, children: '', @@ -93,7 +95,7 @@ export async function render(renderers: SSRLoadedRenderer[], mod: ComponentInsta // Pass framework CSS in as link tags to be appended to the page. let links = new Set<SSRElement>(); - if (!legacy) { + if (!isLegacyBuild) { [...getStylesForURL(filePath, viteServer)].forEach((href) => { if (mode === 'development' && svelteStylesRE.test(href)) { scripts.add({ @@ -114,10 +116,11 @@ export async function render(renderers: SSRLoadedRenderer[], mod: ComponentInsta } let content = await coreRender({ - legacyBuild: astroConfig.buildOptions.legacyBuild, + // TODO: Remove this flag once legacyBuild support is removed + legacyBuild: isLegacyBuild, links, logging, - markdownRender: astroConfig.markdownOptions.render, + markdownRender: [astroRemark, astroConfig.markdown], mod, origin, pathname, @@ -126,28 +129,21 @@ export async function render(renderers: SSRLoadedRenderer[], mod: ComponentInsta // TODO: Can we pass the hydration code more directly through Vite, so that we // don't need to copy-paste and maintain Vite's import resolution here? async resolve(s: string) { - // The legacy build needs these to remain unresolved so that vite HTML - // Can do the resolution. Without this condition the build output will be - // broken in the legacy build. This can be removed once the legacy build is removed. - if (!astroConfig.buildOptions.legacyBuild) { - const [resolvedUrl, resolvedPath] = await viteServer.moduleGraph.resolveUrl(s); - if (resolvedPath.includes('node_modules/.vite')) { - return resolvedPath.replace(/.*?node_modules\/\.vite/, '/node_modules/.vite'); - } - // NOTE: This matches the same logic that Vite uses to add the `/@id/` prefix. - if (!resolvedUrl.startsWith('.') && !resolvedUrl.startsWith('/')) { - return '/@id' + prependForwardSlash(resolvedUrl); - } - return '/@fs' + prependForwardSlash(resolvedPath); - } else { - return s; + const [resolvedUrl, resolvedPath] = await viteServer.moduleGraph.resolveUrl(s); + if (resolvedPath.includes('node_modules/.vite')) { + return resolvedPath.replace(/.*?node_modules\/\.vite/, '/node_modules/.vite'); + } + // NOTE: This matches the same logic that Vite uses to add the `/@id/` prefix. + if (!resolvedUrl.startsWith('.') && !resolvedUrl.startsWith('/')) { + return '/@id' + prependForwardSlash(resolvedUrl); } + return '/@fs' + prependForwardSlash(resolvedPath); }, renderers, request, route, routeCache, - site: astroConfig.buildOptions.site, + site: astroConfig.site ? new URL(astroConfig.base, astroConfig.site).toString() : undefined, ssr: isBuildingToSSR(astroConfig), }); @@ -159,7 +155,7 @@ export async function render(renderers: SSRLoadedRenderer[], mod: ComponentInsta const tags: vite.HtmlTagDescriptor[] = []; // dev only: inject Astro HMR client - if (mode === 'development' && legacy) { + if (mode === 'development' && isLegacyBuild) { tags.push({ tag: 'script', attrs: { type: 'module' }, @@ -171,7 +167,7 @@ export async function render(renderers: SSRLoadedRenderer[], mod: ComponentInsta } // inject CSS - if (legacy) { + if (isLegacyBuild) { [...getStylesForURL(filePath, viteServer)].forEach((href) => { if (mode === 'development' && svelteStylesRE.test(href)) { tags.push({ @@ -196,12 +192,6 @@ export async function render(renderers: SSRLoadedRenderer[], mod: ComponentInsta // add injected tags let html = injectTags(content.html, tags); - // run transformIndexHtml() in dev to run Vite dev transformations - if (mode === 'development' && astroConfig.buildOptions.legacyBuild) { - const relativeURL = filePath.href.replace(astroConfig.projectRoot.href, '/'); - html = await viteServer.transformIndexHtml(relativeURL, html, pathname); - } - // inject <!doctype html> if missing (TODO: is a more robust check needed for comments, etc.?) if (!/<!doctype html/i.test(html)) { html = '<!DOCTYPE html>\n' + content; diff --git a/packages/astro/src/core/render/result.ts b/packages/astro/src/core/render/result.ts index 8eaaadcc8..217044177 100644 --- a/packages/astro/src/core/render/result.ts +++ b/packages/astro/src/core/render/result.ts @@ -158,6 +158,7 @@ ${extra}` // Ensure this API is not exposed to users enumerable: false, writable: false, + // TODO: remove 1. markdown parser logic 2. update MarkdownRenderOptions to take a function only // <Markdown> also needs the same `astroConfig.markdownOptions.render` as `.md` pages value: async function (content: string, opts: any) { let [mdRender, renderOpts] = markdownRender; diff --git a/packages/astro/src/core/render/rss.ts b/packages/astro/src/core/render/rss.ts index e02a6155e..89c4ac40c 100644 --- a/packages/astro/src/core/render/rss.ts +++ b/packages/astro/src/core/render/rss.ts @@ -87,7 +87,7 @@ export function generateRSSStylesheet() { export function generateRssFunction(site: string | undefined, route: RouteData): RSSFunction { return function rssUtility(args: RSS): RSSResult { if (!site) { - throw new Error(`[${route.component}] rss() tried to generate RSS but "buildOptions.site" missing in astro.config.mjs`); + throw new Error(`[${route.component}] rss() tried to generate RSS but "site" missing in astro.config.mjs`); } let result: RSSResult = {} as any; const { dest, ...rssData } = args; diff --git a/packages/astro/src/core/render/sitemap.ts b/packages/astro/src/core/render/sitemap.ts deleted file mode 100644 index b7191e23e..000000000 --- a/packages/astro/src/core/render/sitemap.ts +++ /dev/null @@ -1,23 +0,0 @@ -const STATUS_CODE_PAGE_REGEXP = /\/[0-9]{3}\/?$/; - -/** Construct sitemap.xml given a set of URLs */ -export function generateSitemap(pages: string[], filter?: (page: string) => boolean): string { - // TODO: find way to respect <link rel="canonical"> URLs here - - // copy just in case original copy is needed - // make sure that 404 page is excluded - // also works for other error pages - let urls = [...pages].filter((url) => !STATUS_CODE_PAGE_REGEXP.test(url)); - - if (filter) { - urls = urls.filter((url) => filter(url)); - } - - urls.sort((a, b) => a.localeCompare(b, 'en', { numeric: true })); // sort alphabetically so sitemap is same each time - let sitemap = `<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">`; - for (const url of urls) { - sitemap += `<url><loc>${url}</loc></url>`; - } - sitemap += `</urlset>\n`; - return sitemap; -} diff --git a/packages/astro/src/core/routing/manifest/create.ts b/packages/astro/src/core/routing/manifest/create.ts index 6c7cb4829..905f0ed74 100644 --- a/packages/astro/src/core/routing/manifest/create.ts +++ b/packages/astro/src/core/routing/manifest/create.ts @@ -7,6 +7,7 @@ import { compile } from 'path-to-regexp'; import slash from 'slash'; import { fileURLToPath } from 'url'; import { warn } from '../../logger/core.js'; +import { resolvePages } from '../../util.js'; interface Part { content: string; @@ -55,7 +56,7 @@ function getParts(part: string, file: string) { return result; } -function getPattern(segments: Part[][], addTrailingSlash: AstroConfig['devOptions']['trailingSlash']) { +function getPattern(segments: Part[][], addTrailingSlash: AstroConfig['trailingSlash']) { const pathname = segments .map((segment) => { return segment[0].spread @@ -82,7 +83,7 @@ function getPattern(segments: Part[][], addTrailingSlash: AstroConfig['devOption return new RegExp(`^${pathname || '\\/'}${trailing}`); } -function getTrailingSlashPattern(addTrailingSlash: AstroConfig['devOptions']['trailingSlash']): string { +function getTrailingSlashPattern(addTrailingSlash: AstroConfig['trailingSlash']): string { if (addTrailingSlash === 'always') { return '\\/$'; } @@ -92,7 +93,7 @@ function getTrailingSlashPattern(addTrailingSlash: AstroConfig['devOptions']['tr return '\\/?$'; } -function getGenerator(segments: Part[][], addTrailingSlash: AstroConfig['devOptions']['trailingSlash']) { +function getGenerator(segments: Part[][], addTrailingSlash: AstroConfig['trailingSlash']) { const template = segments .map((segment) => { return segment[0].spread @@ -177,7 +178,7 @@ export function createRouteManifest({ config, cwd }: { config: AstroConfig; cwd? let items: Item[] = []; fs.readdirSync(dir).forEach((basename) => { const resolved = path.join(dir, basename); - const file = slash(path.relative(cwd || fileURLToPath(config.projectRoot), resolved)); + const file = slash(path.relative(cwd || fileURLToPath(config.root), resolved)); const isDir = fs.statSync(resolved).isDirectory(); const ext = path.extname(basename); @@ -265,7 +266,7 @@ export function createRouteManifest({ config, cwd }: { config: AstroConfig; cwd? } else { components.push(item.file); const component = item.file; - const trailingSlash = item.isPage ? config.devOptions.trailingSlash : 'never'; + const trailingSlash = item.isPage ? config.trailingSlash : 'never'; const pattern = getPattern(segments, trailingSlash); const generate = getGenerator(segments, trailingSlash); const pathname = segments.every((segment) => segment.length === 1 && !segment[0].dynamic) ? `/${segments.map((segment) => segment[0].content).join('/')}` : null; @@ -282,10 +283,12 @@ export function createRouteManifest({ config, cwd }: { config: AstroConfig; cwd? }); } - if (fs.existsSync(config.pages)) { - walk(fileURLToPath(config.pages), [], []); + const pages = resolvePages(config); + + if (fs.existsSync(pages)) { + walk(fileURLToPath(pages), [], []); } else { - const pagesDirRootRelative = config.pages.href.slice(config.projectRoot.href.length); + const pagesDirRootRelative = pages.href.slice(config.root.href.length); warn(logging, 'astro', `Missing pages directory: ${pagesDirRootRelative}`); } diff --git a/packages/astro/src/core/util.ts b/packages/astro/src/core/util.ts index 2ec2a1744..5ac1686aa 100644 --- a/packages/astro/src/core/util.ts +++ b/packages/astro/src/core/util.ts @@ -34,7 +34,7 @@ export function getOutputFilename(astroConfig: AstroConfig, name: string) { if (name === '/' || name === '') { return path.posix.join(name, 'index.html'); } - if (astroConfig.buildOptions.pageUrlFormat === 'directory' && !STATUS_CODE_REGEXP.test(name)) { + if (astroConfig.build.format === 'directory' && !STATUS_CODE_REGEXP.test(name)) { return path.posix.join(name, 'index.html'); } return `${removeEndingForwardSlash(name || 'index')}.html`; @@ -97,7 +97,7 @@ export function codeFrame(src: string, loc: ErrorPayload['err']['loc']): string export function resolveDependency(dep: string, astroConfig: AstroConfig) { const resolved = resolve.sync(dep, { - basedir: fileURLToPath(astroConfig.projectRoot), + basedir: fileURLToPath(astroConfig.root), }); // For Windows compat, we need a fully resolved `file://` URL string return pathToFileURL(resolved).toString(); @@ -138,12 +138,16 @@ export function emptyDir(_dir: URL, skip?: Set<string>): void { } } +export function resolvePages(config: AstroConfig) { + return new URL('./pages', config.srcDir); +} + export function isBuildingToSSR(config: AstroConfig): boolean { const adapter = config._ctx.adapter; if (!adapter) return false; if (typeof adapter.serverEntrypoint === 'string') { - if (!adapter.name.startsWith('@astrojs/') && !config.buildOptions.experimentalSsr) { + if (!adapter.name.startsWith('@astrojs/') && !config.experimental.ssr) { throw new Error( [ `Server-side rendering (SSR) is still experimental.`, @@ -166,17 +170,7 @@ export function emoji(char: string, fallback: string) { return process.platform !== 'win32' ? char : fallback; } -// TODO: remove once --hostname is baselined -export function getResolvedHostForVite(config: AstroConfig) { - if (config.devOptions.host === false && config.devOptions.hostname !== 'localhost') { - return config.devOptions.hostname; - } else { - return config.devOptions.host; - } -} - -export function getLocalAddress(serverAddress: string, config: AstroConfig): string { - const host = getResolvedHostForVite(config); +export function getLocalAddress(serverAddress: string, host: string | boolean): string { if (typeof host === 'boolean' || host === 'localhost') { return 'localhost'; } else { diff --git a/packages/astro/src/integrations/index.ts b/packages/astro/src/integrations/index.ts index 93176a6bf..1b0b04e39 100644 --- a/packages/astro/src/integrations/index.ts +++ b/packages/astro/src/integrations/index.ts @@ -103,7 +103,7 @@ export async function runHookBuildSetup({ config, vite, target }: { config: Astr export async function runHookBuildDone({ config, pages, routes }: { config: AstroConfig; pages: string[]; routes: RouteData[] }) { for (const integration of config.integrations) { if (integration.hooks['astro:build:done']) { - await integration.hooks['astro:build:done']({ pages: pages.map((p) => ({ pathname: p })), dir: config.dist, routes }); + await integration.hooks['astro:build:done']({ pages: pages.map((p) => ({ pathname: p })), dir: config.outDir, routes }); } } } diff --git a/packages/astro/src/runtime/server/index.ts b/packages/astro/src/runtime/server/index.ts index 7e8bc2b50..271a16ffc 100644 --- a/packages/astro/src/runtime/server/index.ts +++ b/packages/astro/src/runtime/server/index.ts @@ -467,6 +467,7 @@ export async function renderHead(result: SSRResult): Promise<string> { const styles = Array.from(result.styles) .filter(uniqueElements) .map((style) => { + // TODO: clean up legacyBuild from metadata const styleChildren = !result._metadata.legacyBuild ? '' : style.children; return renderElement('style', { children: styleChildren, diff --git a/packages/astro/src/template/4xx.ts b/packages/astro/src/template/4xx.ts index 7f90b6e16..6d5c051f7 100644 --- a/packages/astro/src/template/4xx.ts +++ b/packages/astro/src/template/4xx.ts @@ -64,7 +64,7 @@ export function subpathNotUsedTemplate(base: string, pathname: string) { statusCode: 404, title: 'Not found', tabTitle: '404: Not Found', - body: `<p>In your <code>buildOptions.site</code> you have your base path set to <a href="${base}">${base}</a>. Do you want to go there instead?</p> + body: `<p>In your <code>site</code> you have your base path set to <a href="${base}">${base}</a>. Do you want to go there instead?</p> <p>Come to our <a href="https://astro.build/chat">Discord</a> if you need help.</p>`, }); } diff --git a/packages/astro/src/vite-plugin-astro-server/index.ts b/packages/astro/src/vite-plugin-astro-server/index.ts index 5d85555af..46ee6b607 100644 --- a/packages/astro/src/vite-plugin-astro-server/index.ts +++ b/packages/astro/src/vite-plugin-astro-server/index.ts @@ -6,7 +6,7 @@ import { debug, info, warn, error, LogOptions } from '../core/logger/core.js'; import { getParamsAndProps, GetParamsAndPropsError } from '../core/render/core.js'; import { createRouteManifest, matchRoute } from '../core/routing/index.js'; import stripAnsi from 'strip-ansi'; -import { createSafeError, isBuildingToSSR } from '../core/util.js'; +import { createSafeError, resolvePages, isBuildingToSSR } from '../core/util.js'; import { ssr, preload } from '../core/render/dev/index.js'; import { call as callEndpoint } from '../core/endpoint/dev/index.js'; import * as msg from '../core/messages.js'; @@ -74,7 +74,7 @@ async function writeSSRResult(result: RenderResponse, res: http.ServerResponse, } async function handle404Response(origin: string, config: AstroConfig, req: http.IncomingMessage, res: http.ServerResponse) { - const site = config.buildOptions.site ? new URL(config.buildOptions.site) : undefined; + const site = config.site ? new URL(config.base, config.site) : undefined; const devRoot = site ? site.pathname : '/'; const pathname = decodeURI(new URL(origin + req.url).pathname); let html = ''; @@ -101,7 +101,7 @@ async function handle500Response(viteServer: vite.ViteDevServer, origin: string, } function getCustom404Route(config: AstroConfig, manifest: ManifestData) { - const relPages = config.pages.href.replace(config.projectRoot.href, ''); + const relPages = resolvePages(config).href.replace(config.root.href, ''); return manifest.routes.find((r) => r.component === relPages + '404.astro'); } @@ -120,7 +120,7 @@ async function handleRequest( res: http.ServerResponse ) { const reqStart = performance.now(); - const site = config.buildOptions.site ? new URL(config.buildOptions.site) : undefined; + const site = config.site ? new URL(config.base, config.site) : undefined; const devRoot = site ? site.pathname : '/'; const origin = `${viteServer.config.server.https ? 'https' : 'http'}://${req.headers.host}`; const buildingToSSR = isBuildingToSSR(config); @@ -174,7 +174,7 @@ async function handleRequest( } } - const filePath = new URL(`./${route.component}`, config.projectRoot); + const filePath = new URL(`./${route.component}`, config.root); const preloadedComponent = await preload({ astroConfig: config, filePath, viteServer }); const [, mod] = preloadedComponent; // attempt to get static paths @@ -192,7 +192,7 @@ async function handleRequest( log404(logging, pathname); const routeCustom404 = getCustom404Route(config, manifest); if (routeCustom404) { - const filePathCustom404 = new URL(`./${routeCustom404.component}`, config.projectRoot); + const filePathCustom404 = new URL(`./${routeCustom404.component}`, config.root); const preloadedCompCustom404 = await preload({ astroConfig: config, filePath: filePathCustom404, viteServer }); const result = await ssr(preloadedCompCustom404, { astroConfig: config, diff --git a/packages/astro/src/vite-plugin-astro/compile.ts b/packages/astro/src/vite-plugin-astro/compile.ts index 48bada5f4..9048c4830 100644 --- a/packages/astro/src/vite-plugin-astro/compile.ts +++ b/packages/astro/src/vite-plugin-astro/compile.ts @@ -37,7 +37,7 @@ const configCache = new WeakMap<AstroConfig, CompilationCache>(); async function compile(config: AstroConfig, filename: string, source: string, viteTransform: TransformHook, opts: { ssr: boolean }): Promise<CompileResult> { const filenameURL = new URL(`file://${filename}`); const normalizedID = fileURLToPath(filenameURL); - const pathname = filenameURL.pathname.substr(config.projectRoot.pathname.length - 1); + const pathname = filenameURL.pathname.substr(config.root.pathname.length - 1); let rawCSSDeps = new Set<string>(); let cssTransformError: Error | undefined; @@ -47,30 +47,28 @@ async function compile(config: AstroConfig, filename: string, source: string, vi // result passed to esbuild, but also available in the catch handler. const transformResult = await transform(source, { pathname, - projectRoot: config.projectRoot.toString(), - site: config.buildOptions.site, + projectRoot: config.root.toString(), + site: config.site ? new URL(config.base, config.site).toString() : undefined, sourcefile: filename, sourcemap: 'both', internalURL: `/@fs${prependForwardSlash(viteID(new URL('../runtime/server/index.js', import.meta.url)))}`, - experimentalStaticExtraction: !config.buildOptions.legacyBuild, - // TODO add experimental flag here + // TODO: baseline flag + experimentalStaticExtraction: true, preprocessStyle: async (value: string, attrs: Record<string, string>) => { const lang = `.${attrs?.lang || 'css'}`.toLowerCase(); try { // In the static build, grab any @import as CSS dependencies for HMR. - if (!config.buildOptions.legacyBuild) { - value.replace(/(?:@import)\s(?:url\()?\s?["\'](.*?)["\']\s?\)?(?:[^;]*);?/gi, (match, spec) => { - rawCSSDeps.add(spec); - // If the language is CSS: prevent `@import` inlining to prevent scoping of imports. - // Otherwise: Sass, etc. need to see imports for variables, so leave in for their compiler to handle. - if (lang === '.css') { - return createImportPlaceholder(spec); - } else { - return match; - } - }); - } + value.replace(/(?:@import)\s(?:url\()?\s?["\'](.*?)["\']\s?\)?(?:[^;]*);?/gi, (match, spec) => { + rawCSSDeps.add(spec); + // If the language is CSS: prevent `@import` inlining to prevent scoping of imports. + // Otherwise: Sass, etc. need to see imports for variables, so leave in for their compiler to handle. + if (lang === '.css') { + return createImportPlaceholder(spec); + } else { + return match; + } + }); const result = await transformWithVite({ value, diff --git a/packages/astro/src/vite-plugin-astro/hmr.ts b/packages/astro/src/vite-plugin-astro/hmr.ts index b70efa2a8..82b31b998 100644 --- a/packages/astro/src/vite-plugin-astro/hmr.ts +++ b/packages/astro/src/vite-plugin-astro/hmr.ts @@ -80,10 +80,10 @@ export async function handleHotUpdate(ctx: HmrContext, config: AstroConfig, logg } const mod = ctx.modules.find((m) => m.file === ctx.file); - const file = ctx.file.replace(config.projectRoot.pathname, '/'); // Note: this intentionally ONLY applies to Astro components // HMR is handled for other file types by their respective plugins + const file = ctx.file.replace(config.root.pathname, '/'); if (ctx.file.endsWith('.astro')) { ctx.server.ws.send({ type: 'custom', event: 'astro:update', data: { file } }); } diff --git a/packages/astro/src/vite-plugin-astro/index.ts b/packages/astro/src/vite-plugin-astro/index.ts index 8aff612ba..b8c82d456 100644 --- a/packages/astro/src/vite-plugin-astro/index.ts +++ b/packages/astro/src/vite-plugin-astro/index.ts @@ -14,6 +14,7 @@ import ancestor from 'common-ancestor-path'; import { trackCSSDependencies, handleHotUpdate } from './hmr.js'; import { isRelativePath, startsWithForwardSlash } from '../core/path.js'; import { PAGE_SCRIPT_ID, PAGE_SSR_SCRIPT_ID } from '../vite-plugin-scripts/index.js'; +import { resolvePages } from '../core/util.js'; const FRONTMATTER_PARSE_REGEXP = /^\-\-\-(.*)^\-\-\-/ms; interface AstroPluginOptions { @@ -26,14 +27,14 @@ export default function astro({ config, logging }: AstroPluginOptions): vite.Plu function normalizeFilename(filename: string) { if (filename.startsWith('/@fs')) { filename = filename.slice('/@fs'.length); - } else if (filename.startsWith('/') && !ancestor(filename, config.projectRoot.pathname)) { - filename = new URL('.' + filename, config.projectRoot).pathname; + } else if (filename.startsWith('/') && !ancestor(filename, config.root.pathname)) { + filename = new URL('.' + filename, config.root).pathname; } return filename; } function relativeToRoot(pathname: string) { const arg = startsWithForwardSlash(pathname) ? '.' + pathname : pathname; - const url = new URL(arg, config.projectRoot); + const url = new URL(arg, config.root); return slash(fileURLToPath(url)) + url.search; } @@ -42,7 +43,7 @@ export default function astro({ config, logging }: AstroPluginOptions): vite.Plu let viteDevServer: vite.ViteDevServer | null = null; // Variables for determing if an id starts with /src... - const srcRootWeb = config.src.pathname.slice(config.projectRoot.pathname.length - 1); + const srcRootWeb = config.srcDir.pathname.slice(config.root.pathname.length - 1); const isBrowserPath = (path: string) => path.startsWith(srcRootWeb); return { @@ -94,7 +95,7 @@ export default function astro({ config, logging }: AstroPluginOptions): vite.Plu const filename = normalizeFilename(parsedId.filename); const fileUrl = new URL(`file://${filename}`); let source = await fs.promises.readFile(fileUrl, 'utf-8'); - const isPage = fileUrl.pathname.startsWith(config.pages.pathname); + const isPage = fileUrl.pathname.startsWith(resolvePages(config).pathname); if (isPage && config._ctx.scripts.some((s) => s.stage === 'page')) { source += `\n<script src="${PAGE_SCRIPT_ID}" />`; } @@ -130,7 +131,7 @@ export default function astro({ config, logging }: AstroPluginOptions): vite.Plu if (hoistedScript.type === 'external') { const src = hoistedScript.src!; if (src.startsWith('/') && !isBrowserPath(src)) { - const publicDir = config.public.pathname.replace(/\/$/, '').split('/').pop() + '/'; + const publicDir = config.publicDir.pathname.replace(/\/$/, '').split('/').pop() + '/'; throw new Error( `\n\n<script src="${src}"> references an asset in the "${publicDir}" directory. Please add the "is:inline" directive to keep this asset from being bundled.\n\nFile: ${filename}` ); @@ -153,7 +154,7 @@ export default function astro({ config, logging }: AstroPluginOptions): vite.Plu sourcemap: 'external', sourcefile: id, // Pass relevant Vite options, if needed: - define: config.vite.define, + define: config.vite?.define, }); let SUFFIX = ''; @@ -201,7 +202,7 @@ export default function astro({ config, logging }: AstroPluginOptions): vite.Plu \`@astrojs/compiler\` encountered an unrecoverable error when compiling the following file. - **${id.replace(fileURLToPath(config.projectRoot), '')}** + **${id.replace(fileURLToPath(config.root), '')}** \`\`\`astro ${source} \`\`\` diff --git a/packages/astro/src/vite-plugin-build-html/index.ts b/packages/astro/src/vite-plugin-build-html/index.ts index a3af1f97e..32c59e531 100644 --- a/packages/astro/src/vite-plugin-build-html/index.ts +++ b/packages/astro/src/vite-plugin-build-html/index.ts @@ -48,9 +48,9 @@ export function rollupPluginAstroScanHTML(options: PluginOptions): VitePlugin { const { astroConfig, internals, logging, origin, allPages, routeCache, viteServer, pageNames } = options; // The filepath root of the src folder - const srcRoot = astroConfig.src.pathname; + const srcRoot = astroConfig.srcDir.pathname; // The web path of the src folter - const srcRootWeb = srcRoot.substr(astroConfig.projectRoot.pathname.length - 1); + const srcRootWeb = srcRoot.substr(astroConfig.root.pathname.length - 1); // A map of pages to rendered HTML const renderedPageMap = new Map<string, string>(); @@ -86,7 +86,7 @@ export function rollupPluginAstroScanHTML(options: PluginOptions): VitePlugin { const id = ASTRO_PAGE_PREFIX + pathname; const response = await ssrRender(renderers, mod, { astroConfig, - filePath: new URL(`./${component}`, astroConfig.projectRoot), + filePath: new URL(`./${component}`, astroConfig.root), logging, request: createRequest({ url: new URL(origin + pathname), @@ -162,7 +162,7 @@ export function rollupPluginAstroScanHTML(options: PluginOptions): VitePlugin { if (src?.startsWith(srcRoot) && !astroAssetMap.has(src)) { astroAssetMap.set(src, fs.readFile(new URL(`file://${src}`))); } else if (src?.startsWith(srcRootWeb) && !astroAssetMap.has(src)) { - const resolved = new URL('.' + src, astroConfig.projectRoot); + const resolved = new URL('.' + src, astroConfig.root); astroAssetMap.set(src, fs.readFile(resolved)); } } @@ -173,7 +173,7 @@ export function rollupPluginAstroScanHTML(options: PluginOptions): VitePlugin { if (url.startsWith(srcRoot) && !astroAssetMap.has(url)) { astroAssetMap.set(url, fs.readFile(new URL(`file://${url}`))); } else if (url.startsWith(srcRootWeb) && !astroAssetMap.has(url)) { - const resolved = new URL('.' + url, astroConfig.projectRoot); + const resolved = new URL('.' + url, astroConfig.root); astroAssetMap.set(url, fs.readFile(resolved)); } } @@ -403,7 +403,7 @@ export function rollupPluginAstroScanHTML(options: PluginOptions): VitePlugin { let src = getAttribute(script, 'src'); // If this is projectRoot relative, get the fullpath to match the facadeId. if (src?.startsWith(srcRootWeb)) { - src = new URL('.' + src, astroConfig.projectRoot).pathname; + src = new URL('.' + src, astroConfig.root).pathname; } // On windows the facadeId doesn't start with / but does not Unix :/ if (src && (facadeIdMap.has(src) || facadeIdMap.has(src.substr(1)))) { diff --git a/packages/astro/src/vite-plugin-config-alias/index.ts b/packages/astro/src/vite-plugin-config-alias/index.ts index 022165a03..f87a2c74d 100644 --- a/packages/astro/src/vite-plugin-config-alias/index.ts +++ b/packages/astro/src/vite-plugin-config-alias/index.ts @@ -70,9 +70,9 @@ const getConfigAlias = (cwd: string | undefined): Alias[] | null => { }; /** Returns a Vite plugin used to alias pathes from tsconfig.json and jsconfig.json. */ -export default function configAliasVitePlugin(astroConfig: { projectRoot?: URL; [key: string]: unknown }): vite.PluginOption { +export default function configAliasVitePlugin(astroConfig: { root?: URL; [key: string]: unknown }): vite.PluginOption { /** Aliases from the tsconfig.json or jsconfig.json configuration. */ - const configAlias = getConfigAlias(astroConfig.projectRoot && url.fileURLToPath(astroConfig.projectRoot)); + const configAlias = getConfigAlias(astroConfig.root && url.fileURLToPath(astroConfig.root)); // if no config alias was found, bypass this plugin if (!configAlias) return {} as vite.PluginOption; diff --git a/packages/astro/src/vite-plugin-env/index.ts b/packages/astro/src/vite-plugin-env/index.ts index e602a675e..2c2d2bba8 100644 --- a/packages/astro/src/vite-plugin-env/index.ts +++ b/packages/astro/src/vite-plugin-env/index.ts @@ -14,7 +14,7 @@ function getPrivateEnv(viteConfig: vite.ResolvedConfig, astroConfig: AstroConfig if (viteConfig.envPrefix) { envPrefixes = Array.isArray(viteConfig.envPrefix) ? viteConfig.envPrefix : [viteConfig.envPrefix]; } - const fullEnv = loadEnv(viteConfig.mode, viteConfig.envDir ?? fileURLToPath(astroConfig.projectRoot), ''); + const fullEnv = loadEnv(viteConfig.mode, viteConfig.envDir ?? fileURLToPath(astroConfig.root), ''); const privateKeys = Object.keys(fullEnv).filter((key) => { // don't expose any variables also on `process.env` // note: this filters out `CLI_ARGS=1` passed to node! diff --git a/packages/astro/src/vite-plugin-markdown/index.ts b/packages/astro/src/vite-plugin-markdown/index.ts index a250da2af..8f174556f 100644 --- a/packages/astro/src/vite-plugin-markdown/index.ts +++ b/packages/astro/src/vite-plugin-markdown/index.ts @@ -1,3 +1,4 @@ +import astroRemark from '@astrojs/markdown-remark'; import { transform } from '@astrojs/compiler'; import ancestor from 'common-ancestor-path'; import esbuild from 'esbuild'; @@ -8,6 +9,8 @@ import type { Plugin } from 'vite'; import type { AstroConfig } from '../@types/astro'; import { PAGE_SSR_SCRIPT_ID } from '../vite-plugin-scripts/index.js'; import { virtualModuleId as pagesVirtualModuleId } from '../core/build/vite-plugin-pages.js'; +import { appendForwardSlash } from '../core/path.js'; +import { resolvePages } from '../core/util.js'; interface AstroPluginOptions { config: AstroConfig; @@ -23,8 +26,8 @@ export default function markdown({ config }: AstroPluginOptions): Plugin { function normalizeFilename(filename: string) { if (filename.startsWith('/@fs')) { filename = filename.slice('/@fs'.length); - } else if (filename.startsWith('/') && !ancestor(filename, config.projectRoot.pathname)) { - filename = new URL('.' + filename, config.projectRoot).pathname; + } else if (filename.startsWith('/') && !ancestor(filename, config.root.pathname)) { + filename = new URL('.' + filename, config.root).pathname; } return filename; } @@ -32,7 +35,7 @@ export default function markdown({ config }: AstroPluginOptions): Plugin { // Weird Vite behavior: Vite seems to use a fake "index.html" importer when you // have `enforce: pre`. This can probably be removed once the vite issue is fixed. // see: https://github.com/vitejs/vite/issues/5981 - const fakeRootImporter = fileURLToPath(new URL('index.html', config.projectRoot)); + const fakeRootImporter = fileURLToPath(new URL('index.html', config.root)); function isRootImport(importer: string | undefined) { if (!importer) { return true; @@ -79,7 +82,7 @@ export default function markdown({ config }: AstroPluginOptions): Plugin { // Return the file's JS representation, including all Markdown // frontmatter and a deferred `import() of the compiled markdown content. if (id.startsWith(VIRTUAL_MODULE_ID)) { - const sitePathname = config.buildOptions.site ? new URL(config.buildOptions.site).pathname : '/'; + const sitePathname = config.site ? appendForwardSlash(new URL(config.base, config.site).pathname) : '/'; const fileId = id.substring(VIRTUAL_MODULE_ID.length); const fileUrl = fileId.includes('/pages/') ? fileId.replace(/^.*\/pages\//, sitePathname).replace(/(\/index)?\.md$/, '') : undefined; const source = await fs.promises.readFile(fileId, 'utf8'); @@ -111,19 +114,12 @@ export default function markdown({ config }: AstroPluginOptions): Plugin { // This returns the compiled markdown -> astro component that renders to HTML. if (id.endsWith('.md')) { const source = await fs.promises.readFile(id, 'utf8'); - let render = config.markdownOptions.render; - let renderOpts = {}; - if (Array.isArray(render)) { - renderOpts = render[1]; - render = render[0]; - } - if (typeof render === 'string') { - ({ default: render } = await import(render)); - } + const render = astroRemark; + const renderOpts = config.markdown; const filename = normalizeFilename(id); const fileUrl = new URL(`file://${filename}`); - const isPage = fileUrl.pathname.startsWith(config.pages.pathname); + const isPage = fileUrl.pathname.startsWith(resolvePages(config).pathname); const hasInjectedScript = isPage && config._ctx.scripts.some((s) => s.stage === 'page-ssr'); // Extract special frontmatter keys @@ -151,9 +147,9 @@ ${setup}`.trim(); // Transform from `.astro` to valid `.ts` let { code: tsResult } = await transform(astroResult, { - pathname: fileUrl.pathname.substr(config.projectRoot.pathname.length - 1), - projectRoot: config.projectRoot.toString(), - site: config.buildOptions.site, + pathname: fileUrl.pathname.substr(config.root.pathname.length - 1), + projectRoot: config.root.toString(), + site: config.site ? new URL(config.base, config.site).toString() : undefined, sourcefile: id, sourcemap: 'inline', internalURL: `/@fs${new URL('../runtime/server/index.js', import.meta.url).pathname}`, diff --git a/packages/astro/test/0-css.test.js b/packages/astro/test/0-css.test.js index 6d86bf886..9633127c9 100644 --- a/packages/astro/test/0-css.test.js +++ b/packages/astro/test/0-css.test.js @@ -12,7 +12,7 @@ let fixture; describe('CSS', function () { before(async () => { - fixture = await loadFixture({ projectRoot: './fixtures/0-css/' }); + fixture = await loadFixture({ root: './fixtures/0-css/' }); }); // test HTML and CSS contents for accuracy diff --git a/packages/astro/test/astro-assets.test.js b/packages/astro/test/astro-assets.test.js index 84f361672..a003f70c9 100644 --- a/packages/astro/test/astro-assets.test.js +++ b/packages/astro/test/astro-assets.test.js @@ -12,7 +12,7 @@ describe('Assets', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/astro-assets/', + root: './fixtures/astro-assets/', }); await fixture.build(); }); diff --git a/packages/astro/test/astro-attrs.test.js b/packages/astro/test/astro-attrs.test.js index 1f2dc1544..ad52782bb 100644 --- a/packages/astro/test/astro-attrs.test.js +++ b/packages/astro/test/astro-attrs.test.js @@ -6,7 +6,7 @@ describe('Attributes', async () => { let fixture; before(async () => { - fixture = await loadFixture({ projectRoot: './fixtures/astro-attrs/' }); + fixture = await loadFixture({ root: './fixtures/astro-attrs/' }); await fixture.build(); }); diff --git a/packages/astro/test/astro-basic.test.js b/packages/astro/test/astro-basic.test.js index 4b76b7d40..0b421a026 100644 --- a/packages/astro/test/astro-basic.test.js +++ b/packages/astro/test/astro-basic.test.js @@ -8,7 +8,7 @@ describe('Astro basics', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/astro-basic/', + root: './fixtures/astro-basic/', }); await fixture.build(); previewServer = await fixture.preview(); diff --git a/packages/astro/test/astro-children.test.js b/packages/astro/test/astro-children.test.js index d3f985f63..73e896474 100644 --- a/packages/astro/test/astro-children.test.js +++ b/packages/astro/test/astro-children.test.js @@ -6,7 +6,7 @@ describe('Component children', () => { let fixture; before(async () => { - fixture = await loadFixture({ projectRoot: './fixtures/astro-children/' }); + fixture = await loadFixture({ root: './fixtures/astro-children/' }); await fixture.build(); }); diff --git a/packages/astro/test/astro-class-list.test.js b/packages/astro/test/astro-class-list.test.js index 9516c3002..24a6ff81e 100644 --- a/packages/astro/test/astro-class-list.test.js +++ b/packages/astro/test/astro-class-list.test.js @@ -6,7 +6,7 @@ describe('Class List', async () => { let fixture; before(async () => { - fixture = await loadFixture({ projectRoot: './fixtures/astro-class-list/' }); + fixture = await loadFixture({ root: './fixtures/astro-class-list/' }); await fixture.build(); }); diff --git a/packages/astro/test/astro-client-only.test.js b/packages/astro/test/astro-client-only.test.js index 211a7df2a..812b7229b 100644 --- a/packages/astro/test/astro-client-only.test.js +++ b/packages/astro/test/astro-client-only.test.js @@ -7,7 +7,7 @@ describe('Client only components', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/astro-client-only/', + root: './fixtures/astro-client-only/', }); await fixture.build(); }); diff --git a/packages/astro/test/astro-component-code.test.js b/packages/astro/test/astro-component-code.test.js index 6c143eb18..26aec0138 100644 --- a/packages/astro/test/astro-component-code.test.js +++ b/packages/astro/test/astro-component-code.test.js @@ -6,7 +6,7 @@ describe('<Code>', () => { let fixture; before(async () => { - fixture = await loadFixture({ projectRoot: './fixtures/astro-component-code/' }); + fixture = await loadFixture({ root: './fixtures/astro-component-code/' }); await fixture.build(); }); diff --git a/packages/astro/test/astro-css-bundling-import.test.js b/packages/astro/test/astro-css-bundling-import.test.js index 4722a7e33..62e996dbd 100644 --- a/packages/astro/test/astro-css-bundling-import.test.js +++ b/packages/astro/test/astro-css-bundling-import.test.js @@ -7,7 +7,7 @@ describe('CSS Bundling (ESM import)', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/astro-css-bundling-import/', + root: './fixtures/astro-css-bundling-import/', }); await fixture.build(); }); diff --git a/packages/astro/test/astro-css-bundling.test.js b/packages/astro/test/astro-css-bundling.test.js index 105b35bc9..abddfa6f4 100644 --- a/packages/astro/test/astro-css-bundling.test.js +++ b/packages/astro/test/astro-css-bundling.test.js @@ -16,7 +16,7 @@ describe('CSS Bundling', function () { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/astro-css-bundling/', + root: './fixtures/astro-css-bundling/', }); await fixture.build({ mode: 'production' }); }); diff --git a/packages/astro/test/astro-directives.test.js b/packages/astro/test/astro-directives.test.js index 536ba3441..e2223e637 100644 --- a/packages/astro/test/astro-directives.test.js +++ b/packages/astro/test/astro-directives.test.js @@ -6,7 +6,7 @@ describe('Directives', async () => { let fixture; before(async () => { - fixture = await loadFixture({ projectRoot: './fixtures/astro-directives/' }); + fixture = await loadFixture({ root: './fixtures/astro-directives/' }); await fixture.build(); }); diff --git a/packages/astro/test/astro-doctype.test.js b/packages/astro/test/astro-doctype.test.js index b1661db1a..cb9a0c63c 100644 --- a/packages/astro/test/astro-doctype.test.js +++ b/packages/astro/test/astro-doctype.test.js @@ -6,7 +6,7 @@ describe('Doctype', () => { let fixture; before(async () => { - fixture = await loadFixture({ projectRoot: './fixtures/astro-doctype/' }); + fixture = await loadFixture({ root: './fixtures/astro-doctype/' }); await fixture.build(); }); diff --git a/packages/astro/test/astro-dynamic.test.js b/packages/astro/test/astro-dynamic.test.js index bc3d10b78..d133fba29 100644 --- a/packages/astro/test/astro-dynamic.test.js +++ b/packages/astro/test/astro-dynamic.test.js @@ -7,7 +7,7 @@ describe('Dynamic components', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/astro-dynamic/', + root: './fixtures/astro-dynamic/', }); await fixture.build(); }); diff --git a/packages/astro/test/astro-envs.test.js b/packages/astro/test/astro-envs.test.js index 5cf3dc84a..f44b007c8 100644 --- a/packages/astro/test/astro-envs.test.js +++ b/packages/astro/test/astro-envs.test.js @@ -6,7 +6,7 @@ describe('Environment Variables', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/astro-envs/', + root: './fixtures/astro-envs/', }); await fixture.build(); diff --git a/packages/astro/test/astro-expr.test.js b/packages/astro/test/astro-expr.test.js index 679cac1cf..0a514e48f 100644 --- a/packages/astro/test/astro-expr.test.js +++ b/packages/astro/test/astro-expr.test.js @@ -7,7 +7,7 @@ describe('Expressions', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/astro-expr/', + root: './fixtures/astro-expr/', }); await fixture.build(); }); diff --git a/packages/astro/test/astro-external-files.test.js b/packages/astro/test/astro-external-files.test.js index fba051c65..397f31785 100644 --- a/packages/astro/test/astro-external-files.test.js +++ b/packages/astro/test/astro-external-files.test.js @@ -6,7 +6,7 @@ import { loadFixture } from './test-utils.js'; let fixture; before(async () => { - fixture = await loadFixture({ projectRoot: './fixtures/astro-external-files/' }); + fixture = await loadFixture({ root: './fixtures/astro-external-files/' }); await fixture.build(); }); diff --git a/packages/astro/test/astro-fallback.test.js b/packages/astro/test/astro-fallback.test.js index f098bd177..9e9752c8a 100644 --- a/packages/astro/test/astro-fallback.test.js +++ b/packages/astro/test/astro-fallback.test.js @@ -7,7 +7,7 @@ describe('Dynamic component fallback', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/astro-fallback', + root: './fixtures/astro-fallback', }); await fixture.build(); }); diff --git a/packages/astro/test/astro-get-static-paths.test.js b/packages/astro/test/astro-get-static-paths.test.js index cecfebe70..3de3b58c9 100644 --- a/packages/astro/test/astro-get-static-paths.test.js +++ b/packages/astro/test/astro-get-static-paths.test.js @@ -4,11 +4,9 @@ import { loadFixture } from './test-utils.js'; describe('getStaticPaths - build calls', () => { before(async () => { const fixture = await loadFixture({ - projectRoot: './fixtures/astro-get-static-paths/', - buildOptions: { - site: 'https://mysite.dev/blog/', - sitemap: false, - }, + root: './fixtures/astro-get-static-paths/', + site: 'https://mysite.dev/', + base: '/blog', }); await fixture.build(); }); @@ -23,7 +21,7 @@ describe('getStaticPaths - 404 behavior', () => { let devServer; before(async () => { - fixture = await loadFixture({ projectRoot: './fixtures/astro-get-static-paths/' }); + fixture = await loadFixture({ root: './fixtures/astro-get-static-paths/' }); devServer = await fixture.startDevServer(); }); diff --git a/packages/astro/test/astro-global.test.js b/packages/astro/test/astro-global.test.js index 8330be821..41baa39de 100644 --- a/packages/astro/test/astro-global.test.js +++ b/packages/astro/test/astro-global.test.js @@ -7,11 +7,7 @@ describe('Astro.*', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/astro-global/', - buildOptions: { - site: 'https://mysite.dev/blog/', - sitemap: false, - }, + root: './fixtures/astro-global/' }); await fixture.build(); }); diff --git a/packages/astro/test/astro-markdown-drafts.test.js b/packages/astro/test/astro-markdown-drafts.test.js index beee3fd7f..2c6e60be8 100644 --- a/packages/astro/test/astro-markdown-drafts.test.js +++ b/packages/astro/test/astro-markdown-drafts.test.js @@ -7,12 +7,7 @@ describe('Astro Markdown with draft posts disabled', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/astro-markdown-drafts/', - buildOptions: { - // drafts is false by default but added here for clarity - drafts: false, - sitemap: false, - }, + root: './fixtures/astro-markdown-drafts/', }); await fixture.build(); }); @@ -30,10 +25,9 @@ describe('Astro Markdown with draft posts enabled', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/astro-markdown-drafts/', - buildOptions: { + root: './fixtures/astro-markdown-drafts/', + markdown: { drafts: true, - sitemap: false, }, }); await fixture.build(); diff --git a/packages/astro/test/astro-markdown-plugins.test.js b/packages/astro/test/astro-markdown-plugins.test.js index 01c6c01b2..6277bbf0d 100644 --- a/packages/astro/test/astro-markdown-plugins.test.js +++ b/packages/astro/test/astro-markdown-plugins.test.js @@ -1,7 +1,6 @@ import { expect } from 'chai'; import cheerio from 'cheerio'; import { loadFixture } from './test-utils.js'; -import markdownRemark from '@astrojs/markdown-remark'; import addClasses from './fixtures/astro-markdown-plugins/add-classes.mjs'; describe('Astro Markdown plugins', () => { @@ -9,18 +8,10 @@ describe('Astro Markdown plugins', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/astro-markdown-plugins/', - markdownOptions: { - render: [ - markdownRemark, - { - remarkPlugins: ['remark-code-titles', ['rehype-autolink-headings', { behavior: 'prepend' }]], - rehypePlugins: [['rehype-toc', { headings: ['h2', 'h3'] }], [addClasses, { 'h1,h2,h3': 'title' }], 'rehype-slug'], - }, - ], - }, - buildOptions: { - sitemap: false, + root: './fixtures/astro-markdown-plugins/', + markdown: { + remarkPlugins: ['remark-code-titles', ['rehype-autolink-headings', { behavior: 'prepend' }]], + rehypePlugins: [['rehype-toc', { headings: ['h2', 'h3'] }], [addClasses, { 'h1,h2,h3': 'title' }], 'rehype-slug'], }, }); await fixture.build(); diff --git a/packages/astro/test/astro-markdown-shiki.test.js b/packages/astro/test/astro-markdown-shiki.test.js index f98b5413b..d8cd43fcb 100644 --- a/packages/astro/test/astro-markdown-shiki.test.js +++ b/packages/astro/test/astro-markdown-shiki.test.js @@ -7,7 +7,7 @@ describe('Astro Markdown Shiki', () => { let fixture; before(async () => { - fixture = await loadFixture({ projectRoot: './fixtures/astro-markdown-shiki/normal/' }); + fixture = await loadFixture({ root: './fixtures/astro-markdown-shiki/normal/' }); await fixture.build(); }); @@ -43,7 +43,7 @@ describe('Astro Markdown Shiki', () => { let fixture; before(async () => { - fixture = await loadFixture({ projectRoot: './fixtures/astro-markdown-shiki/themes-integrated/' }); + fixture = await loadFixture({ root: './fixtures/astro-markdown-shiki/themes-integrated/' }); await fixture.build(); }); @@ -70,7 +70,7 @@ describe('Astro Markdown Shiki', () => { let fixture; before(async () => { - fixture = await loadFixture({ projectRoot: './fixtures/astro-markdown-shiki/themes-custom/' }); + fixture = await loadFixture({ root: './fixtures/astro-markdown-shiki/themes-custom/' }); await fixture.build(); }); @@ -98,7 +98,7 @@ describe('Astro Markdown Shiki', () => { let fixture; before(async () => { - fixture = await loadFixture({ projectRoot: './fixtures/astro-markdown-shiki/langs/' }); + fixture = await loadFixture({ root: './fixtures/astro-markdown-shiki/langs/' }); await fixture.build(); }); @@ -130,7 +130,7 @@ describe('Astro Markdown Shiki', () => { let fixture; before(async () => { - fixture = await loadFixture({ projectRoot: './fixtures/astro-markdown-shiki/wrap-true/' }); + fixture = await loadFixture({ root: './fixtures/astro-markdown-shiki/wrap-true/' }); await fixture.build(); }); @@ -157,7 +157,7 @@ describe('Astro Markdown Shiki', () => { let fixture; before(async () => { - fixture = await loadFixture({ projectRoot: './fixtures/astro-markdown-shiki/wrap-false/' }); + fixture = await loadFixture({ root: './fixtures/astro-markdown-shiki/wrap-false/' }); await fixture.build(); }); @@ -183,7 +183,7 @@ describe('Astro Markdown Shiki', () => { let fixture; before(async () => { - fixture = await loadFixture({ projectRoot: './fixtures/astro-markdown-shiki/wrap-null/' }); + fixture = await loadFixture({ root: './fixtures/astro-markdown-shiki/wrap-null/' }); await fixture.build(); }); diff --git a/packages/astro/test/astro-markdown.test.js b/packages/astro/test/astro-markdown.test.js index fdcd2bde2..10e403659 100644 --- a/packages/astro/test/astro-markdown.test.js +++ b/packages/astro/test/astro-markdown.test.js @@ -7,7 +7,7 @@ describe('Astro Markdown', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/astro-markdown/', + root: './fixtures/astro-markdown/', }); await fixture.build(); }); diff --git a/packages/astro/test/astro-pageDirectoryUrl.test.js b/packages/astro/test/astro-pageDirectoryUrl.test.js index 7fec5bb35..978db056a 100644 --- a/packages/astro/test/astro-pageDirectoryUrl.test.js +++ b/packages/astro/test/astro-pageDirectoryUrl.test.js @@ -1,14 +1,14 @@ import { expect } from 'chai'; import { loadFixture } from './test-utils.js'; -describe('pageUrlFormat', () => { +describe('build format', () => { let fixture; before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/astro-page-directory-url', - buildOptions: { - pageUrlFormat: 'file', + root: './fixtures/astro-page-directory-url', + build: { + format: 'file', }, }); await fixture.build(); diff --git a/packages/astro/test/astro-pages.test.js b/packages/astro/test/astro-pages.test.js index 6cb0f8dfd..3a1a504ad 100644 --- a/packages/astro/test/astro-pages.test.js +++ b/packages/astro/test/astro-pages.test.js @@ -6,7 +6,7 @@ describe('Pages', () => { let fixture; before(async () => { - fixture = await loadFixture({ projectRoot: './fixtures/astro-pages/' }); + fixture = await loadFixture({ root: './fixtures/astro-pages/' }); await fixture.build(); }); diff --git a/packages/astro/test/astro-pagination.test.js b/packages/astro/test/astro-pagination.test.js index 923342cd7..7090cec4f 100644 --- a/packages/astro/test/astro-pagination.test.js +++ b/packages/astro/test/astro-pagination.test.js @@ -7,11 +7,9 @@ describe('Pagination', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/astro-pagination/', - buildOptions: { - site: 'https://mysite.dev/blog/', - sitemap: false, - }, + root: './fixtures/astro-pagination/', + site: 'https://mysite.dev/', + base: '/blog', }); await fixture.build(); }); diff --git a/packages/astro/test/astro-partial-html.test.js b/packages/astro/test/astro-partial-html.test.js index f2d1852dd..bc50df41b 100644 --- a/packages/astro/test/astro-partial-html.test.js +++ b/packages/astro/test/astro-partial-html.test.js @@ -8,7 +8,7 @@ describe('Partial HTML', async () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/astro-partial-html/', + root: './fixtures/astro-partial-html/', }); devServer = await fixture.startDevServer(); }); diff --git a/packages/astro/test/astro-public.test.js b/packages/astro/test/astro-public.test.js index cf992a282..9f4094e1c 100644 --- a/packages/astro/test/astro-public.test.js +++ b/packages/astro/test/astro-public.test.js @@ -5,7 +5,7 @@ describe('Public', () => { let fixture; before(async () => { - fixture = await loadFixture({ projectRoot: './fixtures/astro-public/' }); + fixture = await loadFixture({ root: './fixtures/astro-public/' }); await fixture.build(); }); diff --git a/packages/astro/test/astro-response.test.js b/packages/astro/test/astro-response.test.js index 719d14d30..195247eba 100644 --- a/packages/astro/test/astro-response.test.js +++ b/packages/astro/test/astro-response.test.js @@ -10,7 +10,7 @@ describe('Returning responses', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/astro-response/', + root: './fixtures/astro-response/', }); devServer = await fixture.startDevServer(); diff --git a/packages/astro/test/astro-scripts.test.js b/packages/astro/test/astro-scripts.test.js index d11b7c264..ad60511ed 100644 --- a/packages/astro/test/astro-scripts.test.js +++ b/packages/astro/test/astro-scripts.test.js @@ -8,7 +8,7 @@ describe('Scripts (hoisted and not)', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/astro-scripts/', + root: './fixtures/astro-scripts/', vite: { build: { assetsInlineLimit: 0, diff --git a/packages/astro/test/astro-sitemap-rss.test.js b/packages/astro/test/astro-sitemap-rss.test.js deleted file mode 100644 index 38b788efb..000000000 --- a/packages/astro/test/astro-sitemap-rss.test.js +++ /dev/null @@ -1,67 +0,0 @@ -import { expect } from 'chai'; -import { loadFixture } from './test-utils.js'; - -describe('Sitemaps', () => { - let fixture; - - before(async () => { - fixture = await loadFixture({ - projectRoot: './fixtures/astro-sitemap-rss/', - buildOptions: { - site: 'https://astro.build/', - sitemap: true, - }, - }); - await fixture.build(); - }); - - describe('RSS Generation', () => { - it('generates RSS correctly', async () => { - const rss = await fixture.readFile('/custom/feed.xml'); - expect(rss).to.equal( - `<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title><![CDATA[MF Doomcast]]></title><description><![CDATA[The podcast about the things you find on a picnic, or at a picnic table]]></description><link>https://astro.build/</link><language>en-us</language><itunes:author>MF Doom</itunes:author><item><title><![CDATA[Rap Snitch Knishes (feat. Mr. Fantastik)]]></title><link>https://astro.build/episode/rap-snitch-knishes/</link><guid>https://astro.build/episode/rap-snitch-knishes/</guid><description><![CDATA[Complex named this song the “22nd funniest rap song of all time.”]]></description><pubDate>Tue, 16 Nov 2004 00:00:00 GMT</pubDate><itunes:episodeType>music</itunes:episodeType><itunes:duration>172</itunes:duration><itunes:explicit>true</itunes:explicit></item><item><title><![CDATA[Fazers]]></title><link>https://astro.build/episode/fazers/</link><guid>https://astro.build/episode/fazers/</guid><description><![CDATA[Rhapsody ranked Take Me to Your Leader 17th on its list “Hip-Hop’s Best Albums of the Decade”]]></description><pubDate>Thu, 03 Jul 2003 00:00:00 GMT</pubDate><itunes:episodeType>music</itunes:episodeType><itunes:duration>197</itunes:duration><itunes:explicit>true</itunes:explicit></item><item><title><![CDATA[Rhymes Like Dimes (feat. Cucumber Slice)]]></title><link>https://astro.build/episode/rhymes-like-dimes/</link><guid>https://astro.build/episode/rhymes-like-dimes/</guid><description><![CDATA[Operation: Doomsday has been heralded as an underground classic that established MF Doom's rank within the underground hip-hop scene during the early to mid-2000s. -]]></description><pubDate>Tue, 19 Oct 1999 00:00:00 GMT</pubDate><itunes:episodeType>music</itunes:episodeType><itunes:duration>259</itunes:duration><itunes:explicit>true</itunes:explicit></item></channel></rss>` - ); - }); - it('generates RSS with pregenerated URLs correctly', async () => { - const rss = await fixture.readFile('/custom/feed-pregenerated-urls.xml'); - expect(rss).to.equal( - `<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title><![CDATA[MF Doomcast]]></title><description><![CDATA[The podcast about the things you find on a picnic, or at a picnic table]]></description><link>https://astro.build/</link><language>en-us</language><itunes:author>MF Doom</itunes:author><item><title><![CDATA[Rap Snitch Knishes (feat. Mr. Fantastik)]]></title><link>https://example.com/episode/rap-snitch-knishes/</link><guid>https://example.com/episode/rap-snitch-knishes/</guid><description><![CDATA[Complex named this song the “22nd funniest rap song of all time.”]]></description><pubDate>Tue, 16 Nov 2004 00:00:00 GMT</pubDate><itunes:episodeType>music</itunes:episodeType><itunes:duration>172</itunes:duration><itunes:explicit>true</itunes:explicit></item><item><title><![CDATA[Fazers]]></title><link>https://example.com/episode/fazers/</link><guid>https://example.com/episode/fazers/</guid><description><![CDATA[Rhapsody ranked Take Me to Your Leader 17th on its list “Hip-Hop’s Best Albums of the Decade”]]></description><pubDate>Thu, 03 Jul 2003 00:00:00 GMT</pubDate><itunes:episodeType>music</itunes:episodeType><itunes:duration>197</itunes:duration><itunes:explicit>true</itunes:explicit></item><item><title><![CDATA[Rhymes Like Dimes (feat. Cucumber Slice)]]></title><link>https://example.com/episode/rhymes-like-dimes/</link><guid>https://example.com/episode/rhymes-like-dimes/</guid><description><![CDATA[Operation: Doomsday has been heralded as an underground classic that established MF Doom's rank within the underground hip-hop scene during the early to mid-2000s. -]]></description><pubDate>Tue, 19 Oct 1999 00:00:00 GMT</pubDate><itunes:episodeType>music</itunes:episodeType><itunes:duration>259</itunes:duration><itunes:explicit>true</itunes:explicit></item></channel></rss>` - ); - }); - }); - - describe('Sitemap Generation', () => { - it('Generates Sitemap correctly', async () => { - let sitemap = await fixture.readFile('/sitemap.xml'); - expect(sitemap).to.equal( - `<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"><url><loc>https://astro.build/episode/fazers/</loc></url><url><loc>https://astro.build/episode/rap-snitch-knishes/</loc></url><url><loc>https://astro.build/episode/rhymes-like-dimes/</loc></url><url><loc>https://astro.build/episodes/</loc></url></urlset>\n` - ); - }); - }); -}); - -describe('Sitemaps served from subdirectory', () => { - let fixture; - - before(async () => { - fixture = await loadFixture({ - projectRoot: './fixtures/astro-sitemap-rss/', - buildOptions: { - site: 'https://astro.build/base-directory/', - sitemap: true, - }, - }); - await fixture.build(); - }); - - describe('Sitemap Generation', () => { - it('Generates Sitemap correctly', async () => { - let sitemap = await fixture.readFile('/sitemap.xml'); - expect(sitemap).to.equal( - `<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"><url><loc>https://astro.build/base-directory/episode/fazers/</loc></url><url><loc>https://astro.build/base-directory/episode/rap-snitch-knishes/</loc></url><url><loc>https://astro.build/base-directory/episode/rhymes-like-dimes/</loc></url><url><loc>https://astro.build/base-directory/episodes/</loc></url></urlset>\n` - ); - }); - }); -}); diff --git a/packages/astro/test/astro-slots.test.js b/packages/astro/test/astro-slots.test.js index dd4883708..d890f2f31 100644 --- a/packages/astro/test/astro-slots.test.js +++ b/packages/astro/test/astro-slots.test.js @@ -6,7 +6,7 @@ describe('Slots', () => { let fixture; before(async () => { - fixture = await loadFixture({ projectRoot: './fixtures/astro-slots/' }); + fixture = await loadFixture({ root: './fixtures/astro-slots/' }); await fixture.build(); }); diff --git a/packages/astro/test/cli.test.js b/packages/astro/test/cli.test.js index c23fca34f..b40807f11 100644 --- a/packages/astro/test/cli.test.js +++ b/packages/astro/test/cli.test.js @@ -7,7 +7,7 @@ import { isIPv4 } from 'net'; describe('astro cli', () => { const cliServerLogSetupWithFixture = (flags, cmd) => { const projectRootURL = new URL('./fixtures/astro-basic/', import.meta.url); - return cliServerLogSetup(['--project-root', fileURLToPath(projectRootURL), ...flags], cmd); + return cliServerLogSetup(['--root', fileURLToPath(projectRootURL), ...flags], cmd); }; it('astro', async () => { @@ -27,7 +27,7 @@ describe('astro cli', () => { it('astro build', async () => { const projectRootURL = new URL('./fixtures/astro-basic/', import.meta.url); - const proc = await cli('build', '--project-root', fileURLToPath(projectRootURL)); + const proc = await cli('build', '--root', fileURLToPath(projectRootURL)); expect(proc.stdout).to.include('Complete'); }); @@ -36,7 +36,7 @@ describe('astro cli', () => { const pkgVersion = await fs.readFile(pkgURL, 'utf8').then((data) => JSON.parse(data).version); const projectRootURL = new URL('./fixtures/astro-basic/', import.meta.url); - const proc = cli('dev', '--project-root', fileURLToPath(projectRootURL)); + const proc = cli('dev', '--root', fileURLToPath(projectRootURL)); const { messages } = await parseCliDevStart(proc); expect(messages[0]).to.contain('astro'); @@ -45,7 +45,7 @@ describe('astro cli', () => { }); ['dev', 'preview'].forEach((cmd) => { - const networkLogFlags = [['--host'], ['--host', '0.0.0.0'], ['--hostname', '0.0.0.0']]; + const networkLogFlags = [['--host'], ['--host', '0.0.0.0']]; networkLogFlags.forEach(([flag, flagValue]) => { it(`astro ${cmd} ${flag} ${flagValue ?? ''} - network log`, async () => { const { local, network } = await cliServerLogSetupWithFixture(flagValue ? [flag, flagValue] : [flag], cmd); @@ -66,7 +66,6 @@ describe('astro cli', () => { const hostToExposeFlags = [ ['', ''], - ['--hostname', 'localhost'], ]; hostToExposeFlags.forEach(([flag, flagValue]) => { it(`astro ${cmd} ${flag} ${flagValue} - host to expose`, async () => { @@ -84,7 +83,6 @@ describe('astro cli', () => { const noNetworkLogFlags = [ ['--host', 'localhost'], ['--host', '127.0.0.1'], - ['--hostname', '127.0.0.1'], ]; noNetworkLogFlags.forEach(([flag, flagValue]) => { it(`astro ${cmd} ${flag} ${flagValue} - no network log`, async () => { diff --git a/packages/astro/test/config-validate.test.js b/packages/astro/test/config-validate.test.js index c543a013c..dadc69582 100644 --- a/packages/astro/test/config-validate.test.js +++ b/packages/astro/test/config-validate.test.js @@ -10,40 +10,32 @@ describe('Config Validation', () => { }); it('Zod errors are returned when invalid config is used', async () => { - const configError = await validateConfig({ buildOptions: { sitemap: 42 } }, process.cwd()).catch((err) => err); + const configError = await validateConfig({ site: 42 }, process.cwd()).catch((err) => err); expect(configError instanceof z.ZodError).to.equal(true); }); - it('errors when an older markdownOptions format is used', async () => { - const configError = await validateConfig({ markdownOptions: { rehypePlugins: ['rehype-autolink-headings'] } }, process.cwd()).catch((err) => err); - expect(configError instanceof z.ZodError).to.equal(true); - expect(configError.issues[0].message).to.equal("Unrecognized key(s) in object: 'rehypePlugins'"); - }); - it('A validation error can be formatted correctly', async () => { - const configError = await validateConfig({ buildOptions: { sitemap: 42 } }, process.cwd()).catch((err) => err); + const configError = await validateConfig({ site: 42 }, process.cwd()).catch((err) => err); expect(configError instanceof z.ZodError).to.equal(true); const formattedError = stripAnsi(formatConfigErrorMessage(configError)); expect(formattedError).to.equal( `[config] Astro found issue(s) with your configuration: - ! buildOptions.sitemap Expected boolean, received number.` + ! site Expected string, received number.` ); }); it('Multiple validation errors can be formatted correctly', async () => { const veryBadConfig = { integrations: [42], - buildOptions: { pageUrlFormat: 'invalid' }, - pages: {}, + build: { format: 'invalid' }, }; const configError = await validateConfig(veryBadConfig, process.cwd()).catch((err) => err); expect(configError instanceof z.ZodError).to.equal(true); const formattedError = stripAnsi(formatConfigErrorMessage(configError)); expect(formattedError).to.equal( `[config] Astro found issue(s) with your configuration: - ! pages Expected string, received object. ! integrations.0 Expected object, received number. - ! buildOptions.pageUrlFormat Invalid input.` + ! build.format Invalid input.` ); }); @@ -69,6 +61,6 @@ describe('Config Validation', () => { expect(configError.message).to.include('Astro integrations are still experimental.'); }); it('allows third-party "integration" values with the --experimental-integrations flag', async () => { - await validateConfig({ integrations: [{ name: '@my-plugin/a' }], experimentalIntegrations: true }, process.cwd()).catch((err) => err); + await validateConfig({ integrations: [{ name: '@my-plugin/a' }], experimental: { integrations: true }}, process.cwd()).catch((err) => err); }); }); diff --git a/packages/astro/test/config.test.js b/packages/astro/test/config.test.js index 80a2668e6..5c78efa0c 100644 --- a/packages/astro/test/config.test.js +++ b/packages/astro/test/config.test.js @@ -1,62 +1,40 @@ import { expect } from 'chai'; -import { cli, loadFixture, cliServerLogSetup } from './test-utils.js'; +import { loadFixture, cliServerLogSetup } from './test-utils.js'; import { fileURLToPath } from 'url'; import { isIPv4 } from 'net'; describe('config', () => { - let hostnameFixture; let hostFixture; let portFixture; before(async () => { - [hostnameFixture, hostFixture, portFixture] = await Promise.all([ + [hostFixture, portFixture] = await Promise.all([ loadFixture({ - projectRoot: './fixtures/config-host/', - devOptions: { - hostname: '0.0.0.0', - }, - }), - loadFixture({ - projectRoot: './fixtures/config-host/', - devOptions: { + root: './fixtures/config-host/', + server: { host: true, }, }), loadFixture({ - projectRoot: './fixtures/config-host/', - devOptions: { + root: './fixtures/config-host/', + server: { port: 5006, }, }), ]); }); - // TODO: remove test once --hostname is baselined - describe('hostname', () => { - it('can be specified in astro.config.mjs', async () => { - expect(hostnameFixture.config.devOptions.hostname).to.equal('0.0.0.0'); - }); - - it('can be specified via --hostname flag', async () => { - const projectRootURL = new URL('./fixtures/astro-basic/', import.meta.url); - const { network } = await cliServerLogSetup(['--project-root', fileURLToPath(projectRootURL), '--hostname', '0.0.0.0']); - - const networkURL = new URL(network); - expect(isIPv4(networkURL.hostname)).to.be.equal(true, `Expected network URL to respect --hostname flag`); - }); - }); - describe('host', () => { it('can be specified in astro.config.mjs', async () => { - expect(hostFixture.config.devOptions.host).to.equal(true); + expect(hostFixture.config.server.host).to.equal(true); }); it('can be specified via --host flag', async () => { const projectRootURL = new URL('./fixtures/astro-basic/', import.meta.url); - const { network } = await cliServerLogSetup(['--project-root', fileURLToPath(projectRootURL), '--host']); + const { network } = await cliServerLogSetup(['--root', fileURLToPath(projectRootURL), '--host']); const networkURL = new URL(network); - expect(isIPv4(networkURL.hostname)).to.be.equal(true, `Expected network URL to respect --hostname flag`); + expect(isIPv4(networkURL.hostname)).to.be.equal(true, `Expected network URL to respect --host flag`); }); }); @@ -64,16 +42,16 @@ describe('config', () => { it('can be passed via --config', async () => { const projectRootURL = new URL('./fixtures/astro-basic/', import.meta.url); const configFileURL = new URL('./fixtures/config-path/config/my-config.mjs', import.meta.url); - const { network } = await cliServerLogSetup(['--project-root', fileURLToPath(projectRootURL), '--config', configFileURL.pathname]); + const { network } = await cliServerLogSetup(['--root', fileURLToPath(projectRootURL), '--config', configFileURL.pathname]); const networkURL = new URL(network); - expect(isIPv4(networkURL.hostname)).to.be.equal(true, `Expected network URL to respect --hostname flag`); + expect(isIPv4(networkURL.hostname)).to.be.equal(true, `Expected network URL to respect --host flag`); }); }); describe('port', () => { it('can be specified in astro.config.mjs', async () => { - expect(portFixture.config.devOptions.port).to.deep.equal(5006); + expect(portFixture.config.server.port).to.deep.equal(5006); }); }); }); diff --git a/packages/astro/test/custom-elements.test.js b/packages/astro/test/custom-elements.test.js index 4224cbc83..a34efca14 100644 --- a/packages/astro/test/custom-elements.test.js +++ b/packages/astro/test/custom-elements.test.js @@ -11,7 +11,7 @@ describe.skip('Custom Elements', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/custom-elements/', + root: './fixtures/custom-elements/', intergrations: ['@test/custom-element-renderer'], }); await fixture.build(); diff --git a/packages/astro/test/debug-component.test.js b/packages/astro/test/debug-component.test.js index 1eae70d1d..ef5e0ad34 100644 --- a/packages/astro/test/debug-component.test.js +++ b/packages/astro/test/debug-component.test.js @@ -14,7 +14,7 @@ describe('<Debug />', () => { let devServer; before(async () => { - fixture = await loadFixture({ projectRoot: './fixtures/debug-component/' }); + fixture = await loadFixture({ root: './fixtures/debug-component/' }); devServer = await fixture.startDevServer(); }); diff --git a/packages/astro/test/dev-routing.test.js b/packages/astro/test/dev-routing.test.js index d411f5de9..7ec6348c4 100644 --- a/packages/astro/test/dev-routing.test.js +++ b/packages/astro/test/dev-routing.test.js @@ -10,7 +10,7 @@ describe('Development Routing', () => { let devServer; before(async () => { - fixture = await loadFixture({ projectRoot: './fixtures/without-site-config/' }); + fixture = await loadFixture({ root: './fixtures/without-site-config/' }); devServer = await fixture.startDevServer(); }); @@ -52,11 +52,9 @@ describe('Development Routing', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/with-subpath-no-trailing-slash/', - dist: './dist-4007', - buildOptions: { - site: 'http://example.com/', - }, + root: './fixtures/with-subpath-no-trailing-slash/', + outDir: './dist-4007', + site: 'http://example.com/', }); devServer = await fixture.startDevServer(); }); @@ -94,11 +92,10 @@ describe('Development Routing', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/with-subpath-no-trailing-slash/', - dist: './dist-4008', - buildOptions: { - site: 'http://example.com/blog/', - }, + root: './fixtures/with-subpath-no-trailing-slash/', + outDir: './dist-4008', + site: 'http://example.com', + base: '/blog', }); devServer = await fixture.startDevServer(); }); @@ -146,8 +143,9 @@ describe('Development Routing', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/with-subpath-no-trailing-slash/', - dist: './dist-4009', + root: './fixtures/with-subpath-no-trailing-slash/', + base: '/blog', + outDir: './dist-4009', }); devServer = await fixture.startDevServer(); }); @@ -195,10 +193,8 @@ describe('Development Routing', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/with-endpoint-routes/', - buildOptions: { - site: 'http://example.com/', - }, + root: './fixtures/with-endpoint-routes/', + site: 'http://example.com/', }); devServer = await fixture.startDevServer(); }); diff --git a/packages/astro/test/errors.test.js b/packages/astro/test/errors.test.js index 7caec0642..85baee002 100644 --- a/packages/astro/test/errors.test.js +++ b/packages/astro/test/errors.test.js @@ -9,7 +9,7 @@ describe('Error display', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/errors', + root: './fixtures/errors', }); }); diff --git a/packages/astro/test/fetch.test.js b/packages/astro/test/fetch.test.js index ba76ce6a6..2fcb7be9f 100644 --- a/packages/astro/test/fetch.test.js +++ b/packages/astro/test/fetch.test.js @@ -6,7 +6,7 @@ describe('Global Fetch', () => { let fixture; before(async () => { - fixture = await loadFixture({ projectRoot: './fixtures/fetch/' }); + fixture = await loadFixture({ root: './fixtures/fetch/' }); await fixture.build(); }); diff --git a/packages/astro/test/fixtures/astro-global/astro.config.mjs b/packages/astro/test/fixtures/astro-global/astro.config.mjs new file mode 100644 index 000000000..d87985387 --- /dev/null +++ b/packages/astro/test/fixtures/astro-global/astro.config.mjs @@ -0,0 +1,4 @@ +export default { + site: 'https://mysite.dev/', + base: '/blog' +} diff --git a/packages/astro/test/fixtures/astro-global/src/pages/posts/[page].astro b/packages/astro/test/fixtures/astro-global/src/pages/posts/[page].astro index 1a21cf475..ee34156db 100644 --- a/packages/astro/test/fixtures/astro-global/src/pages/posts/[page].astro +++ b/packages/astro/test/fixtures/astro-global/src/pages/posts/[page].astro @@ -4,7 +4,7 @@ export async function getStaticPaths({paginate}) { return paginate(data, {pageSize: 1}); } const { page } = Astro.props; -const { params, canonicalURL} = Astro; +const { params, canonicalURL } = Astro; --- <html> diff --git a/packages/astro/test/fixtures/astro-markdown-shiki/langs/astro.config.mjs b/packages/astro/test/fixtures/astro-markdown-shiki/langs/astro.config.mjs index 97198ae94..130596b0c 100644 --- a/packages/astro/test/fixtures/astro-markdown-shiki/langs/astro.config.mjs +++ b/packages/astro/test/fixtures/astro-markdown-shiki/langs/astro.config.mjs @@ -3,25 +3,17 @@ const riGrammar = JSON.parse( ); export default { - markdownOptions: { - render: [ - "@astrojs/markdown-remark", - { - syntaxHighlight: 'shiki', - shikiConfig: { - langs: [ - { - id: 'rinfo', - scopeName: 'source.rinfo', - grammar: riGrammar, - aliases: ['ri'], - }, - ], + markdown: { + syntaxHighlight: 'shiki', + shikiConfig: { + langs: [ + { + id: 'rinfo', + scopeName: 'source.rinfo', + grammar: riGrammar, + aliases: ['ri'], }, - }, - ], - }, - buildOptions: { - sitemap: false, + ], + }, }, } diff --git a/packages/astro/test/fixtures/astro-markdown-shiki/normal/astro.config.mjs b/packages/astro/test/fixtures/astro-markdown-shiki/normal/astro.config.mjs index 8d5aa6f81..acd4c5abc 100644 --- a/packages/astro/test/fixtures/astro-markdown-shiki/normal/astro.config.mjs +++ b/packages/astro/test/fixtures/astro-markdown-shiki/normal/astro.config.mjs @@ -1,8 +1,5 @@ export default { - markdownOptions: { - render: ['@astrojs/markdown-remark', { syntaxHighlight: 'shiki' }], - }, - buildOptions: { - sitemap: false, + markdown: { + syntaxHighlight: 'shiki', }, } diff --git a/packages/astro/test/fixtures/astro-markdown-shiki/themes-custom/astro.config.mjs b/packages/astro/test/fixtures/astro-markdown-shiki/themes-custom/astro.config.mjs index 8f5289d0e..fa208789e 100644 --- a/packages/astro/test/fixtures/astro-markdown-shiki/themes-custom/astro.config.mjs +++ b/packages/astro/test/fixtures/astro-markdown-shiki/themes-custom/astro.config.mjs @@ -3,10 +3,8 @@ const serendipity = JSON.parse( ); export default { - markdownOptions: { - render: ["@astrojs/markdown-remark", { syntaxHighlight: 'shiki', shikiConfig: { theme: serendipity } }], - }, - buildOptions: { - sitemap: false, + markdown: { + syntaxHighlight: 'shiki', + shikiConfig: { theme: serendipity }, }, } diff --git a/packages/astro/test/fixtures/astro-markdown-shiki/themes-integrated/astro.config.mjs b/packages/astro/test/fixtures/astro-markdown-shiki/themes-integrated/astro.config.mjs index 26ce0d008..7ddfeeb16 100644 --- a/packages/astro/test/fixtures/astro-markdown-shiki/themes-integrated/astro.config.mjs +++ b/packages/astro/test/fixtures/astro-markdown-shiki/themes-integrated/astro.config.mjs @@ -1,8 +1,6 @@ export default { - markdownOptions: { - render: ["@astrojs/markdown-remark", { syntaxHighlight: 'shiki', shikiConfig: { theme: 'github-light' } }], - }, - buildOptions: { - sitemap: false, + markdown: { + syntaxHighlight: 'shiki', + shikiConfig: { theme: 'github-light' }, }, } diff --git a/packages/astro/test/fixtures/astro-markdown-shiki/wrap-false/astro.config.mjs b/packages/astro/test/fixtures/astro-markdown-shiki/wrap-false/astro.config.mjs index 2317e36f7..e95742529 100644 --- a/packages/astro/test/fixtures/astro-markdown-shiki/wrap-false/astro.config.mjs +++ b/packages/astro/test/fixtures/astro-markdown-shiki/wrap-false/astro.config.mjs @@ -1,8 +1,6 @@ export default { - markdownOptions: { - render: ['@astrojs/markdown-remark', { syntaxHighlight: 'shiki', shikiConfig: { wrap: false } }], - }, - buildOptions: { - sitemap: false, + markdown: { + syntaxHighlight: 'shiki', + shikiConfig: { wrap: false }, }, } diff --git a/packages/astro/test/fixtures/astro-markdown-shiki/wrap-null/astro.config.mjs b/packages/astro/test/fixtures/astro-markdown-shiki/wrap-null/astro.config.mjs index 12a27dbbe..b1fa06335 100644 --- a/packages/astro/test/fixtures/astro-markdown-shiki/wrap-null/astro.config.mjs +++ b/packages/astro/test/fixtures/astro-markdown-shiki/wrap-null/astro.config.mjs @@ -1,8 +1,6 @@ export default { - markdownOptions: { - render: ['@astrojs/markdown-remark', { syntaxHighlight: 'shiki', shikiConfig: { wrap: null } }], - }, - buildOptions: { - sitemap: false, + markdown: { + syntaxHighlight: 'shiki', + shikiConfig: { wrap: null }, }, } diff --git a/packages/astro/test/fixtures/astro-markdown-shiki/wrap-true/astro.config.mjs b/packages/astro/test/fixtures/astro-markdown-shiki/wrap-true/astro.config.mjs index f1cae49a9..0e95f569b 100644 --- a/packages/astro/test/fixtures/astro-markdown-shiki/wrap-true/astro.config.mjs +++ b/packages/astro/test/fixtures/astro-markdown-shiki/wrap-true/astro.config.mjs @@ -1,8 +1,6 @@ export default { - markdownOptions: { - render: ['@astrojs/markdown-remark', { syntaxHighlight: 'shiki', shikiConfig: { wrap: true } }], - }, - buildOptions: { - sitemap: false, + markdown: { + syntaxHighlight: 'shiki', + shikiConfig: { wrap: true }, }, } diff --git a/packages/astro/test/fixtures/astro-markdown/astro.config.mjs b/packages/astro/test/fixtures/astro-markdown/astro.config.mjs index 680c77bdb..08916b1fe 100644 --- a/packages/astro/test/fixtures/astro-markdown/astro.config.mjs +++ b/packages/astro/test/fixtures/astro-markdown/astro.config.mjs @@ -4,7 +4,4 @@ import preact from '@astrojs/preact'; // https://astro.build/config export default defineConfig({ integrations: [preact()], - buildOptions: { - sitemap: false, - }, }); diff --git a/packages/astro/test/fixtures/config-path/config/my-config.mjs b/packages/astro/test/fixtures/config-path/config/my-config.mjs index c9d45e6c8..eb66c74ca 100644 --- a/packages/astro/test/fixtures/config-path/config/my-config.mjs +++ b/packages/astro/test/fixtures/config-path/config/my-config.mjs @@ -1,5 +1,5 @@ export default { - devOptions: { + server: { host: true, port: 8080, }, diff --git a/packages/astro/test/fixtures/markdown/astro.config.mjs b/packages/astro/test/fixtures/markdown/astro.config.mjs index b4ba9c918..08916b1fe 100644 --- a/packages/astro/test/fixtures/markdown/astro.config.mjs +++ b/packages/astro/test/fixtures/markdown/astro.config.mjs @@ -3,8 +3,5 @@ import preact from '@astrojs/preact'; // https://astro.build/config export default defineConfig({ - buildOptions: { - sitemap: false, - }, integrations: [preact()], -});
\ No newline at end of file +}); diff --git a/packages/astro/test/fixtures/static build/astro.config.mjs b/packages/astro/test/fixtures/static build/astro.config.mjs index 32807d063..cc4fa3ae9 100644 --- a/packages/astro/test/fixtures/static build/astro.config.mjs +++ b/packages/astro/test/fixtures/static build/astro.config.mjs @@ -4,10 +4,9 @@ import preact from '@astrojs/preact'; // https://astro.build/config export default defineConfig({ integrations: [preact()], - buildOptions: { - site: 'http://example.com/subpath/', - }, + site: 'http://example.com', + base: '/subpath', ssr: { noExternal: ['@test/static-build-pkg'], }, -});
\ No newline at end of file +}); diff --git a/packages/astro/test/fixtures/static-build-page-url-format/astro.config.mjs b/packages/astro/test/fixtures/static-build-page-url-format/astro.config.mjs index 7c6e98cc0..55525c455 100644 --- a/packages/astro/test/fixtures/static-build-page-url-format/astro.config.mjs +++ b/packages/astro/test/fixtures/static-build-page-url-format/astro.config.mjs @@ -2,8 +2,9 @@ import { defineConfig } from 'astro/config'; // https://astro.build/config export default defineConfig({ - buildOptions: { - site: 'http://example.com/subpath/', - pageUrlFormat: 'file', + site: 'http://example.com/', + base: '/subpath', + build: { + format: 'file', }, -});
\ No newline at end of file +}); diff --git a/packages/astro/test/fixtures/with-subpath-no-trailing-slash/astro.config.mjs b/packages/astro/test/fixtures/with-subpath-no-trailing-slash/astro.config.mjs index 3ce56e992..227d24574 100644 --- a/packages/astro/test/fixtures/with-subpath-no-trailing-slash/astro.config.mjs +++ b/packages/astro/test/fixtures/with-subpath-no-trailing-slash/astro.config.mjs @@ -1,6 +1,4 @@ export default { - buildOptions: { - site: 'http://example.com/blog' - } + site: 'http://example.com', } diff --git a/packages/astro/test/legacy-build.test.js b/packages/astro/test/legacy-build.test.js deleted file mode 100644 index 20b8dcf9c..000000000 --- a/packages/astro/test/legacy-build.test.js +++ /dev/null @@ -1,22 +0,0 @@ -import { expect } from 'chai'; -import cheerio from 'cheerio'; -import { loadFixture } from './test-utils.js'; - -describe('Legacy Build', () => { - let fixture; - - before(async () => { - fixture = await loadFixture({ - projectRoot: './fixtures/legacy-build/', - }); - await fixture.build({ buildOptions: { legacyBuild: true } }); - }); - - describe('build', () => { - it('is successful', async () => { - const html = await fixture.readFile(`/index.html`); - const $ = cheerio.load(html); - expect($('title').text()).to.equal('Demo app'); - }); - }); -}); diff --git a/packages/astro/test/lit-element.test.js b/packages/astro/test/lit-element.test.js index 65f1a01fb..6c939dbd3 100644 --- a/packages/astro/test/lit-element.test.js +++ b/packages/astro/test/lit-element.test.js @@ -16,7 +16,7 @@ describe('LitElement test', function () { return; } fixture = await loadFixture({ - projectRoot: './fixtures/lit-element/', + root: './fixtures/lit-element/', }); await fixture.build(); }); diff --git a/packages/astro/test/markdown.test.js b/packages/astro/test/markdown.test.js index 5d4fdefda..b8263ce76 100644 --- a/packages/astro/test/markdown.test.js +++ b/packages/astro/test/markdown.test.js @@ -7,7 +7,7 @@ describe('Markdown tests', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/markdown/', + root: './fixtures/markdown/', }); await fixture.build(); }); diff --git a/packages/astro/test/page-level-styles.test.js b/packages/astro/test/page-level-styles.test.js index 6b3fb5dac..3fdce62b9 100644 --- a/packages/astro/test/page-level-styles.test.js +++ b/packages/astro/test/page-level-styles.test.js @@ -8,7 +8,7 @@ describe('Page-level styles', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/page-level-styles/', + root: './fixtures/page-level-styles/', }); await fixture.build(); }); diff --git a/packages/astro/test/postcss.test.js b/packages/astro/test/postcss.test.js index c60cf772f..53c4f7665 100644 --- a/packages/astro/test/postcss.test.js +++ b/packages/astro/test/postcss.test.js @@ -10,7 +10,7 @@ describe('PostCSS', () => { let bundledCSS; before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/postcss', + root: './fixtures/postcss', }); await fixture.build(); diff --git a/packages/astro/test/preact-component.test.js b/packages/astro/test/preact-component.test.js index e6e018068..868f15270 100644 --- a/packages/astro/test/preact-component.test.js +++ b/packages/astro/test/preact-component.test.js @@ -7,7 +7,7 @@ describe('Preact component', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/preact-component/', + root: './fixtures/preact-component/', }); await fixture.build(); }); diff --git a/packages/astro/test/preview-routing.test.js b/packages/astro/test/preview-routing.test.js index 005eeef57..591618126 100644 --- a/packages/astro/test/preview-routing.test.js +++ b/packages/astro/test/preview-routing.test.js @@ -2,7 +2,7 @@ import { expect } from 'chai'; import { loadFixture } from './test-utils.js'; describe('Preview Routing', () => { - describe('pageUrlFormat: directory', () => { + describe('build format: directory', () => { describe('Subpath without trailing slash and trailingSlash: never', () => { /** @type {import('./test-utils').Fixture} */ let fixture; @@ -11,13 +11,14 @@ describe('Preview Routing', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/with-subpath-no-trailing-slash/', - dist: new URL('./fixtures/with-subpath-no-trailing-slash/dist-4000/', import.meta.url), - buildOptions: { - pageUrlFormat: 'directory', + root: './fixtures/with-subpath-no-trailing-slash/', + base: '/blog', + outDir: new URL('./fixtures/with-subpath-no-trailing-slash/dist-4000/', import.meta.url), + build: { + format: 'directory', }, - devOptions: { - trailingSlash: 'never', + trailingSlash: 'never', + server: { port: 4000, }, }); @@ -69,11 +70,11 @@ describe('Preview Routing', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/with-subpath-no-trailing-slash/', - dist: new URL('./fixtures/with-subpath-no-trailing-slash/dist-4001/', import.meta.url), - buildOptions: {}, - devOptions: { - trailingSlash: 'always', + root: './fixtures/with-subpath-no-trailing-slash/', + base: '/blog', + outDir: new URL('./fixtures/with-subpath-no-trailing-slash/dist-4001/', import.meta.url), + trailingSlash: 'always', + server: { port: 4001, }, }); @@ -129,11 +130,11 @@ describe('Preview Routing', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/with-subpath-no-trailing-slash/', - dist: new URL('./fixtures/with-subpath-no-trailing-slash/dist-4002/', import.meta.url), - buildOptions: {}, - devOptions: { - trailingSlash: 'ignore', + root: './fixtures/with-subpath-no-trailing-slash/', + base: '/blog', + outDir: new URL('./fixtures/with-subpath-no-trailing-slash/dist-4002/', import.meta.url), + trailingSlash: 'ignore', + server: { port: 4002, }, }); @@ -182,7 +183,7 @@ describe('Preview Routing', () => { }); }); - describe('pageUrlFormat: file', () => { + describe('build format: file', () => { describe('Subpath without trailing slash and trailingSlash: never', () => { /** @type {import('./test-utils').Fixture} */ let fixture; @@ -191,13 +192,14 @@ describe('Preview Routing', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/with-subpath-no-trailing-slash/', - dist: new URL('./fixtures/with-subpath-no-trailing-slash/dist-4003/', import.meta.url), - buildOptions: { - pageUrlFormat: 'file', + root: './fixtures/with-subpath-no-trailing-slash/', + base: '/blog', + outDir: new URL('./fixtures/with-subpath-no-trailing-slash/dist-4003/', import.meta.url), + build: { + format: 'file', }, - devOptions: { - trailingSlash: 'never', + trailingSlash: 'never', + server: { port: 4003, }, }); @@ -249,13 +251,14 @@ describe('Preview Routing', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/with-subpath-no-trailing-slash/', - dist: new URL('./fixtures/with-subpath-no-trailing-slash/dist-4004/', import.meta.url), - buildOptions: { - pageUrlFormat: 'file', + root: './fixtures/with-subpath-no-trailing-slash/', + base: '/blog', + outDir: new URL('./fixtures/with-subpath-no-trailing-slash/dist-4004/', import.meta.url), + build: { + format: 'file', }, - devOptions: { - trailingSlash: 'always', + trailingSlash: 'always', + server: { port: 4004, }, }); @@ -311,13 +314,14 @@ describe('Preview Routing', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/with-subpath-no-trailing-slash/', - dist: new URL('./fixtures/with-subpath-no-trailing-slash/dist-4005/', import.meta.url), - buildOptions: { - pageUrlFormat: 'file', + root: './fixtures/with-subpath-no-trailing-slash/', + base: '/blog', + outDir: new URL('./fixtures/with-subpath-no-trailing-slash/dist-4005/', import.meta.url), + build: { + format: 'file', }, - devOptions: { - trailingSlash: 'ignore', + trailingSlash: 'ignore', + server: { port: 4005, }, }); @@ -373,13 +377,14 @@ describe('Preview Routing', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/with-subpath-no-trailing-slash/', - dist: new URL('./fixtures/with-subpath-no-trailing-slash/dist-4006/', import.meta.url), - buildOptions: { - pageUrlFormat: 'file', + root: './fixtures/with-subpath-no-trailing-slash/', + base: '/blog', + outDir: new URL('./fixtures/with-subpath-no-trailing-slash/dist-4006/', import.meta.url), + build: { + format: 'file', }, - devOptions: { - trailingSlash: 'ignore', + trailingSlash: 'ignore', + server: { port: 4006, }, }); diff --git a/packages/astro/test/react-component.test.js b/packages/astro/test/react-component.test.js index b1080dc9f..bb67f3df2 100644 --- a/packages/astro/test/react-component.test.js +++ b/packages/astro/test/react-component.test.js @@ -7,7 +7,7 @@ let fixture; describe('React Components', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/react-component/', + root: './fixtures/react-component/', }); }); diff --git a/packages/astro/test/remote-css.test.js b/packages/astro/test/remote-css.test.js index a6f5cdd55..e7cb54090 100644 --- a/packages/astro/test/remote-css.test.js +++ b/packages/astro/test/remote-css.test.js @@ -7,7 +7,7 @@ describe('Remote CSS', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/remote-css/', + root: './fixtures/remote-css/', }); await fixture.build(); }); diff --git a/packages/astro/test/route-manifest.test.js b/packages/astro/test/route-manifest.test.js index 2432b0327..0b4052256 100644 --- a/packages/astro/test/route-manifest.test.js +++ b/packages/astro/test/route-manifest.test.js @@ -1,242 +1,241 @@ -import { expect } from 'chai'; -import { fileURLToPath } from 'url'; -import { createRouteManifest } from '../dist/core/routing/index.js'; - -const cwd = new URL('./fixtures/route-manifest/', import.meta.url); - -const create = (dir, trailingSlash) => { - return createRouteManifest({ - config: { - projectRoot: cwd, - pages: new URL(dir, cwd), - devOptions: { - trailingSlash, - }, - }, - cwd: fileURLToPath(cwd), - }); -}; -function cleanRoutes(routes) { - return routes.map((r) => { - delete r.generate; - return r; - }); -} - -describe('route manifest', () => { - it('creates routes with trailingSlashes = always', () => { - const { routes } = create('basic', 'always'); - expect(cleanRoutes(routes)).to.deep.equal([ - { - type: 'page', - pattern: /^\/$/, - params: [], - component: 'basic/index.astro', - pathname: '/', - }, - - { - type: 'page', - pattern: /^\/about\/$/, - params: [], - component: 'basic/about.astro', - pathname: '/about', - }, - - { - type: 'page', - pattern: /^\/blog\/$/, - params: [], - component: 'basic/blog/index.astro', - pathname: '/blog', - }, - - { - type: 'page', - pattern: /^\/blog\/([^/]+?)\/$/, - params: ['slug'], - component: 'basic/blog/[slug].astro', - pathname: undefined, - }, - ]); - }); - - it('creates routes with trailingSlashes = never', () => { - const { routes } = create('basic', 'never'); - expect(cleanRoutes(routes)).to.deep.equal([ - { - type: 'page', - pattern: /^\/$/, - params: [], - component: 'basic/index.astro', - pathname: '/', - }, - - { - type: 'page', - pattern: /^\/about$/, - params: [], - component: 'basic/about.astro', - pathname: '/about', - }, - - { - type: 'page', - pattern: /^\/blog$/, - params: [], - component: 'basic/blog/index.astro', - pathname: '/blog', - }, - - { - type: 'page', - pattern: /^\/blog\/([^/]+?)$/, - params: ['slug'], - component: 'basic/blog/[slug].astro', - pathname: undefined, - }, - ]); - }); - - it('creates routes with trailingSlashes = ignore', () => { - const { routes } = create('basic', 'ignore'); - expect(cleanRoutes(routes)).to.deep.equal([ - { - type: 'page', - pattern: /^\/$/, - params: [], - component: 'basic/index.astro', - pathname: '/', - }, - - { - type: 'page', - pattern: /^\/about\/?$/, - params: [], - component: 'basic/about.astro', - pathname: '/about', - }, - - { - type: 'page', - pattern: /^\/blog\/?$/, - params: [], - component: 'basic/blog/index.astro', - pathname: '/blog', - }, - - { - type: 'page', - pattern: /^\/blog\/([^/]+?)\/?$/, - params: ['slug'], - component: 'basic/blog/[slug].astro', - pathname: undefined, - }, - ]); - }); - - it('encodes invalid characters', () => { - const { routes } = create('encoding', 'always'); - - // had to remove ? and " because windows - - // const quote = 'encoding/".astro'; - const hash = 'encoding/#.astro'; - // const question_mark = 'encoding/?.astro'; - - expect(routes.map((p) => p.pattern)).to.deep.equal([ - // /^\/%22$/, - /^\/%23\/$/, - // /^\/%3F$/ - ]); - }); - - it('ignores files and directories with leading underscores', () => { - const { routes } = create('hidden-underscore', 'always'); - - expect(routes.map((r) => r.component).filter(Boolean)).to.deep.equal(['hidden-underscore/index.astro', 'hidden-underscore/e/f/g/h.astro']); - }); - - it('ignores files and directories with leading dots except .well-known', () => { - const { routes } = create('hidden-dot', 'always'); - - expect(routes.map((r) => r.component).filter(Boolean)).to.deep.equal(['hidden-dot/.well-known/dnt-policy.astro']); - }); - - it('fails if dynamic params are not separated', () => { - expect(() => create('invalid-params', 'always')).to.throw('Invalid route invalid-params/[foo][bar].astro — parameters must be separated'); - }); - - it('disallows rest parameters inside segments', () => { - expect(() => create('invalid-rest', 'always')).to.throw('Invalid route invalid-rest/foo-[...rest]-bar.astro — rest parameter must be a standalone segment'); - }); - - it('ignores things that look like lockfiles', () => { - const { routes } = create('lockfiles', 'always'); - expect(cleanRoutes(routes)).to.deep.equal([ - { - type: 'page', - pattern: /^\/foo\/$/, - params: [], - component: 'lockfiles/foo.astro', - pathname: '/foo', - }, - ]); - }); - - it('ignores invalid route extensions', () => { - const { routes } = create('invalid-extension', 'always'); - expect(cleanRoutes(routes)).to.deep.equal([ - { - type: 'page', - pattern: /^\/$/, - params: [], - component: 'invalid-extension/index.astro', - pathname: '/', - }, - - { - type: 'page', - pattern: /^\/about\/$/, - params: [], - component: 'invalid-extension/about.astro', - pathname: '/about', - }, - ]); - }); - - it('allows multiple slugs', () => { - const { routes } = create('multiple-slugs', 'always'); - - expect(cleanRoutes(routes)).to.deep.equal([ - { - type: 'page', - pattern: /^\/([^/]+?)\.([^/]+?)\/$/, - component: 'multiple-slugs/[file].[ext].astro', - params: ['file', 'ext'], - pathname: undefined, - }, - ]); - }); - - it('sorts routes correctly', () => { - const { routes } = create('sorting', 'always'); - - expect(routes.map((p) => p.component)).to.deep.equal([ - 'sorting/index.astro', - 'sorting/about.astro', - 'sorting/post/index.astro', - 'sorting/post/bar.astro', - 'sorting/post/foo.astro', - 'sorting/post/f[xx].astro', - 'sorting/post/f[yy].astro', - 'sorting/post/[id].astro', - 'sorting/[wildcard].astro', - 'sorting/[...rest]/deep/[...deep_rest]/xyz.astro', - 'sorting/[...rest]/deep/[...deep_rest]/index.astro', - 'sorting/[...rest]/deep/index.astro', - 'sorting/[...rest]/abc.astro', - 'sorting/[...rest]/index.astro', - ]); - }); -}); +// TODO: unskip this test +// import { expect } from 'chai'; +// import { fileURLToPath } from 'url'; +// import { createRouteManifest } from '../dist/core/routing/index.js'; +// import { validateConfig } from '../dist/core/config.js'; + +// const cwd = new URL('./fixtures/route-manifest/', import.meta.url); + +// const create = async (dir, trailingSlash) => { +// return createRouteManifest({ +// config: await validateConfig({ +// root: cwd.pathname, +// trailingSlash, +// }), +// cwd: fileURLToPath(cwd), +// }); +// }; +// function cleanRoutes(routes) { +// return routes.map((r) => { +// delete r.generate; +// return r; +// }); +// } + +// describe('route manifest', () => { +// it('creates routes with trailingSlashes = always', async () => { +// const { routes } = await create('basic', 'always'); +// expect(cleanRoutes(routes)).to.deep.equal([ +// { +// type: 'page', +// pattern: /^\/$/, +// params: [], +// component: 'basic/index.astro', +// pathname: '/', +// }, + +// { +// type: 'page', +// pattern: /^\/about\/$/, +// params: [], +// component: 'basic/about.astro', +// pathname: '/about', +// }, + +// { +// type: 'page', +// pattern: /^\/blog\/$/, +// params: [], +// component: 'basic/blog/index.astro', +// pathname: '/blog', +// }, + +// { +// type: 'page', +// pattern: /^\/blog\/([^/]+?)\/$/, +// params: ['slug'], +// component: 'basic/blog/[slug].astro', +// pathname: undefined, +// }, +// ]); +// }); + +// it('creates routes with trailingSlashes = never', async () => { +// const { routes } = await create('basic', 'never'); +// expect(cleanRoutes(routes)).to.deep.equal([ +// { +// type: 'page', +// pattern: /^\/$/, +// params: [], +// component: 'basic/index.astro', +// pathname: '/', +// }, + +// { +// type: 'page', +// pattern: /^\/about$/, +// params: [], +// component: 'basic/about.astro', +// pathname: '/about', +// }, + +// { +// type: 'page', +// pattern: /^\/blog$/, +// params: [], +// component: 'basic/blog/index.astro', +// pathname: '/blog', +// }, + +// { +// type: 'page', +// pattern: /^\/blog\/([^/]+?)$/, +// params: ['slug'], +// component: 'basic/blog/[slug].astro', +// pathname: undefined, +// }, +// ]); +// }); + +// it('creates routes with trailingSlashes = ignore', async () => { +// const { routes } = await create('basic', 'ignore'); +// expect(cleanRoutes(routes)).to.deep.equal([ +// { +// type: 'page', +// pattern: /^\/$/, +// params: [], +// component: 'basic/index.astro', +// pathname: '/', +// }, + +// { +// type: 'page', +// pattern: /^\/about\/?$/, +// params: [], +// component: 'basic/about.astro', +// pathname: '/about', +// }, + +// { +// type: 'page', +// pattern: /^\/blog\/?$/, +// params: [], +// component: 'basic/blog/index.astro', +// pathname: '/blog', +// }, + +// { +// type: 'page', +// pattern: /^\/blog\/([^/]+?)\/?$/, +// params: ['slug'], +// component: 'basic/blog/[slug].astro', +// pathname: undefined, +// }, +// ]); +// }); + +// it('encodes invalid characters', async () => { +// const { routes } = await create('encoding', 'always'); + +// // had to remove ? and " because windows + +// // const quote = 'encoding/".astro'; +// const hash = 'encoding/#.astro'; +// // const question_mark = 'encoding/?.astro'; + +// expect(routes.map((p) => p.pattern)).to.deep.equal([ +// // /^\/%22$/, +// /^\/%23\/$/, +// // /^\/%3F$/ +// ]); +// }); + +// it('ignores files and directories with leading underscores', async () => { +// const { routes } = await create('hidden-underscore', 'always'); + +// expect(routes.map((r) => r.component).filter(Boolean)).to.deep.equal(['hidden-underscore/index.astro', 'hidden-underscore/e/f/g/h.astro']); +// }); + +// it('ignores files and directories with leading dots except .well-known', async () => { +// const { routes } = await create('hidden-dot', 'always'); + +// expect(routes.map((r) => r.component).filter(Boolean)).to.deep.equal(['hidden-dot/.well-known/dnt-policy.astro']); +// }); + +// it('fails if dynamic params are not separated', async () => { +// expect(() => await create('invalid-params', 'always')).to.throw('Invalid route invalid-params/[foo][bar].astro — parameters must be separated'); +// }); + +// it('disallows rest parameters inside segments', async () => { +// expect(() => await create('invalid-rest', 'always')).to.throw('Invalid route invalid-rest/foo-[...rest]-bar.astro — rest parameter must be a standalone segment'); +// }); + +// it('ignores things that look like lockfiles', async () => { +// const { routes } = await create('lockfiles', 'always'); +// expect(cleanRoutes(routes)).to.deep.equal([ +// { +// type: 'page', +// pattern: /^\/foo\/$/, +// params: [], +// component: 'lockfiles/foo.astro', +// pathname: '/foo', +// }, +// ]); +// }); + +// it('ignores invalid route extensions', async () => { +// const { routes } = await create('invalid-extension', 'always'); +// expect(cleanRoutes(routes)).to.deep.equal([ +// { +// type: 'page', +// pattern: /^\/$/, +// params: [], +// component: 'invalid-extension/index.astro', +// pathname: '/', +// }, + +// { +// type: 'page', +// pattern: /^\/about\/$/, +// params: [], +// component: 'invalid-extension/about.astro', +// pathname: '/about', +// }, +// ]); +// }); + +// it('allows multiple slugs', async () => { +// const { routes } = await create('multiple-slugs', 'always'); + +// expect(cleanRoutes(routes)).to.deep.equal([ +// { +// type: 'page', +// pattern: /^\/([^/]+?)\.([^/]+?)\/$/, +// component: 'multiple-slugs/[file].[ext].astro', +// params: ['file', 'ext'], +// pathname: undefined, +// }, +// ]); +// }); + +// it('sorts routes correctly', async () => { +// const { routes } = await create('sorting', 'always'); + +// expect(routes.map((p) => p.component)).to.deep.equal([ +// 'sorting/index.astro', +// 'sorting/about.astro', +// 'sorting/post/index.astro', +// 'sorting/post/bar.astro', +// 'sorting/post/foo.astro', +// 'sorting/post/f[xx].astro', +// 'sorting/post/f[yy].astro', +// 'sorting/post/[id].astro', +// 'sorting/[wildcard].astro', +// 'sorting/[...rest]/deep/[...deep_rest]/xyz.astro', +// 'sorting/[...rest]/deep/[...deep_rest]/index.astro', +// 'sorting/[...rest]/deep/index.astro', +// 'sorting/[...rest]/abc.astro', +// 'sorting/[...rest]/index.astro', +// ]); +// }); +// }); diff --git a/packages/astro/test/sass.test.js b/packages/astro/test/sass.test.js index e62092e42..4072d5547 100644 --- a/packages/astro/test/sass.test.js +++ b/packages/astro/test/sass.test.js @@ -9,7 +9,7 @@ describe('Sass', () => { let devServer; before(async () => { - fixture = await loadFixture({ projectRoot: './fixtures/sass/' }); + fixture = await loadFixture({ root: './fixtures/sass/' }); devServer = await fixture.startDevServer(); }); diff --git a/packages/astro/test/slots-preact.test.js b/packages/astro/test/slots-preact.test.js index 3419dfda6..380979f04 100644 --- a/packages/astro/test/slots-preact.test.js +++ b/packages/astro/test/slots-preact.test.js @@ -6,7 +6,7 @@ describe('Slots: Preact', () => { let fixture; before(async () => { - fixture = await loadFixture({ projectRoot: './fixtures/slots-preact/' }); + fixture = await loadFixture({ root: './fixtures/slots-preact/' }); await fixture.build(); }); diff --git a/packages/astro/test/slots-react.test.js b/packages/astro/test/slots-react.test.js index 1c721c6e2..3cca8ae05 100644 --- a/packages/astro/test/slots-react.test.js +++ b/packages/astro/test/slots-react.test.js @@ -6,7 +6,7 @@ describe('Slots: React', () => { let fixture; before(async () => { - fixture = await loadFixture({ projectRoot: './fixtures/slots-react/' }); + fixture = await loadFixture({ root: './fixtures/slots-react/' }); await fixture.build(); }); diff --git a/packages/astro/test/slots-solid.test.js b/packages/astro/test/slots-solid.test.js index 2b45dd5d9..cf59ada41 100644 --- a/packages/astro/test/slots-solid.test.js +++ b/packages/astro/test/slots-solid.test.js @@ -6,7 +6,7 @@ describe('Slots: Solid', () => { let fixture; before(async () => { - fixture = await loadFixture({ projectRoot: './fixtures/slots-solid/' }); + fixture = await loadFixture({ root: './fixtures/slots-solid/' }); await fixture.build(); }); diff --git a/packages/astro/test/slots-svelte.test.js b/packages/astro/test/slots-svelte.test.js index 3a267ccb1..3c5b5d7fa 100644 --- a/packages/astro/test/slots-svelte.test.js +++ b/packages/astro/test/slots-svelte.test.js @@ -6,7 +6,7 @@ describe('Slots: Svelte', () => { let fixture; before(async () => { - fixture = await loadFixture({ projectRoot: './fixtures/slots-svelte/' }); + fixture = await loadFixture({ root: './fixtures/slots-svelte/' }); await fixture.build(); }); diff --git a/packages/astro/test/slots-vue.test.js b/packages/astro/test/slots-vue.test.js index c598d346b..9cd8ac6eb 100644 --- a/packages/astro/test/slots-vue.test.js +++ b/packages/astro/test/slots-vue.test.js @@ -6,7 +6,7 @@ describe('Slots: Vue', () => { let fixture; before(async () => { - fixture = await loadFixture({ projectRoot: './fixtures/slots-vue/' }); + fixture = await loadFixture({ root: './fixtures/slots-vue/' }); await fixture.build(); }); diff --git a/packages/astro/test/solid-component.test.js b/packages/astro/test/solid-component.test.js index 07e01fba0..f870468f2 100644 --- a/packages/astro/test/solid-component.test.js +++ b/packages/astro/test/solid-component.test.js @@ -7,7 +7,7 @@ describe('Solid component', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/solid-component/', + root: './fixtures/solid-component/', }); }); diff --git a/packages/astro/test/ssr-adapter-build-config.test.js b/packages/astro/test/ssr-adapter-build-config.test.js index bda7752ff..427049532 100644 --- a/packages/astro/test/ssr-adapter-build-config.test.js +++ b/packages/astro/test/ssr-adapter-build-config.test.js @@ -11,9 +11,9 @@ describe('Integration buildConfig hook', () => { before(async () => { let _config; fixture = await loadFixture({ - projectRoot: './fixtures/ssr-request/', - buildOptions: { - experimentalSsr: true, + root: './fixtures/ssr-request/', + experimental: { + ssr: true, }, adapter: { name: 'my-ssr-adapter', @@ -42,8 +42,8 @@ describe('Integration buildConfig hook', () => { }); }, 'astro:build:start': ({ buildConfig }) => { - buildConfig.server = new URL('./dist/.root/server/', _config.projectRoot); - buildConfig.client = new URL('./dist/.root/client/', _config.projectRoot); + buildConfig.server = new URL('./dist/.root/server/', _config.root); + buildConfig.client = new URL('./dist/.root/client/', _config.root); }, 'astro:config:done': ({ config, setAdapter }) => { _config = config; diff --git a/packages/astro/test/ssr-api-route.test.js b/packages/astro/test/ssr-api-route.test.js index 5ed37f0c5..666fd217d 100644 --- a/packages/astro/test/ssr-api-route.test.js +++ b/packages/astro/test/ssr-api-route.test.js @@ -9,8 +9,10 @@ describe('API routes in SSR', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/ssr-api-route/', - buildOptions: { experimentalSsr: true }, + root: './fixtures/ssr-api-route/', + experimental: { + ssr: true, + }, adapter: testAdapter(), }); await fixture.build(); diff --git a/packages/astro/test/ssr-dynamic.test.js b/packages/astro/test/ssr-dynamic.test.js index 98d73b98e..01ff3d2be 100644 --- a/packages/astro/test/ssr-dynamic.test.js +++ b/packages/astro/test/ssr-dynamic.test.js @@ -10,8 +10,10 @@ describe('Dynamic pages in SSR', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/ssr-dynamic/', - buildOptions: { experimentalSsr: true }, + root: './fixtures/ssr-dynamic/', + experimental: { + ssr: true, + }, adapter: testAdapter(), }); await fixture.build(); diff --git a/packages/astro/test/ssr-request.test.js b/packages/astro/test/ssr-request.test.js index 04a00a195..29e6ea50e 100644 --- a/packages/astro/test/ssr-request.test.js +++ b/packages/astro/test/ssr-request.test.js @@ -10,11 +10,11 @@ describe('Using Astro.request in SSR', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/ssr-request/', - buildOptions: { - experimentalSsr: true, - }, + root: './fixtures/ssr-request/', adapter: testAdapter(), + experimental: { + ssr: true + } }); await fixture.build(); }); diff --git a/packages/astro/test/static-build-code-component.test.js b/packages/astro/test/static-build-code-component.test.js index ec5e33945..f6a7d205d 100644 --- a/packages/astro/test/static-build-code-component.test.js +++ b/packages/astro/test/static-build-code-component.test.js @@ -7,7 +7,7 @@ describe('Code component inside static build', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/static-build-code-component/', + root: './fixtures/static-build-code-component/', }); await fixture.build(); }); diff --git a/packages/astro/test/static-build-frameworks.test.js b/packages/astro/test/static-build-frameworks.test.js index 9b6d50028..8bb2e116a 100644 --- a/packages/astro/test/static-build-frameworks.test.js +++ b/packages/astro/test/static-build-frameworks.test.js @@ -11,7 +11,7 @@ describe('Static build - frameworks', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/static-build-frameworks/', + root: './fixtures/static-build-frameworks/', }); await fixture.build(); }); diff --git a/packages/astro/test/static-build-page-url-format.test.js b/packages/astro/test/static-build-page-url-format.test.js index 4a21419cc..941a7e571 100644 --- a/packages/astro/test/static-build-page-url-format.test.js +++ b/packages/astro/test/static-build-page-url-format.test.js @@ -6,12 +6,12 @@ function addLeadingSlash(path) { return path.startsWith('/') ? path : '/' + path; } -describe("Static build - pageUrlFormat: 'file'", () => { +describe("Static build - format: 'file'", () => { let fixture; before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/static-build-page-url-format/', + root: './fixtures/static-build-page-url-format/', }); await fixture.build(); }); diff --git a/packages/astro/test/static-build.test.js b/packages/astro/test/static-build.test.js index 47707ea27..55ce6ca07 100644 --- a/packages/astro/test/static-build.test.js +++ b/packages/astro/test/static-build.test.js @@ -11,7 +11,7 @@ describe('Static build', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/static build/', + root: './fixtures/static build/', }); await fixture.build(); }); @@ -72,7 +72,7 @@ describe('Static build', () => { const $ = cheerioLoad(html); const links = $('link[rel=stylesheet]'); for (const link of links) { - const href = $(link).attr('href').slice('/subpath'.length); + const href = $(link).attr('href'); const data = await fixture.readFile(addLeadingSlash(href)); if (expected.test(data)) { return true; diff --git a/packages/astro/test/status-page.test.js b/packages/astro/test/status-page.test.js index 5cce71f48..06b2d0ae8 100644 --- a/packages/astro/test/status-page.test.js +++ b/packages/astro/test/status-page.test.js @@ -7,7 +7,7 @@ describe('Status Code Pages', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/status-code/', + root: './fixtures/status-code/', }); await fixture.build(); }); diff --git a/packages/astro/test/svelte-component.test.js b/packages/astro/test/svelte-component.test.js index c088bf9b5..36ba35b51 100644 --- a/packages/astro/test/svelte-component.test.js +++ b/packages/astro/test/svelte-component.test.js @@ -7,7 +7,7 @@ describe('Svelte component', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/svelte-component/', + root: './fixtures/svelte-component/', }); }); diff --git a/packages/astro/test/tailwindcss.test.js b/packages/astro/test/tailwindcss.test.js index 957b3f1a2..e4c0bb55b 100644 --- a/packages/astro/test/tailwindcss.test.js +++ b/packages/astro/test/tailwindcss.test.js @@ -9,7 +9,7 @@ describe('Tailwind', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/tailwindcss/', + root: './fixtures/tailwindcss/', }); }); diff --git a/packages/astro/test/test-utils.js b/packages/astro/test/test-utils.js index 56c18580b..4e0295da4 100644 --- a/packages/astro/test/test-utils.js +++ b/packages/astro/test/test-utils.js @@ -36,7 +36,7 @@ polyfill(globalThis, { /** * Load Astro fixture - * @param {AstroConfig} inlineConfig Astro config partial (note: must specify projectRoot) + * @param {AstroConfig} inlineConfig Astro config partial (note: must specify `root`) * @returns {Promise<Fixture>} The fixture. Has the following properties: * .config - Returns the final config. Will be automatically passed to the methods below: * @@ -55,11 +55,11 @@ polyfill(globalThis, { * .clean() - Async. Removes the project’s dist folder. */ export async function loadFixture(inlineConfig) { - if (!inlineConfig || !inlineConfig.projectRoot) throw new Error("Must provide { projectRoot: './fixtures/...' }"); + if (!inlineConfig || !inlineConfig.root) throw new Error("Must provide { root: './fixtures/...' }"); // load config - let cwd = inlineConfig.projectRoot; - delete inlineConfig.projectRoot; + let cwd = inlineConfig.root; + delete inlineConfig.root; if (typeof cwd === 'string') { try { cwd = new URL(cwd.replace(/\/?$/, '/')); @@ -69,7 +69,15 @@ export async function loadFixture(inlineConfig) { } // Load the config. let config = await loadConfig({ cwd: fileURLToPath(cwd) }); - config = merge(config, { ...inlineConfig, projectRoot: cwd }); + config = merge(config, { ...inlineConfig, root: cwd }); + + // Note: the inline config doesn't run through config validation where these normalizations usually occur + if (typeof inlineConfig.site === 'string') { + config.site = new URL(inlineConfig.site); + } + if (inlineConfig.base && !inlineConfig.base.endsWith('/')) { + config.base = inlineConfig.base + '/'; + } /** @type {import('../src/core/logger/core').LogOptions} */ const logging = { @@ -81,20 +89,20 @@ export async function loadFixture(inlineConfig) { build: (opts = {}) => build(config, { mode: 'development', logging, ...opts }), startDevServer: async (opts = {}) => { const devResult = await dev(config, { logging, ...opts }); - config.devOptions.port = devResult.address.port; // update port + config.server.port = devResult.address.port; // update port return devResult; }, config, - fetch: (url, init) => fetch(`http://${'127.0.0.1'}:${config.devOptions.port}${url.replace(/^\/?/, '/')}`, init), + fetch: (url, init) => fetch(`http://${'127.0.0.1'}:${config.server.port}${url.replace(/^\/?/, '/')}`, init), preview: async (opts = {}) => { const previewServer = await preview(config, { logging, ...opts }); return previewServer; }, - readFile: (filePath) => fs.promises.readFile(new URL(filePath.replace(/^\//, ''), config.dist), 'utf8'), - readdir: (fp) => fs.promises.readdir(new URL(fp.replace(/^\//, ''), config.dist)), - clean: () => fs.promises.rm(config.dist, { maxRetries: 10, recursive: true, force: true }), + readFile: (filePath) => fs.promises.readFile(new URL(filePath.replace(/^\//, ''), config.outDir), 'utf8'), + readdir: (fp) => fs.promises.readdir(new URL(fp.replace(/^\//, ''), config.outDir)), + clean: () => fs.promises.rm(config.outDir, { maxRetries: 10, recursive: true, force: true }), loadTestAdapterApp: async () => { - const url = new URL('./server/entry.mjs', config.dist); + const url = new URL('./server/entry.mjs', config.outDir); const { createApp } = await import(url); return createApp(); }, diff --git a/packages/astro/test/vue-component.test.js b/packages/astro/test/vue-component.test.js index b15f6a759..e26a3cdbe 100644 --- a/packages/astro/test/vue-component.test.js +++ b/packages/astro/test/vue-component.test.js @@ -7,7 +7,7 @@ describe('Vue component', () => { before(async () => { fixture = await loadFixture({ - projectRoot: './fixtures/vue-component/', + root: './fixtures/vue-component/', }); }); diff --git a/packages/integrations/deno/test/fixtures/basics/astro.config.mjs b/packages/integrations/deno/test/fixtures/basics/astro.config.mjs index 38490926b..e56fe2e98 100644 --- a/packages/integrations/deno/test/fixtures/basics/astro.config.mjs +++ b/packages/integrations/deno/test/fixtures/basics/astro.config.mjs @@ -3,5 +3,7 @@ import deno from '@astrojs/deno'; export default defineConfig({ adapter: deno(), - buildOptions: { experimentalSsr: true } + experimental: { + ssr: true + } }) diff --git a/packages/integrations/netlify/src/index.ts b/packages/integrations/netlify/src/index.ts index 5d54f7db6..e7fb72633 100644 --- a/packages/integrations/netlify/src/index.ts +++ b/packages/integrations/netlify/src/index.ts @@ -22,19 +22,19 @@ function netlifyFunctions({ dist }: NetlifyFunctionsOptions = {}): AstroIntegrat hooks: { 'astro:config:setup': ({ config }) => { if (dist) { - config.dist = dist; + config.outDir = dist; } else { - config.dist = new URL('./netlify/', config.projectRoot); + config.outDir = new URL('./netlify/', config.root); } }, 'astro:config:done': ({ config, setAdapter }) => { - setAdapter(getAdapter(config.buildOptions.site)); + setAdapter(getAdapter(new URL(config.base, config.site).toString())); _config = config; }, 'astro:build:start': async ({ buildConfig }) => { entryFile = buildConfig.serverEntry.replace(/\.m?js/, ''); - buildConfig.client = _config.dist; - buildConfig.server = new URL('./functions/', _config.dist); + buildConfig.client = _config.outDir; + buildConfig.server = new URL('./functions/', _config.outDir); }, 'astro:build:done': async ({ routes, dir }) => { const _redirectsURL = new URL('./_redirects', dir); diff --git a/packages/integrations/partytown/src/index.ts b/packages/integrations/partytown/src/index.ts index 479f86b07..bddbeae62 100644 --- a/packages/integrations/partytown/src/index.ts +++ b/packages/integrations/partytown/src/index.ts @@ -26,7 +26,7 @@ export default function createPlugin(): AstroIntegration { server.middlewares.use(sirv(partytownLibDirectory, { mount: '/~partytown', dev: true, etag: true, extensions: [] })); }, 'astro:build:done': async () => { - await copyLibFiles(fileURLToPath(new URL('~partytown', config.dist)), { debugDir: false }); + await copyLibFiles(fileURLToPath(new URL('~partytown', config.outDir)), { debugDir: false }); }, }, }; diff --git a/packages/integrations/sitemap/README.md b/packages/integrations/sitemap/README.md index 02fa02597..9d84cae19 100644 --- a/packages/integrations/sitemap/README.md +++ b/packages/integrations/sitemap/README.md @@ -50,7 +50,7 @@ export default { ## Getting started -`@astrojs/sitemap` requires a deployment / site URL for generation. Add your site's URL under your `astro.config.*` using the `buildOptions.site` property: +`@astrojs/sitemap` requires a deployment / site URL for generation. Add your site's URL under your `astro.config.*` using the `site` property: __astro.config.mjs__ @@ -59,9 +59,7 @@ import sitemap from '@astrojs/sitemap'; export default { // ... - buildOptions: { - site: 'https://stargazers.club', - }, + site: 'https://stargazers.club', integrations: [sitemap()], } ``` @@ -70,5 +68,48 @@ Now, [build your site for production](https://docs.astro.build/en/reference/cli- You can also check our [Astro Integration Documentation][astro-integration] for more on integrations. +## Configuration + +### filter + +All pages are included in your sitemap by default. By adding a custom `filter`, you can filter included pages by URL. + +__astro.config.mjs__ + +```js +import sitemap from '@astrojs/sitemap'; + +export default { + site: 'https://stargazers.club', + integrations: [ + sitemap({ + filter: (page) => page !== 'https://stargazers.club/secret-vip-lounge' + }), + ], +} +``` + +The `page` function parameter is the full URL of your rendered page, including your `site` domain. Return `true` to include a page in your sitemap, and `false` to remove it. + +### canonicalURL + +If present, we use the `site` config option as the base for all sitemap URLs. Use `canonicalURL` to override this. + +__astro.config.mjs__ + +```js +import sitemap from '@astrojs/sitemap'; + +export default { + site: 'https://stargazers.club', + integrations: [ + sitemap({ + // https://astronaut.party will be used for all sitemap URLs instead + canonicalURL: 'https://astronaut.party', + }), + ], +} +``` + [astro-integration]: https://docs.astro.build/en/guides/integrations-guide/ [astro-ui-frameworks]: https://docs.astro.build/en/core-concepts/framework-components/#using-framework-components diff --git a/packages/integrations/sitemap/src/index.ts b/packages/integrations/sitemap/src/index.ts index 28bc61396..ef1538ce6 100644 --- a/packages/integrations/sitemap/src/index.ts +++ b/packages/integrations/sitemap/src/index.ts @@ -2,10 +2,32 @@ import fs from 'node:fs'; import type { AstroConfig, AstroIntegration } from 'astro'; const STATUS_CODE_PAGE_REGEXP = /\/[0-9]{3}\/?$/; +type SitemapOptions = + | { + /** + * All pages are included in your sitemap by default. + * With this config option, you can filter included pages by URL. + * + * The `page` function parameter is the full URL of your rendered page, including your `site` domain. + * Return `true` to include a page in your sitemap, and `false` to remove it. + * + * ```js + * filter: (page) => page !== 'http://example.com/secret-page' + * ``` + */ + filter?(page: string): string; + + /** + * If present, we use the `site` config option as the base for all sitemap URLs + * Use `canonicalURL` to override this + */ + canonicalURL?: string; + } + | undefined; + /** Construct sitemap.xml given a set of URLs */ function generateSitemap(pages: string[]) { // TODO: find way to respect <link rel="canonical"> URLs here - // TODO: find way to exclude pages from sitemap const urls = [...pages].filter((url) => !STATUS_CODE_PAGE_REGEXP.test(url)); urls.sort((a, b) => a.localeCompare(b, 'en', { numeric: true })); // sort alphabetically so sitemap is same each time let sitemap = `<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">`; @@ -16,7 +38,7 @@ function generateSitemap(pages: string[]) { return sitemap; } -export default function createPlugin(): AstroIntegration { +export default function createPlugin({ filter, canonicalURL }: SitemapOptions = {}): AstroIntegration { let config: AstroConfig; return { name: '@astrojs/sitemap', @@ -25,11 +47,15 @@ export default function createPlugin(): AstroIntegration { config = _config; }, 'astro:build:done': async ({ pages, dir }) => { - const finalSiteUrl = config.buildOptions.site; + const finalSiteUrl = canonicalURL || config.site; if (!finalSiteUrl) { + console.warn('The Sitemap integration requires either the `site` astro.config option or `canonicalURL` integration option. Skipping.'); return; } - const pageUrls = pages.map((p) => new URL(p.pathname, finalSiteUrl).href); + let pageUrls = pages.map((p) => new URL(p.pathname, finalSiteUrl).href); + if (filter) { + pageUrls = pageUrls.filter((page: string) => filter(page)); + } const sitemapContent = generateSitemap(pageUrls); fs.writeFileSync(new URL('sitemap.xml', dir), sitemapContent); }, diff --git a/packages/integrations/tailwind/src/index.ts b/packages/integrations/tailwind/src/index.ts index 3bdd65011..2f469b507 100644 --- a/packages/integrations/tailwind/src/index.ts +++ b/packages/integrations/tailwind/src/index.ts @@ -17,16 +17,16 @@ function getDefaultTailwindConfig(srcUrl: URL): TailwindConfig { }); } -async function getUserConfig(projectRoot: URL, configPath?: string) { - const resolvedProjectRoot = fileURLToPath(projectRoot); +async function getUserConfig(root: URL, configPath?: string) { + const resolvedRoot = fileURLToPath(root); let userConfigPath: string | undefined; if (configPath) { const configPathWithLeadingSlash = /^\.*\//.test(configPath) ? configPath : `./${configPath}`; - userConfigPath = fileURLToPath(new URL(configPathWithLeadingSlash, projectRoot)); + userConfigPath = fileURLToPath(new URL(configPathWithLeadingSlash, root)); } - return await load('tailwind', { mustExist: false, cwd: resolvedProjectRoot, filePath: userConfigPath }); + return await load('tailwind', { mustExist: false, cwd: resolvedRoot, filePath: userConfigPath }); } type TailwindOptions = @@ -64,21 +64,21 @@ export default function tailwindIntegration(options: TailwindOptions): AstroInte hooks: { 'astro:config:setup': async ({ config, injectScript }) => { // Inject the Tailwind postcss plugin - const userConfig = await getUserConfig(config.projectRoot, customConfigPath); + const userConfig = await getUserConfig(config.root, customConfigPath); if (customConfigPath && !userConfig?.value) { throw new Error(`Could not find a Tailwind config at ${JSON.stringify(customConfigPath)}. Does the file exist?`); } - const tailwindConfig: TailwindConfig = (userConfig?.value as TailwindConfig) ?? getDefaultTailwindConfig(config.src); + const tailwindConfig: TailwindConfig = (userConfig?.value as TailwindConfig) ?? getDefaultTailwindConfig(config.srcDir); if (applyAstroConfigPreset && userConfig?.value) { // apply Astro config as a preset to user config // this avoids merging or applying nested spread operators ourselves - tailwindConfig.presets = [getDefaultTailwindConfig(config.src), ...(tailwindConfig.presets || [])]; + tailwindConfig.presets = [getDefaultTailwindConfig(config.srcDir), ...(tailwindConfig.presets || [])]; } - config.styleOptions.postcss.plugins.push(tailwindPlugin(tailwindConfig)); - config.styleOptions.postcss.plugins.push(autoprefixerPlugin); + config.style.postcss.plugins.push(tailwindPlugin(tailwindConfig)); + config.style.postcss.plugins.push(autoprefixerPlugin); if (applyBaseStyles) { // Inject the Tailwind base import diff --git a/packages/markdown/remark/src/index.ts b/packages/markdown/remark/src/index.ts index 3ea436795..0fb398bc7 100644 --- a/packages/markdown/remark/src/index.ts +++ b/packages/markdown/remark/src/index.ts @@ -1,4 +1,4 @@ -import type { AstroMarkdownOptions, MarkdownRenderingOptions } from './types'; +import type { AstroMarkdownOptions, MarkdownRenderingOptions, ShikiConfig, Plugin } from './types'; import createCollectHeaders from './rehype-collect-headers.js'; import scopedStyles from './remark-scoped-styles.js'; @@ -20,7 +20,7 @@ import rehypeStringify from 'rehype-stringify'; import rehypeRaw from 'rehype-raw'; import matter from 'gray-matter'; -export { AstroMarkdownOptions, MarkdownRenderingOptions }; +export { AstroMarkdownOptions, MarkdownRenderingOptions, ShikiConfig, Plugin }; /** Internal utility for rendering a full markdown file and extracting Frontmatter data */ export async function renderMarkdownWithFrontmatter(contents: string, opts?: MarkdownRenderingOptions | null) { diff --git a/packages/markdown/remark/src/types.ts b/packages/markdown/remark/src/types.ts index eb0eb5d3e..43e8331b4 100644 --- a/packages/markdown/remark/src/types.ts +++ b/packages/markdown/remark/src/types.ts @@ -1,5 +1,6 @@ import type * as unified from 'unified'; import type { ShikiConfig } from './remark-shiki'; +export { ShikiConfig }; export type Plugin = string | [string, any] | unified.Plugin | [unified.Plugin, any]; diff --git a/scripts/memory/index.js b/scripts/memory/index.js index 969b1bb17..a1e34e144 100644 --- a/scripts/memory/index.js +++ b/scripts/memory/index.js @@ -18,8 +18,6 @@ let config = await loadConfig({ cwd: fileURLToPath(projDir), }); -config.buildOptions.legacyBuild = false; - const server = await dev(config, { logging: { level: 'error' } }); // Prime the server so initial memory is created |