Refactor to remove AstroConfig['_ctx'] (#4771)
* Refactor to remove AstroConfig['_ctx'] * Fix type error * Export validateConfig * Move to an options bag for createSettings * Move config tests into test/untils/config * Add a changeste * fix build
This commit is contained in:
parent
48567639e0
commit
f3a81d82f6
44 changed files with 776 additions and 744 deletions
5
.changeset/new-llamas-wash.md
Normal file
5
.changeset/new-llamas-wash.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'astro': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Internal refactor
|
|
@ -11,7 +11,7 @@ import type * as babel from '@babel/core';
|
||||||
import type { AddressInfo } from 'net';
|
import type { AddressInfo } from 'net';
|
||||||
import type { TsConfigJson } from 'tsconfig-resolver';
|
import type { TsConfigJson } from 'tsconfig-resolver';
|
||||||
import type * as vite from 'vite';
|
import type * as vite from 'vite';
|
||||||
import { z } from 'zod';
|
import type { z } from 'zod';
|
||||||
import type { SerializedSSRManifest } from '../core/app/types';
|
import type { SerializedSSRManifest } from '../core/app/types';
|
||||||
import type { PageBuildData } from '../core/build/types';
|
import type { PageBuildData } from '../core/build/types';
|
||||||
import type { AstroConfigSchema } from '../core/config';
|
import type { AstroConfigSchema } from '../core/config';
|
||||||
|
@ -871,20 +871,21 @@ export interface AstroConfig extends z.output<typeof AstroConfigSchema> {
|
||||||
// This is a more detailed type than zod validation gives us.
|
// This is a more detailed type than zod validation gives us.
|
||||||
// TypeScript still confirms zod validation matches this type.
|
// TypeScript still confirms zod validation matches this type.
|
||||||
integrations: AstroIntegration[];
|
integrations: AstroIntegration[];
|
||||||
|
}
|
||||||
|
|
||||||
// Private:
|
export interface AstroSettings {
|
||||||
// We have a need to pass context based on configured state,
|
config: AstroConfig;
|
||||||
// that is different from the user-exposed configuration.
|
|
||||||
// TODO: Create an AstroConfig class to manage this, long-term.
|
adapter: AstroAdapter | undefined;
|
||||||
_ctx: {
|
injectedRoutes: InjectedRoute[];
|
||||||
tsConfig: TsConfigJson | undefined;
|
pageExtensions: string[];
|
||||||
tsConfigPath: string | undefined;
|
renderers: AstroRenderer[];
|
||||||
pageExtensions: string[];
|
scripts: {
|
||||||
injectedRoutes: InjectedRoute[];
|
stage: InjectedScriptStage;
|
||||||
adapter: AstroAdapter | undefined;
|
content: string
|
||||||
renderers: AstroRenderer[];
|
}[];
|
||||||
scripts: { stage: InjectedScriptStage; content: string }[];
|
tsConfig: TsConfigJson | undefined;
|
||||||
};
|
tsConfigPath: string | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AsyncRendererComponentFn<U> = (
|
export type AsyncRendererComponentFn<U> = (
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* eslint-disable no-console */
|
/* eslint-disable no-console */
|
||||||
import { AstroCheck, DiagnosticSeverity } from '@astrojs/language-server';
|
import { AstroCheck, DiagnosticSeverity } from '@astrojs/language-server';
|
||||||
import type { AstroConfig } from '../../@types/astro';
|
import type { AstroSettings } from '../../@types/astro';
|
||||||
|
|
||||||
import glob from 'fast-glob';
|
import glob from 'fast-glob';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
|
@ -16,10 +16,10 @@ interface Result {
|
||||||
hints: number;
|
hints: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function check(astroConfig: AstroConfig) {
|
export async function check(settings: AstroSettings) {
|
||||||
console.log(bold('astro check'));
|
console.log(bold('astro check'));
|
||||||
|
|
||||||
const root = astroConfig.root;
|
const root = settings.config.root;
|
||||||
|
|
||||||
const spinner = ora(` Getting diagnostics for Astro files in ${fileURLToPath(root)}…`).start();
|
const spinner = ora(` Getting diagnostics for Astro files in ${fileURLToPath(root)}…`).start();
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import yargs from 'yargs-parser';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import add from '../core/add/index.js';
|
import add from '../core/add/index.js';
|
||||||
import build from '../core/build/index.js';
|
import build from '../core/build/index.js';
|
||||||
import { openConfig, resolveConfigPath, resolveFlags, resolveRoot } from '../core/config.js';
|
import { openConfig, resolveConfigPath, resolveFlags, resolveRoot, createSettings, loadTSConfig } from '../core/config/index.js';
|
||||||
import devServer from '../core/dev/index.js';
|
import devServer from '../core/dev/index.js';
|
||||||
import { collectErrorMetadata } from '../core/errors.js';
|
import { collectErrorMetadata } from '../core/errors.js';
|
||||||
import { debug, error, info, LogOptions } from '../core/logger/core.js';
|
import { debug, error, info, LogOptions } from '../core/logger/core.js';
|
||||||
|
@ -150,7 +150,7 @@ async function runCommand(cmd: string, flags: yargs.Arguments) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let { astroConfig, userConfig } = await openConfig({
|
let { astroConfig: initialAstroConfig, userConfig: initialUserConfig } = await openConfig({
|
||||||
cwd: root,
|
cwd: root,
|
||||||
flags,
|
flags,
|
||||||
cmd,
|
cmd,
|
||||||
|
@ -159,8 +159,14 @@ async function runCommand(cmd: string, flags: yargs.Arguments) {
|
||||||
await handleConfigError(e, { cwd: root, flags, logging });
|
await handleConfigError(e, { cwd: root, flags, logging });
|
||||||
return {} as any;
|
return {} as any;
|
||||||
});
|
});
|
||||||
if (!astroConfig) return;
|
if (!initialAstroConfig) return;
|
||||||
telemetry.record(event.eventCliSession(cmd, userConfig, flags));
|
telemetry.record(event.eventCliSession(cmd, initialUserConfig, flags));
|
||||||
|
let initialTsConfig = loadTSConfig(root);
|
||||||
|
let settings = createSettings({
|
||||||
|
config: initialAstroConfig,
|
||||||
|
tsConfig: initialTsConfig?.config,
|
||||||
|
tsConfigPath: initialTsConfig?.path,
|
||||||
|
});
|
||||||
|
|
||||||
// Common CLI Commands:
|
// Common CLI Commands:
|
||||||
// These commands run normally. All commands are assumed to have been handled
|
// These commands run normally. All commands are assumed to have been handled
|
||||||
|
@ -168,7 +174,7 @@ async function runCommand(cmd: string, flags: yargs.Arguments) {
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case 'dev': {
|
case 'dev': {
|
||||||
async function startDevServer({ isRestart = false }: { isRestart?: boolean } = {}) {
|
async function startDevServer({ isRestart = false }: { isRestart?: boolean } = {}) {
|
||||||
const { watcher, stop } = await devServer(astroConfig, { logging, telemetry, isRestart });
|
const { watcher, stop } = await devServer(settings, { logging, telemetry, isRestart });
|
||||||
let restartInFlight = false;
|
let restartInFlight = false;
|
||||||
const configFlag = resolveFlags(flags).config;
|
const configFlag = resolveFlags(flags).config;
|
||||||
const configFlagPath = configFlag
|
const configFlagPath = configFlag
|
||||||
|
@ -199,7 +205,13 @@ async function runCommand(cmd: string, flags: yargs.Arguments) {
|
||||||
isConfigReload: true,
|
isConfigReload: true,
|
||||||
});
|
});
|
||||||
info(logging, 'astro', logMsg + '\n');
|
info(logging, 'astro', logMsg + '\n');
|
||||||
astroConfig = newConfig.astroConfig;
|
let astroConfig = newConfig.astroConfig;
|
||||||
|
let tsconfig = loadTSConfig(root);
|
||||||
|
settings = createSettings({
|
||||||
|
config: astroConfig,
|
||||||
|
tsConfig: tsconfig?.config,
|
||||||
|
tsConfigPath: tsconfig?.path
|
||||||
|
});
|
||||||
await stop();
|
await stop();
|
||||||
await startDevServer({ isRestart: true });
|
await startDevServer({ isRestart: true });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -220,16 +232,16 @@ async function runCommand(cmd: string, flags: yargs.Arguments) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'build': {
|
case 'build': {
|
||||||
return await build(astroConfig, { logging, telemetry });
|
return await build(settings, { logging, telemetry });
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'check': {
|
case 'check': {
|
||||||
const ret = await check(astroConfig);
|
const ret = await check(settings);
|
||||||
return process.exit(ret);
|
return process.exit(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'preview': {
|
case 'preview': {
|
||||||
const server = await preview(astroConfig, { logging, telemetry });
|
const server = await preview(settings, { logging, telemetry });
|
||||||
return await server.closed(); // keep alive until the server is closed
|
return await server.closed(); // keep alive until the server is closed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ import preferredPM from 'preferred-pm';
|
||||||
import prompts from 'prompts';
|
import prompts from 'prompts';
|
||||||
import { fileURLToPath, pathToFileURL } from 'url';
|
import { fileURLToPath, pathToFileURL } from 'url';
|
||||||
import type yargs from 'yargs-parser';
|
import type yargs from 'yargs-parser';
|
||||||
import { resolveConfigPath } from '../config.js';
|
import { resolveConfigPath } from '../config/index.js';
|
||||||
import { debug, info, LogOptions } from '../logger/core.js';
|
import { debug, info, LogOptions } from '../logger/core.js';
|
||||||
import * as msg from '../messages.js';
|
import * as msg from '../messages.js';
|
||||||
import { printHelp } from '../messages.js';
|
import { printHelp } from '../messages.js';
|
||||||
|
|
|
@ -6,6 +6,7 @@ import type { OutputAsset, OutputChunk } from 'rollup';
|
||||||
import { fileURLToPath } from 'url';
|
import { fileURLToPath } from 'url';
|
||||||
import type {
|
import type {
|
||||||
AstroConfig,
|
AstroConfig,
|
||||||
|
AstroSettings,
|
||||||
ComponentInstance,
|
ComponentInstance,
|
||||||
EndpointHandler,
|
EndpointHandler,
|
||||||
RouteType,
|
RouteType,
|
||||||
|
@ -62,10 +63,10 @@ function* throttle(max: number, inPaths: string[]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function shouldSkipDraft(pageModule: ComponentInstance, astroConfig: AstroConfig): boolean {
|
function shouldSkipDraft(pageModule: ComponentInstance, settings: AstroSettings): boolean {
|
||||||
return (
|
return (
|
||||||
// Drafts are disabled
|
// Drafts are disabled
|
||||||
!astroConfig.markdown.drafts &&
|
!settings.config.markdown.drafts &&
|
||||||
// This is a draft post
|
// This is a draft post
|
||||||
'frontmatter' in pageModule &&
|
'frontmatter' in pageModule &&
|
||||||
(pageModule as any).frontmatter?.draft === true
|
(pageModule as any).frontmatter?.draft === true
|
||||||
|
@ -74,13 +75,13 @@ function shouldSkipDraft(pageModule: ComponentInstance, astroConfig: AstroConfig
|
||||||
|
|
||||||
// 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, settings: AstroSettings): string {
|
||||||
return facadeId.slice(fileURLToPath(astroConfig.root).length);
|
return facadeId.slice(fileURLToPath(settings.config.root).length);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determines of a Rollup chunk is an entrypoint page.
|
// Determines of a Rollup chunk is an entrypoint page.
|
||||||
export function chunkIsPage(
|
export function chunkIsPage(
|
||||||
astroConfig: AstroConfig,
|
settings: AstroSettings,
|
||||||
output: OutputAsset | OutputChunk,
|
output: OutputAsset | OutputChunk,
|
||||||
internals: BuildInternals
|
internals: BuildInternals
|
||||||
) {
|
) {
|
||||||
|
@ -90,7 +91,7 @@ export function chunkIsPage(
|
||||||
const chunk = output as OutputChunk;
|
const chunk = output as OutputChunk;
|
||||||
if (chunk.facadeModuleId) {
|
if (chunk.facadeModuleId) {
|
||||||
const facadeToEntryId = prependForwardSlash(
|
const facadeToEntryId = prependForwardSlash(
|
||||||
rootRelativeFacadeId(chunk.facadeModuleId, astroConfig)
|
rootRelativeFacadeId(chunk.facadeModuleId, settings)
|
||||||
);
|
);
|
||||||
return internals.entrySpecifierToBundleMap.has(facadeToEntryId);
|
return internals.entrySpecifierToBundleMap.has(facadeToEntryId);
|
||||||
}
|
}
|
||||||
|
@ -101,9 +102,9 @@ export async function generatePages(opts: StaticBuildOptions, internals: BuildIn
|
||||||
const timer = performance.now();
|
const timer = performance.now();
|
||||||
info(opts.logging, null, `\n${bgGreen(black(' generating static routes '))}`);
|
info(opts.logging, null, `\n${bgGreen(black(' generating static routes '))}`);
|
||||||
|
|
||||||
const ssr = opts.astroConfig.output === 'server';
|
const ssr = opts.settings.config.output === 'server';
|
||||||
const serverEntry = opts.buildConfig.serverEntry;
|
const serverEntry = opts.buildConfig.serverEntry;
|
||||||
const outFolder = ssr ? opts.buildConfig.server : getOutDirWithinCwd(opts.astroConfig.outDir);
|
const outFolder = ssr ? opts.buildConfig.server : getOutDirWithinCwd(opts.settings.config.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());
|
||||||
const builtPaths = new Set<string>();
|
const builtPaths = new Set<string>();
|
||||||
|
@ -137,7 +138,7 @@ async function generatePage(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldSkipDraft(pageModule, opts.astroConfig)) {
|
if (shouldSkipDraft(pageModule, opts.settings)) {
|
||||||
info(opts.logging, null, `${magenta('⚠️')} Skipping draft ${pageData.route.component}`);
|
info(opts.logging, null, `${magenta('⚠️')} Skipping draft ${pageData.route.component}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -163,7 +164,7 @@ async function generatePage(
|
||||||
const timeEnd = performance.now();
|
const timeEnd = performance.now();
|
||||||
const timeChange = getTimeStat(timeStart, timeEnd);
|
const timeChange = getTimeStat(timeStart, timeEnd);
|
||||||
const timeIncrease = `(+${timeChange})`;
|
const timeIncrease = `(+${timeChange})`;
|
||||||
const filePath = getOutputFilename(opts.astroConfig, path, pageData.route.type);
|
const filePath = getOutputFilename(opts.settings.config, path, pageData.route.type);
|
||||||
const lineIcon = i === paths.length - 1 ? '└─' : '├─';
|
const lineIcon = i === paths.length - 1 ? '└─' : '├─';
|
||||||
info(opts.logging, null, ` ${cyan(lineIcon)} ${dim(filePath)} ${dim(timeIncrease)}`);
|
info(opts.logging, null, ` ${cyan(lineIcon)} ${dim(filePath)} ${dim(timeIncrease)}`);
|
||||||
}
|
}
|
||||||
|
@ -186,7 +187,7 @@ async function getPathsForRoute(
|
||||||
route: pageData.route,
|
route: pageData.route,
|
||||||
isValidate: false,
|
isValidate: false,
|
||||||
logging: opts.logging,
|
logging: opts.logging,
|
||||||
ssr: opts.astroConfig.output === 'server',
|
ssr: opts.settings.config.output === 'server',
|
||||||
})
|
})
|
||||||
.then((_result) => {
|
.then((_result) => {
|
||||||
const label = _result.staticPaths.length === 1 ? 'page' : 'pages';
|
const label = _result.staticPaths.length === 1 ? 'page' : 'pages';
|
||||||
|
@ -262,8 +263,8 @@ function shouldAppendForwardSlash(
|
||||||
}
|
}
|
||||||
|
|
||||||
function addPageName(pathname: string, opts: StaticBuildOptions): void {
|
function addPageName(pathname: string, opts: StaticBuildOptions): void {
|
||||||
const trailingSlash = opts.astroConfig.trailingSlash;
|
const trailingSlash = opts.settings.config.trailingSlash;
|
||||||
const buildFormat = opts.astroConfig.build.format;
|
const buildFormat = opts.settings.config.build.format;
|
||||||
const pageName = shouldAppendForwardSlash(trailingSlash, buildFormat)
|
const pageName = shouldAppendForwardSlash(trailingSlash, buildFormat)
|
||||||
? pathname.replace(/\/?$/, '/').replace(/^\//, '')
|
? pathname.replace(/\/?$/, '/').replace(/^\//, '')
|
||||||
: pathname.replace(/^\//, '');
|
: pathname.replace(/^\//, '');
|
||||||
|
@ -303,7 +304,7 @@ async function generatePath(
|
||||||
opts: StaticBuildOptions,
|
opts: StaticBuildOptions,
|
||||||
gopts: GeneratePathOptions
|
gopts: GeneratePathOptions
|
||||||
) {
|
) {
|
||||||
const { astroConfig, logging, origin, routeCache } = opts;
|
const { settings, logging, origin, routeCache } = opts;
|
||||||
const { mod, internals, linkIds, scripts: hoistedScripts, pageData, renderers } = gopts;
|
const { mod, internals, linkIds, scripts: hoistedScripts, pageData, renderers } = gopts;
|
||||||
|
|
||||||
// This adds the page name to the array so it can be shown as part of stats.
|
// This adds the page name to the array so it can be shown as part of stats.
|
||||||
|
@ -316,18 +317,18 @@ async function generatePath(
|
||||||
// If a base path was provided, append it to the site URL. This ensures that
|
// If a base path was provided, append it to the site URL. This ensures that
|
||||||
// all injected scripts and links are referenced relative to the site and subpath.
|
// all injected scripts and links are referenced relative to the site and subpath.
|
||||||
const site =
|
const site =
|
||||||
astroConfig.base !== '/'
|
settings.config.base !== '/'
|
||||||
? joinPaths(astroConfig.site?.toString() || 'http://localhost/', astroConfig.base)
|
? joinPaths(settings.config.site?.toString() || 'http://localhost/', settings.config.base)
|
||||||
: astroConfig.site;
|
: settings.config.site;
|
||||||
const links = createLinkStylesheetElementSet(linkIds, site);
|
const links = createLinkStylesheetElementSet(linkIds, site);
|
||||||
const scripts = createModuleScriptsSet(hoistedScripts ? [hoistedScripts] : [], site);
|
const scripts = createModuleScriptsSet(hoistedScripts ? [hoistedScripts] : [], site);
|
||||||
|
|
||||||
if (astroConfig._ctx.scripts.some((script) => script.stage === 'page')) {
|
if (settings.scripts.some((script) => script.stage === 'page')) {
|
||||||
const hashedFilePath = internals.entrySpecifierToBundleMap.get(PAGE_SCRIPT_ID);
|
const hashedFilePath = internals.entrySpecifierToBundleMap.get(PAGE_SCRIPT_ID);
|
||||||
if (typeof hashedFilePath !== 'string') {
|
if (typeof hashedFilePath !== 'string') {
|
||||||
throw new Error(`Cannot find the built path for ${PAGE_SCRIPT_ID}`);
|
throw new Error(`Cannot find the built path for ${PAGE_SCRIPT_ID}`);
|
||||||
}
|
}
|
||||||
const src = prependForwardSlash(npath.posix.join(astroConfig.base, hashedFilePath));
|
const src = prependForwardSlash(npath.posix.join(settings.config.base, hashedFilePath));
|
||||||
scripts.add({
|
scripts.add({
|
||||||
props: { type: 'module', src },
|
props: { type: 'module', src },
|
||||||
children: '',
|
children: '',
|
||||||
|
@ -335,7 +336,7 @@ async function generatePath(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add all injected scripts to the page.
|
// Add all injected scripts to the page.
|
||||||
for (const script of astroConfig._ctx.scripts) {
|
for (const script of settings.scripts) {
|
||||||
if (script.stage === 'head-inline') {
|
if (script.stage === 'head-inline') {
|
||||||
scripts.add({
|
scripts.add({
|
||||||
props: {},
|
props: {},
|
||||||
|
@ -344,12 +345,12 @@ async function generatePath(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ssr = opts.astroConfig.output === 'server';
|
const ssr = settings.config.output === 'server';
|
||||||
const url = getUrlForPath(
|
const url = getUrlForPath(
|
||||||
pathname,
|
pathname,
|
||||||
opts.astroConfig.base,
|
opts.settings.config.base,
|
||||||
origin,
|
origin,
|
||||||
opts.astroConfig.build.format,
|
opts.settings.config.build.format,
|
||||||
pageData.route.type
|
pageData.route.type
|
||||||
);
|
);
|
||||||
const options: RenderOptions = {
|
const options: RenderOptions = {
|
||||||
|
@ -357,8 +358,8 @@ async function generatePath(
|
||||||
links,
|
links,
|
||||||
logging,
|
logging,
|
||||||
markdown: {
|
markdown: {
|
||||||
...astroConfig.markdown,
|
...settings.config.markdown,
|
||||||
isAstroFlavoredMd: astroConfig.legacy.astroFlavoredMarkdown,
|
isAstroFlavoredMd: settings.config.legacy.astroFlavoredMarkdown,
|
||||||
},
|
},
|
||||||
mod,
|
mod,
|
||||||
mode: opts.mode,
|
mode: opts.mode,
|
||||||
|
@ -376,14 +377,14 @@ async function generatePath(
|
||||||
}
|
}
|
||||||
throw new Error(`Cannot find the built path for ${specifier}`);
|
throw new Error(`Cannot find the built path for ${specifier}`);
|
||||||
}
|
}
|
||||||
return prependForwardSlash(npath.posix.join(astroConfig.base, hashedFilePath));
|
return prependForwardSlash(npath.posix.join(settings.config.base, hashedFilePath));
|
||||||
},
|
},
|
||||||
request: createRequest({ url, headers: new Headers(), logging, ssr }),
|
request: createRequest({ url, headers: new Headers(), logging, ssr }),
|
||||||
route: pageData.route,
|
route: pageData.route,
|
||||||
routeCache,
|
routeCache,
|
||||||
site: astroConfig.site
|
site: settings.config.site
|
||||||
? new URL(astroConfig.base, astroConfig.site).toString()
|
? new URL(settings.config.base, settings.config.site).toString()
|
||||||
: astroConfig.site,
|
: settings.config.site,
|
||||||
ssr,
|
ssr,
|
||||||
streaming: true,
|
streaming: true,
|
||||||
};
|
};
|
||||||
|
@ -409,8 +410,8 @@ async function generatePath(
|
||||||
body = await response.text();
|
body = await response.text();
|
||||||
}
|
}
|
||||||
|
|
||||||
const outFolder = getOutFolder(astroConfig, pathname, pageData.route.type);
|
const outFolder = getOutFolder(settings.config, pathname, pageData.route.type);
|
||||||
const outFile = getOutFile(astroConfig, outFolder, pathname, pageData.route.type);
|
const outFile = getOutFile(settings.config, outFolder, pathname, pageData.route.type);
|
||||||
pageData.route.distURL = outFile;
|
pageData.route.distURL = outFile;
|
||||||
await fs.promises.mkdir(outFolder, { recursive: true });
|
await fs.promises.mkdir(outFolder, { recursive: true });
|
||||||
await fs.promises.writeFile(outFile, body, encoding ?? 'utf-8');
|
await fs.promises.writeFile(outFile, body, encoding ?? 'utf-8');
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type { AstroTelemetry } from '@astrojs/telemetry';
|
import type { AstroTelemetry } from '@astrojs/telemetry';
|
||||||
import type { AstroConfig, BuildConfig, ManifestData, RuntimeMode } from '../../@types/astro';
|
import type { AstroSettings, BuildConfig, ManifestData, RuntimeMode } from '../../@types/astro';
|
||||||
import type { LogOptions } from '../logger/core';
|
import type { LogOptions } from '../logger/core';
|
||||||
|
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
|
@ -28,14 +28,14 @@ export interface BuildOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** `astro build` */
|
/** `astro build` */
|
||||||
export default async function build(config: AstroConfig, options: BuildOptions): Promise<void> {
|
export default async function build(settings: AstroSettings, options: BuildOptions): Promise<void> {
|
||||||
applyPolyfill();
|
applyPolyfill();
|
||||||
const builder = new AstroBuilder(config, options);
|
const builder = new AstroBuilder(settings, options);
|
||||||
await builder.run();
|
await builder.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
class AstroBuilder {
|
class AstroBuilder {
|
||||||
private config: AstroConfig;
|
private settings: AstroSettings;
|
||||||
private logging: LogOptions;
|
private logging: LogOptions;
|
||||||
private mode: RuntimeMode = 'production';
|
private mode: RuntimeMode = 'production';
|
||||||
private origin: string;
|
private origin: string;
|
||||||
|
@ -43,16 +43,16 @@ class AstroBuilder {
|
||||||
private manifest: ManifestData;
|
private manifest: ManifestData;
|
||||||
private timer: Record<string, number>;
|
private timer: Record<string, number>;
|
||||||
|
|
||||||
constructor(config: AstroConfig, options: BuildOptions) {
|
constructor(settings: AstroSettings, options: BuildOptions) {
|
||||||
if (options.mode) {
|
if (options.mode) {
|
||||||
this.mode = options.mode;
|
this.mode = options.mode;
|
||||||
}
|
}
|
||||||
this.config = config;
|
this.settings = settings;
|
||||||
this.logging = options.logging;
|
this.logging = options.logging;
|
||||||
this.routeCache = new RouteCache(this.logging);
|
this.routeCache = new RouteCache(this.logging);
|
||||||
this.origin = config.site
|
this.origin = settings.config.site
|
||||||
? new URL(config.site).origin
|
? new URL(settings.config.site).origin
|
||||||
: `http://localhost:${config.server.port}`;
|
: `http://localhost:${settings.config.server.port}`;
|
||||||
this.manifest = { routes: [] };
|
this.manifest = { routes: [] };
|
||||||
this.timer = {};
|
this.timer = {};
|
||||||
}
|
}
|
||||||
|
@ -62,8 +62,8 @@ class AstroBuilder {
|
||||||
debug('build', 'Initial setup...');
|
debug('build', 'Initial setup...');
|
||||||
const { logging } = this;
|
const { logging } = this;
|
||||||
this.timer.init = performance.now();
|
this.timer.init = performance.now();
|
||||||
this.config = await runHookConfigSetup({ config: this.config, command: 'build', logging });
|
this.settings = await runHookConfigSetup({ settings: this.settings, command: 'build', logging });
|
||||||
this.manifest = createRouteManifest({ config: this.config }, this.logging);
|
this.manifest = createRouteManifest({ settings: this.settings }, this.logging);
|
||||||
|
|
||||||
const viteConfig = await createVite(
|
const viteConfig = await createVite(
|
||||||
{
|
{
|
||||||
|
@ -73,29 +73,29 @@ class AstroBuilder {
|
||||||
middlewareMode: true,
|
middlewareMode: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{ astroConfig: this.config, logging, mode: 'build' }
|
{ settings: this.settings, logging, mode: 'build' }
|
||||||
);
|
);
|
||||||
await runHookConfigDone({ config: this.config, logging });
|
await runHookConfigDone({ settings: this.settings, logging });
|
||||||
return { viteConfig };
|
return { viteConfig };
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Run the build logic. build() is marked private because usage should go through ".run()" */
|
/** Run the build logic. build() is marked private because usage should go through ".run()" */
|
||||||
private async build({ viteConfig }: { viteConfig: ViteConfigWithSSR }) {
|
private async build({ viteConfig }: { viteConfig: ViteConfigWithSSR }) {
|
||||||
const buildConfig: BuildConfig = {
|
const buildConfig: BuildConfig = {
|
||||||
client: new URL('./client/', this.config.outDir),
|
client: new URL('./client/', this.settings.config.outDir),
|
||||||
server: new URL('./server/', this.config.outDir),
|
server: new URL('./server/', this.settings.config.outDir),
|
||||||
serverEntry: 'entry.mjs',
|
serverEntry: 'entry.mjs',
|
||||||
};
|
};
|
||||||
await runHookBuildStart({ config: this.config, buildConfig, logging: this.logging });
|
await runHookBuildStart({ config: this.settings.config, buildConfig, logging: this.logging });
|
||||||
|
|
||||||
info(this.logging, 'build', `output target: ${colors.green(this.config.output)}`);
|
info(this.logging, 'build', `output target: ${colors.green(this.settings.config.output)}`);
|
||||||
if (this.config._ctx.adapter) {
|
if (this.settings.adapter) {
|
||||||
info(this.logging, 'build', `deploy adapter: ${colors.green(this.config._ctx.adapter.name)}`);
|
info(this.logging, 'build', `deploy adapter: ${colors.green(this.settings.adapter.name)}`);
|
||||||
}
|
}
|
||||||
info(this.logging, 'build', 'Collecting build info...');
|
info(this.logging, 'build', 'Collecting build info...');
|
||||||
this.timer.loadStart = performance.now();
|
this.timer.loadStart = performance.now();
|
||||||
const { assets, allPages } = await collectPagesData({
|
const { assets, allPages } = await collectPagesData({
|
||||||
astroConfig: this.config,
|
settings: this.settings,
|
||||||
logging: this.logging,
|
logging: this.logging,
|
||||||
manifest: this.manifest,
|
manifest: this.manifest,
|
||||||
});
|
});
|
||||||
|
@ -116,7 +116,7 @@ class AstroBuilder {
|
||||||
|
|
||||||
await staticBuild({
|
await staticBuild({
|
||||||
allPages,
|
allPages,
|
||||||
astroConfig: this.config,
|
settings: this.settings,
|
||||||
logging: this.logging,
|
logging: this.logging,
|
||||||
manifest: this.manifest,
|
manifest: this.manifest,
|
||||||
mode: this.mode,
|
mode: this.mode,
|
||||||
|
@ -140,7 +140,7 @@ class AstroBuilder {
|
||||||
|
|
||||||
// You're done! Time to clean up.
|
// You're done! Time to clean up.
|
||||||
await runHookBuildDone({
|
await runHookBuildDone({
|
||||||
config: this.config,
|
config: this.settings.config,
|
||||||
buildConfig,
|
buildConfig,
|
||||||
pages: pageNames,
|
pages: pageNames,
|
||||||
routes: Object.values(allPages).map((pd) => pd.route),
|
routes: Object.values(allPages).map((pd) => pd.route),
|
||||||
|
@ -152,7 +152,7 @@ class AstroBuilder {
|
||||||
logging: this.logging,
|
logging: this.logging,
|
||||||
timeStart: this.timer.init,
|
timeStart: this.timer.init,
|
||||||
pageCount: pageNames.length,
|
pageCount: pageNames.length,
|
||||||
buildMode: this.config.output,
|
buildMode: this.settings.config.output,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import type { AstroConfig, ManifestData } from '../../@types/astro';
|
import type { AstroSettings, ManifestData } from '../../@types/astro';
|
||||||
import type { LogOptions } from '../logger/core';
|
import type { LogOptions } from '../logger/core';
|
||||||
import { info } from '../logger/core.js';
|
import { info } from '../logger/core.js';
|
||||||
import type { AllPagesData } from './types';
|
import type { AllPagesData } from './types';
|
||||||
|
@ -7,7 +7,7 @@ import * as colors from 'kleur/colors';
|
||||||
import { debug } from '../logger/core.js';
|
import { debug } from '../logger/core.js';
|
||||||
|
|
||||||
export interface CollectPagesDataOptions {
|
export interface CollectPagesDataOptions {
|
||||||
astroConfig: AstroConfig;
|
settings: AstroSettings;
|
||||||
logging: LogOptions;
|
logging: LogOptions;
|
||||||
manifest: ManifestData;
|
manifest: ManifestData;
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ export interface CollectPagesDataResult {
|
||||||
export async function collectPagesData(
|
export async function collectPagesData(
|
||||||
opts: CollectPagesDataOptions
|
opts: CollectPagesDataOptions
|
||||||
): Promise<CollectPagesDataResult> {
|
): Promise<CollectPagesDataResult> {
|
||||||
const { astroConfig, manifest } = opts;
|
const { settings, manifest } = opts;
|
||||||
|
|
||||||
const assets: Record<string, string> = {};
|
const assets: Record<string, string> = {};
|
||||||
const allPages: AllPagesData = {};
|
const allPages: AllPagesData = {};
|
||||||
|
@ -58,7 +58,7 @@ export async function collectPagesData(
|
||||||
};
|
};
|
||||||
|
|
||||||
clearInterval(routeCollectionLogTimeout);
|
clearInterval(routeCollectionLogTimeout);
|
||||||
if (astroConfig.output === 'static') {
|
if (settings.config.output === 'static') {
|
||||||
const html = `${route.pathname}`.replace(/\/?$/, '/index.html');
|
const html = `${route.pathname}`.replace(/\/?$/, '/index.html');
|
||||||
debug(
|
debug(
|
||||||
'build',
|
'build',
|
||||||
|
|
|
@ -23,10 +23,10 @@ import { vitePluginPages } from './vite-plugin-pages.js';
|
||||||
import { injectManifest, vitePluginSSR } from './vite-plugin-ssr.js';
|
import { injectManifest, vitePluginSSR } from './vite-plugin-ssr.js';
|
||||||
|
|
||||||
export async function staticBuild(opts: StaticBuildOptions) {
|
export async function staticBuild(opts: StaticBuildOptions) {
|
||||||
const { allPages, astroConfig } = opts;
|
const { allPages, settings } = opts;
|
||||||
|
|
||||||
// Verify this app is buildable.
|
// Verify this app is buildable.
|
||||||
if (isModeServerWithNoAdapter(opts.astroConfig)) {
|
if (isModeServerWithNoAdapter(opts.settings)) {
|
||||||
throw new Error(`Cannot use \`output: 'server'\` without an adapter.
|
throw new Error(`Cannot use \`output: 'server'\` without an adapter.
|
||||||
Install and configure the appropriate server adapter for your final deployment.
|
Install and configure the appropriate server adapter for your final deployment.
|
||||||
Learn more: https://docs.astro.build/en/guides/server-side-rendering/
|
Learn more: https://docs.astro.build/en/guides/server-side-rendering/
|
||||||
|
@ -55,7 +55,7 @@ Learn more: https://docs.astro.build/en/guides/server-side-rendering/
|
||||||
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.root);
|
const astroModuleURL = new URL('./' + component, settings.config.root);
|
||||||
const astroModuleId = prependForwardSlash(component);
|
const astroModuleId = prependForwardSlash(component);
|
||||||
|
|
||||||
// Track the page data in internals
|
// Track the page data in internals
|
||||||
|
@ -68,15 +68,15 @@ Learn more: https://docs.astro.build/en/guides/server-side-rendering/
|
||||||
// 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.outDir, new Set('.git'));
|
emptyDir(settings.config.outDir, new Set('.git'));
|
||||||
|
|
||||||
// Build your project (SSR application code, assets, client JS, etc.)
|
// Build your project (SSR application code, assets, client JS, etc.)
|
||||||
timer.ssr = performance.now();
|
timer.ssr = performance.now();
|
||||||
info(opts.logging, 'build', `Building ${astroConfig.output} entrypoints...`);
|
info(opts.logging, 'build', `Building ${settings.config.output} entrypoints...`);
|
||||||
await ssrBuild(opts, internals, pageInput);
|
await ssrBuild(opts, internals, pageInput);
|
||||||
info(opts.logging, 'build', dim(`Completed in ${getTimeStat(timer.ssr, performance.now())}.`));
|
info(opts.logging, 'build', dim(`Completed in ${getTimeStat(timer.ssr, performance.now())}.`));
|
||||||
|
|
||||||
const rendererClientEntrypoints = opts.astroConfig._ctx.renderers
|
const rendererClientEntrypoints = settings.renderers
|
||||||
.map((r) => r.clientEntrypoint)
|
.map((r) => r.clientEntrypoint)
|
||||||
.filter((a) => typeof a === 'string') as string[];
|
.filter((a) => typeof a === 'string') as string[];
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ Learn more: https://docs.astro.build/en/guides/server-side-rendering/
|
||||||
...internals.discoveredScripts,
|
...internals.discoveredScripts,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (astroConfig._ctx.scripts.some((script) => script.stage === 'page')) {
|
if (settings.scripts.some((script) => script.stage === 'page')) {
|
||||||
clientInput.add(PAGE_SCRIPT_ID);
|
clientInput.add(PAGE_SCRIPT_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ Learn more: https://docs.astro.build/en/guides/server-side-rendering/
|
||||||
await clientBuild(opts, internals, clientInput);
|
await clientBuild(opts, internals, clientInput);
|
||||||
|
|
||||||
timer.generate = performance.now();
|
timer.generate = performance.now();
|
||||||
if (astroConfig.output === 'static') {
|
if (settings.config.output === 'static') {
|
||||||
await generatePages(opts, internals);
|
await generatePages(opts, internals);
|
||||||
await cleanSsrOutput(opts);
|
await cleanSsrOutput(opts);
|
||||||
} else {
|
} else {
|
||||||
|
@ -109,9 +109,9 @@ Learn more: https://docs.astro.build/en/guides/server-side-rendering/
|
||||||
}
|
}
|
||||||
|
|
||||||
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 { settings, viteConfig } = opts;
|
||||||
const ssr = astroConfig.output === 'server';
|
const ssr = settings.config.output === 'server';
|
||||||
const out = ssr ? opts.buildConfig.server : getOutDirWithinCwd(astroConfig.outDir);
|
const out = ssr ? opts.buildConfig.server : getOutDirWithinCwd(settings.config.outDir);
|
||||||
|
|
||||||
const viteBuildConfig: ViteConfigWithSSR = {
|
const viteBuildConfig: ViteConfigWithSSR = {
|
||||||
...viteConfig,
|
...viteConfig,
|
||||||
|
@ -148,21 +148,20 @@ async function ssrBuild(opts: StaticBuildOptions, internals: BuildInternals, inp
|
||||||
buildOptions: opts,
|
buildOptions: opts,
|
||||||
internals,
|
internals,
|
||||||
target: 'server',
|
target: 'server',
|
||||||
astroConfig,
|
|
||||||
}),
|
}),
|
||||||
...(viteConfig.plugins || []),
|
...(viteConfig.plugins || []),
|
||||||
// SSR needs to be last
|
// SSR needs to be last
|
||||||
opts.astroConfig.output === 'server' &&
|
settings.config.output === 'server' &&
|
||||||
vitePluginSSR(internals, opts.astroConfig._ctx.adapter!),
|
vitePluginSSR(internals, settings.adapter!),
|
||||||
vitePluginAnalyzer(internals),
|
vitePluginAnalyzer(internals),
|
||||||
],
|
],
|
||||||
publicDir: ssr ? false : viteConfig.publicDir,
|
publicDir: ssr ? false : viteConfig.publicDir,
|
||||||
envPrefix: 'PUBLIC_',
|
envPrefix: 'PUBLIC_',
|
||||||
base: astroConfig.base,
|
base: settings.config.base,
|
||||||
};
|
};
|
||||||
|
|
||||||
await runHookBuildSetup({
|
await runHookBuildSetup({
|
||||||
config: astroConfig,
|
config: settings.config,
|
||||||
pages: internals.pagesByComponent,
|
pages: internals.pagesByComponent,
|
||||||
vite: viteBuildConfig,
|
vite: viteBuildConfig,
|
||||||
target: 'server',
|
target: 'server',
|
||||||
|
@ -177,16 +176,16 @@ async function clientBuild(
|
||||||
internals: BuildInternals,
|
internals: BuildInternals,
|
||||||
input: Set<string>
|
input: Set<string>
|
||||||
) {
|
) {
|
||||||
const { astroConfig, viteConfig } = opts;
|
const { settings, viteConfig } = opts;
|
||||||
const timer = performance.now();
|
const timer = performance.now();
|
||||||
const ssr = astroConfig.output === 'server';
|
const ssr = settings.config.output === 'server';
|
||||||
const out = ssr ? opts.buildConfig.client : astroConfig.outDir;
|
const out = ssr ? opts.buildConfig.client : settings.config.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.publicDir, out);
|
await copyFiles(settings.config.publicDir, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -219,21 +218,20 @@ async function clientBuild(
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
vitePluginInternals(input, internals),
|
vitePluginInternals(input, internals),
|
||||||
vitePluginHoistedScripts(astroConfig, internals),
|
vitePluginHoistedScripts(settings, internals),
|
||||||
rollupPluginAstroBuildCSS({
|
rollupPluginAstroBuildCSS({
|
||||||
buildOptions: opts,
|
buildOptions: opts,
|
||||||
internals,
|
internals,
|
||||||
target: 'client',
|
target: 'client',
|
||||||
astroConfig,
|
|
||||||
}),
|
}),
|
||||||
...(viteConfig.plugins || []),
|
...(viteConfig.plugins || []),
|
||||||
],
|
],
|
||||||
envPrefix: 'PUBLIC_',
|
envPrefix: 'PUBLIC_',
|
||||||
base: astroConfig.base,
|
base: settings.config.base,
|
||||||
} as ViteConfigWithSSR;
|
} as ViteConfigWithSSR;
|
||||||
|
|
||||||
await runHookBuildSetup({
|
await runHookBuildSetup({
|
||||||
config: astroConfig,
|
config: settings.config,
|
||||||
pages: internals.pagesByComponent,
|
pages: internals.pagesByComponent,
|
||||||
vite: viteBuildConfig,
|
vite: viteBuildConfig,
|
||||||
target: 'client',
|
target: 'client',
|
||||||
|
@ -246,9 +244,9 @@ async function clientBuild(
|
||||||
}
|
}
|
||||||
|
|
||||||
async function cleanSsrOutput(opts: StaticBuildOptions) {
|
async function cleanSsrOutput(opts: StaticBuildOptions) {
|
||||||
const out = getOutDirWithinCwd(opts.astroConfig.outDir);
|
const out = getOutDirWithinCwd(opts.settings.config.outDir);
|
||||||
// Clean out directly if the outDir is outside of root
|
// Clean out directly if the outDir is outside of root
|
||||||
if (out.toString() !== opts.astroConfig.outDir.toString()) {
|
if (out.toString() !== opts.settings.config.outDir.toString()) {
|
||||||
await fs.promises.rm(out, { recursive: true });
|
await fs.promises.rm(out, { recursive: true });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -284,7 +282,7 @@ async function copyFiles(fromFolder: URL, toFolder: URL) {
|
||||||
async function ssrMoveAssets(opts: StaticBuildOptions) {
|
async function ssrMoveAssets(opts: StaticBuildOptions) {
|
||||||
info(opts.logging, 'build', 'Rearranging server assets...');
|
info(opts.logging, 'build', 'Rearranging server assets...');
|
||||||
const serverRoot =
|
const serverRoot =
|
||||||
opts.astroConfig.output === 'static' ? opts.buildConfig.client : opts.buildConfig.server;
|
opts.settings.config.output === 'static' ? opts.buildConfig.client : opts.buildConfig.server;
|
||||||
const clientRoot = opts.buildConfig.client;
|
const clientRoot = opts.buildConfig.client;
|
||||||
const serverAssets = new URL('./assets/', serverRoot);
|
const serverAssets = new URL('./assets/', serverRoot);
|
||||||
const clientAssets = new URL('./assets/', clientRoot);
|
const clientAssets = new URL('./assets/', clientRoot);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type {
|
import type {
|
||||||
AstroConfig,
|
AstroSettings,
|
||||||
BuildConfig,
|
BuildConfig,
|
||||||
ComponentInstance,
|
ComponentInstance,
|
||||||
ManifestData,
|
ManifestData,
|
||||||
|
@ -26,7 +26,7 @@ export type AllPagesData = Record<ComponentPath, PageBuildData>;
|
||||||
/** Options for the static build */
|
/** Options for the static build */
|
||||||
export interface StaticBuildOptions {
|
export interface StaticBuildOptions {
|
||||||
allPages: AllPagesData;
|
allPages: AllPagesData;
|
||||||
astroConfig: AstroConfig;
|
settings: AstroSettings;
|
||||||
buildConfig: BuildConfig;
|
buildConfig: BuildConfig;
|
||||||
logging: LogOptions;
|
logging: LogOptions;
|
||||||
manifest: ManifestData;
|
manifest: ManifestData;
|
||||||
|
|
|
@ -22,7 +22,6 @@ interface PluginOptions {
|
||||||
internals: BuildInternals;
|
internals: BuildInternals;
|
||||||
buildOptions: StaticBuildOptions;
|
buildOptions: StaticBuildOptions;
|
||||||
target: 'client' | 'server';
|
target: 'client' | 'server';
|
||||||
astroConfig: AstroConfig;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Arbitrary magic number, can change.
|
// Arbitrary magic number, can change.
|
||||||
|
@ -30,13 +29,13 @@ const MAX_NAME_LENGTH = 70;
|
||||||
|
|
||||||
export function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin[] {
|
export function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin[] {
|
||||||
const { internals, buildOptions } = options;
|
const { internals, buildOptions } = options;
|
||||||
const { astroConfig } = buildOptions;
|
const { settings } = buildOptions;
|
||||||
|
|
||||||
let resolvedConfig: ResolvedConfig;
|
let resolvedConfig: ResolvedConfig;
|
||||||
|
|
||||||
// Turn a page location into a name to be used for the CSS file.
|
// Turn a page location into a name to be used for the CSS file.
|
||||||
function nameifyPage(id: string) {
|
function nameifyPage(id: string) {
|
||||||
let rel = relativeToSrcDir(astroConfig, id);
|
let rel = relativeToSrcDir(settings.config, id);
|
||||||
// Remove pages, ex. blog/posts/something.astro
|
// Remove pages, ex. blog/posts/something.astro
|
||||||
if (rel.startsWith('pages/')) {
|
if (rel.startsWith('pages/')) {
|
||||||
rel = rel.slice(6);
|
rel = rel.slice(6);
|
||||||
|
@ -240,7 +239,7 @@ export function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin[]
|
||||||
for (const [, output] of Object.entries(bundle)) {
|
for (const [, output] of Object.entries(bundle)) {
|
||||||
if (output.type === 'asset') {
|
if (output.type === 'asset') {
|
||||||
if (output.name?.endsWith('.css') && typeof output.source === 'string') {
|
if (output.name?.endsWith('.css') && typeof output.source === 'string') {
|
||||||
const cssTarget = options.astroConfig.vite.build?.cssTarget;
|
const cssTarget = settings.config.vite.build?.cssTarget;
|
||||||
const { code: minifiedCSS } = await esbuild.transform(output.source, {
|
const { code: minifiedCSS } = await esbuild.transform(output.source, {
|
||||||
loader: 'css',
|
loader: 'css',
|
||||||
minify: true,
|
minify: true,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type { Plugin as VitePlugin } from 'vite';
|
import type { Plugin as VitePlugin } from 'vite';
|
||||||
import type { AstroConfig } from '../../@types/astro';
|
import type { AstroSettings } from '../../@types/astro';
|
||||||
import type { BuildInternals } from '../../core/build/internal.js';
|
import type { BuildInternals } from '../../core/build/internal.js';
|
||||||
import { viteID } from '../util.js';
|
import { viteID } from '../util.js';
|
||||||
import { getPageDataByViteID } from './internal.js';
|
import { getPageDataByViteID } from './internal.js';
|
||||||
|
@ -9,7 +9,7 @@ function virtualHoistedEntry(id: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function vitePluginHoistedScripts(
|
export function vitePluginHoistedScripts(
|
||||||
astroConfig: AstroConfig,
|
settings: AstroSettings,
|
||||||
internals: BuildInternals
|
internals: BuildInternals
|
||||||
): VitePlugin {
|
): VitePlugin {
|
||||||
return {
|
return {
|
||||||
|
@ -40,7 +40,7 @@ export function vitePluginHoistedScripts(
|
||||||
},
|
},
|
||||||
|
|
||||||
async generateBundle(_options, bundle) {
|
async generateBundle(_options, bundle) {
|
||||||
let assetInlineLimit = astroConfig.vite?.build?.assetsInlineLimit || 4096;
|
let assetInlineLimit = settings.config.vite?.build?.assetsInlineLimit || 4096;
|
||||||
|
|
||||||
// Find all page entry points and create a map of the entry point to the hashed hoisted script.
|
// Find all page entry points and create a map of the entry point to the hashed hoisted script.
|
||||||
// This is used when we render so that we can add the script to the head.
|
// This is used when we render so that we can add the script to the head.
|
||||||
|
@ -58,7 +58,7 @@ export function vitePluginHoistedScripts(
|
||||||
const facadeId = output.facadeModuleId!;
|
const facadeId = output.facadeModuleId!;
|
||||||
const pages = internals.hoistedScriptIdToPagesMap.get(facadeId)!;
|
const pages = internals.hoistedScriptIdToPagesMap.get(facadeId)!;
|
||||||
for (const pathname of pages) {
|
for (const pathname of pages) {
|
||||||
const vid = viteID(new URL('.' + pathname, astroConfig.root));
|
const vid = viteID(new URL('.' + pathname, settings.config.root));
|
||||||
const pageInfo = getPageDataByViteID(internals, vid);
|
const pageInfo = getPageDataByViteID(internals, vid);
|
||||||
if (pageInfo) {
|
if (pageInfo) {
|
||||||
if (canBeInlined) {
|
if (canBeInlined) {
|
||||||
|
|
|
@ -10,7 +10,7 @@ export function vitePluginPages(opts: StaticBuildOptions, internals: BuildIntern
|
||||||
name: '@astro/plugin-build-pages',
|
name: '@astro/plugin-build-pages',
|
||||||
|
|
||||||
options(options) {
|
options(options) {
|
||||||
if (opts.astroConfig.output === 'static') {
|
if (opts.settings.config.output === 'static') {
|
||||||
return addRollupInput(options, [pagesVirtualModuleId]);
|
return addRollupInput(options, [pagesVirtualModuleId]);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -35,7 +35,7 @@ export function vitePluginPages(opts: StaticBuildOptions, internals: BuildIntern
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
let rendererItems = '';
|
let rendererItems = '';
|
||||||
for (const renderer of opts.astroConfig._ctx.renderers) {
|
for (const renderer of opts.settings.renderers) {
|
||||||
const variable = `_renderer${i}`;
|
const variable = `_renderer${i}`;
|
||||||
// Use unshift so that renderers are imported before user code, in case they set globals
|
// Use unshift so that renderers are imported before user code, in case they set globals
|
||||||
// that user code depends on.
|
// that user code depends on.
|
||||||
|
|
|
@ -103,7 +103,7 @@ export async function injectManifest(buildOpts: StaticBuildOptions, internals: B
|
||||||
|
|
||||||
const staticFiles = internals.staticFiles;
|
const staticFiles = internals.staticFiles;
|
||||||
const manifest = buildManifest(buildOpts, internals, Array.from(staticFiles));
|
const manifest = buildManifest(buildOpts, internals, Array.from(staticFiles));
|
||||||
await runHookBuildSsr({ config: buildOpts.astroConfig, manifest, logging: buildOpts.logging });
|
await runHookBuildSsr({ config: buildOpts.settings.config, manifest, logging: buildOpts.logging });
|
||||||
|
|
||||||
const chunk = internals.ssrEntryChunk;
|
const chunk = internals.ssrEntryChunk;
|
||||||
const code = chunk.code;
|
const code = chunk.code;
|
||||||
|
@ -120,11 +120,11 @@ function buildManifest(
|
||||||
internals: BuildInternals,
|
internals: BuildInternals,
|
||||||
staticFiles: string[]
|
staticFiles: string[]
|
||||||
): SerializedSSRManifest {
|
): SerializedSSRManifest {
|
||||||
const { astroConfig } = opts;
|
const { settings } = opts;
|
||||||
|
|
||||||
const routes: SerializedRouteInfo[] = [];
|
const routes: SerializedRouteInfo[] = [];
|
||||||
const entryModules = Object.fromEntries(internals.entrySpecifierToBundleMap.entries());
|
const entryModules = Object.fromEntries(internals.entrySpecifierToBundleMap.entries());
|
||||||
if (astroConfig._ctx.scripts.some((script) => script.stage === 'page')) {
|
if (settings.scripts.some((script) => script.stage === 'page')) {
|
||||||
staticFiles.push(entryModules[PAGE_SCRIPT_ID]);
|
staticFiles.push(entryModules[PAGE_SCRIPT_ID]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,7 +133,7 @@ function buildManifest(
|
||||||
if (pageData.hoistedScript) {
|
if (pageData.hoistedScript) {
|
||||||
scripts.unshift(pageData.hoistedScript);
|
scripts.unshift(pageData.hoistedScript);
|
||||||
}
|
}
|
||||||
if (astroConfig._ctx.scripts.some((script) => script.stage === 'page')) {
|
if (settings.scripts.some((script) => script.stage === 'page')) {
|
||||||
scripts.push({ type: 'external', value: entryModules[PAGE_SCRIPT_ID] });
|
scripts.push({ type: 'external', value: entryModules[PAGE_SCRIPT_ID] });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,11 +142,11 @@ function buildManifest(
|
||||||
links: sortedCSS(pageData),
|
links: sortedCSS(pageData),
|
||||||
scripts: [
|
scripts: [
|
||||||
...scripts,
|
...scripts,
|
||||||
...astroConfig._ctx.scripts
|
...settings.scripts
|
||||||
.filter((script) => script.stage === 'head-inline')
|
.filter((script) => script.stage === 'head-inline')
|
||||||
.map(({ stage, content }) => ({ stage, children: content })),
|
.map(({ stage, content }) => ({ stage, children: content })),
|
||||||
],
|
],
|
||||||
routeData: serializeRouteData(pageData.route, astroConfig.trailingSlash),
|
routeData: serializeRouteData(pageData.route, settings.config.trailingSlash),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,13 +157,13 @@ function buildManifest(
|
||||||
}
|
}
|
||||||
|
|
||||||
const ssrManifest: SerializedSSRManifest = {
|
const ssrManifest: SerializedSSRManifest = {
|
||||||
adapterName: opts.astroConfig._ctx.adapter!.name,
|
adapterName: opts.settings.adapter!.name,
|
||||||
routes,
|
routes,
|
||||||
site: astroConfig.site,
|
site: settings.config.site,
|
||||||
base: astroConfig.base,
|
base: settings.config.base,
|
||||||
markdown: {
|
markdown: {
|
||||||
...astroConfig.markdown,
|
...settings.config.markdown,
|
||||||
isAstroFlavoredMd: astroConfig.legacy.astroFlavoredMarkdown,
|
isAstroFlavoredMd: settings.config.legacy.astroFlavoredMarkdown,
|
||||||
},
|
},
|
||||||
pageMap: null as any,
|
pageMap: null as any,
|
||||||
renderers: [],
|
renderers: [],
|
||||||
|
|
|
@ -1,90 +1,20 @@
|
||||||
import type { RehypePlugin, RemarkPlugin, RemarkRehype } from '@astrojs/markdown-remark';
|
|
||||||
import fs from 'fs';
|
|
||||||
import type * as Postcss from 'postcss';
|
|
||||||
import type { ILanguageRegistration, IThemeRegistration, Theme } from 'shiki';
|
|
||||||
import type { Arguments as Flags } from 'yargs-parser';
|
import type { Arguments as Flags } from 'yargs-parser';
|
||||||
import type { AstroConfig, AstroUserConfig, CLIFlags, ViteUserConfig } from '../@types/astro';
|
import type { AstroConfig, AstroUserConfig, CLIFlags } from '../../@types/astro';
|
||||||
|
|
||||||
|
import fs from 'fs';
|
||||||
import load, { ProloadError, resolve } from '@proload/core';
|
import load, { ProloadError, resolve } from '@proload/core';
|
||||||
import loadTypeScript from '@proload/plugin-tsm';
|
import loadTypeScript from '@proload/plugin-tsm';
|
||||||
import * as colors from 'kleur/colors';
|
import * as colors from 'kleur/colors';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import postcssrc from 'postcss-load-config';
|
|
||||||
import { BUNDLED_THEMES } from 'shiki';
|
|
||||||
import * as tsr from 'tsconfig-resolver';
|
|
||||||
import { fileURLToPath, pathToFileURL } from 'url';
|
import { fileURLToPath, pathToFileURL } from 'url';
|
||||||
import * as vite from 'vite';
|
import * as vite from 'vite';
|
||||||
import { mergeConfig as mergeViteConfig } from 'vite';
|
import { mergeConfig as mergeViteConfig } from 'vite';
|
||||||
import { z } from 'zod';
|
import { LogOptions } from '../logger/core.js';
|
||||||
import jsxRenderer from '../jsx/renderer.js';
|
import { arraify, isObject } from '../util.js';
|
||||||
import { LogOptions } from './logger/core.js';
|
import { createRelativeSchema } from './schema.js';
|
||||||
import { appendForwardSlash, prependForwardSlash, trimSlashes } from './path.js';
|
|
||||||
import { arraify, isObject } from './util.js';
|
|
||||||
|
|
||||||
load.use([loadTypeScript]);
|
load.use([loadTypeScript]);
|
||||||
|
|
||||||
interface PostCSSConfigResult {
|
|
||||||
options: Postcss.ProcessOptions;
|
|
||||||
plugins: Postcss.Plugin[];
|
|
||||||
}
|
|
||||||
|
|
||||||
const ASTRO_CONFIG_DEFAULTS: AstroUserConfig & any = {
|
|
||||||
root: '.',
|
|
||||||
srcDir: './src',
|
|
||||||
publicDir: './public',
|
|
||||||
outDir: './dist',
|
|
||||||
base: '/',
|
|
||||||
trailingSlash: 'ignore',
|
|
||||||
build: { format: 'directory' },
|
|
||||||
server: {
|
|
||||||
host: false,
|
|
||||||
port: 3000,
|
|
||||||
streaming: true,
|
|
||||||
},
|
|
||||||
style: { postcss: { options: {}, plugins: [] } },
|
|
||||||
integrations: [],
|
|
||||||
markdown: {
|
|
||||||
drafts: false,
|
|
||||||
syntaxHighlight: 'shiki',
|
|
||||||
shikiConfig: {
|
|
||||||
langs: [],
|
|
||||||
theme: 'github-dark',
|
|
||||||
wrap: false,
|
|
||||||
},
|
|
||||||
remarkPlugins: [],
|
|
||||||
rehypePlugins: [],
|
|
||||||
remarkRehype: {},
|
|
||||||
},
|
|
||||||
vite: {},
|
|
||||||
legacy: {
|
|
||||||
astroFlavoredMarkdown: false,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
async function resolvePostcssConfig(inlineOptions: any, root: URL): Promise<PostCSSConfigResult> {
|
|
||||||
if (isObject(inlineOptions)) {
|
|
||||||
const options = { ...inlineOptions };
|
|
||||||
delete options.plugins;
|
|
||||||
return {
|
|
||||||
options,
|
|
||||||
plugins: inlineOptions.plugins || [],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
const searchPath = typeof inlineOptions === 'string' ? inlineOptions : fileURLToPath(root);
|
|
||||||
try {
|
|
||||||
// @ts-ignore
|
|
||||||
return await postcssrc({}, searchPath);
|
|
||||||
} catch (err: any) {
|
|
||||||
if (!/No PostCSS Config found/.test(err.message)) {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
options: {},
|
|
||||||
plugins: [],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const LEGACY_ASTRO_CONFIG_KEYS = new Set([
|
export const LEGACY_ASTRO_CONFIG_KEYS = new Set([
|
||||||
'projectRoot',
|
'projectRoot',
|
||||||
'src',
|
'src',
|
||||||
|
@ -97,146 +27,6 @@ export const LEGACY_ASTRO_CONFIG_KEYS = new Set([
|
||||||
'devOptions',
|
'devOptions',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export const AstroConfigSchema = z.object({
|
|
||||||
root: z
|
|
||||||
.string()
|
|
||||||
.optional()
|
|
||||||
.default(ASTRO_CONFIG_DEFAULTS.root)
|
|
||||||
.transform((val) => new URL(val)),
|
|
||||||
srcDir: z
|
|
||||||
.string()
|
|
||||||
.optional()
|
|
||||||
.default(ASTRO_CONFIG_DEFAULTS.srcDir)
|
|
||||||
.transform((val) => new URL(val)),
|
|
||||||
publicDir: z
|
|
||||||
.string()
|
|
||||||
.optional()
|
|
||||||
.default(ASTRO_CONFIG_DEFAULTS.publicDir)
|
|
||||||
.transform((val) => new URL(val)),
|
|
||||||
outDir: z
|
|
||||||
.string()
|
|
||||||
.optional()
|
|
||||||
.default(ASTRO_CONFIG_DEFAULTS.outDir)
|
|
||||||
.transform((val) => new URL(val)),
|
|
||||||
site: z
|
|
||||||
.string()
|
|
||||||
.url()
|
|
||||||
.optional()
|
|
||||||
.transform((val) => (val ? appendForwardSlash(val) : val)),
|
|
||||||
base: z
|
|
||||||
.string()
|
|
||||||
.optional()
|
|
||||||
.default(ASTRO_CONFIG_DEFAULTS.base)
|
|
||||||
.transform((val) => prependForwardSlash(appendForwardSlash(trimSlashes(val)))),
|
|
||||||
trailingSlash: z
|
|
||||||
.union([z.literal('always'), z.literal('never'), z.literal('ignore')])
|
|
||||||
.optional()
|
|
||||||
.default(ASTRO_CONFIG_DEFAULTS.trailingSlash),
|
|
||||||
output: z
|
|
||||||
.union([z.literal('static'), z.literal('server')])
|
|
||||||
.optional()
|
|
||||||
.default('static'),
|
|
||||||
adapter: z.object({ name: z.string(), hooks: z.object({}).passthrough().default({}) }).optional(),
|
|
||||||
integrations: z.preprocess(
|
|
||||||
// preprocess
|
|
||||||
(val) => (Array.isArray(val) ? val.flat(Infinity).filter(Boolean) : val),
|
|
||||||
// validate
|
|
||||||
z
|
|
||||||
.array(z.object({ name: z.string(), hooks: z.object({}).passthrough().default({}) }))
|
|
||||||
.default(ASTRO_CONFIG_DEFAULTS.integrations)
|
|
||||||
),
|
|
||||||
build: z
|
|
||||||
.object({
|
|
||||||
format: z
|
|
||||||
.union([z.literal('file'), z.literal('directory')])
|
|
||||||
.optional()
|
|
||||||
.default(ASTRO_CONFIG_DEFAULTS.build.format),
|
|
||||||
})
|
|
||||||
.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(ASTRO_CONFIG_DEFAULTS.server.host),
|
|
||||||
port: z.number().optional().default(ASTRO_CONFIG_DEFAULTS.server.port),
|
|
||||||
})
|
|
||||||
.optional()
|
|
||||||
.default({})
|
|
||||||
),
|
|
||||||
style: z
|
|
||||||
.object({
|
|
||||||
postcss: z
|
|
||||||
.object({
|
|
||||||
options: z.any(),
|
|
||||||
plugins: z.array(z.any()),
|
|
||||||
})
|
|
||||||
.optional()
|
|
||||||
.default(ASTRO_CONFIG_DEFAULTS.style.postcss),
|
|
||||||
})
|
|
||||||
.optional()
|
|
||||||
.default({}),
|
|
||||||
markdown: z
|
|
||||||
.object({
|
|
||||||
drafts: z.boolean().default(false),
|
|
||||||
syntaxHighlight: z
|
|
||||||
.union([z.literal('shiki'), z.literal('prism'), z.literal(false)])
|
|
||||||
.default(ASTRO_CONFIG_DEFAULTS.markdown.syntaxHighlight),
|
|
||||||
shikiConfig: z
|
|
||||||
.object({
|
|
||||||
langs: z.custom<ILanguageRegistration>().array().default([]),
|
|
||||||
theme: z
|
|
||||||
.enum(BUNDLED_THEMES as [Theme, ...Theme[]])
|
|
||||||
.or(z.custom<IThemeRegistration>())
|
|
||||||
.default(ASTRO_CONFIG_DEFAULTS.markdown.shikiConfig.theme),
|
|
||||||
wrap: z.boolean().or(z.null()).default(ASTRO_CONFIG_DEFAULTS.markdown.shikiConfig.wrap),
|
|
||||||
})
|
|
||||||
.default({}),
|
|
||||||
remarkPlugins: z
|
|
||||||
.union([
|
|
||||||
z.string(),
|
|
||||||
z.tuple([z.string(), z.any()]),
|
|
||||||
z.custom<RemarkPlugin>((data) => typeof data === 'function'),
|
|
||||||
z.tuple([z.custom<RemarkPlugin>((data) => typeof data === 'function'), z.any()]),
|
|
||||||
])
|
|
||||||
.array()
|
|
||||||
.default(ASTRO_CONFIG_DEFAULTS.markdown.remarkPlugins),
|
|
||||||
rehypePlugins: z
|
|
||||||
.union([
|
|
||||||
z.string(),
|
|
||||||
z.tuple([z.string(), z.any()]),
|
|
||||||
z.custom<RehypePlugin>((data) => typeof data === 'function'),
|
|
||||||
z.tuple([z.custom<RehypePlugin>((data) => typeof data === 'function'), z.any()]),
|
|
||||||
])
|
|
||||||
.array()
|
|
||||||
.default(ASTRO_CONFIG_DEFAULTS.markdown.rehypePlugins),
|
|
||||||
remarkRehype: z
|
|
||||||
.custom<RemarkRehype>((data) => data instanceof Object && !Array.isArray(data))
|
|
||||||
.optional()
|
|
||||||
.default(ASTRO_CONFIG_DEFAULTS.markdown.remarkRehype),
|
|
||||||
extendDefaultPlugins: z.boolean().default(false),
|
|
||||||
})
|
|
||||||
.default({}),
|
|
||||||
vite: z
|
|
||||||
.custom<ViteUserConfig>((data) => data instanceof Object && !Array.isArray(data))
|
|
||||||
.default(ASTRO_CONFIG_DEFAULTS.vite),
|
|
||||||
legacy: z
|
|
||||||
.object({
|
|
||||||
astroFlavoredMarkdown: z
|
|
||||||
.boolean()
|
|
||||||
.optional()
|
|
||||||
.default(ASTRO_CONFIG_DEFAULTS.legacy.astroFlavoredMarkdown),
|
|
||||||
})
|
|
||||||
.optional()
|
|
||||||
.default({}),
|
|
||||||
});
|
|
||||||
|
|
||||||
/** Turn raw config values into normalized values */
|
/** Turn raw config values into normalized values */
|
||||||
export async function validateConfig(
|
export async function validateConfig(
|
||||||
|
@ -294,72 +84,10 @@ export async function validateConfig(
|
||||||
}
|
}
|
||||||
/* eslint-enable no-console */
|
/* eslint-enable no-console */
|
||||||
|
|
||||||
// We need to extend the global schema to add transforms that are relative to root.
|
const AstroConfigRelativeSchema = createRelativeSchema(cmd, fileProtocolRoot);
|
||||||
// This is type checked against the global schema to make sure we still match.
|
|
||||||
const AstroConfigRelativeSchema = AstroConfigSchema.extend({
|
|
||||||
root: z
|
|
||||||
.string()
|
|
||||||
.default(ASTRO_CONFIG_DEFAULTS.root)
|
|
||||||
.transform((val) => new URL(appendForwardSlash(val), fileProtocolRoot)),
|
|
||||||
srcDir: z
|
|
||||||
.string()
|
|
||||||
.default(ASTRO_CONFIG_DEFAULTS.srcDir)
|
|
||||||
.transform((val) => new URL(appendForwardSlash(val), fileProtocolRoot)),
|
|
||||||
publicDir: z
|
|
||||||
.string()
|
|
||||||
.default(ASTRO_CONFIG_DEFAULTS.publicDir)
|
|
||||||
.transform((val) => new URL(appendForwardSlash(val), fileProtocolRoot)),
|
|
||||||
outDir: z
|
|
||||||
.string()
|
|
||||||
.default(ASTRO_CONFIG_DEFAULTS.outDir)
|
|
||||||
.transform((val) => new URL(appendForwardSlash(val), fileProtocolRoot)),
|
|
||||||
server: z.preprocess(
|
|
||||||
// preprocess
|
|
||||||
(val) =>
|
|
||||||
typeof val === 'function' ? val({ command: cmd === 'dev' ? 'dev' : 'preview' }) : val,
|
|
||||||
// validate
|
|
||||||
z
|
|
||||||
.object({
|
|
||||||
host: z
|
|
||||||
.union([z.string(), z.boolean()])
|
|
||||||
.optional()
|
|
||||||
.default(ASTRO_CONFIG_DEFAULTS.server.host),
|
|
||||||
port: z.number().optional().default(ASTRO_CONFIG_DEFAULTS.server.port),
|
|
||||||
streaming: z.boolean().optional().default(true),
|
|
||||||
})
|
|
||||||
.optional()
|
|
||||||
.default({})
|
|
||||||
),
|
|
||||||
style: z
|
|
||||||
.object({
|
|
||||||
postcss: z.preprocess(
|
|
||||||
(val) => resolvePostcssConfig(val, fileProtocolRoot),
|
|
||||||
z
|
|
||||||
.object({
|
|
||||||
options: z.any(),
|
|
||||||
plugins: z.array(z.any()),
|
|
||||||
})
|
|
||||||
.optional()
|
|
||||||
.default(ASTRO_CONFIG_DEFAULTS.style.postcss)
|
|
||||||
),
|
|
||||||
})
|
|
||||||
.optional()
|
|
||||||
.default({}),
|
|
||||||
});
|
|
||||||
const tsconfig = loadTSConfig(root);
|
|
||||||
// First-Pass Validation
|
// First-Pass Validation
|
||||||
const result = {
|
const result = await AstroConfigRelativeSchema.parseAsync(userConfig);
|
||||||
...(await AstroConfigRelativeSchema.parseAsync(userConfig)),
|
|
||||||
_ctx: {
|
|
||||||
pageExtensions: ['.astro', '.md', '.html'],
|
|
||||||
tsConfig: tsconfig?.config,
|
|
||||||
tsConfigPath: tsconfig?.path,
|
|
||||||
scripts: [],
|
|
||||||
renderers: [jsxRenderer],
|
|
||||||
injectedRoutes: [],
|
|
||||||
adapter: undefined,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// If successful, return the result as a verified AstroConfig object.
|
// If successful, return the result as a verified AstroConfig object.
|
||||||
return result;
|
return result;
|
||||||
|
@ -554,16 +282,6 @@ async function tryLoadConfig(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadTSConfig(cwd: string | undefined): tsr.TsConfigResult | undefined {
|
|
||||||
for (const searchName of ['tsconfig.json', 'jsconfig.json']) {
|
|
||||||
const config = tsr.tsconfigResolverSync({ cwd, searchName });
|
|
||||||
if (config.exists) {
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempt to load an `astro.config.mjs` file
|
* Attempt to load an `astro.config.mjs` file
|
||||||
* @deprecated
|
* @deprecated
|
20
packages/astro/src/core/config/index.ts
Normal file
20
packages/astro/src/core/config/index.ts
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
|
||||||
|
export type {
|
||||||
|
AstroConfigSchema
|
||||||
|
} from './schema';
|
||||||
|
|
||||||
|
export {
|
||||||
|
openConfig,
|
||||||
|
resolveConfigPath,
|
||||||
|
resolveFlags,
|
||||||
|
resolveRoot,
|
||||||
|
validateConfig,
|
||||||
|
} from './config.js';
|
||||||
|
|
||||||
|
export {
|
||||||
|
createSettings
|
||||||
|
} from './settings.js';
|
||||||
|
|
||||||
|
export {
|
||||||
|
loadTSConfig
|
||||||
|
} from './tsconfig.js';
|
271
packages/astro/src/core/config/schema.ts
Normal file
271
packages/astro/src/core/config/schema.ts
Normal file
|
@ -0,0 +1,271 @@
|
||||||
|
import type { RehypePlugin, RemarkPlugin, RemarkRehype } from '@astrojs/markdown-remark';
|
||||||
|
import type * as Postcss from 'postcss';
|
||||||
|
import type { ILanguageRegistration, IThemeRegistration, Theme } from 'shiki';
|
||||||
|
import type { AstroUserConfig, ViteUserConfig } from '../../@types/astro';
|
||||||
|
|
||||||
|
import postcssrc from 'postcss-load-config';
|
||||||
|
import { BUNDLED_THEMES } from 'shiki';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
import { z } from 'zod';
|
||||||
|
import { appendForwardSlash, prependForwardSlash, trimSlashes } from '../path.js';
|
||||||
|
import { isObject } from '../util.js';
|
||||||
|
|
||||||
|
const ASTRO_CONFIG_DEFAULTS: AstroUserConfig & any = {
|
||||||
|
root: '.',
|
||||||
|
srcDir: './src',
|
||||||
|
publicDir: './public',
|
||||||
|
outDir: './dist',
|
||||||
|
base: '/',
|
||||||
|
trailingSlash: 'ignore',
|
||||||
|
build: { format: 'directory' },
|
||||||
|
server: {
|
||||||
|
host: false,
|
||||||
|
port: 3000,
|
||||||
|
streaming: true,
|
||||||
|
},
|
||||||
|
style: { postcss: { options: {}, plugins: [] } },
|
||||||
|
integrations: [],
|
||||||
|
markdown: {
|
||||||
|
drafts: false,
|
||||||
|
syntaxHighlight: 'shiki',
|
||||||
|
shikiConfig: {
|
||||||
|
langs: [],
|
||||||
|
theme: 'github-dark',
|
||||||
|
wrap: false,
|
||||||
|
},
|
||||||
|
remarkPlugins: [],
|
||||||
|
rehypePlugins: [],
|
||||||
|
remarkRehype: {},
|
||||||
|
},
|
||||||
|
vite: {},
|
||||||
|
legacy: {
|
||||||
|
astroFlavoredMarkdown: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const AstroConfigSchema = z.object({
|
||||||
|
root: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.default(ASTRO_CONFIG_DEFAULTS.root)
|
||||||
|
.transform((val) => new URL(val)),
|
||||||
|
srcDir: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.default(ASTRO_CONFIG_DEFAULTS.srcDir)
|
||||||
|
.transform((val) => new URL(val)),
|
||||||
|
publicDir: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.default(ASTRO_CONFIG_DEFAULTS.publicDir)
|
||||||
|
.transform((val) => new URL(val)),
|
||||||
|
outDir: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.default(ASTRO_CONFIG_DEFAULTS.outDir)
|
||||||
|
.transform((val) => new URL(val)),
|
||||||
|
site: z
|
||||||
|
.string()
|
||||||
|
.url()
|
||||||
|
.optional()
|
||||||
|
.transform((val) => (val ? appendForwardSlash(val) : val)),
|
||||||
|
base: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.default(ASTRO_CONFIG_DEFAULTS.base)
|
||||||
|
.transform((val) => prependForwardSlash(appendForwardSlash(trimSlashes(val)))),
|
||||||
|
trailingSlash: z
|
||||||
|
.union([z.literal('always'), z.literal('never'), z.literal('ignore')])
|
||||||
|
.optional()
|
||||||
|
.default(ASTRO_CONFIG_DEFAULTS.trailingSlash),
|
||||||
|
output: z
|
||||||
|
.union([z.literal('static'), z.literal('server')])
|
||||||
|
.optional()
|
||||||
|
.default('static'),
|
||||||
|
adapter: z.object({ name: z.string(), hooks: z.object({}).passthrough().default({}) }).optional(),
|
||||||
|
integrations: z.preprocess(
|
||||||
|
// preprocess
|
||||||
|
(val) => (Array.isArray(val) ? val.flat(Infinity).filter(Boolean) : val),
|
||||||
|
// validate
|
||||||
|
z
|
||||||
|
.array(z.object({ name: z.string(), hooks: z.object({}).passthrough().default({}) }))
|
||||||
|
.default(ASTRO_CONFIG_DEFAULTS.integrations)
|
||||||
|
),
|
||||||
|
build: z
|
||||||
|
.object({
|
||||||
|
format: z
|
||||||
|
.union([z.literal('file'), z.literal('directory')])
|
||||||
|
.optional()
|
||||||
|
.default(ASTRO_CONFIG_DEFAULTS.build.format),
|
||||||
|
})
|
||||||
|
.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(ASTRO_CONFIG_DEFAULTS.server.host),
|
||||||
|
port: z.number().optional().default(ASTRO_CONFIG_DEFAULTS.server.port),
|
||||||
|
})
|
||||||
|
.optional()
|
||||||
|
.default({})
|
||||||
|
),
|
||||||
|
style: z
|
||||||
|
.object({
|
||||||
|
postcss: z
|
||||||
|
.object({
|
||||||
|
options: z.any(),
|
||||||
|
plugins: z.array(z.any()),
|
||||||
|
})
|
||||||
|
.optional()
|
||||||
|
.default(ASTRO_CONFIG_DEFAULTS.style.postcss),
|
||||||
|
})
|
||||||
|
.optional()
|
||||||
|
.default({}),
|
||||||
|
markdown: z
|
||||||
|
.object({
|
||||||
|
drafts: z.boolean().default(false),
|
||||||
|
syntaxHighlight: z
|
||||||
|
.union([z.literal('shiki'), z.literal('prism'), z.literal(false)])
|
||||||
|
.default(ASTRO_CONFIG_DEFAULTS.markdown.syntaxHighlight),
|
||||||
|
shikiConfig: z
|
||||||
|
.object({
|
||||||
|
langs: z.custom<ILanguageRegistration>().array().default([]),
|
||||||
|
theme: z
|
||||||
|
.enum(BUNDLED_THEMES as [Theme, ...Theme[]])
|
||||||
|
.or(z.custom<IThemeRegistration>())
|
||||||
|
.default(ASTRO_CONFIG_DEFAULTS.markdown.shikiConfig.theme),
|
||||||
|
wrap: z.boolean().or(z.null()).default(ASTRO_CONFIG_DEFAULTS.markdown.shikiConfig.wrap),
|
||||||
|
})
|
||||||
|
.default({}),
|
||||||
|
remarkPlugins: z
|
||||||
|
.union([
|
||||||
|
z.string(),
|
||||||
|
z.tuple([z.string(), z.any()]),
|
||||||
|
z.custom<RemarkPlugin>((data) => typeof data === 'function'),
|
||||||
|
z.tuple([z.custom<RemarkPlugin>((data) => typeof data === 'function'), z.any()]),
|
||||||
|
])
|
||||||
|
.array()
|
||||||
|
.default(ASTRO_CONFIG_DEFAULTS.markdown.remarkPlugins),
|
||||||
|
rehypePlugins: z
|
||||||
|
.union([
|
||||||
|
z.string(),
|
||||||
|
z.tuple([z.string(), z.any()]),
|
||||||
|
z.custom<RehypePlugin>((data) => typeof data === 'function'),
|
||||||
|
z.tuple([z.custom<RehypePlugin>((data) => typeof data === 'function'), z.any()]),
|
||||||
|
])
|
||||||
|
.array()
|
||||||
|
.default(ASTRO_CONFIG_DEFAULTS.markdown.rehypePlugins),
|
||||||
|
remarkRehype: z
|
||||||
|
.custom<RemarkRehype>((data) => data instanceof Object && !Array.isArray(data))
|
||||||
|
.optional()
|
||||||
|
.default(ASTRO_CONFIG_DEFAULTS.markdown.remarkRehype),
|
||||||
|
extendDefaultPlugins: z.boolean().default(false),
|
||||||
|
})
|
||||||
|
.default({}),
|
||||||
|
vite: z
|
||||||
|
.custom<ViteUserConfig>((data) => data instanceof Object && !Array.isArray(data))
|
||||||
|
.default(ASTRO_CONFIG_DEFAULTS.vite),
|
||||||
|
legacy: z
|
||||||
|
.object({
|
||||||
|
astroFlavoredMarkdown: z
|
||||||
|
.boolean()
|
||||||
|
.optional()
|
||||||
|
.default(ASTRO_CONFIG_DEFAULTS.legacy.astroFlavoredMarkdown),
|
||||||
|
})
|
||||||
|
.optional()
|
||||||
|
.default({}),
|
||||||
|
});
|
||||||
|
|
||||||
|
interface PostCSSConfigResult {
|
||||||
|
options: Postcss.ProcessOptions;
|
||||||
|
plugins: Postcss.Plugin[];
|
||||||
|
}
|
||||||
|
|
||||||
|
async function resolvePostcssConfig(inlineOptions: any, root: URL): Promise<PostCSSConfigResult> {
|
||||||
|
if (isObject(inlineOptions)) {
|
||||||
|
const options = { ...inlineOptions };
|
||||||
|
delete options.plugins;
|
||||||
|
return {
|
||||||
|
options,
|
||||||
|
plugins: inlineOptions.plugins || [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const searchPath = typeof inlineOptions === 'string' ? inlineOptions : fileURLToPath(root);
|
||||||
|
try {
|
||||||
|
// @ts-ignore
|
||||||
|
return await postcssrc({}, searchPath);
|
||||||
|
} catch (err: any) {
|
||||||
|
if (!/No PostCSS Config found/.test(err.message)) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
options: {},
|
||||||
|
plugins: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createRelativeSchema(cmd: string, fileProtocolRoot: URL) {
|
||||||
|
// We need to extend the global schema to add transforms that are relative to root.
|
||||||
|
// This is type checked against the global schema to make sure we still match.
|
||||||
|
const AstroConfigRelativeSchema = AstroConfigSchema.extend({
|
||||||
|
root: z
|
||||||
|
.string()
|
||||||
|
.default(ASTRO_CONFIG_DEFAULTS.root)
|
||||||
|
.transform((val) => new URL(appendForwardSlash(val), fileProtocolRoot)),
|
||||||
|
srcDir: z
|
||||||
|
.string()
|
||||||
|
.default(ASTRO_CONFIG_DEFAULTS.srcDir)
|
||||||
|
.transform((val) => new URL(appendForwardSlash(val), fileProtocolRoot)),
|
||||||
|
publicDir: z
|
||||||
|
.string()
|
||||||
|
.default(ASTRO_CONFIG_DEFAULTS.publicDir)
|
||||||
|
.transform((val) => new URL(appendForwardSlash(val), fileProtocolRoot)),
|
||||||
|
outDir: z
|
||||||
|
.string()
|
||||||
|
.default(ASTRO_CONFIG_DEFAULTS.outDir)
|
||||||
|
.transform((val) => new URL(appendForwardSlash(val), fileProtocolRoot)),
|
||||||
|
server: z.preprocess(
|
||||||
|
// preprocess
|
||||||
|
(val) =>
|
||||||
|
typeof val === 'function' ? val({ command: cmd === 'dev' ? 'dev' : 'preview' }) : val,
|
||||||
|
// validate
|
||||||
|
z
|
||||||
|
.object({
|
||||||
|
host: z
|
||||||
|
.union([z.string(), z.boolean()])
|
||||||
|
.optional()
|
||||||
|
.default(ASTRO_CONFIG_DEFAULTS.server.host),
|
||||||
|
port: z.number().optional().default(ASTRO_CONFIG_DEFAULTS.server.port),
|
||||||
|
streaming: z.boolean().optional().default(true),
|
||||||
|
})
|
||||||
|
.optional()
|
||||||
|
.default({})
|
||||||
|
),
|
||||||
|
style: z
|
||||||
|
.object({
|
||||||
|
postcss: z.preprocess(
|
||||||
|
(val) => resolvePostcssConfig(val, fileProtocolRoot),
|
||||||
|
z
|
||||||
|
.object({
|
||||||
|
options: z.any(),
|
||||||
|
plugins: z.array(z.any()),
|
||||||
|
})
|
||||||
|
.optional()
|
||||||
|
.default(ASTRO_CONFIG_DEFAULTS.style.postcss)
|
||||||
|
),
|
||||||
|
})
|
||||||
|
.optional()
|
||||||
|
.default({}),
|
||||||
|
});
|
||||||
|
|
||||||
|
return AstroConfigRelativeSchema;
|
||||||
|
}
|
31
packages/astro/src/core/config/settings.ts
Normal file
31
packages/astro/src/core/config/settings.ts
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import type {
|
||||||
|
AstroConfig,
|
||||||
|
AstroSettings,
|
||||||
|
} from '../../@types/astro';
|
||||||
|
import type { TsConfigJson } from 'tsconfig-resolver';
|
||||||
|
|
||||||
|
import jsxRenderer from '../../jsx/renderer.js';
|
||||||
|
|
||||||
|
export interface CreateSettings {
|
||||||
|
config: AstroConfig;
|
||||||
|
tsConfig?: TsConfigJson;
|
||||||
|
tsConfigPath?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createSettings({
|
||||||
|
config,
|
||||||
|
tsConfig,
|
||||||
|
tsConfigPath,
|
||||||
|
}: CreateSettings): AstroSettings {
|
||||||
|
return {
|
||||||
|
config,
|
||||||
|
tsConfig,
|
||||||
|
tsConfigPath,
|
||||||
|
|
||||||
|
adapter: undefined,
|
||||||
|
injectedRoutes: [],
|
||||||
|
pageExtensions: ['.astro', '.md', '.html'],
|
||||||
|
renderers: [jsxRenderer],
|
||||||
|
scripts: [],
|
||||||
|
};
|
||||||
|
}
|
11
packages/astro/src/core/config/tsconfig.ts
Normal file
11
packages/astro/src/core/config/tsconfig.ts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import * as tsr from 'tsconfig-resolver';
|
||||||
|
|
||||||
|
export function loadTSConfig(cwd: string | undefined): tsr.TsConfigResult | undefined {
|
||||||
|
for (const searchName of ['tsconfig.json', 'jsconfig.json']) {
|
||||||
|
const config = tsr.tsconfigResolverSync({ cwd, searchName });
|
||||||
|
if (config.exists) {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
import type { AstroConfig } from '../@types/astro';
|
import type { AstroSettings } from '../@types/astro';
|
||||||
import type { LogOptions } from './logger/core';
|
import type { LogOptions } from './logger/core';
|
||||||
|
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
|
@ -25,7 +25,7 @@ import { resolveDependency } from './util.js';
|
||||||
export type ViteConfigWithSSR = vite.InlineConfig & { ssr?: vite.SSROptions };
|
export type ViteConfigWithSSR = vite.InlineConfig & { ssr?: vite.SSROptions };
|
||||||
|
|
||||||
interface CreateViteOptions {
|
interface CreateViteOptions {
|
||||||
astroConfig: AstroConfig;
|
settings: AstroSettings;
|
||||||
logging: LogOptions;
|
logging: LogOptions;
|
||||||
mode: 'dev' | 'build' | string;
|
mode: 'dev' | 'build' | string;
|
||||||
}
|
}
|
||||||
|
@ -59,12 +59,12 @@ function getSsrNoExternalDeps(projectRoot: URL): string[] {
|
||||||
/** Return a common starting point for all Vite actions */
|
/** Return a common starting point for all Vite actions */
|
||||||
export async function createVite(
|
export async function createVite(
|
||||||
commandConfig: ViteConfigWithSSR,
|
commandConfig: ViteConfigWithSSR,
|
||||||
{ astroConfig, logging, mode }: CreateViteOptions
|
{ settings, logging, mode }: CreateViteOptions
|
||||||
): Promise<ViteConfigWithSSR> {
|
): Promise<ViteConfigWithSSR> {
|
||||||
const thirdPartyAstroPackages = await getAstroPackages(astroConfig);
|
const thirdPartyAstroPackages = await getAstroPackages(settings);
|
||||||
// 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.root)), // using local caches allows Astro to be used in monorepos, etc.
|
cacheDir: fileURLToPath(new URL('./node_modules/.vite/', settings.config.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
|
||||||
appType: 'custom',
|
appType: 'custom',
|
||||||
|
@ -73,27 +73,27 @@ export async function createVite(
|
||||||
exclude: ['node-fetch'],
|
exclude: ['node-fetch'],
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
configAliasVitePlugin({ config: astroConfig }),
|
configAliasVitePlugin({ settings }),
|
||||||
astroVitePlugin({ config: astroConfig, logging }),
|
astroVitePlugin({ settings, logging }),
|
||||||
astroScriptsPlugin({ config: astroConfig }),
|
astroScriptsPlugin({ settings }),
|
||||||
// The server plugin is for dev only and having it run during the build causes
|
// The server plugin is for dev only and having it run during the build causes
|
||||||
// the build to run very slow as the filewatcher is triggered often.
|
// the build to run very slow as the filewatcher is triggered often.
|
||||||
mode !== 'build' && astroViteServerPlugin({ config: astroConfig, logging }),
|
mode !== 'build' && astroViteServerPlugin({ settings, logging }),
|
||||||
envVitePlugin({ config: astroConfig }),
|
envVitePlugin({ settings }),
|
||||||
astroConfig.legacy.astroFlavoredMarkdown
|
settings.config.legacy.astroFlavoredMarkdown
|
||||||
? legacyMarkdownVitePlugin({ config: astroConfig, logging })
|
? legacyMarkdownVitePlugin({ settings, logging })
|
||||||
: markdownVitePlugin({ config: astroConfig, logging }),
|
: markdownVitePlugin({ settings, logging }),
|
||||||
htmlVitePlugin(),
|
htmlVitePlugin(),
|
||||||
jsxVitePlugin({ config: astroConfig, logging }),
|
jsxVitePlugin({ settings, logging }),
|
||||||
astroPostprocessVitePlugin({ config: astroConfig }),
|
astroPostprocessVitePlugin({ settings }),
|
||||||
astroIntegrationsContainerPlugin({ config: astroConfig, logging }),
|
astroIntegrationsContainerPlugin({ settings, logging }),
|
||||||
astroScriptsPageSSRPlugin({ config: astroConfig }),
|
astroScriptsPageSSRPlugin({ settings }),
|
||||||
],
|
],
|
||||||
publicDir: fileURLToPath(astroConfig.publicDir),
|
publicDir: fileURLToPath(settings.config.publicDir),
|
||||||
root: fileURLToPath(astroConfig.root),
|
root: fileURLToPath(settings.config.root),
|
||||||
envPrefix: 'PUBLIC_',
|
envPrefix: 'PUBLIC_',
|
||||||
define: {
|
define: {
|
||||||
'import.meta.env.SITE': astroConfig.site ? `'${astroConfig.site}'` : 'undefined',
|
'import.meta.env.SITE': settings.config.site ? `'${settings.config.site}'` : 'undefined',
|
||||||
},
|
},
|
||||||
server: {
|
server: {
|
||||||
hmr:
|
hmr:
|
||||||
|
@ -110,7 +110,7 @@ export async function createVite(
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
css: {
|
css: {
|
||||||
postcss: astroConfig.style.postcss || {},
|
postcss: settings.config.style.postcss || {},
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: [
|
alias: [
|
||||||
|
@ -129,7 +129,7 @@ export async function createVite(
|
||||||
conditions: ['astro'],
|
conditions: ['astro'],
|
||||||
},
|
},
|
||||||
ssr: {
|
ssr: {
|
||||||
noExternal: [...getSsrNoExternalDeps(astroConfig.root), ...thirdPartyAstroPackages],
|
noExternal: [...getSsrNoExternalDeps(settings.config.root), ...thirdPartyAstroPackages],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -140,7 +140,7 @@ export async function createVite(
|
||||||
// 3. integration-provided vite config, via the `config:setup` hook
|
// 3. integration-provided vite config, via the `config:setup` hook
|
||||||
// 4. command vite config, passed as the argument to this function
|
// 4. command vite config, passed as the argument to this function
|
||||||
let result = commonConfig;
|
let result = commonConfig;
|
||||||
result = vite.mergeConfig(result, astroConfig.vite || {});
|
result = vite.mergeConfig(result, settings.config.vite || {});
|
||||||
result = vite.mergeConfig(result, commandConfig);
|
result = vite.mergeConfig(result, commandConfig);
|
||||||
if (result.plugins) {
|
if (result.plugins) {
|
||||||
sortPlugins(result.plugins);
|
sortPlugins(result.plugins);
|
||||||
|
@ -175,8 +175,8 @@ function sortPlugins(pluginOptions: vite.PluginOption[]) {
|
||||||
|
|
||||||
// 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({ root }: AstroConfig): Promise<string[]> {
|
async function getAstroPackages(settings: AstroSettings): Promise<string[]> {
|
||||||
const { astroPackages } = new DependencyWalker(root);
|
const { astroPackages } = new DependencyWalker(settings.config.root);
|
||||||
return astroPackages;
|
return astroPackages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import type { AstroTelemetry } from '@astrojs/telemetry';
|
||||||
import type { AddressInfo } from 'net';
|
import type { AddressInfo } from 'net';
|
||||||
import { performance } from 'perf_hooks';
|
import { performance } from 'perf_hooks';
|
||||||
import * as vite from 'vite';
|
import * as vite from 'vite';
|
||||||
import type { AstroConfig } from '../../@types/astro';
|
import type { AstroSettings } from '../../@types/astro';
|
||||||
import {
|
import {
|
||||||
runHookConfigDone,
|
runHookConfigDone,
|
||||||
runHookConfigSetup,
|
runHookConfigSetup,
|
||||||
|
@ -28,17 +28,17 @@ export interface DevServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** `astro dev` */
|
/** `astro dev` */
|
||||||
export default async function dev(config: AstroConfig, options: DevOptions): Promise<DevServer> {
|
export default async function dev(settings: AstroSettings, options: DevOptions): Promise<DevServer> {
|
||||||
const devStart = performance.now();
|
const devStart = performance.now();
|
||||||
applyPolyfill();
|
applyPolyfill();
|
||||||
await options.telemetry.record([]);
|
await options.telemetry.record([]);
|
||||||
config = await runHookConfigSetup({ config, command: 'dev', logging: options.logging });
|
settings = await runHookConfigSetup({ settings, command: 'dev', logging: options.logging });
|
||||||
const { host, port } = config.server;
|
const { host, port } = settings.config.server;
|
||||||
const { isRestart = false } = options;
|
const { isRestart = false } = options;
|
||||||
|
|
||||||
// The client entrypoint for renderers. Since these are imported dynamically
|
// The client entrypoint for renderers. Since these are imported dynamically
|
||||||
// we need to tell Vite to preoptimize them.
|
// we need to tell Vite to preoptimize them.
|
||||||
const rendererClientEntries = config._ctx.renderers
|
const rendererClientEntries = settings.renderers
|
||||||
.map((r) => r.clientEntrypoint)
|
.map((r) => r.clientEntrypoint)
|
||||||
.filter(Boolean) as string[];
|
.filter(Boolean) as string[];
|
||||||
|
|
||||||
|
@ -50,21 +50,21 @@ export default async function dev(config: AstroConfig, options: DevOptions): Pro
|
||||||
include: rendererClientEntries,
|
include: rendererClientEntries,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{ astroConfig: config, logging: options.logging, mode: 'dev' }
|
{ settings, logging: options.logging, mode: 'dev' }
|
||||||
);
|
);
|
||||||
await runHookConfigDone({ config, logging: options.logging });
|
await runHookConfigDone({ settings, logging: options.logging });
|
||||||
const viteServer = await vite.createServer(viteConfig);
|
const viteServer = await vite.createServer(viteConfig);
|
||||||
runHookServerSetup({ config, server: viteServer, logging: options.logging });
|
runHookServerSetup({ config: settings.config, server: viteServer, logging: options.logging });
|
||||||
await viteServer.listen(port);
|
await viteServer.listen(port);
|
||||||
|
|
||||||
const devServerAddressInfo = viteServer.httpServer!.address() as AddressInfo;
|
const devServerAddressInfo = viteServer.httpServer!.address() as AddressInfo;
|
||||||
const site = config.site ? new URL(config.base, config.site) : undefined;
|
const site = settings.config.site ? new URL(settings.config.base, settings.config.site) : undefined;
|
||||||
info(
|
info(
|
||||||
options.logging,
|
options.logging,
|
||||||
null,
|
null,
|
||||||
msg.devStart({
|
msg.devStart({
|
||||||
startupTime: performance.now() - devStart,
|
startupTime: performance.now() - devStart,
|
||||||
config,
|
config: settings.config,
|
||||||
devServerAddressInfo,
|
devServerAddressInfo,
|
||||||
site,
|
site,
|
||||||
https: !!viteConfig.server?.https,
|
https: !!viteConfig.server?.https,
|
||||||
|
@ -80,7 +80,7 @@ export default async function dev(config: AstroConfig, options: DevOptions): Pro
|
||||||
warn(options.logging, null, msg.fsStrictWarning());
|
warn(options.logging, null, msg.fsStrictWarning());
|
||||||
}
|
}
|
||||||
|
|
||||||
await runHookServerStart({ config, address: devServerAddressInfo, logging: options.logging });
|
await runHookServerStart({ config: settings.config, address: devServerAddressInfo, logging: options.logging });
|
||||||
|
|
||||||
return {
|
return {
|
||||||
address: devServerAddressInfo,
|
address: devServerAddressInfo,
|
||||||
|
@ -89,7 +89,7 @@ export default async function dev(config: AstroConfig, options: DevOptions): Pro
|
||||||
},
|
},
|
||||||
stop: async () => {
|
stop: async () => {
|
||||||
await viteServer.close();
|
await viteServer.close();
|
||||||
await runHookServerDone({ config, logging: options.logging });
|
await runHookServerDone({ config: settings.config, logging: options.logging });
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,6 @@ export async function call(ssrOpts: SSROptions) {
|
||||||
const [, mod] = await preload(ssrOpts);
|
const [, mod] = await preload(ssrOpts);
|
||||||
return await callEndpoint(mod as unknown as EndpointHandler, {
|
return await callEndpoint(mod as unknown as EndpointHandler, {
|
||||||
...ssrOpts,
|
...ssrOpts,
|
||||||
ssr: ssrOpts.astroConfig.output === 'server',
|
ssr: ssrOpts.settings.config.output === 'server',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import type { AstroTelemetry } from '@astrojs/telemetry';
|
import type { AstroTelemetry } from '@astrojs/telemetry';
|
||||||
import type { AddressInfo } from 'net';
|
import type { AddressInfo } from 'net';
|
||||||
import type { AstroConfig } from '../../@types/astro';
|
import type { AstroSettings } from '../../@types/astro';
|
||||||
import type { LogOptions } from '../logger/core';
|
import type { LogOptions } from '../logger/core';
|
||||||
|
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
|
@ -30,20 +30,20 @@ const HAS_FILE_EXTENSION_REGEXP = /^.*\.[^\\]+$/;
|
||||||
|
|
||||||
/** The primary dev action */
|
/** The primary dev action */
|
||||||
export default async function preview(
|
export default async function preview(
|
||||||
config: AstroConfig,
|
settings: AstroSettings,
|
||||||
{ logging }: PreviewOptions
|
{ logging }: PreviewOptions
|
||||||
): Promise<PreviewServer> {
|
): Promise<PreviewServer> {
|
||||||
if (config.output === 'server') {
|
if (settings.config.output === 'server') {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`[preview] 'output: server' not supported. Use your deploy platform's preview command directly instead, if one exists. (ex: 'netlify dev', 'vercel dev', 'wrangler', etc.)`
|
`[preview] 'output: server' not supported. Use your deploy platform's preview command directly instead, if one exists. (ex: 'netlify dev', 'vercel dev', 'wrangler', etc.)`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const startServerTime = performance.now();
|
const startServerTime = performance.now();
|
||||||
const defaultOrigin = 'http://localhost';
|
const defaultOrigin = 'http://localhost';
|
||||||
const trailingSlash = config.trailingSlash;
|
const trailingSlash = settings.config.trailingSlash;
|
||||||
/** Base request URL. */
|
/** Base request URL. */
|
||||||
let baseURL = new URL(config.base, new URL(config.site || '/', defaultOrigin));
|
let baseURL = new URL(settings.config.base, new URL(settings.config.site || '/', defaultOrigin));
|
||||||
const staticFileServer = sirv(fileURLToPath(config.outDir), {
|
const staticFileServer = sirv(fileURLToPath(settings.config.outDir), {
|
||||||
dev: true,
|
dev: true,
|
||||||
etag: true,
|
etag: true,
|
||||||
maxAge: 0,
|
maxAge: 0,
|
||||||
|
@ -84,7 +84,7 @@ export default async function preview(
|
||||||
// HACK: rewrite req.url so that sirv finds the file
|
// HACK: rewrite req.url so that sirv finds the file
|
||||||
req.url = '/' + req.url?.replace(baseURL.pathname, '');
|
req.url = '/' + req.url?.replace(baseURL.pathname, '');
|
||||||
staticFileServer(req, res, () => {
|
staticFileServer(req, res, () => {
|
||||||
const errorPagePath = fileURLToPath(config.outDir + '/404.html');
|
const errorPagePath = fileURLToPath(settings.config.outDir + '/404.html');
|
||||||
if (fs.existsSync(errorPagePath)) {
|
if (fs.existsSync(errorPagePath)) {
|
||||||
res.statusCode = 404;
|
res.statusCode = 404;
|
||||||
res.setHeader('Content-Type', 'text/html;charset=utf-8');
|
res.setHeader('Content-Type', 'text/html;charset=utf-8');
|
||||||
|
@ -100,8 +100,8 @@ export default async function preview(
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let { port } = config.server;
|
let { port } = settings.config.server;
|
||||||
const host = getResolvedHostForHttpServer(config.server.host);
|
const host = getResolvedHostForHttpServer(settings.config.server.host);
|
||||||
|
|
||||||
let httpServer: http.Server;
|
let httpServer: http.Server;
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ export default async function preview(
|
||||||
null,
|
null,
|
||||||
msg.devStart({
|
msg.devStart({
|
||||||
startupTime: performance.now() - timerStart,
|
startupTime: performance.now() - timerStart,
|
||||||
config,
|
config: settings.config,
|
||||||
devServerAddressInfo,
|
devServerAddressInfo,
|
||||||
https: false,
|
https: false,
|
||||||
site: baseURL,
|
site: baseURL,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { fileURLToPath } from 'url';
|
import { fileURLToPath } from 'url';
|
||||||
import type { ViteDevServer } from 'vite';
|
import type { ViteDevServer } from 'vite';
|
||||||
import type {
|
import type {
|
||||||
AstroConfig,
|
AstroSettings,
|
||||||
AstroRenderer,
|
AstroRenderer,
|
||||||
ComponentInstance,
|
ComponentInstance,
|
||||||
RouteData,
|
RouteData,
|
||||||
|
@ -20,8 +20,8 @@ import { resolveClientDevPath } from './resolve.js';
|
||||||
import { getScriptsForURL } from './scripts.js';
|
import { getScriptsForURL } from './scripts.js';
|
||||||
|
|
||||||
export interface SSROptions {
|
export interface SSROptions {
|
||||||
/** an instance of the AstroConfig */
|
/** an instance of the AstroSettings */
|
||||||
astroConfig: AstroConfig;
|
settings: AstroSettings;
|
||||||
/** location of file on disk */
|
/** location of file on disk */
|
||||||
filePath: URL;
|
filePath: URL;
|
||||||
/** logging options */
|
/** logging options */
|
||||||
|
@ -58,18 +58,18 @@ async function loadRenderer(
|
||||||
|
|
||||||
export async function loadRenderers(
|
export async function loadRenderers(
|
||||||
viteServer: ViteDevServer,
|
viteServer: ViteDevServer,
|
||||||
astroConfig: AstroConfig
|
settings: AstroSettings
|
||||||
): Promise<SSRLoadedRenderer[]> {
|
): Promise<SSRLoadedRenderer[]> {
|
||||||
return Promise.all(astroConfig._ctx.renderers.map((r) => loadRenderer(viteServer, r)));
|
return Promise.all(settings.renderers.map((r) => loadRenderer(viteServer, r)));
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function preload({
|
export async function preload({
|
||||||
astroConfig,
|
settings,
|
||||||
filePath,
|
filePath,
|
||||||
viteServer,
|
viteServer,
|
||||||
}: Pick<SSROptions, 'astroConfig' | 'filePath' | 'viteServer'>): Promise<ComponentPreload> {
|
}: Pick<SSROptions, 'settings' | 'filePath' | 'viteServer'>): Promise<ComponentPreload> {
|
||||||
// Important: This needs to happen first, in case a renderer provides polyfills.
|
// Important: This needs to happen first, in case a renderer provides polyfills.
|
||||||
const renderers = await loadRenderers(viteServer, astroConfig);
|
const renderers = await loadRenderers(viteServer, settings);
|
||||||
// Load the module from the Vite SSR Runtime.
|
// Load the module from the Vite SSR Runtime.
|
||||||
const mod = (await viteServer.ssrLoadModule(fileURLToPath(filePath))) as ComponentInstance;
|
const mod = (await viteServer.ssrLoadModule(fileURLToPath(filePath))) as ComponentInstance;
|
||||||
if (viteServer.config.mode === 'development' || !mod?.$$metadata) {
|
if (viteServer.config.mode === 'development' || !mod?.$$metadata) {
|
||||||
|
@ -92,7 +92,7 @@ export async function render(
|
||||||
ssrOpts: SSROptions
|
ssrOpts: SSROptions
|
||||||
): Promise<Response> {
|
): Promise<Response> {
|
||||||
const {
|
const {
|
||||||
astroConfig,
|
settings,
|
||||||
filePath,
|
filePath,
|
||||||
logging,
|
logging,
|
||||||
mode,
|
mode,
|
||||||
|
@ -104,10 +104,10 @@ export async function render(
|
||||||
viteServer,
|
viteServer,
|
||||||
} = ssrOpts;
|
} = ssrOpts;
|
||||||
// Add hoisted script tags
|
// Add hoisted script tags
|
||||||
const scripts = await getScriptsForURL(filePath, astroConfig, viteServer);
|
const scripts = await getScriptsForURL(filePath, viteServer);
|
||||||
|
|
||||||
// Inject HMR scripts
|
// Inject HMR scripts
|
||||||
if (isPage(filePath, astroConfig) && mode === 'development') {
|
if (isPage(filePath, settings) && mode === 'development') {
|
||||||
scripts.add({
|
scripts.add({
|
||||||
props: { type: 'module', src: '/@vite/client' },
|
props: { type: 'module', src: '/@vite/client' },
|
||||||
children: '',
|
children: '',
|
||||||
|
@ -122,13 +122,13 @@ export async function render(
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: We should allow adding generic HTML elements to the head, not just scripts
|
// TODO: We should allow adding generic HTML elements to the head, not just scripts
|
||||||
for (const script of astroConfig._ctx.scripts) {
|
for (const script of settings.scripts) {
|
||||||
if (script.stage === 'head-inline') {
|
if (script.stage === 'head-inline') {
|
||||||
scripts.add({
|
scripts.add({
|
||||||
props: {},
|
props: {},
|
||||||
children: script.content,
|
children: script.content,
|
||||||
});
|
});
|
||||||
} else if (script.stage === 'page' && isPage(filePath, astroConfig)) {
|
} else if (script.stage === 'page' && isPage(filePath, settings)) {
|
||||||
scripts.add({
|
scripts.add({
|
||||||
props: { type: 'module', src: `/@id/${PAGE_SCRIPT_ID}` },
|
props: { type: 'module', src: `/@id/${PAGE_SCRIPT_ID}` },
|
||||||
children: '',
|
children: '',
|
||||||
|
@ -167,13 +167,13 @@ export async function render(
|
||||||
});
|
});
|
||||||
|
|
||||||
let response = await coreRender({
|
let response = await coreRender({
|
||||||
adapterName: astroConfig.adapter?.name,
|
adapterName: settings.config.adapter?.name,
|
||||||
links,
|
links,
|
||||||
styles,
|
styles,
|
||||||
logging,
|
logging,
|
||||||
markdown: {
|
markdown: {
|
||||||
...astroConfig.markdown,
|
...settings.config.markdown,
|
||||||
isAstroFlavoredMd: astroConfig.legacy.astroFlavoredMarkdown,
|
isAstroFlavoredMd: settings.config.legacy.astroFlavoredMarkdown,
|
||||||
},
|
},
|
||||||
mod,
|
mod,
|
||||||
mode,
|
mode,
|
||||||
|
@ -191,8 +191,8 @@ export async function render(
|
||||||
request,
|
request,
|
||||||
route,
|
route,
|
||||||
routeCache,
|
routeCache,
|
||||||
site: astroConfig.site ? new URL(astroConfig.base, astroConfig.site).toString() : undefined,
|
site: settings.config.site ? new URL(settings.config.base, settings.config.site).toString() : undefined,
|
||||||
ssr: astroConfig.output === 'server',
|
ssr: settings.config.output === 'server',
|
||||||
streaming: true,
|
streaming: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -10,19 +10,17 @@ import { crawlGraph } from './vite.js';
|
||||||
|
|
||||||
export async function getScriptsForURL(
|
export async function getScriptsForURL(
|
||||||
filePath: URL,
|
filePath: URL,
|
||||||
astroConfig: AstroConfig,
|
|
||||||
viteServer: vite.ViteDevServer
|
viteServer: vite.ViteDevServer
|
||||||
): Promise<Set<SSRElement>> {
|
): Promise<Set<SSRElement>> {
|
||||||
const elements = new Set<SSRElement>();
|
const elements = new Set<SSRElement>();
|
||||||
const rootID = viteID(filePath);
|
const rootID = viteID(filePath);
|
||||||
let rootProjectFolder = slash(fileURLToPath(astroConfig.root));
|
|
||||||
const modInfo = viteServer.pluginContainer.getModuleInfo(rootID);
|
const modInfo = viteServer.pluginContainer.getModuleInfo(rootID);
|
||||||
addHoistedScripts(elements, modInfo, rootProjectFolder);
|
addHoistedScripts(elements, modInfo);
|
||||||
for await (const moduleNode of crawlGraph(viteServer, rootID, true)) {
|
for await (const moduleNode of crawlGraph(viteServer, rootID, true)) {
|
||||||
const id = moduleNode.id;
|
const id = moduleNode.id;
|
||||||
if (id) {
|
if (id) {
|
||||||
const info = viteServer.pluginContainer.getModuleInfo(id);
|
const info = viteServer.pluginContainer.getModuleInfo(id);
|
||||||
addHoistedScripts(elements, info, rootProjectFolder);
|
addHoistedScripts(elements, info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +30,6 @@ export async function getScriptsForURL(
|
||||||
function addHoistedScripts(
|
function addHoistedScripts(
|
||||||
set: Set<SSRElement>,
|
set: Set<SSRElement>,
|
||||||
info: ModuleInfo | null,
|
info: ModuleInfo | null,
|
||||||
rootProjectFolder: string
|
|
||||||
) {
|
) {
|
||||||
if (!info?.meta?.astro) {
|
if (!info?.meta?.astro) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import type {
|
import type {
|
||||||
AstroConfig,
|
AstroConfig,
|
||||||
|
AstroSettings,
|
||||||
InjectedRoute,
|
InjectedRoute,
|
||||||
ManifestData,
|
ManifestData,
|
||||||
RouteData,
|
RouteData,
|
||||||
|
@ -190,7 +191,7 @@ function injectedRouteToItem(
|
||||||
|
|
||||||
/** Create manifest of all static routes */
|
/** Create manifest of all static routes */
|
||||||
export function createRouteManifest(
|
export function createRouteManifest(
|
||||||
{ config, cwd }: { config: AstroConfig; cwd?: string },
|
{ settings, cwd }: { settings: AstroSettings; cwd?: string },
|
||||||
logging: LogOptions
|
logging: LogOptions
|
||||||
): ManifestData {
|
): ManifestData {
|
||||||
const components: string[] = [];
|
const components: string[] = [];
|
||||||
|
@ -198,7 +199,7 @@ export function createRouteManifest(
|
||||||
const validPageExtensions: Set<string> = new Set([
|
const validPageExtensions: Set<string> = new Set([
|
||||||
'.astro',
|
'.astro',
|
||||||
'.md',
|
'.md',
|
||||||
...config._ctx.pageExtensions,
|
...settings.pageExtensions,
|
||||||
]);
|
]);
|
||||||
const validEndpointExtensions: Set<string> = new Set(['.js', '.ts']);
|
const validEndpointExtensions: Set<string> = new Set(['.js', '.ts']);
|
||||||
|
|
||||||
|
@ -206,7 +207,7 @@ export function createRouteManifest(
|
||||||
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.root), resolved));
|
const file = slash(path.relative(cwd || fileURLToPath(settings.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);
|
||||||
|
@ -283,7 +284,7 @@ export function createRouteManifest(
|
||||||
} else {
|
} else {
|
||||||
components.push(item.file);
|
components.push(item.file);
|
||||||
const component = item.file;
|
const component = item.file;
|
||||||
const trailingSlash = item.isPage ? config.trailingSlash : 'never';
|
const trailingSlash = item.isPage ? settings.config.trailingSlash : 'never';
|
||||||
const pattern = getPattern(segments, trailingSlash);
|
const pattern = getPattern(segments, trailingSlash);
|
||||||
const generate = getRouteGenerator(segments, trailingSlash);
|
const generate = getRouteGenerator(segments, trailingSlash);
|
||||||
const pathname = segments.every((segment) => segment.length === 1 && !segment[0].dynamic)
|
const pathname = segments.every((segment) => segment.length === 1 && !segment[0].dynamic)
|
||||||
|
@ -307,17 +308,18 @@ export function createRouteManifest(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { config } = settings;
|
||||||
const pages = resolvePages(config);
|
const pages = resolvePages(config);
|
||||||
|
|
||||||
if (fs.existsSync(pages)) {
|
if (fs.existsSync(pages)) {
|
||||||
walk(fileURLToPath(pages), [], []);
|
walk(fileURLToPath(pages), [], []);
|
||||||
} else if (config?._ctx?.injectedRoutes?.length === 0) {
|
} else if (settings.injectedRoutes.length === 0) {
|
||||||
const pagesDirRootRelative = pages.href.slice(config.root.href.length);
|
const pagesDirRootRelative = pages.href.slice(settings.config.root.href.length);
|
||||||
|
|
||||||
warn(logging, 'astro', `Missing pages directory: ${pagesDirRootRelative}`);
|
warn(logging, 'astro', `Missing pages directory: ${pagesDirRootRelative}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
config?._ctx?.injectedRoutes
|
settings.injectedRoutes
|
||||||
?.sort((a, b) =>
|
?.sort((a, b) =>
|
||||||
// sort injected routes in the same way as user-defined routes
|
// sort injected routes in the same way as user-defined routes
|
||||||
comparator(injectedRouteToItem({ config, cwd }, a), injectedRouteToItem({ config, cwd }, b))
|
comparator(injectedRouteToItem({ config, cwd }, a), injectedRouteToItem({ config, cwd }, b))
|
||||||
|
|
|
@ -5,7 +5,7 @@ import resolve from 'resolve';
|
||||||
import slash from 'slash';
|
import slash from 'slash';
|
||||||
import { fileURLToPath, pathToFileURL } from 'url';
|
import { fileURLToPath, pathToFileURL } from 'url';
|
||||||
import type { ErrorPayload, ViteDevServer } from 'vite';
|
import type { ErrorPayload, ViteDevServer } from 'vite';
|
||||||
import type { AstroConfig, RouteType } from '../@types/astro';
|
import type { AstroConfig, AstroSettings, RouteType } from '../@types/astro';
|
||||||
import { prependForwardSlash, removeTrailingForwardSlash } from './path.js';
|
import { prependForwardSlash, removeTrailingForwardSlash } from './path.js';
|
||||||
|
|
||||||
// process.env.PACKAGE_VERSION is injected when we build and publish the astro package.
|
// process.env.PACKAGE_VERSION is injected when we build and publish the astro package.
|
||||||
|
@ -172,21 +172,21 @@ function isPublicRoute(file: URL, config: AstroConfig): boolean {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function endsWithPageExt(file: URL, config: AstroConfig): boolean {
|
function endsWithPageExt(file: URL, settings: AstroSettings): boolean {
|
||||||
for (const ext of config._ctx.pageExtensions) {
|
for (const ext of settings.pageExtensions) {
|
||||||
if (file.toString().endsWith(ext)) return true;
|
if (file.toString().endsWith(ext)) return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isPage(file: URL, config: AstroConfig): boolean {
|
export function isPage(file: URL, settings: AstroSettings): boolean {
|
||||||
if (!isInPagesDir(file, config)) return false;
|
if (!isInPagesDir(file, settings.config)) return false;
|
||||||
if (!isPublicRoute(file, config)) return false;
|
if (!isPublicRoute(file, settings.config)) return false;
|
||||||
return endsWithPageExt(file, config);
|
return endsWithPageExt(file, settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isModeServerWithNoAdapter(config: AstroConfig): boolean {
|
export function isModeServerWithNoAdapter(settings: AstroSettings): boolean {
|
||||||
return config.output === 'server' && !config._ctx.adapter;
|
return settings.config.output === 'server' && !settings.adapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function relativeToSrcDir(config: AstroConfig, idOrUrl: URL | string) {
|
export function relativeToSrcDir(config: AstroConfig, idOrUrl: URL | string) {
|
||||||
|
|
|
@ -3,6 +3,7 @@ import type { AddressInfo } from 'net';
|
||||||
import type { ViteDevServer } from 'vite';
|
import type { ViteDevServer } from 'vite';
|
||||||
import {
|
import {
|
||||||
AstroConfig,
|
AstroConfig,
|
||||||
|
AstroSettings,
|
||||||
AstroRenderer,
|
AstroRenderer,
|
||||||
BuildConfig,
|
BuildConfig,
|
||||||
HookParameters,
|
HookParameters,
|
||||||
|
@ -10,7 +11,7 @@ import {
|
||||||
} from '../@types/astro.js';
|
} from '../@types/astro.js';
|
||||||
import type { SerializedSSRManifest } from '../core/app/types';
|
import type { SerializedSSRManifest } from '../core/app/types';
|
||||||
import type { PageBuildData } from '../core/build/types';
|
import type { PageBuildData } from '../core/build/types';
|
||||||
import { mergeConfig } from '../core/config.js';
|
import { mergeConfig } from '../core/config/config.js';
|
||||||
import type { ViteConfigWithSSR } from '../core/create-vite.js';
|
import type { ViteConfigWithSSR } from '../core/create-vite.js';
|
||||||
import { info, LogOptions } from '../core/logger/core.js';
|
import { info, LogOptions } from '../core/logger/core.js';
|
||||||
|
|
||||||
|
@ -34,21 +35,22 @@ async function withTakingALongTimeMsg<T>({
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function runHookConfigSetup({
|
export async function runHookConfigSetup({
|
||||||
config: _config,
|
settings,
|
||||||
command,
|
command,
|
||||||
logging,
|
logging,
|
||||||
}: {
|
}: {
|
||||||
config: AstroConfig;
|
settings: AstroSettings;
|
||||||
command: 'dev' | 'build';
|
command: 'dev' | 'build';
|
||||||
logging: LogOptions;
|
logging: LogOptions;
|
||||||
}): Promise<AstroConfig> {
|
}): Promise<AstroSettings> {
|
||||||
// An adapter is an integration, so if one is provided push it.
|
// An adapter is an integration, so if one is provided push it.
|
||||||
if (_config.adapter) {
|
if (settings.config.adapter) {
|
||||||
_config.integrations.push(_config.adapter);
|
settings.config.integrations.push(settings.config.adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
let updatedConfig: AstroConfig = { ..._config };
|
let updatedConfig: AstroConfig = { ...settings.config };
|
||||||
for (const integration of _config.integrations) {
|
let updatedSettings: AstroSettings = { ...settings, config: updatedConfig };
|
||||||
|
for (const integration of settings.config.integrations) {
|
||||||
/**
|
/**
|
||||||
* By making integration hooks optional, Astro can now ignore null or undefined Integrations
|
* By making integration hooks optional, Astro can now ignore null or undefined Integrations
|
||||||
* instead of giving an internal error most people can't read
|
* instead of giving an internal error most people can't read
|
||||||
|
@ -74,22 +76,22 @@ export async function runHookConfigSetup({
|
||||||
throw new Error(`Renderer ${bold(renderer.name)} does not provide a serverEntrypoint.`);
|
throw new Error(`Renderer ${bold(renderer.name)} does not provide a serverEntrypoint.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
updatedConfig._ctx.renderers.push(renderer);
|
updatedSettings.renderers.push(renderer);
|
||||||
},
|
},
|
||||||
injectScript: (stage, content) => {
|
injectScript: (stage, content) => {
|
||||||
updatedConfig._ctx.scripts.push({ stage, content });
|
updatedSettings.scripts.push({ stage, content });
|
||||||
},
|
},
|
||||||
updateConfig: (newConfig) => {
|
updateConfig: (newConfig) => {
|
||||||
updatedConfig = mergeConfig(updatedConfig, newConfig) as AstroConfig;
|
updatedConfig = mergeConfig(updatedConfig, newConfig) as AstroConfig;
|
||||||
},
|
},
|
||||||
injectRoute: (injectRoute) => {
|
injectRoute: (injectRoute) => {
|
||||||
updatedConfig._ctx.injectedRoutes.push(injectRoute);
|
updatedSettings.injectedRoutes.push(injectRoute);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
// Semi-private `addPageExtension` hook
|
// Semi-private `addPageExtension` hook
|
||||||
function addPageExtension(...input: (string | string[])[]) {
|
function addPageExtension(...input: (string | string[])[]) {
|
||||||
const exts = (input.flat(Infinity) as string[]).map((ext) => `.${ext.replace(/^\./, '')}`);
|
const exts = (input.flat(Infinity) as string[]).map((ext) => `.${ext.replace(/^\./, '')}`);
|
||||||
updatedConfig._ctx.pageExtensions.push(...exts);
|
updatedSettings.pageExtensions.push(...exts);
|
||||||
}
|
}
|
||||||
Object.defineProperty(hooks, 'addPageExtension', {
|
Object.defineProperty(hooks, 'addPageExtension', {
|
||||||
value: addPageExtension,
|
value: addPageExtension,
|
||||||
|
@ -103,29 +105,31 @@ export async function runHookConfigSetup({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return updatedConfig;
|
|
||||||
|
updatedSettings.config = updatedConfig;
|
||||||
|
return updatedSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function runHookConfigDone({
|
export async function runHookConfigDone({
|
||||||
config,
|
settings,
|
||||||
logging,
|
logging,
|
||||||
}: {
|
}: {
|
||||||
config: AstroConfig;
|
settings: AstroSettings;
|
||||||
logging: LogOptions;
|
logging: LogOptions;
|
||||||
}) {
|
}) {
|
||||||
for (const integration of config.integrations) {
|
for (const integration of settings.config.integrations) {
|
||||||
if (integration?.hooks?.['astro:config:done']) {
|
if (integration?.hooks?.['astro:config:done']) {
|
||||||
await withTakingALongTimeMsg({
|
await withTakingALongTimeMsg({
|
||||||
name: integration.name,
|
name: integration.name,
|
||||||
hookResult: integration.hooks['astro:config:done']({
|
hookResult: integration.hooks['astro:config:done']({
|
||||||
config,
|
config: settings.config,
|
||||||
setAdapter(adapter) {
|
setAdapter(adapter) {
|
||||||
if (config._ctx.adapter && config._ctx.adapter.name !== adapter.name) {
|
if (settings.adapter && settings.adapter.name !== adapter.name) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Integration "${integration.name}" conflicts with "${config._ctx.adapter.name}". You can only configure one deployment integration.`
|
`Integration "${integration.name}" conflicts with "${settings.adapter.name}". You can only configure one deployment integration.`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
config._ctx.adapter = adapter;
|
settings.adapter = adapter;
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
logging,
|
logging,
|
||||||
|
|
|
@ -3,18 +3,18 @@ import type { ArrowFunctionExpressionKind, CallExpressionKind } from 'ast-types/
|
||||||
import type { NodePath } from 'ast-types/lib/node-path';
|
import type { NodePath } from 'ast-types/lib/node-path';
|
||||||
import { parse, print, types, visit } from 'recast';
|
import { parse, print, types, visit } from 'recast';
|
||||||
import type { Plugin } from 'vite';
|
import type { Plugin } from 'vite';
|
||||||
import type { AstroConfig } from '../@types/astro';
|
import type { AstroSettings } from '../@types/astro';
|
||||||
|
|
||||||
// Check for `Astro.glob()`. Be very forgiving of whitespace. False positives are okay.
|
// Check for `Astro.glob()`. Be very forgiving of whitespace. False positives are okay.
|
||||||
const ASTRO_GLOB_REGEX = /Astro2?\s*\.\s*glob\s*\(/;
|
const ASTRO_GLOB_REGEX = /Astro2?\s*\.\s*glob\s*\(/;
|
||||||
interface AstroPluginOptions {
|
interface AstroPluginOptions {
|
||||||
config: AstroConfig;
|
settings: AstroSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
// esbuild transforms the component-scoped Astro into Astro2, so need to check both.
|
// esbuild transforms the component-scoped Astro into Astro2, so need to check both.
|
||||||
const validAstroGlobalNames = new Set(['Astro', 'Astro2']);
|
const validAstroGlobalNames = new Set(['Astro', 'Astro2']);
|
||||||
|
|
||||||
export default function astro({ config }: AstroPluginOptions): Plugin {
|
export default function astro(_opts: AstroPluginOptions): Plugin {
|
||||||
return {
|
return {
|
||||||
name: 'astro:postprocess',
|
name: 'astro:postprocess',
|
||||||
async transform(code, id) {
|
async transform(code, id) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import type http from 'http';
|
import type http from 'http';
|
||||||
import mime from 'mime';
|
import mime from 'mime';
|
||||||
import type * as vite from 'vite';
|
import type * as vite from 'vite';
|
||||||
import type { AstroConfig, ManifestData } from '../@types/astro';
|
import type { AstroSettings, ManifestData } from '../@types/astro';
|
||||||
import type { SSROptions } from '../core/render/dev/index';
|
import type { SSROptions } from '../core/render/dev/index';
|
||||||
|
|
||||||
import { Readable } from 'stream';
|
import { Readable } from 'stream';
|
||||||
|
@ -24,7 +24,7 @@ import { resolvePages } from '../core/util.js';
|
||||||
import notFoundTemplate, { subpathNotUsedTemplate } from '../template/4xx.js';
|
import notFoundTemplate, { subpathNotUsedTemplate } from '../template/4xx.js';
|
||||||
|
|
||||||
interface AstroPluginOptions {
|
interface AstroPluginOptions {
|
||||||
config: AstroConfig;
|
settings: AstroSettings;
|
||||||
logging: LogOptions;
|
logging: LogOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@ async function writeSSRResult(webResponse: Response, res: http.ServerResponse) {
|
||||||
|
|
||||||
async function handle404Response(
|
async function handle404Response(
|
||||||
origin: string,
|
origin: string,
|
||||||
config: AstroConfig,
|
settings: AstroSettings,
|
||||||
req: http.IncomingMessage,
|
req: http.IncomingMessage,
|
||||||
res: http.ServerResponse
|
res: http.ServerResponse
|
||||||
) {
|
) {
|
||||||
|
@ -129,7 +129,7 @@ async function handle500Response(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCustom404Route(config: AstroConfig, manifest: ManifestData) {
|
function getCustom404Route({ config }: AstroSettings, manifest: ManifestData) {
|
||||||
// For Windows compat, use relative page paths to match the 404 route
|
// For Windows compat, use relative page paths to match the 404 route
|
||||||
const relPages = resolvePages(config).href.replace(config.root.href, '');
|
const relPages = resolvePages(config).href.replace(config.root.href, '');
|
||||||
const pattern = new RegExp(`${appendForwardSlash(relPages)}404.(astro|md)`);
|
const pattern = new RegExp(`${appendForwardSlash(relPages)}404.(astro|md)`);
|
||||||
|
@ -141,9 +141,10 @@ function log404(logging: LogOptions, pathname: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function baseMiddleware(
|
export function baseMiddleware(
|
||||||
config: AstroConfig,
|
settings: AstroSettings,
|
||||||
logging: LogOptions
|
logging: LogOptions
|
||||||
): vite.Connect.NextHandleFunction {
|
): vite.Connect.NextHandleFunction {
|
||||||
|
const { config } = settings;
|
||||||
const site = config.site ? new URL(config.base, config.site) : undefined;
|
const site = config.site ? new URL(config.base, config.site) : undefined;
|
||||||
const devRoot = site ? site.pathname : '/';
|
const devRoot = site ? site.pathname : '/';
|
||||||
|
|
||||||
|
@ -184,13 +185,13 @@ async function matchRoute(
|
||||||
viteServer: vite.ViteDevServer,
|
viteServer: vite.ViteDevServer,
|
||||||
logging: LogOptions,
|
logging: LogOptions,
|
||||||
manifest: ManifestData,
|
manifest: ManifestData,
|
||||||
config: AstroConfig
|
settings: AstroSettings
|
||||||
) {
|
) {
|
||||||
const matches = matchAllRoutes(pathname, manifest);
|
const matches = matchAllRoutes(pathname, manifest);
|
||||||
|
|
||||||
for await (const maybeRoute of matches) {
|
for await (const maybeRoute of matches) {
|
||||||
const filePath = new URL(`./${maybeRoute.component}`, config.root);
|
const filePath = new URL(`./${maybeRoute.component}`, settings.config.root);
|
||||||
const preloadedComponent = await preload({ astroConfig: config, filePath, viteServer });
|
const preloadedComponent = await preload({ settings, filePath, viteServer });
|
||||||
const [, mod] = preloadedComponent;
|
const [, mod] = preloadedComponent;
|
||||||
// attempt to get static paths
|
// attempt to get static paths
|
||||||
// if this fails, we have a bad URL match!
|
// if this fails, we have a bad URL match!
|
||||||
|
@ -200,7 +201,7 @@ async function matchRoute(
|
||||||
routeCache,
|
routeCache,
|
||||||
pathname: pathname,
|
pathname: pathname,
|
||||||
logging,
|
logging,
|
||||||
ssr: config.output === 'server',
|
ssr: settings.config.output === 'server',
|
||||||
});
|
});
|
||||||
|
|
||||||
if (paramsAndPropsRes !== GetParamsAndPropsError.NoMatchingStaticPath) {
|
if (paramsAndPropsRes !== GetParamsAndPropsError.NoMatchingStaticPath) {
|
||||||
|
@ -222,11 +223,11 @@ async function matchRoute(
|
||||||
}
|
}
|
||||||
|
|
||||||
log404(logging, pathname);
|
log404(logging, pathname);
|
||||||
const custom404 = getCustom404Route(config, manifest);
|
const custom404 = getCustom404Route(settings, manifest);
|
||||||
|
|
||||||
if (custom404) {
|
if (custom404) {
|
||||||
const filePath = new URL(`./${custom404.component}`, config.root);
|
const filePath = new URL(`./${custom404.component}`, settings.config.root);
|
||||||
const preloadedComponent = await preload({ astroConfig: config, filePath, viteServer });
|
const preloadedComponent = await preload({ settings, filePath, viteServer });
|
||||||
const [, mod] = preloadedComponent;
|
const [, mod] = preloadedComponent;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -246,10 +247,11 @@ async function handleRequest(
|
||||||
viteServer: vite.ViteDevServer,
|
viteServer: vite.ViteDevServer,
|
||||||
logging: LogOptions,
|
logging: LogOptions,
|
||||||
manifest: ManifestData,
|
manifest: ManifestData,
|
||||||
config: AstroConfig,
|
settings: AstroSettings,
|
||||||
req: http.IncomingMessage,
|
req: http.IncomingMessage,
|
||||||
res: http.ServerResponse
|
res: http.ServerResponse
|
||||||
) {
|
) {
|
||||||
|
const { config } = settings;
|
||||||
const origin = `${viteServer.config.server.https ? 'https' : 'http'}://${req.headers.host}`;
|
const origin = `${viteServer.config.server.https ? 'https' : 'http'}://${req.headers.host}`;
|
||||||
const buildingToSSR = config.output === 'server';
|
const buildingToSSR = config.output === 'server';
|
||||||
// Ignore `.html` extensions and `index.html` in request URLS to ensure that
|
// Ignore `.html` extensions and `index.html` in request URLS to ensure that
|
||||||
|
@ -292,7 +294,7 @@ async function handleRequest(
|
||||||
viteServer,
|
viteServer,
|
||||||
logging,
|
logging,
|
||||||
manifest,
|
manifest,
|
||||||
config
|
settings
|
||||||
);
|
);
|
||||||
filePath = matchedRoute?.filePath;
|
filePath = matchedRoute?.filePath;
|
||||||
|
|
||||||
|
@ -306,7 +308,7 @@ async function handleRequest(
|
||||||
viteServer,
|
viteServer,
|
||||||
manifest,
|
manifest,
|
||||||
logging,
|
logging,
|
||||||
config,
|
settings,
|
||||||
req,
|
req,
|
||||||
res
|
res
|
||||||
);
|
);
|
||||||
|
@ -328,14 +330,15 @@ async function handleRoute(
|
||||||
viteServer: vite.ViteDevServer,
|
viteServer: vite.ViteDevServer,
|
||||||
manifest: ManifestData,
|
manifest: ManifestData,
|
||||||
logging: LogOptions,
|
logging: LogOptions,
|
||||||
config: AstroConfig,
|
settings: AstroSettings,
|
||||||
req: http.IncomingMessage,
|
req: http.IncomingMessage,
|
||||||
res: http.ServerResponse
|
res: http.ServerResponse
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (!matchedRoute) {
|
if (!matchedRoute) {
|
||||||
return handle404Response(origin, config, req, res);
|
return handle404Response(origin, settings, req, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { config } = settings;
|
||||||
const filePath: URL | undefined = matchedRoute.filePath;
|
const filePath: URL | undefined = matchedRoute.filePath;
|
||||||
const { route, preloadedComponent, mod } = matchedRoute;
|
const { route, preloadedComponent, mod } = matchedRoute;
|
||||||
const buildingToSSR = config.output === 'server';
|
const buildingToSSR = config.output === 'server';
|
||||||
|
@ -363,7 +366,7 @@ async function handleRoute(
|
||||||
});
|
});
|
||||||
|
|
||||||
const options: SSROptions = {
|
const options: SSROptions = {
|
||||||
astroConfig: config,
|
settings,
|
||||||
filePath,
|
filePath,
|
||||||
logging,
|
logging,
|
||||||
mode: 'development',
|
mode: 'development',
|
||||||
|
@ -386,7 +389,7 @@ async function handleRoute(
|
||||||
viteServer,
|
viteServer,
|
||||||
logging,
|
logging,
|
||||||
manifest,
|
manifest,
|
||||||
config
|
settings
|
||||||
);
|
);
|
||||||
return handleRoute(
|
return handleRoute(
|
||||||
fourOhFourRoute,
|
fourOhFourRoute,
|
||||||
|
@ -398,7 +401,7 @@ async function handleRoute(
|
||||||
viteServer,
|
viteServer,
|
||||||
manifest,
|
manifest,
|
||||||
logging,
|
logging,
|
||||||
config,
|
settings,
|
||||||
req,
|
req,
|
||||||
res
|
res
|
||||||
);
|
);
|
||||||
|
@ -423,17 +426,17 @@ async function handleRoute(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function createPlugin({ config, logging }: AstroPluginOptions): vite.Plugin {
|
export default function createPlugin({ settings, logging }: AstroPluginOptions): vite.Plugin {
|
||||||
return {
|
return {
|
||||||
name: 'astro:server',
|
name: 'astro:server',
|
||||||
configureServer(viteServer) {
|
configureServer(viteServer) {
|
||||||
let routeCache = new RouteCache(logging);
|
let routeCache = new RouteCache(logging);
|
||||||
let manifest: ManifestData = createRouteManifest({ config: config }, logging);
|
let manifest: ManifestData = createRouteManifest({ settings }, logging);
|
||||||
/** rebuild the route cache + manifest, as needed. */
|
/** rebuild the route cache + manifest, as needed. */
|
||||||
function rebuildManifest(needsManifestRebuild: boolean, file: string) {
|
function rebuildManifest(needsManifestRebuild: boolean, file: string) {
|
||||||
routeCache.clearAll();
|
routeCache.clearAll();
|
||||||
if (needsManifestRebuild) {
|
if (needsManifestRebuild) {
|
||||||
manifest = createRouteManifest({ config: config }, logging);
|
manifest = createRouteManifest({ settings }, logging);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Rebuild route manifest on file change, if needed.
|
// Rebuild route manifest on file change, if needed.
|
||||||
|
@ -442,17 +445,17 @@ export default function createPlugin({ config, logging }: AstroPluginOptions): v
|
||||||
viteServer.watcher.on('change', rebuildManifest.bind(null, false));
|
viteServer.watcher.on('change', rebuildManifest.bind(null, false));
|
||||||
return () => {
|
return () => {
|
||||||
// Push this middleware to the front of the stack so that it can intercept responses.
|
// Push this middleware to the front of the stack so that it can intercept responses.
|
||||||
if (config.base !== '/') {
|
if (settings.config.base !== '/') {
|
||||||
viteServer.middlewares.stack.unshift({
|
viteServer.middlewares.stack.unshift({
|
||||||
route: '',
|
route: '',
|
||||||
handle: baseMiddleware(config, logging),
|
handle: baseMiddleware(settings, logging),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
viteServer.middlewares.use(async (req, res) => {
|
viteServer.middlewares.use(async (req, res) => {
|
||||||
if (!req.url || !req.method) {
|
if (!req.url || !req.method) {
|
||||||
throw new Error('Incomplete request');
|
throw new Error('Incomplete request');
|
||||||
}
|
}
|
||||||
handleRequest(routeCache, viteServer, logging, manifest, config, req, res);
|
handleRequest(routeCache, viteServer, logging, manifest, settings, req, res);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import type { PluginContext, SourceDescription } from 'rollup';
|
import type { PluginContext, SourceDescription } from 'rollup';
|
||||||
import type * as vite from 'vite';
|
import type * as vite from 'vite';
|
||||||
import type { AstroConfig } from '../@types/astro';
|
import type { AstroSettings } from '../@types/astro';
|
||||||
import type { LogOptions } from '../core/logger/core.js';
|
import type { LogOptions } from '../core/logger/core.js';
|
||||||
import type { ViteStyleTransformer } from '../vite-style-transform';
|
import type { ViteStyleTransformer } from '../vite-style-transform';
|
||||||
import type { PluginMetadata as AstroPluginMetadata } from './types';
|
import type { PluginMetadata as AstroPluginMetadata } from './types';
|
||||||
|
@ -22,12 +22,13 @@ import { parseAstroRequest, ParsedRequestResult } from './query.js';
|
||||||
|
|
||||||
const FRONTMATTER_PARSE_REGEXP = /^\-\-\-(.*)^\-\-\-/ms;
|
const FRONTMATTER_PARSE_REGEXP = /^\-\-\-(.*)^\-\-\-/ms;
|
||||||
interface AstroPluginOptions {
|
interface AstroPluginOptions {
|
||||||
config: AstroConfig;
|
settings: AstroSettings;
|
||||||
logging: LogOptions;
|
logging: LogOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Transform .astro files for Vite */
|
/** Transform .astro files for Vite */
|
||||||
export default function astro({ config, logging }: AstroPluginOptions): vite.Plugin {
|
export default function astro({ settings, logging }: AstroPluginOptions): vite.Plugin {
|
||||||
|
const { config } = settings;
|
||||||
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);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import type { AstroConfig } from '../@types/astro';
|
import type { AstroSettings } from '../@types/astro';
|
||||||
|
|
||||||
import type * as vite from 'vite';
|
import type * as vite from 'vite';
|
||||||
|
|
||||||
|
@ -13,10 +13,10 @@ export declare interface Alias {
|
||||||
const normalize = (pathname: string) => String(pathname).split(path.sep).join(path.posix.sep);
|
const normalize = (pathname: string) => String(pathname).split(path.sep).join(path.posix.sep);
|
||||||
|
|
||||||
/** Returns a list of compiled aliases. */
|
/** Returns a list of compiled aliases. */
|
||||||
const getConfigAlias = (astroConfig: AstroConfig): Alias[] | null => {
|
const getConfigAlias = (settings: AstroSettings): Alias[] | null => {
|
||||||
/** Closest tsconfig.json or jsconfig.json */
|
/** Closest tsconfig.json or jsconfig.json */
|
||||||
const config = astroConfig._ctx.tsConfig;
|
const config = settings.tsConfig;
|
||||||
const configPath = astroConfig._ctx.tsConfigPath;
|
const configPath = settings.tsConfigPath;
|
||||||
|
|
||||||
// if no config was found, return null
|
// if no config was found, return null
|
||||||
if (!config || !configPath) return null;
|
if (!config || !configPath) return null;
|
||||||
|
@ -77,12 +77,13 @@ const getConfigAlias = (astroConfig: AstroConfig): 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({
|
export default function configAliasVitePlugin({
|
||||||
config: astroConfig,
|
settings,
|
||||||
}: {
|
}: {
|
||||||
config: AstroConfig;
|
settings: AstroSettings;
|
||||||
}): vite.PluginOption {
|
}): vite.PluginOption {
|
||||||
|
const { config } = settings;
|
||||||
/** Aliases from the tsconfig.json or jsconfig.json configuration. */
|
/** Aliases from the tsconfig.json or jsconfig.json configuration. */
|
||||||
const configAlias = getConfigAlias(astroConfig);
|
const configAlias = getConfigAlias(settings);
|
||||||
|
|
||||||
// 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;
|
||||||
|
|
|
@ -2,10 +2,10 @@ import MagicString from 'magic-string';
|
||||||
import { fileURLToPath } from 'url';
|
import { fileURLToPath } from 'url';
|
||||||
import type * as vite from 'vite';
|
import type * as vite from 'vite';
|
||||||
import { loadEnv } from 'vite';
|
import { loadEnv } from 'vite';
|
||||||
import type { AstroConfig } from '../@types/astro';
|
import type { AstroConfig, AstroSettings } from '../@types/astro';
|
||||||
|
|
||||||
interface EnvPluginOptions {
|
interface EnvPluginOptions {
|
||||||
config: AstroConfig;
|
settings: AstroSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPrivateEnv(viteConfig: vite.ResolvedConfig, astroConfig: AstroConfig) {
|
function getPrivateEnv(viteConfig: vite.ResolvedConfig, astroConfig: AstroConfig) {
|
||||||
|
@ -51,12 +51,13 @@ function getReferencedPrivateKeys(source: string, privateEnv: Record<string, any
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function envVitePlugin({
|
export default function envVitePlugin({
|
||||||
config: astroConfig,
|
settings,
|
||||||
}: EnvPluginOptions): vite.PluginOption {
|
}: EnvPluginOptions): vite.PluginOption {
|
||||||
let privateEnv: Record<string, any> | null;
|
let privateEnv: Record<string, any> | null;
|
||||||
let config: vite.ResolvedConfig;
|
let config: vite.ResolvedConfig;
|
||||||
let replacements: Record<string, string>;
|
let replacements: Record<string, string>;
|
||||||
let pattern: RegExp | undefined;
|
let pattern: RegExp | undefined;
|
||||||
|
const { config: astroConfig } = settings;
|
||||||
return {
|
return {
|
||||||
name: 'astro:vite-plugin-env',
|
name: 'astro:vite-plugin-env',
|
||||||
enforce: 'pre',
|
enforce: 'pre',
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
import { Plugin as VitePlugin } from 'vite';
|
import { Plugin as VitePlugin } from 'vite';
|
||||||
import { AstroConfig } from '../@types/astro.js';
|
import { AstroSettings } from '../@types/astro.js';
|
||||||
import { LogOptions } from '../core/logger/core.js';
|
import { LogOptions } from '../core/logger/core.js';
|
||||||
import { runHookServerSetup } from '../integrations/index.js';
|
import { runHookServerSetup } from '../integrations/index.js';
|
||||||
|
|
||||||
/** Connect Astro integrations into Vite, as needed. */
|
/** Connect Astro integrations into Vite, as needed. */
|
||||||
export default function astroIntegrationsContainerPlugin({
|
export default function astroIntegrationsContainerPlugin({
|
||||||
config,
|
settings,
|
||||||
logging,
|
logging,
|
||||||
}: {
|
}: {
|
||||||
config: AstroConfig;
|
settings: AstroSettings;
|
||||||
logging: LogOptions;
|
logging: LogOptions;
|
||||||
}): VitePlugin {
|
}): VitePlugin {
|
||||||
return {
|
return {
|
||||||
name: 'astro:integration-container',
|
name: 'astro:integration-container',
|
||||||
configureServer(server) {
|
configureServer(server) {
|
||||||
runHookServerSetup({ config, server, logging });
|
runHookServerSetup({ config: settings.config, server, logging });
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import type { TransformResult } from 'rollup';
|
import type { TransformResult } from 'rollup';
|
||||||
import type { TsConfigJson } from 'tsconfig-resolver';
|
import type { TsConfigJson } from 'tsconfig-resolver';
|
||||||
import type { Plugin, ResolvedConfig } from 'vite';
|
import type { Plugin, ResolvedConfig } from 'vite';
|
||||||
import type { AstroConfig, AstroRenderer } from '../@types/astro';
|
import type { AstroSettings, AstroRenderer } from '../@types/astro';
|
||||||
import type { LogOptions } from '../core/logger/core.js';
|
import type { LogOptions } from '../core/logger/core.js';
|
||||||
import type { PluginMetadata } from '../vite-plugin-astro/types';
|
import type { PluginMetadata } from '../vite-plugin-astro/types';
|
||||||
|
|
||||||
|
@ -152,12 +152,12 @@ async function transformJSX({
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AstroPluginJSXOptions {
|
interface AstroPluginJSXOptions {
|
||||||
config: AstroConfig;
|
settings: AstroSettings;
|
||||||
logging: LogOptions;
|
logging: LogOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Use Astro config to allow for alternate or multiple JSX renderers (by default Vite will assume React) */
|
/** Use Astro config to allow for alternate or multiple JSX renderers (by default Vite will assume React) */
|
||||||
export default function jsx({ config, logging }: AstroPluginJSXOptions): Plugin {
|
export default function jsx({ settings, logging }: AstroPluginJSXOptions): Plugin {
|
||||||
let viteConfig: ResolvedConfig;
|
let viteConfig: ResolvedConfig;
|
||||||
const jsxRenderers = new Map<string, AstroRenderer>();
|
const jsxRenderers = new Map<string, AstroRenderer>();
|
||||||
const jsxRenderersIntegrationOnly = new Map<string, AstroRenderer>();
|
const jsxRenderersIntegrationOnly = new Map<string, AstroRenderer>();
|
||||||
|
@ -172,7 +172,7 @@ export default function jsx({ config, logging }: AstroPluginJSXOptions): Plugin
|
||||||
enforce: 'pre', // run transforms before other plugins
|
enforce: 'pre', // run transforms before other plugins
|
||||||
async configResolved(resolvedConfig) {
|
async configResolved(resolvedConfig) {
|
||||||
viteConfig = resolvedConfig;
|
viteConfig = resolvedConfig;
|
||||||
const possibleRenderers = collectJSXRenderers(config._ctx.renderers);
|
const possibleRenderers = collectJSXRenderers(settings.renderers);
|
||||||
for (const [importSource, renderer] of possibleRenderers) {
|
for (const [importSource, renderer] of possibleRenderers) {
|
||||||
jsxRenderers.set(importSource, renderer);
|
jsxRenderers.set(importSource, renderer);
|
||||||
if (importSource === 'astro') {
|
if (importSource === 'astro') {
|
||||||
|
@ -230,7 +230,7 @@ export default function jsx({ config, logging }: AstroPluginJSXOptions): Plugin
|
||||||
|
|
||||||
// Check the tsconfig
|
// Check the tsconfig
|
||||||
if (!importSource) {
|
if (!importSource) {
|
||||||
const compilerOptions = config._ctx.tsConfig?.compilerOptions;
|
const compilerOptions = settings.tsConfig?.compilerOptions;
|
||||||
importSource = (compilerOptions as FixedCompilerOptions | undefined)?.jsxImportSource;
|
importSource = (compilerOptions as FixedCompilerOptions | undefined)?.jsxImportSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import fs from 'fs';
|
||||||
import matter from 'gray-matter';
|
import matter from 'gray-matter';
|
||||||
import { fileURLToPath } from 'url';
|
import { fileURLToPath } from 'url';
|
||||||
import type { Plugin, ViteDevServer } from 'vite';
|
import type { Plugin, ViteDevServer } from 'vite';
|
||||||
import type { AstroConfig } from '../@types/astro';
|
import type { AstroSettings } from '../@types/astro';
|
||||||
import { pagesVirtualModuleId } from '../core/app/index.js';
|
import { pagesVirtualModuleId } from '../core/app/index.js';
|
||||||
import { cachedCompilation, CompileProps } from '../core/compile/index.js';
|
import { cachedCompilation, CompileProps } from '../core/compile/index.js';
|
||||||
import { collectErrorMetadata } from '../core/errors.js';
|
import { collectErrorMetadata } from '../core/errors.js';
|
||||||
|
@ -19,7 +19,7 @@ import {
|
||||||
} from '../vite-style-transform/index.js';
|
} from '../vite-style-transform/index.js';
|
||||||
|
|
||||||
interface AstroPluginOptions {
|
interface AstroPluginOptions {
|
||||||
config: AstroConfig;
|
settings: AstroSettings;
|
||||||
logging: LogOptions;
|
logging: LogOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +38,8 @@ function safeMatter(source: string, id: string) {
|
||||||
// TODO: Clean up some of the shared logic between this Markdown plugin and the Astro plugin.
|
// TODO: Clean up some of the shared logic between this Markdown plugin and the Astro plugin.
|
||||||
// Both end up connecting a `load()` hook to the Astro compiler, and share some copy-paste
|
// Both end up connecting a `load()` hook to the Astro compiler, and share some copy-paste
|
||||||
// logic in how that is done.
|
// logic in how that is done.
|
||||||
export default function markdown({ config, logging }: AstroPluginOptions): Plugin {
|
export default function markdown({ settings }: AstroPluginOptions): Plugin {
|
||||||
|
const { config } = settings;
|
||||||
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);
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { renderMarkdown } from '@astrojs/markdown-remark';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import matter from 'gray-matter';
|
import matter from 'gray-matter';
|
||||||
import type { Plugin } from 'vite';
|
import type { Plugin } from 'vite';
|
||||||
import type { AstroConfig } from '../@types/astro';
|
import type { AstroSettings } from '../@types/astro';
|
||||||
import { collectErrorMetadata } from '../core/errors.js';
|
import { collectErrorMetadata } from '../core/errors.js';
|
||||||
import type { LogOptions } from '../core/logger/core.js';
|
import type { LogOptions } from '../core/logger/core.js';
|
||||||
import { warn } from '../core/logger/core.js';
|
import { warn } from '../core/logger/core.js';
|
||||||
|
@ -10,7 +10,7 @@ import type { PluginMetadata } from '../vite-plugin-astro/types.js';
|
||||||
import { getFileInfo, safelyGetAstroData } from '../vite-plugin-utils/index.js';
|
import { getFileInfo, safelyGetAstroData } from '../vite-plugin-utils/index.js';
|
||||||
|
|
||||||
interface AstroPluginOptions {
|
interface AstroPluginOptions {
|
||||||
config: AstroConfig;
|
settings: AstroSettings;
|
||||||
logging: LogOptions;
|
logging: LogOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ function safeMatter(source: string, id: string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function markdown({ config, logging }: AstroPluginOptions): Plugin {
|
export default function markdown({ settings, logging }: AstroPluginOptions): Plugin {
|
||||||
return {
|
return {
|
||||||
enforce: 'pre',
|
enforce: 'pre',
|
||||||
name: 'astro:markdown',
|
name: 'astro:markdown',
|
||||||
|
@ -33,11 +33,11 @@ export default function markdown({ config, logging }: AstroPluginOptions): Plugi
|
||||||
// to escape "import.meta.env" ourselves.
|
// to escape "import.meta.env" ourselves.
|
||||||
async load(id) {
|
async load(id) {
|
||||||
if (id.endsWith('.md')) {
|
if (id.endsWith('.md')) {
|
||||||
const { fileId, fileUrl } = getFileInfo(id, config);
|
const { fileId, fileUrl } = getFileInfo(id, settings.config);
|
||||||
const rawFile = await fs.promises.readFile(fileId, 'utf-8');
|
const rawFile = await fs.promises.readFile(fileId, 'utf-8');
|
||||||
const raw = safeMatter(rawFile, id);
|
const raw = safeMatter(rawFile, id);
|
||||||
const renderResult = await renderMarkdown(raw.content, {
|
const renderResult = await renderMarkdown(raw.content, {
|
||||||
...config.markdown,
|
...settings.config.markdown,
|
||||||
fileURL: new URL(`file://${fileId}`),
|
fileURL: new URL(`file://${fileId}`),
|
||||||
isAstroFlavoredMd: false,
|
isAstroFlavoredMd: false,
|
||||||
} as any);
|
} as any);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { ConfigEnv, Plugin as VitePlugin } from 'vite';
|
import { ConfigEnv, Plugin as VitePlugin } from 'vite';
|
||||||
import { AstroConfig, InjectedScriptStage } from '../@types/astro.js';
|
import { AstroSettings, InjectedScriptStage } from '../@types/astro.js';
|
||||||
|
|
||||||
// NOTE: We can't use the virtual "\0" ID convention because we need to
|
// NOTE: We can't use the virtual "\0" ID convention because we need to
|
||||||
// inject these as ESM imports into actual code, where they would not
|
// inject these as ESM imports into actual code, where they would not
|
||||||
|
@ -11,7 +11,7 @@ export const BEFORE_HYDRATION_SCRIPT_ID = `${SCRIPT_ID_PREFIX}${
|
||||||
export const PAGE_SCRIPT_ID = `${SCRIPT_ID_PREFIX}${'page' as InjectedScriptStage}.js`;
|
export const PAGE_SCRIPT_ID = `${SCRIPT_ID_PREFIX}${'page' as InjectedScriptStage}.js`;
|
||||||
export const PAGE_SSR_SCRIPT_ID = `${SCRIPT_ID_PREFIX}${'page-ssr' as InjectedScriptStage}.js`;
|
export const PAGE_SSR_SCRIPT_ID = `${SCRIPT_ID_PREFIX}${'page-ssr' as InjectedScriptStage}.js`;
|
||||||
|
|
||||||
export default function astroScriptsPlugin({ config }: { config: AstroConfig }): VitePlugin {
|
export default function astroScriptsPlugin({ settings }: { settings: AstroSettings }): VitePlugin {
|
||||||
let env: ConfigEnv | undefined = undefined;
|
let env: ConfigEnv | undefined = undefined;
|
||||||
return {
|
return {
|
||||||
name: 'astro:scripts',
|
name: 'astro:scripts',
|
||||||
|
@ -29,19 +29,19 @@ export default function astroScriptsPlugin({ config }: { config: AstroConfig }):
|
||||||
|
|
||||||
async load(id) {
|
async load(id) {
|
||||||
if (id === BEFORE_HYDRATION_SCRIPT_ID) {
|
if (id === BEFORE_HYDRATION_SCRIPT_ID) {
|
||||||
return config._ctx.scripts
|
return settings.scripts
|
||||||
.filter((s) => s.stage === 'before-hydration')
|
.filter((s) => s.stage === 'before-hydration')
|
||||||
.map((s) => s.content)
|
.map((s) => s.content)
|
||||||
.join('\n');
|
.join('\n');
|
||||||
}
|
}
|
||||||
if (id === PAGE_SCRIPT_ID) {
|
if (id === PAGE_SCRIPT_ID) {
|
||||||
return config._ctx.scripts
|
return settings.scripts
|
||||||
.filter((s) => s.stage === 'page')
|
.filter((s) => s.stage === 'page')
|
||||||
.map((s) => s.content)
|
.map((s) => s.content)
|
||||||
.join('\n');
|
.join('\n');
|
||||||
}
|
}
|
||||||
if (id === PAGE_SSR_SCRIPT_ID) {
|
if (id === PAGE_SSR_SCRIPT_ID) {
|
||||||
return config._ctx.scripts
|
return settings.scripts
|
||||||
.filter((s) => s.stage === 'page-ssr')
|
.filter((s) => s.stage === 'page-ssr')
|
||||||
.map((s) => s.content)
|
.map((s) => s.content)
|
||||||
.join('\n');
|
.join('\n');
|
||||||
|
@ -49,7 +49,7 @@ export default function astroScriptsPlugin({ config }: { config: AstroConfig }):
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
buildStart(options) {
|
buildStart(options) {
|
||||||
const hasHydrationScripts = config._ctx.scripts.some((s) => s.stage === 'before-hydration');
|
const hasHydrationScripts = settings.scripts.some((s) => s.stage === 'before-hydration');
|
||||||
if (hasHydrationScripts && env?.command === 'build' && !env?.ssrBuild) {
|
if (hasHydrationScripts && env?.command === 'build' && !env?.ssrBuild) {
|
||||||
this.emitFile({
|
this.emitFile({
|
||||||
type: 'chunk',
|
type: 'chunk',
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
import { Plugin as VitePlugin } from 'vite';
|
import { Plugin as VitePlugin } from 'vite';
|
||||||
import { AstroConfig } from '../@types/astro.js';
|
import { AstroSettings } from '../@types/astro.js';
|
||||||
import { PAGE_SSR_SCRIPT_ID } from './index.js';
|
import { PAGE_SSR_SCRIPT_ID } from './index.js';
|
||||||
|
|
||||||
import ancestor from 'common-ancestor-path';
|
import ancestor from 'common-ancestor-path';
|
||||||
import MagicString from 'magic-string';
|
import MagicString from 'magic-string';
|
||||||
import { isPage } from '../core/util.js';
|
import { isPage } from '../core/util.js';
|
||||||
|
|
||||||
export default function astroScriptsPostPlugin({ config }: { config: AstroConfig }): VitePlugin {
|
export default function astroScriptsPostPlugin({ settings }: { settings: AstroSettings }): VitePlugin {
|
||||||
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.root.pathname)) {
|
} else if (filename.startsWith('/') && !ancestor(filename, settings.config.root.pathname)) {
|
||||||
filename = new URL('.' + filename, config.root).pathname;
|
filename = new URL('.' + filename, settings.config.root).pathname;
|
||||||
}
|
}
|
||||||
return filename;
|
return filename;
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ export default function astroScriptsPostPlugin({ config }: { config: AstroConfig
|
||||||
transform(this, code, id, options) {
|
transform(this, code, id, options) {
|
||||||
if (!options?.ssr) return;
|
if (!options?.ssr) return;
|
||||||
|
|
||||||
const hasInjectedScript = config._ctx.scripts.some((s) => s.stage === 'page-ssr');
|
const hasInjectedScript = settings.scripts.some((s) => s.stage === 'page-ssr');
|
||||||
if (!hasInjectedScript) return;
|
if (!hasInjectedScript) return;
|
||||||
|
|
||||||
const filename = normalizeFilename(id);
|
const filename = normalizeFilename(id);
|
||||||
|
@ -35,7 +35,7 @@ export default function astroScriptsPostPlugin({ config }: { config: AstroConfig
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileIsPage = isPage(fileURL, config);
|
const fileIsPage = isPage(fileURL, settings);
|
||||||
if (!fileIsPage) return;
|
if (!fileIsPage) return;
|
||||||
|
|
||||||
const s = new MagicString(code, { filename });
|
const s = new MagicString(code, { filename });
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { load as cheerioLoad } from 'cheerio';
|
||||||
import { loadFixture } from './test-utils.js';
|
import { loadFixture } from './test-utils.js';
|
||||||
import testAdapter from './test-adapter.js';
|
import testAdapter from './test-adapter.js';
|
||||||
|
|
||||||
describe('AstroConfig - config.mode', () => {
|
describe('AstroConfig - config.output', () => {
|
||||||
describe(`output: 'server'`, () => {
|
describe(`output: 'server'`, () => {
|
||||||
describe('deploy config provided', () => {
|
describe('deploy config provided', () => {
|
||||||
/** @type {import('./test-utils').Fixture} */
|
/** @type {import('./test-utils').Fixture} */
|
||||||
|
@ -58,7 +58,7 @@ describe('AstroConfig - config.mode', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe(`output: 'static'`, () => {
|
describe(`output: 'static'`, () => {
|
||||||
describe('Deploy config omitted', () => {
|
describe('Output config omitted', () => {
|
||||||
/** @type {import('./test-utils').Fixture} */
|
/** @type {import('./test-utils').Fixture} */
|
||||||
let fixture;
|
let fixture;
|
||||||
|
|
||||||
|
|
|
@ -1,126 +0,0 @@
|
||||||
import { expect } from 'chai';
|
|
||||||
import { loadFixture, cliServerLogSetup } from './test-utils.js';
|
|
||||||
import { fileURLToPath } from 'url';
|
|
||||||
import { isIPv4 } from 'net';
|
|
||||||
|
|
||||||
describe('config', () => {
|
|
||||||
let hostFixture;
|
|
||||||
let portFixture;
|
|
||||||
|
|
||||||
before(async () => {
|
|
||||||
[hostFixture, portFixture] = await Promise.all([
|
|
||||||
loadFixture({
|
|
||||||
root: './fixtures/config-host/',
|
|
||||||
server: {
|
|
||||||
host: true,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
loadFixture({
|
|
||||||
root: './fixtures/config-host/',
|
|
||||||
server: {
|
|
||||||
port: 5006,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('host', () => {
|
|
||||||
it('can be specified in astro.config.mjs', async () => {
|
|
||||||
expect(hostFixture.config.server.host).to.equal(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can be specified via --host flag', async () => {
|
|
||||||
const projectRootURL = new URL('./fixtures/astro-basic/', import.meta.url);
|
|
||||||
const { network } = await cliServerLogSetup([
|
|
||||||
'--root',
|
|
||||||
fileURLToPath(projectRootURL),
|
|
||||||
'--host',
|
|
||||||
]);
|
|
||||||
|
|
||||||
const networkURL = new URL(network);
|
|
||||||
expect(isIPv4(networkURL.hostname)).to.be.equal(
|
|
||||||
true,
|
|
||||||
`Expected network URL to respect --host flag`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('path', () => {
|
|
||||||
it('can be passed via --config', async () => {
|
|
||||||
const projectRootURL = new URL('./fixtures/astro-basic/', import.meta.url);
|
|
||||||
const configFileURL = new URL('./fixtures/config-path/config/my-config.mjs', import.meta.url);
|
|
||||||
const { network } = await cliServerLogSetup([
|
|
||||||
'--root',
|
|
||||||
fileURLToPath(projectRootURL),
|
|
||||||
'--config',
|
|
||||||
configFileURL.pathname,
|
|
||||||
]);
|
|
||||||
|
|
||||||
const networkURL = new URL(network);
|
|
||||||
expect(isIPv4(networkURL.hostname)).to.be.equal(
|
|
||||||
true,
|
|
||||||
`Expected network URL to respect --host flag`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('relative path', () => {
|
|
||||||
it('can be passed via relative --config', async () => {
|
|
||||||
const projectRootURL = new URL('./fixtures/astro-basic/', import.meta.url);
|
|
||||||
const configFileURL = 'my-config.mjs';
|
|
||||||
const { local } = await cliServerLogSetup([
|
|
||||||
'--root',
|
|
||||||
fileURLToPath(projectRootURL),
|
|
||||||
'--config',
|
|
||||||
configFileURL,
|
|
||||||
]);
|
|
||||||
|
|
||||||
const localURL = new URL(local);
|
|
||||||
expect(localURL.port).to.equal('8080');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('relative path with leading ./', () => {
|
|
||||||
it('can be passed via relative --config', async () => {
|
|
||||||
const projectRootURL = new URL('./fixtures/astro-basic/', import.meta.url);
|
|
||||||
const configFileURL = './my-config.mjs';
|
|
||||||
const { local } = await cliServerLogSetup([
|
|
||||||
'--root',
|
|
||||||
fileURLToPath(projectRootURL),
|
|
||||||
'--config',
|
|
||||||
configFileURL,
|
|
||||||
]);
|
|
||||||
|
|
||||||
const localURL = new URL(local);
|
|
||||||
expect(localURL.port).to.equal('8080');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('incorrect path', () => {
|
|
||||||
it('fails and exits when config does not exist', async () => {
|
|
||||||
const projectRootURL = new URL('./fixtures/astro-basic/', import.meta.url);
|
|
||||||
const configFileURL = './does-not-exist.mjs';
|
|
||||||
let exit = 0;
|
|
||||||
try {
|
|
||||||
await cliServerLogSetup([
|
|
||||||
'--root',
|
|
||||||
fileURLToPath(projectRootURL),
|
|
||||||
'--config',
|
|
||||||
configFileURL,
|
|
||||||
]);
|
|
||||||
} catch (e) {
|
|
||||||
if (e.message.includes('Unable to resolve --config')) {
|
|
||||||
exit = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(exit).to.equal(1, 'Throws helpful error message when --config does not exist');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('port', () => {
|
|
||||||
it('can be specified in astro.config.mjs', async () => {
|
|
||||||
expect(portFixture.config.server.port).to.deep.equal(5006);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -2,7 +2,8 @@ import { execa } from 'execa';
|
||||||
import { polyfill } from '@astrojs/webapi';
|
import { polyfill } from '@astrojs/webapi';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import { fileURLToPath } from 'url';
|
import { fileURLToPath } from 'url';
|
||||||
import { loadConfig } from '../dist/core/config.js';
|
import { loadConfig } from '../dist/core/config/config.js';
|
||||||
|
import { createSettings, loadTSConfig } from '../dist/core/config/index.js';
|
||||||
import dev from '../dist/core/dev/index.js';
|
import dev from '../dist/core/dev/index.js';
|
||||||
import build from '../dist/core/build/index.js';
|
import build from '../dist/core/build/index.js';
|
||||||
import preview from '../dist/core/preview/index.js';
|
import preview from '../dist/core/preview/index.js';
|
||||||
|
@ -18,7 +19,7 @@ polyfill(globalThis, {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {import('node-fetch').Response} Response
|
* @typedef {import('node-fetch').Response} Response
|
||||||
* @typedef {import('../src/core/dev/index').DevServer} DevServer
|
* @typedef {import('../src/core/dev/index').DedvServer} DevServer
|
||||||
* @typedef {import('../src/@types/astro').AstroConfig} AstroConfig
|
* @typedef {import('../src/@types/astro').AstroConfig} AstroConfig
|
||||||
* @typedef {import('../src/core/preview/index').PreviewServer} PreviewServer
|
* @typedef {import('../src/core/preview/index').PreviewServer} PreviewServer
|
||||||
* @typedef {import('../src/core/app/index').App} App
|
* @typedef {import('../src/core/app/index').App} App
|
||||||
|
@ -39,6 +40,12 @@ polyfill(globalThis, {
|
||||||
* @property {() => Promise<void>} onNextChange
|
* @property {() => Promise<void>} onNextChange
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/** @type {import('../src/core/logger/core').LogOptions} */
|
||||||
|
export const defaultLogging = {
|
||||||
|
dest: nodeLogDestination,
|
||||||
|
level: 'error',
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load Astro fixture
|
* Load Astro fixture
|
||||||
* @param {AstroConfig} inlineConfig Astro config partial (note: must specify `root`)
|
* @param {AstroConfig} inlineConfig Astro config partial (note: must specify `root`)
|
||||||
|
@ -75,10 +82,7 @@ export async function loadFixture(inlineConfig) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @type {import('../src/core/logger/core').LogOptions} */
|
/** @type {import('../src/core/logger/core').LogOptions} */
|
||||||
const logging = {
|
const logging = defaultLogging;
|
||||||
dest: nodeLogDestination,
|
|
||||||
level: 'error',
|
|
||||||
};
|
|
||||||
|
|
||||||
// Load the config.
|
// Load the config.
|
||||||
let config = await loadConfig({ cwd: fileURLToPath(cwd), logging });
|
let config = await loadConfig({ cwd: fileURLToPath(cwd), logging });
|
||||||
|
@ -91,10 +95,16 @@ export async function loadFixture(inlineConfig) {
|
||||||
if (inlineConfig.base && !inlineConfig.base.endsWith('/')) {
|
if (inlineConfig.base && !inlineConfig.base.endsWith('/')) {
|
||||||
config.base = inlineConfig.base + '/';
|
config.base = inlineConfig.base + '/';
|
||||||
}
|
}
|
||||||
|
let tsconfig = loadTSConfig(fileURLToPath(cwd));
|
||||||
|
let settings = createSettings({
|
||||||
|
config,
|
||||||
|
tsConfig: tsconfig?.config,
|
||||||
|
tsConfigPath: tsconfig?.path
|
||||||
|
});
|
||||||
if (config.integrations.find((integration) => integration.name === '@astrojs/mdx')) {
|
if (config.integrations.find((integration) => integration.name === '@astrojs/mdx')) {
|
||||||
// Enable default JSX integration. It needs to come first, so unshift rather than push!
|
// Enable default JSX integration. It needs to come first, so unshift rather than push!
|
||||||
const { default: jsxRenderer } = await import('astro/jsx/renderer.js');
|
const { default: jsxRenderer } = await import('astro/jsx/renderer.js');
|
||||||
config._ctx.renderers.unshift(jsxRenderer);
|
settings.renderers.unshift(jsxRenderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @type {import('@astrojs/telemetry').AstroTelemetry} */
|
/** @type {import('@astrojs/telemetry').AstroTelemetry} */
|
||||||
|
@ -133,9 +143,9 @@ export async function loadFixture(inlineConfig) {
|
||||||
let devServer;
|
let devServer;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
build: (opts = {}) => build(config, { logging, telemetry, ...opts }),
|
build: (opts = {}) => build(settings, { logging, telemetry, ...opts }),
|
||||||
startDevServer: async (opts = {}) => {
|
startDevServer: async (opts = {}) => {
|
||||||
devServer = await dev(config, { logging, telemetry, ...opts });
|
devServer = await dev(settings, { logging, telemetry, ...opts });
|
||||||
config.server.port = devServer.address.port; // update port
|
config.server.port = devServer.address.port; // update port
|
||||||
return devServer;
|
return devServer;
|
||||||
},
|
},
|
||||||
|
@ -143,7 +153,7 @@ export async function loadFixture(inlineConfig) {
|
||||||
resolveUrl,
|
resolveUrl,
|
||||||
fetch: (url, init) => fetch(resolveUrl(url), init),
|
fetch: (url, init) => fetch(resolveUrl(url), init),
|
||||||
preview: async (opts = {}) => {
|
preview: async (opts = {}) => {
|
||||||
const previewServer = await preview(config, { logging, telemetry, ...opts });
|
const previewServer = await preview(settings, { logging, telemetry, ...opts });
|
||||||
return previewServer;
|
return previewServer;
|
||||||
},
|
},
|
||||||
readFile: (filePath, encoding) =>
|
readFile: (filePath, encoding) =>
|
||||||
|
|
71
packages/astro/test/units/config/config-server.test.js
Normal file
71
packages/astro/test/units/config/config-server.test.js
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
import { expect } from 'chai';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
import { defaultLogging as logging } from '../../test-utils.js';
|
||||||
|
import { openConfig } from '../../../dist/core/config/index.js';
|
||||||
|
|
||||||
|
const cwd = fileURLToPath(new URL('../../fixtures/config-host/', import.meta.url));
|
||||||
|
|
||||||
|
describe('config.server', () => {
|
||||||
|
function openConfigWithFlags(flags) {
|
||||||
|
return openConfig({
|
||||||
|
cwd: flags.root || cwd,
|
||||||
|
flags,
|
||||||
|
cmd: 'dev',
|
||||||
|
logging
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('host', () => {
|
||||||
|
it('can be specified via --host flag', async () => {
|
||||||
|
const projectRootURL = new URL('../../fixtures/astro-basic/', import.meta.url);
|
||||||
|
const { astroConfig } = await openConfigWithFlags({
|
||||||
|
root: fileURLToPath(projectRootURL),
|
||||||
|
host: true
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(astroConfig.server.host).to.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('config', () => {
|
||||||
|
describe('relative path', () => {
|
||||||
|
it('can be passed via relative --config', async () => {
|
||||||
|
const projectRootURL = new URL('../../fixtures/astro-basic/', import.meta.url);
|
||||||
|
const configFileURL = 'my-config.mjs';
|
||||||
|
const { astroConfig } = await openConfigWithFlags({
|
||||||
|
root: fileURLToPath(projectRootURL),
|
||||||
|
config: configFileURL
|
||||||
|
});
|
||||||
|
expect(astroConfig.server.port).to.equal(8080);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('relative path with leading ./', () => {
|
||||||
|
it('can be passed via relative --config', async () => {
|
||||||
|
const projectRootURL = new URL('../../fixtures/astro-basic/', import.meta.url);
|
||||||
|
const configFileURL = './my-config.mjs';
|
||||||
|
const { astroConfig } = await openConfigWithFlags({
|
||||||
|
root: fileURLToPath(projectRootURL),
|
||||||
|
config: configFileURL
|
||||||
|
});
|
||||||
|
expect(astroConfig.server.port).to.equal(8080);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('incorrect path', () => {
|
||||||
|
it('fails and exits when config does not exist', async () => {
|
||||||
|
const projectRootURL = new URL('../../fixtures/astro-basic/', import.meta.url);
|
||||||
|
const configFileURL = './does-not-exist.mjs';
|
||||||
|
try {
|
||||||
|
await openConfigWithFlags({
|
||||||
|
root: fileURLToPath(projectRootURL),
|
||||||
|
config: configFileURL
|
||||||
|
});
|
||||||
|
expect(false).to.equal(true, 'this should not have resolved');
|
||||||
|
} catch(err) {
|
||||||
|
expect(err.message).to.match(/Unable to resolve/);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
|
@ -1,8 +1,8 @@
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import stripAnsi from 'strip-ansi';
|
import stripAnsi from 'strip-ansi';
|
||||||
import { formatConfigErrorMessage } from '../dist/core/messages.js';
|
import { formatConfigErrorMessage } from '../../../dist/core/messages.js';
|
||||||
import { validateConfig } from '../dist/core/config.js';
|
import { validateConfig } from '../../../dist/core/config/index.js';
|
||||||
|
|
||||||
describe('Config Validation', () => {
|
describe('Config Validation', () => {
|
||||||
it('empty user config is valid', async () => {
|
it('empty user config is valid', async () => {
|
Loading…
Add table
Reference in a new issue