diff --git a/packages/docusaurus/src/server/index.ts b/packages/docusaurus/src/server/index.ts index 9734f4b1db2c..acb97cf58180 100644 --- a/packages/docusaurus/src/server/index.ts +++ b/packages/docusaurus/src/server/index.ts @@ -89,7 +89,7 @@ export async function load( plugins.map(plugin => plugin.getThemePath && plugin.getThemePath()), ); const userTheme = path.resolve(siteDir, THEME_PATH); - const alias = loadThemeAlias([fallbackTheme, ...pluginThemes, userTheme]); + const alias = loadThemeAlias([fallbackTheme, ...pluginThemes], [userTheme]); // Make a fake plugin to: // - Resolve aliased theme components diff --git a/packages/docusaurus/src/server/themes/__tests__/alias.test.ts b/packages/docusaurus/src/server/themes/__tests__/alias.test.ts index 5814f00b9e00..6f9a357fe98a 100644 --- a/packages/docusaurus/src/server/themes/__tests__/alias.test.ts +++ b/packages/docusaurus/src/server/themes/__tests__/alias.test.ts @@ -14,6 +14,19 @@ describe('themeAlias', () => { const fixtures = path.join(__dirname, '__fixtures__'); const themePath = path.join(fixtures, 'theme-1'); const alias = themeAlias(themePath); + expect(alias).toEqual({ + '@theme/Footer': path.join(themePath, 'Footer/index.js'), + '@theme-original/Footer': path.join(themePath, 'Footer/index.js'), + '@theme/Layout': path.join(themePath, 'Layout.js'), + '@theme-original/Layout': path.join(themePath, 'Layout.js'), + }); + expect(alias).not.toEqual({}); + }); + + test('valid themePath 1 with components without original', () => { + const fixtures = path.join(__dirname, '__fixtures__'); + const themePath = path.join(fixtures, 'theme-1'); + const alias = themeAlias(themePath, false); expect(alias).toEqual({ '@theme/Footer': path.join(themePath, 'Footer/index.js'), '@theme/Layout': path.join(themePath, 'Layout.js'), @@ -25,6 +38,19 @@ describe('themeAlias', () => { const fixtures = path.join(__dirname, '__fixtures__'); const themePath = path.join(fixtures, 'theme-2'); const alias = themeAlias(themePath); + expect(alias).toEqual({ + '@theme/Navbar': path.join(themePath, 'Navbar.js'), + '@theme-original/Navbar': path.join(themePath, 'Navbar.js'), + '@theme/Layout': path.join(themePath, 'Layout/index.js'), + '@theme-original/Layout': path.join(themePath, 'Layout/index.js'), + }); + expect(alias).not.toEqual({}); + }); + + test('valid themePath 2 with components without original', () => { + const fixtures = path.join(__dirname, '__fixtures__'); + const themePath = path.join(fixtures, 'theme-2'); + const alias = themeAlias(themePath, false); expect(alias).toEqual({ '@theme/Navbar': path.join(themePath, 'Navbar.js'), '@theme/Layout': path.join(themePath, 'Layout/index.js'), @@ -40,6 +66,14 @@ describe('themeAlias', () => { expect(alias).toEqual({}); }); + test('valid themePath with no components without original', () => { + const fixtures = path.join(__dirname, '__fixtures__'); + const themePath = path.join(fixtures, 'empty-theme'); + fs.ensureDirSync(themePath); + const alias = themeAlias(themePath, false); + expect(alias).toEqual({}); + }); + test('invalid themePath that does not exist', () => { const fixtures = path.join(__dirname, '__fixtures__'); const themePath = path.join(fixtures, '__noExist__'); diff --git a/packages/docusaurus/src/server/themes/__tests__/index.ts b/packages/docusaurus/src/server/themes/__tests__/index.ts index 502b05b631c1..40032cc5abf2 100644 --- a/packages/docusaurus/src/server/themes/__tests__/index.ts +++ b/packages/docusaurus/src/server/themes/__tests__/index.ts @@ -17,8 +17,11 @@ describe('loadThemeAlias', () => { const alias = loadThemeAlias([theme1Path, theme2Path]); expect(alias).toEqual({ '@theme/Footer': path.join(theme1Path, 'Footer/index.js'), + '@theme-original/Footer': path.join(theme1Path, 'Footer/index.js'), '@theme/Navbar': path.join(theme2Path, 'Navbar.js'), + '@theme-original/Navbar': path.join(theme2Path, 'Navbar.js'), '@theme/Layout': path.join(theme2Path, 'Layout/index.js'), + '@theme-original/Layout': path.join(theme2Path, 'Layout/index.js'), }); expect(alias).not.toEqual({}); }); diff --git a/packages/docusaurus/src/server/themes/alias.ts b/packages/docusaurus/src/server/themes/alias.ts index a3daf069ecb2..3aff5e46864a 100644 --- a/packages/docusaurus/src/server/themes/alias.ts +++ b/packages/docusaurus/src/server/themes/alias.ts @@ -11,7 +11,10 @@ import path from 'path'; import {fileToPath, posixPath, normalizeUrl} from '@docusaurus/utils'; import {ThemeAlias} from '@docusaurus/types'; -export function themeAlias(themePath: string): ThemeAlias { +export function themeAlias( + themePath: string, + addOriginalAlias: boolean = true, +): ThemeAlias { if (!fs.pathExistsSync(themePath)) { return {}; } @@ -20,15 +23,25 @@ export function themeAlias(themePath: string): ThemeAlias { cwd: themePath, }); - const alias: ThemeAlias = {}; + const aliases: ThemeAlias = {}; + themeComponentFiles.forEach(relativeSource => { const filePath = path.join(themePath, relativeSource); const fileName = fileToPath(relativeSource); + const aliasName = posixPath( normalizeUrl(['@theme', fileName]).replace(/\/$/, ''), ); - alias[aliasName] = filePath; + aliases[aliasName] = filePath; + + if (addOriginalAlias) { + // For swizzled components to access the original. + const originalAliasName = posixPath( + normalizeUrl(['@theme-original', fileName]).replace(/\/$/, ''), + ); + aliases[originalAliasName] = filePath; + } }); - return alias; + return aliases; } diff --git a/packages/docusaurus/src/server/themes/index.ts b/packages/docusaurus/src/server/themes/index.ts index ea5b87eb9c6b..fb2da680e0f8 100644 --- a/packages/docusaurus/src/server/themes/index.ts +++ b/packages/docusaurus/src/server/themes/index.ts @@ -8,12 +8,25 @@ import {ThemeAlias} from '@docusaurus/types'; import {themeAlias} from './alias'; -export function loadThemeAlias(themePaths: string[]): ThemeAlias { - return themePaths.reduce( - (alias, themePath) => ({ - ...alias, - ...themeAlias(themePath), - }), - {}, - ); +export function loadThemeAlias( + themePaths: string[], + userThemePaths: string[] = [], +): ThemeAlias { + const aliases = {}; + + themePaths.forEach(themePath => { + const themeAliases = themeAlias(themePath); + Object.keys(themeAliases).forEach(aliasKey => { + aliases[aliasKey] = themeAliases[aliasKey]; + }); + }); + + userThemePaths.forEach(themePath => { + const userThemeAliases = themeAlias(themePath, false); + Object.keys(userThemeAliases).forEach(aliasKey => { + aliases[aliasKey] = userThemeAliases[aliasKey]; + }); + }); + + return aliases; }