mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-29 08:57:03 +02:00
feat(v2): easier plugin theme components swizzling (#1436)
* feat(v2): easier plugin theme components override * add context * refactor again * rename eject -> swizzle * nits
This commit is contained in:
parent
3298d8cd23
commit
0834784455
11 changed files with 91 additions and 90 deletions
|
@ -156,24 +156,12 @@ class DocusaurusPluginContentBlog {
|
|||
);
|
||||
}
|
||||
|
||||
getThemePath() {
|
||||
return path.resolve(__dirname, './theme');
|
||||
}
|
||||
|
||||
configureWebpack(config, isServer, {getBabelLoader, getCacheLoader}) {
|
||||
return {
|
||||
resolve: {
|
||||
alias: {
|
||||
'@theme/BlogListPage': path.resolve(
|
||||
__dirname,
|
||||
'./theme/BlogListPage',
|
||||
),
|
||||
'@theme/BlogPostItem': path.resolve(
|
||||
__dirname,
|
||||
'./theme/BlogPostItem',
|
||||
),
|
||||
'@theme/BlogPostPage': path.resolve(
|
||||
__dirname,
|
||||
'./theme/BlogPostPage',
|
||||
),
|
||||
},
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
|
|
|
@ -151,19 +151,12 @@ class DocusaurusPluginContentDocs {
|
|||
});
|
||||
}
|
||||
|
||||
getThemePath() {
|
||||
return path.resolve(__dirname, './theme');
|
||||
}
|
||||
|
||||
configureWebpack(config, isServer, {getBabelLoader, getCacheLoader}) {
|
||||
return {
|
||||
resolve: {
|
||||
alias: {
|
||||
'@theme/DocItem': path.resolve(__dirname, './theme/DocItem'),
|
||||
'@theme/DocPage': path.resolve(__dirname, './theme/DocPage'),
|
||||
'@theme/DocPaginator': path.resolve(
|
||||
__dirname,
|
||||
'./theme/DocPaginator',
|
||||
),
|
||||
'@theme/DocSidebar': path.resolve(__dirname, './theme/DocSidebar'),
|
||||
},
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
|
|
|
@ -19,18 +19,8 @@ class DocusaurusThemeDefault {
|
|||
return 'docusaurus-theme-classic';
|
||||
}
|
||||
|
||||
configureWebpack() {
|
||||
return {
|
||||
resolve: {
|
||||
alias: {
|
||||
'@theme/Footer': path.resolve(__dirname, './theme/Footer'),
|
||||
'@theme/Layout': path.resolve(__dirname, './theme/Layout'),
|
||||
'@theme/Navbar': path.resolve(__dirname, './theme/Navbar'),
|
||||
'@theme/NotFound': path.resolve(__dirname, './theme/NotFound'),
|
||||
'@theme/Search': path.resolve(__dirname, './theme/Search'),
|
||||
},
|
||||
},
|
||||
};
|
||||
getThemePath() {
|
||||
return path.resolve(__dirname, './theme');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ const envinfo = require('envinfo');
|
|||
const semver = require('semver');
|
||||
const path = require('path');
|
||||
const program = require('commander');
|
||||
const {build, eject, init, deploy, start} = require('../lib');
|
||||
const {build, swizzle, init, deploy, start} = require('../lib');
|
||||
const requiredVersion = require('../package.json').engines.node;
|
||||
|
||||
if (!semver.satisfies(process.version, requiredVersion)) {
|
||||
|
@ -55,10 +55,10 @@ program
|
|||
});
|
||||
|
||||
program
|
||||
.command('eject [siteDir]')
|
||||
.description('copy the default theme into website folder for customization.')
|
||||
.action((siteDir = '.') => {
|
||||
wrapCommand(eject)(path.resolve(siteDir));
|
||||
.command('swizzle <themeName> [componentName] [siteDir]')
|
||||
.description('Copy the theme files into website folder for customization.')
|
||||
.action((themeName, componentName, siteDir = '.') => {
|
||||
wrapCommand(swizzle)(path.resolve(siteDir), themeName, componentName);
|
||||
});
|
||||
|
||||
program
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2017-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
const fs = require('fs-extra');
|
||||
const chalk = require('chalk');
|
||||
const path = require('path');
|
||||
|
||||
module.exports = async function eject(siteDir) {
|
||||
const defaultTheme = path.resolve(__dirname, '..', 'default-theme');
|
||||
const customTheme = path.resolve(siteDir, 'theme');
|
||||
await fs.copy(defaultTheme, customTheme);
|
||||
|
||||
const relativeDir = path.relative(process.cwd(), customTheme);
|
||||
console.log(
|
||||
`\n${chalk.green('Success!')} Copied default theme files to ${chalk.cyan(
|
||||
relativeDir,
|
||||
)}.\n`,
|
||||
);
|
||||
};
|
36
packages/docusaurus/lib/commands/swizzle.js
Normal file
36
packages/docusaurus/lib/commands/swizzle.js
Normal file
|
@ -0,0 +1,36 @@
|
|||
/**
|
||||
* Copyright (c) 2017-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
const fs = require('fs-extra');
|
||||
const chalk = require('chalk');
|
||||
const path = require('path');
|
||||
const importFresh = require('import-fresh');
|
||||
|
||||
module.exports = async function swizzle(siteDir, themeName, componentName) {
|
||||
const Plugin = importFresh(themeName);
|
||||
const context = {siteDir};
|
||||
const PluginInstance = new Plugin(context);
|
||||
let fromPath = PluginInstance.getThemePath();
|
||||
|
||||
if (fromPath) {
|
||||
let toPath = path.resolve(siteDir, 'theme');
|
||||
if (componentName) {
|
||||
fromPath = path.join(fromPath, componentName);
|
||||
toPath = path.join(toPath, componentName);
|
||||
}
|
||||
await fs.copy(fromPath, toPath);
|
||||
|
||||
const relativeDir = path.relative(process.cwd(), toPath);
|
||||
const fromMsg = chalk.blue(
|
||||
componentName ? `${themeName}/${componentName}` : themeName,
|
||||
);
|
||||
const toMsg = chalk.cyan(relativeDir);
|
||||
console.log(
|
||||
`\n${chalk.green('Success!')} Copied ${fromMsg} to ${toMsg}.\n`,
|
||||
);
|
||||
}
|
||||
};
|
|
@ -8,12 +8,12 @@
|
|||
const build = require('./commands/build');
|
||||
const init = require('./commands/init');
|
||||
const start = require('./commands/start');
|
||||
const eject = require('./commands/eject');
|
||||
const swizzle = require('./commands/swizzle');
|
||||
const deploy = require('./commands/deploy');
|
||||
|
||||
module.exports = {
|
||||
build,
|
||||
eject,
|
||||
swizzle,
|
||||
init,
|
||||
start,
|
||||
deploy,
|
||||
|
|
|
@ -51,10 +51,35 @@ module.exports = async function load(siteDir, cliOptions = {}) {
|
|||
const outDir = path.resolve(siteDir, 'build');
|
||||
const {baseUrl} = siteConfig;
|
||||
|
||||
// Resolve custom theme override aliases.
|
||||
const themeAliases = await loadTheme(siteDir);
|
||||
// Make a fake plugin to resolve user's theme overrides.
|
||||
if (themeAliases != null) {
|
||||
// Default theme components that are essential and must exist in a Docusaurus app
|
||||
// These can be overriden in plugins/ through component swizzling.
|
||||
// However, we alias it here first as a fallback.
|
||||
const themeFallback = path.resolve(__dirname, '../client/theme-fallback');
|
||||
let themeAliases = await loadTheme(themeFallback);
|
||||
|
||||
// create theme alias from plugins
|
||||
await Promise.all(
|
||||
plugins.map(async plugin => {
|
||||
if (!plugin.getThemePath) {
|
||||
return;
|
||||
}
|
||||
const aliases = await loadTheme(plugin.getThemePath());
|
||||
themeAliases = {
|
||||
...themeAliases,
|
||||
...aliases,
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
// user's own theme alias override. Highest priority
|
||||
const themePath = path.resolve(siteDir, 'theme');
|
||||
const aliases = await loadTheme(themePath);
|
||||
themeAliases = {
|
||||
...themeAliases,
|
||||
...aliases,
|
||||
};
|
||||
|
||||
// Make a fake plugin to resolve alias theme.
|
||||
plugins.push({
|
||||
configureWebpack: () => ({
|
||||
resolve: {
|
||||
|
@ -62,7 +87,6 @@ module.exports = async function load(siteDir, cliOptions = {}) {
|
|||
},
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
// Routing
|
||||
const {
|
||||
|
|
|
@ -10,8 +10,7 @@ const fs = require('fs-extra');
|
|||
const path = require('path');
|
||||
const {fileToPath, posixPath, normalizeUrl} = require('@docusaurus/utils');
|
||||
|
||||
module.exports = async function loadTheme(siteDir) {
|
||||
const themePath = path.resolve(siteDir, 'theme');
|
||||
module.exports = async function loadTheme(themePath) {
|
||||
if (!fs.existsSync(themePath)) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -25,7 +25,6 @@ module.exports = function createBaseConfig(props, isServer) {
|
|||
} = props;
|
||||
|
||||
const isProd = process.env.NODE_ENV === 'production';
|
||||
const themeFallback = path.resolve(__dirname, '../client/theme-fallback');
|
||||
return {
|
||||
mode: isProd ? 'production' : 'development',
|
||||
output: {
|
||||
|
@ -44,11 +43,6 @@ module.exports = function createBaseConfig(props, isServer) {
|
|||
alias: {
|
||||
// https://stackoverflow.com/a/55433680/6072730
|
||||
ejs: 'ejs/ejs.min.js',
|
||||
// These alias can be overriden in plugins. However, these components are essential
|
||||
// (e.g: react-loadable requires Loading component) so we alias it here first as fallback.
|
||||
'@theme/Layout': path.join(themeFallback, 'Layout'),
|
||||
'@theme/Loading': path.join(themeFallback, 'Loading'),
|
||||
'@theme/NotFound': path.join(themeFallback, 'NotFound'),
|
||||
'@site': siteDir,
|
||||
'@generated': generatedFilesDir,
|
||||
'@docusaurus': path.resolve(__dirname, '../client/exports'),
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
"scripts": {
|
||||
"start": "docusaurus start",
|
||||
"build": "docusaurus build",
|
||||
"eject": "docusaurus eject",
|
||||
"swizzle": "docusaurus swizzle",
|
||||
"deploy": "docusaurus deploy"
|
||||
},
|
||||
"dependencies": {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue