diff --git a/packages/docusaurus-utils/src/constants.ts b/packages/docusaurus-utils/src/constants.ts index a9a91394f48c..633f365f38fc 100644 --- a/packages/docusaurus-utils/src/constants.ts +++ b/packages/docusaurus-utils/src/constants.ts @@ -29,8 +29,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..165c2e74ba6a 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,54 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`loadSiteConfig website with .cjs siteConfig 1`] = ` +{ + "siteConfig": { + "baseUrl": "/", + "baseUrlIssueBanner": true, + "clientModules": [ + "foo.js", + ], + "customFields": {}, + "favicon": "img/docusaurus.ico", + "i18n": { + "defaultLocale": "en", + "localeConfigs": {}, + "locales": [ + "en", + ], + }, + "noIndex": false, + "onBrokenLinks": "throw", + "onBrokenMarkdownLinks": "warn", + "onDuplicateRoutes": "warn", + "organizationName": "endiliey", + "plugins": [ + [ + "@docusaurus/plugin-content-docs", + { + "path": "../docs", + }, + ], + "@docusaurus/plugin-content-pages", + ], + "presets": [], + "projectName": "hello", + "scripts": [], + "staticDirectories": [ + "static", + ], + "stylesheets": [], + "tagline": "Hello World", + "themeConfig": {}, + "themes": [], + "title": "Hello", + "titleDelimiter": "|", + "url": "https://docusaurus.io", + }, + "siteConfigPath": "/packages/docusaurus/src/server/__tests__/__fixtures__/simple-site/docusaurus.config.js", +} +`; + 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..ba713d997562 100644 --- a/packages/docusaurus/src/server/__tests__/config.test.ts +++ b/packages/docusaurus/src/server/__tests__/config.test.ts @@ -19,6 +19,14 @@ describe('loadSiteConfig', () => { expect(config).not.toEqual({}); }); + it('website with .cjs siteConfig', async () => { + const config = await loadSiteConfig({ + siteDir: path.join(__dirname, '__fixtures__', 'simple-site'), + }); + expect(config).toMatchSnapshot(); + expect(config).not.toEqual({}); + }); + it('website with valid config creator function', async () => { const config = await loadSiteConfig({ siteDir, @@ -65,7 +73,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 70eaa3900e3c..0c41cd540db6 100644 --- a/packages/docusaurus/src/server/__tests__/configValidation.test.ts +++ b/packages/docusaurus/src/server/__tests__/configValidation.test.ts @@ -18,7 +18,8 @@ const baseConfig: DocusaurusConfig = { url: 'https://mysite.com', }; -const normalizeConfig = (config) => validateConfig({...baseConfig, ...config}); +const normalizeConfig = (config) => + validateConfig({...baseConfig, ...config}, 'docusaurus.config.js'); describe('normalizeConfig', () => { it('normalizes empty config', () => { @@ -289,13 +290,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 84b4975f1249..6287b63ce3c1 100644 --- a/packages/docusaurus/src/server/config.ts +++ b/packages/docusaurus/src/server/config.ts @@ -8,10 +8,28 @@ 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 type {LoadContext} from '@docusaurus/types'; import {validateConfig} from './configValidation'; +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 +37,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 +52,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 f8a0985903a8..de94161306cd 100644 --- a/packages/docusaurus/src/server/configValidation.ts +++ b/packages/docusaurus/src/server/configValidation.ts @@ -6,10 +6,7 @@ */ import type {DocusaurusConfig, I18nConfig} from '@docusaurus/types'; -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'; const DEFAULT_I18N_LOCALE = 'en'; @@ -239,6 +236,7 @@ export const ConfigSchema = Joi.object({ // TODO move to @docusaurus/utils-validation export function validateConfig( config: Partial, + siteConfigPath: string, ): DocusaurusConfig { const {error, warning, value} = ConfigSchema.validate(config, { abortEarly: false, @@ -261,7 +259,7 @@ export function validateConfig( '', ); 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 {