From 3f54f4fe1b533c4b5b8adead746f69fc15ab621b Mon Sep 17 00:00:00 2001 From: Chongyi Zheng Date: Sun, 17 Sep 2023 05:50:54 -0400 Subject: [PATCH 01/46] feat: support typescript configuration --- .../package.json | 1 + .../src/sidebars/index.ts | 6 ++-- packages/docusaurus/package.json | 2 +- packages/docusaurus/src/server/config.ts | 11 +++--- project-words.txt | 27 +++++++-------- yarn.lock | 34 +++++++++++++++---- 6 files changed, 50 insertions(+), 31 deletions(-) diff --git a/packages/docusaurus-plugin-content-docs/package.json b/packages/docusaurus-plugin-content-docs/package.json index 0dc30735264e..ae3647d02a92 100644 --- a/packages/docusaurus-plugin-content-docs/package.json +++ b/packages/docusaurus-plugin-content-docs/package.json @@ -46,6 +46,7 @@ "combine-promises": "^1.1.0", "fs-extra": "^11.1.1", "import-fresh": "^3.3.0", + "jiti": "^1.20.0", "js-yaml": "^4.1.0", "lodash": "^4.17.21", "tslib": "^2.6.0", diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/index.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/index.ts index 36bd576f7f8a..6f0f1e4d0a00 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/index.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/index.ts @@ -12,7 +12,7 @@ import logger from '@docusaurus/logger'; import {Globby} from '@docusaurus/utils'; import Yaml from 'js-yaml'; import combinePromises from 'combine-promises'; -import importFresh from 'import-fresh'; +import jiti from 'jiti'; import {validateSidebars, validateCategoryMetadataFile} from './validation'; import {normalizeSidebars} from './normalization'; import {processSidebars} from './processor'; @@ -89,7 +89,9 @@ export async function loadSidebarsFileUnsafe( } // We don't want sidebars to be cached because of hot reloading. - return importFresh(sidebarFilePath); + return jiti(__filename, { + cache: false, + })(sidebarFilePath); } export async function loadSidebars( diff --git a/packages/docusaurus/package.json b/packages/docusaurus/package.json index ff242b908f19..3f2c5ed4b548 100644 --- a/packages/docusaurus/package.json +++ b/packages/docusaurus/package.json @@ -76,7 +76,7 @@ "html-minifier-terser": "^7.2.0", "html-tags": "^3.3.1", "html-webpack-plugin": "^5.5.3", - "import-fresh": "^3.3.0", + "jiti": "^1.20.0", "leven": "^3.1.0", "lodash": "^4.17.21", "mini-css-extract-plugin": "^2.7.6", diff --git a/packages/docusaurus/src/server/config.ts b/packages/docusaurus/src/server/config.ts index 8f2fa9c9129e..ae9b758cc40d 100644 --- a/packages/docusaurus/src/server/config.ts +++ b/packages/docusaurus/src/server/config.ts @@ -7,7 +7,7 @@ import path from 'path'; import fs from 'fs-extra'; -import importFresh from 'import-fresh'; +import jiti from 'jiti'; import logger from '@docusaurus/logger'; import {DEFAULT_CONFIG_FILE_NAME, findAsyncSequential} from '@docusaurus/utils'; import {validateConfig} from './configValidation'; @@ -46,12 +46,9 @@ export async function loadSiteConfig({ throw new Error(`Config file at "${siteConfigPath}" not found.`); } - const importedConfig = importFresh(siteConfigPath); - - const loadedConfig: unknown = - typeof importedConfig === 'function' - ? await importedConfig() - : await importedConfig; + const loadedConfig = jiti(__filename, { + cache: false, + })(siteConfigPath); const siteConfig = validateConfig( loadedConfig, diff --git a/project-words.txt b/project-words.txt index 4e8076b252c2..441db0ac77b2 100644 --- a/project-words.txt +++ b/project-words.txt @@ -60,7 +60,6 @@ cssnano csvg customizability dabit -dabit daishi datagit datas @@ -98,20 +97,23 @@ eslintcache estree evaluable execa -execa externalwaiting failfast +Fargate fbid février fienny flac +Flightcontrol +Flightcontrol's formik fouc froms funboxteam -gantt gabrielcsapo +gantt getopts +Gifs gitgraph gitpod globbing @@ -123,6 +125,7 @@ gtag hahaha hamel hardcoding +hastscript hasura heavener héctor @@ -136,6 +139,7 @@ hoverable husain ianad idempotency +Iframes immer infima inlines @@ -148,6 +152,7 @@ jakepartusch jamstack janvier javadoc +jiti jmarcey jodyheavener joshcena @@ -183,6 +188,7 @@ mathjax maxlynch maxresdefault mdast +mdwn mdxa mdxast mdxhast @@ -198,9 +204,8 @@ minifier mkcert mkdir mkdirs -mkdocs mkdn -mdwn +mkdocs mkdown moesif msapplication @@ -273,6 +278,7 @@ prerendered prerendering println prismjs +producthunt profilo protobuf protobuffet @@ -319,7 +325,6 @@ serializers setaf setext shiki -shiki showinfo sida simen @@ -328,7 +333,6 @@ sluggified sluggifies sluggify solana -solana spâce stackblitz stackblitzrc @@ -373,6 +377,7 @@ typecheck typechecks typedoc typesense +Unavatar unflat unist unlinkable @@ -415,11 +420,3 @@ yangshunz zhou zoomable zpao -hastscript -Flightcontrol -Fargate -Flightcontrol's -producthunt -Gifs -Iframes -Unavatar diff --git a/yarn.lock b/yarn.lock index 60f73f64034d..cf5f50580a4c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5532,6 +5532,11 @@ commander@^2.20.0: resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== +commander@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" + integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== + commander@^5.0.0, commander@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" @@ -8315,6 +8320,18 @@ glob@7.1.4: once "^1.3.0" path-is-absolute "^1.0.0" +glob@7.1.6: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + glob@^10.2.2: version "10.3.3" resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.3.tgz#8360a4ffdd6ed90df84aa8d52f21f452e86a123b" @@ -10197,10 +10214,10 @@ jest@^29.6.1: import-local "^3.0.2" jest-cli "^29.6.1" -jiti@^1.18.2: - version "1.19.1" - resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.19.1.tgz#fa99e4b76a23053e0e7cde098efe1704a14c16f1" - integrity sha512-oVhqoRDaBXf7sjkll95LHVS6Myyyb1zaunVwk4Z0+WPSW4gjS0pl01zYKHScTuyEhQsFxV5L4DR5r+YqSyqyyg== +jiti@^1.18.2, jiti@^1.20.0: + version "1.20.0" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.20.0.tgz#2d823b5852ee8963585c8dd8b7992ffc1ae83b42" + integrity sha512-3TV69ZbrvV6U5DfQimop50jE9Dl6J8O1ja1dvBbMba/sZ3YBEQqJ2VZRoQPVnhlzjNtU1vaXRZVrVjU4qtm8yA== jkroso-type@1: version "1.1.1" @@ -12093,7 +12110,7 @@ mute-stream@0.0.8, mute-stream@~0.0.4: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== -mz@^2.4.0: +mz@^2.4.0, mz@^2.7.0: version "2.7.0" resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== @@ -13213,7 +13230,7 @@ pify@^4.0.1: resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== -pirates@^4.0.4, pirates@^4.0.5: +pirates@^4.0.1, pirates@^4.0.4, pirates@^4.0.5: version "4.0.6" resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== @@ -16200,6 +16217,11 @@ ts-dedent@^2.2.0: resolved "https://registry.yarnpkg.com/ts-dedent/-/ts-dedent-2.2.0.tgz#39e4bd297cd036292ae2394eb3412be63f563bb5" integrity sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ== +ts-interface-checker@^0.1.9: + version "0.1.13" + resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699" + integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA== + tsconfig-paths@^3.14.1: version "3.14.2" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz#6e32f1f79412decd261f92d633a9dc1cfa99f088" From b9db57427c227719840c4e925d01aa4b5f96e19a Mon Sep 17 00:00:00 2001 From: Chongyi Zheng Date: Tue, 19 Sep 2023 16:53:25 -0400 Subject: [PATCH 02/46] Apply suggestions from code review Co-authored-by: Joshua Chen --- project-words.txt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/project-words.txt b/project-words.txt index 441db0ac77b2..aec839742361 100644 --- a/project-words.txt +++ b/project-words.txt @@ -104,8 +104,7 @@ fbid février fienny flac -Flightcontrol -Flightcontrol's +flightcontrol formik fouc froms @@ -113,7 +112,7 @@ funboxteam gabrielcsapo gantt getopts -Gifs +gifs gitgraph gitpod globbing @@ -377,7 +376,7 @@ typecheck typechecks typedoc typesense -Unavatar +unavatar unflat unist unlinkable From b88e1c88dbeb8ae83a80e4fd9592125f8723bd7b Mon Sep 17 00:00:00 2001 From: Chongyi Zheng Date: Tue, 19 Sep 2023 16:56:32 -0400 Subject: [PATCH 03/46] fix: handle function typed config --- packages/docusaurus/src/server/config.ts | 7 ++++++- yarn.lock | 26 ++---------------------- 2 files changed, 8 insertions(+), 25 deletions(-) diff --git a/packages/docusaurus/src/server/config.ts b/packages/docusaurus/src/server/config.ts index ae9b758cc40d..0fcf2b45ed57 100644 --- a/packages/docusaurus/src/server/config.ts +++ b/packages/docusaurus/src/server/config.ts @@ -46,10 +46,15 @@ export async function loadSiteConfig({ throw new Error(`Config file at "${siteConfigPath}" not found.`); } - const loadedConfig = jiti(__filename, { + const importedConfig = jiti(__filename, { cache: false, })(siteConfigPath); + const loadedConfig: unknown = + typeof importedConfig === 'function' + ? await importedConfig() + : importedConfig; + const siteConfig = validateConfig( loadedConfig, path.relative(siteDir, siteConfigPath), diff --git a/yarn.lock b/yarn.lock index cf5f50580a4c..12c8956a57bf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5532,11 +5532,6 @@ commander@^2.20.0: resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== -commander@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" - integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== - commander@^5.0.0, commander@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" @@ -8320,18 +8315,6 @@ glob@7.1.4: once "^1.3.0" path-is-absolute "^1.0.0" -glob@7.1.6: - version "7.1.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - glob@^10.2.2: version "10.3.3" resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.3.tgz#8360a4ffdd6ed90df84aa8d52f21f452e86a123b" @@ -12110,7 +12093,7 @@ mute-stream@0.0.8, mute-stream@~0.0.4: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== -mz@^2.4.0, mz@^2.7.0: +mz@^2.4.0: version "2.7.0" resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== @@ -13230,7 +13213,7 @@ pify@^4.0.1: resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== -pirates@^4.0.1, pirates@^4.0.4, pirates@^4.0.5: +pirates@^4.0.4, pirates@^4.0.5: version "4.0.6" resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== @@ -16217,11 +16200,6 @@ ts-dedent@^2.2.0: resolved "https://registry.yarnpkg.com/ts-dedent/-/ts-dedent-2.2.0.tgz#39e4bd297cd036292ae2394eb3412be63f563bb5" integrity sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ== -ts-interface-checker@^0.1.9: - version "0.1.13" - resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699" - integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA== - tsconfig-paths@^3.14.1: version "3.14.2" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz#6e32f1f79412decd261f92d633a9dc1cfa99f088" From 0f661911b5b3f9b78090088a5b6f8c787498a501 Mon Sep 17 00:00:00 2001 From: Chongyi Zheng Date: Sun, 24 Sep 2023 02:22:44 -0400 Subject: [PATCH 04/46] chore: remove other usage of `import-fresh` --- .../src/__tests__/migrationConfig.test.ts | 10 ++++------ packages/docusaurus/src/server/plugins/configs.ts | 6 +++--- packages/docusaurus/src/server/plugins/presets.ts | 7 +++---- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/packages/docusaurus-migrate/src/__tests__/migrationConfig.test.ts b/packages/docusaurus-migrate/src/__tests__/migrationConfig.test.ts index 6e77e277e042..cb68f5efce5d 100644 --- a/packages/docusaurus-migrate/src/__tests__/migrationConfig.test.ts +++ b/packages/docusaurus-migrate/src/__tests__/migrationConfig.test.ts @@ -5,23 +5,21 @@ * LICENSE file in the root directory of this source tree. */ -import importFresh from 'import-fresh'; +import jiti from 'jiti'; import {createConfigFile} from '../index'; import type {VersionOneConfig} from '../types'; describe('create config', () => { it('simple test', () => { - const v1Config: VersionOneConfig = importFresh( - `${__dirname}/__fixtures__/sourceSiteConfig.js`, + const v1Config: VersionOneConfig = jiti(__dirname)( + `__fixtures__/sourceSiteConfig.js`, ); const siteDir = 'website'; const newDir = 'websiteMigrated'; const result = createConfigFile({v1Config, siteDir, newDir}); - const output = importFresh( - `${__dirname}/__fixtures__/expectedSiteConfig.js`, - ); + const output = jiti(__dirname)(`__fixtures__/expectedSiteConfig.js`); expect(result).toEqual(output); }); }); diff --git a/packages/docusaurus/src/server/plugins/configs.ts b/packages/docusaurus/src/server/plugins/configs.ts index eb2898e5d312..66411b3f082b 100644 --- a/packages/docusaurus/src/server/plugins/configs.ts +++ b/packages/docusaurus/src/server/plugins/configs.ts @@ -6,7 +6,7 @@ */ import {createRequire} from 'module'; -import importFresh from 'import-fresh'; +import jiti from 'jiti'; import {loadPresets} from './presets'; import {resolveModuleName} from './moduleShorthand'; import type { @@ -61,7 +61,7 @@ async function normalizePluginConfig( if (typeof pluginConfig === 'string') { const pluginModuleImport = pluginConfig; const pluginPath = pluginRequire.resolve(pluginModuleImport); - const pluginModule = importFresh(pluginPath); + const pluginModule = jiti(__filename)(pluginPath) as ImportedPluginModule; return { plugin: pluginModule.default ?? pluginModule, options: {}, @@ -88,7 +88,7 @@ async function normalizePluginConfig( if (typeof pluginConfig[0] === 'string') { const pluginModuleImport = pluginConfig[0]; const pluginPath = pluginRequire.resolve(pluginModuleImport); - const pluginModule = importFresh(pluginPath); + const pluginModule = jiti(__dirname)(pluginPath) as ImportedPluginModule; return { plugin: pluginModule.default ?? pluginModule, options: pluginConfig[1], diff --git a/packages/docusaurus/src/server/plugins/presets.ts b/packages/docusaurus/src/server/plugins/presets.ts index 04b73357f38f..070ca7bc4240 100644 --- a/packages/docusaurus/src/server/plugins/presets.ts +++ b/packages/docusaurus/src/server/plugins/presets.ts @@ -6,7 +6,7 @@ */ import {createRequire} from 'module'; -import importFresh from 'import-fresh'; +import jiti from 'jiti'; import {resolveModuleName} from './moduleShorthand'; import type { LoadContext, @@ -49,9 +49,8 @@ export async function loadPresets( 'preset', ); - const presetModule = importFresh( - presetRequire.resolve(presetName), - ); + const presetPath = presetRequire.resolve(presetName); + const presetModule = jiti(__filename)(presetPath) as ImportedPresetModule; const preset = (presetModule.default ?? presetModule)( context, presetOptions, From 8f48f9de8532d88c138933a56acee6eb06a126b6 Mon Sep 17 00:00:00 2001 From: Chongyi Zheng Date: Sun, 24 Sep 2023 02:27:07 -0400 Subject: [PATCH 05/46] chore: remove `import-fresh` in package.json --- packages/docusaurus-plugin-content-docs/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/docusaurus-plugin-content-docs/package.json b/packages/docusaurus-plugin-content-docs/package.json index ae3647d02a92..fada06eaae9b 100644 --- a/packages/docusaurus-plugin-content-docs/package.json +++ b/packages/docusaurus-plugin-content-docs/package.json @@ -45,7 +45,6 @@ "@types/react-router-config": "^5.0.7", "combine-promises": "^1.1.0", "fs-extra": "^11.1.1", - "import-fresh": "^3.3.0", "jiti": "^1.20.0", "js-yaml": "^4.1.0", "lodash": "^4.17.21", From 138e25e53eb4f9370312d007bbe888e8877b1a09 Mon Sep 17 00:00:00 2001 From: Chongyi Zheng Date: Sun, 24 Sep 2023 02:42:05 -0400 Subject: [PATCH 06/46] fix: fix tests related to config loading --- .../src/__tests__/migrationConfig.test.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/docusaurus-migrate/src/__tests__/migrationConfig.test.ts b/packages/docusaurus-migrate/src/__tests__/migrationConfig.test.ts index cb68f5efce5d..f0e9a8b65fb9 100644 --- a/packages/docusaurus-migrate/src/__tests__/migrationConfig.test.ts +++ b/packages/docusaurus-migrate/src/__tests__/migrationConfig.test.ts @@ -12,14 +12,16 @@ import type {VersionOneConfig} from '../types'; describe('create config', () => { it('simple test', () => { const v1Config: VersionOneConfig = jiti(__dirname)( - `__fixtures__/sourceSiteConfig.js`, + `${__dirname}/__fixtures__/sourceSiteConfig.js`, ); const siteDir = 'website'; const newDir = 'websiteMigrated'; const result = createConfigFile({v1Config, siteDir, newDir}); - const output = jiti(__dirname)(`__fixtures__/expectedSiteConfig.js`); + const output = jiti(__dirname)( + `${__dirname}/__fixtures__/expectedSiteConfig.js`, + ); expect(result).toEqual(output); }); }); From 901c95e662ae7143f0dd77ad76949de586637d4b Mon Sep 17 00:00:00 2001 From: Chongyi Zheng Date: Mon, 25 Sep 2023 11:41:04 -0400 Subject: [PATCH 07/46] fix: test case when config is promise --- packages/docusaurus/src/server/config.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/docusaurus/src/server/config.ts b/packages/docusaurus/src/server/config.ts index 0fcf2b45ed57..2b7e3a07abfb 100644 --- a/packages/docusaurus/src/server/config.ts +++ b/packages/docusaurus/src/server/config.ts @@ -50,10 +50,16 @@ export async function loadSiteConfig({ cache: false, })(siteConfigPath); - const loadedConfig: unknown = - typeof importedConfig === 'function' - ? await importedConfig() - : importedConfig; + let loadedConfig: unknown; + if (typeof importedConfig === 'function') { + loadedConfig = await importedConfig(); + } else if ( + Object.prototype.toString.call(importedConfig) === '[object Promise]' + ) { + loadedConfig = await importedConfig; + } else { + loadedConfig = importedConfig; + } const siteConfig = validateConfig( loadedConfig, From 3913aa8ff951887fb98d4736f732e3f5c114879b Mon Sep 17 00:00:00 2001 From: Chongyi Zheng Date: Mon, 25 Sep 2023 11:48:31 -0400 Subject: [PATCH 08/46] chore: add testcase for typescript --- .../config/configTypescript.config.ts | 7 +++ .../__snapshots__/config.test.ts.snap | 48 +++++++++++++++++++ .../src/server/__tests__/config.test.ts | 9 ++++ 3 files changed, 64 insertions(+) create mode 100644 packages/docusaurus/src/server/__tests__/__fixtures__/config/configTypescript.config.ts diff --git a/packages/docusaurus/src/server/__tests__/__fixtures__/config/configTypescript.config.ts b/packages/docusaurus/src/server/__tests__/__fixtures__/config/configTypescript.config.ts new file mode 100644 index 000000000000..c9118f7c7c8e --- /dev/null +++ b/packages/docusaurus/src/server/__tests__/__fixtures__/config/configTypescript.config.ts @@ -0,0 +1,7 @@ +import type {Config} from '@docusaurus/types'; + +module.exports = { + title: 'title', + url: 'https://example.com', + baseUrl: '/' +} as Config; 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 d83f688d657d..9a91bf16c256 100644 --- a/packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap +++ b/packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap @@ -258,3 +258,51 @@ exports[`loadSiteConfig website with valid siteConfig 1`] = ` "siteConfigPath": "/packages/docusaurus/src/server/__tests__/__fixtures__/simple-site/docusaurus.config.js", } `; + +exports[`loadSiteConfig website with valid typescript config 1`] = ` +{ + "siteConfig": { + "baseUrl": "/", + "baseUrlIssueBanner": true, + "clientModules": [], + "customFields": {}, + "headTags": [], + "i18n": { + "defaultLocale": "en", + "localeConfigs": {}, + "locales": [ + "en", + ], + "path": "i18n", + }, + "markdown": { + "format": "mdx", + "mdx1Compat": { + "admonitions": true, + "comments": true, + "headingIds": true, + }, + "mermaid": false, + "preprocessor": undefined, + }, + "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/configTypescript.config.ts", +} +`; diff --git a/packages/docusaurus/src/server/__tests__/config.test.ts b/packages/docusaurus/src/server/__tests__/config.test.ts index d66a56c4f325..7967cd26dfdd 100644 --- a/packages/docusaurus/src/server/__tests__/config.test.ts +++ b/packages/docusaurus/src/server/__tests__/config.test.ts @@ -52,6 +52,15 @@ describe('loadSiteConfig', () => { expect(config).not.toEqual({}); }); + it('website with valid typescript config', async () => { + const config = await loadSiteConfig({ + siteDir, + customConfigFilePath: 'configTypescript.config.ts', + }); + expect(config).toMatchSnapshot(); + expect(config).not.toEqual({}); + }); + it('website with incomplete siteConfig', async () => { await expect( loadSiteConfig({ From 693205757bdedce4e8d72b5351f5bc278a4e495d Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Thu, 12 Oct 2023 19:37:34 +0200 Subject: [PATCH 09/46] Attempt to use TS sidebar --- .../docusaurus-plugin-content-docs/src/sidebars/index.ts | 9 ++++++++- website/docs/guides/docs/sidebar/index.mdx | 2 +- website/docusaurus.config.js | 2 +- website/{sidebars.js => sidebars.ts} | 7 +++---- .../version-2.0.1/guides/docs/sidebar/index.mdx | 4 ++-- .../version-2.1.0/guides/docs/sidebar/index.mdx | 2 +- .../version-2.2.0/guides/docs/sidebar/index.mdx | 2 +- .../version-2.3.1/guides/docs/sidebar/index.mdx | 2 +- .../version-2.4.3/guides/docs/sidebar/index.mdx | 2 +- .../version-3.0.0-beta.0/guides/docs/sidebar/index.mdx | 2 +- 10 files changed, 20 insertions(+), 14 deletions(-) rename website/{sidebars.js => sidebars.ts} (96%) diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/index.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/index.ts index 6f0f1e4d0a00..4bebf0ce50c2 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/index.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/index.ts @@ -89,9 +89,16 @@ export async function loadSidebarsFileUnsafe( } // We don't want sidebars to be cached because of hot reloading. - return jiti(__filename, { + const sidebars = jiti(__filename, { cache: false, + interopDefault: true, + debug: true, })(sidebarFilePath); + + sidebarFilePath.endsWith('.ts') && + console.log({sidebarFilePath}, JSON.stringify(sidebars, null, 2)); + + return sidebars; } export async function loadSidebars( diff --git a/website/docs/guides/docs/sidebar/index.mdx b/website/docs/guides/docs/sidebar/index.mdx index 0caba80169c9..5c14b5eec6c3 100644 --- a/website/docs/guides/docs/sidebar/index.mdx +++ b/website/docs/guides/docs/sidebar/index.mdx @@ -201,7 +201,7 @@ A real-world example from the Docusaurus site: import CodeBlock from '@theme/CodeBlock'; - {require('!!raw-loader!@site/sidebars.js') + {require('!!raw-loader!@site/sidebars.ts') .default .split('\n') // remove comments diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index 7e11dd04f8af..154884f4605c 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -365,7 +365,7 @@ module.exports = async function createConfigAsync() { docs: { // routeBasePath: '/', path: 'docs', - sidebarPath: 'sidebars.js', + sidebarPath: 'sidebars.ts', // sidebarCollapsible: false, // sidebarCollapsed: true, editUrl: ({locale, docPath}) => { diff --git a/website/sidebars.js b/website/sidebars.ts similarity index 96% rename from website/sidebars.js rename to website/sidebars.ts index a5be9b42a915..0b7b39b51e5a 100644 --- a/website/sidebars.js +++ b/website/sidebars.ts @@ -5,10 +5,9 @@ * LICENSE file in the root directory of this source tree. */ -// @ts-check +import type {SidebarsConfig} from '@docusaurus/plugin-content-docs'; -/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ -const sidebars = { +const sidebars: SidebarsConfig = { docs: [ 'introduction', { @@ -153,4 +152,4 @@ const sidebars = { ], }; -module.exports = sidebars; +export default sidebars; diff --git a/website/versioned_docs/version-2.0.1/guides/docs/sidebar/index.mdx b/website/versioned_docs/version-2.0.1/guides/docs/sidebar/index.mdx index e9624728b491..7cd834184134 100644 --- a/website/versioned_docs/version-2.0.1/guides/docs/sidebar/index.mdx +++ b/website/versioned_docs/version-2.0.1/guides/docs/sidebar/index.mdx @@ -201,8 +201,8 @@ A real-world example from the Docusaurus site: ```mdx-code-block import CodeBlock from '@theme/CodeBlock'; - - {require('!!raw-loader!@site/sidebars.js') + + {require('!!raw-loader!@site/sidebars.ts') .default .split('\n') // remove comments diff --git a/website/versioned_docs/version-2.1.0/guides/docs/sidebar/index.mdx b/website/versioned_docs/version-2.1.0/guides/docs/sidebar/index.mdx index 0caba80169c9..5c14b5eec6c3 100644 --- a/website/versioned_docs/version-2.1.0/guides/docs/sidebar/index.mdx +++ b/website/versioned_docs/version-2.1.0/guides/docs/sidebar/index.mdx @@ -201,7 +201,7 @@ A real-world example from the Docusaurus site: import CodeBlock from '@theme/CodeBlock'; - {require('!!raw-loader!@site/sidebars.js') + {require('!!raw-loader!@site/sidebars.ts') .default .split('\n') // remove comments diff --git a/website/versioned_docs/version-2.2.0/guides/docs/sidebar/index.mdx b/website/versioned_docs/version-2.2.0/guides/docs/sidebar/index.mdx index 0caba80169c9..5c14b5eec6c3 100644 --- a/website/versioned_docs/version-2.2.0/guides/docs/sidebar/index.mdx +++ b/website/versioned_docs/version-2.2.0/guides/docs/sidebar/index.mdx @@ -201,7 +201,7 @@ A real-world example from the Docusaurus site: import CodeBlock from '@theme/CodeBlock'; - {require('!!raw-loader!@site/sidebars.js') + {require('!!raw-loader!@site/sidebars.ts') .default .split('\n') // remove comments diff --git a/website/versioned_docs/version-2.3.1/guides/docs/sidebar/index.mdx b/website/versioned_docs/version-2.3.1/guides/docs/sidebar/index.mdx index 0caba80169c9..5c14b5eec6c3 100644 --- a/website/versioned_docs/version-2.3.1/guides/docs/sidebar/index.mdx +++ b/website/versioned_docs/version-2.3.1/guides/docs/sidebar/index.mdx @@ -201,7 +201,7 @@ A real-world example from the Docusaurus site: import CodeBlock from '@theme/CodeBlock'; - {require('!!raw-loader!@site/sidebars.js') + {require('!!raw-loader!@site/sidebars.ts') .default .split('\n') // remove comments diff --git a/website/versioned_docs/version-2.4.3/guides/docs/sidebar/index.mdx b/website/versioned_docs/version-2.4.3/guides/docs/sidebar/index.mdx index 0caba80169c9..5c14b5eec6c3 100644 --- a/website/versioned_docs/version-2.4.3/guides/docs/sidebar/index.mdx +++ b/website/versioned_docs/version-2.4.3/guides/docs/sidebar/index.mdx @@ -201,7 +201,7 @@ A real-world example from the Docusaurus site: import CodeBlock from '@theme/CodeBlock'; - {require('!!raw-loader!@site/sidebars.js') + {require('!!raw-loader!@site/sidebars.ts') .default .split('\n') // remove comments diff --git a/website/versioned_docs/version-3.0.0-beta.0/guides/docs/sidebar/index.mdx b/website/versioned_docs/version-3.0.0-beta.0/guides/docs/sidebar/index.mdx index 0caba80169c9..5c14b5eec6c3 100644 --- a/website/versioned_docs/version-3.0.0-beta.0/guides/docs/sidebar/index.mdx +++ b/website/versioned_docs/version-3.0.0-beta.0/guides/docs/sidebar/index.mdx @@ -201,7 +201,7 @@ A real-world example from the Docusaurus site: import CodeBlock from '@theme/CodeBlock'; - {require('!!raw-loader!@site/sidebars.js') + {require('!!raw-loader!@site/sidebars.ts') .default .split('\n') // remove comments From 201c8748ebb30ba548bb1d54054630ea3f43238e Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Fri, 13 Oct 2023 11:55:49 +0200 Subject: [PATCH 10/46] Hide jiti behind Docusaurus utils loadFreshModule abstraction --- .../package.json | 1 - .../docusaurus-plugin-content-docs/src/cli.ts | 4 +- .../src/sidebars/index.ts | 24 ++++++----- packages/docusaurus-types/src/index.d.ts | 1 + packages/docusaurus-types/src/plugin.d.ts | 8 ++-- packages/docusaurus-utils/package.json | 1 + packages/docusaurus-utils/src/index.ts | 1 + packages/docusaurus-utils/src/moduleUtils.ts | 32 +++++++++++++++ packages/docusaurus/package.json | 1 - packages/docusaurus/src/server/config.ts | 25 +++++------- .../docusaurus/src/server/plugins/configs.ts | 10 +++-- .../docusaurus/src/server/plugins/presets.ts | 40 +++++++++---------- 12 files changed, 89 insertions(+), 59 deletions(-) create mode 100644 packages/docusaurus-utils/src/moduleUtils.ts diff --git a/packages/docusaurus-plugin-content-docs/package.json b/packages/docusaurus-plugin-content-docs/package.json index 6d320c353c4e..623e90419939 100644 --- a/packages/docusaurus-plugin-content-docs/package.json +++ b/packages/docusaurus-plugin-content-docs/package.json @@ -45,7 +45,6 @@ "@types/react-router-config": "^5.0.7", "combine-promises": "^1.1.0", "fs-extra": "^11.1.1", - "jiti": "^1.20.0", "js-yaml": "^4.1.0", "lodash": "^4.17.21", "tslib": "^2.6.0", diff --git a/packages/docusaurus-plugin-content-docs/src/cli.ts b/packages/docusaurus-plugin-content-docs/src/cli.ts index 23cd26e7e461..5cc52f2a5f9b 100644 --- a/packages/docusaurus-plugin-content-docs/src/cli.ts +++ b/packages/docusaurus-plugin-content-docs/src/cli.ts @@ -17,7 +17,7 @@ import { readVersionsFile, } from './versions/files'; import {validateVersionName} from './versions/validation'; -import {loadSidebarsFileUnsafe} from './sidebars'; +import {loadSidebarsFile} from './sidebars'; import {CURRENT_VERSION_NAME} from './constants'; import type {PluginOptions} from '@docusaurus/plugin-content-docs'; import type {LoadContext} from '@docusaurus/types'; @@ -37,7 +37,7 @@ async function createVersionedSidebarFile({ // Note: we don't need the sidebars file to be normalized: it's ok to let // plugin option changes to impact older, versioned sidebars // We don't validate here, assuming the user has already built the version - const sidebars = await loadSidebarsFileUnsafe(sidebarPath); + const sidebars = await loadSidebarsFile(sidebarPath); // Do not create a useless versioned sidebars file if sidebars file is empty // or sidebars are disabled/false) diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/index.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/index.ts index 4bebf0ce50c2..1566ec82175a 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/index.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/index.ts @@ -9,10 +9,9 @@ import fs from 'fs-extra'; import path from 'path'; import _ from 'lodash'; import logger from '@docusaurus/logger'; -import {Globby} from '@docusaurus/utils'; +import {loadFreshModule, Globby} from '@docusaurus/utils'; import Yaml from 'js-yaml'; import combinePromises from 'combine-promises'; -import jiti from 'jiti'; import {validateSidebars, validateCategoryMetadataFile} from './validation'; import {normalizeSidebars} from './normalization'; import {processSidebars} from './processor'; @@ -68,7 +67,7 @@ async function readCategoriesMetadata(contentPath: string) { ); } -export async function loadSidebarsFileUnsafe( +async function loadSidebarsFileUnsafe( sidebarFilePath: string | false | undefined, ): Promise { // false => no sidebars @@ -89,16 +88,19 @@ export async function loadSidebarsFileUnsafe( } // We don't want sidebars to be cached because of hot reloading. - const sidebars = jiti(__filename, { - cache: false, - interopDefault: true, - debug: true, - })(sidebarFilePath); + const module = await loadFreshModule(sidebarFilePath); - sidebarFilePath.endsWith('.ts') && - console.log({sidebarFilePath}, JSON.stringify(sidebars, null, 2)); + // TODO unsafe, need to refactor and improve validation + return module as SidebarsConfig; +} + +export async function loadSidebarsFile( + sidebarFilePath: string | false | undefined, +): Promise { + const sidebars = await loadSidebarsFileUnsafe(sidebarFilePath); - return sidebars; + // TODO unsafe, need to refactor and improve validation + return sidebars as SidebarsConfig; } export async function loadSidebars( diff --git a/packages/docusaurus-types/src/index.d.ts b/packages/docusaurus-types/src/index.d.ts index afb737e96b48..53e83ce96345 100644 --- a/packages/docusaurus-types/src/index.d.ts +++ b/packages/docusaurus-types/src/index.d.ts @@ -52,6 +52,7 @@ export { PluginVersionInformation, Preset, PresetConfig, + PresetConfigDefined, PresetModule, OptionValidationContext, ThemeConfigValidationContext, diff --git a/packages/docusaurus-types/src/plugin.d.ts b/packages/docusaurus-types/src/plugin.d.ts index 482699623d5a..646562df8d9d 100644 --- a/packages/docusaurus-types/src/plugin.d.ts +++ b/packages/docusaurus-types/src/plugin.d.ts @@ -26,11 +26,9 @@ export type PluginConfig = | false | null; -export type PresetConfig = - | string - | [string, {[key: string]: unknown}] - | false - | null; +export type PresetConfigDefined = string | [string, {[key: string]: unknown}]; + +export type PresetConfig = PresetConfigDefined | false | null; /** * - `type: 'package'`, plugin is in a different package. diff --git a/packages/docusaurus-utils/package.json b/packages/docusaurus-utils/package.json index b9ad09ba9873..a9bfd73c9792 100644 --- a/packages/docusaurus-utils/package.json +++ b/packages/docusaurus-utils/package.json @@ -26,6 +26,7 @@ "github-slugger": "^1.5.0", "globby": "^11.1.0", "gray-matter": "^4.0.3", + "jiti": "^1.20.0", "js-yaml": "^4.1.0", "lodash": "^4.17.21", "micromatch": "^4.0.5", diff --git a/packages/docusaurus-utils/src/index.ts b/packages/docusaurus-utils/src/index.ts index fbfe062952d8..d5cabc65301a 100644 --- a/packages/docusaurus-utils/src/index.ts +++ b/packages/docusaurus-utils/src/index.ts @@ -100,6 +100,7 @@ export { } from './globUtils'; export {getFileLoaderUtils} from './webpackUtils'; export {escapeShellArg} from './shellUtils'; +export {loadFreshModule} from './moduleUtils'; export { getDataFilePath, getDataFileData, diff --git a/packages/docusaurus-utils/src/moduleUtils.ts b/packages/docusaurus-utils/src/moduleUtils.ts new file mode 100644 index 000000000000..5b3ffca898e7 --- /dev/null +++ b/packages/docusaurus-utils/src/moduleUtils.ts @@ -0,0 +1,32 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import jiti from 'jiti'; +import logger from '@docusaurus/logger'; + +/* +jiti is able to load ESM, CJS, JSON, TS modules + */ +export async function loadFreshModule(modulePath: string): Promise { + try { + const load = jiti(__filename, { + cache: true, // Transpilation cache, can be safely enabled + requireCache: false, // Bypass Node.js runtime require cache + interopDefault: true, + // debug: true, + }); + + return load(modulePath); + } catch (error) { + throw new Error( + logger.interpolate`Docusaurus could not load module at path=${modulePath}: ${ + (error as Error).message + }}`, + {cause: error}, + ); + } +} diff --git a/packages/docusaurus/package.json b/packages/docusaurus/package.json index a0208d754a96..61158590d8ff 100644 --- a/packages/docusaurus/package.json +++ b/packages/docusaurus/package.json @@ -76,7 +76,6 @@ "html-minifier-terser": "^7.2.0", "html-tags": "^3.3.1", "html-webpack-plugin": "^5.5.3", - "jiti": "^1.20.0", "leven": "^3.1.0", "lodash": "^4.17.21", "mini-css-extract-plugin": "^2.7.6", diff --git a/packages/docusaurus/src/server/config.ts b/packages/docusaurus/src/server/config.ts index 2b7e3a07abfb..ba4e1ed6d966 100644 --- a/packages/docusaurus/src/server/config.ts +++ b/packages/docusaurus/src/server/config.ts @@ -7,9 +7,12 @@ import path from 'path'; import fs from 'fs-extra'; -import jiti from 'jiti'; import logger from '@docusaurus/logger'; -import {DEFAULT_CONFIG_FILE_NAME, findAsyncSequential} from '@docusaurus/utils'; +import { + DEFAULT_CONFIG_FILE_NAME, + findAsyncSequential, + loadFreshModule, +} from '@docusaurus/utils'; import {validateConfig} from './configValidation'; import type {LoadContext} from '@docusaurus/types'; @@ -46,20 +49,12 @@ export async function loadSiteConfig({ throw new Error(`Config file at "${siteConfigPath}" not found.`); } - const importedConfig = jiti(__filename, { - cache: false, - })(siteConfigPath); + const importedConfig = await loadFreshModule(siteConfigPath); - let loadedConfig: unknown; - if (typeof importedConfig === 'function') { - loadedConfig = await importedConfig(); - } else if ( - Object.prototype.toString.call(importedConfig) === '[object Promise]' - ) { - loadedConfig = await importedConfig; - } else { - loadedConfig = importedConfig; - } + const loadedConfig: unknown = + typeof importedConfig === 'function' + ? await importedConfig() + : await importedConfig; const siteConfig = validateConfig( loadedConfig, diff --git a/packages/docusaurus/src/server/plugins/configs.ts b/packages/docusaurus/src/server/plugins/configs.ts index 66411b3f082b..2100dd9be1b7 100644 --- a/packages/docusaurus/src/server/plugins/configs.ts +++ b/packages/docusaurus/src/server/plugins/configs.ts @@ -6,7 +6,7 @@ */ import {createRequire} from 'module'; -import jiti from 'jiti'; +import {loadFreshModule} from '@docusaurus/utils'; import {loadPresets} from './presets'; import {resolveModuleName} from './moduleShorthand'; import type { @@ -61,7 +61,9 @@ async function normalizePluginConfig( if (typeof pluginConfig === 'string') { const pluginModuleImport = pluginConfig; const pluginPath = pluginRequire.resolve(pluginModuleImport); - const pluginModule = jiti(__filename)(pluginPath) as ImportedPluginModule; + const pluginModule = (await loadFreshModule( + pluginPath, + )) as ImportedPluginModule; return { plugin: pluginModule.default ?? pluginModule, options: {}, @@ -88,7 +90,9 @@ async function normalizePluginConfig( if (typeof pluginConfig[0] === 'string') { const pluginModuleImport = pluginConfig[0]; const pluginPath = pluginRequire.resolve(pluginModuleImport); - const pluginModule = jiti(__dirname)(pluginPath) as ImportedPluginModule; + const pluginModule = (await loadFreshModule( + pluginPath, + )) as ImportedPluginModule; return { plugin: pluginModule.default ?? pluginModule, options: pluginConfig[1], diff --git a/packages/docusaurus/src/server/plugins/presets.ts b/packages/docusaurus/src/server/plugins/presets.ts index 070ca7bc4240..f8318ee9a1e1 100644 --- a/packages/docusaurus/src/server/plugins/presets.ts +++ b/packages/docusaurus/src/server/plugins/presets.ts @@ -6,12 +6,13 @@ */ import {createRequire} from 'module'; -import jiti from 'jiti'; +import {loadFreshModule} from '@docusaurus/utils'; import {resolveModuleName} from './moduleShorthand'; import type { LoadContext, - PluginConfig, + PresetConfigDefined, PresetModule, + Preset, DocusaurusConfig, } from '@docusaurus/types'; @@ -28,16 +29,13 @@ export async function loadPresets( // we are using `require.resolve` on those module names. const presetRequire = createRequire(context.siteConfigPath); - const {presets} = context.siteConfig; - const plugins: PluginConfig[] = []; - const themes: PluginConfig[] = []; + const presets = context.siteConfig.presets.filter( + (p): p is PresetConfigDefined => !!p, + ); - presets.forEach((presetItem) => { + async function loadPreset(presetItem: PresetConfigDefined): Promise { let presetModuleImport: string; let presetOptions = {}; - if (!presetItem) { - return; - } if (typeof presetItem === 'string') { presetModuleImport = presetItem; } else { @@ -50,19 +48,19 @@ export async function loadPresets( ); const presetPath = presetRequire.resolve(presetName); - const presetModule = jiti(__filename)(presetPath) as ImportedPresetModule; - const preset = (presetModule.default ?? presetModule)( - context, - presetOptions, - ); + const presetModule = (await loadFreshModule( + presetPath, + )) as ImportedPresetModule; - if (preset.plugins) { - plugins.push(...preset.plugins); - } - if (preset.themes) { - themes.push(...preset.themes); - } - }); + const presetFunction = presetModule.default ?? presetModule; + + return presetFunction(context, presetOptions); + } + + const loadedPresets = await Promise.all(presets.map(loadPreset)); + + const plugins = loadedPresets.flatMap((preset) => preset.plugins ?? []); + const themes = loadedPresets.flatMap((preset) => preset.themes ?? []); return {plugins, themes}; } From 7af9f729794b3fee163afe9c72439328fa067204 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Fri, 13 Oct 2023 12:48:57 +0200 Subject: [PATCH 11/46] Add more loadSiteConfig test fixtures --- .../__fixtures__/config/configCJS.js | 12 + .../__fixtures__/config/configCJS.ts | 14 ++ .../__fixtures__/config/configESM.js | 12 + .../__fixtures__/config/configESM.ts | 14 ++ .../config/configTypescript.config.ts | 7 - .../__snapshots__/config.test.ts.snap | 210 +++++++++++++++--- .../src/server/__tests__/config.test.ts | 31 ++- 7 files changed, 258 insertions(+), 42 deletions(-) create mode 100644 packages/docusaurus/src/server/__tests__/__fixtures__/config/configCJS.js create mode 100644 packages/docusaurus/src/server/__tests__/__fixtures__/config/configCJS.ts create mode 100644 packages/docusaurus/src/server/__tests__/__fixtures__/config/configESM.js create mode 100644 packages/docusaurus/src/server/__tests__/__fixtures__/config/configESM.ts delete mode 100644 packages/docusaurus/src/server/__tests__/__fixtures__/config/configTypescript.config.ts diff --git a/packages/docusaurus/src/server/__tests__/__fixtures__/config/configCJS.js b/packages/docusaurus/src/server/__tests__/__fixtures__/config/configCJS.js new file mode 100644 index 000000000000..0a57bd7fade6 --- /dev/null +++ b/packages/docusaurus/src/server/__tests__/__fixtures__/config/configCJS.js @@ -0,0 +1,12 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +module.exports = { + title: 'title', + url: 'https://example.com', + baseUrl: '/', +} diff --git a/packages/docusaurus/src/server/__tests__/__fixtures__/config/configCJS.ts b/packages/docusaurus/src/server/__tests__/__fixtures__/config/configCJS.ts new file mode 100644 index 000000000000..2a63438819ed --- /dev/null +++ b/packages/docusaurus/src/server/__tests__/__fixtures__/config/configCJS.ts @@ -0,0 +1,14 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import type {Config} from '@docusaurus/types'; + +module.exports = { + title: 'title', + url: 'https://example.com', + baseUrl: '/', +} satisfies Config; diff --git a/packages/docusaurus/src/server/__tests__/__fixtures__/config/configESM.js b/packages/docusaurus/src/server/__tests__/__fixtures__/config/configESM.js new file mode 100644 index 000000000000..307aff266bc2 --- /dev/null +++ b/packages/docusaurus/src/server/__tests__/__fixtures__/config/configESM.js @@ -0,0 +1,12 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +export default { + title: 'title', + url: 'https://example.com', + baseUrl: '/', +} diff --git a/packages/docusaurus/src/server/__tests__/__fixtures__/config/configESM.ts b/packages/docusaurus/src/server/__tests__/__fixtures__/config/configESM.ts new file mode 100644 index 000000000000..8530617239be --- /dev/null +++ b/packages/docusaurus/src/server/__tests__/__fixtures__/config/configESM.ts @@ -0,0 +1,14 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import type {Config} from '@docusaurus/types'; + +export default { + title: 'title', + url: 'https://example.com', + baseUrl: '/', +} satisfies Config; diff --git a/packages/docusaurus/src/server/__tests__/__fixtures__/config/configTypescript.config.ts b/packages/docusaurus/src/server/__tests__/__fixtures__/config/configTypescript.config.ts deleted file mode 100644 index c9118f7c7c8e..000000000000 --- a/packages/docusaurus/src/server/__tests__/__fixtures__/config/configTypescript.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type {Config} from '@docusaurus/types'; - -module.exports = { - title: 'title', - url: 'https://example.com', - baseUrl: '/' -} as Config; 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 9a91bf16c256..4dfe3e06100b 100644 --- a/packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap +++ b/packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap @@ -48,7 +48,7 @@ exports[`loadSiteConfig website with .cjs siteConfig 1`] = ` } `; -exports[`loadSiteConfig website with valid async config 1`] = ` +exports[`loadSiteConfig website with valid JS CJS config 1`] = ` { "siteConfig": { "baseUrl": "/", @@ -78,27 +78,169 @@ exports[`loadSiteConfig website with valid async config 1`] = ` "onBrokenLinks": "throw", "onBrokenMarkdownLinks": "warn", "onDuplicateRoutes": "warn", - "organizationName": "endiliey", "plugins": [], "presets": [], - "projectName": "hello", "scripts": [], "staticDirectories": [ "static", ], "stylesheets": [], - "tagline": "Hello World", + "tagline": "", "themeConfig": {}, "themes": [], - "title": "Hello", + "title": "title", "titleDelimiter": "|", - "url": "https://docusaurus.io", + "url": "https://example.com", }, - "siteConfigPath": "/packages/docusaurus/src/server/__tests__/__fixtures__/config/configAsync.config.js", + "siteConfigPath": "/packages/docusaurus/src/server/__tests__/__fixtures__/config/configCJS.js", } `; -exports[`loadSiteConfig website with valid async config creator function 1`] = ` +exports[`loadSiteConfig website with valid JS ESM config 1`] = ` +{ + "siteConfig": { + "baseUrl": "/", + "baseUrlIssueBanner": true, + "clientModules": [], + "customFields": {}, + "headTags": [], + "i18n": { + "defaultLocale": "en", + "localeConfigs": {}, + "locales": [ + "en", + ], + "path": "i18n", + }, + "markdown": { + "format": "mdx", + "mdx1Compat": { + "admonitions": true, + "comments": true, + "headingIds": true, + }, + "mermaid": false, + "preprocessor": undefined, + }, + "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/configESM.js", +} +`; + +exports[`loadSiteConfig website with valid TypeScript CJS config 1`] = ` +{ + "siteConfig": { + "baseUrl": "/", + "baseUrlIssueBanner": true, + "clientModules": [], + "customFields": {}, + "headTags": [], + "i18n": { + "defaultLocale": "en", + "localeConfigs": {}, + "locales": [ + "en", + ], + "path": "i18n", + }, + "markdown": { + "format": "mdx", + "mdx1Compat": { + "admonitions": true, + "comments": true, + "headingIds": true, + }, + "mermaid": false, + "preprocessor": undefined, + }, + "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/configCJS.ts", +} +`; + +exports[`loadSiteConfig website with valid TypeScript ESM config 1`] = ` +{ + "siteConfig": { + "baseUrl": "/", + "baseUrlIssueBanner": true, + "clientModules": [], + "customFields": {}, + "headTags": [], + "i18n": { + "defaultLocale": "en", + "localeConfigs": {}, + "locales": [ + "en", + ], + "path": "i18n", + }, + "markdown": { + "format": "mdx", + "mdx1Compat": { + "admonitions": true, + "comments": true, + "headingIds": true, + }, + "mermaid": false, + "preprocessor": undefined, + }, + "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/configESM.ts", +} +`; + +exports[`loadSiteConfig website with valid async config 1`] = ` { "siteConfig": { "baseUrl": "/", @@ -144,11 +286,11 @@ exports[`loadSiteConfig website with valid async config creator function 1`] = ` "titleDelimiter": "|", "url": "https://docusaurus.io", }, - "siteConfigPath": "/packages/docusaurus/src/server/__tests__/__fixtures__/config/createConfigAsync.config.js", + "siteConfigPath": "/packages/docusaurus/src/server/__tests__/__fixtures__/config/configAsync.config.js", } `; -exports[`loadSiteConfig website with valid config creator function 1`] = ` +exports[`loadSiteConfig website with valid async config creator function 1`] = ` { "siteConfig": { "baseUrl": "/", @@ -194,20 +336,17 @@ exports[`loadSiteConfig website with valid config creator function 1`] = ` "titleDelimiter": "|", "url": "https://docusaurus.io", }, - "siteConfigPath": "/packages/docusaurus/src/server/__tests__/__fixtures__/config/createConfig.config.js", + "siteConfigPath": "/packages/docusaurus/src/server/__tests__/__fixtures__/config/createConfigAsync.config.js", } `; -exports[`loadSiteConfig website with valid siteConfig 1`] = ` +exports[`loadSiteConfig website with valid config creator function 1`] = ` { "siteConfig": { "baseUrl": "/", "baseUrlIssueBanner": true, - "clientModules": [ - "foo.js", - ], + "clientModules": [], "customFields": {}, - "favicon": "img/docusaurus.ico", "headTags": [], "i18n": { "defaultLocale": "en", @@ -232,15 +371,7 @@ exports[`loadSiteConfig website with valid siteConfig 1`] = ` "onBrokenMarkdownLinks": "warn", "onDuplicateRoutes": "warn", "organizationName": "endiliey", - "plugins": [ - [ - "@docusaurus/plugin-content-docs", - { - "path": "../docs", - }, - ], - "@docusaurus/plugin-content-pages", - ], + "plugins": [], "presets": [], "projectName": "hello", "scripts": [], @@ -255,17 +386,20 @@ exports[`loadSiteConfig website with valid siteConfig 1`] = ` "titleDelimiter": "|", "url": "https://docusaurus.io", }, - "siteConfigPath": "/packages/docusaurus/src/server/__tests__/__fixtures__/simple-site/docusaurus.config.js", + "siteConfigPath": "/packages/docusaurus/src/server/__tests__/__fixtures__/config/createConfig.config.js", } `; -exports[`loadSiteConfig website with valid typescript config 1`] = ` +exports[`loadSiteConfig website with valid siteConfig 1`] = ` { "siteConfig": { "baseUrl": "/", "baseUrlIssueBanner": true, - "clientModules": [], + "clientModules": [ + "foo.js", + ], "customFields": {}, + "favicon": "img/docusaurus.ico", "headTags": [], "i18n": { "defaultLocale": "en", @@ -289,20 +423,30 @@ exports[`loadSiteConfig website with valid typescript config 1`] = ` "onBrokenLinks": "throw", "onBrokenMarkdownLinks": "warn", "onDuplicateRoutes": "warn", - "plugins": [], + "organizationName": "endiliey", + "plugins": [ + [ + "@docusaurus/plugin-content-docs", + { + "path": "../docs", + }, + ], + "@docusaurus/plugin-content-pages", + ], "presets": [], + "projectName": "hello", "scripts": [], "staticDirectories": [ "static", ], "stylesheets": [], - "tagline": "", + "tagline": "Hello World", "themeConfig": {}, "themes": [], - "title": "title", + "title": "Hello", "titleDelimiter": "|", - "url": "https://example.com", + "url": "https://docusaurus.io", }, - "siteConfigPath": "/packages/docusaurus/src/server/__tests__/__fixtures__/config/configTypescript.config.ts", + "siteConfigPath": "/packages/docusaurus/src/server/__tests__/__fixtures__/simple-site/docusaurus.config.js", } `; diff --git a/packages/docusaurus/src/server/__tests__/config.test.ts b/packages/docusaurus/src/server/__tests__/config.test.ts index 7967cd26dfdd..a5f9b75c0a92 100644 --- a/packages/docusaurus/src/server/__tests__/config.test.ts +++ b/packages/docusaurus/src/server/__tests__/config.test.ts @@ -52,10 +52,37 @@ describe('loadSiteConfig', () => { expect(config).not.toEqual({}); }); - it('website with valid typescript config', async () => { + it('website with valid JS CJS config', async () => { const config = await loadSiteConfig({ siteDir, - customConfigFilePath: 'configTypescript.config.ts', + customConfigFilePath: 'configCJS.js', + }); + expect(config).toMatchSnapshot(); + expect(config).not.toEqual({}); + }); + + it('website with valid JS ESM config', async () => { + const config = await loadSiteConfig({ + siteDir, + customConfigFilePath: 'configESM.js', + }); + expect(config).toMatchSnapshot(); + expect(config).not.toEqual({}); + }); + + it('website with valid TypeScript CJS config', async () => { + const config = await loadSiteConfig({ + siteDir, + customConfigFilePath: 'configCJS.ts', + }); + expect(config).toMatchSnapshot(); + expect(config).not.toEqual({}); + }); + + it('website with valid TypeScript ESM config', async () => { + const config = await loadSiteConfig({ + siteDir, + customConfigFilePath: 'configESM.ts', }); expect(config).toMatchSnapshot(); expect(config).not.toEqual({}); From 1e4d95ef28d050a2471ca7b36817b3abcc283a68 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Fri, 13 Oct 2023 14:39:00 +0200 Subject: [PATCH 12/46] scaffold loadFreshModule tests --- .../__fixtures__/moduleUtils/user/user.cjs.js | 7 ++ .../src/__tests__/moduleUtils.test.ts | 105 ++++++++++++++++++ packages/docusaurus-utils/src/moduleUtils.ts | 19 +++- 3 files changed, 127 insertions(+), 4 deletions(-) create mode 100644 packages/docusaurus-utils/src/__tests__/__fixtures__/moduleUtils/user/user.cjs.js create mode 100644 packages/docusaurus-utils/src/__tests__/moduleUtils.test.ts diff --git a/packages/docusaurus-utils/src/__tests__/__fixtures__/moduleUtils/user/user.cjs.js b/packages/docusaurus-utils/src/__tests__/__fixtures__/moduleUtils/user/user.cjs.js new file mode 100644 index 000000000000..4a19b89b7d15 --- /dev/null +++ b/packages/docusaurus-utils/src/__tests__/__fixtures__/moduleUtils/user/user.cjs.js @@ -0,0 +1,7 @@ +exports.someNamedExport = 52; + +module.exports = { + firstName: 'Sebastien', + lastName: 'Lorber', + birthYear: 1986, +}; diff --git a/packages/docusaurus-utils/src/__tests__/moduleUtils.test.ts b/packages/docusaurus-utils/src/__tests__/moduleUtils.test.ts new file mode 100644 index 000000000000..fdccb23d08af --- /dev/null +++ b/packages/docusaurus-utils/src/__tests__/moduleUtils.test.ts @@ -0,0 +1,105 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import fs from 'fs-extra'; +import path from 'path'; +import tmp from 'tmp-promise'; +import {loadFreshModule} from '../moduleUtils'; + +async function createTmpDir() { + return ( + await tmp.dir({ + prefix: 'jest-tmp-moduleUtils-tests', + }) + ).path; +} + +async function createModuleFile(content: string) { + const siteDir = await createTmpDir(); + const filePath = path.join(siteDir, 'i18n/en/code.json'); + await fs.outputFile(filePath, JSON.stringify(content, null, 2)); +} + +async function loadFixtureModule(fixtureName: string) { + return loadFreshModule( + path.resolve(__dirname, '__fixtures__/moduleUtils', fixtureName), + ); +} + +describe('loadFreshModule', () => { + describe('can load fresh module', () => { + it('todo', async () => { + createModuleFile(''); + }); + }); + + describe('can load user module', () => { + async function testUserFixture(fixtureName: string) { + const userFixturePath = `user/${fixtureName}`; + const userModule = await loadFixtureModule(userFixturePath); + expect(userModule).toEqual({ + birthYear: 1986, + firstName: 'Sebastien', + lastName: 'Lorber', + }); + } + + it('with CJS', async () => { + await testUserFixture('user.cjs.js'); + }); + }); + + describe('using invalid module path param', () => { + it('throws if module path does not exist', async () => { + await expect(() => loadFreshModule('/some/unknown/module/path.js')) + .rejects.toThrowErrorMatchingInlineSnapshot(` + "Docusaurus could not load module at path "/some/unknown/module/path.js" + Cause: Cannot find module '/some/unknown/module/path.js' from 'packages/docusaurus-utils/src/moduleUtils.ts'" + `); + }); + + it('throws if module path is undefined', async () => { + await expect(() => + // @ts-expect-error: undefined is invalid + loadFreshModule(undefined), + ).rejects.toThrowErrorMatchingInlineSnapshot(` + "Docusaurus could not load module at path "undefined" + Cause: Invalid module path of type undefined" + `); + }); + + it('throws if module path is null', async () => { + await expect(() => + // @ts-expect-error: null is invalid + loadFreshModule(null), + ).rejects.toThrowErrorMatchingInlineSnapshot(` + "Docusaurus could not load module at path "null" + Cause: Invalid module path of type null" + `); + }); + + it('throws if module path is number', async () => { + await expect(() => + // @ts-expect-error: number is invalid + loadFreshModule(42), + ).rejects.toThrowErrorMatchingInlineSnapshot(` + "Docusaurus could not load module at path "42" + Cause: Invalid module path of type 42" + `); + }); + + it('throws if module path is object', async () => { + await expect(() => + // @ts-expect-error: object is invalid + loadFreshModule({}), + ).rejects.toThrowErrorMatchingInlineSnapshot(` + "Docusaurus could not load module at path "[object Object]" + Cause: Invalid module path of type [object Object]" + `); + }); + }); +}); diff --git a/packages/docusaurus-utils/src/moduleUtils.ts b/packages/docusaurus-utils/src/moduleUtils.ts index 5b3ffca898e7..e7adaf9880e5 100644 --- a/packages/docusaurus-utils/src/moduleUtils.ts +++ b/packages/docusaurus-utils/src/moduleUtils.ts @@ -13,9 +13,20 @@ jiti is able to load ESM, CJS, JSON, TS modules */ export async function loadFreshModule(modulePath: string): Promise { try { + if (typeof modulePath !== 'string') { + throw new Error( + logger.interpolate`Invalid module path of type name=${modulePath}`, + ); + } const load = jiti(__filename, { - cache: true, // Transpilation cache, can be safely enabled - requireCache: false, // Bypass Node.js runtime require cache + // Transpilation cache, can be safely enabled + cache: true, + // Bypass Node.js runtime require cache + // Same as "import-fresh" package we used previously + requireCache: false, + // Only take into consideration the default export + // For now we don't need named exports + // This also helps normalize return value for both CJS/ESM/TS modules interopDefault: true, // debug: true, }); @@ -23,9 +34,9 @@ export async function loadFreshModule(modulePath: string): Promise { return load(modulePath); } catch (error) { throw new Error( - logger.interpolate`Docusaurus could not load module at path=${modulePath}: ${ + logger.interpolate`Docusaurus could not load module at path path=${modulePath}\nCause: ${ (error as Error).message - }}`, + }`, {cause: error}, ); } From 2c4a2e74dc89b7589e3fb8f7677ad99c3a3f6ac5 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Fri, 13 Oct 2023 14:48:07 +0200 Subject: [PATCH 13/46] loadFreshModule tests for CJS / ESM --- .../__fixtures__/moduleUtils/user/user.cjs | 7 ++++ .../__fixtures__/moduleUtils/user/user.cjs.js | 2 +- .../__fixtures__/moduleUtils/user/user.cjs.ts | 11 ++++++ .../__fixtures__/moduleUtils/user/user.esm.js | 7 ++++ .../__fixtures__/moduleUtils/user/user.esm.ts | 11 ++++++ .../__fixtures__/moduleUtils/user/user.mjs | 7 ++++ .../src/__tests__/moduleUtils.test.ts | 37 ++++++++++++++++++- 7 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 packages/docusaurus-utils/src/__tests__/__fixtures__/moduleUtils/user/user.cjs create mode 100644 packages/docusaurus-utils/src/__tests__/__fixtures__/moduleUtils/user/user.cjs.ts create mode 100644 packages/docusaurus-utils/src/__tests__/__fixtures__/moduleUtils/user/user.esm.js create mode 100644 packages/docusaurus-utils/src/__tests__/__fixtures__/moduleUtils/user/user.esm.ts create mode 100644 packages/docusaurus-utils/src/__tests__/__fixtures__/moduleUtils/user/user.mjs diff --git a/packages/docusaurus-utils/src/__tests__/__fixtures__/moduleUtils/user/user.cjs b/packages/docusaurus-utils/src/__tests__/__fixtures__/moduleUtils/user/user.cjs new file mode 100644 index 000000000000..394d1bb4ce56 --- /dev/null +++ b/packages/docusaurus-utils/src/__tests__/__fixtures__/moduleUtils/user/user.cjs @@ -0,0 +1,7 @@ +exports.someNamedExport = 42; + +module.exports = { + firstName: 'Sebastien', + lastName: 'Lorber', + birthYear: 1986, +}; diff --git a/packages/docusaurus-utils/src/__tests__/__fixtures__/moduleUtils/user/user.cjs.js b/packages/docusaurus-utils/src/__tests__/__fixtures__/moduleUtils/user/user.cjs.js index 4a19b89b7d15..394d1bb4ce56 100644 --- a/packages/docusaurus-utils/src/__tests__/__fixtures__/moduleUtils/user/user.cjs.js +++ b/packages/docusaurus-utils/src/__tests__/__fixtures__/moduleUtils/user/user.cjs.js @@ -1,4 +1,4 @@ -exports.someNamedExport = 52; +exports.someNamedExport = 42; module.exports = { firstName: 'Sebastien', diff --git a/packages/docusaurus-utils/src/__tests__/__fixtures__/moduleUtils/user/user.cjs.ts b/packages/docusaurus-utils/src/__tests__/__fixtures__/moduleUtils/user/user.cjs.ts new file mode 100644 index 000000000000..7b4798aa9093 --- /dev/null +++ b/packages/docusaurus-utils/src/__tests__/__fixtures__/moduleUtils/user/user.cjs.ts @@ -0,0 +1,11 @@ +exports.someNamedExport = 42 as number; + +module.exports = { + firstName: 'Sebastien', + lastName: 'Lorber', + birthYear: 1986, +} satisfies { + firstName: string; + lastName: string; + birthYear: number; +}; diff --git a/packages/docusaurus-utils/src/__tests__/__fixtures__/moduleUtils/user/user.esm.js b/packages/docusaurus-utils/src/__tests__/__fixtures__/moduleUtils/user/user.esm.js new file mode 100644 index 000000000000..82912ee03082 --- /dev/null +++ b/packages/docusaurus-utils/src/__tests__/__fixtures__/moduleUtils/user/user.esm.js @@ -0,0 +1,7 @@ +export const someNamedExport = 42; + +export default { + firstName: 'Sebastien', + lastName: 'Lorber', + birthYear: 1986, +}; diff --git a/packages/docusaurus-utils/src/__tests__/__fixtures__/moduleUtils/user/user.esm.ts b/packages/docusaurus-utils/src/__tests__/__fixtures__/moduleUtils/user/user.esm.ts new file mode 100644 index 000000000000..af7241e542b2 --- /dev/null +++ b/packages/docusaurus-utils/src/__tests__/__fixtures__/moduleUtils/user/user.esm.ts @@ -0,0 +1,11 @@ +export const someNamedExport: number = 42; + +export default { + firstName: 'Sebastien', + lastName: 'Lorber', + birthYear: 1986, +} satisfies { + firstName: string; + lastName: string; + birthYear: number; +}; diff --git a/packages/docusaurus-utils/src/__tests__/__fixtures__/moduleUtils/user/user.mjs b/packages/docusaurus-utils/src/__tests__/__fixtures__/moduleUtils/user/user.mjs new file mode 100644 index 000000000000..82912ee03082 --- /dev/null +++ b/packages/docusaurus-utils/src/__tests__/__fixtures__/moduleUtils/user/user.mjs @@ -0,0 +1,7 @@ +export const someNamedExport = 42; + +export default { + firstName: 'Sebastien', + lastName: 'Lorber', + birthYear: 1986, +}; diff --git a/packages/docusaurus-utils/src/__tests__/moduleUtils.test.ts b/packages/docusaurus-utils/src/__tests__/moduleUtils.test.ts index fdccb23d08af..c628c141fdc0 100644 --- a/packages/docusaurus-utils/src/__tests__/moduleUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/moduleUtils.test.ts @@ -37,7 +37,7 @@ describe('loadFreshModule', () => { }); }); - describe('can load user module', () => { + describe('can load CJS user module', () => { async function testUserFixture(fixtureName: string) { const userFixturePath = `user/${fixtureName}`; const userModule = await loadFixtureModule(userFixturePath); @@ -48,9 +48,42 @@ describe('loadFreshModule', () => { }); } - it('with CJS', async () => { + it('for .cjs.js', async () => { await testUserFixture('user.cjs.js'); }); + + it('for .cjs.ts', async () => { + await testUserFixture('user.cjs.ts'); + }); + + it('for .cjs', async () => { + await testUserFixture('user.cjs'); + }); + }); + + describe('can load ESM user module', () => { + async function testUserFixture(fixtureName: string) { + const userFixturePath = `user/${fixtureName}`; + const userModule = await loadFixtureModule(userFixturePath); + expect(userModule).toEqual({ + birthYear: 1986, + firstName: 'Sebastien', + lastName: 'Lorber', + someNamedExport: 42, + }); + } + + it('for .esm.js', async () => { + await testUserFixture('user.esm.js'); + }); + + it('for .esm.ts', async () => { + await testUserFixture('user.esm.ts'); + }); + + it('for .mjs', async () => { + await testUserFixture('user.mjs'); + }); }); describe('using invalid module path param', () => { From 2f522b21e5fdf3476f2fb43ec6cb7e36220d1af7 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Fri, 13 Oct 2023 15:25:42 +0200 Subject: [PATCH 14/46] add loadFreshModule tests --- packages/docusaurus-utils/package.json | 3 +- .../src/__tests__/moduleUtils.test.ts | 173 ++++++++++++++++-- 2 files changed, 164 insertions(+), 12 deletions(-) diff --git a/packages/docusaurus-utils/package.json b/packages/docusaurus-utils/package.json index a9bfd73c9792..f5f757e5673c 100644 --- a/packages/docusaurus-utils/package.json +++ b/packages/docusaurus-utils/package.json @@ -45,7 +45,8 @@ "@types/github-slugger": "^1.3.0", "@types/micromatch": "^4.0.2", "@types/react-dom": "^18.2.7", - "dedent": "^0.7.0" + "dedent": "^0.7.0", + "tmp-promise": "^3.0.3" }, "peerDependencies": { "@docusaurus/types": "*" diff --git a/packages/docusaurus-utils/src/__tests__/moduleUtils.test.ts b/packages/docusaurus-utils/src/__tests__/moduleUtils.test.ts index c628c141fdc0..653667292a9a 100644 --- a/packages/docusaurus-utils/src/__tests__/moduleUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/moduleUtils.test.ts @@ -8,6 +8,7 @@ import fs from 'fs-extra'; import path from 'path'; import tmp from 'tmp-promise'; +import dedent from 'dedent'; import {loadFreshModule} from '../moduleUtils'; async function createTmpDir() { @@ -18,10 +19,22 @@ async function createTmpDir() { ).path; } -async function createModuleFile(content: string) { - const siteDir = await createTmpDir(); - const filePath = path.join(siteDir, 'i18n/en/code.json'); - await fs.outputFile(filePath, JSON.stringify(content, null, 2)); +async function moduleGraphHelpers() { + const dir = await createTmpDir(); + + async function fileHelper(name: string, initialContent?: string) { + const filePath = path.resolve(dir, name); + if (initialContent) { + await fs.outputFile(filePath, initialContent); + } + return { + filePath, + write: (content: string) => fs.outputFile(filePath, content), + load: () => loadFreshModule(filePath), + }; + } + + return {fileHelper}; } async function loadFixtureModule(fixtureName: string) { @@ -31,12 +44,6 @@ async function loadFixtureModule(fixtureName: string) { } describe('loadFreshModule', () => { - describe('can load fresh module', () => { - it('todo', async () => { - createModuleFile(''); - }); - }); - describe('can load CJS user module', () => { async function testUserFixture(fixtureName: string) { const userFixturePath = `user/${fixtureName}`; @@ -86,7 +93,151 @@ describe('loadFreshModule', () => { }); }); - describe('using invalid module path param', () => { + describe('module graph', () => { + it('can load and reload fresh module graph', async () => { + const {fileHelper} = await moduleGraphHelpers(); + + const dependency1 = await fileHelper( + 'dependency1.js', + /* language=js */ + dedent` + export const dep1Export = "dep1 val1"; + + export default {dep1Val: "dep1 val2"} + `, + ); + + const dependency2 = await fileHelper( + 'dependency2.ts', + /* language=ts */ + dedent` + export default {dep2Val: "dep2 val"} satisfies {dep2Val: string} + `, + ); + + const entryFile = await fileHelper( + 'entry.js', + /* language=js */ + dedent` + import dependency1 from "./dependency1"; + import dependency2 from "./dependency2"; + + export default { + someEntryValue: "entryVal", + dependency1, + dependency2 + }; + `, + ); + + // Should be able to read the initial module graph + await expect(entryFile.load()).resolves.toEqual({ + someEntryValue: 'entryVal', + dependency1: { + dep1Export: 'dep1 val1', + dep1Val: 'dep1 val2', + }, + dependency2: { + dep2Val: 'dep2 val', + }, + }); + await expect(dependency1.load()).resolves.toEqual({ + dep1Export: 'dep1 val1', + dep1Val: 'dep1 val2', + }); + await expect(dependency2.load()).resolves.toEqual({ + dep2Val: 'dep2 val', + }); + + // Should be able to read the module graph again after updates + await dependency1.write( + /* language=js */ + dedent` + export const dep1Export = "dep1 val1 updated"; + + export default {dep1Val: "dep1 val2 updated"} + `, + ); + await expect(entryFile.load()).resolves.toEqual({ + someEntryValue: 'entryVal', + dependency1: { + dep1Export: 'dep1 val1 updated', + dep1Val: 'dep1 val2 updated', + }, + dependency2: { + dep2Val: 'dep2 val', + }, + }); + await expect(dependency1.load()).resolves.toEqual({ + dep1Export: 'dep1 val1 updated', + dep1Val: 'dep1 val2 updated', + }); + await expect(dependency2.load()).resolves.toEqual({ + dep2Val: 'dep2 val', + }); + + // Should be able to read the module graph again after updates + await dependency2.write( + /* language=ts */ + dedent` + export default {dep2Val: "dep2 val updated"} satisfies {dep2Val: string} + `, + ); + await expect(entryFile.load()).resolves.toEqual({ + someEntryValue: 'entryVal', + dependency1: { + dep1Export: 'dep1 val1 updated', + dep1Val: 'dep1 val2 updated', + }, + dependency2: { + dep2Val: 'dep2 val updated', + }, + }); + await expect(dependency1.load()).resolves.toEqual({ + dep1Export: 'dep1 val1 updated', + dep1Val: 'dep1 val2 updated', + }); + await expect(dependency2.load()).resolves.toEqual({ + dep2Val: 'dep2 val updated', + }); + + // Should be able to read the module graph again after updates + await entryFile.write( + /* language=js */ + dedent` + import dependency1 from "./dependency1"; + import dependency2 from "./dependency2"; + + export default { + someEntryValue: "entryVal updated", + dependency1, + dependency2, + newAttribute: "is there" + } + `, + ); + await expect(entryFile.load()).resolves.toEqual({ + someEntryValue: 'entryVal updated', + newAttribute: 'is there', + dependency1: { + dep1Export: 'dep1 val1 updated', + dep1Val: 'dep1 val2 updated', + }, + dependency2: { + dep2Val: 'dep2 val updated', + }, + }); + await expect(dependency1.load()).resolves.toEqual({ + dep1Export: 'dep1 val1 updated', + dep1Val: 'dep1 val2 updated', + }); + await expect(dependency2.load()).resolves.toEqual({ + dep2Val: 'dep2 val updated', + }); + }); + }); + + describe('invalid module path param', () => { it('throws if module path does not exist', async () => { await expect(() => loadFreshModule('/some/unknown/module/path.js')) .rejects.toThrowErrorMatchingInlineSnapshot(` From 5468bf9dff3bc9c6884f9f296ced1205253eb26d Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Fri, 13 Oct 2023 16:45:18 +0200 Subject: [PATCH 15/46] Migrate templates to ESM --- .../templates/classic/docusaurus.config.js | 11 ++++------- .../create-docusaurus/templates/shared/sidebars.js | 2 +- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/packages/create-docusaurus/templates/classic/docusaurus.config.js b/packages/create-docusaurus/templates/classic/docusaurus.config.js index 12d5019f3505..e4b2ca622375 100644 --- a/packages/create-docusaurus/templates/classic/docusaurus.config.js +++ b/packages/create-docusaurus/templates/classic/docusaurus.config.js @@ -4,10 +4,7 @@ // There are various equivalent ways to declare your Docusaurus config. // See: https://docusaurus.io/docs/api/docusaurus-config -const {themes} = require('prism-react-renderer'); - -const lightCodeTheme = themes.github; -const darkCodeTheme = themes.dracula; +import {themes as prismThemes} from 'prism-react-renderer'; /** @type {import('@docusaurus/types').Config} */ const config = { @@ -135,10 +132,10 @@ const config = { copyright: `Copyright © ${new Date().getFullYear()} My Project, Inc. Built with Docusaurus.`, }, prism: { - theme: lightCodeTheme, - darkTheme: darkCodeTheme, + theme: prismThemes.github, + darkTheme: prismThemes.dracula, }, }), }; -module.exports = config; +export default config; diff --git a/packages/create-docusaurus/templates/shared/sidebars.js b/packages/create-docusaurus/templates/shared/sidebars.js index 9ab54c2459c4..332758032214 100644 --- a/packages/create-docusaurus/templates/shared/sidebars.js +++ b/packages/create-docusaurus/templates/shared/sidebars.js @@ -30,4 +30,4 @@ const sidebars = { */ }; -module.exports = sidebars; +export default sidebars; From d1876454b94be322cb891845522f3dea35fd0a74 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Fri, 13 Oct 2023 17:08:42 +0200 Subject: [PATCH 16/46] Refactor init templates to ESM + TS --- packages/create-docusaurus/src/index.ts | 11 -- .../classic-typescript/docusaurus.config.ts | 133 ++++++++++++++++++ .../templates/classic-typescript/sidebars.ts | 31 ++++ .../HomepageFeatures/styles.module.css | 1 - .../src/pages/index.module.css | 1 - .../templates/classic/docusaurus.config.js | 4 +- .../templates/{shared => classic}/sidebars.js | 0 .../HomepageFeatures/styles.module.css | 0 .../{classic => shared}/src/css/custom.css | 0 .../src/pages/index.module.css | 0 packages/docusaurus/src/server/config.ts | 2 +- 11 files changed, 167 insertions(+), 16 deletions(-) create mode 100644 packages/create-docusaurus/templates/classic-typescript/docusaurus.config.ts create mode 100644 packages/create-docusaurus/templates/classic-typescript/sidebars.ts delete mode 120000 packages/create-docusaurus/templates/classic-typescript/src/components/HomepageFeatures/styles.module.css delete mode 120000 packages/create-docusaurus/templates/classic-typescript/src/pages/index.module.css rename packages/create-docusaurus/templates/{shared => classic}/sidebars.js (100%) rename packages/create-docusaurus/templates/{classic => shared}/src/components/HomepageFeatures/styles.module.css (100%) rename packages/create-docusaurus/templates/{classic => shared}/src/css/custom.css (100%) rename packages/create-docusaurus/templates/{classic => shared}/src/pages/index.module.css (100%) diff --git a/packages/create-docusaurus/src/index.ts b/packages/create-docusaurus/src/index.ts index f41121d686f7..f216e3651c47 100755 --- a/packages/create-docusaurus/src/index.ts +++ b/packages/create-docusaurus/src/index.ts @@ -157,17 +157,6 @@ async function copyTemplate( ): Promise { await fs.copy(path.join(templatesDir, 'shared'), dest); - // TypeScript variants will copy duplicate resources like CSS & config from - // base template - if (typescript) { - await fs.copy(template.path, dest, { - filter: async (filePath) => - (await fs.stat(filePath)).isDirectory() || - path.extname(filePath) === '.css' || - path.basename(filePath) === 'docusaurus.config.js', - }); - } - await fs.copy(typescript ? template.tsVariantPath! : template.path, dest, { // Symlinks don't exist in published npm packages anymore, so this is only // to prevent errors during local testing diff --git a/packages/create-docusaurus/templates/classic-typescript/docusaurus.config.ts b/packages/create-docusaurus/templates/classic-typescript/docusaurus.config.ts new file mode 100644 index 000000000000..4058eac59e23 --- /dev/null +++ b/packages/create-docusaurus/templates/classic-typescript/docusaurus.config.ts @@ -0,0 +1,133 @@ +import {themes as prismThemes} from 'prism-react-renderer'; +import type {Config} from '@docusaurus/types'; +import type * as Preset from '@docusaurus/preset-classic'; + +const config: Config = { + title: 'My Site', + tagline: 'Dinosaurs are cool', + favicon: 'img/favicon.ico', + + // Set the production url of your site here + url: 'https://your-docusaurus-site.example.com', + // Set the // pathname under which your site is served + // For GitHub pages deployment, it is often '//' + baseUrl: '/', + + // GitHub pages deployment config. + // If you aren't using GitHub pages, you don't need these. + organizationName: 'facebook', // Usually your GitHub org/user name. + projectName: 'docusaurus', // Usually your repo name. + + onBrokenLinks: 'throw', + onBrokenMarkdownLinks: 'warn', + + // Even if you don't use internationalization, you can use this field to set + // useful metadata like html lang. For example, if your site is Chinese, you + // may want to replace "en" with "zh-Hans". + i18n: { + defaultLocale: 'en', + locales: ['en'], + }, + + presets: [ + [ + 'classic', + { + docs: { + sidebarPath: './sidebars.ts', + // Please change this to your repo. + // Remove this to remove the "edit this page" links. + editUrl: + 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/', + }, + blog: { + showReadingTime: true, + // Please change this to your repo. + // Remove this to remove the "edit this page" links. + editUrl: + 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/', + }, + theme: { + customCss: './src/css/custom.css', + }, + } satisfies Preset.Options, + ], + ], + + themeConfig: { + // Replace with your project's social card + image: 'img/docusaurus-social-card.jpg', + navbar: { + title: 'My Site', + logo: { + alt: 'My Site Logo', + src: 'img/logo.svg', + }, + items: [ + { + type: 'docSidebar', + sidebarId: 'tutorialSidebar', + position: 'left', + label: 'Tutorial', + }, + {to: '/blog', label: 'Blog', position: 'left'}, + { + href: 'https://github.com/facebook/docusaurus', + label: 'GitHub', + position: 'right', + }, + ], + }, + footer: { + style: 'dark', + links: [ + { + title: 'Docs', + items: [ + { + label: 'Tutorial', + to: '/docs/intro', + }, + ], + }, + { + title: 'Community', + items: [ + { + label: 'Stack Overflow', + href: 'https://stackoverflow.com/questions/tagged/docusaurus', + }, + { + label: 'Discord', + href: 'https://discordapp.com/invite/docusaurus', + }, + { + label: 'Twitter', + href: 'https://twitter.com/docusaurus', + }, + ], + }, + { + title: 'More', + items: [ + { + label: 'Blog', + to: '/blog', + }, + { + label: 'GitHub', + href: 'https://github.com/facebook/docusaurus', + }, + ], + }, + ], + copyright: `Copyright © ${new Date().getFullYear()} My Project, Inc. Built with Docusaurus.`, + }, + prism: { + theme: prismThemes.github, + darkTheme: prismThemes.dracula, + }, + } satisfies Preset.ThemeConfig, +}; + +export default config; diff --git a/packages/create-docusaurus/templates/classic-typescript/sidebars.ts b/packages/create-docusaurus/templates/classic-typescript/sidebars.ts new file mode 100644 index 000000000000..acc7685acd59 --- /dev/null +++ b/packages/create-docusaurus/templates/classic-typescript/sidebars.ts @@ -0,0 +1,31 @@ +import type {SidebarsConfig} from '@docusaurus/plugin-content-docs'; + +/** + * Creating a sidebar enables you to: + - create an ordered group of docs + - render a sidebar for each doc of that group + - provide next/previous navigation + + The sidebars can be generated from the filesystem, or explicitly defined here. + + Create as many sidebars as you want. + */ +const sidebars: SidebarsConfig = { + // By default, Docusaurus generates a sidebar from the docs folder structure + tutorialSidebar: [{type: 'autogenerated', dirName: '.'}], + + // But you can create a sidebar manually + /* + tutorialSidebar: [ + 'intro', + 'hello', + { + type: 'category', + label: 'Tutorial', + items: ['tutorial-basics/create-a-document'], + }, + ], + */ +}; + +export default sidebars; diff --git a/packages/create-docusaurus/templates/classic-typescript/src/components/HomepageFeatures/styles.module.css b/packages/create-docusaurus/templates/classic-typescript/src/components/HomepageFeatures/styles.module.css deleted file mode 120000 index 26d4838f9dc9..000000000000 --- a/packages/create-docusaurus/templates/classic-typescript/src/components/HomepageFeatures/styles.module.css +++ /dev/null @@ -1 +0,0 @@ -../../../../classic/src/components/HomepageFeatures/styles.module.css \ No newline at end of file diff --git a/packages/create-docusaurus/templates/classic-typescript/src/pages/index.module.css b/packages/create-docusaurus/templates/classic-typescript/src/pages/index.module.css deleted file mode 120000 index 38af7a6ff1b4..000000000000 --- a/packages/create-docusaurus/templates/classic-typescript/src/pages/index.module.css +++ /dev/null @@ -1 +0,0 @@ -../../../classic/src/pages/index.module.css \ No newline at end of file diff --git a/packages/create-docusaurus/templates/classic/docusaurus.config.js b/packages/create-docusaurus/templates/classic/docusaurus.config.js index e4b2ca622375..7b8d5b1c7f11 100644 --- a/packages/create-docusaurus/templates/classic/docusaurus.config.js +++ b/packages/create-docusaurus/templates/classic/docusaurus.config.js @@ -40,7 +40,7 @@ const config = { /** @type {import('@docusaurus/preset-classic').Options} */ ({ docs: { - sidebarPath: require.resolve('./sidebars.js'), + sidebarPath: './sidebars.js', // Please change this to your repo. // Remove this to remove the "edit this page" links. editUrl: @@ -54,7 +54,7 @@ const config = { 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/', }, theme: { - customCss: require.resolve('./src/css/custom.css'), + customCss: './src/css/custom.css', }, }), ], diff --git a/packages/create-docusaurus/templates/shared/sidebars.js b/packages/create-docusaurus/templates/classic/sidebars.js similarity index 100% rename from packages/create-docusaurus/templates/shared/sidebars.js rename to packages/create-docusaurus/templates/classic/sidebars.js diff --git a/packages/create-docusaurus/templates/classic/src/components/HomepageFeatures/styles.module.css b/packages/create-docusaurus/templates/shared/src/components/HomepageFeatures/styles.module.css similarity index 100% rename from packages/create-docusaurus/templates/classic/src/components/HomepageFeatures/styles.module.css rename to packages/create-docusaurus/templates/shared/src/components/HomepageFeatures/styles.module.css diff --git a/packages/create-docusaurus/templates/classic/src/css/custom.css b/packages/create-docusaurus/templates/shared/src/css/custom.css similarity index 100% rename from packages/create-docusaurus/templates/classic/src/css/custom.css rename to packages/create-docusaurus/templates/shared/src/css/custom.css diff --git a/packages/create-docusaurus/templates/classic/src/pages/index.module.css b/packages/create-docusaurus/templates/shared/src/pages/index.module.css similarity index 100% rename from packages/create-docusaurus/templates/classic/src/pages/index.module.css rename to packages/create-docusaurus/templates/shared/src/pages/index.module.css diff --git a/packages/docusaurus/src/server/config.ts b/packages/docusaurus/src/server/config.ts index ba4e1ed6d966..59b30b133e24 100644 --- a/packages/docusaurus/src/server/config.ts +++ b/packages/docusaurus/src/server/config.ts @@ -18,7 +18,7 @@ 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( + const candidates = ['.ts', '.mts', '.cts', '.js', '.mjs', '.cjs'].map( (ext) => DEFAULT_CONFIG_FILE_NAME + ext, ); const configPath = await findAsyncSequential( From 5b120e6908e645955f0fba2dcd28d5ae44c4cae0 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Fri, 13 Oct 2023 17:39:48 +0200 Subject: [PATCH 17/46] add @docusaurus/types to templates by default --- .../templates/classic-typescript/package.json | 1 + packages/create-docusaurus/templates/classic/package.json | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/create-docusaurus/templates/classic-typescript/package.json b/packages/create-docusaurus/templates/classic-typescript/package.json index e3191cf647ea..db11de07e28a 100644 --- a/packages/create-docusaurus/templates/classic-typescript/package.json +++ b/packages/create-docusaurus/templates/classic-typescript/package.json @@ -26,6 +26,7 @@ "devDependencies": { "@docusaurus/module-type-aliases": "3.0.0-beta.0", "@docusaurus/tsconfig": "3.0.0-beta.0", + "@docusaurus/types": "3.0.0-beta.0", "typescript": "~5.2.2" }, "browserslist": { diff --git a/packages/create-docusaurus/templates/classic/package.json b/packages/create-docusaurus/templates/classic/package.json index 67bc1513b7c5..2d85197e2c96 100644 --- a/packages/create-docusaurus/templates/classic/package.json +++ b/packages/create-docusaurus/templates/classic/package.json @@ -23,7 +23,8 @@ "react-dom": "^18.0.0" }, "devDependencies": { - "@docusaurus/module-type-aliases": "3.0.0-beta.0" + "@docusaurus/module-type-aliases": "3.0.0-beta.0", + "@docusaurus/types": "3.0.0-beta.0" }, "browserslist": { "production": [ From 80fb76db404f6395da469fbd86093122a52197c7 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Fri, 13 Oct 2023 17:40:01 +0200 Subject: [PATCH 18/46] refactor TS docs --- website/docs/typescript-support.mdx | 109 +++++++++++++++------------- 1 file changed, 59 insertions(+), 50 deletions(-) diff --git a/website/docs/typescript-support.mdx b/website/docs/typescript-support.mdx index cb64419a0865..3746982f4cc1 100644 --- a/website/docs/typescript-support.mdx +++ b/website/docs/typescript-support.mdx @@ -6,6 +6,8 @@ description: Docusaurus is written in TypeScript and provides first-class TypeSc Docusaurus is written in TypeScript and provides first-class TypeScript support. +The minimum required version is **TypeScript 5.0**. + ## Initialization {#initialization} Docusaurus supports writing and using TypeScript theme components. If the init template provides a TypeScript variant, you can directly initialize a site with full TypeScript support by using the `--typescript` flag. @@ -18,10 +20,10 @@ Below are some guides on how to migrate an existing project to TypeScript. ## Setup {#setup} -To start using TypeScript, add `@docusaurus/module-type-aliases` and the base TS config to your project: +Add the following packages to your project: ```bash npm2yarn -npm install --save-dev typescript @docusaurus/module-type-aliases @docusaurus/tsconfig +npm install --save-dev typescript @docusaurus/module-type-aliases @docusaurus/tsconfig @docusaurus/types ``` Then add `tsconfig.json` to your project root with the following content: @@ -41,69 +43,84 @@ Now you can start writing TypeScript theme components. ## Typing the config file {#typing-config} -It is **not possible** to use a TypeScript config file in Docusaurus unless you compile it yourself to JavaScript. +It is possible to use a TypeScript config file in Docusaurus. -We recommend using [JSDoc type annotations](https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html): +```ts title="docusaurus.config.ts" +import type {Config} from '@docusaurus/types'; +import type * as Preset from '@docusaurus/preset-classic'; -```js title="docusaurus.config.js" // highlight-next-line -// @ts-check +const config: Config = { + title: 'My Site', + favicon: 'img/favicon.ico', + + /* Your site config here */ + + presets: [ + [ + 'classic', + { + /* Your preset config here */ + // highlight-next-line + } satisfies Preset.Options, + ], + ], + + themeConfig: { + /* Your theme config here */ + // highlight-next-line + } satisfies Preset.ThemeConfig, +}; + +export default config; +``` + +
+ It is also possible to use [JSDoc type annotations](https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html) within a `.js` file: + +By default, the Docusaurus TypeScript config does not type-check JavaScript files. + +The `// @ts-check` comment ensures the config file is properly type-checked when running `npx tsc`. +```js title="docusaurus.config.js" // highlight-next-line -/** @type {import('@docusaurus/types').Plugin} */ -function MyPlugin(context, options) { - return { - name: 'my-plugin', - }; -} +// @ts-check // highlight-next-line /** @type {import('@docusaurus/types').Config} */ const config = { - title: 'Docusaurus', - tagline: 'Build optimized websites quickly, focus on your content', - organizationName: 'facebook', - projectName: 'docusaurus', - plugins: [MyPlugin], + tagline: 'Dinosaurs are cool', + favicon: 'img/favicon.ico', + + /* Your site config here */ + presets: [ [ '@docusaurus/preset-classic', // highlight-next-line /** @type {import('@docusaurus/preset-classic').Options} */ - ({ - docs: { - path: 'docs', - sidebarPath: 'sidebars.js', - }, - blog: { - path: 'blog', - postsPerPage: 5, - }, - }), + ( + { + /* Your preset config here */ + } + ), ], ], themeConfig: // highlight-next-line /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ - ({ - colorMode: { - defaultMode: 'dark', - }, - navbar: { - hideOnScroll: true, - title: 'Docusaurus', - logo: { - alt: 'Docusaurus Logo', - src: 'img/docusaurus.svg', - srcDark: 'img/docusaurus_keytar.svg', - }, - }, - }), + ( + { + /* Your theme config here */ + } + ), }; -module.exports = config; +export default config; ``` +
+ :::tip Type annotations are very useful and help your IDE understand the type of config objects! @@ -112,14 +129,6 @@ The best IDEs (VS Code, WebStorm, IntelliJ...) will provide a nice auto-completi ::: -:::info - -By default, the Docusaurus TypeScript config does not type-check JavaScript files. - -The `// @ts-check` comment ensures the config file is properly type-checked when running `npx tsc`. - -::: - ## Swizzling TypeScript theme components {#swizzling-typescript-theme-components} For themes that support TypeScript theme components, you can add the `--typescript` flag to the end of the `swizzle` command to get TypeScript source code. For example, the following command will generate `index.tsx` and `styles.module.css` into `src/theme/Footer`. From bad83af347410d8ea075c93f0c7db7c640645b2d Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Fri, 13 Oct 2023 18:15:11 +0200 Subject: [PATCH 19/46] update docs to ESM --- website/docs/advanced/plugins.mdx | 12 ++-- website/docs/api/docusaurus.config.js.mdx | 58 +++++++++---------- website/docs/api/plugin-methods/README.mdx | 12 ++-- .../plugin-methods/extend-infrastructure.mdx | 23 ++++---- .../api/plugin-methods/i18n-lifecycles.mdx | 24 ++++---- .../api/plugin-methods/lifecycle-apis.mdx | 34 +++++------ .../api/plugin-methods/static-methods.mdx | 16 ++--- .../api/plugins/plugin-client-redirects.mdx | 2 +- website/docs/api/plugins/plugin-debug.mdx | 6 +- .../docs/api/plugins/plugin-ideal-image.mdx | 2 +- website/docs/api/plugins/plugin-pwa.mdx | 6 +- .../docs/api/themes/theme-configuration.mdx | 54 ++++++++--------- .../docs/api/themes/theme-live-codeblock.mdx | 2 +- website/docs/api/themes/theme-mermaid.mdx | 2 +- website/docs/blog.mdx | 22 +++---- website/docs/deployment.mdx | 8 +-- .../docs/guides/docs/docs-introduction.mdx | 4 +- .../docs/guides/docs/docs-multi-instance.mdx | 14 ++--- .../guides/docs/sidebar/autogenerated.mdx | 16 ++--- website/docs/guides/docs/sidebar/index.mdx | 14 ++--- website/docs/guides/docs/sidebar/items.mdx | 40 ++++++------- .../guides/docs/sidebar/multiple-sidebars.mdx | 9 ++- website/docs/guides/docs/versioning.mdx | 2 +- .../markdown-features-admonitions.mdx | 4 +- .../markdown-features-code-blocks.mdx | 14 ++--- .../markdown-features-diagrams.mdx | 6 +- .../markdown-features-math-equations.mdx | 10 ++-- .../markdown-features-plugins.mdx | 18 +++--- .../markdown-features-toc.mdx | 2 +- website/docs/i18n/i18n-crowdin.mdx | 4 +- website/docs/i18n/i18n-git.mdx | 2 +- website/docs/i18n/i18n-tutorial.mdx | 4 +- website/docs/search.mdx | 10 ++-- website/docs/seo.mdx | 2 +- website/docs/static-assets.mdx | 2 +- website/docs/styling-layout.mdx | 6 +- website/docs/using-plugins.mdx | 26 ++++----- 37 files changed, 241 insertions(+), 251 deletions(-) diff --git a/website/docs/advanced/plugins.mdx b/website/docs/advanced/plugins.mdx index 01b66d0c305b..e724c6214a18 100644 --- a/website/docs/advanced/plugins.mdx +++ b/website/docs/advanced/plugins.mdx @@ -11,7 +11,7 @@ A plugin is a function that takes two parameters: `context` and `options`. It re You can use a plugin as a function directly included in the Docusaurus config file: ```js title="docusaurus.config.js" -module.exports = { +export default { // ... plugins: [ // highlight-start @@ -38,7 +38,7 @@ module.exports = { You can use a plugin as a module path referencing a separate file or npm package: ```js title="docusaurus.config.js" -module.exports = { +export default { // ... plugins: [ // without options: @@ -52,7 +52,7 @@ module.exports = { Then in the folder `my-plugin`, you can create an `index.js` such as this: ```js title="my-plugin/index.js" -module.exports = async function myPlugin(context, options) { +export default async function myPlugin(context, options) { // ... return { name: 'my-plugin', @@ -64,7 +64,7 @@ module.exports = async function myPlugin(context, options) { }, /* other lifecycle API */ }; -}; +} ``` --- @@ -99,7 +99,7 @@ This is a contrived example: in practice, `@docusaurus/theme-classic` provides t ::: ```js title="docusaurus.config.js" -module.exports = { +export default { // highlight-next-line themes: ['theme-blog'], plugins: ['plugin-content-blog'], @@ -109,7 +109,7 @@ module.exports = { And if you want to use Bootstrap styling, you can swap out the theme with `theme-blog-bootstrap` (another fictitious non-existing theme): ```js title="docusaurus.config.js" -module.exports = { +export default { // highlight-next-line themes: ['theme-blog-bootstrap'], plugins: ['plugin-content-blog'], diff --git a/website/docs/api/docusaurus.config.js.mdx b/website/docs/api/docusaurus.config.js.mdx index 35ab29326a61..8b06e134cb57 100644 --- a/website/docs/api/docusaurus.config.js.mdx +++ b/website/docs/api/docusaurus.config.js.mdx @@ -23,7 +23,7 @@ This file is run in Node.js using the [**CommonJS**](https://flaviocopes.com/com Examples: ```js title="docusaurus.config.js" -module.exports = { +export default { title: 'Docusaurus', url: 'https://docusaurus.io', // your site config ... @@ -31,13 +31,13 @@ module.exports = { ``` ```js title="docusaurus.config.js" -module.exports = async function createConfigAsync() { +export default async function createConfigAsync() { return { title: 'Docusaurus', url: 'https://docusaurus.io', // your site config ... }; -}; +} ``` :::tip @@ -55,7 +55,7 @@ Refer to [**Syntax to declare `docusaurus.config.js`**](../configuration.mdx#syn Title for your website. Will be used in metadata and as browser tab title. ```js title="docusaurus.config.js" -module.exports = { +export default { title: 'Docusaurus', }; ``` @@ -67,7 +67,7 @@ module.exports = { URL for your website. This can also be considered the top-level hostname. For example, `https://facebook.github.io` is the URL of https://facebook.github.io/metro/, and `https://docusaurus.io` is the URL for https://docusaurus.io. This field is related to the [`baseUrl`](#baseUrl) field. ```js title="docusaurus.config.js" -module.exports = { +export default { url: 'https://docusaurus.io', }; ``` @@ -79,7 +79,7 @@ module.exports = { Base URL for your site. Can be considered as the path after the host. For example, `/metro/` is the base URL of https://facebook.github.io/metro/. For URLs that have no path, the baseUrl should be set to `/`. This field is related to the [`url`](#url) field. Always has both leading and trailing slash. ```js title="docusaurus.config.js" -module.exports = { +export default { baseUrl: '/', }; ``` @@ -93,7 +93,7 @@ module.exports = { Path to your site favicon; must be a URL that can be used in link's href. For example, if your favicon is in `static/img/favicon.ico`: ```js title="docusaurus.config.js" -module.exports = { +export default { favicon: '/img/favicon.ico', }; ``` @@ -127,7 +127,7 @@ Example: {/* cSpell:ignore فارسی */} ```js title="docusaurus.config.js" -module.exports = { +export default { i18n: { defaultLocale: 'en', locales: ['en', 'fa'], @@ -171,7 +171,7 @@ This option adds `` to every pag Example: ```js title="docusaurus.config.js" -module.exports = { +export default { noIndex: true, // Defaults to `false` }; ``` @@ -213,7 +213,7 @@ By default, it displays a warning after you run `yarn start` or `yarn build`. The tagline for your website. ```js title="docusaurus.config.js" -module.exports = { +export default { tagline: 'Docusaurus makes it easy to maintain Open Source documentation websites.', }; @@ -226,7 +226,7 @@ module.exports = { The GitHub user or organization that owns the repository. You don't need this if you are not using the `docusaurus deploy` command. ```js title="docusaurus.config.js" -module.exports = { +export default { // Docusaurus' organization is facebook organizationName: 'facebook', }; @@ -239,7 +239,7 @@ module.exports = { The name of the GitHub repository. You don't need this if you are not using the `docusaurus deploy` command. ```js title="docusaurus.config.js" -module.exports = { +export default { projectName: 'docusaurus', }; ``` @@ -251,7 +251,7 @@ module.exports = { The name of the branch to deploy the static files to. You don't need this if you are not using the `docusaurus deploy` command. ```js title="docusaurus.config.js" -module.exports = { +export default { deploymentBranch: 'gh-pages', }; ``` @@ -263,7 +263,7 @@ module.exports = { The hostname of your server. Useful if you are using GitHub Enterprise. You don't need this if you are not using the `docusaurus deploy` command. ```js title="docusaurus.config.js" -module.exports = { +export default { githubHost: 'github.com', }; ``` @@ -275,7 +275,7 @@ module.exports = { The port of your server. Useful if you are using GitHub Enterprise. You don't need this if you are not using the `docusaurus deploy` command. ```js title="docusaurus.config.js" -module.exports = { +export default { githubPort: '22', }; ``` @@ -289,7 +289,7 @@ The [theme configuration](./themes/theme-configuration.mdx) object to customize Example: ```js title="docusaurus.config.js" -module.exports = { +export default { themeConfig: { docs: { sidebar: { @@ -358,7 +358,7 @@ type PluginConfig = string | [string, any] | PluginModule | [PluginModule, any]; See [plugin method references](./plugin-methods/README.mdx) for the shape of a `PluginModule`. ```js title="docusaurus.config.js" -module.exports = { +export default { plugins: [ 'docusaurus-plugin-awesome', ['docusuarus-plugin-confetti', {fancy: false}], @@ -376,7 +376,7 @@ module.exports = { - Type: `PluginConfig[]` ```js title="docusaurus.config.js" -module.exports = { +export default { themes: ['@docusaurus/theme-classic'], }; ``` @@ -390,7 +390,7 @@ type PresetConfig = string | [string, any]; ``` ```js title="docusaurus.config.js" -module.exports = { +export default { presets: [], }; ``` @@ -426,7 +426,7 @@ type MarkdownConfig = { Example: ```js title="docusaurus.config.js" -module.exports = { +export default { markdown: { format: 'mdx', mermaid: true, @@ -464,7 +464,7 @@ Docusaurus guards `docusaurus.config.js` from unknown fields. To add a custom fi - Type: `Object` ```js title="docusaurus.config.js" -module.exports = { +export default { customFields: { admin: 'endi', superman: 'lol', @@ -487,7 +487,7 @@ An array of paths, relative to the site's directory or absolute. Files under the Example: ```js title="docusaurus.config.js" -module.exports = { +export default { staticDirectories: ['static'], }; ``` @@ -501,7 +501,7 @@ An array of tags that will be inserted in the HTML ``. The values must be Example: ```js title="docusaurus.config.js" -module.exports = { +export default { headTags: [ { tagName: 'link', @@ -527,7 +527,7 @@ Note that `