Refactor and improve Astro config loading flow (#7879)
This commit is contained in:
parent
9e22038472
commit
ebf7ebbf7a
57 changed files with 740 additions and 825 deletions
5
.changeset/twenty-oranges-poke.md
Normal file
5
.changeset/twenty-oranges-poke.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'astro': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Refactor and improve Astro config loading flow
|
|
@ -1,5 +1,5 @@
|
||||||
import { expect } from '@playwright/test';
|
import { expect } from '@playwright/test';
|
||||||
import { getErrorOverlayContent, silentLogging, testFactory } from './test-utils.js';
|
import { getErrorOverlayContent, testFactory } from './test-utils.js';
|
||||||
|
|
||||||
const test = testFactory({
|
const test = testFactory({
|
||||||
root: './fixtures/errors/',
|
root: './fixtures/errors/',
|
||||||
|
@ -12,10 +12,7 @@ const test = testFactory({
|
||||||
let devServer;
|
let devServer;
|
||||||
|
|
||||||
test.beforeAll(async ({ astro }) => {
|
test.beforeAll(async ({ astro }) => {
|
||||||
devServer = await astro.startDevServer({
|
devServer = await astro.startDevServer();
|
||||||
// Only test the error overlay, don't print to console
|
|
||||||
logging: silentLogging,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test.afterAll(async ({ astro }) => {
|
test.afterAll(async ({ astro }) => {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { expect, test as testBase } from '@playwright/test';
|
import { expect, test as testBase } from '@playwright/test';
|
||||||
import fs from 'node:fs/promises';
|
import fs from 'node:fs/promises';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
import { loadFixture as baseLoadFixture } from '../test/test-utils.js';
|
import { loadFixture as baseLoadFixture } from '../test/test-utils.js';
|
||||||
|
|
||||||
export const isWindows = process.platform === 'win32';
|
export const isWindows = process.platform === 'win32';
|
||||||
|
@ -24,7 +25,7 @@ export function loadFixture(inlineConfig) {
|
||||||
// without this, the main `loadFixture` helper will resolve relative to `packages/astro/test`
|
// without this, the main `loadFixture` helper will resolve relative to `packages/astro/test`
|
||||||
return baseLoadFixture({
|
return baseLoadFixture({
|
||||||
...inlineConfig,
|
...inlineConfig,
|
||||||
root: new URL(inlineConfig.root, import.meta.url).toString(),
|
root: fileURLToPath(new URL(inlineConfig.root, import.meta.url)),
|
||||||
server: {
|
server: {
|
||||||
port: testFileToPort.get(path.basename(inlineConfig.root)),
|
port: testFileToPort.get(path.basename(inlineConfig.root)),
|
||||||
},
|
},
|
||||||
|
|
|
@ -19,7 +19,7 @@ import type { PageBuildData } from '../core/build/types';
|
||||||
import type { AstroConfigSchema } from '../core/config';
|
import type { AstroConfigSchema } from '../core/config';
|
||||||
import type { AstroTimer } from '../core/config/timer';
|
import type { AstroTimer } from '../core/config/timer';
|
||||||
import type { AstroCookies } from '../core/cookies';
|
import type { AstroCookies } from '../core/cookies';
|
||||||
import type { LogOptions } from '../core/logger/core';
|
import type { LogOptions, LoggerLevel } from '../core/logger/core';
|
||||||
import type { AstroComponentFactory, AstroComponentInstance } from '../runtime/server';
|
import type { AstroComponentFactory, AstroComponentInstance } from '../runtime/server';
|
||||||
import type { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from './../core/constants.js';
|
import type { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from './../core/constants.js';
|
||||||
export type {
|
export type {
|
||||||
|
@ -1331,6 +1331,16 @@ export interface AstroConfig extends z.output<typeof AstroConfigSchema> {
|
||||||
// TypeScript still confirms zod validation matches this type.
|
// TypeScript still confirms zod validation matches this type.
|
||||||
integrations: AstroIntegration[];
|
integrations: AstroIntegration[];
|
||||||
}
|
}
|
||||||
|
export interface AstroInlineConfig extends AstroUserConfig, AstroInlineOnlyConfig {}
|
||||||
|
export interface AstroInlineOnlyConfig {
|
||||||
|
configFile?: string | false;
|
||||||
|
mode?: RuntimeMode;
|
||||||
|
logLevel?: LoggerLevel;
|
||||||
|
/**
|
||||||
|
* @internal for testing only
|
||||||
|
*/
|
||||||
|
logging?: LogOptions;
|
||||||
|
}
|
||||||
|
|
||||||
export type ContentEntryModule = {
|
export type ContentEntryModule = {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
|
@ -9,7 +9,7 @@ import ora from 'ora';
|
||||||
import preferredPM from 'preferred-pm';
|
import preferredPM from 'preferred-pm';
|
||||||
import prompts from 'prompts';
|
import prompts from 'prompts';
|
||||||
import type yargs from 'yargs-parser';
|
import type yargs from 'yargs-parser';
|
||||||
import { loadTSConfig, resolveConfigPath } from '../../core/config/index.js';
|
import { loadTSConfig, resolveConfigPath, resolveRoot } from '../../core/config/index.js';
|
||||||
import {
|
import {
|
||||||
defaultTSConfig,
|
defaultTSConfig,
|
||||||
presets,
|
presets,
|
||||||
|
@ -23,12 +23,12 @@ import { appendForwardSlash } from '../../core/path.js';
|
||||||
import { apply as applyPolyfill } from '../../core/polyfill.js';
|
import { apply as applyPolyfill } from '../../core/polyfill.js';
|
||||||
import { parseNpmName } from '../../core/util.js';
|
import { parseNpmName } from '../../core/util.js';
|
||||||
import { eventCliSession, telemetry } from '../../events/index.js';
|
import { eventCliSession, telemetry } from '../../events/index.js';
|
||||||
|
import { createLoggingFromFlags } from '../flags.js';
|
||||||
import { generate, parse, t, visit } from './babel.js';
|
import { generate, parse, t, visit } from './babel.js';
|
||||||
import { ensureImport } from './imports.js';
|
import { ensureImport } from './imports.js';
|
||||||
import { wrapDefaultExport } from './wrapper.js';
|
import { wrapDefaultExport } from './wrapper.js';
|
||||||
|
|
||||||
interface AddOptions {
|
interface AddOptions {
|
||||||
logging: LogOptions;
|
|
||||||
flags: yargs.Arguments;
|
flags: yargs.Arguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ async function getRegistry(): Promise<string> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function add(names: string[], { flags, logging }: AddOptions) {
|
export async function add(names: string[], { flags }: AddOptions) {
|
||||||
telemetry.record(eventCliSession('add'));
|
telemetry.record(eventCliSession('add'));
|
||||||
applyPolyfill();
|
applyPolyfill();
|
||||||
if (flags.help || names.length === 0) {
|
if (flags.help || names.length === 0) {
|
||||||
|
@ -130,10 +130,12 @@ export async function add(names: string[], { flags, logging }: AddOptions) {
|
||||||
|
|
||||||
// Some packages might have a common alias! We normalize those here.
|
// Some packages might have a common alias! We normalize those here.
|
||||||
const cwd = flags.root;
|
const cwd = flags.root;
|
||||||
|
const logging = createLoggingFromFlags(flags);
|
||||||
const integrationNames = names.map((name) => (ALIASES.has(name) ? ALIASES.get(name)! : name));
|
const integrationNames = names.map((name) => (ALIASES.has(name) ? ALIASES.get(name)! : name));
|
||||||
const integrations = await validateIntegrations(integrationNames);
|
const integrations = await validateIntegrations(integrationNames);
|
||||||
let installResult = await tryToInstallIntegrations({ integrations, cwd, flags, logging });
|
let installResult = await tryToInstallIntegrations({ integrations, cwd, flags, logging });
|
||||||
const root = pathToFileURL(cwd ? path.resolve(cwd) : process.cwd());
|
const rootPath = resolveRoot(cwd);
|
||||||
|
const root = pathToFileURL(rootPath);
|
||||||
// Append forward slash to compute relative paths
|
// Append forward slash to compute relative paths
|
||||||
root.href = appendForwardSlash(root.href);
|
root.href = appendForwardSlash(root.href);
|
||||||
|
|
||||||
|
@ -199,7 +201,11 @@ export async function add(names: string[], { flags, logging }: AddOptions) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const rawConfigPath = await resolveConfigPath({ cwd, flags, fs: fsMod });
|
const rawConfigPath = await resolveConfigPath({
|
||||||
|
root: rootPath,
|
||||||
|
configFile: flags.config,
|
||||||
|
fs: fsMod,
|
||||||
|
});
|
||||||
let configURL = rawConfigPath ? pathToFileURL(rawConfigPath) : undefined;
|
let configURL = rawConfigPath ? pathToFileURL(rawConfigPath) : undefined;
|
||||||
|
|
||||||
if (configURL) {
|
if (configURL) {
|
||||||
|
|
|
@ -1,21 +1,31 @@
|
||||||
import type yargs from 'yargs-parser';
|
import type yargs from 'yargs-parser';
|
||||||
import _build from '../../core/build/index.js';
|
import _build from '../../core/build/index.js';
|
||||||
import type { LogOptions } from '../../core/logger/core.js';
|
import { printHelp } from '../../core/messages.js';
|
||||||
import { loadSettings } from '../load-settings.js';
|
import { flagsToAstroInlineConfig } from '../flags.js';
|
||||||
|
|
||||||
interface BuildOptions {
|
interface BuildOptions {
|
||||||
flags: yargs.Arguments;
|
flags: yargs.Arguments;
|
||||||
logging: LogOptions;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function build({ flags, logging }: BuildOptions) {
|
export async function build({ flags }: BuildOptions) {
|
||||||
const settings = await loadSettings({ cmd: 'build', flags, logging });
|
if (flags?.help || flags?.h) {
|
||||||
if (!settings) return;
|
printHelp({
|
||||||
|
commandName: 'astro build',
|
||||||
|
usage: '[...flags]',
|
||||||
|
tables: {
|
||||||
|
Flags: [
|
||||||
|
['--drafts', `Include Markdown draft pages in the build.`],
|
||||||
|
['--help (-h)', 'See all available flags.'],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
description: `Builds your site for deployment.`,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await _build(settings, {
|
const inlineConfig = flagsToAstroInlineConfig(flags);
|
||||||
flags,
|
|
||||||
logging,
|
await _build(inlineConfig, {
|
||||||
teardownCompiler: true,
|
teardownCompiler: true,
|
||||||
mode: flags.mode,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,11 +13,16 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||||
import ora from 'ora';
|
import ora from 'ora';
|
||||||
import type { Arguments as Flags } from 'yargs-parser';
|
import type { Arguments as Flags } from 'yargs-parser';
|
||||||
import type { AstroSettings } from '../../@types/astro';
|
import type { AstroSettings } from '../../@types/astro';
|
||||||
|
import { resolveConfig } from '../../core/config/config.js';
|
||||||
|
import { createNodeLogging } from '../../core/config/logging.js';
|
||||||
|
import { createSettings } from '../../core/config/settings.js';
|
||||||
import type { LogOptions } from '../../core/logger/core.js';
|
import type { LogOptions } from '../../core/logger/core.js';
|
||||||
import { debug, info } from '../../core/logger/core.js';
|
import { debug, info } from '../../core/logger/core.js';
|
||||||
import { printHelp } from '../../core/messages.js';
|
import { printHelp } from '../../core/messages.js';
|
||||||
import type { ProcessExit, SyncOptions } from '../../core/sync';
|
import type { syncInternal } from '../../core/sync';
|
||||||
import { loadSettings } from '../load-settings.js';
|
import { eventCliSession, telemetry } from '../../events/index.js';
|
||||||
|
import { runHookConfigSetup } from '../../integrations/index.js';
|
||||||
|
import { flagsToAstroInlineConfig } from '../flags.js';
|
||||||
import { printDiagnostic } from './print.js';
|
import { printDiagnostic } from './print.js';
|
||||||
|
|
||||||
type DiagnosticResult = {
|
type DiagnosticResult = {
|
||||||
|
@ -31,11 +36,6 @@ export type CheckPayload = {
|
||||||
* Flags passed via CLI
|
* Flags passed via CLI
|
||||||
*/
|
*/
|
||||||
flags: Flags;
|
flags: Flags;
|
||||||
|
|
||||||
/**
|
|
||||||
* Logging options
|
|
||||||
*/
|
|
||||||
logging: LogOptions;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type CheckFlags = {
|
type CheckFlags = {
|
||||||
|
@ -77,9 +77,8 @@ const ASTRO_GLOB_PATTERN = '**/*.astro';
|
||||||
*
|
*
|
||||||
* @param {CheckPayload} options Options passed {@link AstroChecker}
|
* @param {CheckPayload} options Options passed {@link AstroChecker}
|
||||||
* @param {Flags} options.flags Flags coming from the CLI
|
* @param {Flags} options.flags Flags coming from the CLI
|
||||||
* @param {LogOptions} options.logging Logging options
|
|
||||||
*/
|
*/
|
||||||
export async function check({ logging, flags }: CheckPayload): Promise<AstroChecker | undefined> {
|
export async function check({ flags }: CheckPayload): Promise<AstroChecker | undefined> {
|
||||||
if (flags.help || flags.h) {
|
if (flags.help || flags.h) {
|
||||||
printHelp({
|
printHelp({
|
||||||
commandName: 'astro check',
|
commandName: 'astro check',
|
||||||
|
@ -95,8 +94,12 @@ export async function check({ logging, flags }: CheckPayload): Promise<AstroChec
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const settings = await loadSettings({ cmd: 'check', flags, logging });
|
// Load settings
|
||||||
if (!settings) return;
|
const inlineConfig = flagsToAstroInlineConfig(flags);
|
||||||
|
const logging = createNodeLogging(inlineConfig);
|
||||||
|
const { userConfig, astroConfig } = await resolveConfig(inlineConfig, 'check');
|
||||||
|
telemetry.record(eventCliSession('check', userConfig, flags));
|
||||||
|
const settings = createSettings(astroConfig, fileURLToPath(astroConfig.root));
|
||||||
|
|
||||||
const checkFlags = parseFlags(flags);
|
const checkFlags = parseFlags(flags);
|
||||||
if (checkFlags.watch) {
|
if (checkFlags.watch) {
|
||||||
|
@ -105,7 +108,7 @@ export async function check({ logging, flags }: CheckPayload): Promise<AstroChec
|
||||||
info(logging, 'check', 'Checking files');
|
info(logging, 'check', 'Checking files');
|
||||||
}
|
}
|
||||||
|
|
||||||
const { syncCli } = await import('../../core/sync/index.js');
|
const { syncInternal } = await import('../../core/sync/index.js');
|
||||||
const root = settings.config.root;
|
const root = settings.config.root;
|
||||||
const require = createRequire(import.meta.url);
|
const require = createRequire(import.meta.url);
|
||||||
const diagnosticChecker = new AstroCheck(
|
const diagnosticChecker = new AstroCheck(
|
||||||
|
@ -116,7 +119,7 @@ export async function check({ logging, flags }: CheckPayload): Promise<AstroChec
|
||||||
);
|
);
|
||||||
|
|
||||||
return new AstroChecker({
|
return new AstroChecker({
|
||||||
syncCli,
|
syncInternal,
|
||||||
settings,
|
settings,
|
||||||
fileSystem: fs,
|
fileSystem: fs,
|
||||||
logging,
|
logging,
|
||||||
|
@ -130,7 +133,7 @@ type CheckerConstructor = {
|
||||||
|
|
||||||
isWatchMode: boolean;
|
isWatchMode: boolean;
|
||||||
|
|
||||||
syncCli: (settings: AstroSettings, options: SyncOptions) => Promise<ProcessExit>;
|
syncInternal: typeof syncInternal;
|
||||||
|
|
||||||
settings: Readonly<AstroSettings>;
|
settings: Readonly<AstroSettings>;
|
||||||
|
|
||||||
|
@ -148,7 +151,7 @@ type CheckerConstructor = {
|
||||||
export class AstroChecker {
|
export class AstroChecker {
|
||||||
readonly #diagnosticsChecker: AstroCheck;
|
readonly #diagnosticsChecker: AstroCheck;
|
||||||
readonly #shouldWatch: boolean;
|
readonly #shouldWatch: boolean;
|
||||||
readonly #syncCli: (settings: AstroSettings, opts: SyncOptions) => Promise<ProcessExit>;
|
readonly #syncInternal: CheckerConstructor['syncInternal'];
|
||||||
|
|
||||||
readonly #settings: AstroSettings;
|
readonly #settings: AstroSettings;
|
||||||
|
|
||||||
|
@ -162,14 +165,14 @@ export class AstroChecker {
|
||||||
constructor({
|
constructor({
|
||||||
diagnosticChecker,
|
diagnosticChecker,
|
||||||
isWatchMode,
|
isWatchMode,
|
||||||
syncCli,
|
syncInternal,
|
||||||
settings,
|
settings,
|
||||||
fileSystem,
|
fileSystem,
|
||||||
logging,
|
logging,
|
||||||
}: CheckerConstructor) {
|
}: CheckerConstructor) {
|
||||||
this.#diagnosticsChecker = diagnosticChecker;
|
this.#diagnosticsChecker = diagnosticChecker;
|
||||||
this.#shouldWatch = isWatchMode;
|
this.#shouldWatch = isWatchMode;
|
||||||
this.#syncCli = syncCli;
|
this.#syncInternal = syncInternal;
|
||||||
this.#logging = logging;
|
this.#logging = logging;
|
||||||
this.#settings = settings;
|
this.#settings = settings;
|
||||||
this.#fs = fileSystem;
|
this.#fs = fileSystem;
|
||||||
|
@ -223,7 +226,14 @@ export class AstroChecker {
|
||||||
* @param openDocuments Whether the operation should open all `.astro` files
|
* @param openDocuments Whether the operation should open all `.astro` files
|
||||||
*/
|
*/
|
||||||
async #checkAllFiles(openDocuments: boolean): Promise<CheckResult> {
|
async #checkAllFiles(openDocuments: boolean): Promise<CheckResult> {
|
||||||
const processExit = await this.#syncCli(this.#settings, {
|
// Run `astro:config:setup` before syncing to initialize integrations.
|
||||||
|
// We do this manually as we're calling `syncInternal` directly.
|
||||||
|
const syncSettings = await runHookConfigSetup({
|
||||||
|
settings: this.#settings,
|
||||||
|
logging: this.#logging,
|
||||||
|
command: 'build',
|
||||||
|
});
|
||||||
|
const processExit = await this.#syncInternal(syncSettings, {
|
||||||
logging: this.#logging,
|
logging: this.#logging,
|
||||||
fs: this.#fs,
|
fs: this.#fs,
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,31 +1,35 @@
|
||||||
import fs from 'node:fs';
|
import { cyan } from 'kleur/colors';
|
||||||
import type yargs from 'yargs-parser';
|
import type yargs from 'yargs-parser';
|
||||||
import { resolveConfigPath, resolveFlags } from '../../core/config/index.js';
|
|
||||||
import devServer from '../../core/dev/index.js';
|
import devServer from '../../core/dev/index.js';
|
||||||
import { info, type LogOptions } from '../../core/logger/core.js';
|
import { printHelp } from '../../core/messages.js';
|
||||||
import { handleConfigError, loadSettings } from '../load-settings.js';
|
import { flagsToAstroInlineConfig } from '../flags.js';
|
||||||
|
|
||||||
interface DevOptions {
|
interface DevOptions {
|
||||||
flags: yargs.Arguments;
|
flags: yargs.Arguments;
|
||||||
logging: LogOptions;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function dev({ flags, logging }: DevOptions) {
|
export async function dev({ flags }: DevOptions) {
|
||||||
const settings = await loadSettings({ cmd: 'dev', flags, logging });
|
if (flags.help || flags.h) {
|
||||||
if (!settings) return;
|
printHelp({
|
||||||
|
commandName: 'astro dev',
|
||||||
|
usage: '[...flags]',
|
||||||
|
tables: {
|
||||||
|
Flags: [
|
||||||
|
['--port', `Specify which port to run on. Defaults to 3000.`],
|
||||||
|
['--host', `Listen on all addresses, including LAN and public addresses.`],
|
||||||
|
['--host <custom-address>', `Expose on a network IP address at <custom-address>`],
|
||||||
|
['--open', 'Automatically open the app in the browser on server start'],
|
||||||
|
['--help (-h)', 'See all available flags.'],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
description: `Check ${cyan(
|
||||||
|
'https://docs.astro.build/en/reference/cli-reference/#astro-dev'
|
||||||
|
)} for more information.`,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const root = flags.root;
|
const inlineConfig = flagsToAstroInlineConfig(flags);
|
||||||
const configFlag = resolveFlags(flags).config;
|
|
||||||
const configFlagPath = configFlag ? await resolveConfigPath({ cwd: root, flags, fs }) : undefined;
|
|
||||||
|
|
||||||
return await devServer(settings, {
|
return await devServer(inlineConfig);
|
||||||
configFlag,
|
|
||||||
configFlagPath,
|
|
||||||
flags,
|
|
||||||
logging,
|
|
||||||
handleConfigError(e) {
|
|
||||||
handleConfigError(e, { cmd: 'dev', cwd: root, flags, logging });
|
|
||||||
info(logging, 'astro', 'Continuing with previous valid configuration\n');
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
49
packages/astro/src/cli/flags.ts
Normal file
49
packages/astro/src/cli/flags.ts
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
import type { Arguments as Flags } from 'yargs-parser';
|
||||||
|
import type { AstroInlineConfig } from '../@types/astro.js';
|
||||||
|
import type { LogOptions } from '../core/logger/core.js';
|
||||||
|
import { nodeLogDestination } from '../core/logger/node.js';
|
||||||
|
|
||||||
|
export function flagsToAstroInlineConfig(flags: Flags): AstroInlineConfig {
|
||||||
|
return {
|
||||||
|
// Inline-only configs
|
||||||
|
configFile: typeof flags.config === 'string' ? flags.config : undefined,
|
||||||
|
mode: typeof flags.mode === 'string' ? (flags.mode as AstroInlineConfig['mode']) : undefined,
|
||||||
|
logLevel: flags.verbose ? 'debug' : flags.silent ? 'silent' : undefined,
|
||||||
|
|
||||||
|
// Astro user configs
|
||||||
|
root: typeof flags.root === 'string' ? flags.root : undefined,
|
||||||
|
site: typeof flags.site === 'string' ? flags.site : undefined,
|
||||||
|
base: typeof flags.base === 'string' ? flags.base : undefined,
|
||||||
|
markdown: {
|
||||||
|
drafts: typeof flags.drafts === 'boolean' ? flags.drafts : undefined,
|
||||||
|
},
|
||||||
|
server: {
|
||||||
|
port: typeof flags.port === 'number' ? flags.port : undefined,
|
||||||
|
host:
|
||||||
|
typeof flags.host === 'string' || typeof flags.host === 'boolean' ? flags.host : undefined,
|
||||||
|
open: typeof flags.open === 'boolean' ? flags.open : undefined,
|
||||||
|
},
|
||||||
|
experimental: {
|
||||||
|
assets: typeof flags.experimentalAssets === 'boolean' ? flags.experimentalAssets : undefined,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `logging` is usually created from an `AstroInlineConfig`, but some flows like `add`
|
||||||
|
* doesn't read the AstroConfig directly, so we create a `logging` object from the CLI flags instead.
|
||||||
|
*/
|
||||||
|
export function createLoggingFromFlags(flags: Flags): LogOptions {
|
||||||
|
const logging: LogOptions = {
|
||||||
|
dest: nodeLogDestination,
|
||||||
|
level: 'info',
|
||||||
|
};
|
||||||
|
|
||||||
|
if (flags.verbose) {
|
||||||
|
logging.level = 'debug';
|
||||||
|
} else if (flags.silent) {
|
||||||
|
logging.level = 'silent';
|
||||||
|
}
|
||||||
|
|
||||||
|
return logging;
|
||||||
|
}
|
|
@ -2,7 +2,6 @@
|
||||||
import * as colors from 'kleur/colors';
|
import * as colors from 'kleur/colors';
|
||||||
import yargs from 'yargs-parser';
|
import yargs from 'yargs-parser';
|
||||||
import { ASTRO_VERSION } from '../core/constants.js';
|
import { ASTRO_VERSION } from '../core/constants.js';
|
||||||
import type { LogOptions } from '../core/logger/core.js';
|
|
||||||
|
|
||||||
type CLICommand =
|
type CLICommand =
|
||||||
| 'help'
|
| 'help'
|
||||||
|
@ -112,16 +111,10 @@ async function runCommand(cmd: string, flags: yargs.Arguments) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const { enableVerboseLogging, nodeLogDestination } = await import('../core/logger/node.js');
|
// In verbose/debug mode, we log the debug logs asap before any potential errors could appear
|
||||||
const logging: LogOptions = {
|
|
||||||
dest: nodeLogDestination,
|
|
||||||
level: 'info',
|
|
||||||
};
|
|
||||||
if (flags.verbose) {
|
if (flags.verbose) {
|
||||||
logging.level = 'debug';
|
const { enableVerboseLogging } = await import('../core/logger/node.js');
|
||||||
enableVerboseLogging();
|
enableVerboseLogging();
|
||||||
} else if (flags.silent) {
|
|
||||||
logging.level = 'silent';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start with a default NODE_ENV so Vite doesn't set an incorrect default when loading the Astro config
|
// Start with a default NODE_ENV so Vite doesn't set an incorrect default when loading the Astro config
|
||||||
|
@ -135,12 +128,12 @@ async function runCommand(cmd: string, flags: yargs.Arguments) {
|
||||||
case 'add': {
|
case 'add': {
|
||||||
const { add } = await import('./add/index.js');
|
const { add } = await import('./add/index.js');
|
||||||
const packages = flags._.slice(3) as string[];
|
const packages = flags._.slice(3) as string[];
|
||||||
await add(packages, { flags, logging });
|
await add(packages, { flags });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case 'dev': {
|
case 'dev': {
|
||||||
const { dev } = await import('./dev/index.js');
|
const { dev } = await import('./dev/index.js');
|
||||||
const server = await dev({ flags, logging });
|
const server = await dev({ flags });
|
||||||
if (server) {
|
if (server) {
|
||||||
return await new Promise(() => {}); // lives forever
|
return await new Promise(() => {}); // lives forever
|
||||||
}
|
}
|
||||||
|
@ -148,12 +141,12 @@ async function runCommand(cmd: string, flags: yargs.Arguments) {
|
||||||
}
|
}
|
||||||
case 'build': {
|
case 'build': {
|
||||||
const { build } = await import('./build/index.js');
|
const { build } = await import('./build/index.js');
|
||||||
await build({ flags, logging });
|
await build({ flags });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case 'preview': {
|
case 'preview': {
|
||||||
const { preview } = await import('./preview/index.js');
|
const { preview } = await import('./preview/index.js');
|
||||||
const server = await preview({ flags, logging });
|
const server = await preview({ flags });
|
||||||
if (server) {
|
if (server) {
|
||||||
return await server.closed(); // keep alive until the server is closed
|
return await server.closed(); // keep alive until the server is closed
|
||||||
}
|
}
|
||||||
|
@ -162,7 +155,7 @@ async function runCommand(cmd: string, flags: yargs.Arguments) {
|
||||||
case 'check': {
|
case 'check': {
|
||||||
const { check } = await import('./check/index.js');
|
const { check } = await import('./check/index.js');
|
||||||
// We create a server to start doing our operations
|
// We create a server to start doing our operations
|
||||||
const checkServer = await check({ flags, logging });
|
const checkServer = await check({ flags });
|
||||||
if (checkServer) {
|
if (checkServer) {
|
||||||
if (checkServer.isWatchMode) {
|
if (checkServer.isWatchMode) {
|
||||||
await checkServer.watch();
|
await checkServer.watch();
|
||||||
|
@ -176,7 +169,7 @@ async function runCommand(cmd: string, flags: yargs.Arguments) {
|
||||||
}
|
}
|
||||||
case 'sync': {
|
case 'sync': {
|
||||||
const { sync } = await import('./sync/index.js');
|
const { sync } = await import('./sync/index.js');
|
||||||
const exitCode = await sync({ flags, logging });
|
const exitCode = await sync({ flags });
|
||||||
return process.exit(exitCode);
|
return process.exit(exitCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,14 +3,16 @@ import * as colors from 'kleur/colors';
|
||||||
import { arch, platform } from 'node:os';
|
import { arch, platform } from 'node:os';
|
||||||
import whichPm from 'which-pm';
|
import whichPm from 'which-pm';
|
||||||
import type yargs from 'yargs-parser';
|
import type yargs from 'yargs-parser';
|
||||||
import { openConfig } from '../../core/config/index.js';
|
import { resolveConfig } from '../../core/config/index.js';
|
||||||
import { ASTRO_VERSION } from '../../core/constants.js';
|
import { ASTRO_VERSION } from '../../core/constants.js';
|
||||||
|
import { flagsToAstroInlineConfig } from '../flags.js';
|
||||||
|
|
||||||
interface InfoOptions {
|
interface InfoOptions {
|
||||||
flags: yargs.Arguments;
|
flags: yargs.Arguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function printInfo({ flags }: InfoOptions) {
|
export async function printInfo({ flags }: InfoOptions) {
|
||||||
|
const inlineConfig = flagsToAstroInlineConfig(flags);
|
||||||
const packageManager = await whichPm(process.cwd());
|
const packageManager = await whichPm(process.cwd());
|
||||||
let adapter = "Couldn't determine.";
|
let adapter = "Couldn't determine.";
|
||||||
let integrations = [];
|
let integrations = [];
|
||||||
|
@ -22,11 +24,7 @@ export async function printInfo({ flags }: InfoOptions) {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { userConfig } = await openConfig({
|
const { userConfig } = await resolveConfig(inlineConfig, 'info');
|
||||||
cwd: flags.root,
|
|
||||||
flags,
|
|
||||||
cmd: 'info',
|
|
||||||
});
|
|
||||||
if (userConfig.adapter?.name) {
|
if (userConfig.adapter?.name) {
|
||||||
adapter = userConfig.adapter.name;
|
adapter = userConfig.adapter.name;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,47 +0,0 @@
|
||||||
/* eslint-disable no-console */
|
|
||||||
import * as colors from 'kleur/colors';
|
|
||||||
import fs from 'node:fs';
|
|
||||||
import type { Arguments as Flags } from 'yargs-parser';
|
|
||||||
import { ZodError } from 'zod';
|
|
||||||
import { createSettings, openConfig, resolveConfigPath } from '../core/config/index.js';
|
|
||||||
import { collectErrorMetadata } from '../core/errors/dev/index.js';
|
|
||||||
import { error, type LogOptions } from '../core/logger/core.js';
|
|
||||||
import { formatConfigErrorMessage, formatErrorMessage } from '../core/messages.js';
|
|
||||||
import * as event from '../events/index.js';
|
|
||||||
import { eventConfigError, telemetry } from '../events/index.js';
|
|
||||||
|
|
||||||
interface LoadSettingsOptions {
|
|
||||||
cmd: string;
|
|
||||||
flags: Flags;
|
|
||||||
logging: LogOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function loadSettings({ cmd, flags, logging }: LoadSettingsOptions) {
|
|
||||||
const root = flags.root;
|
|
||||||
const { astroConfig: initialAstroConfig, userConfig: initialUserConfig } = await openConfig({
|
|
||||||
cwd: root,
|
|
||||||
flags,
|
|
||||||
cmd,
|
|
||||||
}).catch(async (e) => {
|
|
||||||
await handleConfigError(e, { cmd, cwd: root, flags, logging });
|
|
||||||
return {} as any;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!initialAstroConfig) return;
|
|
||||||
telemetry.record(event.eventCliSession(cmd, initialUserConfig, flags));
|
|
||||||
return createSettings(initialAstroConfig, root);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function handleConfigError(
|
|
||||||
e: any,
|
|
||||||
{ cmd, cwd, flags, logging }: { cmd: string; cwd?: string; flags?: Flags; logging: LogOptions }
|
|
||||||
) {
|
|
||||||
const path = await resolveConfigPath({ cwd, flags, fs });
|
|
||||||
error(logging, 'astro', `Unable to load ${path ? colors.bold(path) : 'your Astro config'}\n`);
|
|
||||||
if (e instanceof ZodError) {
|
|
||||||
console.error(formatConfigErrorMessage(e) + '\n');
|
|
||||||
telemetry.record(eventConfigError({ cmd, err: e, isFatal: true }));
|
|
||||||
} else if (e instanceof Error) {
|
|
||||||
console.error(formatErrorMessage(collectErrorMetadata(e)) + '\n');
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,16 +1,32 @@
|
||||||
|
import { cyan } from 'kleur/colors';
|
||||||
import type yargs from 'yargs-parser';
|
import type yargs from 'yargs-parser';
|
||||||
import type { LogOptions } from '../../core/logger/core.js';
|
import { printHelp } from '../../core/messages.js';
|
||||||
import previewServer from '../../core/preview/index.js';
|
import previewServer from '../../core/preview/index.js';
|
||||||
import { loadSettings } from '../load-settings.js';
|
import { flagsToAstroInlineConfig } from '../flags.js';
|
||||||
|
|
||||||
interface PreviewOptions {
|
interface PreviewOptions {
|
||||||
flags: yargs.Arguments;
|
flags: yargs.Arguments;
|
||||||
logging: LogOptions;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function preview({ flags, logging }: PreviewOptions) {
|
export async function preview({ flags }: PreviewOptions) {
|
||||||
const settings = await loadSettings({ cmd: 'preview', flags, logging });
|
if (flags?.help || flags?.h) {
|
||||||
if (!settings) return;
|
printHelp({
|
||||||
|
commandName: 'astro preview',
|
||||||
|
usage: '[...flags]',
|
||||||
|
tables: {
|
||||||
|
Flags: [
|
||||||
|
['--open', 'Automatically open the app in the browser on server start'],
|
||||||
|
['--help (-h)', 'See all available flags.'],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
description: `Starts a local server to serve your static dist/ directory. Check ${cyan(
|
||||||
|
'https://docs.astro.build/en/reference/cli-reference/#astro-preview'
|
||||||
|
)} for more information.`,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
return await previewServer(settings, { flags, logging });
|
const inlineConfig = flagsToAstroInlineConfig(flags);
|
||||||
|
|
||||||
|
return await previewServer(inlineConfig);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,27 @@
|
||||||
import fs from 'node:fs';
|
|
||||||
import type yargs from 'yargs-parser';
|
import type yargs from 'yargs-parser';
|
||||||
import type { LogOptions } from '../../core/logger/core.js';
|
import { printHelp } from '../../core/messages.js';
|
||||||
import { syncCli } from '../../core/sync/index.js';
|
import { sync as _sync } from '../../core/sync/index.js';
|
||||||
import { loadSettings } from '../load-settings.js';
|
import { flagsToAstroInlineConfig } from '../flags.js';
|
||||||
|
|
||||||
interface SyncOptions {
|
interface SyncOptions {
|
||||||
flags: yargs.Arguments;
|
flags: yargs.Arguments;
|
||||||
logging: LogOptions;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function sync({ flags, logging }: SyncOptions) {
|
export async function sync({ flags }: SyncOptions) {
|
||||||
const settings = await loadSettings({ cmd: 'sync', flags, logging });
|
if (flags?.help || flags?.h) {
|
||||||
if (!settings) return;
|
printHelp({
|
||||||
|
commandName: 'astro sync',
|
||||||
|
usage: '[...flags]',
|
||||||
|
tables: {
|
||||||
|
Flags: [['--help (-h)', 'See all available flags.']],
|
||||||
|
},
|
||||||
|
description: `Generates TypeScript types for all Astro modules.`,
|
||||||
|
});
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
const exitCode = await syncCli(settings, { logging, fs, flags });
|
const inlineConfig = flagsToAstroInlineConfig(flags);
|
||||||
|
|
||||||
|
const exitCode = await _sync(inlineConfig);
|
||||||
return exitCode;
|
return exitCode;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/* eslint-disable no-console */
|
/* eslint-disable no-console */
|
||||||
import { collectErrorMetadata } from '../core/errors/dev/index.js';
|
import { collectErrorMetadata } from '../core/errors/dev/index.js';
|
||||||
|
import { isAstroConfigZodError } from '../core/errors/errors.js';
|
||||||
import { createSafeError } from '../core/errors/index.js';
|
import { createSafeError } from '../core/errors/index.js';
|
||||||
import { debug } from '../core/logger/core.js';
|
import { debug } from '../core/logger/core.js';
|
||||||
import { formatErrorMessage } from '../core/messages.js';
|
import { formatErrorMessage } from '../core/messages.js';
|
||||||
|
@ -7,6 +8,9 @@ import { eventError, telemetry } from '../events/index.js';
|
||||||
|
|
||||||
/** Display error and exit */
|
/** Display error and exit */
|
||||||
export async function throwAndExit(cmd: string, err: unknown) {
|
export async function throwAndExit(cmd: string, err: unknown) {
|
||||||
|
// Suppress ZodErrors from AstroConfig as the pre-logged error is sufficient
|
||||||
|
if (isAstroConfigZodError(err)) return;
|
||||||
|
|
||||||
let telemetryPromise: Promise<any>;
|
let telemetryPromise: Promise<any>;
|
||||||
let errorMessage: string;
|
let errorMessage: string;
|
||||||
function exitWithErrorMessage() {
|
function exitWithErrorMessage() {
|
||||||
|
|
|
@ -17,7 +17,7 @@ export function getViteConfig(inlineConfig: UserConfig) {
|
||||||
fs,
|
fs,
|
||||||
{ mergeConfig },
|
{ mergeConfig },
|
||||||
{ nodeLogDestination },
|
{ nodeLogDestination },
|
||||||
{ openConfig, createSettings },
|
{ resolveConfig, createSettings },
|
||||||
{ createVite },
|
{ createVite },
|
||||||
{ runHookConfigSetup, runHookConfigDone },
|
{ runHookConfigSetup, runHookConfigDone },
|
||||||
{ astroContentListenPlugin },
|
{ astroContentListenPlugin },
|
||||||
|
@ -34,7 +34,7 @@ export function getViteConfig(inlineConfig: UserConfig) {
|
||||||
dest: nodeLogDestination,
|
dest: nodeLogDestination,
|
||||||
level: 'info',
|
level: 'info',
|
||||||
};
|
};
|
||||||
const { astroConfig: config } = await openConfig({ cmd });
|
const { astroConfig: config } = await resolveConfig({}, cmd);
|
||||||
const settings = createSettings(config, inlineConfig.root);
|
const settings = createSettings(config, inlineConfig.root);
|
||||||
await runHookConfigSetup({ settings, command: cmd, logging });
|
await runHookConfigSetup({ settings, command: cmd, logging });
|
||||||
const viteConfig = await createVite(
|
const viteConfig = await createVite(
|
||||||
|
|
|
@ -1,10 +1,18 @@
|
||||||
import * as colors from 'kleur/colors';
|
import * as colors from 'kleur/colors';
|
||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
import { performance } from 'node:perf_hooks';
|
import { performance } from 'node:perf_hooks';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
import type * as vite from 'vite';
|
import type * as vite from 'vite';
|
||||||
import type yargs from 'yargs-parser';
|
import type {
|
||||||
import type { AstroConfig, AstroSettings, ManifestData, RuntimeMode } from '../../@types/astro';
|
AstroConfig,
|
||||||
|
AstroInlineConfig,
|
||||||
|
AstroSettings,
|
||||||
|
ManifestData,
|
||||||
|
RuntimeMode,
|
||||||
|
} from '../../@types/astro';
|
||||||
import { injectImageEndpoint } from '../../assets/internal.js';
|
import { injectImageEndpoint } from '../../assets/internal.js';
|
||||||
|
import { telemetry } from '../../events/index.js';
|
||||||
|
import { eventCliSession } from '../../events/session.js';
|
||||||
import {
|
import {
|
||||||
runHookBuildDone,
|
runHookBuildDone,
|
||||||
runHookBuildStart,
|
runHookBuildStart,
|
||||||
|
@ -12,9 +20,11 @@ import {
|
||||||
runHookConfigSetup,
|
runHookConfigSetup,
|
||||||
} from '../../integrations/index.js';
|
} from '../../integrations/index.js';
|
||||||
import { isServerLikeOutput } from '../../prerender/utils.js';
|
import { isServerLikeOutput } from '../../prerender/utils.js';
|
||||||
|
import { resolveConfig } from '../config/config.js';
|
||||||
|
import { createNodeLogging } from '../config/logging.js';
|
||||||
|
import { createSettings } from '../config/settings.js';
|
||||||
import { createVite } from '../create-vite.js';
|
import { createVite } from '../create-vite.js';
|
||||||
import { debug, info, levels, timerMessage, warn, type LogOptions } from '../logger/core.js';
|
import { debug, info, levels, timerMessage, warn, type LogOptions } from '../logger/core.js';
|
||||||
import { printHelp } from '../messages.js';
|
|
||||||
import { apply as applyPolyfill } from '../polyfill.js';
|
import { apply as applyPolyfill } from '../polyfill.js';
|
||||||
import { RouteCache } from '../render/route-cache.js';
|
import { RouteCache } from '../render/route-cache.js';
|
||||||
import { createRouteManifest } from '../routing/index.js';
|
import { createRouteManifest } from '../routing/index.js';
|
||||||
|
@ -24,38 +34,38 @@ import type { StaticBuildOptions } from './types.js';
|
||||||
import { getTimeStat } from './util.js';
|
import { getTimeStat } from './util.js';
|
||||||
|
|
||||||
export interface BuildOptions {
|
export interface BuildOptions {
|
||||||
mode?: RuntimeMode;
|
|
||||||
logging: LogOptions;
|
|
||||||
/**
|
/**
|
||||||
* Teardown the compiler WASM instance after build. This can improve performance when
|
* Teardown the compiler WASM instance after build. This can improve performance when
|
||||||
* building once, but may cause a performance hit if building multiple times in a row.
|
* building once, but may cause a performance hit if building multiple times in a row.
|
||||||
*/
|
*/
|
||||||
teardownCompiler?: boolean;
|
teardownCompiler?: boolean;
|
||||||
flags?: yargs.Arguments;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** `astro build` */
|
/** `astro build` */
|
||||||
export default async function build(settings: AstroSettings, options: BuildOptions): Promise<void> {
|
export default async function build(
|
||||||
|
inlineConfig: AstroInlineConfig,
|
||||||
|
options: BuildOptions
|
||||||
|
): Promise<void> {
|
||||||
applyPolyfill();
|
applyPolyfill();
|
||||||
if (options.flags?.help || options.flags?.h) {
|
const logging = createNodeLogging(inlineConfig);
|
||||||
printHelp({
|
const { userConfig, astroConfig } = await resolveConfig(inlineConfig, 'build');
|
||||||
commandName: 'astro build',
|
telemetry.record(eventCliSession('build', userConfig));
|
||||||
usage: '[...flags]',
|
|
||||||
tables: {
|
|
||||||
Flags: [
|
|
||||||
['--drafts', `Include Markdown draft pages in the build.`],
|
|
||||||
['--help (-h)', 'See all available flags.'],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
description: `Builds your site for deployment.`,
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const builder = new AstroBuilder(settings, options);
|
const settings = createSettings(astroConfig, fileURLToPath(astroConfig.root));
|
||||||
|
|
||||||
|
const builder = new AstroBuilder(settings, {
|
||||||
|
...options,
|
||||||
|
logging,
|
||||||
|
mode: inlineConfig.mode,
|
||||||
|
});
|
||||||
await builder.run();
|
await builder.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface AstroBuilderOptions extends BuildOptions {
|
||||||
|
logging: LogOptions;
|
||||||
|
mode?: RuntimeMode;
|
||||||
|
}
|
||||||
|
|
||||||
class AstroBuilder {
|
class AstroBuilder {
|
||||||
private settings: AstroSettings;
|
private settings: AstroSettings;
|
||||||
private logging: LogOptions;
|
private logging: LogOptions;
|
||||||
|
@ -66,7 +76,7 @@ class AstroBuilder {
|
||||||
private timer: Record<string, number>;
|
private timer: Record<string, number>;
|
||||||
private teardownCompiler: boolean;
|
private teardownCompiler: boolean;
|
||||||
|
|
||||||
constructor(settings: AstroSettings, options: BuildOptions) {
|
constructor(settings: AstroSettings, options: AstroBuilderOptions) {
|
||||||
if (options.mode) {
|
if (options.mode) {
|
||||||
this.mode = options.mode;
|
this.mode = options.mode;
|
||||||
}
|
}
|
||||||
|
@ -112,8 +122,8 @@ class AstroBuilder {
|
||||||
);
|
);
|
||||||
await runHookConfigDone({ settings: this.settings, logging });
|
await runHookConfigDone({ settings: this.settings, logging });
|
||||||
|
|
||||||
const { sync } = await import('../sync/index.js');
|
const { syncInternal } = await import('../sync/index.js');
|
||||||
const syncRet = await sync(this.settings, { logging, fs });
|
const syncRet = await syncInternal(this.settings, { logging, fs });
|
||||||
if (syncRet !== 0) {
|
if (syncRet !== 0) {
|
||||||
return process.exit(syncRet);
|
return process.exit(syncRet);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,26 @@
|
||||||
import type { Arguments as Flags } from 'yargs-parser';
|
import type { Arguments as Flags } from 'yargs-parser';
|
||||||
import type { AstroConfig, AstroUserConfig, CLIFlags } from '../../@types/astro';
|
import type {
|
||||||
|
AstroConfig,
|
||||||
|
AstroInlineConfig,
|
||||||
|
AstroInlineOnlyConfig,
|
||||||
|
AstroUserConfig,
|
||||||
|
CLIFlags,
|
||||||
|
} from '../../@types/astro';
|
||||||
|
|
||||||
import * as colors from 'kleur/colors';
|
import * as colors from 'kleur/colors';
|
||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
|
import { ZodError } from 'zod';
|
||||||
|
import { eventConfigError, telemetry } from '../../events/index.js';
|
||||||
|
import { trackAstroConfigZodError } from '../errors/errors.js';
|
||||||
import { AstroError, AstroErrorData } from '../errors/index.js';
|
import { AstroError, AstroErrorData } from '../errors/index.js';
|
||||||
|
import { formatConfigErrorMessage } from '../messages.js';
|
||||||
import { mergeConfig } from './merge.js';
|
import { mergeConfig } from './merge.js';
|
||||||
import { createRelativeSchema } from './schema.js';
|
import { createRelativeSchema } from './schema.js';
|
||||||
import { loadConfigWithVite } from './vite-load.js';
|
import { loadConfigWithVite } from './vite-load.js';
|
||||||
|
|
||||||
export const LEGACY_ASTRO_CONFIG_KEYS = new Set([
|
const LEGACY_ASTRO_CONFIG_KEYS = new Set([
|
||||||
'projectRoot',
|
'projectRoot',
|
||||||
'src',
|
'src',
|
||||||
'pages',
|
'pages',
|
||||||
|
@ -80,13 +90,29 @@ export async function validateConfig(
|
||||||
const AstroConfigRelativeSchema = createRelativeSchema(cmd, root);
|
const AstroConfigRelativeSchema = createRelativeSchema(cmd, root);
|
||||||
|
|
||||||
// First-Pass Validation
|
// First-Pass Validation
|
||||||
const result = await AstroConfigRelativeSchema.parseAsync(userConfig);
|
let result: AstroConfig;
|
||||||
|
try {
|
||||||
|
result = await AstroConfigRelativeSchema.parseAsync(userConfig);
|
||||||
|
} catch (e) {
|
||||||
|
// Improve config zod error messages
|
||||||
|
if (e instanceof ZodError) {
|
||||||
|
// Mark this error so the callee can decide to suppress Zod's error if needed.
|
||||||
|
// We still want to throw the error to signal an error in validation.
|
||||||
|
trackAstroConfigZodError(e);
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.error(formatConfigErrorMessage(e) + '\n');
|
||||||
|
telemetry.record(eventConfigError({ cmd, err: e, isFatal: true }));
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
// If successful, return the result as a verified AstroConfig object.
|
// If successful, return the result as a verified AstroConfig object.
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Convert the generic "yargs" flag object into our own, custom TypeScript object. */
|
/** Convert the generic "yargs" flag object into our own, custom TypeScript object. */
|
||||||
|
// NOTE: This function will be removed in a later PR. Use `flagsToAstroInlineConfig` instead.
|
||||||
|
// All CLI related flow should be located in the `packages/astro/src/cli` directory.
|
||||||
export function resolveFlags(flags: Partial<Flags>): CLIFlags {
|
export function resolveFlags(flags: Partial<Flags>): CLIFlags {
|
||||||
return {
|
return {
|
||||||
root: typeof flags.root === 'string' ? flags.root : undefined,
|
root: typeof flags.root === 'string' ? flags.root : undefined,
|
||||||
|
@ -110,22 +136,6 @@ export function resolveRoot(cwd?: string | URL): string {
|
||||||
return cwd ? path.resolve(cwd) : process.cwd();
|
return cwd ? path.resolve(cwd) : process.cwd();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Merge CLI flags & user config object (CLI flags take priority) */
|
|
||||||
function mergeCLIFlags(astroConfig: AstroUserConfig, flags: CLIFlags) {
|
|
||||||
return mergeConfig(astroConfig, {
|
|
||||||
site: flags.site,
|
|
||||||
base: flags.base,
|
|
||||||
markdown: {
|
|
||||||
drafts: flags.drafts,
|
|
||||||
},
|
|
||||||
server: {
|
|
||||||
port: flags.port,
|
|
||||||
host: flags.host,
|
|
||||||
open: flags.open,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function search(fsMod: typeof fs, root: string) {
|
async function search(fsMod: typeof fs, root: string) {
|
||||||
const paths = [
|
const paths = [
|
||||||
'astro.config.mjs',
|
'astro.config.mjs',
|
||||||
|
@ -143,19 +153,9 @@ async function search(fsMod: typeof fs, root: string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface LoadConfigOptions {
|
|
||||||
cwd?: string;
|
|
||||||
flags?: Flags;
|
|
||||||
cmd: string;
|
|
||||||
validate?: boolean;
|
|
||||||
/** Invalidate when reloading a previously loaded config */
|
|
||||||
isRestart?: boolean;
|
|
||||||
fsMod?: typeof fs;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ResolveConfigPathOptions {
|
interface ResolveConfigPathOptions {
|
||||||
cwd?: string;
|
root: string;
|
||||||
flags?: Flags;
|
configFile?: string;
|
||||||
fs: typeof fs;
|
fs: typeof fs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,87 +163,85 @@ interface ResolveConfigPathOptions {
|
||||||
* Resolve the file URL of the user's `astro.config.js|cjs|mjs|ts` file
|
* Resolve the file URL of the user's `astro.config.js|cjs|mjs|ts` file
|
||||||
*/
|
*/
|
||||||
export async function resolveConfigPath(
|
export async function resolveConfigPath(
|
||||||
configOptions: ResolveConfigPathOptions
|
options: ResolveConfigPathOptions
|
||||||
): Promise<string | undefined> {
|
): Promise<string | undefined> {
|
||||||
const root = resolveRoot(configOptions.cwd);
|
|
||||||
const flags = resolveFlags(configOptions.flags || {});
|
|
||||||
|
|
||||||
let userConfigPath: string | undefined;
|
let userConfigPath: string | undefined;
|
||||||
if (flags?.config) {
|
if (options.configFile) {
|
||||||
userConfigPath = /^\.*\//.test(flags.config) ? flags.config : `./${flags.config}`;
|
userConfigPath = path.join(options.root, options.configFile);
|
||||||
userConfigPath = fileURLToPath(new URL(userConfigPath, `file://${root}/`));
|
if (!options.fs.existsSync(userConfigPath)) {
|
||||||
if (!configOptions.fs.existsSync(userConfigPath)) {
|
|
||||||
throw new AstroError({
|
throw new AstroError({
|
||||||
...AstroErrorData.ConfigNotFound,
|
...AstroErrorData.ConfigNotFound,
|
||||||
message: AstroErrorData.ConfigNotFound.message(flags.config),
|
message: AstroErrorData.ConfigNotFound.message(options.configFile),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
userConfigPath = await search(configOptions.fs, root);
|
userConfigPath = await search(options.fs, options.root);
|
||||||
}
|
}
|
||||||
|
|
||||||
return userConfigPath;
|
return userConfigPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface OpenConfigResult {
|
|
||||||
userConfig: AstroUserConfig;
|
|
||||||
astroConfig: AstroConfig;
|
|
||||||
flags: CLIFlags;
|
|
||||||
root: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Load a configuration file, returning both the userConfig and astroConfig */
|
|
||||||
export async function openConfig(configOptions: LoadConfigOptions): Promise<OpenConfigResult> {
|
|
||||||
const root = resolveRoot(configOptions.cwd);
|
|
||||||
const flags = resolveFlags(configOptions.flags || {});
|
|
||||||
|
|
||||||
const userConfig = await loadConfig(configOptions, root);
|
|
||||||
const astroConfig = await resolveConfig(userConfig, root, flags, configOptions.cmd);
|
|
||||||
|
|
||||||
return {
|
|
||||||
astroConfig,
|
|
||||||
userConfig,
|
|
||||||
flags,
|
|
||||||
root,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async function loadConfig(
|
async function loadConfig(
|
||||||
configOptions: LoadConfigOptions,
|
root: string,
|
||||||
root: string
|
configFile?: string | false,
|
||||||
|
fsMod = fs
|
||||||
): Promise<Record<string, any>> {
|
): Promise<Record<string, any>> {
|
||||||
const fsMod = configOptions.fsMod ?? fs;
|
if (configFile === false) return {};
|
||||||
|
|
||||||
const configPath = await resolveConfigPath({
|
const configPath = await resolveConfigPath({
|
||||||
cwd: configOptions.cwd,
|
root,
|
||||||
flags: configOptions.flags,
|
configFile,
|
||||||
fs: fsMod,
|
fs: fsMod,
|
||||||
});
|
});
|
||||||
if (!configPath) return {};
|
if (!configPath) return {};
|
||||||
|
|
||||||
// Create a vite server to load the config
|
// Create a vite server to load the config
|
||||||
return await loadConfigWithVite({
|
try {
|
||||||
configPath,
|
return await loadConfigWithVite({
|
||||||
fs: fsMod,
|
root,
|
||||||
root,
|
configPath,
|
||||||
});
|
fs: fsMod,
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
const configPathText = configFile ? colors.bold(configFile) : 'your Astro config';
|
||||||
|
// Config errors should bypass log level as it breaks startup
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.error(`${colors.bold(colors.red('[astro]'))} Unable to load ${configPathText}\n`);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function splitInlineConfig(inlineConfig: AstroInlineConfig): {
|
||||||
|
inlineUserConfig: AstroUserConfig;
|
||||||
|
inlineOnlyConfig: AstroInlineOnlyConfig;
|
||||||
|
} {
|
||||||
|
const { configFile, mode, logLevel, ...inlineUserConfig } = inlineConfig;
|
||||||
|
return {
|
||||||
|
inlineUserConfig,
|
||||||
|
inlineOnlyConfig: {
|
||||||
|
configFile,
|
||||||
|
mode,
|
||||||
|
logLevel,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ResolveConfigResult {
|
||||||
|
userConfig: AstroUserConfig;
|
||||||
|
astroConfig: AstroConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Attempt to resolve an Astro configuration object. Normalize, validate, and return. */
|
|
||||||
export async function resolveConfig(
|
export async function resolveConfig(
|
||||||
userConfig: AstroUserConfig,
|
inlineConfig: AstroInlineConfig,
|
||||||
root: string,
|
command: string,
|
||||||
flags: CLIFlags = {},
|
fsMod = fs
|
||||||
cmd: string
|
): Promise<ResolveConfigResult> {
|
||||||
): Promise<AstroConfig> {
|
const root = resolveRoot(inlineConfig.root);
|
||||||
const mergedConfig = mergeCLIFlags(userConfig, flags);
|
const { inlineUserConfig, inlineOnlyConfig } = splitInlineConfig(inlineConfig);
|
||||||
const validatedConfig = await validateConfig(mergedConfig, root, cmd);
|
|
||||||
|
|
||||||
return validatedConfig;
|
const userConfig = await loadConfig(root, inlineOnlyConfig.configFile, fsMod);
|
||||||
}
|
const mergedConfig = mergeConfig(userConfig, inlineUserConfig);
|
||||||
|
const astroConfig = await validateConfig(mergedConfig, root, command);
|
||||||
|
|
||||||
export function createDefaultDevConfig(
|
return { userConfig, astroConfig };
|
||||||
userConfig: AstroUserConfig = {},
|
|
||||||
root: string = process.cwd()
|
|
||||||
) {
|
|
||||||
return resolveConfig(userConfig, root, undefined, 'dev');
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,6 @@
|
||||||
export {
|
export { resolveConfig, resolveConfigPath, resolveFlags, resolveRoot } from './config.js';
|
||||||
createDefaultDevConfig,
|
export { createNodeLogging } from './logging.js';
|
||||||
openConfig,
|
|
||||||
resolveConfigPath,
|
|
||||||
resolveFlags,
|
|
||||||
resolveRoot,
|
|
||||||
validateConfig,
|
|
||||||
} from './config.js';
|
|
||||||
export { mergeConfig } from './merge.js';
|
export { mergeConfig } from './merge.js';
|
||||||
export type { AstroConfigSchema } from './schema';
|
export type { AstroConfigSchema } from './schema';
|
||||||
export { createDefaultDevSettings, createSettings } from './settings.js';
|
export { createSettings } from './settings.js';
|
||||||
export { loadTSConfig, updateTSConfigForFramework } from './tsconfig.js';
|
export { loadTSConfig, updateTSConfigForFramework } from './tsconfig.js';
|
||||||
|
|
13
packages/astro/src/core/config/logging.ts
Normal file
13
packages/astro/src/core/config/logging.ts
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import type { AstroInlineConfig } from '../../@types/astro.js';
|
||||||
|
import type { LogOptions } from '../logger/core.js';
|
||||||
|
import { nodeLogDestination } from '../logger/node.js';
|
||||||
|
|
||||||
|
export function createNodeLogging(inlineConfig: AstroInlineConfig): LogOptions {
|
||||||
|
// For internal testing, the inline config can pass the raw `logging` object directly
|
||||||
|
if (inlineConfig.logging) return inlineConfig.logging;
|
||||||
|
|
||||||
|
return {
|
||||||
|
dest: nodeLogDestination,
|
||||||
|
level: inlineConfig.logLevel ?? 'info',
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
import yaml from 'js-yaml';
|
import yaml from 'js-yaml';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import { fileURLToPath, pathToFileURL } from 'node:url';
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||||
import type { AstroConfig, AstroSettings, AstroUserConfig } from '../../@types/astro';
|
import type { AstroConfig, AstroSettings } from '../../@types/astro';
|
||||||
import { getContentPaths } from '../../content/index.js';
|
import { getContentPaths } from '../../content/index.js';
|
||||||
import jsxRenderer from '../../jsx/renderer.js';
|
import jsxRenderer from '../../jsx/renderer.js';
|
||||||
import { markdownContentEntryType } from '../../vite-plugin-markdown/content-entry-type.js';
|
import { markdownContentEntryType } from '../../vite-plugin-markdown/content-entry-type.js';
|
||||||
|
@ -9,7 +9,6 @@ import { getDefaultClientDirectives } from '../client-directive/index.js';
|
||||||
import { AstroError, AstroErrorData } from '../errors/index.js';
|
import { AstroError, AstroErrorData } from '../errors/index.js';
|
||||||
import { formatYAMLException, isYAMLException } from '../errors/utils.js';
|
import { formatYAMLException, isYAMLException } from '../errors/utils.js';
|
||||||
import { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from './../constants.js';
|
import { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from './../constants.js';
|
||||||
import { createDefaultDevConfig } from './config.js';
|
|
||||||
import { AstroTimer } from './timer.js';
|
import { AstroTimer } from './timer.js';
|
||||||
import { loadTSConfig } from './tsconfig.js';
|
import { loadTSConfig } from './tsconfig.js';
|
||||||
|
|
||||||
|
@ -119,14 +118,3 @@ export function createSettings(config: AstroConfig, cwd?: string): AstroSettings
|
||||||
settings.watchFiles = watchFiles;
|
settings.watchFiles = watchFiles;
|
||||||
return settings;
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createDefaultDevSettings(
|
|
||||||
userConfig: AstroUserConfig = {},
|
|
||||||
root?: string | URL
|
|
||||||
): Promise<AstroSettings> {
|
|
||||||
if (root && typeof root !== 'string') {
|
|
||||||
root = fileURLToPath(root);
|
|
||||||
}
|
|
||||||
const config = await createDefaultDevConfig(userConfig, root);
|
|
||||||
return createBaseSettings(config);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import type * as http from 'node:http';
|
import type * as http from 'node:http';
|
||||||
import type { AddressInfo } from 'node:net';
|
import type { AddressInfo } from 'node:net';
|
||||||
import type { AstroSettings, AstroUserConfig } from '../../@types/astro';
|
import type { AstroInlineConfig, AstroSettings } from '../../@types/astro';
|
||||||
|
|
||||||
import nodeFs from 'node:fs';
|
import nodeFs from 'node:fs';
|
||||||
import * as vite from 'vite';
|
import * as vite from 'vite';
|
||||||
|
@ -11,52 +11,36 @@ import {
|
||||||
runHookServerDone,
|
runHookServerDone,
|
||||||
runHookServerStart,
|
runHookServerStart,
|
||||||
} from '../../integrations/index.js';
|
} from '../../integrations/index.js';
|
||||||
import { createDefaultDevSettings, resolveRoot } from '../config/index.js';
|
|
||||||
import { createVite } from '../create-vite.js';
|
import { createVite } from '../create-vite.js';
|
||||||
import type { LogOptions } from '../logger/core.js';
|
import type { LogOptions } from '../logger/core.js';
|
||||||
import { nodeLogDestination } from '../logger/node.js';
|
|
||||||
import { appendForwardSlash } from '../path.js';
|
|
||||||
import { apply as applyPolyfill } from '../polyfill.js';
|
import { apply as applyPolyfill } from '../polyfill.js';
|
||||||
|
|
||||||
const defaultLogging: LogOptions = {
|
|
||||||
dest: nodeLogDestination,
|
|
||||||
level: 'error',
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface Container {
|
export interface Container {
|
||||||
fs: typeof nodeFs;
|
fs: typeof nodeFs;
|
||||||
logging: LogOptions;
|
logging: LogOptions;
|
||||||
settings: AstroSettings;
|
settings: AstroSettings;
|
||||||
viteConfig: vite.InlineConfig;
|
|
||||||
viteServer: vite.ViteDevServer;
|
viteServer: vite.ViteDevServer;
|
||||||
resolvedRoot: string;
|
inlineConfig: AstroInlineConfig;
|
||||||
configFlag: string | undefined;
|
|
||||||
configFlagPath: string | undefined;
|
|
||||||
restartInFlight: boolean; // gross
|
restartInFlight: boolean; // gross
|
||||||
handle: (req: http.IncomingMessage, res: http.ServerResponse) => void;
|
handle: (req: http.IncomingMessage, res: http.ServerResponse) => void;
|
||||||
close: () => Promise<void>;
|
close: () => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CreateContainerParams {
|
export interface CreateContainerParams {
|
||||||
|
logging: LogOptions;
|
||||||
|
settings: AstroSettings;
|
||||||
|
inlineConfig?: AstroInlineConfig;
|
||||||
isRestart?: boolean;
|
isRestart?: boolean;
|
||||||
logging?: LogOptions;
|
|
||||||
userConfig?: AstroUserConfig;
|
|
||||||
settings?: AstroSettings;
|
|
||||||
fs?: typeof nodeFs;
|
fs?: typeof nodeFs;
|
||||||
root?: string | URL;
|
|
||||||
// The string passed to --config and the resolved path
|
|
||||||
configFlag?: string;
|
|
||||||
configFlagPath?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createContainer(params: CreateContainerParams = {}): Promise<Container> {
|
export async function createContainer({
|
||||||
let {
|
isRestart = false,
|
||||||
isRestart = false,
|
logging,
|
||||||
logging = defaultLogging,
|
inlineConfig,
|
||||||
settings = await createDefaultDevSettings(params.userConfig, params.root),
|
settings,
|
||||||
fs = nodeFs,
|
fs = nodeFs,
|
||||||
} = params;
|
}: CreateContainerParams): Promise<Container> {
|
||||||
|
|
||||||
// Initialize
|
// Initialize
|
||||||
applyPolyfill();
|
applyPolyfill();
|
||||||
settings = await runHookConfigSetup({
|
settings = await runHookConfigSetup({
|
||||||
|
@ -94,14 +78,11 @@ export async function createContainer(params: CreateContainerParams = {}): Promi
|
||||||
const viteServer = await vite.createServer(viteConfig);
|
const viteServer = await vite.createServer(viteConfig);
|
||||||
|
|
||||||
const container: Container = {
|
const container: Container = {
|
||||||
configFlag: params.configFlag,
|
inlineConfig: inlineConfig ?? {},
|
||||||
configFlagPath: params.configFlagPath,
|
|
||||||
fs,
|
fs,
|
||||||
logging,
|
logging,
|
||||||
resolvedRoot: appendForwardSlash(resolveRoot(params.root)),
|
|
||||||
restartInFlight: false,
|
restartInFlight: false,
|
||||||
settings,
|
settings,
|
||||||
viteConfig,
|
|
||||||
viteServer,
|
viteServer,
|
||||||
handle(req, res) {
|
handle(req, res) {
|
||||||
viteServer.middlewares.handle(req, res, Function.prototype);
|
viteServer.middlewares.handle(req, res, Function.prototype);
|
||||||
|
@ -143,18 +124,3 @@ export async function startContainer({
|
||||||
export function isStarted(container: Container): boolean {
|
export function isStarted(container: Container): boolean {
|
||||||
return !!container.viteServer.httpServer?.listening;
|
return !!container.viteServer.httpServer?.listening;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Only used in tests
|
|
||||||
*/
|
|
||||||
export async function runInContainer(
|
|
||||||
params: CreateContainerParams,
|
|
||||||
callback: (container: Container) => Promise<void> | void
|
|
||||||
) {
|
|
||||||
const container = await createContainer(params);
|
|
||||||
try {
|
|
||||||
await callback(container);
|
|
||||||
} finally {
|
|
||||||
await container.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,27 +1,16 @@
|
||||||
import { cyan } from 'kleur/colors';
|
import fs from 'node:fs';
|
||||||
import type http from 'node:http';
|
import type http from 'node:http';
|
||||||
import type { AddressInfo } from 'node:net';
|
import type { AddressInfo } from 'node:net';
|
||||||
import { performance } from 'perf_hooks';
|
import { performance } from 'perf_hooks';
|
||||||
import type * as vite from 'vite';
|
import type * as vite from 'vite';
|
||||||
import type yargs from 'yargs-parser';
|
import type { AstroInlineConfig } from '../../@types/astro';
|
||||||
import type { AstroSettings } from '../../@types/astro';
|
|
||||||
import { attachContentServerListeners } from '../../content/index.js';
|
import { attachContentServerListeners } from '../../content/index.js';
|
||||||
import { telemetry } from '../../events/index.js';
|
import { telemetry } from '../../events/index.js';
|
||||||
import { info, warn, type LogOptions } from '../logger/core.js';
|
import { info, warn } from '../logger/core.js';
|
||||||
import * as msg from '../messages.js';
|
import * as msg from '../messages.js';
|
||||||
import { printHelp } from '../messages.js';
|
|
||||||
import { startContainer } from './container.js';
|
import { startContainer } from './container.js';
|
||||||
import { createContainerWithAutomaticRestart } from './restart.js';
|
import { createContainerWithAutomaticRestart } from './restart.js';
|
||||||
|
|
||||||
export interface DevOptions {
|
|
||||||
configFlag: string | undefined;
|
|
||||||
configFlagPath: string | undefined;
|
|
||||||
flags?: yargs.Arguments;
|
|
||||||
logging: LogOptions;
|
|
||||||
handleConfigError: (error: Error) => void;
|
|
||||||
isRestart?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DevServer {
|
export interface DevServer {
|
||||||
address: AddressInfo;
|
address: AddressInfo;
|
||||||
handle: (req: http.IncomingMessage, res: http.ServerResponse<http.IncomingMessage>) => void;
|
handle: (req: http.IncomingMessage, res: http.ServerResponse<http.IncomingMessage>) => void;
|
||||||
|
@ -30,68 +19,34 @@ export interface DevServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** `astro dev` */
|
/** `astro dev` */
|
||||||
export default async function dev(
|
export default async function dev(inlineConfig: AstroInlineConfig): Promise<DevServer> {
|
||||||
settings: AstroSettings,
|
|
||||||
options: DevOptions
|
|
||||||
): Promise<DevServer | undefined> {
|
|
||||||
if (options.flags?.help || options.flags?.h) {
|
|
||||||
printHelp({
|
|
||||||
commandName: 'astro dev',
|
|
||||||
usage: '[...flags]',
|
|
||||||
tables: {
|
|
||||||
Flags: [
|
|
||||||
['--port', `Specify which port to run on. Defaults to 3000.`],
|
|
||||||
['--host', `Listen on all addresses, including LAN and public addresses.`],
|
|
||||||
['--host <custom-address>', `Expose on a network IP address at <custom-address>`],
|
|
||||||
['--open', 'Automatically open the app in the browser on server start'],
|
|
||||||
['--help (-h)', 'See all available flags.'],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
description: `Check ${cyan(
|
|
||||||
'https://docs.astro.build/en/reference/cli-reference/#astro-dev'
|
|
||||||
)} for more information.`,
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const devStart = performance.now();
|
const devStart = performance.now();
|
||||||
await telemetry.record([]);
|
await telemetry.record([]);
|
||||||
|
|
||||||
// Create a container which sets up the Vite server.
|
// Create a container which sets up the Vite server.
|
||||||
const restart = await createContainerWithAutomaticRestart({
|
const restart = await createContainerWithAutomaticRestart({ inlineConfig, fs });
|
||||||
flags: options.flags ?? {},
|
const logging = restart.container.logging;
|
||||||
handleConfigError: options.handleConfigError,
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
beforeRestart: () => console.clear(),
|
|
||||||
params: {
|
|
||||||
settings,
|
|
||||||
root: options.flags?.root,
|
|
||||||
logging: options.logging,
|
|
||||||
isRestart: options.isRestart,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Start listening to the port
|
// Start listening to the port
|
||||||
const devServerAddressInfo = await startContainer(restart.container);
|
const devServerAddressInfo = await startContainer(restart.container);
|
||||||
|
|
||||||
info(
|
info(
|
||||||
options.logging,
|
logging,
|
||||||
null,
|
null,
|
||||||
msg.serverStart({
|
msg.serverStart({
|
||||||
startupTime: performance.now() - devStart,
|
startupTime: performance.now() - devStart,
|
||||||
resolvedUrls: restart.container.viteServer.resolvedUrls || { local: [], network: [] },
|
resolvedUrls: restart.container.viteServer.resolvedUrls || { local: [], network: [] },
|
||||||
host: settings.config.server.host,
|
host: restart.container.settings.config.server.host,
|
||||||
base: settings.config.base,
|
base: restart.container.settings.config.base,
|
||||||
isRestart: options.isRestart,
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const currentVersion = process.env.PACKAGE_VERSION ?? '0.0.0';
|
const currentVersion = process.env.PACKAGE_VERSION ?? '0.0.0';
|
||||||
if (currentVersion.includes('-')) {
|
if (currentVersion.includes('-')) {
|
||||||
warn(options.logging, null, msg.prerelease({ currentVersion }));
|
warn(logging, null, msg.prerelease({ currentVersion }));
|
||||||
}
|
}
|
||||||
if (restart.container.viteConfig.server?.fs?.strict === false) {
|
if (restart.container.viteServer.config.server?.fs?.strict === false) {
|
||||||
warn(options.logging, null, msg.fsStrictWarning());
|
warn(logging, null, msg.fsStrictWarning());
|
||||||
}
|
}
|
||||||
|
|
||||||
await attachContentServerListeners(restart.container);
|
await attachContentServerListeners(restart.container);
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
export { createContainer, isStarted, runInContainer, startContainer } from './container.js';
|
export { createContainer, isStarted, startContainer } from './container.js';
|
||||||
export { default } from './dev.js';
|
export { default } from './dev.js';
|
||||||
export { createContainerWithAutomaticRestart } from './restart.js';
|
export { createContainerWithAutomaticRestart } from './restart.js';
|
||||||
|
|
|
@ -1,9 +1,15 @@
|
||||||
|
import nodeFs from 'node:fs';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
import * as vite from 'vite';
|
import * as vite from 'vite';
|
||||||
import type { AstroSettings } from '../../@types/astro';
|
import type { AstroInlineConfig, AstroSettings } from '../../@types/astro';
|
||||||
import { createSettings, openConfig } from '../config/index.js';
|
import { eventCliSession, telemetry } from '../../events/index.js';
|
||||||
|
import { createNodeLogging, createSettings, resolveConfig } from '../config/index.js';
|
||||||
|
import { collectErrorMetadata } from '../errors/dev/utils.js';
|
||||||
|
import { isAstroConfigZodError } from '../errors/errors.js';
|
||||||
import { createSafeError } from '../errors/index.js';
|
import { createSafeError } from '../errors/index.js';
|
||||||
import { info } from '../logger/core.js';
|
import { info, error as logError } from '../logger/core.js';
|
||||||
import type { Container, CreateContainerParams } from './container';
|
import { formatErrorMessage } from '../messages.js';
|
||||||
|
import type { Container } from './container';
|
||||||
import { createContainer, isStarted, startContainer } from './container.js';
|
import { createContainer, isStarted, startContainer } from './container.js';
|
||||||
|
|
||||||
async function createRestartedContainer(
|
async function createRestartedContainer(
|
||||||
|
@ -11,15 +17,13 @@ async function createRestartedContainer(
|
||||||
settings: AstroSettings,
|
settings: AstroSettings,
|
||||||
needsStart: boolean
|
needsStart: boolean
|
||||||
): Promise<Container> {
|
): Promise<Container> {
|
||||||
const { logging, fs, resolvedRoot, configFlag, configFlagPath } = container;
|
const { logging, fs, inlineConfig } = container;
|
||||||
const newContainer = await createContainer({
|
const newContainer = await createContainer({
|
||||||
isRestart: true,
|
isRestart: true,
|
||||||
logging,
|
logging,
|
||||||
settings,
|
settings,
|
||||||
|
inlineConfig,
|
||||||
fs,
|
fs,
|
||||||
root: resolvedRoot,
|
|
||||||
configFlag,
|
|
||||||
configFlagPath,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (needsStart) {
|
if (needsStart) {
|
||||||
|
@ -30,7 +34,7 @@ async function createRestartedContainer(
|
||||||
}
|
}
|
||||||
|
|
||||||
export function shouldRestartContainer(
|
export function shouldRestartContainer(
|
||||||
{ settings, configFlag, configFlagPath, restartInFlight }: Container,
|
{ settings, inlineConfig, restartInFlight }: Container,
|
||||||
changedFile: string
|
changedFile: string
|
||||||
): boolean {
|
): boolean {
|
||||||
if (restartInFlight) return false;
|
if (restartInFlight) return false;
|
||||||
|
@ -38,10 +42,8 @@ export function shouldRestartContainer(
|
||||||
let shouldRestart = false;
|
let shouldRestart = false;
|
||||||
|
|
||||||
// If the config file changed, reload the config and restart the server.
|
// If the config file changed, reload the config and restart the server.
|
||||||
if (configFlag) {
|
if (inlineConfig.configFile) {
|
||||||
if (!!configFlagPath) {
|
shouldRestart = vite.normalizePath(inlineConfig.configFile) === vite.normalizePath(changedFile);
|
||||||
shouldRestart = vite.normalizePath(configFlagPath) === vite.normalizePath(changedFile);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Otherwise, watch for any astro.config.* file changes in project root
|
// Otherwise, watch for any astro.config.* file changes in project root
|
||||||
else {
|
else {
|
||||||
|
@ -60,39 +62,16 @@ export function shouldRestartContainer(
|
||||||
return shouldRestart;
|
return shouldRestart;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface RestartContainerParams {
|
export async function restartContainer(
|
||||||
container: Container;
|
container: Container
|
||||||
flags: any;
|
): Promise<{ container: Container; error: Error | null }> {
|
||||||
logMsg: string;
|
const { logging, close, settings: existingSettings } = container;
|
||||||
handleConfigError: (err: Error) => Promise<void> | void;
|
|
||||||
beforeRestart?: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function restartContainer({
|
|
||||||
container,
|
|
||||||
flags,
|
|
||||||
logMsg,
|
|
||||||
handleConfigError,
|
|
||||||
beforeRestart,
|
|
||||||
}: RestartContainerParams): Promise<{ container: Container; error: Error | null }> {
|
|
||||||
const { logging, close, resolvedRoot, settings: existingSettings } = container;
|
|
||||||
container.restartInFlight = true;
|
container.restartInFlight = true;
|
||||||
|
|
||||||
if (beforeRestart) {
|
|
||||||
beforeRestart();
|
|
||||||
}
|
|
||||||
const needsStart = isStarted(container);
|
const needsStart = isStarted(container);
|
||||||
try {
|
try {
|
||||||
const newConfig = await openConfig({
|
const { astroConfig } = await resolveConfig(container.inlineConfig, 'dev', container.fs);
|
||||||
cwd: resolvedRoot,
|
const settings = createSettings(astroConfig, fileURLToPath(existingSettings.config.root));
|
||||||
flags,
|
|
||||||
cmd: 'dev',
|
|
||||||
isRestart: true,
|
|
||||||
fsMod: container.fs,
|
|
||||||
});
|
|
||||||
info(logging, 'astro', logMsg + '\n');
|
|
||||||
let astroConfig = newConfig.astroConfig;
|
|
||||||
const settings = createSettings(astroConfig, resolvedRoot);
|
|
||||||
await close();
|
await close();
|
||||||
return {
|
return {
|
||||||
container: await createRestartedContainer(container, settings, needsStart),
|
container: await createRestartedContainer(container, settings, needsStart),
|
||||||
|
@ -100,7 +79,18 @@ export async function restartContainer({
|
||||||
};
|
};
|
||||||
} catch (_err) {
|
} catch (_err) {
|
||||||
const error = createSafeError(_err);
|
const error = createSafeError(_err);
|
||||||
await handleConfigError(error);
|
// Print all error messages except ZodErrors from AstroConfig as the pre-logged error is sufficient
|
||||||
|
if (!isAstroConfigZodError(_err)) {
|
||||||
|
logError(logging, 'config', formatErrorMessage(collectErrorMetadata(error)) + '\n');
|
||||||
|
}
|
||||||
|
// Inform connected clients of the config error
|
||||||
|
container.viteServer.ws.send({
|
||||||
|
type: 'error',
|
||||||
|
err: {
|
||||||
|
message: error.message,
|
||||||
|
stack: error.stack || '',
|
||||||
|
},
|
||||||
|
});
|
||||||
await close();
|
await close();
|
||||||
info(logging, 'astro', 'Continuing with previous valid configuration\n');
|
info(logging, 'astro', 'Continuing with previous valid configuration\n');
|
||||||
return {
|
return {
|
||||||
|
@ -111,10 +101,8 @@ export async function restartContainer({
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CreateContainerWithAutomaticRestart {
|
export interface CreateContainerWithAutomaticRestart {
|
||||||
flags: any;
|
inlineConfig?: AstroInlineConfig;
|
||||||
params: CreateContainerParams;
|
fs: typeof nodeFs;
|
||||||
handleConfigError?: (error: Error) => void | Promise<void>;
|
|
||||||
beforeRestart?: () => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Restart {
|
interface Restart {
|
||||||
|
@ -123,12 +111,17 @@ interface Restart {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createContainerWithAutomaticRestart({
|
export async function createContainerWithAutomaticRestart({
|
||||||
flags,
|
inlineConfig,
|
||||||
handleConfigError = () => {},
|
fs,
|
||||||
beforeRestart,
|
|
||||||
params,
|
|
||||||
}: CreateContainerWithAutomaticRestart): Promise<Restart> {
|
}: CreateContainerWithAutomaticRestart): Promise<Restart> {
|
||||||
const initialContainer = await createContainer(params);
|
const logging = createNodeLogging(inlineConfig ?? {});
|
||||||
|
const { userConfig, astroConfig } = await resolveConfig(inlineConfig ?? {}, 'dev', fs);
|
||||||
|
telemetry.record(eventCliSession('dev', userConfig));
|
||||||
|
|
||||||
|
const settings = createSettings(astroConfig, fileURLToPath(astroConfig.root));
|
||||||
|
|
||||||
|
const initialContainer = await createContainer({ settings, logging, inlineConfig, fs });
|
||||||
|
|
||||||
let resolveRestart: (value: Error | null) => void;
|
let resolveRestart: (value: Error | null) => void;
|
||||||
let restartComplete = new Promise<Error | null>((resolve) => {
|
let restartComplete = new Promise<Error | null>((resolve) => {
|
||||||
resolveRestart = resolve;
|
resolveRestart = resolve;
|
||||||
|
@ -142,24 +135,9 @@ export async function createContainerWithAutomaticRestart({
|
||||||
};
|
};
|
||||||
|
|
||||||
async function handleServerRestart(logMsg: string) {
|
async function handleServerRestart(logMsg: string) {
|
||||||
|
info(logging, 'astro', logMsg + '\n');
|
||||||
const container = restart.container;
|
const container = restart.container;
|
||||||
const { container: newContainer, error } = await restartContainer({
|
const { container: newContainer, error } = await restartContainer(container);
|
||||||
beforeRestart,
|
|
||||||
container,
|
|
||||||
flags,
|
|
||||||
logMsg,
|
|
||||||
async handleConfigError(err) {
|
|
||||||
// Send an error message to the client if one is connected.
|
|
||||||
await handleConfigError(err);
|
|
||||||
container.viteServer.ws.send({
|
|
||||||
type: 'error',
|
|
||||||
err: {
|
|
||||||
message: err.message,
|
|
||||||
stack: err.stack || '',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
restart.container = newContainer;
|
restart.container = newContainer;
|
||||||
// Add new watches because this is a new container with a new Vite server
|
// Add new watches because this is a new container with a new Vite server
|
||||||
addWatches();
|
addWatches();
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import type { ZodError } from 'zod';
|
||||||
import { codeFrame } from './printer.js';
|
import { codeFrame } from './printer.js';
|
||||||
import { getErrorDataByTitle } from './utils.js';
|
import { getErrorDataByTitle } from './utils.js';
|
||||||
|
|
||||||
|
@ -141,6 +142,23 @@ export class AggregateError extends AstroError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const astroConfigZodErrors = new WeakSet<ZodError>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if an error is a ZodError from an AstroConfig validation.
|
||||||
|
* Used to suppress formatting a ZodError if needed.
|
||||||
|
*/
|
||||||
|
export function isAstroConfigZodError(error: unknown): error is ZodError {
|
||||||
|
return astroConfigZodErrors.has(error as ZodError);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Track that a ZodError comes from an AstroConfig validation.
|
||||||
|
*/
|
||||||
|
export function trackAstroConfigZodError(error: ZodError): void {
|
||||||
|
astroConfigZodErrors.add(error);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic object representing an error with all possible data
|
* Generic object representing an error with all possible data
|
||||||
* Compatible with both Astro's and Vite's errors
|
* Compatible with both Astro's and Vite's errors
|
||||||
|
|
|
@ -1,40 +1,24 @@
|
||||||
import { cyan } from 'kleur/colors';
|
import { createRequire } from 'node:module';
|
||||||
import { createRequire } from 'module';
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||||
import { pathToFileURL } from 'node:url';
|
import type { AstroInlineConfig, PreviewModule, PreviewServer } from '../../@types/astro';
|
||||||
import type { Arguments } from 'yargs-parser';
|
import { telemetry } from '../../events/index.js';
|
||||||
import type { AstroSettings, PreviewModule, PreviewServer } from '../../@types/astro';
|
import { eventCliSession } from '../../events/session.js';
|
||||||
import { runHookConfigDone, runHookConfigSetup } from '../../integrations/index.js';
|
import { runHookConfigDone, runHookConfigSetup } from '../../integrations/index.js';
|
||||||
import type { LogOptions } from '../logger/core';
|
import { resolveConfig } from '../config/config.js';
|
||||||
import { printHelp } from '../messages.js';
|
import { createNodeLogging } from '../config/logging.js';
|
||||||
|
import { createSettings } from '../config/settings.js';
|
||||||
import createStaticPreviewServer from './static-preview-server.js';
|
import createStaticPreviewServer from './static-preview-server.js';
|
||||||
import { getResolvedHostForHttpServer } from './util.js';
|
import { getResolvedHostForHttpServer } from './util.js';
|
||||||
|
|
||||||
interface PreviewOptions {
|
|
||||||
logging: LogOptions;
|
|
||||||
flags?: Arguments;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** The primary dev action */
|
/** The primary dev action */
|
||||||
export default async function preview(
|
export default async function preview(
|
||||||
_settings: AstroSettings,
|
inlineConfig: AstroInlineConfig
|
||||||
{ logging, flags }: PreviewOptions
|
|
||||||
): Promise<PreviewServer | undefined> {
|
): Promise<PreviewServer | undefined> {
|
||||||
if (flags?.help || flags?.h) {
|
const logging = createNodeLogging(inlineConfig);
|
||||||
printHelp({
|
const { userConfig, astroConfig } = await resolveConfig(inlineConfig ?? {}, 'preview');
|
||||||
commandName: 'astro preview',
|
telemetry.record(eventCliSession('preview', userConfig));
|
||||||
usage: '[...flags]',
|
|
||||||
tables: {
|
const _settings = createSettings(astroConfig, fileURLToPath(astroConfig.root));
|
||||||
Flags: [
|
|
||||||
['--open', 'Automatically open the app in the browser on server start'],
|
|
||||||
['--help (-h)', 'See all available flags.'],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
description: `Starts a local server to serve your static dist/ directory. Check ${cyan(
|
|
||||||
'https://docs.astro.build/en/reference/cli-reference/#astro-preview'
|
|
||||||
)} for more information.`,
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const settings = await runHookConfigSetup({
|
const settings = await runHookConfigSetup({
|
||||||
settings: _settings,
|
settings: _settings,
|
||||||
|
|
|
@ -1,48 +1,54 @@
|
||||||
import { dim } from 'kleur/colors';
|
import { dim } from 'kleur/colors';
|
||||||
import type fsMod from 'node:fs';
|
import fsMod from 'node:fs';
|
||||||
import { performance } from 'node:perf_hooks';
|
import { performance } from 'node:perf_hooks';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
import { createServer, type HMRPayload } from 'vite';
|
import { createServer, type HMRPayload } from 'vite';
|
||||||
import type { Arguments } from 'yargs-parser';
|
import type { AstroInlineConfig, AstroSettings } from '../../@types/astro';
|
||||||
import type { AstroSettings } from '../../@types/astro';
|
|
||||||
import { createContentTypesGenerator } from '../../content/index.js';
|
import { createContentTypesGenerator } from '../../content/index.js';
|
||||||
import { globalContentConfigObserver } from '../../content/utils.js';
|
import { globalContentConfigObserver } from '../../content/utils.js';
|
||||||
|
import { telemetry } from '../../events/index.js';
|
||||||
|
import { eventCliSession } from '../../events/session.js';
|
||||||
import { runHookConfigSetup } from '../../integrations/index.js';
|
import { runHookConfigSetup } from '../../integrations/index.js';
|
||||||
import { setUpEnvTs } from '../../vite-plugin-inject-env-ts/index.js';
|
import { setUpEnvTs } from '../../vite-plugin-inject-env-ts/index.js';
|
||||||
import { getTimeStat } from '../build/util.js';
|
import { getTimeStat } from '../build/util.js';
|
||||||
|
import { resolveConfig } from '../config/config.js';
|
||||||
|
import { createNodeLogging } from '../config/logging.js';
|
||||||
|
import { createSettings } from '../config/settings.js';
|
||||||
import { createVite } from '../create-vite.js';
|
import { createVite } from '../create-vite.js';
|
||||||
import { AstroError, AstroErrorData, createSafeError, isAstroError } from '../errors/index.js';
|
import { AstroError, AstroErrorData, createSafeError, isAstroError } from '../errors/index.js';
|
||||||
import { info, type LogOptions } from '../logger/core.js';
|
import { info, type LogOptions } from '../logger/core.js';
|
||||||
import { printHelp } from '../messages.js';
|
|
||||||
|
|
||||||
export type ProcessExit = 0 | 1;
|
export type ProcessExit = 0 | 1;
|
||||||
|
|
||||||
export type SyncOptions = {
|
export type SyncOptions = {
|
||||||
logging: LogOptions;
|
/**
|
||||||
fs: typeof fsMod;
|
* Only used for testing
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
fs?: typeof fsMod;
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function syncCli(
|
export type SyncInternalOptions = SyncOptions & {
|
||||||
settings: AstroSettings,
|
logging: LogOptions;
|
||||||
{ logging, fs, flags }: { logging: LogOptions; fs: typeof fsMod; flags?: Arguments }
|
};
|
||||||
): Promise<ProcessExit> {
|
|
||||||
if (flags?.help || flags?.h) {
|
|
||||||
printHelp({
|
|
||||||
commandName: 'astro sync',
|
|
||||||
usage: '[...flags]',
|
|
||||||
tables: {
|
|
||||||
Flags: [['--help (-h)', 'See all available flags.']],
|
|
||||||
},
|
|
||||||
description: `Generates TypeScript types for all Astro modules.`,
|
|
||||||
});
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const resolvedSettings = await runHookConfigSetup({
|
export async function sync(
|
||||||
settings,
|
inlineConfig: AstroInlineConfig,
|
||||||
logging,
|
options?: SyncOptions
|
||||||
|
): Promise<ProcessExit> {
|
||||||
|
const logging = createNodeLogging(inlineConfig);
|
||||||
|
const { userConfig, astroConfig } = await resolveConfig(inlineConfig ?? {}, 'sync');
|
||||||
|
telemetry.record(eventCliSession('sync', userConfig));
|
||||||
|
|
||||||
|
const _settings = createSettings(astroConfig, fileURLToPath(astroConfig.root));
|
||||||
|
|
||||||
|
const settings = await runHookConfigSetup({
|
||||||
|
settings: _settings,
|
||||||
|
logging: logging,
|
||||||
command: 'build',
|
command: 'build',
|
||||||
});
|
});
|
||||||
return sync(resolvedSettings, { logging, fs });
|
|
||||||
|
return await syncInternal(settings, { logging, fs: options?.fs });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -50,15 +56,18 @@ export async function syncCli(
|
||||||
*
|
*
|
||||||
* A non-zero process signal is emitted in case there's an error while generating content collection types.
|
* A non-zero process signal is emitted in case there's an error while generating content collection types.
|
||||||
*
|
*
|
||||||
|
* This should only be used when the callee already has an `AstroSetting`, otherwise use `sync()` instead.
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
* @param {SyncOptions} options
|
* @param {SyncOptions} options
|
||||||
* @param {AstroSettings} settings Astro settings
|
* @param {AstroSettings} settings Astro settings
|
||||||
* @param {typeof fsMod} options.fs The file system
|
* @param {typeof fsMod} options.fs The file system
|
||||||
* @param {LogOptions} options.logging Logging options
|
* @param {LogOptions} options.logging Logging options
|
||||||
* @return {Promise<ProcessExit>}
|
* @return {Promise<ProcessExit>}
|
||||||
*/
|
*/
|
||||||
export async function sync(
|
export async function syncInternal(
|
||||||
settings: AstroSettings,
|
settings: AstroSettings,
|
||||||
{ logging, fs }: SyncOptions
|
{ logging, fs }: SyncInternalOptions
|
||||||
): Promise<ProcessExit> {
|
): Promise<ProcessExit> {
|
||||||
const timerStart = performance.now();
|
const timerStart = performance.now();
|
||||||
// Needed to load content config
|
// Needed to load content config
|
||||||
|
@ -88,7 +97,7 @@ export async function sync(
|
||||||
const contentTypesGenerator = await createContentTypesGenerator({
|
const contentTypesGenerator = await createContentTypesGenerator({
|
||||||
contentConfigObserver: globalContentConfigObserver,
|
contentConfigObserver: globalContentConfigObserver,
|
||||||
logging,
|
logging,
|
||||||
fs,
|
fs: fs ?? fsMod,
|
||||||
settings,
|
settings,
|
||||||
viteServer: tempViteServer,
|
viteServer: tempViteServer,
|
||||||
});
|
});
|
||||||
|
@ -124,7 +133,7 @@ export async function sync(
|
||||||
}
|
}
|
||||||
|
|
||||||
info(logging, 'content', `Types generated ${dim(getTimeStat(timerStart, performance.now()))}`);
|
info(logging, 'content', `Types generated ${dim(getTimeStat(timerStart, performance.now()))}`);
|
||||||
await setUpEnvTs({ settings, logging, fs });
|
await setUpEnvTs({ settings, logging, fs: fs ?? fsMod });
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ describe('Astro Markdown URL', () => {
|
||||||
it('trailingSlash: always', async () => {
|
it('trailingSlash: always', async () => {
|
||||||
let fixture = await loadFixture({
|
let fixture = await loadFixture({
|
||||||
root: './fixtures/astro-markdown-url/',
|
root: './fixtures/astro-markdown-url/',
|
||||||
outDir: new URL('./fixtures/astro-markdown-url/with-subpath-always/', import.meta.url),
|
outDir: './with-subpath-always',
|
||||||
base: '/my-cool-base',
|
base: '/my-cool-base',
|
||||||
trailingSlash: 'always',
|
trailingSlash: 'always',
|
||||||
});
|
});
|
||||||
|
@ -24,7 +24,7 @@ describe('Astro Markdown URL', () => {
|
||||||
it('trailingSlash: never', async () => {
|
it('trailingSlash: never', async () => {
|
||||||
let fixture = await loadFixture({
|
let fixture = await loadFixture({
|
||||||
root: './fixtures/astro-markdown-url/',
|
root: './fixtures/astro-markdown-url/',
|
||||||
outDir: new URL('./fixtures/astro-markdown-url/with-subpath-never/', import.meta.url),
|
outDir: './with-subpath-never',
|
||||||
base: '/my-cool-base',
|
base: '/my-cool-base',
|
||||||
trailingSlash: 'never',
|
trailingSlash: 'never',
|
||||||
});
|
});
|
||||||
|
@ -39,7 +39,7 @@ describe('Astro Markdown URL', () => {
|
||||||
it('trailingSlash: ignore', async () => {
|
it('trailingSlash: ignore', async () => {
|
||||||
let fixture = await loadFixture({
|
let fixture = await loadFixture({
|
||||||
root: './fixtures/astro-markdown-url/',
|
root: './fixtures/astro-markdown-url/',
|
||||||
outDir: new URL('./fixtures/astro-markdown-url/with-subpath-ignore/', import.meta.url),
|
outDir: './with-subpath-ignore',
|
||||||
base: '/my-cool-base',
|
base: '/my-cool-base',
|
||||||
trailingSlash: 'ignore',
|
trailingSlash: 'ignore',
|
||||||
});
|
});
|
||||||
|
@ -58,7 +58,7 @@ describe('Astro Markdown URL', () => {
|
||||||
it('trailingSlash: always', async () => {
|
it('trailingSlash: always', async () => {
|
||||||
let fixture = await loadFixture({
|
let fixture = await loadFixture({
|
||||||
root: './fixtures/astro-markdown-url/',
|
root: './fixtures/astro-markdown-url/',
|
||||||
outDir: new URL('./fixtures/astro-markdown-url/without-subpath-always/', import.meta.url),
|
outDir: './without-subpath-always',
|
||||||
trailingSlash: 'always',
|
trailingSlash: 'always',
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
|
@ -72,7 +72,7 @@ describe('Astro Markdown URL', () => {
|
||||||
it('trailingSlash: never', async () => {
|
it('trailingSlash: never', async () => {
|
||||||
let fixture = await loadFixture({
|
let fixture = await loadFixture({
|
||||||
root: './fixtures/astro-markdown-url/',
|
root: './fixtures/astro-markdown-url/',
|
||||||
outDir: new URL('./fixtures/astro-markdown-url/without-subpath-never/', import.meta.url),
|
outDir: './without-subpath-never',
|
||||||
trailingSlash: 'never',
|
trailingSlash: 'never',
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
|
@ -86,7 +86,7 @@ describe('Astro Markdown URL', () => {
|
||||||
it('trailingSlash: ignore', async () => {
|
it('trailingSlash: ignore', async () => {
|
||||||
let fixture = await loadFixture({
|
let fixture = await loadFixture({
|
||||||
root: './fixtures/astro-markdown-url/',
|
root: './fixtures/astro-markdown-url/',
|
||||||
outDir: new URL('./fixtures/astro-markdown-url/without-subpath-ignore/', import.meta.url),
|
outDir: './without-subpath-ignore',
|
||||||
trailingSlash: 'ignore',
|
trailingSlash: 'ignore',
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
|
|
|
@ -19,7 +19,7 @@ describe('astro sync', () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
await fixture.sync({ fs: fsMock });
|
await fixture.sync({}, { fs: fsMock });
|
||||||
|
|
||||||
const expectedTypesFile = new URL('.astro/types.d.ts', fixture.config.root).href;
|
const expectedTypesFile = new URL('.astro/types.d.ts', fixture.config.root).href;
|
||||||
expect(writtenFiles).to.haveOwnProperty(expectedTypesFile);
|
expect(writtenFiles).to.haveOwnProperty(expectedTypesFile);
|
||||||
|
@ -55,7 +55,7 @@ describe('astro sync', () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
await fixture.sync({ fs: fsMock });
|
await fixture.sync({}, { fs: fsMock });
|
||||||
|
|
||||||
expect(writtenFiles, 'Did not try to update env.d.ts file.').to.haveOwnProperty(typesEnvPath);
|
expect(writtenFiles, 'Did not try to update env.d.ts file.').to.haveOwnProperty(typesEnvPath);
|
||||||
expect(writtenFiles[typesEnvPath]).to.include(`/// <reference path="../.astro/types.d.ts" />`);
|
expect(writtenFiles[typesEnvPath]).to.include(`/// <reference path="../.astro/types.d.ts" />`);
|
||||||
|
@ -79,7 +79,7 @@ describe('astro sync', () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
await fixture.sync({ fs: fsMock });
|
await fixture.sync({}, { fs: fsMock });
|
||||||
|
|
||||||
expect(writtenFiles, 'Did not try to write env.d.ts file.').to.haveOwnProperty(typesEnvPath);
|
expect(writtenFiles, 'Did not try to write env.d.ts file.').to.haveOwnProperty(typesEnvPath);
|
||||||
expect(writtenFiles[typesEnvPath]).to.include(`/// <reference types="astro/client" />`);
|
expect(writtenFiles[typesEnvPath]).to.include(`/// <reference types="astro/client" />`);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import { loadFixture, silentLogging } from './test-utils.js';
|
import { loadFixture } from './test-utils.js';
|
||||||
import testAdapter from './test-adapter.js';
|
import testAdapter from './test-adapter.js';
|
||||||
import * as cheerio from 'cheerio';
|
import * as cheerio from 'cheerio';
|
||||||
|
|
||||||
|
@ -108,8 +108,7 @@ describe('Astro.clientAddress', () => {
|
||||||
let devServer;
|
let devServer;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
// We expect an error, so silence the output
|
devServer = await fixture.startDevServer();
|
||||||
devServer = await fixture.startDevServer({ logging: silentLogging });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
after(async () => {
|
after(async () => {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import { loadFixture, silentLogging } from './test-utils.js';
|
import { loadFixture } from './test-utils.js';
|
||||||
|
|
||||||
describe('Development Routing', () => {
|
describe('Development Routing', () => {
|
||||||
describe('No site config', () => {
|
describe('No site config', () => {
|
||||||
|
@ -10,9 +10,7 @@ describe('Development Routing', () => {
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({ root: './fixtures/without-site-config/' });
|
fixture = await loadFixture({ root: './fixtures/without-site-config/' });
|
||||||
devServer = await fixture.startDevServer({
|
devServer = await fixture.startDevServer();
|
||||||
logging: silentLogging,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
after(async () => {
|
after(async () => {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import { load as cheerioLoad } from 'cheerio';
|
import { load as cheerioLoad } from 'cheerio';
|
||||||
import { loadFixture, silentLogging } from './test-utils.js';
|
import { loadFixture } from './test-utils.js';
|
||||||
|
|
||||||
describe('Dynamic endpoint collision', () => {
|
describe('Dynamic endpoint collision', () => {
|
||||||
describe('build', () => {
|
describe('build', () => {
|
||||||
|
@ -31,9 +31,7 @@ describe('Dynamic endpoint collision', () => {
|
||||||
root: './fixtures/dynamic-endpoint-collision/',
|
root: './fixtures/dynamic-endpoint-collision/',
|
||||||
});
|
});
|
||||||
|
|
||||||
devServer = await fixture.startDevServer({
|
devServer = await fixture.startDevServer();
|
||||||
logging: silentLogging,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
after(async () => {
|
after(async () => {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import { loadFixture, silentLogging } from './test-utils.js';
|
import { loadFixture } from './test-utils.js';
|
||||||
|
|
||||||
describe('Errors in JavaScript', () => {
|
describe('Errors in JavaScript', () => {
|
||||||
/** @type {import('./test-utils').Fixture} */
|
/** @type {import('./test-utils').Fixture} */
|
||||||
|
@ -15,9 +15,7 @@ describe('Errors in JavaScript', () => {
|
||||||
logLevel: 'silent',
|
logLevel: 'silent',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
devServer = await fixture.startDevServer({
|
devServer = await fixture.startDevServer();
|
||||||
logging: silentLogging,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
after(async () => {
|
after(async () => {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import { loadFixture, silentLogging } from './test-utils.js';
|
import { loadFixture } from './test-utils.js';
|
||||||
|
|
||||||
describe('Can handle errors that are not instanceof Error', () => {
|
describe('Can handle errors that are not instanceof Error', () => {
|
||||||
/** @type {import('./test-utils').Fixture} */
|
/** @type {import('./test-utils').Fixture} */
|
||||||
|
@ -12,9 +12,7 @@ describe('Can handle errors that are not instanceof Error', () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: './fixtures/error-non-error',
|
root: './fixtures/error-non-error',
|
||||||
});
|
});
|
||||||
devServer = await fixture.startDevServer({
|
devServer = await fixture.startDevServer();
|
||||||
logging: silentLogging,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
after(async () => {
|
after(async () => {
|
||||||
|
|
|
@ -13,7 +13,7 @@ describe('Preview Routing', () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: './fixtures/with-subpath-no-trailing-slash/',
|
root: './fixtures/with-subpath-no-trailing-slash/',
|
||||||
base: '/blog',
|
base: '/blog',
|
||||||
outDir: new URL('./fixtures/with-subpath-no-trailing-slash/dist-4000/', import.meta.url),
|
outDir: './dist-4000',
|
||||||
build: {
|
build: {
|
||||||
format: 'directory',
|
format: 'directory',
|
||||||
},
|
},
|
||||||
|
@ -41,9 +41,10 @@ describe('Preview Routing', () => {
|
||||||
expect(response.redirected).to.equal(false);
|
expect(response.redirected).to.equal(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('404 when loading subpath root without trailing slash', async () => {
|
it('200 when loading subpath root without trailing slash', async () => {
|
||||||
const response = await fixture.fetch('/blog');
|
const response = await fixture.fetch('/blog');
|
||||||
expect(response.status).to.equal(404);
|
expect(response.status).to.equal(200);
|
||||||
|
expect(response.redirected).to.equal(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('404 when loading another page with subpath used', async () => {
|
it('404 when loading another page with subpath used', async () => {
|
||||||
|
@ -72,7 +73,7 @@ describe('Preview Routing', () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: './fixtures/with-subpath-no-trailing-slash/',
|
root: './fixtures/with-subpath-no-trailing-slash/',
|
||||||
base: '/blog',
|
base: '/blog',
|
||||||
outDir: new URL('./fixtures/with-subpath-no-trailing-slash/dist-4001/', import.meta.url),
|
outDir: './dist-4001',
|
||||||
trailingSlash: 'always',
|
trailingSlash: 'always',
|
||||||
server: {
|
server: {
|
||||||
port: 4001,
|
port: 4001,
|
||||||
|
@ -132,7 +133,7 @@ describe('Preview Routing', () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: './fixtures/with-subpath-no-trailing-slash/',
|
root: './fixtures/with-subpath-no-trailing-slash/',
|
||||||
base: '/blog',
|
base: '/blog',
|
||||||
outDir: new URL('./fixtures/with-subpath-no-trailing-slash/dist-4002/', import.meta.url),
|
outDir: './dist-4002',
|
||||||
trailingSlash: 'ignore',
|
trailingSlash: 'ignore',
|
||||||
server: {
|
server: {
|
||||||
port: 4002,
|
port: 4002,
|
||||||
|
@ -194,7 +195,7 @@ describe('Preview Routing', () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: './fixtures/with-subpath-no-trailing-slash/',
|
root: './fixtures/with-subpath-no-trailing-slash/',
|
||||||
base: '/blog',
|
base: '/blog',
|
||||||
outDir: new URL('./fixtures/with-subpath-no-trailing-slash/dist-4003/', import.meta.url),
|
outDir: './dist-4003',
|
||||||
build: {
|
build: {
|
||||||
format: 'file',
|
format: 'file',
|
||||||
},
|
},
|
||||||
|
@ -222,9 +223,10 @@ describe('Preview Routing', () => {
|
||||||
expect(response.redirected).to.equal(false);
|
expect(response.redirected).to.equal(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('404 when loading subpath root without trailing slash', async () => {
|
it('200 when loading subpath root without trailing slash', async () => {
|
||||||
const response = await fixture.fetch('/blog');
|
const response = await fixture.fetch('/blog');
|
||||||
expect(response.status).to.equal(404);
|
expect(response.status).to.equal(200);
|
||||||
|
expect(response.redirected).to.equal(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('404 when loading another page with subpath used', async () => {
|
it('404 when loading another page with subpath used', async () => {
|
||||||
|
@ -253,7 +255,7 @@ describe('Preview Routing', () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: './fixtures/with-subpath-no-trailing-slash/',
|
root: './fixtures/with-subpath-no-trailing-slash/',
|
||||||
base: '/blog',
|
base: '/blog',
|
||||||
outDir: new URL('./fixtures/with-subpath-no-trailing-slash/dist-4004/', import.meta.url),
|
outDir: './dist-4004',
|
||||||
build: {
|
build: {
|
||||||
format: 'file',
|
format: 'file',
|
||||||
},
|
},
|
||||||
|
@ -316,7 +318,7 @@ describe('Preview Routing', () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: './fixtures/with-subpath-no-trailing-slash/',
|
root: './fixtures/with-subpath-no-trailing-slash/',
|
||||||
base: '/blog',
|
base: '/blog',
|
||||||
outDir: new URL('./fixtures/with-subpath-no-trailing-slash/dist-4005/', import.meta.url),
|
outDir: './dist-4005',
|
||||||
build: {
|
build: {
|
||||||
format: 'file',
|
format: 'file',
|
||||||
},
|
},
|
||||||
|
@ -379,7 +381,7 @@ describe('Preview Routing', () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: './fixtures/with-subpath-no-trailing-slash/',
|
root: './fixtures/with-subpath-no-trailing-slash/',
|
||||||
base: '/blog',
|
base: '/blog',
|
||||||
outDir: new URL('./fixtures/with-subpath-no-trailing-slash/dist-4006/', import.meta.url),
|
outDir: './dist-4006',
|
||||||
build: {
|
build: {
|
||||||
format: 'file',
|
format: 'file',
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import { load as cheerioLoad } from 'cheerio';
|
import { load as cheerioLoad } from 'cheerio';
|
||||||
import { isWindows, loadFixture, silentLogging } from './test-utils.js';
|
import { isWindows, loadFixture } from './test-utils.js';
|
||||||
|
|
||||||
let fixture;
|
let fixture;
|
||||||
|
|
||||||
|
@ -108,9 +108,7 @@ describe('React Components', () => {
|
||||||
let devServer;
|
let devServer;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
devServer = await fixture.startDevServer({
|
devServer = await fixture.startDevServer();
|
||||||
logging: silentLogging,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
after(async () => {
|
after(async () => {
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { execa } from 'execa';
|
||||||
import fastGlob from 'fast-glob';
|
import fastGlob from 'fast-glob';
|
||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
import os from 'node:os';
|
import os from 'node:os';
|
||||||
|
import path from 'node:path';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
import stripAnsi from 'strip-ansi';
|
import stripAnsi from 'strip-ansi';
|
||||||
import { check } from '../dist/cli/check/index.js';
|
import { check } from '../dist/cli/check/index.js';
|
||||||
|
@ -10,8 +11,7 @@ import build from '../dist/core/build/index.js';
|
||||||
import { RESOLVED_SPLIT_MODULE_ID } from '../dist/core/build/plugins/plugin-ssr.js';
|
import { RESOLVED_SPLIT_MODULE_ID } from '../dist/core/build/plugins/plugin-ssr.js';
|
||||||
import { getVirtualModulePageNameFromPath } from '../dist/core/build/plugins/util.js';
|
import { getVirtualModulePageNameFromPath } from '../dist/core/build/plugins/util.js';
|
||||||
import { makeSplitEntryPointFileName } from '../dist/core/build/static-build.js';
|
import { makeSplitEntryPointFileName } from '../dist/core/build/static-build.js';
|
||||||
import { openConfig } from '../dist/core/config/config.js';
|
import { mergeConfig, resolveConfig } from '../dist/core/config/index.js';
|
||||||
import { createSettings } from '../dist/core/config/index.js';
|
|
||||||
import dev from '../dist/core/dev/index.js';
|
import dev from '../dist/core/dev/index.js';
|
||||||
import { nodeLogDestination } from '../dist/core/logger/node.js';
|
import { nodeLogDestination } from '../dist/core/logger/node.js';
|
||||||
import preview from '../dist/core/preview/index.js';
|
import preview from '../dist/core/preview/index.js';
|
||||||
|
@ -28,7 +28,7 @@ process.env.ASTRO_TELEMETRY_DISABLED = true;
|
||||||
/**
|
/**
|
||||||
* @typedef {import('undici').Response} Response
|
* @typedef {import('undici').Response} Response
|
||||||
* @typedef {import('../src/core/dev/dev').DedvServer} DevServer
|
* @typedef {import('../src/core/dev/dev').DedvServer} DevServer
|
||||||
* @typedef {import('../src/@types/astro').AstroConfig} AstroConfig
|
* @typedef {import('../src/@types/astro').AstroInlineConfig & { root?: string | URL }} AstroInlineConfig
|
||||||
* @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
|
||||||
* @typedef {import('../src/cli/check/index').AstroChecker} AstroChecker
|
* @typedef {import('../src/cli/check/index').AstroChecker} AstroChecker
|
||||||
|
@ -43,12 +43,13 @@ process.env.ASTRO_TELEMETRY_DISABLED = true;
|
||||||
* @property {(path: string, updater: (content: string) => string) => Promise<void>} writeFile
|
* @property {(path: string, updater: (content: string) => string) => Promise<void>} writeFile
|
||||||
* @property {(path: string) => Promise<string[]>} readdir
|
* @property {(path: string) => Promise<string[]>} readdir
|
||||||
* @property {(pattern: string) => Promise<string[]>} glob
|
* @property {(pattern: string) => Promise<string[]>} glob
|
||||||
* @property {() => Promise<DevServer>} startDevServer
|
* @property {typeof dev} startDevServer
|
||||||
* @property {() => Promise<PreviewServer>} preview
|
* @property {typeof preview} preview
|
||||||
* @property {() => Promise<void>} clean
|
* @property {() => Promise<void>} clean
|
||||||
* @property {() => Promise<App>} loadTestAdapterApp
|
* @property {() => Promise<App>} loadTestAdapterApp
|
||||||
* @property {() => Promise<void>} onNextChange
|
* @property {() => Promise<void>} onNextChange
|
||||||
* @property {(opts: CheckPayload) => Promise<AstroChecker>} check
|
* @property {typeof check} check
|
||||||
|
* @property {typeof sync} sync
|
||||||
*
|
*
|
||||||
* This function returns an instance of the Check
|
* This function returns an instance of the Check
|
||||||
*
|
*
|
||||||
|
@ -82,7 +83,7 @@ export const silentLogging = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load Astro fixture
|
* Load Astro fixture
|
||||||
* @param {AstroConfig} inlineConfig Astro config partial (note: must specify `root`)
|
* @param {AstroInlineConfig} inlineConfig Astro config partial (note: must specify `root`)
|
||||||
* @returns {Promise<Fixture>} The fixture. Has the following properties:
|
* @returns {Promise<Fixture>} The fixture. Has the following properties:
|
||||||
* .config - Returns the final config. Will be automatically passed to the methods below:
|
* .config - Returns the final config. Will be automatically passed to the methods below:
|
||||||
*
|
*
|
||||||
|
@ -103,50 +104,25 @@ export const silentLogging = {
|
||||||
export async function loadFixture(inlineConfig) {
|
export async function loadFixture(inlineConfig) {
|
||||||
if (!inlineConfig?.root) throw new Error("Must provide { root: './fixtures/...' }");
|
if (!inlineConfig?.root) throw new Error("Must provide { root: './fixtures/...' }");
|
||||||
|
|
||||||
// load config
|
// Silent by default during tests to not pollute the console output
|
||||||
let cwd = inlineConfig.root;
|
inlineConfig.logLevel = 'silent';
|
||||||
delete inlineConfig.root;
|
|
||||||
if (typeof cwd === 'string') {
|
let root = inlineConfig.root;
|
||||||
try {
|
// Handle URL, should already be absolute so just convert to path
|
||||||
cwd = new URL(cwd.replace(/\/?$/, '/'));
|
if (typeof root !== 'string') {
|
||||||
} catch (err1) {
|
root = fileURLToPath(root);
|
||||||
cwd = new URL(cwd.replace(/\/?$/, '/'), import.meta.url);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// Handle "file:///C:/Users/fred", convert to "C:/Users/fred"
|
||||||
/** @type {import('../src/core/logger/core').LogOptions} */
|
else if (root.startsWith('file://')) {
|
||||||
const logging = defaultLogging;
|
root = fileURLToPath(new URL(root));
|
||||||
|
}
|
||||||
|
// Handle "./fixtures/...", convert to absolute path
|
||||||
|
else if (!path.isAbsolute(root)) {
|
||||||
|
root = fileURLToPath(new URL(root, import.meta.url));
|
||||||
|
}
|
||||||
|
inlineConfig = { ...inlineConfig, root };
|
||||||
// Load the config.
|
// Load the config.
|
||||||
let { astroConfig: config } = await openConfig({
|
const { astroConfig: config } = await resolveConfig(inlineConfig, 'dev');
|
||||||
cwd: fileURLToPath(cwd),
|
|
||||||
logging,
|
|
||||||
cmd: 'dev',
|
|
||||||
});
|
|
||||||
config = merge(config, { ...inlineConfig, root: cwd });
|
|
||||||
|
|
||||||
// HACK: the inline config doesn't run through config validation where these normalizations usually occur
|
|
||||||
if (typeof inlineConfig.site === 'string') {
|
|
||||||
config.site = new URL(inlineConfig.site);
|
|
||||||
}
|
|
||||||
if (inlineConfig.base && !inlineConfig.base.endsWith('/')) {
|
|
||||||
config.base = inlineConfig.base + '/';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The dev/build/sync/check commands run integrations' `astro:config:setup` hook that could mutate
|
|
||||||
* the `AstroSettings`. This function helps to create a fresh settings object that is used by the
|
|
||||||
* command functions below to prevent tests from polluting each other.
|
|
||||||
*/
|
|
||||||
const getSettings = async () => {
|
|
||||||
let settings = createSettings(config, fileURLToPath(cwd));
|
|
||||||
if (config.integrations.find((integration) => integration.name === '@astrojs/mdx')) {
|
|
||||||
// Enable default JSX integration. It needs to come first, so unshift rather than push!
|
|
||||||
const { default: jsxRenderer } = await import('astro/jsx/renderer.js');
|
|
||||||
settings.renderers.unshift(jsxRenderer);
|
|
||||||
}
|
|
||||||
return settings;
|
|
||||||
};
|
|
||||||
|
|
||||||
const resolveUrl = (url) =>
|
const resolveUrl = (url) =>
|
||||||
`http://${config.server.host || 'localhost'}:${config.server.port}${url.replace(/^\/?/, '/')}`;
|
`http://${config.server.host || 'localhost'}:${config.server.port}${url.replace(/^\/?/, '/')}`;
|
||||||
|
@ -177,17 +153,19 @@ export async function loadFixture(inlineConfig) {
|
||||||
let devServer;
|
let devServer;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
build: async (opts = {}) => {
|
build: async (extraInlineConfig = {}) => {
|
||||||
process.env.NODE_ENV = 'production';
|
process.env.NODE_ENV = 'production';
|
||||||
return build(await getSettings('build'), { logging, ...opts });
|
return build(mergeConfig(inlineConfig, extraInlineConfig));
|
||||||
|
},
|
||||||
|
sync: async (extraInlineConfig = {}, opts) => {
|
||||||
|
return sync(mergeConfig(inlineConfig, extraInlineConfig), opts);
|
||||||
},
|
},
|
||||||
sync: async (opts) => sync(await getSettings('build'), { logging, fs, ...opts }),
|
|
||||||
check: async (opts) => {
|
check: async (opts) => {
|
||||||
return await check(await getSettings('build'), { logging, ...opts });
|
return await check(opts);
|
||||||
},
|
},
|
||||||
startDevServer: async (opts = {}) => {
|
startDevServer: async (extraInlineConfig = {}) => {
|
||||||
process.env.NODE_ENV = 'development';
|
process.env.NODE_ENV = 'development';
|
||||||
devServer = await dev(await getSettings('dev'), { logging, ...opts });
|
devServer = await dev(mergeConfig(inlineConfig, extraInlineConfig));
|
||||||
config.server.host = parseAddressToHost(devServer.address.address); // update host
|
config.server.host = parseAddressToHost(devServer.address.address); // update host
|
||||||
config.server.port = devServer.address.port; // update port
|
config.server.port = devServer.address.port; // update port
|
||||||
return devServer;
|
return devServer;
|
||||||
|
@ -207,9 +185,9 @@ export async function loadFixture(inlineConfig) {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
preview: async (opts = {}) => {
|
preview: async (extraInlineConfig = {}) => {
|
||||||
process.env.NODE_ENV = 'production';
|
process.env.NODE_ENV = 'production';
|
||||||
const previewServer = await preview(await getSettings('build'), { logging, ...opts });
|
const previewServer = await preview(mergeConfig(inlineConfig, extraInlineConfig));
|
||||||
config.server.host = parseAddressToHost(previewServer.host); // update host
|
config.server.host = parseAddressToHost(previewServer.host); // update host
|
||||||
config.server.port = previewServer.port; // update port
|
config.server.port = previewServer.port; // update port
|
||||||
return previewServer;
|
return previewServer;
|
||||||
|
@ -282,32 +260,6 @@ function parseAddressToHost(address) {
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Basic object merge utility. Returns new copy of merged Object.
|
|
||||||
* @param {Object} a
|
|
||||||
* @param {Object} b
|
|
||||||
* @returns {Object}
|
|
||||||
*/
|
|
||||||
function merge(a, b) {
|
|
||||||
const allKeys = new Set([...Object.keys(a), ...Object.keys(b)]);
|
|
||||||
const c = {};
|
|
||||||
for (const k of allKeys) {
|
|
||||||
const needsObjectMerge =
|
|
||||||
typeof a[k] === 'object' &&
|
|
||||||
typeof b[k] === 'object' &&
|
|
||||||
(Object.keys(a[k]).length || Object.keys(b[k]).length) &&
|
|
||||||
!Array.isArray(a[k]) &&
|
|
||||||
!Array.isArray(b[k]);
|
|
||||||
if (needsObjectMerge) {
|
|
||||||
c[k] = merge(a[k] || {}, b[k] || {});
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
c[k] = a[k];
|
|
||||||
if (b[k] !== undefined) c[k] = b[k];
|
|
||||||
}
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
const cliPath = fileURLToPath(new URL('../astro.js', import.meta.url));
|
const cliPath = fileURLToPath(new URL('../astro.js', import.meta.url));
|
||||||
|
|
||||||
/** Returns a process running the Astro CLI. */
|
/** Returns a process running the Astro CLI. */
|
||||||
|
|
|
@ -1,24 +1,25 @@
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
import { defaultLogging } from '../test-utils.js';
|
import { flagsToAstroInlineConfig } from '../../../dist/cli/flags.js';
|
||||||
import { openConfig } from '../../../dist/core/config/index.js';
|
import { resolveConfig } from '../../../dist/core/config/index.js';
|
||||||
|
|
||||||
const cwd = fileURLToPath(new URL('../../fixtures/config-host/', import.meta.url));
|
const cwd = fileURLToPath(new URL('../../fixtures/config-host/', import.meta.url));
|
||||||
|
|
||||||
describe('config.server', () => {
|
describe('config.server', () => {
|
||||||
function openConfigWithFlags(flags) {
|
function resolveConfigWithFlags(flags) {
|
||||||
return openConfig({
|
return resolveConfig(
|
||||||
cwd: flags.root || cwd,
|
flagsToAstroInlineConfig({
|
||||||
flags,
|
root: cwd,
|
||||||
cmd: 'dev',
|
...flags,
|
||||||
logging: defaultLogging,
|
}),
|
||||||
});
|
'dev'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('host', () => {
|
describe('host', () => {
|
||||||
it('can be specified via --host flag', async () => {
|
it('can be specified via --host flag', async () => {
|
||||||
const projectRootURL = new URL('../../fixtures/astro-basic/', import.meta.url);
|
const projectRootURL = new URL('../../fixtures/astro-basic/', import.meta.url);
|
||||||
const { astroConfig } = await openConfigWithFlags({
|
const { astroConfig } = await resolveConfigWithFlags({
|
||||||
root: fileURLToPath(projectRootURL),
|
root: fileURLToPath(projectRootURL),
|
||||||
host: true,
|
host: true,
|
||||||
});
|
});
|
||||||
|
@ -32,7 +33,7 @@ describe('config.server', () => {
|
||||||
it('can be passed via relative --config', async () => {
|
it('can be passed via relative --config', async () => {
|
||||||
const projectRootURL = new URL('../../fixtures/astro-basic/', import.meta.url);
|
const projectRootURL = new URL('../../fixtures/astro-basic/', import.meta.url);
|
||||||
const configFileURL = 'my-config.mjs';
|
const configFileURL = 'my-config.mjs';
|
||||||
const { astroConfig } = await openConfigWithFlags({
|
const { astroConfig } = await resolveConfigWithFlags({
|
||||||
root: fileURLToPath(projectRootURL),
|
root: fileURLToPath(projectRootURL),
|
||||||
config: configFileURL,
|
config: configFileURL,
|
||||||
});
|
});
|
||||||
|
@ -44,7 +45,7 @@ describe('config.server', () => {
|
||||||
it('can be passed via relative --config', async () => {
|
it('can be passed via relative --config', async () => {
|
||||||
const projectRootURL = new URL('../../fixtures/astro-basic/', import.meta.url);
|
const projectRootURL = new URL('../../fixtures/astro-basic/', import.meta.url);
|
||||||
const configFileURL = './my-config.mjs';
|
const configFileURL = './my-config.mjs';
|
||||||
const { astroConfig } = await openConfigWithFlags({
|
const { astroConfig } = await resolveConfigWithFlags({
|
||||||
root: fileURLToPath(projectRootURL),
|
root: fileURLToPath(projectRootURL),
|
||||||
config: configFileURL,
|
config: configFileURL,
|
||||||
});
|
});
|
||||||
|
@ -57,7 +58,7 @@ describe('config.server', () => {
|
||||||
const projectRootURL = new URL('../../fixtures/astro-basic/', import.meta.url);
|
const projectRootURL = new URL('../../fixtures/astro-basic/', import.meta.url);
|
||||||
const configFileURL = './does-not-exist.mjs';
|
const configFileURL = './does-not-exist.mjs';
|
||||||
try {
|
try {
|
||||||
await openConfigWithFlags({
|
await resolveConfigWithFlags({
|
||||||
root: fileURLToPath(projectRootURL),
|
root: fileURLToPath(projectRootURL),
|
||||||
config: configFileURL,
|
config: configFileURL,
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,7 +2,7 @@ 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/index.js';
|
import { validateConfig } from '../../../dist/core/config/config.js';
|
||||||
|
|
||||||
describe('Config Validation', () => {
|
describe('Config Validation', () => {
|
||||||
it('empty user config is valid', async () => {
|
it('empty user config is valid', async () => {
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
|
import { createFs, runInContainer } from '../test-utils.js';
|
||||||
import { createSettings, openConfig } from '../../../dist/core/config/index.js';
|
|
||||||
import { runInContainer } from '../../../dist/core/dev/index.js';
|
|
||||||
import { createFs, defaultLogging } from '../test-utils.js';
|
|
||||||
|
|
||||||
const root = new URL('../../fixtures/tailwindcss-ts/', import.meta.url);
|
const root = new URL('../../fixtures/tailwindcss-ts/', import.meta.url);
|
||||||
|
|
||||||
|
@ -20,16 +18,7 @@ describe('Astro config formats', () => {
|
||||||
root
|
root
|
||||||
);
|
);
|
||||||
|
|
||||||
const { astroConfig } = await openConfig({
|
await runInContainer({ fs, inlineConfig: { root: fileURLToPath(root) } }, () => {
|
||||||
cwd: root,
|
|
||||||
flags: {},
|
|
||||||
cmd: 'dev',
|
|
||||||
logging: defaultLogging,
|
|
||||||
fsMod: fs,
|
|
||||||
});
|
|
||||||
const settings = createSettings(astroConfig);
|
|
||||||
|
|
||||||
await runInContainer({ fs, root, settings }, () => {
|
|
||||||
expect(true).to.equal(
|
expect(true).to.equal(
|
||||||
true,
|
true,
|
||||||
'We were able to get into the container which means the config loaded.'
|
'We were able to get into the container which means the config loaded.'
|
||||||
|
|
|
@ -2,9 +2,8 @@ import { fileURLToPath } from 'node:url';
|
||||||
import nodeFS from 'node:fs';
|
import nodeFS from 'node:fs';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
|
|
||||||
import { runInContainer } from '../../../dist/core/dev/index.js';
|
|
||||||
import { attachContentServerListeners } from '../../../dist/content/index.js';
|
import { attachContentServerListeners } from '../../../dist/content/index.js';
|
||||||
import { createFs, triggerFSEvent } from '../test-utils.js';
|
import { createFs, runInContainer, triggerFSEvent } from '../test-utils.js';
|
||||||
|
|
||||||
const root = new URL('../../fixtures/alias/', import.meta.url);
|
const root = new URL('../../fixtures/alias/', import.meta.url);
|
||||||
|
|
||||||
|
@ -53,7 +52,7 @@ describe('frontmatter', () => {
|
||||||
root
|
root
|
||||||
);
|
);
|
||||||
|
|
||||||
await runInContainer({ fs, root }, async (container) => {
|
await runInContainer({ fs, inlineConfig: { root: fileURLToPath(root) } }, async (container) => {
|
||||||
await attachContentServerListeners(container);
|
await attachContentServerListeners(container);
|
||||||
|
|
||||||
fs.writeFileFromRootSync(
|
fs.writeFileFromRootSync(
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
import { runInContainer } from '../../../dist/core/dev/index.js';
|
import { createFs, createRequestAndResponse, runInContainer } from '../test-utils.js';
|
||||||
import { createFs, createRequestAndResponse } from '../test-utils.js';
|
|
||||||
|
|
||||||
const root = new URL('../../fixtures/alias/', import.meta.url);
|
const root = new URL('../../fixtures/alias/', import.meta.url);
|
||||||
|
|
||||||
|
@ -19,8 +18,8 @@ describe('base configuration', () => {
|
||||||
await runInContainer(
|
await runInContainer(
|
||||||
{
|
{
|
||||||
fs,
|
fs,
|
||||||
root,
|
inlineConfig: {
|
||||||
userConfig: {
|
root: fileURLToPath(root),
|
||||||
base: '/docs',
|
base: '/docs',
|
||||||
trailingSlash: 'never',
|
trailingSlash: 'never',
|
||||||
},
|
},
|
||||||
|
@ -48,8 +47,8 @@ describe('base configuration', () => {
|
||||||
await runInContainer(
|
await runInContainer(
|
||||||
{
|
{
|
||||||
fs,
|
fs,
|
||||||
root,
|
inlineConfig: {
|
||||||
userConfig: {
|
root: fileURLToPath(root),
|
||||||
base: '/docs',
|
base: '/docs',
|
||||||
trailingSlash: 'never',
|
trailingSlash: 'never',
|
||||||
},
|
},
|
||||||
|
@ -79,8 +78,8 @@ describe('base configuration', () => {
|
||||||
await runInContainer(
|
await runInContainer(
|
||||||
{
|
{
|
||||||
fs,
|
fs,
|
||||||
root,
|
inlineConfig: {
|
||||||
userConfig: {
|
root: fileURLToPath(root),
|
||||||
base: '/docs',
|
base: '/docs',
|
||||||
trailingSlash: 'never',
|
trailingSlash: 'never',
|
||||||
},
|
},
|
||||||
|
@ -108,8 +107,8 @@ describe('base configuration', () => {
|
||||||
await runInContainer(
|
await runInContainer(
|
||||||
{
|
{
|
||||||
fs,
|
fs,
|
||||||
root,
|
inlineConfig: {
|
||||||
userConfig: {
|
root: fileURLToPath(root),
|
||||||
base: '/docs',
|
base: '/docs',
|
||||||
trailingSlash: 'never',
|
trailingSlash: 'never',
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,18 +1,12 @@
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
import { validateConfig } from '../../../dist/core/config/config.js';
|
|
||||||
import { createSettings } from '../../../dist/core/config/index.js';
|
|
||||||
import { sync as _sync } from '../../../dist/core/sync/index.js';
|
import { sync as _sync } from '../../../dist/core/sync/index.js';
|
||||||
import { createFsWithFallback, defaultLogging } from '../test-utils.js';
|
import { createFsWithFallback } from '../test-utils.js';
|
||||||
|
|
||||||
const root = new URL('../../fixtures/content-mixed-errors/', import.meta.url);
|
const root = new URL('../../fixtures/content-mixed-errors/', import.meta.url);
|
||||||
const logging = defaultLogging;
|
|
||||||
|
|
||||||
async function sync({ fs, config = {} }) {
|
async function sync({ fs, config = {} }) {
|
||||||
const astroConfig = await validateConfig(config, fileURLToPath(root), 'prod');
|
return _sync({ ...config, root: fileURLToPath(root), logLevel: 'silent' }, { fs });
|
||||||
const settings = createSettings(astroConfig, fileURLToPath(root));
|
|
||||||
|
|
||||||
return _sync(settings, { logging, fs });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('Content Collections - mixed content errors', () => {
|
describe('Content Collections - mixed content errors', () => {
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import * as cheerio from 'cheerio';
|
import * as cheerio from 'cheerio';
|
||||||
import os from 'node:os';
|
import os from 'node:os';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
|
||||||
import mdx from '../../../../integrations/mdx/dist/index.js';
|
|
||||||
import { attachContentServerListeners } from '../../../dist/content/server-listeners.js';
|
import { attachContentServerListeners } from '../../../dist/content/server-listeners.js';
|
||||||
import { runInContainer } from '../../../dist/core/dev/index.js';
|
import { createFsWithFallback, createRequestAndResponse, runInContainer } from '../test-utils.js';
|
||||||
import { createFsWithFallback, createRequestAndResponse } from '../test-utils.js';
|
|
||||||
|
|
||||||
const root = new URL('../../fixtures/content/', import.meta.url);
|
const root = new URL('../../fixtures/content/', import.meta.url);
|
||||||
|
|
||||||
const describe = os.platform() === 'win32' ? global.describe.skip : global.describe;
|
const describe = os.platform() === 'win32' ? global.describe.skip : global.describe;
|
||||||
|
|
||||||
|
/** @type {typeof runInContainer} */
|
||||||
async function runInContainerWithContentListeners(params, callback) {
|
async function runInContainerWithContentListeners(params, callback) {
|
||||||
return await runInContainer(params, async (container) => {
|
return await runInContainer(params, async (container) => {
|
||||||
await attachContentServerListeners(container);
|
await attachContentServerListeners(container);
|
||||||
|
@ -56,9 +56,8 @@ describe('Content Collections - render()', () => {
|
||||||
await runInContainerWithContentListeners(
|
await runInContainerWithContentListeners(
|
||||||
{
|
{
|
||||||
fs,
|
fs,
|
||||||
root,
|
inlineConfig: {
|
||||||
userConfig: {
|
root: fileURLToPath(root),
|
||||||
integrations: [mdx()],
|
|
||||||
vite: { server: { middlewareMode: true } },
|
vite: { server: { middlewareMode: true } },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -129,9 +128,8 @@ description: Astro is launching this week!
|
||||||
await runInContainerWithContentListeners(
|
await runInContainerWithContentListeners(
|
||||||
{
|
{
|
||||||
fs,
|
fs,
|
||||||
root,
|
inlineConfig: {
|
||||||
userConfig: {
|
root: fileURLToPath(root),
|
||||||
integrations: [mdx()],
|
|
||||||
vite: { server: { middlewareMode: true } },
|
vite: { server: { middlewareMode: true } },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -200,9 +198,8 @@ description: Astro is launching this week!
|
||||||
await runInContainerWithContentListeners(
|
await runInContainerWithContentListeners(
|
||||||
{
|
{
|
||||||
fs,
|
fs,
|
||||||
root,
|
inlineConfig: {
|
||||||
userConfig: {
|
root: fileURLToPath(root),
|
||||||
integrations: [mdx()],
|
|
||||||
vite: { server: { middlewareMode: true } },
|
vite: { server: { middlewareMode: true } },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -270,9 +267,8 @@ description: Astro is launching this week!
|
||||||
await runInContainerWithContentListeners(
|
await runInContainerWithContentListeners(
|
||||||
{
|
{
|
||||||
fs,
|
fs,
|
||||||
root,
|
inlineConfig: {
|
||||||
userConfig: {
|
root: fileURLToPath(root),
|
||||||
integrations: [mdx()],
|
|
||||||
vite: { server: { middlewareMode: true } },
|
vite: { server: { middlewareMode: true } },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import * as cheerio from 'cheerio';
|
import * as cheerio from 'cheerio';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
import { runInContainer } from '../../../dist/core/dev/index.js';
|
import {
|
||||||
import { createFs, createRequestAndResponse, triggerFSEvent } from '../test-utils.js';
|
createFs,
|
||||||
|
createRequestAndResponse,
|
||||||
|
triggerFSEvent,
|
||||||
|
runInContainer,
|
||||||
|
} from '../test-utils.js';
|
||||||
|
|
||||||
const root = new URL('../../fixtures/alias/', import.meta.url);
|
const root = new URL('../../fixtures/alias/', import.meta.url);
|
||||||
|
|
||||||
|
@ -25,7 +29,7 @@ describe('dev container', () => {
|
||||||
root
|
root
|
||||||
);
|
);
|
||||||
|
|
||||||
await runInContainer({ fs, root }, async (container) => {
|
await runInContainer({ fs, inlineConfig: { root: fileURLToPath(root) } }, async (container) => {
|
||||||
const { req, res, text } = createRequestAndResponse({
|
const { req, res, text } = createRequestAndResponse({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: '/',
|
url: '/',
|
||||||
|
@ -60,7 +64,7 @@ describe('dev container', () => {
|
||||||
root
|
root
|
||||||
);
|
);
|
||||||
|
|
||||||
await runInContainer({ fs, root }, async (container) => {
|
await runInContainer({ fs, inlineConfig: { root: fileURLToPath(root) } }, async (container) => {
|
||||||
let r = createRequestAndResponse({
|
let r = createRequestAndResponse({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: '/',
|
url: '/',
|
||||||
|
@ -119,8 +123,8 @@ describe('dev container', () => {
|
||||||
await runInContainer(
|
await runInContainer(
|
||||||
{
|
{
|
||||||
fs,
|
fs,
|
||||||
root,
|
inlineConfig: {
|
||||||
userConfig: {
|
root: fileURLToPath(root),
|
||||||
output: 'server',
|
output: 'server',
|
||||||
integrations: [
|
integrations: [
|
||||||
{
|
{
|
||||||
|
@ -170,8 +174,8 @@ describe('dev container', () => {
|
||||||
await runInContainer(
|
await runInContainer(
|
||||||
{
|
{
|
||||||
fs,
|
fs,
|
||||||
root,
|
inlineConfig: {
|
||||||
userConfig: {
|
root: fileURLToPath(root),
|
||||||
output: 'server',
|
output: 'server',
|
||||||
integrations: [
|
integrations: [
|
||||||
{
|
{
|
||||||
|
@ -223,8 +227,8 @@ describe('dev container', () => {
|
||||||
it('items in public/ are not available from root when using a base', async () => {
|
it('items in public/ are not available from root when using a base', async () => {
|
||||||
await runInContainer(
|
await runInContainer(
|
||||||
{
|
{
|
||||||
root,
|
inlineConfig: {
|
||||||
userConfig: {
|
root: fileURLToPath(root),
|
||||||
base: '/sub/',
|
base: '/sub/',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -256,7 +260,7 @@ describe('dev container', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('items in public/ are available from root when not using a base', async () => {
|
it('items in public/ are available from root when not using a base', async () => {
|
||||||
await runInContainer({ root }, async (container) => {
|
await runInContainer({ inlineConfig: { root: fileURLToPath(root) } }, async (container) => {
|
||||||
// Try the root path
|
// Try the root path
|
||||||
let r = createRequestAndResponse({
|
let r = createRequestAndResponse({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import * as cheerio from 'cheerio';
|
import * as cheerio from 'cheerio';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
import { runInContainer } from '../../../dist/core/dev/index.js';
|
import { createFs, createRequestAndResponse, runInContainer } from '../test-utils.js';
|
||||||
import { createFs, createRequestAndResponse } from '../test-utils.js';
|
|
||||||
|
|
||||||
const root = new URL('../../fixtures/alias/', import.meta.url);
|
const root = new URL('../../fixtures/alias/', import.meta.url);
|
||||||
|
|
||||||
|
@ -65,8 +64,8 @@ describe('head injection', () => {
|
||||||
await runInContainer(
|
await runInContainer(
|
||||||
{
|
{
|
||||||
fs,
|
fs,
|
||||||
root,
|
inlineConfig: {
|
||||||
userConfig: {
|
root: fileURLToPath(root),
|
||||||
vite: { server: { middlewareMode: true } },
|
vite: { server: { middlewareMode: true } },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -154,8 +153,8 @@ describe('head injection', () => {
|
||||||
await runInContainer(
|
await runInContainer(
|
||||||
{
|
{
|
||||||
fs,
|
fs,
|
||||||
root,
|
inlineConfig: {
|
||||||
userConfig: {
|
root: fileURLToPath(root),
|
||||||
vite: { server: { middlewareMode: true } },
|
vite: { server: { middlewareMode: true } },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
import { runInContainer } from '../../../dist/core/dev/index.js';
|
import { createFs, createRequestAndResponse, runInContainer } from '../test-utils.js';
|
||||||
import { createFs, createRequestAndResponse, silentLogging } from '../test-utils.js';
|
|
||||||
import svelte from '../../../../integrations/svelte/dist/index.js';
|
|
||||||
|
|
||||||
const root = new URL('../../fixtures/alias/', import.meta.url);
|
const root = new URL('../../fixtures/alias/', import.meta.url);
|
||||||
|
|
||||||
describe('dev container', () => {
|
describe('hydration', () => {
|
||||||
it('should not crash when reassigning a hydrated component', async () => {
|
it('should not crash when reassigning a hydrated component', async () => {
|
||||||
const fs = createFs(
|
const fs = createFs(
|
||||||
{
|
{
|
||||||
|
@ -31,10 +29,9 @@ describe('dev container', () => {
|
||||||
await runInContainer(
|
await runInContainer(
|
||||||
{
|
{
|
||||||
fs,
|
fs,
|
||||||
root,
|
inlineConfig: {
|
||||||
logging: silentLogging,
|
root: fileURLToPath(root),
|
||||||
userConfig: {
|
logLevel: 'silent',
|
||||||
integrations: [svelte()],
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
async (container) => {
|
async (container) => {
|
||||||
|
|
|
@ -2,18 +2,12 @@ import { expect } from 'chai';
|
||||||
import * as cheerio from 'cheerio';
|
import * as cheerio from 'cheerio';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
|
|
||||||
import { createSettings, openConfig } from '../../../dist/core/config/index.js';
|
|
||||||
import {
|
import {
|
||||||
createContainerWithAutomaticRestart,
|
createContainerWithAutomaticRestart,
|
||||||
isStarted,
|
isStarted,
|
||||||
startContainer,
|
startContainer,
|
||||||
} from '../../../dist/core/dev/index.js';
|
} from '../../../dist/core/dev/index.js';
|
||||||
import {
|
import { createFs, createRequestAndResponse, triggerFSEvent } from '../test-utils.js';
|
||||||
createFs,
|
|
||||||
createRequestAndResponse,
|
|
||||||
defaultLogging,
|
|
||||||
triggerFSEvent,
|
|
||||||
} from '../test-utils.js';
|
|
||||||
|
|
||||||
const root = new URL('../../fixtures/alias/', import.meta.url);
|
const root = new URL('../../fixtures/alias/', import.meta.url);
|
||||||
|
|
||||||
|
@ -36,8 +30,9 @@ describe('dev container restarts', () => {
|
||||||
root
|
root
|
||||||
);
|
);
|
||||||
|
|
||||||
let restart = await createContainerWithAutomaticRestart({
|
const restart = await createContainerWithAutomaticRestart({
|
||||||
params: { fs, root },
|
fs,
|
||||||
|
inlineConfig: { root: fileURLToPath(root), logLevel: 'silent' },
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -99,8 +94,9 @@ describe('dev container restarts', () => {
|
||||||
root
|
root
|
||||||
);
|
);
|
||||||
|
|
||||||
let restart = await createContainerWithAutomaticRestart({
|
const restart = await createContainerWithAutomaticRestart({
|
||||||
params: { fs, root },
|
fs,
|
||||||
|
inlineConfig: { root: fileURLToPath(root), logLevel: 'silent' },
|
||||||
});
|
});
|
||||||
await startContainer(restart.container);
|
await startContainer(restart.container);
|
||||||
expect(isStarted(restart.container)).to.equal(true);
|
expect(isStarted(restart.container)).to.equal(true);
|
||||||
|
@ -127,16 +123,9 @@ describe('dev container restarts', () => {
|
||||||
troot
|
troot
|
||||||
);
|
);
|
||||||
|
|
||||||
const { astroConfig } = await openConfig({
|
const restart = await createContainerWithAutomaticRestart({
|
||||||
cwd: troot,
|
fs,
|
||||||
flags: {},
|
inlineConfig: { root: fileURLToPath(root), logLevel: 'silent' },
|
||||||
cmd: 'dev',
|
|
||||||
logging: defaultLogging,
|
|
||||||
});
|
|
||||||
const settings = createSettings(astroConfig);
|
|
||||||
|
|
||||||
let restart = await createContainerWithAutomaticRestart({
|
|
||||||
params: { fs, root, settings },
|
|
||||||
});
|
});
|
||||||
await startContainer(restart.container);
|
await startContainer(restart.container);
|
||||||
expect(isStarted(restart.container)).to.equal(true);
|
expect(isStarted(restart.container)).to.equal(true);
|
||||||
|
@ -161,16 +150,9 @@ describe('dev container restarts', () => {
|
||||||
root
|
root
|
||||||
);
|
);
|
||||||
|
|
||||||
const { astroConfig } = await openConfig({
|
const restart = await createContainerWithAutomaticRestart({
|
||||||
cwd: root,
|
fs,
|
||||||
flags: {},
|
inlineConfig: { root: fileURLToPath(root), logLevel: 'silent' },
|
||||||
cmd: 'dev',
|
|
||||||
logging: defaultLogging,
|
|
||||||
});
|
|
||||||
const settings = createSettings(astroConfig, fileURLToPath(root));
|
|
||||||
|
|
||||||
let restart = await createContainerWithAutomaticRestart({
|
|
||||||
params: { fs, root, settings },
|
|
||||||
});
|
});
|
||||||
await startContainer(restart.container);
|
await startContainer(restart.container);
|
||||||
expect(isStarted(restart.container)).to.equal(true);
|
expect(isStarted(restart.container)).to.equal(true);
|
||||||
|
@ -193,16 +175,9 @@ describe('dev container restarts', () => {
|
||||||
root
|
root
|
||||||
);
|
);
|
||||||
|
|
||||||
const { astroConfig } = await openConfig({
|
const restart = await createContainerWithAutomaticRestart({
|
||||||
cwd: root,
|
fs,
|
||||||
flags: {},
|
inlineConfig: { root: fileURLToPath(root), logLevel: 'silent' },
|
||||||
cmd: 'dev',
|
|
||||||
logging: defaultLogging,
|
|
||||||
});
|
|
||||||
const settings = createSettings(astroConfig, fileURLToPath(root));
|
|
||||||
|
|
||||||
let restart = await createContainerWithAutomaticRestart({
|
|
||||||
params: { fs, root, settings },
|
|
||||||
});
|
});
|
||||||
await startContainer(restart.container);
|
await startContainer(restart.container);
|
||||||
expect(isStarted(restart.container)).to.equal(true);
|
expect(isStarted(restart.container)).to.equal(true);
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import * as cheerio from 'cheerio';
|
import * as cheerio from 'cheerio';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
import { runInContainer } from '../../../dist/core/dev/index.js';
|
|
||||||
import { createFs, createRequestAndResponse, silentLogging } from '../test-utils.js';
|
|
||||||
import svelte from '../../../../integrations/svelte/dist/index.js';
|
import svelte from '../../../../integrations/svelte/dist/index.js';
|
||||||
|
import { createFs, createRequestAndResponse, runInContainer } from '../test-utils.js';
|
||||||
|
|
||||||
const root = new URL('../../fixtures/alias/', import.meta.url);
|
const root = new URL('../../fixtures/alias/', import.meta.url);
|
||||||
|
|
||||||
|
@ -31,9 +30,9 @@ describe('core/render components', () => {
|
||||||
await runInContainer(
|
await runInContainer(
|
||||||
{
|
{
|
||||||
fs,
|
fs,
|
||||||
root,
|
inlineConfig: {
|
||||||
logging: silentLogging,
|
root: fileURLToPath(root),
|
||||||
userConfig: {
|
logLevel: 'silent',
|
||||||
integrations: [svelte()],
|
integrations: [svelte()],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
|
|
||||||
import { createFs } from '../test-utils.js';
|
|
||||||
import { createRouteManifest } from '../../../dist/core/routing/manifest/create.js';
|
|
||||||
import { createDefaultDevSettings } from '../../../dist/core/config/index.js';
|
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
import { defaultLogging } from '../test-utils.js';
|
import { createRouteManifest } from '../../../dist/core/routing/manifest/create.js';
|
||||||
|
import { createBasicSettings, createFs, defaultLogging } from '../test-utils.js';
|
||||||
|
|
||||||
const root = new URL('../../fixtures/alias/', import.meta.url);
|
const root = new URL('../../fixtures/alias/', import.meta.url);
|
||||||
|
|
||||||
|
@ -16,13 +14,11 @@ describe('routing - createRouteManifest', () => {
|
||||||
},
|
},
|
||||||
root
|
root
|
||||||
);
|
);
|
||||||
const settings = await createDefaultDevSettings(
|
const settings = await createBasicSettings({
|
||||||
{
|
root: fileURLToPath(root),
|
||||||
base: '/search',
|
base: '/search',
|
||||||
trailingSlash: 'never',
|
trailingSlash: 'never',
|
||||||
},
|
});
|
||||||
root
|
|
||||||
);
|
|
||||||
const manifest = createRouteManifest({
|
const manifest = createRouteManifest({
|
||||||
cwd: fileURLToPath(root),
|
cwd: fileURLToPath(root),
|
||||||
settings,
|
settings,
|
||||||
|
@ -41,17 +37,15 @@ describe('routing - createRouteManifest', () => {
|
||||||
},
|
},
|
||||||
root
|
root
|
||||||
);
|
);
|
||||||
const settings = await createDefaultDevSettings(
|
const settings = await createBasicSettings({
|
||||||
{
|
root: fileURLToPath(root),
|
||||||
base: '/search',
|
base: '/search',
|
||||||
trailingSlash: 'never',
|
trailingSlash: 'never',
|
||||||
redirects: {
|
redirects: {
|
||||||
'/blog/[...slug]': '/',
|
'/blog/[...slug]': '/',
|
||||||
'/blog/contributing': '/another',
|
'/blog/contributing': '/another',
|
||||||
},
|
|
||||||
},
|
},
|
||||||
root
|
});
|
||||||
);
|
|
||||||
const manifest = createRouteManifest({
|
const manifest = createRouteManifest({
|
||||||
cwd: fileURLToPath(root),
|
cwd: fileURLToPath(root),
|
||||||
settings,
|
settings,
|
||||||
|
@ -70,15 +64,13 @@ describe('routing - createRouteManifest', () => {
|
||||||
},
|
},
|
||||||
root
|
root
|
||||||
);
|
);
|
||||||
const settings = await createDefaultDevSettings(
|
const settings = await createBasicSettings({
|
||||||
{
|
root: fileURLToPath(root),
|
||||||
trailingSlash: 'never',
|
trailingSlash: 'never',
|
||||||
redirects: {
|
redirects: {
|
||||||
'/foo': '/bar',
|
'/foo': '/bar',
|
||||||
},
|
|
||||||
},
|
},
|
||||||
root
|
});
|
||||||
);
|
|
||||||
const manifest = createRouteManifest(
|
const manifest = createRouteManifest(
|
||||||
{
|
{
|
||||||
cwd: fileURLToPath(root),
|
cwd: fileURLToPath(root),
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
// @ts-check
|
import {
|
||||||
import { createFs, createRequestAndResponse, defaultLogging } from '../test-utils.js';
|
createBasicSettings,
|
||||||
|
createFs,
|
||||||
|
createRequestAndResponse,
|
||||||
|
defaultLogging,
|
||||||
|
} from '../test-utils.js';
|
||||||
import { createRouteManifest, matchAllRoutes } from '../../../dist/core/routing/index.js';
|
import { createRouteManifest, matchAllRoutes } from '../../../dist/core/routing/index.js';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
import { createViteLoader } from '../../../dist/core/module-loader/vite.js';
|
import { createViteLoader } from '../../../dist/core/module-loader/vite.js';
|
||||||
|
@ -127,16 +131,17 @@ describe('Route matching', () => {
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
const fs = createFs(fileSystem, root);
|
const fs = createFs(fileSystem, root);
|
||||||
|
settings = await createBasicSettings({
|
||||||
|
root: fileURLToPath(root),
|
||||||
|
trailingSlash: 'never',
|
||||||
|
output: 'hybrid',
|
||||||
|
adapter: testAdapter(),
|
||||||
|
});
|
||||||
container = await createContainer({
|
container = await createContainer({
|
||||||
fs,
|
fs,
|
||||||
root,
|
settings,
|
||||||
userConfig: {
|
logging: defaultLogging,
|
||||||
trailingSlash: 'never',
|
|
||||||
output: 'hybrid',
|
|
||||||
adapter: testAdapter(),
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
settings = container.settings;
|
|
||||||
|
|
||||||
const loader = createViteLoader(container.viteServer);
|
const loader = createViteLoader(container.viteServer);
|
||||||
const manifest = createDevelopmentManifest(container.settings);
|
const manifest = createDevelopmentManifest(container.settings);
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
import { createContainer } from '../../../dist/core/dev/index.js';
|
import { createContainer } from '../../../dist/core/dev/index.js';
|
||||||
import { createViteLoader } from '../../../dist/core/module-loader/index.js';
|
import { createViteLoader } from '../../../dist/core/module-loader/index.js';
|
||||||
|
import { createBasicSettings, defaultLogging } from '../test-utils.js';
|
||||||
|
|
||||||
const root = new URL('../../fixtures/alias/', import.meta.url);
|
const root = new URL('../../fixtures/alias/', import.meta.url);
|
||||||
|
|
||||||
|
@ -9,7 +11,8 @@ describe('<Code />', () => {
|
||||||
let container;
|
let container;
|
||||||
let mod;
|
let mod;
|
||||||
before(async () => {
|
before(async () => {
|
||||||
container = await createContainer({ root });
|
const settings = await createBasicSettings({ root: fileURLToPath(root) });
|
||||||
|
container = await createContainer({ settings, logging: defaultLogging });
|
||||||
const loader = createViteLoader(container.viteServer);
|
const loader = createViteLoader(container.viteServer);
|
||||||
mod = await loader.import('astro/components/Shiki.js');
|
mod = await loader.import('astro/components/Shiki.js');
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,6 +8,9 @@ import { getDefaultClientDirectives } from '../../dist/core/client-directive/ind
|
||||||
import { nodeLogDestination } from '../../dist/core/logger/node.js';
|
import { nodeLogDestination } from '../../dist/core/logger/node.js';
|
||||||
import { createEnvironment } from '../../dist/core/render/index.js';
|
import { createEnvironment } from '../../dist/core/render/index.js';
|
||||||
import { RouteCache } from '../../dist/core/render/route-cache.js';
|
import { RouteCache } from '../../dist/core/render/route-cache.js';
|
||||||
|
import { resolveConfig } from '../../dist/core/config/index.js';
|
||||||
|
import { createBaseSettings } from '../../dist/core/config/settings.js';
|
||||||
|
import { createContainer } from '../../dist/core/dev/container.js';
|
||||||
import { unixify } from './correct-path.js';
|
import { unixify } from './correct-path.js';
|
||||||
|
|
||||||
/** @type {import('../../src/core/logger/core').LogOptions} */
|
/** @type {import('../../src/core/logger/core').LogOptions} */
|
||||||
|
@ -189,3 +192,42 @@ export function createBasicEnvironment(options = {}) {
|
||||||
streaming: options.streaming ?? true,
|
streaming: options.streaming ?? true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {import('../../src/@types/astro.js').AstroInlineConfig} inlineConfig
|
||||||
|
* @returns {Promise<import('../../src/@types/astro.js').AstroSettings>}
|
||||||
|
*/
|
||||||
|
export async function createBasicSettings(inlineConfig = {}) {
|
||||||
|
if (!inlineConfig.root) {
|
||||||
|
inlineConfig.root = fileURLToPath(new URL('.', import.meta.url));
|
||||||
|
}
|
||||||
|
const { astroConfig } = await resolveConfig(inlineConfig, 'dev');
|
||||||
|
return createBaseSettings(astroConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {{
|
||||||
|
* fs?: typeof realFS,
|
||||||
|
* inlineConfig?: import('../../src/@types/astro.js').AstroInlineConfig,
|
||||||
|
* logging?: import('../../src/core/logger/core').LogOptions,
|
||||||
|
* }} RunInContainerOptions
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {RunInContainerOptions} options
|
||||||
|
* @param {(container: import('../../src/core/dev/container.js').Container) => Promise<void> | void} callback
|
||||||
|
*/
|
||||||
|
export async function runInContainer(options = {}, callback) {
|
||||||
|
const settings = await createBasicSettings(options.inlineConfig ?? {});
|
||||||
|
const container = await createContainer({
|
||||||
|
fs: options?.fs ?? realFS,
|
||||||
|
settings,
|
||||||
|
inlineConfig: options.inlineConfig ?? {},
|
||||||
|
logging: defaultLogging,
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
await callback(container);
|
||||||
|
} finally {
|
||||||
|
await container.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
|
|
||||||
import { createDefaultDevSettings } from '../../../dist/core/config/index.js';
|
|
||||||
import { createLoader } from '../../../dist/core/module-loader/index.js';
|
import { createLoader } from '../../../dist/core/module-loader/index.js';
|
||||||
import { createRouteManifest } from '../../../dist/core/routing/index.js';
|
import { createRouteManifest } from '../../../dist/core/routing/index.js';
|
||||||
import { createComponent, render } from '../../../dist/runtime/server/index.js';
|
import { createComponent, render } from '../../../dist/runtime/server/index.js';
|
||||||
|
@ -8,6 +7,7 @@ import { createController, handleRequest } from '../../../dist/vite-plugin-astro
|
||||||
import {
|
import {
|
||||||
createAstroModule,
|
createAstroModule,
|
||||||
createBasicEnvironment,
|
createBasicEnvironment,
|
||||||
|
createBasicSettings,
|
||||||
createFs,
|
createFs,
|
||||||
createRequestAndResponse,
|
createRequestAndResponse,
|
||||||
defaultLogging,
|
defaultLogging,
|
||||||
|
@ -15,7 +15,7 @@ import {
|
||||||
|
|
||||||
async function createDevEnvironment(overrides = {}) {
|
async function createDevEnvironment(overrides = {}) {
|
||||||
const env = createBasicEnvironment();
|
const env = createBasicEnvironment();
|
||||||
env.settings = await createDefaultDevSettings({}, '/');
|
env.settings = await createBasicSettings({ root: '/' });
|
||||||
env.settings.renderers = [];
|
env.settings.renderers = [];
|
||||||
env.loader = createLoader();
|
env.loader = createLoader();
|
||||||
Object.assign(env, overrides);
|
Object.assign(env, overrides);
|
||||||
|
|
|
@ -23,7 +23,7 @@ describe('getStaticPaths', () => {
|
||||||
const $ = cheerio.load(html);
|
const $ = cheerio.load(html);
|
||||||
expect($('p').text()).to.equal('First mdx file');
|
expect($('p').text()).to.equal('First mdx file');
|
||||||
expect($('#one').text()).to.equal('hello', 'Frontmatter included');
|
expect($('#one').text()).to.equal('hello', 'Frontmatter included');
|
||||||
expect($('#url').text()).to.equal('/src/content/1.mdx', 'url is included');
|
expect($('#url').text()).to.equal('src/content/1.mdx', 'url is included');
|
||||||
expect($('#file').text()).to.contain(
|
expect($('#file').text()).to.contain(
|
||||||
'fixtures/mdx-get-static-paths/src/content/1.mdx',
|
'fixtures/mdx-get-static-paths/src/content/1.mdx',
|
||||||
'file is included'
|
'file is included'
|
||||||
|
|
|
@ -96,7 +96,7 @@ describe('MDX plugins', () => {
|
||||||
it('ignores string-based plugins in markdown config', async () => {
|
it('ignores string-based plugins in markdown config', async () => {
|
||||||
const fixture = await buildFixture({
|
const fixture = await buildFixture({
|
||||||
markdown: {
|
markdown: {
|
||||||
remarkPlugins: [['remark-toc']],
|
remarkPlugins: [['remark-toc', {}]],
|
||||||
},
|
},
|
||||||
integrations: [mdx()],
|
integrations: [mdx()],
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue