mirror of
https://github.com/facebook/docusaurus.git
synced 2025-07-23 19:48:54 +02:00
feat(v2): implement client modules API (#1554)
* feat(v2): load client modules * docs(v2): update plugins API * misc(v2): change to import
This commit is contained in:
parent
90138d52c2
commit
c06ccc0a07
9 changed files with 174 additions and 3 deletions
|
@ -8,12 +8,15 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {renderRoutes} from 'react-router-config';
|
import {renderRoutes} from 'react-router-config';
|
||||||
|
|
||||||
import Head from '@docusaurus/Head';
|
|
||||||
import routes from '@generated/routes';
|
import routes from '@generated/routes';
|
||||||
import siteConfig from '@generated/docusaurus.config';
|
import siteConfig from '@generated/docusaurus.config';
|
||||||
|
|
||||||
|
import Head from '@docusaurus/Head';
|
||||||
import DocusaurusContext from '@docusaurus/context';
|
import DocusaurusContext from '@docusaurus/context';
|
||||||
import PendingNavigation from './PendingNavigation';
|
import PendingNavigation from './PendingNavigation';
|
||||||
|
|
||||||
|
import '@generated/client-modules';
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
<DocusaurusContext.Provider value={{siteConfig}}>
|
<DocusaurusContext.Provider value={{siteConfig}}>
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
module.exports = function() {
|
||||||
|
return {
|
||||||
|
name: 'plugin-empty',
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,8 @@
|
||||||
|
module.exports = function() {
|
||||||
|
return {
|
||||||
|
name: 'plugin-foo-bar',
|
||||||
|
getClientModules() {
|
||||||
|
return ['foo', 'bar'];
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,8 @@
|
||||||
|
module.exports = function() {
|
||||||
|
return {
|
||||||
|
plugin: 'plugin-hello-world',
|
||||||
|
getClientModules() {
|
||||||
|
return ['hello', 'world'];
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,94 @@
|
||||||
|
/**
|
||||||
|
* 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 path from 'path';
|
||||||
|
|
||||||
|
import {loadClientModules} from '../index';
|
||||||
|
import {LoadContext} from '../../index';
|
||||||
|
|
||||||
|
const pluginEmpty = require('./__fixtures__/plugin-empty');
|
||||||
|
const pluginFooBar = require('./__fixtures__/plugin-foo-bar');
|
||||||
|
const pluginHelloWorld = require('./__fixtures__/plugin-hello-world');
|
||||||
|
|
||||||
|
describe('loadClientModules', () => {
|
||||||
|
test('empty', () => {
|
||||||
|
const clientModules = loadClientModules([pluginEmpty()]);
|
||||||
|
expect(clientModules).toMatchInlineSnapshot(`Array []`);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('non-empty', () => {
|
||||||
|
const clientModules = loadClientModules([pluginFooBar()]);
|
||||||
|
expect(clientModules).toMatchInlineSnapshot(`
|
||||||
|
Array [
|
||||||
|
"foo",
|
||||||
|
"bar",
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('multiple non-empty', () => {
|
||||||
|
const clientModules = loadClientModules([
|
||||||
|
pluginFooBar(),
|
||||||
|
pluginHelloWorld(),
|
||||||
|
]);
|
||||||
|
expect(clientModules).toMatchInlineSnapshot(`
|
||||||
|
Array [
|
||||||
|
"foo",
|
||||||
|
"bar",
|
||||||
|
"hello",
|
||||||
|
"world",
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('multiple non-empty different order', () => {
|
||||||
|
const clientModules = loadClientModules([
|
||||||
|
pluginHelloWorld(),
|
||||||
|
pluginFooBar(),
|
||||||
|
]);
|
||||||
|
expect(clientModules).toMatchInlineSnapshot(`
|
||||||
|
Array [
|
||||||
|
"hello",
|
||||||
|
"world",
|
||||||
|
"foo",
|
||||||
|
"bar",
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('empty and non-empty', () => {
|
||||||
|
const clientModules = loadClientModules([
|
||||||
|
pluginHelloWorld(),
|
||||||
|
pluginEmpty(),
|
||||||
|
pluginFooBar(),
|
||||||
|
]);
|
||||||
|
expect(clientModules).toMatchInlineSnapshot(`
|
||||||
|
Array [
|
||||||
|
"hello",
|
||||||
|
"world",
|
||||||
|
"foo",
|
||||||
|
"bar",
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('empty and non-empty different order', () => {
|
||||||
|
const clientModules = loadClientModules([
|
||||||
|
pluginHelloWorld(),
|
||||||
|
pluginFooBar(),
|
||||||
|
pluginEmpty(),
|
||||||
|
]);
|
||||||
|
expect(clientModules).toMatchInlineSnapshot(`
|
||||||
|
Array [
|
||||||
|
"hello",
|
||||||
|
"world",
|
||||||
|
"foo",
|
||||||
|
"bar",
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
24
packages/docusaurus/src/server/client-modules/index.ts
Normal file
24
packages/docusaurus/src/server/client-modules/index.ts
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
/**
|
||||||
|
* 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 {Plugin} from '../plugins';
|
||||||
|
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
export function loadClientModules(plugins: Plugin<any>[]): string[] {
|
||||||
|
return _.compact(
|
||||||
|
_.flatten<string | null>(
|
||||||
|
plugins.map(plugin => {
|
||||||
|
if (!plugin.getClientModules) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return plugin.getClientModules();
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
|
@ -17,6 +17,8 @@ import {loadThemeAlias} from './themes';
|
||||||
import {loadPlugins} from './plugins';
|
import {loadPlugins} from './plugins';
|
||||||
import {loadRoutes} from './routes';
|
import {loadRoutes} from './routes';
|
||||||
import {loadPresets} from './presets';
|
import {loadPresets} from './presets';
|
||||||
|
import {loadClientModules} from './client-modules';
|
||||||
|
|
||||||
import {GENERATED_FILES_DIR_NAME, CONFIG_FILE_NAME} from '../constants';
|
import {GENERATED_FILES_DIR_NAME, CONFIG_FILE_NAME} from '../constants';
|
||||||
|
|
||||||
export interface CLIOptions {
|
export interface CLIOptions {
|
||||||
|
@ -96,6 +98,16 @@ export async function load(
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Load client modules.
|
||||||
|
const clientModules = loadClientModules(plugins);
|
||||||
|
const genClientModules = generate(
|
||||||
|
generatedFilesDir,
|
||||||
|
'client-modules.js',
|
||||||
|
`export default [\n${clientModules
|
||||||
|
.map(module => ` require(${JSON.stringify(module)}),`)
|
||||||
|
.join('\n')}\n];\n`,
|
||||||
|
);
|
||||||
|
|
||||||
// Routing
|
// Routing
|
||||||
const {
|
const {
|
||||||
registry,
|
registry,
|
||||||
|
@ -128,6 +140,7 @@ ${Object.keys(registry)
|
||||||
const genRoutes = generate(generatedFilesDir, 'routes.js', routesConfig);
|
const genRoutes = generate(generatedFilesDir, 'routes.js', routesConfig);
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
|
genClientModules,
|
||||||
genSiteConfig,
|
genSiteConfig,
|
||||||
genRegistry,
|
genRegistry,
|
||||||
genRoutesChunkNames,
|
genRoutesChunkNames,
|
||||||
|
|
|
@ -26,6 +26,7 @@ export interface Plugin<T> {
|
||||||
configureWebpack?(config: Configuration, isServer: boolean): Configuration;
|
configureWebpack?(config: Configuration, isServer: boolean): Configuration;
|
||||||
getThemePath?(): string;
|
getThemePath?(): string;
|
||||||
getPathsToWatch?(): string[];
|
getPathsToWatch?(): string[];
|
||||||
|
getClientModules?(): string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PluginConfig {
|
export interface PluginConfig {
|
||||||
|
|
|
@ -66,8 +66,12 @@ module.exports = function(context, opts) {
|
||||||
const options = {...DEFAULT_OPTIONS, ...options};
|
const options = {...DEFAULT_OPTIONS, ...options};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// Namespace used for directories to cache the intermediate data for each plugin.
|
// A compulsory field used as the namespace for directories to cache
|
||||||
name: 'docusaurus-cool-plugin',
|
// the intermediate data for each plugin.
|
||||||
|
// If you're writing your own local plugin, you will want it to
|
||||||
|
// be unique in order not to potentially conflict with imported plugins.
|
||||||
|
// A good way will be to add your own project name within.
|
||||||
|
name: 'docusaurus-my-project-cool-plugin',
|
||||||
|
|
||||||
async loadContent() {
|
async loadContent() {
|
||||||
// The loadContent hook is executed after siteConfig and env has been loaded
|
// The loadContent hook is executed after siteConfig and env has been loaded
|
||||||
|
@ -107,6 +111,17 @@ module.exports = function(context, opts) {
|
||||||
getPathsToWatch() {
|
getPathsToWatch() {
|
||||||
// Path to watch
|
// Path to watch
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getThemePath() {
|
||||||
|
// Returns the path to the directory where the theme components can
|
||||||
|
// be found.
|
||||||
|
},
|
||||||
|
|
||||||
|
getClientModules() {
|
||||||
|
// Return an array of paths to the modules that are to be imported
|
||||||
|
// in the client bundle. These modules are imported globally before
|
||||||
|
// React even renders the initial UI.
|
||||||
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue