From be912c698a3c6115ba7e815c652f892d63134079 Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Fri, 27 May 2022 17:11:58 +0800 Subject: [PATCH] feat(core): support docusaurus.config.cjs as default file name (#7371) --- packages/docusaurus-utils/src/constants.ts | 5 ++- .../__fixtures__/config/docusaurus.config.cjs | 5 +++ .../__snapshots__/config.test.ts.snap | 36 +++++++++++++++++++ .../src/server/__tests__/config.test.ts | 8 ++++- .../server/__tests__/configValidation.test.ts | 19 +++++----- packages/docusaurus/src/server/config.ts | 33 +++++++++++++---- .../docusaurus/src/server/configValidation.ts | 12 +++---- packages/docusaurus/src/server/index.ts | 2 +- 8 files changed, 97 insertions(+), 23 deletions(-) create mode 100644 packages/docusaurus/src/server/__tests__/__fixtures__/config/docusaurus.config.cjs diff --git a/packages/docusaurus-utils/src/constants.ts b/packages/docusaurus-utils/src/constants.ts index be9405eab9bd..9f8c452669bb 100644 --- a/packages/docusaurus-utils/src/constants.ts +++ b/packages/docusaurus-utils/src/constants.ts @@ -30,8 +30,11 @@ export const DEFAULT_BUILD_DIR_NAME = 'build'; /** * Can be overridden with cli option `--config`. Code should generally use * `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. */ export const BABEL_CONFIG_FILE_NAME = diff --git a/packages/docusaurus/src/server/__tests__/__fixtures__/config/docusaurus.config.cjs b/packages/docusaurus/src/server/__tests__/__fixtures__/config/docusaurus.config.cjs new file mode 100644 index 000000000000..22c3d0c6ceef --- /dev/null +++ b/packages/docusaurus/src/server/__tests__/__fixtures__/config/docusaurus.config.cjs @@ -0,0 +1,5 @@ +module.exports = { + title: 'title', + url: 'https://example.com', + baseUrl: '/' +}; diff --git a/packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap b/packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap index abaaab349c57..2c20bb59c885 100644 --- a/packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap +++ b/packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap @@ -1,5 +1,41 @@ // 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": "/packages/docusaurus/src/server/__tests__/__fixtures__/config/docusaurus.config.cjs", +} +`; + exports[`loadSiteConfig website with valid async config 1`] = ` { "siteConfig": { diff --git a/packages/docusaurus/src/server/__tests__/config.test.ts b/packages/docusaurus/src/server/__tests__/config.test.ts index 4965d60f5a05..d66a56c4f325 100644 --- a/packages/docusaurus/src/server/__tests__/config.test.ts +++ b/packages/docusaurus/src/server/__tests__/config.test.ts @@ -19,6 +19,12 @@ describe('loadSiteConfig', () => { 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 () => { const config = await loadSiteConfig({ siteDir, @@ -65,7 +71,7 @@ describe('loadSiteConfig', () => { customConfigFilePath: 'wrong.config.js', }), ).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. See https://docusaurus.io/docs/api/docusaurus-config/#customfields" `); diff --git a/packages/docusaurus/src/server/__tests__/configValidation.test.ts b/packages/docusaurus/src/server/__tests__/configValidation.test.ts index bd42f1f96569..a2aad2aeca58 100644 --- a/packages/docusaurus/src/server/__tests__/configValidation.test.ts +++ b/packages/docusaurus/src/server/__tests__/configValidation.test.ts @@ -19,7 +19,7 @@ const baseConfig = { } as Config; const normalizeConfig = (config: Partial) => - validateConfig({...baseConfig, ...config}); + validateConfig({...baseConfig, ...config}, 'docusaurus.config.js'); describe('normalizeConfig', () => { it('normalizes empty config', () => { @@ -296,13 +296,16 @@ describe('normalizeConfig', () => { it('throws error for required fields', () => { expect(() => - validateConfig({ - invalidField: true, - presets: {}, - stylesheets: {}, - themes: {}, - scripts: {}, - }), + validateConfig( + { + invalidField: true, + presets: {}, + stylesheets: {}, + themes: {}, + scripts: {}, + }, + 'docusaurus.config.js', + ), ).toThrowErrorMatchingSnapshot(); }); }); diff --git a/packages/docusaurus/src/server/config.ts b/packages/docusaurus/src/server/config.ts index 73cccc613654..8f2fa9c9129e 100644 --- a/packages/docusaurus/src/server/config.ts +++ b/packages/docusaurus/src/server/config.ts @@ -8,10 +8,29 @@ import path from 'path'; import fs from 'fs-extra'; 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 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({ siteDir, customConfigFilePath, @@ -19,10 +38,9 @@ export async function loadSiteConfig({ siteDir: string; customConfigFilePath?: string; }): Promise> { - const siteConfigPath = path.resolve( - siteDir, - customConfigFilePath ?? DEFAULT_CONFIG_FILE_NAME, - ); + const siteConfigPath = customConfigFilePath + ? path.resolve(siteDir, customConfigFilePath) + : await findConfig(siteDir); if (!(await fs.pathExists(siteConfigPath))) { throw new Error(`Config file at "${siteConfigPath}" not found.`); @@ -35,6 +53,9 @@ export async function loadSiteConfig({ ? await importedConfig() : await importedConfig; - const siteConfig = validateConfig(loadedConfig); + const siteConfig = validateConfig( + loadedConfig, + path.relative(siteDir, siteConfigPath), + ); return {siteConfig, siteConfigPath}; } diff --git a/packages/docusaurus/src/server/configValidation.ts b/packages/docusaurus/src/server/configValidation.ts index f5ef6a3cc9a4..15a66776b19d 100644 --- a/packages/docusaurus/src/server/configValidation.ts +++ b/packages/docusaurus/src/server/configValidation.ts @@ -5,10 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import { - DEFAULT_CONFIG_FILE_NAME, - DEFAULT_STATIC_DIR_NAME, -} from '@docusaurus/utils'; +import {DEFAULT_STATIC_DIR_NAME} from '@docusaurus/utils'; import {Joi, URISchema, printWarning} from '@docusaurus/utils-validation'; import type {DocusaurusConfig, I18nConfig} from '@docusaurus/types'; @@ -239,7 +236,10 @@ export const ConfigSchema = Joi.object({ }); // 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, { abortEarly: false, }); @@ -263,7 +263,7 @@ export function validateConfig(config: unknown): DocusaurusConfig { '', ); 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; throw new Error(formattedError); } else { diff --git a/packages/docusaurus/src/server/index.ts b/packages/docusaurus/src/server/index.ts index 4417f0f7f515..90908237b04f 100644 --- a/packages/docusaurus/src/server/index.ts +++ b/packages/docusaurus/src/server/index.ts @@ -156,7 +156,7 @@ next build. You can clear all build artifacts (including this folder) with the const genSiteConfig = generate( generatedFilesDir, - DEFAULT_CONFIG_FILE_NAME, + `${DEFAULT_CONFIG_FILE_NAME}.mjs`, `/* * AUTOGENERATED - DON'T EDIT * Your edits in this file will be overwritten in the next build!