feat(v2): presets (#1401)

* feat(v2): presets

* misc: add newline

* misc: add tests

* misc: fix path
This commit is contained in:
Yangshun Tay 2019-04-27 10:47:56 -07:00 committed by GitHub
parent 7ebcf10478
commit 361986515c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 394 additions and 89 deletions

View file

@ -4,6 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const {getOptions} = require('loader-utils');
const mdx = require('@mdx-js/mdx');
const rehypePrism = require('@mapbox/rehype-prism');

View file

@ -4,6 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import '@babel/polyfill';
import {join} from 'path';
import remark from 'remark';

View file

@ -4,6 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const {parse} = require('@babel/parser');
const traverse = require('@babel/traverse').default;
const stringifyObject = require('stringify-object');

View file

@ -4,6 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const toString = require('mdast-util-to-string');
const visit = require('unist-util-visit');
const slugs = require('github-slugger')();

View file

@ -29,7 +29,7 @@ const DEFAULT_OPTIONS = {
};
class DocusaurusPluginContentBlog {
constructor(opts, context) {
constructor(context, opts) {
this.options = {...DEFAULT_OPTIONS, ...opts};
this.context = context;
this.contentPath = path.resolve(this.context.siteDir, this.options.path);

View file

@ -15,15 +15,15 @@ describe('loadDocs', () => {
const {env, siteDir, siteConfig} = await loadSetup('simple');
const sidebarPath = path.join(siteDir, 'sidebars.json');
const plugin = new DocusaurusPluginContentDocs(
{
path: '../docs',
sidebarPath,
},
{
env,
siteDir,
siteConfig,
},
{
path: '../docs',
sidebarPath,
},
);
const {docs: docsMetadata} = await plugin.loadContent();
const docsDir = plugin.contentPath;
@ -62,15 +62,15 @@ describe('loadDocs', () => {
const {env, siteDir, siteConfig} = await loadSetup('versioned');
const sidebarPath = path.join(siteDir, 'sidebars.json');
const plugin = new DocusaurusPluginContentDocs(
{
path: '../docs',
sidebarPath,
},
{
env,
siteDir,
siteConfig,
},
{
path: '../docs',
sidebarPath,
},
);
const {docs: docsMetadata, versionedDir} = await plugin.loadContent();
const docsDir = plugin.contentPath;
@ -109,15 +109,15 @@ describe('loadDocs', () => {
const {env, siteDir, siteConfig} = await loadSetup('transversioned');
const sidebarPath = path.join(siteDir, 'sidebars.json');
const plugin = new DocusaurusPluginContentDocs(
{
path: '../docs',
sidebarPath,
},
{
env,
siteDir,
siteConfig,
},
{
path: '../docs',
sidebarPath,
},
);
const {
docs: docsMetadata,
@ -177,15 +177,15 @@ describe('loadDocs', () => {
const {env, siteDir, siteConfig} = await loadSetup('translated');
const sidebarPath = path.join(siteDir, 'sidebars.json');
const plugin = new DocusaurusPluginContentDocs(
{
path: '../docs',
sidebarPath,
},
{
env,
siteDir,
siteConfig,
},
{
path: '../docs',
sidebarPath,
},
);
const {docs: docsMetadata, translatedDir} = await plugin.loadContent();
const docsDir = plugin.contentPath;
@ -227,16 +227,16 @@ describe('loadDocs', () => {
const {env, siteDir, siteConfig} = await loadSetup('versioned');
const sidebarPath = path.join(siteDir, 'sidebars.json');
const plugin = new DocusaurusPluginContentDocs(
{
path: '../docs',
sidebarPath,
skipNextRelease: true,
},
{
env,
siteDir,
siteConfig,
},
{
path: '../docs',
sidebarPath,
skipNextRelease: true,
},
);
const {docs: docsMetadata, versionedDir} = await plugin.loadContent();

View file

@ -32,7 +32,7 @@ const DEFAULT_OPTIONS = {
};
class DocusaurusPluginContentDocs {
constructor(opts, context) {
constructor(context, opts) {
this.options = {...DEFAULT_OPTIONS, ...opts};
this.context = context;
this.contentPath = path.resolve(this.context.siteDir, this.options.path);

View file

@ -111,7 +111,7 @@ describe('docusaurus-plugin-content-pages', () => {
],
])('%s website', async (type, expected) => {
const {env, siteDir, siteConfig} = await loadSetup(type);
const plugin = new DocusaurusPluginContentPages(null, {
const plugin = new DocusaurusPluginContentPages({
env,
siteDir,
siteConfig,

View file

@ -17,7 +17,7 @@ const DEFAULT_OPTIONS = {
};
class DocusaurusPluginContentPages {
constructor(opts, context) {
constructor(context, opts) {
this.options = {...DEFAULT_OPTIONS, ...opts};
this.context = context;
this.contentPath = path.resolve(this.context.siteDir, this.options.path);

View file

@ -13,9 +13,9 @@ describe('docusaurus-plugin-sitemap', () => {
test.each(['simple', 'versioned', 'translated', 'transversioned'])(
'%s website',
async type => {
const props = await loadSetup(type);
const plugin = new DocusaurusPluginSitemap(null, props);
const sitemap = await plugin.createSitemap(props);
const context = await loadSetup(type);
const plugin = new DocusaurusPluginSitemap(context, null);
const sitemap = await plugin.createSitemap(context);
expect(sitemap).toContain(
`<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:mobile="http://www.google.com/schemas/sitemap-mobile/1.0" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1">`,
);
@ -23,10 +23,10 @@ describe('docusaurus-plugin-sitemap', () => {
);
test('empty site', async () => {
const props = await loadSetup('empty');
const plugin = new DocusaurusPluginSitemap(null, props);
const context = await loadSetup('empty');
const plugin = new DocusaurusPluginSitemap(context, null);
expect(
plugin.createSitemap(props),
plugin.createSitemap(context),
).rejects.toThrowErrorMatchingInlineSnapshot(
`"Url in docusaurus.config.js cannot be empty/undefined"`,
);

View file

@ -16,7 +16,7 @@ const DEFAULT_OPTIONS = {
};
class DocusaurusPluginSitemap {
constructor(opts, context) {
constructor(context, opts) {
this.options = {...DEFAULT_OPTIONS, ...opts};
this.context = context;
}

View file

@ -0,0 +1,19 @@
{
"name": "@docusaurus/preset-classic",
"version": "2.0.0-alpha.11",
"description": "Preset for classic Docusaurus",
"main": "src/index.js",
"publishConfig": {
"access": "public"
},
"license": "MIT",
"dependencies": {
"@docusaurus/plugin-content-blog": "^2.0.0-alpha.11",
"@docusaurus/plugin-content-docs": "^2.0.0-alpha.11",
"@docusaurus/plugin-content-pages": "^2.0.0-alpha.11",
"@docusaurus/plugin-sitemap": "^2.0.0-alpha.11"
},
"peerDependencies": {
"@docusaurus/core": "^2.0.0"
}
}

View file

@ -0,0 +1,29 @@
/**
* 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.
*/
module.exports = function preset(context, opts = {}) {
return {
plugins: [
{
name: '@docusaurus/plugin-content-docs',
options: opts.docs,
},
{
name: '@docusaurus/plugin-content-blog',
options: opts.blog,
},
{
name: '@docusaurus/plugin-content-pages',
options: opts.pages,
},
{
name: '@docusaurus/plugin-sitemap',
options: opts.sitemap,
},
],
};
};

View file

@ -9,7 +9,7 @@
- `sidebars.json` now has to be explicitly loaded by users and passed into the the plugin option on `docusaurus-plugin-content-docs`.
- `headerLinks` doc, page, blog is deprecated. The syntax is now:
```js
```js
headerLinks: [
// Link to internal page (without baseUrl)
{ url: "help", label: "Help" },
@ -20,4 +20,10 @@ headerLinks: [
// Determines language drop down position among links
{ languages: true }
],
```js
```
# Additions
### Presets
- Added presets for plugins that follow the [Babel preset convention](https://babeljs.io/docs/en/presets).

View file

@ -6,12 +6,12 @@
*/
const support = function(feature) {
if (typeof document === `undefined`) {
if (typeof document === 'undefined') {
return false;
}
const fakeLink = document.createElement(`link`);
const fakeLink = document.createElement('link');
try {
if (fakeLink.relList && typeof fakeLink.relList.supports === `function`) {
if (fakeLink.relList && typeof fakeLink.relList.supports === 'function') {
return fakeLink.relList.supports(feature);
}
} catch (err) {
@ -22,21 +22,21 @@ const support = function(feature) {
const linkPrefetchStrategy = function(url) {
return new Promise((resolve, reject) => {
if (typeof document === `undefined`) {
if (typeof document === 'undefined') {
reject();
return;
}
const link = document.createElement(`link`);
link.setAttribute(`rel`, `prefetch`);
link.setAttribute(`href`, url);
const link = document.createElement('link');
link.setAttribute('rel', 'prefetch');
link.setAttribute('href', url);
link.onload = resolve;
link.onerror = reject;
const parentElement =
document.getElementsByTagName(`head`)[0] ||
document.getElementsByName(`script`)[0].parentNode;
document.getElementsByTagName('head')[0] ||
document.getElementsByName('script')[0].parentNode;
parentElement.appendChild(link);
});
};
@ -44,7 +44,7 @@ const linkPrefetchStrategy = function(url) {
const xhrPrefetchStrategy = function(url) {
return new Promise((resolve, reject) => {
const req = new XMLHttpRequest();
req.open(`GET`, url, true);
req.open('GET', url, true);
req.withCredentials = true;
req.onload = () => {
@ -59,7 +59,7 @@ const xhrPrefetchStrategy = function(url) {
});
};
const supportedPrefetchStrategy = support(`prefetch`)
const supportedPrefetchStrategy = support('prefetch')
? linkPrefetchStrategy
: xhrPrefetchStrategy;

View file

@ -14,7 +14,7 @@ const path = require('path');
const chalk = require('chalk');
const fs = require('fs-extra');
const globby = require('globby');
const load = require('../server/load');
const load = require('../server');
const createServerConfig = require('../webpack/server');
const createClientConfig = require('../webpack/client');
const {applyConfigureWebpack} = require('../webpack/utils');

View file

@ -19,7 +19,7 @@ const HotModuleReplacementPlugin = require('webpack/lib/HotModuleReplacementPlug
const WebpackDevServer = require('webpack-dev-server');
const merge = require('webpack-merge');
const {normalizeUrl} = require('@docusaurus/utils');
const load = require('../server/load');
const load = require('../server');
const {CONFIG_FILE_NAME} = require('../constants');
const createClientConfig = require('../webpack/client');
const {applyConfigureWebpack} = require('../webpack/utils');

View file

@ -8,12 +8,13 @@
const path = require('path');
const {generate} = require('@docusaurus/utils');
const loadConfig = require('./config');
const loadEnv = require('./env');
const loadTheme = require('./theme');
const loadRoutes = require('./routes');
const loadPlugins = require('./plugins');
const constants = require('../../constants');
const loadConfig = require('./load/config');
const loadEnv = require('./load/env');
const loadTheme = require('./load/theme');
const loadRoutes = require('./load/routes');
const loadPlugins = require('./load/plugins');
const loadPresets = require('./load/presets');
const constants = require('../constants');
module.exports = async function load(siteDir, cliOptions = {}) {
const generatedFilesDir = path.resolve(
@ -35,9 +36,13 @@ module.exports = async function load(siteDir, cliOptions = {}) {
`export default ${JSON.stringify(env, null, 2)};`,
);
// Process plugins.
const pluginConfigs = siteConfig.plugins || [];
const context = {env, siteDir, generatedFilesDir, siteConfig, cliOptions};
// Process presets.
const presetPlugins = loadPresets(context);
// Process plugins.
const pluginConfigs = [...presetPlugins, ...siteConfig.plugins];
const {plugins, pluginsRouteConfigs} = await loadPlugins({
pluginConfigs,
context,

View file

@ -0,0 +1,14 @@
module.exports = function preset(context, opts = {}) {
return {
plugins: [
{
name: '@docusaurus/plugin-content-docs',
options: opts.docs,
},
{
name: '@docusaurus/plugin-content-blog',
options: opts.blog,
},
],
};
};

View file

@ -0,0 +1,14 @@
module.exports = function preset(context, opts = {}) {
return {
plugins: [
{
name: '@docusaurus/plugin-content-pages',
options: opts.pages,
},
{
name: '@docusaurus/plugin-sitemap',
options: opts.sitemap,
},
],
};
};

View file

@ -0,0 +1,193 @@
/**
* 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.
*/
import '@babel/polyfill';
import path from 'path';
import loadPresets from '../presets';
describe('loadPresets', () => {
test('no presets', () => {
const presets = loadPresets({siteConfig: {presets: []}});
expect(presets).toEqual([]);
});
test('string form', () => {
const presets = loadPresets({
siteConfig: {
presets: [path.join(__dirname, '__fixtures__/preset-bar.js')],
},
});
expect(presets).toMatchInlineSnapshot(`
Array [
Object {
"name": "@docusaurus/plugin-content-docs",
"options": undefined,
},
Object {
"name": "@docusaurus/plugin-content-blog",
"options": undefined,
},
]
`);
});
test('string form composite', () => {
const presets = loadPresets({
siteConfig: {
presets: [
path.join(__dirname, '__fixtures__/preset-bar.js'),
path.join(__dirname, '__fixtures__/preset-foo.js'),
],
},
});
expect(presets).toMatchInlineSnapshot(`
Array [
Object {
"name": "@docusaurus/plugin-content-docs",
"options": undefined,
},
Object {
"name": "@docusaurus/plugin-content-blog",
"options": undefined,
},
Object {
"name": "@docusaurus/plugin-content-pages",
"options": undefined,
},
Object {
"name": "@docusaurus/plugin-sitemap",
"options": undefined,
},
]
`);
});
test('array form', () => {
const presets = loadPresets({
siteConfig: {
presets: [[path.join(__dirname, '__fixtures__/preset-bar.js')]],
},
});
expect(presets).toMatchInlineSnapshot(`
Array [
Object {
"name": "@docusaurus/plugin-content-docs",
"options": undefined,
},
Object {
"name": "@docusaurus/plugin-content-blog",
"options": undefined,
},
]
`);
});
test('array form with options', () => {
const presets = loadPresets({
siteConfig: {
presets: [
[
path.join(__dirname, '__fixtures__/preset-bar.js'),
{docs: {path: '../'}},
],
],
},
});
expect(presets).toMatchInlineSnapshot(`
Array [
Object {
"name": "@docusaurus/plugin-content-docs",
"options": Object {
"path": "../",
},
},
Object {
"name": "@docusaurus/plugin-content-blog",
"options": undefined,
},
]
`);
});
test('array form composite', () => {
const presets = loadPresets({
siteConfig: {
presets: [
[
path.join(__dirname, '__fixtures__/preset-bar.js'),
{docs: {path: '../'}},
],
[
path.join(__dirname, '__fixtures__/preset-foo.js'),
{pages: {path: '../'}},
],
],
},
});
expect(presets).toMatchInlineSnapshot(`
Array [
Object {
"name": "@docusaurus/plugin-content-docs",
"options": Object {
"path": "../",
},
},
Object {
"name": "@docusaurus/plugin-content-blog",
"options": undefined,
},
Object {
"name": "@docusaurus/plugin-content-pages",
"options": Object {
"path": "../",
},
},
Object {
"name": "@docusaurus/plugin-sitemap",
"options": undefined,
},
]
`);
});
test('mixed form', () => {
const presets = loadPresets({
siteConfig: {
presets: [
[
path.join(__dirname, '__fixtures__/preset-bar.js'),
{docs: {path: '../'}},
],
path.join(__dirname, '__fixtures__/preset-foo.js'),
],
},
});
expect(presets).toMatchInlineSnapshot(`
Array [
Object {
"name": "@docusaurus/plugin-content-docs",
"options": Object {
"path": "../",
},
},
Object {
"name": "@docusaurus/plugin-content-blog",
"options": undefined,
},
Object {
"name": "@docusaurus/plugin-content-pages",
"options": undefined,
},
Object {
"name": "@docusaurus/plugin-sitemap",
"options": undefined,
},
]
`);
});
});

View file

@ -31,6 +31,7 @@ const OPTIONAL_FIELDS = [
'highlight',
'markdownPlugins',
'plugins',
'presets',
];
const DEFAULT_CONFIG = {

View file

@ -6,6 +6,7 @@
*/
const fs = require('fs-extra');
const importFresh = require('import-fresh');
const path = require('path');
const {generate} = require('@docusaurus/utils');
@ -14,17 +15,11 @@ module.exports = async function loadPlugins({pluginConfigs = [], context}) {
const plugins = pluginConfigs.map(({name, path: pluginPath, options}) => {
let Plugin;
if (pluginPath && fs.existsSync(pluginPath)) {
// eslint-disable-next-line
Plugin = require(pluginPath);
Plugin = importFresh(pluginPath);
} else {
try {
// eslint-disable-next-line
Plugin = require(name);
} catch (ex) {
throw new Error(`Error loading '${name}' plugin.`);
Plugin = importFresh(name);
}
}
return new Plugin(options, context);
return new Plugin(context, options);
});
// 2. Plugin lifecycle - loadContent
@ -72,6 +67,5 @@ module.exports = async function loadPlugins({pluginConfigs = [], context}) {
return {
plugins,
pluginsRouteConfigs,
pluginsLoadedContent,
};
};

View file

@ -0,0 +1,35 @@
/**
* 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 importFresh = require('import-fresh');
const _ = require('lodash');
const fs = require('fs-extra');
module.exports = function loadPresets(context) {
const presets = context.siteConfig.presets || [];
return _.flatten(
presets.map(presetItem => {
let presetModule;
let presetOptions = {};
if (typeof presetItem === 'string') {
presetModule = presetItem;
} else if (Array.isArray(presetItem)) {
[presetModule, presetOptions] = presetItem;
}
let preset;
if (presetModule && fs.existsSync(presetModule)) {
// Local preset.
preset = importFresh(presetModule);
} else {
// From npm.
preset = importFresh(presetModule);
}
return preset(context, presetOptions).plugins;
}),
);
};

View file

@ -52,6 +52,7 @@
"fs-extra": "^7.0.0",
"globby": "^9.1.0",
"html-webpack-plugin": "^4.0.0-beta.5",
"import-fresh": "^3.0.0",
"is-wsl": "^1.1.0",
"lodash": "^4.17.11",
"mini-css-extract-plugin": "^0.4.1",

View file

@ -7,7 +7,7 @@
import '@babel/polyfill';
import path from 'path';
import load from '@lib/server/load';
import load from '@lib/server';
// Helper methods to setup dummy/fake projects
const loadSetup = async name => {

View file

@ -24,25 +24,18 @@ module.exports = {
indexName: 'docusaurus-2',
algoliaOptions: {},
},
plugins: [
presets: [
[
'@docusaurus/preset-classic',
{
name: '@docusaurus/plugin-content-docs',
options: {
docs: {
path: '../docs',
sidebarPath: require.resolve('./sidebars.json'),
},
},
{
name: '@docusaurus/plugin-content-blog',
options: {
blog: {
path: '../website-1.x/blog',
},
},
{
name: '@docusaurus/plugin-content-pages',
},
{
name: '@docusaurus/plugin-sitemap',
},
],
],
};

View file

@ -10,10 +10,7 @@
},
"dependencies": {
"@docusaurus/core": "^2.0.0-alpha.11",
"@docusaurus/plugin-content-blog": "^2.0.0-alpha.11",
"@docusaurus/plugin-content-docs": "^2.0.0-alpha.11",
"@docusaurus/plugin-content-pages": "^2.0.0-alpha.11",
"@docusaurus/plugin-sitemap": "^2.0.0-alpha.11",
"@docusaurus/preset-classic": "^2.0.0-alpha.11",
"classnames": "^2.2.6",
"react": "^16.8.4",
"react-dom": "^16.8.4"