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>
This commit is contained in:
parent
76f6643ddd
commit
17c02925c5
137 changed files with 1191 additions and 1343 deletions
7
.changeset/tall-cooks-begin.md
Normal file
7
.changeset/tall-cooks-begin.md
Normal file
|
@ -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
|
11
.changeset/wicked-toes-flow.md
Normal file
11
.changeset/wicked-toes-flow.md
Normal file
|
@ -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)
|
|
@ -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());
|
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.
|
// 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({
|
// rss({
|
||||||
// title: 'Don’s Blog',
|
// title: 'Don’s Blog',
|
||||||
// description: 'An example blog on Astro',
|
// description: 'An example blog on Astro',
|
||||||
|
|
|
@ -4,7 +4,6 @@ import preact from '@astrojs/preact';
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
integrations: [preact()],
|
integrations: [preact()],
|
||||||
buildOptions: {
|
site: 'https://example.com',
|
||||||
site: 'https://example.com/',
|
base: '/subpath',
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "astro --project-root demo dev",
|
"start": "astro --root demo dev",
|
||||||
"build": "astro --project-root demo build",
|
"build": "astro --root demo build",
|
||||||
"serve": "astro --project-root demo preview"
|
"serve": "astro --root demo preview"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"astro": "^0.25.4"
|
"astro": "^0.25.4"
|
||||||
|
|
|
@ -4,7 +4,5 @@ import react from '@astrojs/react';
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
integrations: [react()],
|
integrations: [react()],
|
||||||
buildOptions: {
|
site: 'http://example.com/blog',
|
||||||
site: 'http://example.com/blog',
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,17 +1,11 @@
|
||||||
import { defineConfig } from 'astro/config';
|
import { defineConfig } from 'astro/config';
|
||||||
import astroRemark from '@astrojs/markdown-remark';
|
|
||||||
import addClasses from './add-classes.mjs';
|
import addClasses from './add-classes.mjs';
|
||||||
|
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
// Enable Custom Markdown options, plugins, etc.
|
// Enable Custom Markdown options, plugins, etc.
|
||||||
markdownOptions: {
|
markdown: {
|
||||||
render: [
|
remarkPlugins: ['remark-code-titles'],
|
||||||
astroRemark,
|
rehypePlugins: [['rehype-autolink-headings', { behavior: 'prepend' }], ['rehype-toc', { headings: ['h2', 'h3'] }], [addClasses, { 'h1,h2,h3': 'title' }], 'rehype-slug'],
|
||||||
{
|
|
||||||
remarkPlugins: ['remark-code-titles'],
|
|
||||||
rehypePlugins: [['rehype-autolink-headings', { behavior: 'prepend' }], ['rehype-toc', { headings: ['h2', 'h3'] }], [addClasses, { 'h1,h2,h3': 'title' }], 'rehype-slug'],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,20 +1,14 @@
|
||||||
import { defineConfig } from 'astro/config';
|
import { defineConfig } from 'astro/config';
|
||||||
import astroRemark from '@astrojs/markdown-remark';
|
|
||||||
|
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
// Enable Custom Markdown options, plugins, etc.
|
// Enable Custom Markdown options, plugins, etc.
|
||||||
markdownOptions: {
|
markdown: {
|
||||||
render: [
|
syntaxHighlight: 'shiki',
|
||||||
astroRemark,
|
shikiConfig: {
|
||||||
{
|
theme: 'dracula',
|
||||||
syntaxHighlight: 'shiki',
|
// Learn more about this configuration here:
|
||||||
shikiConfig: {
|
// https://docs.astro.build/en/guides/markdown-content/#syntax-highlighting
|
||||||
theme: 'dracula',
|
},
|
||||||
// Learn more about this configuration here:
|
}
|
||||||
// https://docs.astro.build/en/guides/markdown-content/#syntax-highlighting
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,6 +2,7 @@ import type { AddressInfo } from 'net';
|
||||||
import type * as babel from '@babel/core';
|
import type * as babel from '@babel/core';
|
||||||
import type * as vite from 'vite';
|
import type * as vite from 'vite';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
import type { ShikiConfig, Plugin } from '@astrojs/markdown-remark';
|
||||||
import type { AstroConfigSchema } from '../core/config';
|
import type { AstroConfigSchema } from '../core/config';
|
||||||
import type { AstroComponentFactory, Metadata } from '../runtime/server';
|
import type { AstroComponentFactory, Metadata } from '../runtime/server';
|
||||||
import type { ViteConfigWithSSR } from '../core/create-vite';
|
import type { ViteConfigWithSSR } from '../core/create-vite';
|
||||||
|
@ -24,18 +25,13 @@ export interface AstroComponentMetadata {
|
||||||
|
|
||||||
/** The flags supported by the Astro CLI */
|
/** The flags supported by the Astro CLI */
|
||||||
export interface CLIFlags {
|
export interface CLIFlags {
|
||||||
projectRoot?: string;
|
root?: string;
|
||||||
site?: string;
|
site?: string;
|
||||||
sitemap?: boolean;
|
|
||||||
host?: string | boolean;
|
host?: string | boolean;
|
||||||
hostname?: string;
|
|
||||||
port?: number;
|
port?: number;
|
||||||
config?: string;
|
config?: string;
|
||||||
/** @deprecated */
|
|
||||||
experimentalStaticBuild?: boolean;
|
|
||||||
experimentalSsr?: boolean;
|
experimentalSsr?: boolean;
|
||||||
experimentalIntegrations?: boolean;
|
experimentalIntegrations?: boolean;
|
||||||
legacyBuild?: boolean;
|
|
||||||
drafts?: boolean;
|
drafts?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,6 +72,32 @@ export interface AstroGlobalPartial {
|
||||||
site: URL;
|
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
|
* Astro User Config
|
||||||
* Docs: https://docs.astro.build/reference/configuration-reference/
|
* Docs: https://docs.astro.build/reference/configuration-reference/
|
||||||
|
@ -89,50 +111,50 @@ export interface AstroUserConfig {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @docs
|
* @docs
|
||||||
* @name projectRoot
|
* @name root
|
||||||
* @cli --project-root
|
* @cli --root
|
||||||
* @type {string}
|
* @type {string}
|
||||||
* @default `"."` (current working directory)
|
* @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.
|
* @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.
|
* @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
|
* #### Examples
|
||||||
*
|
*
|
||||||
* ```js
|
* ```js
|
||||||
* {
|
* {
|
||||||
* projectRoot: './my-project-directory'
|
* root: './my-project-directory'
|
||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
* ```bash
|
* ```bash
|
||||||
* $ astro build --project-root ./my-project-directory
|
* $ astro build --root ./my-project-directory
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
projectRoot?: string;
|
root?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @docs
|
* @docs
|
||||||
* @name dist
|
* @name srcDir
|
||||||
* @type {string}
|
* @type {string}
|
||||||
* @default `"./dist"`
|
* @default `"./src"`
|
||||||
* @description Set the directory that `astro build` writes your final build to.
|
* @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.
|
* The value can be either an absolute file system path or a path relative to the project root.
|
||||||
*
|
*
|
||||||
* ```js
|
* ```js
|
||||||
* {
|
* {
|
||||||
* dist: './my-custom-build-directory'
|
* srcDir: './www'
|
||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
dist?: string;
|
srcDir?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @docs
|
* @docs
|
||||||
* @name public
|
* @name publicDir
|
||||||
* @type {string}
|
* @type {string}
|
||||||
* @default `"./public"`
|
* @default `"./publicDir"`
|
||||||
* @description
|
* @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.
|
* 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
|
* ```js
|
||||||
* {
|
* {
|
||||||
* public: './my-custom-public-directory'
|
* publicDir: './my-custom-publicDir-directory'
|
||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
public?: string;
|
publicDir?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @docs
|
* @docs
|
||||||
* @name integrations
|
* @name outDir
|
||||||
* @type {AstroIntegration[]}
|
* @type {string}
|
||||||
* @default `[]`
|
* @default `"./outDir"`
|
||||||
* @description
|
* @description Set the directory that `astro build` writes your final build to.
|
||||||
* 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).
|
* The value can be either an absolute file system path or a path relative to the project root.
|
||||||
*
|
|
||||||
* Setting this configuration will disable Astro's default integration, so it is recommended to provide a renderer for every framework that you use:
|
|
||||||
*
|
|
||||||
* Note: Integrations are currently under active development, and only first-party integrations are supported. In the future, 3rd-party integrations will be allowed.
|
|
||||||
*
|
*
|
||||||
* ```js
|
* ```js
|
||||||
* import react from '@astrojs/react';
|
|
||||||
* import vue from '@astrojs/vue';
|
|
||||||
* {
|
* {
|
||||||
* // Example: Use Astro with Vue + React, and no other frameworks.
|
* outDir: './my-custom-build-directory'
|
||||||
* integrations: [react(), vue()]
|
|
||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
integrations?: Array<AstroIntegration | AstroIntegration[]>;
|
outDir?: string;
|
||||||
|
|
||||||
/**
|
|
||||||
* @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.
|
|
||||||
*/
|
|
||||||
adapter?: AstroIntegration;
|
|
||||||
|
|
||||||
/** @deprecated - Use "integrations" instead. Run Astro to learn more about migrating. */
|
|
||||||
renderers?: string[];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @docs
|
* @docs
|
||||||
* @name markdownOptions
|
* @name site
|
||||||
* @type {{render: MarkdownRenderOptions}}
|
* @type {string}
|
||||||
* @see [Markdown guide](/en/guides/markdown-content/)
|
|
||||||
* @description
|
* @description
|
||||||
* Configure how markdown files (`.md`) are rendered.
|
* 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
|
* ```js
|
||||||
* import { defineConfig } from "astro/config";
|
* {
|
||||||
* import astroRemark from "@astrojs/markdown-remark";
|
* site: 'https://www.my-site.dev'
|
||||||
* import customRehypePlugin from "/path/to/rehypePlugin.mjs";
|
* }
|
||||||
*
|
|
||||||
* 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"],
|
|
||||||
*
|
|
||||||
* // Add a Rehype plugin to your project.
|
|
||||||
* rehypePlugins: [
|
|
||||||
* "rehype-slug",
|
|
||||||
* [customRehypePlugin, { configKey: "value" }],
|
|
||||||
* ["rehype-autolink-headings", { behavior: "prepend" }],
|
|
||||||
* ],
|
|
||||||
* },
|
|
||||||
* ],
|
|
||||||
* },
|
|
||||||
* });
|
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
markdownOptions?: {
|
site?: string;
|
||||||
render?: MarkdownRenderOptions;
|
|
||||||
};
|
/**
|
||||||
|
* @docs
|
||||||
|
* @name base
|
||||||
|
* @type {string}
|
||||||
|
* @description
|
||||||
|
* 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
|
||||||
|
* {
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* {
|
||||||
|
* // Example: Require a trailing slash during development
|
||||||
|
* trailingSlash: 'always'
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
trailingSlash?: 'always' | 'never' | 'ignore';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @docs
|
* @docs
|
||||||
* @kind heading
|
* @kind heading
|
||||||
* @name Build Options
|
* @name Build Options
|
||||||
*/
|
*/
|
||||||
buildOptions?: {
|
build?: {
|
||||||
/**
|
/**
|
||||||
* @docs
|
* @docs
|
||||||
* @name buildOptions.site
|
* @name build.format
|
||||||
* @type {string}
|
* @typeraw {('file' | 'directory')}
|
||||||
* @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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @docs
|
|
||||||
* @name buildOptions.pageUrlFormat
|
|
||||||
* @type {('file' | 'directory')}
|
|
||||||
* @default `'directory'`
|
* @default `'directory'`
|
||||||
* @description
|
* @description
|
||||||
* Control the output file format of each page.
|
* Control the output file format of each page.
|
||||||
|
@ -304,18 +259,75 @@ export interface AstroUserConfig {
|
||||||
*
|
*
|
||||||
* ```js
|
* ```js
|
||||||
* {
|
* {
|
||||||
* buildOptions: {
|
* build: {
|
||||||
* // Example: Generate `page.html` instead of `page/index.html` during 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
|
* @docs
|
||||||
* @name buildOptions.drafts
|
* @name markdown.drafts
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
* @default `false`
|
* @default `false`
|
||||||
* @description
|
* @description
|
||||||
|
@ -325,117 +337,121 @@ export interface AstroUserConfig {
|
||||||
*
|
*
|
||||||
* ```js
|
* ```js
|
||||||
* {
|
* {
|
||||||
* buildOptions: {
|
* markdown: {
|
||||||
* // Example: Include all drafts in your final build
|
* // Example: Include all drafts in your final build
|
||||||
* drafts: true,
|
* drafts: true,
|
||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
drafts?: boolean;
|
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
|
|
||||||
* @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;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @docs
|
* @docs
|
||||||
* @name devOptions.hostname
|
* @name markdown.shikiConfig
|
||||||
* @type {string}
|
* @type {ShikiConfig}
|
||||||
* @default `'localhost'`
|
|
||||||
* @deprecated Use `host` instead
|
|
||||||
* @description
|
* @description
|
||||||
* > **This option is deprecated.** Consider using `host` instead.
|
* Shiki configuration options. See [the markdown configuration docs](https://docs.astro.build/en/guides/markdown-content/#shiki-configuration) for usage.
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
*/
|
||||||
hostname?: string;
|
shikiConfig?: ShikiConfig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @docs
|
* @docs
|
||||||
* @name devOptions.port
|
* @name markdown.syntaxHighlight
|
||||||
* @type {number}
|
* @type {'shiki' | 'prism' | false}
|
||||||
* @default `3000`
|
* @default `shiki`
|
||||||
* @description
|
* @description
|
||||||
* Set which port the dev server should listen on.
|
* Which syntax highlighter to use, if any.
|
||||||
*
|
* - `shiki` - use the [Shiki](https://github.com/shikijs/shiki) highlighter
|
||||||
* If the given port is already in use, Astro will automatically try the next available port.
|
* - `prism` - use the [Prism](https://prismjs.com/) highlighter
|
||||||
*/
|
* - `false` - do not apply syntax highlighting.
|
||||||
port?: number;
|
*
|
||||||
|
|
||||||
/**
|
|
||||||
* @docs
|
|
||||||
* @name devOptions.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.
|
|
||||||
*
|
|
||||||
* 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
|
* ```js
|
||||||
* {
|
* {
|
||||||
* devOptions: {
|
* markdown: {
|
||||||
* // Example: Require a trailing slash during development
|
* // Example: Switch to use prism for syntax highlighting in Markdown
|
||||||
* trailingSlash: 'always'
|
* syntaxHighlight: 'prism',
|
||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
trailingSlash?: 'always' | 'never' | 'ignore';
|
syntaxHighlight?: 'shiki' | 'prism' | false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @docs
|
||||||
|
* @name markdown.remarkPlugins
|
||||||
|
* @type {Plugin[]}
|
||||||
|
* @description
|
||||||
|
* 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' }]],
|
||||||
|
* },
|
||||||
|
* };
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
remarkPlugins?: Plugin[];
|
||||||
|
/**
|
||||||
|
* @docs
|
||||||
|
* @name markdown.rehypePlugins
|
||||||
|
* @type {Plugin[]}
|
||||||
|
* @description
|
||||||
|
* 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'],
|
||||||
|
* },
|
||||||
|
* };
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
rehypePlugins?: Plugin[];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable experimental support for 3rd-party integrations.
|
* @name adapter
|
||||||
* Default: false
|
* @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
|
* @docs
|
||||||
* @name vite
|
* @kind heading
|
||||||
* @type {vite.UserConfig}
|
* @name Vite
|
||||||
* @description
|
* @description
|
||||||
*
|
*
|
||||||
* Pass additional configuration options to Vite. Useful when Astro doesn't support some advanced configuration that you may need.
|
* 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
|
* ```js
|
||||||
* {
|
* {
|
||||||
* vite: {
|
* vite: {
|
||||||
* ssr: {
|
* ssr: {
|
||||||
* // Example: Force a broken package to skip SSR processing, if needed
|
* // Example: Force a broken package to skip SSR processing, if needed
|
||||||
* external: ['broken-npm-package'],
|
* external: ['broken-npm-package'],
|
||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
|
@ -459,12 +475,54 @@ export interface AstroUserConfig {
|
||||||
* {
|
* {
|
||||||
* vite: {
|
* vite: {
|
||||||
* // Example: Add custom vite plugins directly to your Astro project
|
* // Example: Add custom vite plugins directly to your Astro project
|
||||||
* plugins: [myPlugin()],
|
* plugins: [myPlugin()],
|
||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
vite?: vite.UserConfig & { ssr?: vite.SSROptions };
|
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
|
// NOTE(fks): We choose to keep our hand-generated AstroUserConfig interface so that
|
||||||
|
|
|
@ -64,7 +64,7 @@ function generateString(str: string, len: number) {
|
||||||
export async function run() {}
|
export async function run() {}
|
||||||
|
|
||||||
export async function check(astroConfig: AstroConfig) {
|
export async function check(astroConfig: AstroConfig) {
|
||||||
const root = astroConfig.projectRoot;
|
const root = astroConfig.root;
|
||||||
let checker = new AstroCheck(root.toString());
|
let checker = new AstroCheck(root.toString());
|
||||||
await openAllDocuments(root, [], checker);
|
await openAllDocuments(root, [], checker);
|
||||||
|
|
||||||
|
|
|
@ -36,8 +36,7 @@ function printAstroHelp() {
|
||||||
flags: [
|
flags: [
|
||||||
['--host [optional IP]', 'Expose server on network'],
|
['--host [optional IP]', 'Expose server on network'],
|
||||||
['--config <path>', 'Specify the path to the Astro config file.'],
|
['--config <path>', 'Specify the path to the Astro config file.'],
|
||||||
['--project-root <path>', 'Specify the path to the project root folder.'],
|
['--root <path>', 'Specify the path to the project root folder.'],
|
||||||
['--no-sitemap', 'Disable sitemap generation (build only).'],
|
|
||||||
['--legacy-build', 'Use the build strategy prior to 0.24.0'],
|
['--legacy-build', 'Use the build strategy prior to 0.24.0'],
|
||||||
['--experimental-ssr', 'Enable SSR compilation fot 3rd-party adapters.'],
|
['--experimental-ssr', 'Enable SSR compilation fot 3rd-party adapters.'],
|
||||||
['--drafts', 'Include markdown draft pages in the build.'],
|
['--drafts', 'Include markdown draft pages in the build.'],
|
||||||
|
@ -74,7 +73,7 @@ function resolveCommand(flags: Arguments): CLICommand {
|
||||||
export async function cli(args: string[]) {
|
export async function cli(args: string[]) {
|
||||||
const flags = yargs(args);
|
const flags = yargs(args);
|
||||||
const cmd = resolveCommand(flags);
|
const cmd = resolveCommand(flags);
|
||||||
const projectRoot = flags.projectRoot;
|
const root = flags.root;
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case 'help':
|
case 'help':
|
||||||
|
@ -101,7 +100,7 @@ export async function cli(args: string[]) {
|
||||||
try {
|
try {
|
||||||
// Note: ideally, `loadConfig` would return the config AND its filePath
|
// Note: ideally, `loadConfig` would return the config AND its filePath
|
||||||
// For now, `add` has to resolve the config again internally
|
// 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) {
|
} catch (err) {
|
||||||
return throwAndExit(err);
|
return throwAndExit(err);
|
||||||
}
|
}
|
||||||
|
@ -110,7 +109,7 @@ export async function cli(args: string[]) {
|
||||||
case 'add': {
|
case 'add': {
|
||||||
try {
|
try {
|
||||||
const packages = flags._.slice(3) as string[];
|
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) {
|
} catch (err) {
|
||||||
return throwAndExit(err);
|
return throwAndExit(err);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { appendForwardSlash } from '../../core/path.js';
|
||||||
const STATUS_CODE_PAGES = new Set(['/404', '/500']);
|
const STATUS_CODE_PAGES = new Set(['/404', '/500']);
|
||||||
|
|
||||||
function getOutRoot(astroConfig: AstroConfig): URL {
|
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 {
|
export function getOutFolder(astroConfig: AstroConfig, pathname: string, routeType: RouteType): URL {
|
||||||
|
@ -16,7 +16,7 @@ export function getOutFolder(astroConfig: AstroConfig, pathname: string, routeTy
|
||||||
case 'endpoint':
|
case 'endpoint':
|
||||||
return new URL('.' + appendForwardSlash(npath.dirname(pathname)), outRoot);
|
return new URL('.' + appendForwardSlash(npath.dirname(pathname)), outRoot);
|
||||||
case 'page':
|
case 'page':
|
||||||
switch (astroConfig.buildOptions.pageUrlFormat) {
|
switch (astroConfig.build.format) {
|
||||||
case 'directory': {
|
case 'directory': {
|
||||||
if (STATUS_CODE_PAGES.has(pathname)) {
|
if (STATUS_CODE_PAGES.has(pathname)) {
|
||||||
return new URL('.' + appendForwardSlash(npath.dirname(pathname)), outRoot);
|
return new URL('.' + appendForwardSlash(npath.dirname(pathname)), outRoot);
|
||||||
|
@ -35,7 +35,7 @@ export function getOutFile(astroConfig: AstroConfig, outFolder: URL, pathname: s
|
||||||
case 'endpoint':
|
case 'endpoint':
|
||||||
return new URL(npath.basename(pathname), outFolder);
|
return new URL(npath.basename(pathname), outFolder);
|
||||||
case 'page':
|
case 'page':
|
||||||
switch (astroConfig.buildOptions.pageUrlFormat) {
|
switch (astroConfig.build.format) {
|
||||||
case 'directory': {
|
case 'directory': {
|
||||||
if (STATUS_CODE_PAGES.has(pathname)) {
|
if (STATUS_CODE_PAGES.has(pathname)) {
|
||||||
const baseName = npath.basename(pathname);
|
const baseName = npath.basename(pathname);
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
|
import astroRemark from '@astrojs/markdown-remark';
|
||||||
import fs from 'fs';
|
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 npath from 'path';
|
||||||
import type { OutputAsset, OutputChunk, RollupOutput } from 'rollup';
|
import type { OutputAsset, OutputChunk, RollupOutput } from 'rollup';
|
||||||
import { fileURLToPath } from 'url';
|
import { fileURLToPath } from 'url';
|
||||||
import type { AstroConfig, ComponentInstance, EndpointHandler, SSRLoadedRenderer } from '../../@types/astro';
|
import type { AstroConfig, ComponentInstance, EndpointHandler, SSRLoadedRenderer } from '../../@types/astro';
|
||||||
import type { BuildInternals } from '../../core/build/internal.js';
|
import type { BuildInternals } from '../../core/build/internal.js';
|
||||||
import { debug, info } from '../logger/core.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 type { RenderOptions } from '../../core/render/core';
|
||||||
import { BEFORE_HYDRATION_SCRIPT_ID } from '../../vite-plugin-scripts/index.js';
|
import { BEFORE_HYDRATION_SCRIPT_ID } from '../../vite-plugin-scripts/index.js';
|
||||||
import { call as callEndpoint } from '../endpoint/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.
|
// Gives back a facadeId that is relative to the root.
|
||||||
// ie, src/pages/index.astro instead of /Users/name..../src/pages/index.astro
|
// ie, src/pages/index.astro instead of /Users/name..../src/pages/index.astro
|
||||||
export function rootRelativeFacadeId(facadeId: string, astroConfig: AstroConfig): string {
|
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.
|
// 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 ssr = isBuildingToSSR(opts.astroConfig);
|
||||||
const serverEntry = opts.buildConfig.serverEntry;
|
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 ssrEntryURL = new URL('./' + serverEntry + `?time=${Date.now()}`, outFolder);
|
||||||
const ssrEntry = await import(ssrEntryURL.toString());
|
const ssrEntry = await import(ssrEntryURL.toString());
|
||||||
|
|
||||||
|
@ -151,7 +152,7 @@ async function generatePath(pathname: string, opts: StaticBuildOptions, gopts: G
|
||||||
|
|
||||||
debug('build', `Generating: ${pathname}`);
|
debug('build', `Generating: ${pathname}`);
|
||||||
|
|
||||||
const site = astroConfig.buildOptions.site;
|
const site = astroConfig.site;
|
||||||
const links = createLinkStylesheetElementSet(linkIds.reverse(), site);
|
const links = createLinkStylesheetElementSet(linkIds.reverse(), site);
|
||||||
const scripts = createModuleScriptElementWithSrcSet(hoistedId ? [hoistedId] : [], site);
|
const scripts = createModuleScriptElementWithSrcSet(hoistedId ? [hoistedId] : [], site);
|
||||||
|
|
||||||
|
@ -170,7 +171,7 @@ async function generatePath(pathname: string, opts: StaticBuildOptions, gopts: G
|
||||||
legacyBuild: false,
|
legacyBuild: false,
|
||||||
links,
|
links,
|
||||||
logging,
|
logging,
|
||||||
markdownRender: astroConfig.markdownOptions.render,
|
markdownRender: [astroRemark, astroConfig.markdown],
|
||||||
mod,
|
mod,
|
||||||
origin,
|
origin,
|
||||||
pathname,
|
pathname,
|
||||||
|
@ -196,7 +197,7 @@ async function generatePath(pathname: string, opts: StaticBuildOptions, gopts: G
|
||||||
request: createRequest({ url, headers: new Headers(), logging }),
|
request: createRequest({ url, headers: new Headers(), logging }),
|
||||||
route: pageData.route,
|
route: pageData.route,
|
||||||
routeCache,
|
routeCache,
|
||||||
site: astroConfig.buildOptions.site,
|
site: astroConfig.site ? new URL(astroConfig.base, astroConfig.site).toString() : astroConfig.site,
|
||||||
ssr: isBuildingToSSR(opts.astroConfig),
|
ssr: isBuildingToSSR(opts.astroConfig),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -10,9 +10,7 @@ import { createVite, ViteConfigWithSSR } from '../create-vite.js';
|
||||||
import { debug, info, levels, timerMessage, warn, warnIfUsingExperimentalSSR } from '../logger/core.js';
|
import { debug, info, levels, timerMessage, warn, warnIfUsingExperimentalSSR } from '../logger/core.js';
|
||||||
import { nodeLogOptions } from '../logger/node.js';
|
import { nodeLogOptions } from '../logger/node.js';
|
||||||
import { createRouteManifest } from '../routing/index.js';
|
import { createRouteManifest } from '../routing/index.js';
|
||||||
import { generateSitemap } from '../render/sitemap.js';
|
|
||||||
import { collectPagesData } from './page-data.js';
|
import { collectPagesData } from './page-data.js';
|
||||||
import { build as scanBasedBuild } from './scan-based-build.js';
|
|
||||||
import { staticBuild } from './static-build.js';
|
import { staticBuild } from './static-build.js';
|
||||||
import { RouteCache } from '../render/route-cache.js';
|
import { RouteCache } from '../render/route-cache.js';
|
||||||
import { runHookBuildDone, runHookBuildStart, runHookConfigDone, runHookConfigSetup } from '../../integrations/index.js';
|
import { runHookBuildDone, runHookBuildStart, runHookConfigDone, runHookConfigSetup } from '../../integrations/index.js';
|
||||||
|
@ -42,17 +40,13 @@ class AstroBuilder {
|
||||||
private timer: Record<string, number>;
|
private timer: Record<string, number>;
|
||||||
|
|
||||||
constructor(config: AstroConfig, options: BuildOptions) {
|
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) {
|
if (options.mode) {
|
||||||
this.mode = options.mode;
|
this.mode = options.mode;
|
||||||
}
|
}
|
||||||
this.config = config;
|
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.logging = options.logging;
|
||||||
this.routeCache = new RouteCache(this.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.manifest = createRouteManifest({ config }, this.logging);
|
||||||
this.timer = {};
|
this.timer = {};
|
||||||
}
|
}
|
||||||
|
@ -85,8 +79,8 @@ class AstroBuilder {
|
||||||
private async build({ viteConfig, viteServer }: { viteConfig: ViteConfigWithSSR; viteServer: vite.ViteDevServer }) {
|
private async build({ viteConfig, viteServer }: { viteConfig: ViteConfigWithSSR; viteServer: vite.ViteDevServer }) {
|
||||||
const { origin } = this;
|
const { origin } = this;
|
||||||
const buildConfig: BuildConfig = {
|
const buildConfig: BuildConfig = {
|
||||||
client: new URL('./client/', this.config.dist),
|
client: new URL('./client/', this.config.outDir),
|
||||||
server: new URL('./server/', this.config.dist),
|
server: new URL('./server/', this.config.outDir),
|
||||||
serverEntry: 'entry.mjs',
|
serverEntry: 'entry.mjs',
|
||||||
staticMode: undefined,
|
staticMode: undefined,
|
||||||
};
|
};
|
||||||
|
@ -109,7 +103,7 @@ class AstroBuilder {
|
||||||
if ('frontmatter' in data.preload[1]) {
|
if ('frontmatter' in data.preload[1]) {
|
||||||
// TODO: add better type inference to data.preload[1]
|
// TODO: add better type inference to data.preload[1]
|
||||||
const frontmatter = (data.preload[1] as any).frontmatter;
|
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));
|
debug('build', timerMessage(`Skipping draft page ${page}`, this.timer.loadStart));
|
||||||
delete allPages[page];
|
delete allPages[page];
|
||||||
}
|
}
|
||||||
|
@ -126,31 +120,17 @@ class AstroBuilder {
|
||||||
this.timer.buildStart = performance.now();
|
this.timer.buildStart = performance.now();
|
||||||
info(this.logging, 'build', colors.dim(`Completed in ${getTimeStat(this.timer.init, performance.now())}.`));
|
info(this.logging, 'build', colors.dim(`Completed in ${getTimeStat(this.timer.init, performance.now())}.`));
|
||||||
|
|
||||||
// Use the new faster static based build.
|
await staticBuild({
|
||||||
if (!this.config.buildOptions.legacyBuild) {
|
allPages,
|
||||||
await staticBuild({
|
astroConfig: this.config,
|
||||||
allPages,
|
logging: this.logging,
|
||||||
astroConfig: this.config,
|
manifest: this.manifest,
|
||||||
logging: this.logging,
|
origin: this.origin,
|
||||||
manifest: this.manifest,
|
pageNames,
|
||||||
origin: this.origin,
|
routeCache: this.routeCache,
|
||||||
pageNames,
|
viteConfig,
|
||||||
routeCache: this.routeCache,
|
buildConfig,
|
||||||
viteConfig,
|
});
|
||||||
buildConfig,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
await scanBasedBuild({
|
|
||||||
allPages,
|
|
||||||
astroConfig: this.config,
|
|
||||||
logging: this.logging,
|
|
||||||
origin: this.origin,
|
|
||||||
pageNames,
|
|
||||||
routeCache: this.routeCache,
|
|
||||||
viteConfig,
|
|
||||||
viteServer,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write any additionally generated assets to disk.
|
// Write any additionally generated assets to disk.
|
||||||
this.timer.assetsStart = performance.now();
|
this.timer.assetsStart = performance.now();
|
||||||
|
@ -163,20 +143,6 @@ class AstroBuilder {
|
||||||
});
|
});
|
||||||
debug('build', timerMessage('Additional assets copied', this.timer.assetsStart));
|
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.
|
// You're done! Time to clean up.
|
||||||
await viteServer.close();
|
await viteServer.close();
|
||||||
await runHookBuildDone({ config: this.config, pages: pageNames, routes: Object.values(allPages).map((pd) => pd.route) });
|
await runHookBuildDone({ config: this.config, pages: pageNames, routes: Object.values(allPages).map((pd) => pd.route) });
|
||||||
|
|
|
@ -68,7 +68,7 @@ export async function collectPagesData(opts: CollectPagesDataOptions): Promise<C
|
||||||
scripts: new Set(),
|
scripts: new Set(),
|
||||||
preload: await ssrPreload({
|
preload: await ssrPreload({
|
||||||
astroConfig,
|
astroConfig,
|
||||||
filePath: new URL(`./${route.component}`, astroConfig.projectRoot),
|
filePath: new URL(`./${route.component}`, astroConfig.root),
|
||||||
viteServer,
|
viteServer,
|
||||||
})
|
})
|
||||||
.then((routes) => {
|
.then((routes) => {
|
||||||
|
@ -100,13 +100,13 @@ export async function collectPagesData(opts: CollectPagesDataOptions): Promise<C
|
||||||
debug('build', `├── ${colors.bold(colors.red('✗'))} ${route.component}`);
|
debug('build', `├── ${colors.bold(colors.red('✗'))} ${route.component}`);
|
||||||
throw err;
|
throw err;
|
||||||
});
|
});
|
||||||
const rssFn = generateRssFunction(astroConfig.buildOptions.site, route);
|
const rssFn = generateRssFunction(astroConfig.site, route);
|
||||||
for (const rssCallArg of result.rss) {
|
for (const rssCallArg of result.rss) {
|
||||||
const rssResult = rssFn(rssCallArg);
|
const rssResult = rssFn(rssCallArg);
|
||||||
if (rssResult.xml) {
|
if (rssResult.xml) {
|
||||||
const { url, content } = rssResult.xml;
|
const { url, content } = rssResult.xml;
|
||||||
if (content) {
|
if (content) {
|
||||||
const rssFile = new URL(url.replace(/^\/?/, './'), astroConfig.dist);
|
const rssFile = new URL(url.replace(/^\/?/, './'), astroConfig.outDir);
|
||||||
if (assets[fileURLToPath(rssFile)]) {
|
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})`);
|
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) {
|
if (rssResult.xsl?.content) {
|
||||||
const { url, content } = rssResult.xsl;
|
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)]) {
|
if (assets[fileURLToPath(stylesheetFile)]) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`[getStaticPaths] RSS feed stylesheet ${url} already exists.\nUse \`rss(data, {stylesheet: '...'})\` to choose a unique, custom URL. (${route.component})`
|
`[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(),
|
scripts: new Set(),
|
||||||
preload: await ssrPreload({
|
preload: await ssrPreload({
|
||||||
astroConfig,
|
astroConfig,
|
||||||
filePath: new URL(`./${route.component}`, astroConfig.projectRoot),
|
filePath: new URL(`./${route.component}`, astroConfig.root),
|
||||||
viteServer,
|
viteServer,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
@ -149,7 +149,7 @@ export async function collectPagesData(opts: CollectPagesDataOptions): Promise<C
|
||||||
async function getStaticPathsForRoute(opts: CollectPagesDataOptions, route: RouteData): Promise<RouteCacheEntry> {
|
async function getStaticPathsForRoute(opts: CollectPagesDataOptions, route: RouteData): Promise<RouteCacheEntry> {
|
||||||
const { astroConfig, logging, routeCache, ssr, viteServer } = opts;
|
const { astroConfig, logging, routeCache, ssr, viteServer } = opts;
|
||||||
if (!viteServer) throw new Error(`vite.createServer() not called!`);
|
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 mod = (await viteServer.ssrLoadModule(fileURLToPath(filePath))) as ComponentInstance;
|
||||||
const result = await callGetStaticPaths({ mod, route, isValidate: false, logging, ssr });
|
const result = await callGetStaticPaths({ mod, route, isValidate: false, logging, ssr });
|
||||||
routeCache.set(route, result);
|
routeCache.set(route, result);
|
||||||
|
|
|
@ -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 : '/',
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -44,7 +44,7 @@ export async function staticBuild(opts: StaticBuildOptions) {
|
||||||
timer.buildStart = performance.now();
|
timer.buildStart = performance.now();
|
||||||
|
|
||||||
for (const [component, pageData] of Object.entries(allPages)) {
|
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);
|
const astroModuleId = prependForwardSlash(component);
|
||||||
|
|
||||||
// Track the page data in internals
|
// 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
|
// 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
|
// but because we are running 2 vite builds in parallel, that would cause a race
|
||||||
// condition, so we are doing it ourselves
|
// condition, so we are doing it ourselves
|
||||||
emptyDir(astroConfig.dist, new Set('.git'));
|
emptyDir(astroConfig.outDir, new Set('.git'));
|
||||||
|
|
||||||
timer.clientBuild = performance.now();
|
timer.clientBuild = performance.now();
|
||||||
// Run client build first, so the assets can be fed into the SSR rendered version.
|
// 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>) {
|
async function ssrBuild(opts: StaticBuildOptions, internals: BuildInternals, input: Set<string>) {
|
||||||
const { astroConfig, viteConfig } = opts;
|
const { astroConfig, viteConfig } = opts;
|
||||||
const ssr = isBuildingToSSR(astroConfig);
|
const ssr = isBuildingToSSR(astroConfig);
|
||||||
const out = ssr ? opts.buildConfig.server : astroConfig.dist;
|
const out = ssr ? opts.buildConfig.server : astroConfig.outDir;
|
||||||
|
|
||||||
const viteBuildConfig = {
|
const viteBuildConfig = {
|
||||||
logLevel: 'error',
|
logLevel: 'error',
|
||||||
|
@ -155,7 +155,7 @@ async function ssrBuild(opts: StaticBuildOptions, internals: BuildInternals, inp
|
||||||
root: viteConfig.root,
|
root: viteConfig.root,
|
||||||
envPrefix: 'PUBLIC_',
|
envPrefix: 'PUBLIC_',
|
||||||
server: viteConfig.server,
|
server: viteConfig.server,
|
||||||
base: astroConfig.buildOptions.site ? new URL(astroConfig.buildOptions.site).pathname : '/',
|
base: astroConfig.site ? new URL(astroConfig.site).pathname : '/',
|
||||||
ssr: viteConfig.ssr,
|
ssr: viteConfig.ssr,
|
||||||
resolve: viteConfig.resolve,
|
resolve: viteConfig.resolve,
|
||||||
} as ViteConfigWithSSR;
|
} as ViteConfigWithSSR;
|
||||||
|
@ -170,13 +170,13 @@ async function clientBuild(opts: StaticBuildOptions, internals: BuildInternals,
|
||||||
const { astroConfig, viteConfig } = opts;
|
const { astroConfig, viteConfig } = opts;
|
||||||
const timer = performance.now();
|
const timer = performance.now();
|
||||||
const ssr = isBuildingToSSR(astroConfig);
|
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.
|
// Nothing to do if there is no client-side JS.
|
||||||
if (!input.size) {
|
if (!input.size) {
|
||||||
// If SSR, copy public over
|
// If SSR, copy public over
|
||||||
if (ssr) {
|
if (ssr) {
|
||||||
await copyFiles(astroConfig.public, out);
|
await copyFiles(astroConfig.publicDir, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -184,7 +184,7 @@ async function clientBuild(opts: StaticBuildOptions, internals: BuildInternals,
|
||||||
|
|
||||||
// TODO: use vite.mergeConfig() here?
|
// TODO: use vite.mergeConfig() here?
|
||||||
info(opts.logging, null, `\n${bgGreen(black(' building client '))}`);
|
info(opts.logging, null, `\n${bgGreen(black(' building client '))}`);
|
||||||
|
|
||||||
const viteBuildConfig = {
|
const viteBuildConfig = {
|
||||||
logLevel: 'info',
|
logLevel: 'info',
|
||||||
mode: 'production',
|
mode: 'production',
|
||||||
|
@ -218,7 +218,7 @@ async function clientBuild(opts: StaticBuildOptions, internals: BuildInternals,
|
||||||
root: viteConfig.root,
|
root: viteConfig.root,
|
||||||
envPrefix: 'PUBLIC_',
|
envPrefix: 'PUBLIC_',
|
||||||
server: viteConfig.server,
|
server: viteConfig.server,
|
||||||
base: appendForwardSlash(astroConfig.buildOptions.site ? new URL(astroConfig.buildOptions.site).pathname : '/'),
|
base: astroConfig.base,
|
||||||
} as ViteConfigWithSSR;
|
} as ViteConfigWithSSR;
|
||||||
|
|
||||||
await runHookBuildSetup({ config: astroConfig, vite: viteBuildConfig, target: 'client' });
|
await runHookBuildSetup({ config: astroConfig, vite: viteBuildConfig, target: 'client' });
|
||||||
|
@ -231,11 +231,11 @@ async function clientBuild(opts: StaticBuildOptions, internals: BuildInternals,
|
||||||
async function cleanSsrOutput(opts: StaticBuildOptions) {
|
async function cleanSsrOutput(opts: StaticBuildOptions) {
|
||||||
// The SSR output is all .mjs files, the client output is not.
|
// The SSR output is all .mjs files, the client output is not.
|
||||||
const files = await glob('**/*.mjs', {
|
const files = await glob('**/*.mjs', {
|
||||||
cwd: fileURLToPath(opts.astroConfig.dist),
|
cwd: fileURLToPath(opts.astroConfig.outDir),
|
||||||
});
|
});
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
files.map(async (filename) => {
|
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);
|
await fs.promises.rm(url);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
|
@ -39,7 +39,7 @@ export function vitePluginHoistedScripts(astroConfig: AstroConfig, internals: Bu
|
||||||
const facadeId = output.facadeModuleId!;
|
const facadeId = output.facadeModuleId!;
|
||||||
const pathname = facadeId.slice(0, facadeId.length - '/hoisted.js'.length);
|
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);
|
const pageInfo = getPageDataByViteID(internals, vid);
|
||||||
if (pageInfo) {
|
if (pageInfo) {
|
||||||
pageInfo.hoistedScript = id;
|
pageInfo.hoistedScript = id;
|
||||||
|
|
|
@ -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 { Plugin as VitePlugin } from 'vite';
|
||||||
import type { BuildInternals } from './internal.js';
|
import type { BuildInternals } from './internal.js';
|
||||||
import type { AstroAdapter } from '../../@types/astro';
|
import type { AstroAdapter } from '../../@types/astro';
|
||||||
|
@ -95,9 +95,9 @@ function buildManifest(opts: StaticBuildOptions, internals: BuildInternals): Ser
|
||||||
|
|
||||||
const ssrManifest: SerializedSSRManifest = {
|
const ssrManifest: SerializedSSRManifest = {
|
||||||
routes,
|
routes,
|
||||||
site: astroConfig.buildOptions.site,
|
site: astroConfig.site,
|
||||||
markdown: {
|
markdown: {
|
||||||
render: astroConfig.markdownOptions.render,
|
render: [astroRemark, astroConfig.markdown],
|
||||||
},
|
},
|
||||||
pageMap: null as any,
|
pageMap: null as any,
|
||||||
renderers: [],
|
renderers: [],
|
||||||
|
|
|
@ -11,6 +11,7 @@ import load from '@proload/core';
|
||||||
import loadTypeScript from '@proload/plugin-tsm';
|
import loadTypeScript from '@proload/plugin-tsm';
|
||||||
import postcssrc from 'postcss-load-config';
|
import postcssrc from 'postcss-load-config';
|
||||||
import { arraify, isObject } from './util.js';
|
import { arraify, isObject } from './util.js';
|
||||||
|
import { appendForwardSlash, trimSlashes } from './path.js'
|
||||||
|
|
||||||
load.use([loadTypeScript]);
|
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({
|
export const AstroConfigSchema = z.object({
|
||||||
projectRoot: z
|
adapter: z.object({ name: z.string(), hooks: z.object({}).passthrough().default({}) }).optional(),
|
||||||
|
root: z
|
||||||
.string()
|
.string()
|
||||||
.optional()
|
.optional()
|
||||||
.default('.')
|
.default('.')
|
||||||
.transform((val) => new URL(val)),
|
.transform((val) => new URL(val)),
|
||||||
src: z
|
srcDir: z
|
||||||
.string()
|
.string()
|
||||||
.optional()
|
.optional()
|
||||||
.default('./src')
|
.default('./src')
|
||||||
.transform((val) => new URL(val)),
|
.transform((val) => new URL(val)),
|
||||||
pages: z
|
publicDir: z
|
||||||
.string()
|
|
||||||
.optional()
|
|
||||||
.default('./src/pages')
|
|
||||||
.transform((val) => new URL(val)),
|
|
||||||
public: z
|
|
||||||
.string()
|
.string()
|
||||||
.optional()
|
.optional()
|
||||||
.default('./public')
|
.default('./public')
|
||||||
.transform((val) => new URL(val)),
|
.transform((val) => new URL(val)),
|
||||||
dist: z
|
outDir: z
|
||||||
.string()
|
.string()
|
||||||
.optional()
|
.optional()
|
||||||
.default('./dist')
|
.default('./dist')
|
||||||
.transform((val) => new URL(val)),
|
.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(
|
integrations: z.preprocess(
|
||||||
// preprocess
|
// preprocess
|
||||||
(val) => (Array.isArray(val) ? val.flat(Infinity).filter(Boolean) : val),
|
(val) => (Array.isArray(val) ? val.flat(Infinity).filter(Boolean) : val),
|
||||||
// validate
|
// validate
|
||||||
z.array(z.object({ name: z.string(), hooks: z.object({}).passthrough().default({}) })).default([])
|
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(),
|
style: z
|
||||||
styleOptions: z
|
|
||||||
.object({
|
.object({
|
||||||
postcss: z
|
postcss: z
|
||||||
.object({
|
.object({
|
||||||
|
@ -88,50 +137,37 @@ export const AstroConfigSchema = z.object({
|
||||||
})
|
})
|
||||||
.optional()
|
.optional()
|
||||||
.default({}),
|
.default({}),
|
||||||
markdownOptions: z
|
markdown: z
|
||||||
.object({
|
.object({
|
||||||
render: z.any().optional().default(['@astrojs/markdown-remark', {}]),
|
|
||||||
})
|
|
||||||
.strict()
|
|
||||||
.optional()
|
|
||||||
.default({}),
|
|
||||||
buildOptions: z
|
|
||||||
.object({
|
|
||||||
site: z
|
|
||||||
.string()
|
|
||||||
.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')])
|
|
||||||
.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),
|
drafts: z.boolean().optional().default(false),
|
||||||
})
|
mode: z
|
||||||
.optional()
|
.union([z.literal('md'), z.literal('mdx')])
|
||||||
.default({}),
|
|
||||||
devOptions: 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()
|
.optional()
|
||||||
.default('ignore'),
|
.default('md'),
|
||||||
|
syntaxHighlight: z
|
||||||
|
.union([z.literal('shiki'), z.literal('prism'), z.literal(false)])
|
||||||
|
.optional()
|
||||||
|
.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({}),
|
||||||
|
vite: z.any().optional().default({}),
|
||||||
|
experimental: z
|
||||||
|
.object({
|
||||||
|
ssr: z.boolean().optional().default(false),
|
||||||
|
integrations: z.boolean().optional().default(false),
|
||||||
})
|
})
|
||||||
.optional()
|
.optional()
|
||||||
.default({}),
|
.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 */
|
/** 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);
|
const fileProtocolRoot = pathToFileURL(root + path.sep);
|
||||||
// Manual deprecation checks
|
// Manual deprecation checks
|
||||||
/* eslint-disable no-console */
|
/* eslint-disable no-console */
|
||||||
|
@ -162,32 +198,50 @@ export async function validateConfig(userConfig: any, root: string): Promise<Ast
|
||||||
}
|
}
|
||||||
process.exit(1);
|
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 */
|
/* eslint-enable no-console */
|
||||||
|
|
||||||
// We need to extend the global schema to add transforms that are relative to root.
|
// 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.
|
// This is type checked against the global schema to make sure we still match.
|
||||||
const AstroConfigRelativeSchema = AstroConfigSchema.extend({
|
const AstroConfigRelativeSchema = AstroConfigSchema.extend({
|
||||||
projectRoot: z
|
root: z
|
||||||
.string()
|
.string()
|
||||||
.default('.')
|
.default('.')
|
||||||
.transform((val) => new URL(addTrailingSlash(val), fileProtocolRoot)),
|
.transform((val) => new URL(appendForwardSlash(val), fileProtocolRoot)),
|
||||||
src: z
|
srcDir: z
|
||||||
.string()
|
.string()
|
||||||
.default('./src')
|
.default('./src')
|
||||||
.transform((val) => new URL(addTrailingSlash(val), fileProtocolRoot)),
|
.transform((val) => new URL(appendForwardSlash(val), fileProtocolRoot)),
|
||||||
pages: z
|
publicDir: z
|
||||||
.string()
|
|
||||||
.default('./src/pages')
|
|
||||||
.transform((val) => new URL(addTrailingSlash(val), fileProtocolRoot)),
|
|
||||||
public: z
|
|
||||||
.string()
|
.string()
|
||||||
.default('./public')
|
.default('./public')
|
||||||
.transform((val) => new URL(addTrailingSlash(val), fileProtocolRoot)),
|
.transform((val) => new URL(appendForwardSlash(val), fileProtocolRoot)),
|
||||||
dist: z
|
outDir: z
|
||||||
.string()
|
.string()
|
||||||
.default('./dist')
|
.default('./dist')
|
||||||
.transform((val) => new URL(addTrailingSlash(val), fileProtocolRoot)),
|
.transform((val) => new URL(appendForwardSlash(val), fileProtocolRoot)),
|
||||||
styleOptions: z
|
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({
|
.object({
|
||||||
postcss: z.preprocess(
|
postcss: z.preprocess(
|
||||||
(val) => resolvePostcssConfig(val, fileProtocolRoot),
|
(val) => resolvePostcssConfig(val, fileProtocolRoot),
|
||||||
|
@ -209,7 +263,7 @@ export async function validateConfig(userConfig: any, root: string): Promise<Ast
|
||||||
_ctx: { scripts: [], renderers: [], adapter: undefined },
|
_ctx: { scripts: [], renderers: [], adapter: undefined },
|
||||||
};
|
};
|
||||||
// Final-Pass Validation (perform checks that require the full config object)
|
// 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(
|
throw new Error(
|
||||||
[
|
[
|
||||||
`Astro integrations are still experimental.`,
|
`Astro integrations are still experimental.`,
|
||||||
|
@ -225,51 +279,43 @@ export async function validateConfig(userConfig: any, root: string): Promise<Ast
|
||||||
return result;
|
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. */
|
/** Convert the generic "yargs" flag object into our own, custom TypeScript object. */
|
||||||
function resolveFlags(flags: Partial<Flags>): CLIFlags {
|
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 {
|
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,
|
site: typeof flags.site === 'string' ? flags.site : undefined,
|
||||||
sitemap: typeof flags.sitemap === 'boolean' ? flags.sitemap : undefined,
|
|
||||||
port: typeof flags.port === 'number' ? flags.port : undefined,
|
port: typeof flags.port === 'number' ? flags.port : undefined,
|
||||||
config: typeof flags.config === 'string' ? flags.config : 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,
|
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 : false,
|
||||||
experimentalSsr: typeof flags.experimentalSsr === 'boolean' ? flags.experimentalSsr : undefined,
|
experimentalIntegrations: typeof flags.experimentalIntegrations === 'boolean' ? flags.experimentalIntegrations : false,
|
||||||
experimentalIntegrations: typeof flags.experimentalIntegrations === 'boolean' ? flags.experimentalIntegrations : undefined,
|
drafts: typeof flags.drafts === 'boolean' ? flags.drafts : false,
|
||||||
drafts: typeof flags.drafts === 'boolean' ? flags.drafts : undefined,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Merge CLI flags & user config object (CLI flags take priority) */
|
/** Merge CLI flags & user config object (CLI flags take priority) */
|
||||||
function mergeCLIFlags(astroConfig: AstroUserConfig, flags: CLIFlags) {
|
function mergeCLIFlags(astroConfig: AstroUserConfig, flags: CLIFlags, cmd: string) {
|
||||||
astroConfig.buildOptions = astroConfig.buildOptions || {};
|
astroConfig.server = astroConfig.server || {};
|
||||||
astroConfig.devOptions = astroConfig.devOptions || {};
|
astroConfig.experimental = astroConfig.experimental || {};
|
||||||
if (typeof flags.sitemap === 'boolean') astroConfig.buildOptions.sitemap = flags.sitemap;
|
astroConfig.markdown = astroConfig.markdown || {};
|
||||||
if (typeof flags.site === 'string') astroConfig.buildOptions.site = flags.site;
|
if (typeof flags.site === 'string') astroConfig.site = flags.site;
|
||||||
if (typeof flags.port === 'number') astroConfig.devOptions.port = flags.port;
|
if (typeof flags.experimentalSsr === 'boolean') astroConfig.experimental.ssr = flags.experimentalSsr;
|
||||||
if (typeof flags.host === 'string' || typeof flags.host === 'boolean') astroConfig.devOptions.host = flags.host;
|
if (typeof flags.experimentalIntegrations === 'boolean') astroConfig.experimental.integrations = flags.experimentalIntegrations;
|
||||||
if (typeof flags.hostname === 'string') astroConfig.devOptions.hostname = flags.hostname;
|
if (typeof flags.drafts === 'boolean') astroConfig.markdown.drafts = flags.drafts;
|
||||||
if (typeof flags.legacyBuild === 'boolean') astroConfig.buildOptions.legacyBuild = flags.legacyBuild;
|
// @ts-expect-error astroConfig.server may be a function, but TS doesn't like attaching properties to a function.
|
||||||
if (typeof flags.experimentalSsr === 'boolean') astroConfig.buildOptions.experimentalSsr = flags.experimentalSsr;
|
// TODO: Come back here and refactor to remove this expected error.
|
||||||
if (typeof flags.experimentalIntegrations === 'boolean') astroConfig.experimentalIntegrations = flags.experimentalIntegrations;
|
if (typeof flags.port === 'number') astroConfig.server.port = flags.port;
|
||||||
if (typeof flags.drafts === 'boolean') astroConfig.buildOptions.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.host === 'string' || typeof flags.host === 'boolean') astroConfig.server.host = flags.host;
|
||||||
return astroConfig;
|
return astroConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface LoadConfigOptions {
|
interface LoadConfigOptions {
|
||||||
cwd?: string;
|
cwd?: string;
|
||||||
flags?: Flags;
|
flags?: Flags;
|
||||||
|
cmd: string;
|
||||||
|
validate?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -277,7 +323,7 @@ interface LoadConfigOptions {
|
||||||
* Note: currently the same as loadConfig but only returns the `filePath`
|
* Note: currently the same as loadConfig but only returns the `filePath`
|
||||||
* instead of the resolved config
|
* 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 root = configOptions.cwd ? path.resolve(configOptions.cwd) : process.cwd();
|
||||||
const flags = resolveFlags(configOptions.flags || {});
|
const flags = resolveFlags(configOptions.flags || {});
|
||||||
let userConfigPath: string | undefined;
|
let userConfigPath: string | undefined;
|
||||||
|
@ -311,13 +357,13 @@ export async function loadConfig(configOptions: LoadConfigOptions): Promise<Astr
|
||||||
if (config) {
|
if (config) {
|
||||||
userConfig = config.value;
|
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. */
|
/** Attempt to resolve an Astro configuration object. Normalize, validate, and return. */
|
||||||
export async function resolveConfig(userConfig: AstroUserConfig, root: string, flags: CLIFlags = {}): Promise<AstroConfig> {
|
export async function resolveConfig(userConfig: AstroUserConfig, root: string, flags: CLIFlags = {}, cmd: string): Promise<AstroConfig> {
|
||||||
const mergedConfig = mergeCLIFlags(userConfig, flags);
|
const mergedConfig = mergeCLIFlags(userConfig, flags, cmd);
|
||||||
const validatedConfig = await validateConfig(mergedConfig, root);
|
const validatedConfig = await validateConfig(mergedConfig, root, cmd);
|
||||||
|
|
||||||
return validatedConfig;
|
return validatedConfig;
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@ export async function createVite(commandConfig: ViteConfigWithSSR, { astroConfig
|
||||||
const astroPackages = await getAstroPackages(astroConfig);
|
const astroPackages = await getAstroPackages(astroConfig);
|
||||||
// Start with the Vite configuration that Astro core needs
|
// Start with the Vite configuration that Astro core needs
|
||||||
const commonConfig: ViteConfigWithSSR = {
|
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
|
clearScreen: false, // we want to control the output, not Vite
|
||||||
logLevel: 'warn', // log warnings and errors only
|
logLevel: 'warn', // log warnings and errors only
|
||||||
optimizeDeps: {
|
optimizeDeps: {
|
||||||
|
@ -67,8 +67,8 @@ export async function createVite(commandConfig: ViteConfigWithSSR, { astroConfig
|
||||||
astroPostprocessVitePlugin({ config: astroConfig }),
|
astroPostprocessVitePlugin({ config: astroConfig }),
|
||||||
astroIntegrationsContainerPlugin({ config: astroConfig }),
|
astroIntegrationsContainerPlugin({ config: astroConfig }),
|
||||||
],
|
],
|
||||||
publicDir: fileURLToPath(astroConfig.public),
|
publicDir: fileURLToPath(astroConfig.publicDir),
|
||||||
root: fileURLToPath(astroConfig.projectRoot),
|
root: fileURLToPath(astroConfig.root),
|
||||||
envPrefix: 'PUBLIC_',
|
envPrefix: 'PUBLIC_',
|
||||||
server: {
|
server: {
|
||||||
force: true, // force dependency rebuild (TODO: enabled only while next is unstable; eventually only call in "production" mode?)
|
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: {
|
css: {
|
||||||
postcss: astroConfig.styleOptions.postcss || {},
|
postcss: astroConfig.style.postcss || {},
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
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
|
// 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`
|
// `.astro` files need to be built by Vite, so these should use `noExternal`
|
||||||
async function getAstroPackages({ projectRoot }: AstroConfig): Promise<string[]> {
|
async function getAstroPackages({ root }: AstroConfig): Promise<string[]> {
|
||||||
const pkgUrl = new URL('./package.json', projectRoot);
|
const pkgUrl = new URL('./package.json', root);
|
||||||
const pkgPath = fileURLToPath(pkgUrl);
|
const pkgPath = fileURLToPath(pkgUrl);
|
||||||
if (!fs.existsSync(pkgPath)) return [];
|
if (!fs.existsSync(pkgPath)) return [];
|
||||||
|
|
||||||
|
@ -123,7 +123,7 @@ async function getAstroPackages({ projectRoot }: AstroConfig): Promise<string[]>
|
||||||
if (isCommonNotAstro(dep)) return false;
|
if (isCommonNotAstro(dep)) return false;
|
||||||
// Attempt: package is named `astro-something`. ✅ Likely a community package
|
// Attempt: package is named `astro-something`. ✅ Likely a community package
|
||||||
if (/^astro\-/.test(dep)) return true;
|
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);
|
const depPkgPath = fileURLToPath(depPkgUrl);
|
||||||
if (!fs.existsSync(depPkgPath)) return false;
|
if (!fs.existsSync(depPkgPath)) return false;
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@ import { info, LogOptions, warn, warnIfUsingExperimentalSSR } from '../logger/co
|
||||||
import { nodeLogOptions } from '../logger/node.js';
|
import { nodeLogOptions } from '../logger/node.js';
|
||||||
import * as msg from '../messages.js';
|
import * as msg from '../messages.js';
|
||||||
import { apply as applyPolyfill } from '../polyfill.js';
|
import { apply as applyPolyfill } from '../polyfill.js';
|
||||||
import { getResolvedHostForVite } from '../util.js';
|
|
||||||
|
|
||||||
export interface DevOptions {
|
export interface DevOptions {
|
||||||
logging: LogOptions;
|
logging: LogOptions;
|
||||||
|
@ -24,11 +23,11 @@ export default async function dev(config: AstroConfig, options: DevOptions = { l
|
||||||
const devStart = performance.now();
|
const devStart = performance.now();
|
||||||
applyPolyfill();
|
applyPolyfill();
|
||||||
config = await runHookConfigSetup({ config, command: 'dev' });
|
config = await runHookConfigSetup({ config, command: 'dev' });
|
||||||
|
const { host, port } = config.server;
|
||||||
const viteConfig = await createVite(
|
const viteConfig = await createVite(
|
||||||
{
|
{
|
||||||
mode: 'development',
|
mode: 'development',
|
||||||
// TODO: remove call once --hostname is baselined
|
server: { host },
|
||||||
server: { host: getResolvedHostForVite(config) },
|
|
||||||
},
|
},
|
||||||
{ astroConfig: config, logging: options.logging, mode: 'dev' }
|
{ 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);
|
warnIfUsingExperimentalSSR(options.logging, config);
|
||||||
const viteServer = await vite.createServer(viteConfig);
|
const viteServer = await vite.createServer(viteConfig);
|
||||||
runHookServerSetup({ config, server: viteServer });
|
runHookServerSetup({ config, server: viteServer });
|
||||||
await viteServer.listen(config.devOptions.port);
|
await viteServer.listen(port);
|
||||||
|
|
||||||
const devServerAddressInfo = viteServer.httpServer!.address() as AddressInfo;
|
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 }));
|
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';
|
const currentVersion = process.env.PACKAGE_VERSION ?? '0.0.0';
|
||||||
|
|
|
@ -8,7 +8,7 @@ import type { AddressInfo } from 'net';
|
||||||
import type { AstroConfig } from '../@types/astro';
|
import type { AstroConfig } from '../@types/astro';
|
||||||
import { collectErrorMetadata, cleanErrorStack } from './errors.js';
|
import { collectErrorMetadata, cleanErrorStack } from './errors.js';
|
||||||
import { ZodError } from 'zod';
|
import { ZodError } from 'zod';
|
||||||
import { emoji, getLocalAddress, getResolvedHostForVite, padMultilineString } from './util.js';
|
import { emoji, getLocalAddress, padMultilineString } from './util.js';
|
||||||
|
|
||||||
const PREFIX_PADDING = 6;
|
const PREFIX_PADDING = 6;
|
||||||
|
|
||||||
|
@ -51,8 +51,8 @@ export function devStart({
|
||||||
const networkPrefix = `${dim('┃')} Network `;
|
const networkPrefix = `${dim('┃')} Network `;
|
||||||
|
|
||||||
const { address: networkAddress, port } = devServerAddressInfo;
|
const { address: networkAddress, port } = devServerAddressInfo;
|
||||||
const localAddress = getLocalAddress(networkAddress, config);
|
const localAddress = getLocalAddress(networkAddress, config.server.host);
|
||||||
const networkLogging = getNetworkLogging(config);
|
const networkLogging = getNetworkLogging(config.server.host);
|
||||||
const toDisplayUrl = (hostname: string) => `${https ? 'https' : 'http'}://${hostname}:${port}${rootPath}`;
|
const toDisplayUrl = (hostname: string) => `${https ? 'https' : 'http'}://${hostname}:${port}${rootPath}`;
|
||||||
let addresses = [];
|
let addresses = [];
|
||||||
|
|
||||||
|
@ -125,10 +125,7 @@ export function portInUse({ port }: { port: number }): string {
|
||||||
|
|
||||||
const LOCAL_IP_HOSTS = new Set(['localhost', '127.0.0.1']);
|
const LOCAL_IP_HOSTS = new Set(['localhost', '127.0.0.1']);
|
||||||
|
|
||||||
export function getNetworkLogging(config: AstroConfig): 'none' | 'host-to-expose' | 'visible' {
|
export function getNetworkLogging(host: string | boolean): 'none' | 'host-to-expose' | 'visible' {
|
||||||
// TODO: remove once --hostname is baselined
|
|
||||||
const host = getResolvedHostForVite(config);
|
|
||||||
|
|
||||||
if (host === false) {
|
if (host === false) {
|
||||||
return 'host-to-expose';
|
return 'host-to-expose';
|
||||||
} else if (typeof host === 'string' && LOCAL_IP_HOSTS.has(host)) {
|
} else if (typeof host === 'string' && LOCAL_IP_HOSTS.has(host)) {
|
||||||
|
|
|
@ -27,10 +27,10 @@ const HAS_FILE_EXTENSION_REGEXP = /^.*\.[^\\]+$/;
|
||||||
export default async function preview(config: AstroConfig, { logging }: PreviewOptions): Promise<PreviewServer> {
|
export default async function preview(config: AstroConfig, { logging }: PreviewOptions): Promise<PreviewServer> {
|
||||||
const startServerTime = performance.now();
|
const startServerTime = performance.now();
|
||||||
const defaultOrigin = 'http://localhost';
|
const defaultOrigin = 'http://localhost';
|
||||||
const trailingSlash = config.devOptions.trailingSlash;
|
const trailingSlash = config.trailingSlash;
|
||||||
/** Base request URL. */
|
/** Base request URL. */
|
||||||
let baseURL = new URL(config.buildOptions.site || '/', defaultOrigin);
|
let baseURL = new URL(config.base, new URL(config.site || '/', defaultOrigin));
|
||||||
const staticFileServer = sirv(fileURLToPath(config.dist), {
|
const staticFileServer = sirv(fileURLToPath(config.outDir), {
|
||||||
dev: true,
|
dev: true,
|
||||||
etag: true,
|
etag: true,
|
||||||
maxAge: 0,
|
maxAge: 0,
|
||||||
|
@ -59,10 +59,10 @@ export default async function preview(config: AstroConfig, { logging }: PreviewO
|
||||||
|
|
||||||
switch (true) {
|
switch (true) {
|
||||||
case hasTrailingSlash && trailingSlash == 'never' && !isRoot:
|
case hasTrailingSlash && trailingSlash == 'never' && !isRoot:
|
||||||
sendError('Not Found (devOptions.trailingSlash is set to "never")');
|
sendError('Not Found (trailingSlash is set to "never")');
|
||||||
return;
|
return;
|
||||||
case !hasTrailingSlash && trailingSlash == 'always' && !isRoot && !HAS_FILE_EXTENSION_REGEXP.test(pathname):
|
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;
|
return;
|
||||||
default: {
|
default: {
|
||||||
// HACK: rewrite req.url so that sirv finds the file
|
// 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;
|
let { port } = config.server;
|
||||||
const host = getResolvedHostForHttpServer(config);
|
const host = getResolvedHostForHttpServer(config.server.host);
|
||||||
|
|
||||||
let httpServer: http.Server;
|
let httpServer: http.Server;
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,13 @@
|
||||||
import type { AstroConfig } from '../../@types/astro';
|
import type { AstroConfig } from '../../@types/astro';
|
||||||
|
|
||||||
export function getResolvedHostForHttpServer(config: AstroConfig) {
|
export function getResolvedHostForHttpServer(host: string | boolean) {
|
||||||
const { host, hostname } = config.devOptions;
|
if (host === false) {
|
||||||
|
|
||||||
if (host === false && hostname === 'localhost') {
|
|
||||||
// Use a secure default
|
// Use a secure default
|
||||||
return '127.0.0.1';
|
return '127.0.0.1';
|
||||||
} else if (host === true) {
|
} else if (host === true) {
|
||||||
// If passed --host in the CLI without arguments
|
// If passed --host in the CLI without arguments
|
||||||
return undefined; // undefined typically means 0.0.0.0 or :: (listen on all IPs)
|
return undefined; // undefined typically means 0.0.0.0 or :: (listen on all IPs)
|
||||||
} else if (typeof host === 'string') {
|
|
||||||
return host;
|
|
||||||
} else {
|
} else {
|
||||||
return hostname;
|
return host;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,7 +126,7 @@ export async function render(opts: RenderOptions): Promise<{ type: 'html'; html:
|
||||||
html = html.replace('<!--astro:head:injected-->', '');
|
html = html.replace('<!--astro:head:injected-->', '');
|
||||||
|
|
||||||
// inject <!doctype html> if missing (TODO: is a more robust check needed for comments, etc.?)
|
// 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;
|
html = '<!DOCTYPE html>\n' + html;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import astroRemark from '@astrojs/markdown-remark';
|
||||||
import { fileURLToPath } from 'url';
|
import { fileURLToPath } from 'url';
|
||||||
import type * as vite from 'vite';
|
import type * as vite from 'vite';
|
||||||
import type { AstroConfig, AstroRenderer, ComponentInstance, RouteData, RuntimeMode, SSRElement, SSRLoadedRenderer } from '../../../@types/astro';
|
import type { AstroConfig, AstroRenderer, ComponentInstance, RouteData, RuntimeMode, SSRElement, SSRLoadedRenderer } from '../../../@types/astro';
|
||||||
|
@ -20,7 +21,7 @@ export interface SSROptions {
|
||||||
logging: LogOptions;
|
logging: LogOptions;
|
||||||
/** "development" or "production" */
|
/** "development" or "production" */
|
||||||
mode: RuntimeMode;
|
mode: RuntimeMode;
|
||||||
/** production website, needed for some RSS & Sitemap functions */
|
/** production website, needed for some RSS functions */
|
||||||
origin: string;
|
origin: string;
|
||||||
/** the web request (needed for dynamic routes) */
|
/** the web request (needed for dynamic routes) */
|
||||||
pathname: string;
|
pathname: string;
|
||||||
|
@ -65,13 +66,14 @@ export async function preload({ astroConfig, filePath, viteServer }: Pick<SSROpt
|
||||||
/** use Vite to SSR */
|
/** use Vite to SSR */
|
||||||
export async function render(renderers: SSRLoadedRenderer[], mod: ComponentInstance, ssrOpts: SSROptions): Promise<RenderResponse> {
|
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 { 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
|
// 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
|
// Inject HMR scripts
|
||||||
if (mod.hasOwnProperty('$$metadata') && mode === 'development' && !legacy) {
|
if (mod.hasOwnProperty('$$metadata') && mode === 'development' && !isLegacyBuild) {
|
||||||
scripts.add({
|
scripts.add({
|
||||||
props: { type: 'module', src: '/@vite/client' },
|
props: { type: 'module', src: '/@vite/client' },
|
||||||
children: '',
|
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.
|
// Pass framework CSS in as link tags to be appended to the page.
|
||||||
let links = new Set<SSRElement>();
|
let links = new Set<SSRElement>();
|
||||||
if (!legacy) {
|
if (!isLegacyBuild) {
|
||||||
[...getStylesForURL(filePath, viteServer)].forEach((href) => {
|
[...getStylesForURL(filePath, viteServer)].forEach((href) => {
|
||||||
if (mode === 'development' && svelteStylesRE.test(href)) {
|
if (mode === 'development' && svelteStylesRE.test(href)) {
|
||||||
scripts.add({
|
scripts.add({
|
||||||
|
@ -114,10 +116,11 @@ export async function render(renderers: SSRLoadedRenderer[], mod: ComponentInsta
|
||||||
}
|
}
|
||||||
|
|
||||||
let content = await coreRender({
|
let content = await coreRender({
|
||||||
legacyBuild: astroConfig.buildOptions.legacyBuild,
|
// TODO: Remove this flag once legacyBuild support is removed
|
||||||
|
legacyBuild: isLegacyBuild,
|
||||||
links,
|
links,
|
||||||
logging,
|
logging,
|
||||||
markdownRender: astroConfig.markdownOptions.render,
|
markdownRender: [astroRemark, astroConfig.markdown],
|
||||||
mod,
|
mod,
|
||||||
origin,
|
origin,
|
||||||
pathname,
|
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
|
// 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?
|
// don't need to copy-paste and maintain Vite's import resolution here?
|
||||||
async resolve(s: string) {
|
async resolve(s: string) {
|
||||||
// The legacy build needs these to remain unresolved so that vite HTML
|
const [resolvedUrl, resolvedPath] = await viteServer.moduleGraph.resolveUrl(s);
|
||||||
// Can do the resolution. Without this condition the build output will be
|
if (resolvedPath.includes('node_modules/.vite')) {
|
||||||
// broken in the legacy build. This can be removed once the legacy build is removed.
|
return resolvedPath.replace(/.*?node_modules\/\.vite/, '/node_modules/.vite');
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
// 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,
|
renderers,
|
||||||
request,
|
request,
|
||||||
route,
|
route,
|
||||||
routeCache,
|
routeCache,
|
||||||
site: astroConfig.buildOptions.site,
|
site: astroConfig.site ? new URL(astroConfig.base, astroConfig.site).toString() : undefined,
|
||||||
ssr: isBuildingToSSR(astroConfig),
|
ssr: isBuildingToSSR(astroConfig),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -159,7 +155,7 @@ export async function render(renderers: SSRLoadedRenderer[], mod: ComponentInsta
|
||||||
const tags: vite.HtmlTagDescriptor[] = [];
|
const tags: vite.HtmlTagDescriptor[] = [];
|
||||||
|
|
||||||
// dev only: inject Astro HMR client
|
// dev only: inject Astro HMR client
|
||||||
if (mode === 'development' && legacy) {
|
if (mode === 'development' && isLegacyBuild) {
|
||||||
tags.push({
|
tags.push({
|
||||||
tag: 'script',
|
tag: 'script',
|
||||||
attrs: { type: 'module' },
|
attrs: { type: 'module' },
|
||||||
|
@ -171,7 +167,7 @@ export async function render(renderers: SSRLoadedRenderer[], mod: ComponentInsta
|
||||||
}
|
}
|
||||||
|
|
||||||
// inject CSS
|
// inject CSS
|
||||||
if (legacy) {
|
if (isLegacyBuild) {
|
||||||
[...getStylesForURL(filePath, viteServer)].forEach((href) => {
|
[...getStylesForURL(filePath, viteServer)].forEach((href) => {
|
||||||
if (mode === 'development' && svelteStylesRE.test(href)) {
|
if (mode === 'development' && svelteStylesRE.test(href)) {
|
||||||
tags.push({
|
tags.push({
|
||||||
|
@ -196,12 +192,6 @@ export async function render(renderers: SSRLoadedRenderer[], mod: ComponentInsta
|
||||||
// add injected tags
|
// add injected tags
|
||||||
let html = injectTags(content.html, 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.?)
|
// inject <!doctype html> if missing (TODO: is a more robust check needed for comments, etc.?)
|
||||||
if (!/<!doctype html/i.test(html)) {
|
if (!/<!doctype html/i.test(html)) {
|
||||||
html = '<!DOCTYPE html>\n' + content;
|
html = '<!DOCTYPE html>\n' + content;
|
||||||
|
|
|
@ -158,6 +158,7 @@ ${extra}`
|
||||||
// Ensure this API is not exposed to users
|
// Ensure this API is not exposed to users
|
||||||
enumerable: false,
|
enumerable: false,
|
||||||
writable: 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
|
// <Markdown> also needs the same `astroConfig.markdownOptions.render` as `.md` pages
|
||||||
value: async function (content: string, opts: any) {
|
value: async function (content: string, opts: any) {
|
||||||
let [mdRender, renderOpts] = markdownRender;
|
let [mdRender, renderOpts] = markdownRender;
|
||||||
|
|
|
@ -87,7 +87,7 @@ export function generateRSSStylesheet() {
|
||||||
export function generateRssFunction(site: string | undefined, route: RouteData): RSSFunction {
|
export function generateRssFunction(site: string | undefined, route: RouteData): RSSFunction {
|
||||||
return function rssUtility(args: RSS): RSSResult {
|
return function rssUtility(args: RSS): RSSResult {
|
||||||
if (!site) {
|
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;
|
let result: RSSResult = {} as any;
|
||||||
const { dest, ...rssData } = args;
|
const { dest, ...rssData } = args;
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -7,6 +7,7 @@ import { compile } from 'path-to-regexp';
|
||||||
import slash from 'slash';
|
import slash from 'slash';
|
||||||
import { fileURLToPath } from 'url';
|
import { fileURLToPath } from 'url';
|
||||||
import { warn } from '../../logger/core.js';
|
import { warn } from '../../logger/core.js';
|
||||||
|
import { resolvePages } from '../../util.js';
|
||||||
|
|
||||||
interface Part {
|
interface Part {
|
||||||
content: string;
|
content: string;
|
||||||
|
@ -55,7 +56,7 @@ function getParts(part: string, file: string) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPattern(segments: Part[][], addTrailingSlash: AstroConfig['devOptions']['trailingSlash']) {
|
function getPattern(segments: Part[][], addTrailingSlash: AstroConfig['trailingSlash']) {
|
||||||
const pathname = segments
|
const pathname = segments
|
||||||
.map((segment) => {
|
.map((segment) => {
|
||||||
return segment[0].spread
|
return segment[0].spread
|
||||||
|
@ -82,7 +83,7 @@ function getPattern(segments: Part[][], addTrailingSlash: AstroConfig['devOption
|
||||||
return new RegExp(`^${pathname || '\\/'}${trailing}`);
|
return new RegExp(`^${pathname || '\\/'}${trailing}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTrailingSlashPattern(addTrailingSlash: AstroConfig['devOptions']['trailingSlash']): string {
|
function getTrailingSlashPattern(addTrailingSlash: AstroConfig['trailingSlash']): string {
|
||||||
if (addTrailingSlash === 'always') {
|
if (addTrailingSlash === 'always') {
|
||||||
return '\\/$';
|
return '\\/$';
|
||||||
}
|
}
|
||||||
|
@ -92,7 +93,7 @@ function getTrailingSlashPattern(addTrailingSlash: AstroConfig['devOptions']['tr
|
||||||
return '\\/?$';
|
return '\\/?$';
|
||||||
}
|
}
|
||||||
|
|
||||||
function getGenerator(segments: Part[][], addTrailingSlash: AstroConfig['devOptions']['trailingSlash']) {
|
function getGenerator(segments: Part[][], addTrailingSlash: AstroConfig['trailingSlash']) {
|
||||||
const template = segments
|
const template = segments
|
||||||
.map((segment) => {
|
.map((segment) => {
|
||||||
return segment[0].spread
|
return segment[0].spread
|
||||||
|
@ -177,7 +178,7 @@ export function createRouteManifest({ config, cwd }: { config: AstroConfig; cwd?
|
||||||
let items: Item[] = [];
|
let items: Item[] = [];
|
||||||
fs.readdirSync(dir).forEach((basename) => {
|
fs.readdirSync(dir).forEach((basename) => {
|
||||||
const resolved = path.join(dir, 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 isDir = fs.statSync(resolved).isDirectory();
|
||||||
|
|
||||||
const ext = path.extname(basename);
|
const ext = path.extname(basename);
|
||||||
|
@ -265,7 +266,7 @@ export function createRouteManifest({ config, cwd }: { config: AstroConfig; cwd?
|
||||||
} else {
|
} else {
|
||||||
components.push(item.file);
|
components.push(item.file);
|
||||||
const component = 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 pattern = getPattern(segments, trailingSlash);
|
||||||
const generate = getGenerator(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;
|
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)) {
|
const pages = resolvePages(config);
|
||||||
walk(fileURLToPath(config.pages), [], []);
|
|
||||||
|
if (fs.existsSync(pages)) {
|
||||||
|
walk(fileURLToPath(pages), [], []);
|
||||||
} else {
|
} 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}`);
|
warn(logging, 'astro', `Missing pages directory: ${pagesDirRootRelative}`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ export function getOutputFilename(astroConfig: AstroConfig, name: string) {
|
||||||
if (name === '/' || name === '') {
|
if (name === '/' || name === '') {
|
||||||
return path.posix.join(name, 'index.html');
|
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 path.posix.join(name, 'index.html');
|
||||||
}
|
}
|
||||||
return `${removeEndingForwardSlash(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) {
|
export function resolveDependency(dep: string, astroConfig: AstroConfig) {
|
||||||
const resolved = resolve.sync(dep, {
|
const resolved = resolve.sync(dep, {
|
||||||
basedir: fileURLToPath(astroConfig.projectRoot),
|
basedir: fileURLToPath(astroConfig.root),
|
||||||
});
|
});
|
||||||
// For Windows compat, we need a fully resolved `file://` URL string
|
// For Windows compat, we need a fully resolved `file://` URL string
|
||||||
return pathToFileURL(resolved).toString();
|
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 {
|
export function isBuildingToSSR(config: AstroConfig): boolean {
|
||||||
const adapter = config._ctx.adapter;
|
const adapter = config._ctx.adapter;
|
||||||
if (!adapter) return false;
|
if (!adapter) return false;
|
||||||
|
|
||||||
if (typeof adapter.serverEntrypoint === 'string') {
|
if (typeof adapter.serverEntrypoint === 'string') {
|
||||||
if (!adapter.name.startsWith('@astrojs/') && !config.buildOptions.experimentalSsr) {
|
if (!adapter.name.startsWith('@astrojs/') && !config.experimental.ssr) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
[
|
[
|
||||||
`Server-side rendering (SSR) is still experimental.`,
|
`Server-side rendering (SSR) is still experimental.`,
|
||||||
|
@ -166,17 +170,7 @@ export function emoji(char: string, fallback: string) {
|
||||||
return process.platform !== 'win32' ? char : fallback;
|
return process.platform !== 'win32' ? char : fallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove once --hostname is baselined
|
export function getLocalAddress(serverAddress: string, host: string | boolean): string {
|
||||||
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);
|
|
||||||
if (typeof host === 'boolean' || host === 'localhost') {
|
if (typeof host === 'boolean' || host === 'localhost') {
|
||||||
return 'localhost';
|
return 'localhost';
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -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[] }) {
|
export async function runHookBuildDone({ config, pages, routes }: { config: AstroConfig; pages: string[]; routes: RouteData[] }) {
|
||||||
for (const integration of config.integrations) {
|
for (const integration of config.integrations) {
|
||||||
if (integration.hooks['astro:build:done']) {
|
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 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -467,6 +467,7 @@ export async function renderHead(result: SSRResult): Promise<string> {
|
||||||
const styles = Array.from(result.styles)
|
const styles = Array.from(result.styles)
|
||||||
.filter(uniqueElements)
|
.filter(uniqueElements)
|
||||||
.map((style) => {
|
.map((style) => {
|
||||||
|
// TODO: clean up legacyBuild from metadata
|
||||||
const styleChildren = !result._metadata.legacyBuild ? '' : style.children;
|
const styleChildren = !result._metadata.legacyBuild ? '' : style.children;
|
||||||
return renderElement('style', {
|
return renderElement('style', {
|
||||||
children: styleChildren,
|
children: styleChildren,
|
||||||
|
|
|
@ -64,7 +64,7 @@ export function subpathNotUsedTemplate(base: string, pathname: string) {
|
||||||
statusCode: 404,
|
statusCode: 404,
|
||||||
title: 'Not found',
|
title: 'Not found',
|
||||||
tabTitle: '404: 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>`,
|
<p>Come to our <a href="https://astro.build/chat">Discord</a> if you need help.</p>`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { debug, info, warn, error, LogOptions } from '../core/logger/core.js';
|
||||||
import { getParamsAndProps, GetParamsAndPropsError } from '../core/render/core.js';
|
import { getParamsAndProps, GetParamsAndPropsError } from '../core/render/core.js';
|
||||||
import { createRouteManifest, matchRoute } from '../core/routing/index.js';
|
import { createRouteManifest, matchRoute } from '../core/routing/index.js';
|
||||||
import stripAnsi from 'strip-ansi';
|
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 { ssr, preload } from '../core/render/dev/index.js';
|
||||||
import { call as callEndpoint } from '../core/endpoint/dev/index.js';
|
import { call as callEndpoint } from '../core/endpoint/dev/index.js';
|
||||||
import * as msg from '../core/messages.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) {
|
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 devRoot = site ? site.pathname : '/';
|
||||||
const pathname = decodeURI(new URL(origin + req.url).pathname);
|
const pathname = decodeURI(new URL(origin + req.url).pathname);
|
||||||
let html = '';
|
let html = '';
|
||||||
|
@ -101,7 +101,7 @@ async function handle500Response(viteServer: vite.ViteDevServer, origin: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCustom404Route(config: AstroConfig, manifest: ManifestData) {
|
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');
|
return manifest.routes.find((r) => r.component === relPages + '404.astro');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@ async function handleRequest(
|
||||||
res: http.ServerResponse
|
res: http.ServerResponse
|
||||||
) {
|
) {
|
||||||
const reqStart = performance.now();
|
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 devRoot = site ? site.pathname : '/';
|
||||||
const origin = `${viteServer.config.server.https ? 'https' : 'http'}://${req.headers.host}`;
|
const origin = `${viteServer.config.server.https ? 'https' : 'http'}://${req.headers.host}`;
|
||||||
const buildingToSSR = isBuildingToSSR(config);
|
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 preloadedComponent = await preload({ astroConfig: config, filePath, viteServer });
|
||||||
const [, mod] = preloadedComponent;
|
const [, mod] = preloadedComponent;
|
||||||
// attempt to get static paths
|
// attempt to get static paths
|
||||||
|
@ -192,7 +192,7 @@ async function handleRequest(
|
||||||
log404(logging, pathname);
|
log404(logging, pathname);
|
||||||
const routeCustom404 = getCustom404Route(config, manifest);
|
const routeCustom404 = getCustom404Route(config, manifest);
|
||||||
if (routeCustom404) {
|
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 preloadedCompCustom404 = await preload({ astroConfig: config, filePath: filePathCustom404, viteServer });
|
||||||
const result = await ssr(preloadedCompCustom404, {
|
const result = await ssr(preloadedCompCustom404, {
|
||||||
astroConfig: config,
|
astroConfig: config,
|
||||||
|
|
|
@ -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> {
|
async function compile(config: AstroConfig, filename: string, source: string, viteTransform: TransformHook, opts: { ssr: boolean }): Promise<CompileResult> {
|
||||||
const filenameURL = new URL(`file://${filename}`);
|
const filenameURL = new URL(`file://${filename}`);
|
||||||
const normalizedID = fileURLToPath(filenameURL);
|
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 rawCSSDeps = new Set<string>();
|
||||||
let cssTransformError: Error | undefined;
|
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.
|
// result passed to esbuild, but also available in the catch handler.
|
||||||
const transformResult = await transform(source, {
|
const transformResult = await transform(source, {
|
||||||
pathname,
|
pathname,
|
||||||
projectRoot: config.projectRoot.toString(),
|
projectRoot: config.root.toString(),
|
||||||
site: config.buildOptions.site,
|
site: config.site ? new URL(config.base, config.site).toString() : undefined,
|
||||||
sourcefile: filename,
|
sourcefile: filename,
|
||||||
sourcemap: 'both',
|
sourcemap: 'both',
|
||||||
internalURL: `/@fs${prependForwardSlash(viteID(new URL('../runtime/server/index.js', import.meta.url)))}`,
|
internalURL: `/@fs${prependForwardSlash(viteID(new URL('../runtime/server/index.js', import.meta.url)))}`,
|
||||||
experimentalStaticExtraction: !config.buildOptions.legacyBuild,
|
// TODO: baseline flag
|
||||||
// TODO add experimental flag here
|
experimentalStaticExtraction: true,
|
||||||
preprocessStyle: async (value: string, attrs: Record<string, string>) => {
|
preprocessStyle: async (value: string, attrs: Record<string, string>) => {
|
||||||
const lang = `.${attrs?.lang || 'css'}`.toLowerCase();
|
const lang = `.${attrs?.lang || 'css'}`.toLowerCase();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// In the static build, grab any @import as CSS dependencies for HMR.
|
// 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) => {
|
||||||
value.replace(/(?:@import)\s(?:url\()?\s?["\'](.*?)["\']\s?\)?(?:[^;]*);?/gi, (match, spec) => {
|
rawCSSDeps.add(spec);
|
||||||
rawCSSDeps.add(spec);
|
// If the language is CSS: prevent `@import` inlining to prevent scoping of imports.
|
||||||
// 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.
|
||||||
// Otherwise: Sass, etc. need to see imports for variables, so leave in for their compiler to handle.
|
if (lang === '.css') {
|
||||||
if (lang === '.css') {
|
return createImportPlaceholder(spec);
|
||||||
return createImportPlaceholder(spec);
|
} else {
|
||||||
} else {
|
return match;
|
||||||
return match;
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await transformWithVite({
|
const result = await transformWithVite({
|
||||||
value,
|
value,
|
||||||
|
|
|
@ -80,10 +80,10 @@ export async function handleHotUpdate(ctx: HmrContext, config: AstroConfig, logg
|
||||||
}
|
}
|
||||||
|
|
||||||
const mod = ctx.modules.find((m) => m.file === ctx.file);
|
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
|
// Note: this intentionally ONLY applies to Astro components
|
||||||
// HMR is handled for other file types by their respective plugins
|
// HMR is handled for other file types by their respective plugins
|
||||||
|
const file = ctx.file.replace(config.root.pathname, '/');
|
||||||
if (ctx.file.endsWith('.astro')) {
|
if (ctx.file.endsWith('.astro')) {
|
||||||
ctx.server.ws.send({ type: 'custom', event: 'astro:update', data: { file } });
|
ctx.server.ws.send({ type: 'custom', event: 'astro:update', data: { file } });
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import ancestor from 'common-ancestor-path';
|
||||||
import { trackCSSDependencies, handleHotUpdate } from './hmr.js';
|
import { trackCSSDependencies, handleHotUpdate } from './hmr.js';
|
||||||
import { isRelativePath, startsWithForwardSlash } from '../core/path.js';
|
import { isRelativePath, startsWithForwardSlash } from '../core/path.js';
|
||||||
import { PAGE_SCRIPT_ID, PAGE_SSR_SCRIPT_ID } from '../vite-plugin-scripts/index.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;
|
const FRONTMATTER_PARSE_REGEXP = /^\-\-\-(.*)^\-\-\-/ms;
|
||||||
interface AstroPluginOptions {
|
interface AstroPluginOptions {
|
||||||
|
@ -26,14 +27,14 @@ export default function astro({ config, logging }: AstroPluginOptions): vite.Plu
|
||||||
function normalizeFilename(filename: string) {
|
function normalizeFilename(filename: string) {
|
||||||
if (filename.startsWith('/@fs')) {
|
if (filename.startsWith('/@fs')) {
|
||||||
filename = filename.slice('/@fs'.length);
|
filename = filename.slice('/@fs'.length);
|
||||||
} else if (filename.startsWith('/') && !ancestor(filename, config.projectRoot.pathname)) {
|
} else if (filename.startsWith('/') && !ancestor(filename, config.root.pathname)) {
|
||||||
filename = new URL('.' + filename, config.projectRoot).pathname;
|
filename = new URL('.' + filename, config.root).pathname;
|
||||||
}
|
}
|
||||||
return filename;
|
return filename;
|
||||||
}
|
}
|
||||||
function relativeToRoot(pathname: string) {
|
function relativeToRoot(pathname: string) {
|
||||||
const arg = startsWithForwardSlash(pathname) ? '.' + pathname : pathname;
|
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;
|
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;
|
let viteDevServer: vite.ViteDevServer | null = null;
|
||||||
|
|
||||||
// Variables for determing if an id starts with /src...
|
// 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);
|
const isBrowserPath = (path: string) => path.startsWith(srcRootWeb);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -94,7 +95,7 @@ export default function astro({ config, logging }: AstroPluginOptions): vite.Plu
|
||||||
const filename = normalizeFilename(parsedId.filename);
|
const filename = normalizeFilename(parsedId.filename);
|
||||||
const fileUrl = new URL(`file://${filename}`);
|
const fileUrl = new URL(`file://${filename}`);
|
||||||
let source = await fs.promises.readFile(fileUrl, 'utf-8');
|
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')) {
|
if (isPage && config._ctx.scripts.some((s) => s.stage === 'page')) {
|
||||||
source += `\n<script src="${PAGE_SCRIPT_ID}" />`;
|
source += `\n<script src="${PAGE_SCRIPT_ID}" />`;
|
||||||
}
|
}
|
||||||
|
@ -130,7 +131,7 @@ export default function astro({ config, logging }: AstroPluginOptions): vite.Plu
|
||||||
if (hoistedScript.type === 'external') {
|
if (hoistedScript.type === 'external') {
|
||||||
const src = hoistedScript.src!;
|
const src = hoistedScript.src!;
|
||||||
if (src.startsWith('/') && !isBrowserPath(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(
|
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}`
|
`\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',
|
sourcemap: 'external',
|
||||||
sourcefile: id,
|
sourcefile: id,
|
||||||
// Pass relevant Vite options, if needed:
|
// Pass relevant Vite options, if needed:
|
||||||
define: config.vite.define,
|
define: config.vite?.define,
|
||||||
});
|
});
|
||||||
|
|
||||||
let SUFFIX = '';
|
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.
|
\`@astrojs/compiler\` encountered an unrecoverable error when compiling the following file.
|
||||||
|
|
||||||
**${id.replace(fileURLToPath(config.projectRoot), '')}**
|
**${id.replace(fileURLToPath(config.root), '')}**
|
||||||
\`\`\`astro
|
\`\`\`astro
|
||||||
${source}
|
${source}
|
||||||
\`\`\`
|
\`\`\`
|
||||||
|
|
|
@ -48,9 +48,9 @@ export function rollupPluginAstroScanHTML(options: PluginOptions): VitePlugin {
|
||||||
const { astroConfig, internals, logging, origin, allPages, routeCache, viteServer, pageNames } = options;
|
const { astroConfig, internals, logging, origin, allPages, routeCache, viteServer, pageNames } = options;
|
||||||
|
|
||||||
// The filepath root of the src folder
|
// The filepath root of the src folder
|
||||||
const srcRoot = astroConfig.src.pathname;
|
const srcRoot = astroConfig.srcDir.pathname;
|
||||||
// The web path of the src folter
|
// 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
|
// A map of pages to rendered HTML
|
||||||
const renderedPageMap = new Map<string, string>();
|
const renderedPageMap = new Map<string, string>();
|
||||||
|
@ -86,7 +86,7 @@ export function rollupPluginAstroScanHTML(options: PluginOptions): VitePlugin {
|
||||||
const id = ASTRO_PAGE_PREFIX + pathname;
|
const id = ASTRO_PAGE_PREFIX + pathname;
|
||||||
const response = await ssrRender(renderers, mod, {
|
const response = await ssrRender(renderers, mod, {
|
||||||
astroConfig,
|
astroConfig,
|
||||||
filePath: new URL(`./${component}`, astroConfig.projectRoot),
|
filePath: new URL(`./${component}`, astroConfig.root),
|
||||||
logging,
|
logging,
|
||||||
request: createRequest({
|
request: createRequest({
|
||||||
url: new URL(origin + pathname),
|
url: new URL(origin + pathname),
|
||||||
|
@ -162,7 +162,7 @@ export function rollupPluginAstroScanHTML(options: PluginOptions): VitePlugin {
|
||||||
if (src?.startsWith(srcRoot) && !astroAssetMap.has(src)) {
|
if (src?.startsWith(srcRoot) && !astroAssetMap.has(src)) {
|
||||||
astroAssetMap.set(src, fs.readFile(new URL(`file://${src}`)));
|
astroAssetMap.set(src, fs.readFile(new URL(`file://${src}`)));
|
||||||
} else if (src?.startsWith(srcRootWeb) && !astroAssetMap.has(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));
|
astroAssetMap.set(src, fs.readFile(resolved));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -173,7 +173,7 @@ export function rollupPluginAstroScanHTML(options: PluginOptions): VitePlugin {
|
||||||
if (url.startsWith(srcRoot) && !astroAssetMap.has(url)) {
|
if (url.startsWith(srcRoot) && !astroAssetMap.has(url)) {
|
||||||
astroAssetMap.set(url, fs.readFile(new URL(`file://${url}`)));
|
astroAssetMap.set(url, fs.readFile(new URL(`file://${url}`)));
|
||||||
} else if (url.startsWith(srcRootWeb) && !astroAssetMap.has(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));
|
astroAssetMap.set(url, fs.readFile(resolved));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -403,7 +403,7 @@ export function rollupPluginAstroScanHTML(options: PluginOptions): VitePlugin {
|
||||||
let src = getAttribute(script, 'src');
|
let src = getAttribute(script, 'src');
|
||||||
// If this is projectRoot relative, get the fullpath to match the facadeId.
|
// If this is projectRoot relative, get the fullpath to match the facadeId.
|
||||||
if (src?.startsWith(srcRootWeb)) {
|
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 :/
|
// On windows the facadeId doesn't start with / but does not Unix :/
|
||||||
if (src && (facadeIdMap.has(src) || facadeIdMap.has(src.substr(1)))) {
|
if (src && (facadeIdMap.has(src) || facadeIdMap.has(src.substr(1)))) {
|
||||||
|
|
|
@ -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. */
|
/** 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. */
|
/** 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 no config alias was found, bypass this plugin
|
||||||
if (!configAlias) return {} as vite.PluginOption;
|
if (!configAlias) return {} as vite.PluginOption;
|
||||||
|
|
|
@ -14,7 +14,7 @@ function getPrivateEnv(viteConfig: vite.ResolvedConfig, astroConfig: AstroConfig
|
||||||
if (viteConfig.envPrefix) {
|
if (viteConfig.envPrefix) {
|
||||||
envPrefixes = Array.isArray(viteConfig.envPrefix) ? viteConfig.envPrefix : [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) => {
|
const privateKeys = Object.keys(fullEnv).filter((key) => {
|
||||||
// don't expose any variables also on `process.env`
|
// don't expose any variables also on `process.env`
|
||||||
// note: this filters out `CLI_ARGS=1` passed to node!
|
// note: this filters out `CLI_ARGS=1` passed to node!
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import astroRemark from '@astrojs/markdown-remark';
|
||||||
import { transform } from '@astrojs/compiler';
|
import { transform } from '@astrojs/compiler';
|
||||||
import ancestor from 'common-ancestor-path';
|
import ancestor from 'common-ancestor-path';
|
||||||
import esbuild from 'esbuild';
|
import esbuild from 'esbuild';
|
||||||
|
@ -8,6 +9,8 @@ import type { Plugin } from 'vite';
|
||||||
import type { AstroConfig } from '../@types/astro';
|
import type { AstroConfig } from '../@types/astro';
|
||||||
import { PAGE_SSR_SCRIPT_ID } from '../vite-plugin-scripts/index.js';
|
import { PAGE_SSR_SCRIPT_ID } from '../vite-plugin-scripts/index.js';
|
||||||
import { virtualModuleId as pagesVirtualModuleId } from '../core/build/vite-plugin-pages.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 {
|
interface AstroPluginOptions {
|
||||||
config: AstroConfig;
|
config: AstroConfig;
|
||||||
|
@ -23,8 +26,8 @@ export default function markdown({ config }: AstroPluginOptions): Plugin {
|
||||||
function normalizeFilename(filename: string) {
|
function normalizeFilename(filename: string) {
|
||||||
if (filename.startsWith('/@fs')) {
|
if (filename.startsWith('/@fs')) {
|
||||||
filename = filename.slice('/@fs'.length);
|
filename = filename.slice('/@fs'.length);
|
||||||
} else if (filename.startsWith('/') && !ancestor(filename, config.projectRoot.pathname)) {
|
} else if (filename.startsWith('/') && !ancestor(filename, config.root.pathname)) {
|
||||||
filename = new URL('.' + filename, config.projectRoot).pathname;
|
filename = new URL('.' + filename, config.root).pathname;
|
||||||
}
|
}
|
||||||
return filename;
|
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
|
// 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.
|
// have `enforce: pre`. This can probably be removed once the vite issue is fixed.
|
||||||
// see: https://github.com/vitejs/vite/issues/5981
|
// 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) {
|
function isRootImport(importer: string | undefined) {
|
||||||
if (!importer) {
|
if (!importer) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -79,7 +82,7 @@ export default function markdown({ config }: AstroPluginOptions): Plugin {
|
||||||
// Return the file's JS representation, including all Markdown
|
// Return the file's JS representation, including all Markdown
|
||||||
// frontmatter and a deferred `import() of the compiled markdown content.
|
// frontmatter and a deferred `import() of the compiled markdown content.
|
||||||
if (id.startsWith(VIRTUAL_MODULE_ID)) {
|
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 fileId = id.substring(VIRTUAL_MODULE_ID.length);
|
||||||
const fileUrl = fileId.includes('/pages/') ? fileId.replace(/^.*\/pages\//, sitePathname).replace(/(\/index)?\.md$/, '') : undefined;
|
const fileUrl = fileId.includes('/pages/') ? fileId.replace(/^.*\/pages\//, sitePathname).replace(/(\/index)?\.md$/, '') : undefined;
|
||||||
const source = await fs.promises.readFile(fileId, 'utf8');
|
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.
|
// This returns the compiled markdown -> astro component that renders to HTML.
|
||||||
if (id.endsWith('.md')) {
|
if (id.endsWith('.md')) {
|
||||||
const source = await fs.promises.readFile(id, 'utf8');
|
const source = await fs.promises.readFile(id, 'utf8');
|
||||||
let render = config.markdownOptions.render;
|
const render = astroRemark;
|
||||||
let renderOpts = {};
|
const renderOpts = config.markdown;
|
||||||
if (Array.isArray(render)) {
|
|
||||||
renderOpts = render[1];
|
|
||||||
render = render[0];
|
|
||||||
}
|
|
||||||
if (typeof render === 'string') {
|
|
||||||
({ default: render } = await import(render));
|
|
||||||
}
|
|
||||||
|
|
||||||
const filename = normalizeFilename(id);
|
const filename = normalizeFilename(id);
|
||||||
const fileUrl = new URL(`file://${filename}`);
|
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');
|
const hasInjectedScript = isPage && config._ctx.scripts.some((s) => s.stage === 'page-ssr');
|
||||||
|
|
||||||
// Extract special frontmatter keys
|
// Extract special frontmatter keys
|
||||||
|
@ -151,9 +147,9 @@ ${setup}`.trim();
|
||||||
|
|
||||||
// Transform from `.astro` to valid `.ts`
|
// Transform from `.astro` to valid `.ts`
|
||||||
let { code: tsResult } = await transform(astroResult, {
|
let { code: tsResult } = await transform(astroResult, {
|
||||||
pathname: fileUrl.pathname.substr(config.projectRoot.pathname.length - 1),
|
pathname: fileUrl.pathname.substr(config.root.pathname.length - 1),
|
||||||
projectRoot: config.projectRoot.toString(),
|
projectRoot: config.root.toString(),
|
||||||
site: config.buildOptions.site,
|
site: config.site ? new URL(config.base, config.site).toString() : undefined,
|
||||||
sourcefile: id,
|
sourcefile: id,
|
||||||
sourcemap: 'inline',
|
sourcemap: 'inline',
|
||||||
internalURL: `/@fs${new URL('../runtime/server/index.js', import.meta.url).pathname}`,
|
internalURL: `/@fs${new URL('../runtime/server/index.js', import.meta.url).pathname}`,
|
||||||
|
|
|
@ -12,7 +12,7 @@ let fixture;
|
||||||
|
|
||||||
describe('CSS', function () {
|
describe('CSS', function () {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({ projectRoot: './fixtures/0-css/' });
|
fixture = await loadFixture({ root: './fixtures/0-css/' });
|
||||||
});
|
});
|
||||||
|
|
||||||
// test HTML and CSS contents for accuracy
|
// test HTML and CSS contents for accuracy
|
||||||
|
|
|
@ -12,7 +12,7 @@ describe('Assets', () => {
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
projectRoot: './fixtures/astro-assets/',
|
root: './fixtures/astro-assets/',
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,7 +6,7 @@ describe('Attributes', async () => {
|
||||||
let fixture;
|
let fixture;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({ projectRoot: './fixtures/astro-attrs/' });
|
fixture = await loadFixture({ root: './fixtures/astro-attrs/' });
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ describe('Astro basics', () => {
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
projectRoot: './fixtures/astro-basic/',
|
root: './fixtures/astro-basic/',
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
previewServer = await fixture.preview();
|
previewServer = await fixture.preview();
|
||||||
|
|
|
@ -6,7 +6,7 @@ describe('Component children', () => {
|
||||||
let fixture;
|
let fixture;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({ projectRoot: './fixtures/astro-children/' });
|
fixture = await loadFixture({ root: './fixtures/astro-children/' });
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ describe('Class List', async () => {
|
||||||
let fixture;
|
let fixture;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({ projectRoot: './fixtures/astro-class-list/' });
|
fixture = await loadFixture({ root: './fixtures/astro-class-list/' });
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ describe('Client only components', () => {
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
projectRoot: './fixtures/astro-client-only/',
|
root: './fixtures/astro-client-only/',
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,7 +6,7 @@ describe('<Code>', () => {
|
||||||
let fixture;
|
let fixture;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({ projectRoot: './fixtures/astro-component-code/' });
|
fixture = await loadFixture({ root: './fixtures/astro-component-code/' });
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ describe('CSS Bundling (ESM import)', () => {
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
projectRoot: './fixtures/astro-css-bundling-import/',
|
root: './fixtures/astro-css-bundling-import/',
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
|
|
@ -16,7 +16,7 @@ describe('CSS Bundling', function () {
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
projectRoot: './fixtures/astro-css-bundling/',
|
root: './fixtures/astro-css-bundling/',
|
||||||
});
|
});
|
||||||
await fixture.build({ mode: 'production' });
|
await fixture.build({ mode: 'production' });
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,7 +6,7 @@ describe('Directives', async () => {
|
||||||
let fixture;
|
let fixture;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({ projectRoot: './fixtures/astro-directives/' });
|
fixture = await loadFixture({ root: './fixtures/astro-directives/' });
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ describe('Doctype', () => {
|
||||||
let fixture;
|
let fixture;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({ projectRoot: './fixtures/astro-doctype/' });
|
fixture = await loadFixture({ root: './fixtures/astro-doctype/' });
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ describe('Dynamic components', () => {
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
projectRoot: './fixtures/astro-dynamic/',
|
root: './fixtures/astro-dynamic/',
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,7 +6,7 @@ describe('Environment Variables', () => {
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
projectRoot: './fixtures/astro-envs/',
|
root: './fixtures/astro-envs/',
|
||||||
});
|
});
|
||||||
|
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
|
|
|
@ -7,7 +7,7 @@ describe('Expressions', () => {
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
projectRoot: './fixtures/astro-expr/',
|
root: './fixtures/astro-expr/',
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { loadFixture } from './test-utils.js';
|
||||||
let fixture;
|
let fixture;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({ projectRoot: './fixtures/astro-external-files/' });
|
fixture = await loadFixture({ root: './fixtures/astro-external-files/' });
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ describe('Dynamic component fallback', () => {
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
projectRoot: './fixtures/astro-fallback',
|
root: './fixtures/astro-fallback',
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,11 +4,9 @@ import { loadFixture } from './test-utils.js';
|
||||||
describe('getStaticPaths - build calls', () => {
|
describe('getStaticPaths - build calls', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
const fixture = await loadFixture({
|
const fixture = await loadFixture({
|
||||||
projectRoot: './fixtures/astro-get-static-paths/',
|
root: './fixtures/astro-get-static-paths/',
|
||||||
buildOptions: {
|
site: 'https://mysite.dev/',
|
||||||
site: 'https://mysite.dev/blog/',
|
base: '/blog',
|
||||||
sitemap: false,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
@ -23,7 +21,7 @@ describe('getStaticPaths - 404 behavior', () => {
|
||||||
let devServer;
|
let devServer;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({ projectRoot: './fixtures/astro-get-static-paths/' });
|
fixture = await loadFixture({ root: './fixtures/astro-get-static-paths/' });
|
||||||
devServer = await fixture.startDevServer();
|
devServer = await fixture.startDevServer();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -7,11 +7,7 @@ describe('Astro.*', () => {
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
projectRoot: './fixtures/astro-global/',
|
root: './fixtures/astro-global/'
|
||||||
buildOptions: {
|
|
||||||
site: 'https://mysite.dev/blog/',
|
|
||||||
sitemap: false,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,12 +7,7 @@ describe('Astro Markdown with draft posts disabled', () => {
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
projectRoot: './fixtures/astro-markdown-drafts/',
|
root: './fixtures/astro-markdown-drafts/',
|
||||||
buildOptions: {
|
|
||||||
// drafts is false by default but added here for clarity
|
|
||||||
drafts: false,
|
|
||||||
sitemap: false,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
@ -30,10 +25,9 @@ describe('Astro Markdown with draft posts enabled', () => {
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
projectRoot: './fixtures/astro-markdown-drafts/',
|
root: './fixtures/astro-markdown-drafts/',
|
||||||
buildOptions: {
|
markdown: {
|
||||||
drafts: true,
|
drafts: true,
|
||||||
sitemap: false,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import cheerio from 'cheerio';
|
import cheerio from 'cheerio';
|
||||||
import { loadFixture } from './test-utils.js';
|
import { loadFixture } from './test-utils.js';
|
||||||
import markdownRemark from '@astrojs/markdown-remark';
|
|
||||||
import addClasses from './fixtures/astro-markdown-plugins/add-classes.mjs';
|
import addClasses from './fixtures/astro-markdown-plugins/add-classes.mjs';
|
||||||
|
|
||||||
describe('Astro Markdown plugins', () => {
|
describe('Astro Markdown plugins', () => {
|
||||||
|
@ -9,18 +8,10 @@ describe('Astro Markdown plugins', () => {
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
projectRoot: './fixtures/astro-markdown-plugins/',
|
root: './fixtures/astro-markdown-plugins/',
|
||||||
markdownOptions: {
|
markdown: {
|
||||||
render: [
|
remarkPlugins: ['remark-code-titles', ['rehype-autolink-headings', { behavior: 'prepend' }]],
|
||||||
markdownRemark,
|
rehypePlugins: [['rehype-toc', { headings: ['h2', 'h3'] }], [addClasses, { 'h1,h2,h3': 'title' }], 'rehype-slug'],
|
||||||
{
|
|
||||||
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,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
|
|
|
@ -7,7 +7,7 @@ describe('Astro Markdown Shiki', () => {
|
||||||
let fixture;
|
let fixture;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({ projectRoot: './fixtures/astro-markdown-shiki/normal/' });
|
fixture = await loadFixture({ root: './fixtures/astro-markdown-shiki/normal/' });
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ describe('Astro Markdown Shiki', () => {
|
||||||
let fixture;
|
let fixture;
|
||||||
|
|
||||||
before(async () => {
|
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();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ describe('Astro Markdown Shiki', () => {
|
||||||
let fixture;
|
let fixture;
|
||||||
|
|
||||||
before(async () => {
|
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();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ describe('Astro Markdown Shiki', () => {
|
||||||
let fixture;
|
let fixture;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({ projectRoot: './fixtures/astro-markdown-shiki/langs/' });
|
fixture = await loadFixture({ root: './fixtures/astro-markdown-shiki/langs/' });
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -130,7 +130,7 @@ describe('Astro Markdown Shiki', () => {
|
||||||
let fixture;
|
let fixture;
|
||||||
|
|
||||||
before(async () => {
|
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();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ describe('Astro Markdown Shiki', () => {
|
||||||
let fixture;
|
let fixture;
|
||||||
|
|
||||||
before(async () => {
|
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();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -183,7 +183,7 @@ describe('Astro Markdown Shiki', () => {
|
||||||
let fixture;
|
let fixture;
|
||||||
|
|
||||||
before(async () => {
|
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();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ describe('Astro Markdown', () => {
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
projectRoot: './fixtures/astro-markdown/',
|
root: './fixtures/astro-markdown/',
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import { loadFixture } from './test-utils.js';
|
import { loadFixture } from './test-utils.js';
|
||||||
|
|
||||||
describe('pageUrlFormat', () => {
|
describe('build format', () => {
|
||||||
let fixture;
|
let fixture;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
projectRoot: './fixtures/astro-page-directory-url',
|
root: './fixtures/astro-page-directory-url',
|
||||||
buildOptions: {
|
build: {
|
||||||
pageUrlFormat: 'file',
|
format: 'file',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
|
|
|
@ -6,7 +6,7 @@ describe('Pages', () => {
|
||||||
let fixture;
|
let fixture;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({ projectRoot: './fixtures/astro-pages/' });
|
fixture = await loadFixture({ root: './fixtures/astro-pages/' });
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -7,11 +7,9 @@ describe('Pagination', () => {
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
projectRoot: './fixtures/astro-pagination/',
|
root: './fixtures/astro-pagination/',
|
||||||
buildOptions: {
|
site: 'https://mysite.dev/',
|
||||||
site: 'https://mysite.dev/blog/',
|
base: '/blog',
|
||||||
sitemap: false,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,7 +8,7 @@ describe('Partial HTML', async () => {
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
projectRoot: './fixtures/astro-partial-html/',
|
root: './fixtures/astro-partial-html/',
|
||||||
});
|
});
|
||||||
devServer = await fixture.startDevServer();
|
devServer = await fixture.startDevServer();
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,7 +5,7 @@ describe('Public', () => {
|
||||||
let fixture;
|
let fixture;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({ projectRoot: './fixtures/astro-public/' });
|
fixture = await loadFixture({ root: './fixtures/astro-public/' });
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ describe('Returning responses', () => {
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
projectRoot: './fixtures/astro-response/',
|
root: './fixtures/astro-response/',
|
||||||
});
|
});
|
||||||
|
|
||||||
devServer = await fixture.startDevServer();
|
devServer = await fixture.startDevServer();
|
||||||
|
|
|
@ -8,7 +8,7 @@ describe('Scripts (hoisted and not)', () => {
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
projectRoot: './fixtures/astro-scripts/',
|
root: './fixtures/astro-scripts/',
|
||||||
vite: {
|
vite: {
|
||||||
build: {
|
build: {
|
||||||
assetsInlineLimit: 0,
|
assetsInlineLimit: 0,
|
||||||
|
|
|
@ -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`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -6,7 +6,7 @@ describe('Slots', () => {
|
||||||
let fixture;
|
let fixture;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({ projectRoot: './fixtures/astro-slots/' });
|
fixture = await loadFixture({ root: './fixtures/astro-slots/' });
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { isIPv4 } from 'net';
|
||||||
describe('astro cli', () => {
|
describe('astro cli', () => {
|
||||||
const cliServerLogSetupWithFixture = (flags, cmd) => {
|
const cliServerLogSetupWithFixture = (flags, cmd) => {
|
||||||
const projectRootURL = new URL('./fixtures/astro-basic/', import.meta.url);
|
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 () => {
|
it('astro', async () => {
|
||||||
|
@ -27,7 +27,7 @@ describe('astro cli', () => {
|
||||||
|
|
||||||
it('astro build', async () => {
|
it('astro build', async () => {
|
||||||
const projectRootURL = new URL('./fixtures/astro-basic/', import.meta.url);
|
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');
|
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 pkgVersion = await fs.readFile(pkgURL, 'utf8').then((data) => JSON.parse(data).version);
|
||||||
|
|
||||||
const projectRootURL = new URL('./fixtures/astro-basic/', import.meta.url);
|
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);
|
const { messages } = await parseCliDevStart(proc);
|
||||||
|
|
||||||
expect(messages[0]).to.contain('astro');
|
expect(messages[0]).to.contain('astro');
|
||||||
|
@ -45,7 +45,7 @@ describe('astro cli', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
['dev', 'preview'].forEach((cmd) => {
|
['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]) => {
|
networkLogFlags.forEach(([flag, flagValue]) => {
|
||||||
it(`astro ${cmd} ${flag} ${flagValue ?? ''} - network log`, async () => {
|
it(`astro ${cmd} ${flag} ${flagValue ?? ''} - network log`, async () => {
|
||||||
const { local, network } = await cliServerLogSetupWithFixture(flagValue ? [flag, flagValue] : [flag], cmd);
|
const { local, network } = await cliServerLogSetupWithFixture(flagValue ? [flag, flagValue] : [flag], cmd);
|
||||||
|
@ -66,7 +66,6 @@ describe('astro cli', () => {
|
||||||
|
|
||||||
const hostToExposeFlags = [
|
const hostToExposeFlags = [
|
||||||
['', ''],
|
['', ''],
|
||||||
['--hostname', 'localhost'],
|
|
||||||
];
|
];
|
||||||
hostToExposeFlags.forEach(([flag, flagValue]) => {
|
hostToExposeFlags.forEach(([flag, flagValue]) => {
|
||||||
it(`astro ${cmd} ${flag} ${flagValue} - host to expose`, async () => {
|
it(`astro ${cmd} ${flag} ${flagValue} - host to expose`, async () => {
|
||||||
|
@ -84,7 +83,6 @@ describe('astro cli', () => {
|
||||||
const noNetworkLogFlags = [
|
const noNetworkLogFlags = [
|
||||||
['--host', 'localhost'],
|
['--host', 'localhost'],
|
||||||
['--host', '127.0.0.1'],
|
['--host', '127.0.0.1'],
|
||||||
['--hostname', '127.0.0.1'],
|
|
||||||
];
|
];
|
||||||
noNetworkLogFlags.forEach(([flag, flagValue]) => {
|
noNetworkLogFlags.forEach(([flag, flagValue]) => {
|
||||||
it(`astro ${cmd} ${flag} ${flagValue} - no network log`, async () => {
|
it(`astro ${cmd} ${flag} ${flagValue} - no network log`, async () => {
|
||||||
|
|
|
@ -10,40 +10,32 @@ describe('Config Validation', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Zod errors are returned when invalid config is used', async () => {
|
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);
|
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 () => {
|
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);
|
expect(configError instanceof z.ZodError).to.equal(true);
|
||||||
const formattedError = stripAnsi(formatConfigErrorMessage(configError));
|
const formattedError = stripAnsi(formatConfigErrorMessage(configError));
|
||||||
expect(formattedError).to.equal(
|
expect(formattedError).to.equal(
|
||||||
`[config] Astro found issue(s) with your configuration:
|
`[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 () => {
|
it('Multiple validation errors can be formatted correctly', async () => {
|
||||||
const veryBadConfig = {
|
const veryBadConfig = {
|
||||||
integrations: [42],
|
integrations: [42],
|
||||||
buildOptions: { pageUrlFormat: 'invalid' },
|
build: { format: 'invalid' },
|
||||||
pages: {},
|
|
||||||
};
|
};
|
||||||
const configError = await validateConfig(veryBadConfig, process.cwd()).catch((err) => err);
|
const configError = await validateConfig(veryBadConfig, process.cwd()).catch((err) => err);
|
||||||
expect(configError instanceof z.ZodError).to.equal(true);
|
expect(configError instanceof z.ZodError).to.equal(true);
|
||||||
const formattedError = stripAnsi(formatConfigErrorMessage(configError));
|
const formattedError = stripAnsi(formatConfigErrorMessage(configError));
|
||||||
expect(formattedError).to.equal(
|
expect(formattedError).to.equal(
|
||||||
`[config] Astro found issue(s) with your configuration:
|
`[config] Astro found issue(s) with your configuration:
|
||||||
! pages Expected string, received object.
|
|
||||||
! integrations.0 Expected object, received number.
|
! 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.');
|
expect(configError.message).to.include('Astro integrations are still experimental.');
|
||||||
});
|
});
|
||||||
it('allows third-party "integration" values with the --experimental-integrations flag', async () => {
|
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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,62 +1,40 @@
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import { cli, loadFixture, cliServerLogSetup } from './test-utils.js';
|
import { loadFixture, cliServerLogSetup } from './test-utils.js';
|
||||||
import { fileURLToPath } from 'url';
|
import { fileURLToPath } from 'url';
|
||||||
import { isIPv4 } from 'net';
|
import { isIPv4 } from 'net';
|
||||||
|
|
||||||
describe('config', () => {
|
describe('config', () => {
|
||||||
let hostnameFixture;
|
|
||||||
let hostFixture;
|
let hostFixture;
|
||||||
let portFixture;
|
let portFixture;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
[hostnameFixture, hostFixture, portFixture] = await Promise.all([
|
[hostFixture, portFixture] = await Promise.all([
|
||||||
loadFixture({
|
loadFixture({
|
||||||
projectRoot: './fixtures/config-host/',
|
root: './fixtures/config-host/',
|
||||||
devOptions: {
|
server: {
|
||||||
hostname: '0.0.0.0',
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
loadFixture({
|
|
||||||
projectRoot: './fixtures/config-host/',
|
|
||||||
devOptions: {
|
|
||||||
host: true,
|
host: true,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
loadFixture({
|
loadFixture({
|
||||||
projectRoot: './fixtures/config-host/',
|
root: './fixtures/config-host/',
|
||||||
devOptions: {
|
server: {
|
||||||
port: 5006,
|
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', () => {
|
describe('host', () => {
|
||||||
it('can be specified in astro.config.mjs', async () => {
|
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 () => {
|
it('can be specified via --host flag', async () => {
|
||||||
const projectRootURL = new URL('./fixtures/astro-basic/', import.meta.url);
|
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);
|
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 () => {
|
it('can be passed via --config', async () => {
|
||||||
const projectRootURL = new URL('./fixtures/astro-basic/', import.meta.url);
|
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 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);
|
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', () => {
|
describe('port', () => {
|
||||||
it('can be specified in astro.config.mjs', async () => {
|
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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -11,7 +11,7 @@ describe.skip('Custom Elements', () => {
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
projectRoot: './fixtures/custom-elements/',
|
root: './fixtures/custom-elements/',
|
||||||
intergrations: ['@test/custom-element-renderer'],
|
intergrations: ['@test/custom-element-renderer'],
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
|
|
|
@ -14,7 +14,7 @@ describe('<Debug />', () => {
|
||||||
let devServer;
|
let devServer;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({ projectRoot: './fixtures/debug-component/' });
|
fixture = await loadFixture({ root: './fixtures/debug-component/' });
|
||||||
devServer = await fixture.startDevServer();
|
devServer = await fixture.startDevServer();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ describe('Development Routing', () => {
|
||||||
let devServer;
|
let devServer;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({ projectRoot: './fixtures/without-site-config/' });
|
fixture = await loadFixture({ root: './fixtures/without-site-config/' });
|
||||||
devServer = await fixture.startDevServer();
|
devServer = await fixture.startDevServer();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -52,11 +52,9 @@ describe('Development Routing', () => {
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
projectRoot: './fixtures/with-subpath-no-trailing-slash/',
|
root: './fixtures/with-subpath-no-trailing-slash/',
|
||||||
dist: './dist-4007',
|
outDir: './dist-4007',
|
||||||
buildOptions: {
|
site: 'http://example.com/',
|
||||||
site: 'http://example.com/',
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
devServer = await fixture.startDevServer();
|
devServer = await fixture.startDevServer();
|
||||||
});
|
});
|
||||||
|
@ -94,11 +92,10 @@ describe('Development Routing', () => {
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
projectRoot: './fixtures/with-subpath-no-trailing-slash/',
|
root: './fixtures/with-subpath-no-trailing-slash/',
|
||||||
dist: './dist-4008',
|
outDir: './dist-4008',
|
||||||
buildOptions: {
|
site: 'http://example.com',
|
||||||
site: 'http://example.com/blog/',
|
base: '/blog',
|
||||||
},
|
|
||||||
});
|
});
|
||||||
devServer = await fixture.startDevServer();
|
devServer = await fixture.startDevServer();
|
||||||
});
|
});
|
||||||
|
@ -146,8 +143,9 @@ describe('Development Routing', () => {
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
projectRoot: './fixtures/with-subpath-no-trailing-slash/',
|
root: './fixtures/with-subpath-no-trailing-slash/',
|
||||||
dist: './dist-4009',
|
base: '/blog',
|
||||||
|
outDir: './dist-4009',
|
||||||
});
|
});
|
||||||
devServer = await fixture.startDevServer();
|
devServer = await fixture.startDevServer();
|
||||||
});
|
});
|
||||||
|
@ -195,10 +193,8 @@ describe('Development Routing', () => {
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
projectRoot: './fixtures/with-endpoint-routes/',
|
root: './fixtures/with-endpoint-routes/',
|
||||||
buildOptions: {
|
site: 'http://example.com/',
|
||||||
site: 'http://example.com/',
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
devServer = await fixture.startDevServer();
|
devServer = await fixture.startDevServer();
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,7 +9,7 @@ describe('Error display', () => {
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
projectRoot: './fixtures/errors',
|
root: './fixtures/errors',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ describe('Global Fetch', () => {
|
||||||
let fixture;
|
let fixture;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({ projectRoot: './fixtures/fetch/' });
|
fixture = await loadFixture({ root: './fixtures/fetch/' });
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
4
packages/astro/test/fixtures/astro-global/astro.config.mjs
vendored
Normal file
4
packages/astro/test/fixtures/astro-global/astro.config.mjs
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
export default {
|
||||||
|
site: 'https://mysite.dev/',
|
||||||
|
base: '/blog'
|
||||||
|
}
|
|
@ -4,7 +4,7 @@ export async function getStaticPaths({paginate}) {
|
||||||
return paginate(data, {pageSize: 1});
|
return paginate(data, {pageSize: 1});
|
||||||
}
|
}
|
||||||
const { page } = Astro.props;
|
const { page } = Astro.props;
|
||||||
const { params, canonicalURL} = Astro;
|
const { params, canonicalURL } = Astro;
|
||||||
---
|
---
|
||||||
|
|
||||||
<html>
|
<html>
|
||||||
|
|
|
@ -3,25 +3,17 @@ const riGrammar = JSON.parse(
|
||||||
);
|
);
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
markdownOptions: {
|
markdown: {
|
||||||
render: [
|
syntaxHighlight: 'shiki',
|
||||||
"@astrojs/markdown-remark",
|
shikiConfig: {
|
||||||
{
|
langs: [
|
||||||
syntaxHighlight: 'shiki',
|
{
|
||||||
shikiConfig: {
|
id: 'rinfo',
|
||||||
langs: [
|
scopeName: 'source.rinfo',
|
||||||
{
|
grammar: riGrammar,
|
||||||
id: 'rinfo',
|
aliases: ['ri'],
|
||||||
scopeName: 'source.rinfo',
|
|
||||||
grammar: riGrammar,
|
|
||||||
aliases: ['ri'],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
},
|
],
|
||||||
],
|
},
|
||||||
},
|
|
||||||
buildOptions: {
|
|
||||||
sitemap: false,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
export default {
|
export default {
|
||||||
markdownOptions: {
|
markdown: {
|
||||||
render: ['@astrojs/markdown-remark', { syntaxHighlight: 'shiki' }],
|
syntaxHighlight: 'shiki',
|
||||||
},
|
|
||||||
buildOptions: {
|
|
||||||
sitemap: false,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,8 @@ const serendipity = JSON.parse(
|
||||||
);
|
);
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
markdownOptions: {
|
markdown: {
|
||||||
render: ["@astrojs/markdown-remark", { syntaxHighlight: 'shiki', shikiConfig: { theme: serendipity } }],
|
syntaxHighlight: 'shiki',
|
||||||
},
|
shikiConfig: { theme: serendipity },
|
||||||
buildOptions: {
|
|
||||||
sitemap: false,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
export default {
|
export default {
|
||||||
markdownOptions: {
|
markdown: {
|
||||||
render: ["@astrojs/markdown-remark", { syntaxHighlight: 'shiki', shikiConfig: { theme: 'github-light' } }],
|
syntaxHighlight: 'shiki',
|
||||||
},
|
shikiConfig: { theme: 'github-light' },
|
||||||
buildOptions: {
|
|
||||||
sitemap: false,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
export default {
|
export default {
|
||||||
markdownOptions: {
|
markdown: {
|
||||||
render: ['@astrojs/markdown-remark', { syntaxHighlight: 'shiki', shikiConfig: { wrap: false } }],
|
syntaxHighlight: 'shiki',
|
||||||
},
|
shikiConfig: { wrap: false },
|
||||||
buildOptions: {
|
|
||||||
sitemap: false,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
export default {
|
export default {
|
||||||
markdownOptions: {
|
markdown: {
|
||||||
render: ['@astrojs/markdown-remark', { syntaxHighlight: 'shiki', shikiConfig: { wrap: null } }],
|
syntaxHighlight: 'shiki',
|
||||||
},
|
shikiConfig: { wrap: null },
|
||||||
buildOptions: {
|
|
||||||
sitemap: false,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
export default {
|
export default {
|
||||||
markdownOptions: {
|
markdown: {
|
||||||
render: ['@astrojs/markdown-remark', { syntaxHighlight: 'shiki', shikiConfig: { wrap: true } }],
|
syntaxHighlight: 'shiki',
|
||||||
},
|
shikiConfig: { wrap: true },
|
||||||
buildOptions: {
|
|
||||||
sitemap: false,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,4 @@ import preact from '@astrojs/preact';
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
integrations: [preact()],
|
integrations: [preact()],
|
||||||
buildOptions: {
|
|
||||||
sitemap: false,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
export default {
|
export default {
|
||||||
devOptions: {
|
server: {
|
||||||
host: true,
|
host: true,
|
||||||
port: 8080,
|
port: 8080,
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,8 +3,5 @@ import preact from '@astrojs/preact';
|
||||||
|
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
buildOptions: {
|
|
||||||
sitemap: false,
|
|
||||||
},
|
|
||||||
integrations: [preact()],
|
integrations: [preact()],
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,10 +4,9 @@ import preact from '@astrojs/preact';
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
integrations: [preact()],
|
integrations: [preact()],
|
||||||
buildOptions: {
|
site: 'http://example.com',
|
||||||
site: 'http://example.com/subpath/',
|
base: '/subpath',
|
||||||
},
|
|
||||||
ssr: {
|
ssr: {
|
||||||
noExternal: ['@test/static-build-pkg'],
|
noExternal: ['@test/static-build-pkg'],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,8 +2,9 @@ import { defineConfig } from 'astro/config';
|
||||||
|
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
buildOptions: {
|
site: 'http://example.com/',
|
||||||
site: 'http://example.com/subpath/',
|
base: '/subpath',
|
||||||
pageUrlFormat: 'file',
|
build: {
|
||||||
|
format: 'file',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
buildOptions: {
|
site: 'http://example.com',
|
||||||
site: 'http://example.com/blog'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -16,7 +16,7 @@ describe('LitElement test', function () {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
projectRoot: './fixtures/lit-element/',
|
root: './fixtures/lit-element/',
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue