Skip to content

Commit

Permalink
feat(v2): easier plugin theme components swizzling (#1436)
Browse files Browse the repository at this point in the history
* feat(v2): easier plugin theme components override

* add context

* refactor again

* rename eject -> swizzle

* nits
  • Loading branch information
endiliey authored May 7, 2019
1 parent 3298d8c commit 0834784
Show file tree
Hide file tree
Showing 11 changed files with 91 additions and 90 deletions.
20 changes: 4 additions & 16 deletions packages/docusaurus-plugin-content-blog/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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: [
{
Expand Down
15 changes: 4 additions & 11 deletions packages/docusaurus-plugin-content-docs/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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: [
{
Expand Down
14 changes: 2 additions & 12 deletions packages/docusaurus-theme-classic/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
}
}

Expand Down
10 changes: 5 additions & 5 deletions packages/docusaurus/bin/docusaurus.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down Expand Up @@ -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
Expand Down
23 changes: 0 additions & 23 deletions packages/docusaurus/lib/commands/eject.js

This file was deleted.

36 changes: 36 additions & 0 deletions packages/docusaurus/lib/commands/swizzle.js
Original file line number Diff line number Diff line change
@@ -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`,
);
}
};
4 changes: 2 additions & 2 deletions packages/docusaurus/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
48 changes: 36 additions & 12 deletions packages/docusaurus/lib/server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,42 @@ 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) {
plugins.push({
configureWebpack: () => ({
resolve: {
alias: themeAliases,
},
}),
});
}
// 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: {
alias: themeAliases,
},
}),
});

// Routing
const {
Expand Down
3 changes: 1 addition & 2 deletions packages/docusaurus/lib/server/load/theme.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
6 changes: 0 additions & 6 deletions packages/docusaurus/lib/webpack/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand All @@ -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'),
Expand Down
2 changes: 1 addition & 1 deletion website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"scripts": {
"start": "docusaurus start",
"build": "docusaurus build",
"eject": "docusaurus eject",
"swizzle": "docusaurus swizzle",
"deploy": "docusaurus deploy"
},
"dependencies": {
Expand Down

0 comments on commit 0834784

Please sign in to comment.