clean up config loading and flag merging (#2469)
This commit is contained in:
parent
831a9adc20
commit
c70c4ea211
3 changed files with 79 additions and 71 deletions
|
@ -19,6 +19,18 @@ export interface AstroComponentMetadata {
|
||||||
componentExport?: { value: string; namespace?: boolean };
|
componentExport?: { value: string; namespace?: boolean };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** The flags supported by the Astro CLI */
|
||||||
|
export interface CLIFlags {
|
||||||
|
projectRoot?: string;
|
||||||
|
site?: string;
|
||||||
|
sitemap?: boolean;
|
||||||
|
hostname?: string;
|
||||||
|
port?: number;
|
||||||
|
config?: string;
|
||||||
|
experimentalStaticBuild?: boolean;
|
||||||
|
drafts?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Astro.* available in all components
|
* Astro.* available in all components
|
||||||
* Docs: https://docs.astro.build/reference/api-reference/#astro-global
|
* Docs: https://docs.astro.build/reference/api-reference/#astro-global
|
||||||
|
@ -115,6 +127,11 @@ export interface AstroUserConfig {
|
||||||
* Default: false
|
* Default: false
|
||||||
*/
|
*/
|
||||||
drafts?: boolean;
|
drafts?: boolean;
|
||||||
|
/**
|
||||||
|
* Experimental: Enables "static build mode" for faster builds.
|
||||||
|
* Default: false
|
||||||
|
*/
|
||||||
|
experimentalStaticBuild?: boolean;
|
||||||
};
|
};
|
||||||
/** Options for the development server run with `astro dev`. */
|
/** Options for the development server run with `astro dev`. */
|
||||||
devOptions?: {
|
devOptions?: {
|
||||||
|
|
|
@ -15,54 +15,7 @@ import { check } from './check.js';
|
||||||
import { formatConfigError, loadConfig } from '../core/config.js';
|
import { formatConfigError, loadConfig } from '../core/config.js';
|
||||||
|
|
||||||
type Arguments = yargs.Arguments;
|
type Arguments = yargs.Arguments;
|
||||||
type cliCommand = 'help' | 'version' | 'dev' | 'build' | 'preview' | 'reload' | 'check';
|
type CLICommand = 'help' | 'version' | 'dev' | 'build' | 'preview' | 'reload' | 'check';
|
||||||
interface CLIState {
|
|
||||||
cmd: cliCommand;
|
|
||||||
options: {
|
|
||||||
projectRoot?: string;
|
|
||||||
site?: string;
|
|
||||||
sitemap?: boolean;
|
|
||||||
hostname?: string;
|
|
||||||
port?: number;
|
|
||||||
config?: string;
|
|
||||||
experimentalStaticBuild?: boolean;
|
|
||||||
drafts?: boolean;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Determine which action the user requested */
|
|
||||||
function resolveArgs(flags: Arguments): CLIState {
|
|
||||||
const options: CLIState['options'] = {
|
|
||||||
projectRoot: typeof flags.projectRoot === 'string' ? flags.projectRoot : undefined,
|
|
||||||
site: typeof flags.site === 'string' ? flags.site : undefined,
|
|
||||||
sitemap: typeof flags.sitemap === 'boolean' ? flags.sitemap : undefined,
|
|
||||||
port: typeof flags.port === 'number' ? flags.port : undefined,
|
|
||||||
config: typeof flags.config === 'string' ? flags.config : undefined,
|
|
||||||
hostname: typeof flags.hostname === 'string' ? flags.hostname : undefined,
|
|
||||||
experimentalStaticBuild: typeof flags.experimentalStaticBuild === 'boolean' ? flags.experimentalStaticBuild : false,
|
|
||||||
drafts: typeof flags.drafts === 'boolean' ? flags.drafts : false,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (flags.version) {
|
|
||||||
return { cmd: 'version', options };
|
|
||||||
} else if (flags.help) {
|
|
||||||
return { cmd: 'help', options };
|
|
||||||
}
|
|
||||||
|
|
||||||
const cmd = flags._[2];
|
|
||||||
switch (cmd) {
|
|
||||||
case 'dev':
|
|
||||||
return { cmd: 'dev', options };
|
|
||||||
case 'build':
|
|
||||||
return { cmd: 'build', options };
|
|
||||||
case 'preview':
|
|
||||||
return { cmd: 'preview', options };
|
|
||||||
case 'check':
|
|
||||||
return { cmd: 'check', options };
|
|
||||||
default:
|
|
||||||
return { cmd: 'help', options };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Display --help flag */
|
/** Display --help flag */
|
||||||
function printHelp() {
|
function printHelp() {
|
||||||
|
@ -95,24 +48,28 @@ async function printVersion() {
|
||||||
console.log(pkgVersion);
|
console.log(pkgVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Merge CLI flags & config options (CLI flags take priority) */
|
/** Determine which command the user requested */
|
||||||
function mergeCLIFlags(astroConfig: AstroConfig, flags: CLIState['options']) {
|
function resolveCommand(flags: Arguments): CLICommand {
|
||||||
if (typeof flags.sitemap === 'boolean') astroConfig.buildOptions.sitemap = flags.sitemap;
|
if (flags.version) {
|
||||||
if (typeof flags.site === 'string') astroConfig.buildOptions.site = flags.site;
|
return 'version';
|
||||||
if (typeof flags.port === 'number') astroConfig.devOptions.port = flags.port;
|
} else if (flags.help) {
|
||||||
if (typeof flags.hostname === 'string') astroConfig.devOptions.hostname = flags.hostname;
|
return 'help';
|
||||||
if (typeof flags.experimentalStaticBuild === 'boolean') astroConfig.buildOptions.experimentalStaticBuild = flags.experimentalStaticBuild;
|
}
|
||||||
if (typeof flags.drafts === 'boolean') astroConfig.buildOptions.drafts = flags.drafts;
|
const cmd = flags._[2];
|
||||||
|
const supportedCommands = new Set(['dev', 'build', 'preview', 'check']);
|
||||||
|
if (supportedCommands.has(cmd)) {
|
||||||
|
return cmd as 'dev' | 'build' | 'preview' | 'check';
|
||||||
|
}
|
||||||
|
return 'help';
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The primary CLI action */
|
/** The primary CLI action */
|
||||||
export async function cli(args: string[]) {
|
export async function cli(args: string[]) {
|
||||||
const flags = yargs(args);
|
const flags = yargs(args);
|
||||||
const state = resolveArgs(flags);
|
const cmd = resolveCommand(flags);
|
||||||
const options = { ...state.options };
|
const projectRoot = flags.projectRoot || flags._[3];
|
||||||
const projectRoot = options.projectRoot || flags._[3];
|
|
||||||
|
|
||||||
switch (state.cmd) {
|
switch (cmd) {
|
||||||
case 'help':
|
case 'help':
|
||||||
printHelp();
|
printHelp();
|
||||||
return process.exit(0);
|
return process.exit(0);
|
||||||
|
@ -131,8 +88,7 @@ export async function cli(args: string[]) {
|
||||||
if (flags.silent) logging.level = 'silent';
|
if (flags.silent) logging.level = 'silent';
|
||||||
let config: AstroConfig;
|
let config: AstroConfig;
|
||||||
try {
|
try {
|
||||||
config = await loadConfig({ cwd: projectRoot, filename: options.config });
|
config = await loadConfig({ cwd: projectRoot, flags });
|
||||||
mergeCLIFlags(config, options);
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err instanceof z.ZodError) {
|
if (err instanceof z.ZodError) {
|
||||||
console.error(formatConfigError(err));
|
console.error(formatConfigError(err));
|
||||||
|
@ -142,7 +98,7 @@ export async function cli(args: string[]) {
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (state.cmd) {
|
switch (cmd) {
|
||||||
case 'dev': {
|
case 'dev': {
|
||||||
try {
|
try {
|
||||||
await devServer(config, { logging });
|
await devServer(config, { logging });
|
||||||
|
@ -154,6 +110,7 @@ export async function cli(args: string[]) {
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'build': {
|
case 'build': {
|
||||||
try {
|
try {
|
||||||
await build(config, { logging });
|
await build(config, { logging });
|
||||||
|
@ -163,10 +120,12 @@ export async function cli(args: string[]) {
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'check': {
|
case 'check': {
|
||||||
const ret = await check(config);
|
const ret = await check(config);
|
||||||
return process.exit(ret);
|
return process.exit(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'preview': {
|
case 'preview': {
|
||||||
try {
|
try {
|
||||||
await preview(config, { logging }); // this will keep running
|
await preview(config, { logging }); // this will keep running
|
||||||
|
@ -175,8 +134,9 @@ export async function cli(args: string[]) {
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
throw new Error(`Error running ${state.cmd}`);
|
throw new Error(`Error running ${cmd}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import type { AstroConfig, AstroUserConfig } from '../@types/astro';
|
import type { AstroConfig, AstroUserConfig, CLIFlags } from '../@types/astro';
|
||||||
|
import type { Arguments as Flags } from 'yargs-parser';
|
||||||
|
|
||||||
import * as colors from 'kleur/colors';
|
import * as colors from 'kleur/colors';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
@ -116,19 +117,47 @@ function addTrailingSlash(str: string): string {
|
||||||
return str.replace(/\/*$/, '/');
|
return str.replace(/\/*$/, '/');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Convert the generic "yargs" flag object into our own, custom TypeScript object. */
|
||||||
|
function resolveFlags(flags: Partial<Flags>): CLIFlags {
|
||||||
|
return {
|
||||||
|
projectRoot: typeof flags.projectRoot === 'string' ? flags.projectRoot : undefined,
|
||||||
|
site: typeof flags.site === 'string' ? flags.site : undefined,
|
||||||
|
sitemap: typeof flags.sitemap === 'boolean' ? flags.sitemap : undefined,
|
||||||
|
port: typeof flags.port === 'number' ? flags.port : undefined,
|
||||||
|
config: typeof flags.config === 'string' ? flags.config : undefined,
|
||||||
|
hostname: typeof flags.hostname === 'string' ? flags.hostname : undefined,
|
||||||
|
experimentalStaticBuild: typeof flags.experimentalStaticBuild === 'boolean' ? flags.experimentalStaticBuild : false,
|
||||||
|
drafts: typeof flags.drafts === 'boolean' ? flags.drafts : false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Merge CLI flags & user config object (CLI flags take priority) */
|
||||||
|
function mergeCLIFlags(astroConfig: AstroUserConfig, flags: CLIFlags) {
|
||||||
|
astroConfig.buildOptions = astroConfig.buildOptions || {};
|
||||||
|
astroConfig.devOptions = astroConfig.devOptions || {};
|
||||||
|
if (typeof flags.sitemap === 'boolean') astroConfig.buildOptions.sitemap = flags.sitemap;
|
||||||
|
if (typeof flags.site === 'string') astroConfig.buildOptions.site = flags.site;
|
||||||
|
if (typeof flags.port === 'number') astroConfig.devOptions.port = flags.port;
|
||||||
|
if (typeof flags.hostname === 'string') astroConfig.devOptions.hostname = flags.hostname;
|
||||||
|
if (typeof flags.experimentalStaticBuild === 'boolean') astroConfig.buildOptions.experimentalStaticBuild = flags.experimentalStaticBuild;
|
||||||
|
if (typeof flags.drafts === 'boolean') astroConfig.buildOptions.drafts = flags.drafts;
|
||||||
|
return astroConfig;
|
||||||
|
}
|
||||||
|
|
||||||
interface LoadConfigOptions {
|
interface LoadConfigOptions {
|
||||||
cwd?: string;
|
cwd?: string;
|
||||||
filename?: string;
|
flags?: Flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Attempt to load an `astro.config.mjs` file */
|
/** Attempt to load an `astro.config.mjs` file */
|
||||||
export async function loadConfig(options: LoadConfigOptions): Promise<AstroConfig> {
|
export async function loadConfig(configOptions: LoadConfigOptions): Promise<AstroConfig> {
|
||||||
const root = options.cwd ? path.resolve(options.cwd) : process.cwd();
|
const root = configOptions.cwd ? path.resolve(configOptions.cwd) : process.cwd();
|
||||||
|
const flags = resolveFlags(configOptions.flags || {});
|
||||||
let userConfig: AstroUserConfig = {};
|
let userConfig: AstroUserConfig = {};
|
||||||
let userConfigPath: string | undefined;
|
let userConfigPath: string | undefined;
|
||||||
|
|
||||||
if (options.filename) {
|
if (flags?.config) {
|
||||||
userConfigPath = /^\.*\//.test(options.filename) ? options.filename : `./${options.filename}`;
|
userConfigPath = /^\.*\//.test(flags.config) ? flags.config : `./${flags.config}`;
|
||||||
userConfigPath = fileURLToPath(new URL(userConfigPath, `file://${root}/`));
|
userConfigPath = fileURLToPath(new URL(userConfigPath, `file://${root}/`));
|
||||||
}
|
}
|
||||||
// Automatically load config file using Proload
|
// Automatically load config file using Proload
|
||||||
|
@ -138,7 +167,9 @@ export async function loadConfig(options: LoadConfigOptions): Promise<AstroConfi
|
||||||
userConfig = config.value;
|
userConfig = config.value;
|
||||||
}
|
}
|
||||||
// normalize, validate, and return
|
// normalize, validate, and return
|
||||||
return validateConfig(userConfig, root);
|
const mergedConfig = mergeCLIFlags(userConfig, flags);
|
||||||
|
const validatedConfig = await validateConfig(mergedConfig, root);
|
||||||
|
return validatedConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatConfigError(err: z.ZodError) {
|
export function formatConfigError(err: z.ZodError) {
|
||||||
|
|
Loading…
Reference in a new issue