mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-14 09:37:37 +02:00
feat(core): support docusaurus.config.cjs as default file name (#7371)
This commit is contained in:
parent
35e63515e6
commit
be912c698a
8 changed files with 97 additions and 23 deletions
|
@ -30,8 +30,11 @@ export const DEFAULT_BUILD_DIR_NAME = 'build';
|
||||||
/**
|
/**
|
||||||
* Can be overridden with cli option `--config`. Code should generally use
|
* Can be overridden with cli option `--config`. Code should generally use
|
||||||
* `context.siteConfigPath` instead (which is always absolute).
|
* `context.siteConfigPath` instead (which is always absolute).
|
||||||
|
*
|
||||||
|
* This does not have extensions, so that we can substitute different ones
|
||||||
|
* when resolving the path.
|
||||||
*/
|
*/
|
||||||
export const DEFAULT_CONFIG_FILE_NAME = 'docusaurus.config.js';
|
export const DEFAULT_CONFIG_FILE_NAME = 'docusaurus.config';
|
||||||
|
|
||||||
/** Can be absolute or relative to site directory. */
|
/** Can be absolute or relative to site directory. */
|
||||||
export const BABEL_CONFIG_FILE_NAME =
|
export const BABEL_CONFIG_FILE_NAME =
|
||||||
|
|
5
packages/docusaurus/src/server/__tests__/__fixtures__/config/docusaurus.config.cjs
generated
Normal file
5
packages/docusaurus/src/server/__tests__/__fixtures__/config/docusaurus.config.cjs
generated
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
module.exports = {
|
||||||
|
title: 'title',
|
||||||
|
url: 'https://example.com',
|
||||||
|
baseUrl: '/'
|
||||||
|
};
|
|
@ -1,5 +1,41 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`loadSiteConfig website with .cjs siteConfig 1`] = `
|
||||||
|
{
|
||||||
|
"siteConfig": {
|
||||||
|
"baseUrl": "/",
|
||||||
|
"baseUrlIssueBanner": true,
|
||||||
|
"clientModules": [],
|
||||||
|
"customFields": {},
|
||||||
|
"i18n": {
|
||||||
|
"defaultLocale": "en",
|
||||||
|
"localeConfigs": {},
|
||||||
|
"locales": [
|
||||||
|
"en",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"noIndex": false,
|
||||||
|
"onBrokenLinks": "throw",
|
||||||
|
"onBrokenMarkdownLinks": "warn",
|
||||||
|
"onDuplicateRoutes": "warn",
|
||||||
|
"plugins": [],
|
||||||
|
"presets": [],
|
||||||
|
"scripts": [],
|
||||||
|
"staticDirectories": [
|
||||||
|
"static",
|
||||||
|
],
|
||||||
|
"stylesheets": [],
|
||||||
|
"tagline": "",
|
||||||
|
"themeConfig": {},
|
||||||
|
"themes": [],
|
||||||
|
"title": "title",
|
||||||
|
"titleDelimiter": "|",
|
||||||
|
"url": "https://example.com",
|
||||||
|
},
|
||||||
|
"siteConfigPath": "<PROJECT_ROOT>/packages/docusaurus/src/server/__tests__/__fixtures__/config/docusaurus.config.cjs",
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`loadSiteConfig website with valid async config 1`] = `
|
exports[`loadSiteConfig website with valid async config 1`] = `
|
||||||
{
|
{
|
||||||
"siteConfig": {
|
"siteConfig": {
|
||||||
|
|
|
@ -19,6 +19,12 @@ describe('loadSiteConfig', () => {
|
||||||
expect(config).not.toEqual({});
|
expect(config).not.toEqual({});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('website with .cjs siteConfig', async () => {
|
||||||
|
const config = await loadSiteConfig({siteDir});
|
||||||
|
expect(config).toMatchSnapshot();
|
||||||
|
expect(config).not.toEqual({});
|
||||||
|
});
|
||||||
|
|
||||||
it('website with valid config creator function', async () => {
|
it('website with valid config creator function', async () => {
|
||||||
const config = await loadSiteConfig({
|
const config = await loadSiteConfig({
|
||||||
siteDir,
|
siteDir,
|
||||||
|
@ -65,7 +71,7 @@ describe('loadSiteConfig', () => {
|
||||||
customConfigFilePath: 'wrong.config.js',
|
customConfigFilePath: 'wrong.config.js',
|
||||||
}),
|
}),
|
||||||
).rejects.toThrowErrorMatchingInlineSnapshot(`
|
).rejects.toThrowErrorMatchingInlineSnapshot(`
|
||||||
"These field(s) ("useLessField",) are not recognized in docusaurus.config.js.
|
"These field(s) ("useLessField",) are not recognized in wrong.config.js.
|
||||||
If you still want these fields to be in your configuration, put them in the "customFields" field.
|
If you still want these fields to be in your configuration, put them in the "customFields" field.
|
||||||
See https://docusaurus.io/docs/api/docusaurus-config/#customfields"
|
See https://docusaurus.io/docs/api/docusaurus-config/#customfields"
|
||||||
`);
|
`);
|
||||||
|
|
|
@ -19,7 +19,7 @@ const baseConfig = {
|
||||||
} as Config;
|
} as Config;
|
||||||
|
|
||||||
const normalizeConfig = (config: Partial<Config>) =>
|
const normalizeConfig = (config: Partial<Config>) =>
|
||||||
validateConfig({...baseConfig, ...config});
|
validateConfig({...baseConfig, ...config}, 'docusaurus.config.js');
|
||||||
|
|
||||||
describe('normalizeConfig', () => {
|
describe('normalizeConfig', () => {
|
||||||
it('normalizes empty config', () => {
|
it('normalizes empty config', () => {
|
||||||
|
@ -296,13 +296,16 @@ describe('normalizeConfig', () => {
|
||||||
|
|
||||||
it('throws error for required fields', () => {
|
it('throws error for required fields', () => {
|
||||||
expect(() =>
|
expect(() =>
|
||||||
validateConfig({
|
validateConfig(
|
||||||
|
{
|
||||||
invalidField: true,
|
invalidField: true,
|
||||||
presets: {},
|
presets: {},
|
||||||
stylesheets: {},
|
stylesheets: {},
|
||||||
themes: {},
|
themes: {},
|
||||||
scripts: {},
|
scripts: {},
|
||||||
}),
|
},
|
||||||
|
'docusaurus.config.js',
|
||||||
|
),
|
||||||
).toThrowErrorMatchingSnapshot();
|
).toThrowErrorMatchingSnapshot();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,10 +8,29 @@
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import importFresh from 'import-fresh';
|
import importFresh from 'import-fresh';
|
||||||
import {DEFAULT_CONFIG_FILE_NAME} from '@docusaurus/utils';
|
import logger from '@docusaurus/logger';
|
||||||
|
import {DEFAULT_CONFIG_FILE_NAME, findAsyncSequential} from '@docusaurus/utils';
|
||||||
import {validateConfig} from './configValidation';
|
import {validateConfig} from './configValidation';
|
||||||
import type {LoadContext} from '@docusaurus/types';
|
import type {LoadContext} from '@docusaurus/types';
|
||||||
|
|
||||||
|
async function findConfig(siteDir: string) {
|
||||||
|
// We could support .mjs, .ts, etc. in the future
|
||||||
|
const candidates = ['.js', '.cjs'].map(
|
||||||
|
(ext) => DEFAULT_CONFIG_FILE_NAME + ext,
|
||||||
|
);
|
||||||
|
const configPath = await findAsyncSequential(
|
||||||
|
candidates.map((file) => path.join(siteDir, file)),
|
||||||
|
fs.pathExists,
|
||||||
|
);
|
||||||
|
if (!configPath) {
|
||||||
|
logger.error('No config file found.');
|
||||||
|
logger.info`Expected one of:${candidates}
|
||||||
|
You can provide a custom config path with the code=${'--config'} option.`;
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
return configPath;
|
||||||
|
}
|
||||||
|
|
||||||
export async function loadSiteConfig({
|
export async function loadSiteConfig({
|
||||||
siteDir,
|
siteDir,
|
||||||
customConfigFilePath,
|
customConfigFilePath,
|
||||||
|
@ -19,10 +38,9 @@ export async function loadSiteConfig({
|
||||||
siteDir: string;
|
siteDir: string;
|
||||||
customConfigFilePath?: string;
|
customConfigFilePath?: string;
|
||||||
}): Promise<Pick<LoadContext, 'siteConfig' | 'siteConfigPath'>> {
|
}): Promise<Pick<LoadContext, 'siteConfig' | 'siteConfigPath'>> {
|
||||||
const siteConfigPath = path.resolve(
|
const siteConfigPath = customConfigFilePath
|
||||||
siteDir,
|
? path.resolve(siteDir, customConfigFilePath)
|
||||||
customConfigFilePath ?? DEFAULT_CONFIG_FILE_NAME,
|
: await findConfig(siteDir);
|
||||||
);
|
|
||||||
|
|
||||||
if (!(await fs.pathExists(siteConfigPath))) {
|
if (!(await fs.pathExists(siteConfigPath))) {
|
||||||
throw new Error(`Config file at "${siteConfigPath}" not found.`);
|
throw new Error(`Config file at "${siteConfigPath}" not found.`);
|
||||||
|
@ -35,6 +53,9 @@ export async function loadSiteConfig({
|
||||||
? await importedConfig()
|
? await importedConfig()
|
||||||
: await importedConfig;
|
: await importedConfig;
|
||||||
|
|
||||||
const siteConfig = validateConfig(loadedConfig);
|
const siteConfig = validateConfig(
|
||||||
|
loadedConfig,
|
||||||
|
path.relative(siteDir, siteConfigPath),
|
||||||
|
);
|
||||||
return {siteConfig, siteConfigPath};
|
return {siteConfig, siteConfigPath};
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,7 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import {DEFAULT_STATIC_DIR_NAME} from '@docusaurus/utils';
|
||||||
DEFAULT_CONFIG_FILE_NAME,
|
|
||||||
DEFAULT_STATIC_DIR_NAME,
|
|
||||||
} from '@docusaurus/utils';
|
|
||||||
import {Joi, URISchema, printWarning} from '@docusaurus/utils-validation';
|
import {Joi, URISchema, printWarning} from '@docusaurus/utils-validation';
|
||||||
import type {DocusaurusConfig, I18nConfig} from '@docusaurus/types';
|
import type {DocusaurusConfig, I18nConfig} from '@docusaurus/types';
|
||||||
|
|
||||||
|
@ -239,7 +236,10 @@ export const ConfigSchema = Joi.object<DocusaurusConfig>({
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO move to @docusaurus/utils-validation
|
// TODO move to @docusaurus/utils-validation
|
||||||
export function validateConfig(config: unknown): DocusaurusConfig {
|
export function validateConfig(
|
||||||
|
config: unknown,
|
||||||
|
siteConfigPath: string,
|
||||||
|
): DocusaurusConfig {
|
||||||
const {error, warning, value} = ConfigSchema.validate(config, {
|
const {error, warning, value} = ConfigSchema.validate(config, {
|
||||||
abortEarly: false,
|
abortEarly: false,
|
||||||
});
|
});
|
||||||
|
@ -263,7 +263,7 @@ export function validateConfig(config: unknown): DocusaurusConfig {
|
||||||
'',
|
'',
|
||||||
);
|
);
|
||||||
formattedError = unknownFields
|
formattedError = unknownFields
|
||||||
? `${formattedError}These field(s) (${unknownFields}) are not recognized in ${DEFAULT_CONFIG_FILE_NAME}.\nIf you still want these fields to be in your configuration, put them in the "customFields" field.\nSee https://docusaurus.io/docs/api/docusaurus-config/#customfields`
|
? `${formattedError}These field(s) (${unknownFields}) are not recognized in ${siteConfigPath}.\nIf you still want these fields to be in your configuration, put them in the "customFields" field.\nSee https://docusaurus.io/docs/api/docusaurus-config/#customfields`
|
||||||
: formattedError;
|
: formattedError;
|
||||||
throw new Error(formattedError);
|
throw new Error(formattedError);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -156,7 +156,7 @@ next build. You can clear all build artifacts (including this folder) with the
|
||||||
|
|
||||||
const genSiteConfig = generate(
|
const genSiteConfig = generate(
|
||||||
generatedFilesDir,
|
generatedFilesDir,
|
||||||
DEFAULT_CONFIG_FILE_NAME,
|
`${DEFAULT_CONFIG_FILE_NAME}.mjs`,
|
||||||
`/*
|
`/*
|
||||||
* AUTOGENERATED - DON'T EDIT
|
* AUTOGENERATED - DON'T EDIT
|
||||||
* Your edits in this file will be overwritten in the next build!
|
* Your edits in this file will be overwritten in the next build!
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue