diff --git a/packages/docusaurus-types/src/index.d.ts b/packages/docusaurus-types/src/index.d.ts index 488638e55fab..30af42f3757d 100644 --- a/packages/docusaurus-types/src/index.d.ts +++ b/packages/docusaurus-types/src/index.d.ts @@ -41,6 +41,7 @@ export interface DocusaurusConfig { [key: string]: unknown; } )[]; + clientModules?: string[]; ssrTemplate?: string; stylesheets?: ( | string diff --git a/packages/docusaurus/src/client/client-lifecycles-dispatcher.ts b/packages/docusaurus/src/client/client-lifecycles-dispatcher.ts index 522e8e15ef3d..0baceda2a5fd 100644 --- a/packages/docusaurus/src/client/client-lifecycles-dispatcher.ts +++ b/packages/docusaurus/src/client/client-lifecycles-dispatcher.ts @@ -20,9 +20,11 @@ function dispatchLifecycleAction( ...args: any[] ) { clientModules.forEach((clientModule) => { - const mod = clientModule.__esModule ? clientModule.default : clientModule; - if (mod && mod[lifecycleAction]) { - mod[lifecycleAction](...args); + const lifecycleFunction = + clientModule?.default?.[lifecycleAction] ?? clientModule[lifecycleAction]; + + if (lifecycleFunction) { + lifecycleFunction(...args); } }); } diff --git a/packages/docusaurus/src/server/configValidation.ts b/packages/docusaurus/src/server/configValidation.ts index e609298b431a..c80e26fe0d41 100644 --- a/packages/docusaurus/src/server/configValidation.ts +++ b/packages/docusaurus/src/server/configValidation.ts @@ -91,6 +91,7 @@ const ConfigSchema = Joi.object({ type: Joi.string().required(), }).unknown(), ), + clientModules: Joi.array().items(Joi.string()), tagline: Joi.string().allow(''), titleDelimiter: Joi.string().default('|'), }); diff --git a/packages/docusaurus/src/server/index.ts b/packages/docusaurus/src/server/index.ts index 712ac9765f6c..bcd2c84843a3 100644 --- a/packages/docusaurus/src/server/index.ts +++ b/packages/docusaurus/src/server/index.ts @@ -104,11 +104,18 @@ export async function load( // Make a fake plugin to: // - Resolve aliased theme components // - Inject scripts/stylesheets - const {stylesheets = [], scripts = []} = siteConfig; + const { + stylesheets = [], + scripts = [], + clientModules: siteConfigClientModules = [], + } = siteConfig; plugins.push({ name: 'docusaurus-bootstrap-plugin', options: {}, version: {type: 'synthetic'}, + getClientModules() { + return siteConfigClientModules; + }, configureWebpack: () => ({ resolve: { alias, diff --git a/website/docs/api/docusaurus.config.js.md b/website/docs/api/docusaurus.config.js.md index 6a3e2097cc60..849934849252 100644 --- a/website/docs/api/docusaurus.config.js.md +++ b/website/docs/api/docusaurus.config.js.md @@ -306,6 +306,23 @@ module.exports = { }; ``` +### `clientModules` + +An array of client modules to load globally on your site: + +Example: + +```js title="docusaurus.config.js" +module.exports = { + clientModules: [ + require.resolve('./mySiteGlobalJs.js'), + require.resolve('./mySiteGlobalCss.css'), + ], +}; +``` + +See also: [`getClientModules()`](lifecycle-apis.md#getclientmodules). + ### `ssrTemplate` An HTML template written in [Eta's syntax](https://eta.js.org/docs/syntax#syntax-overview) that will be used to render your application. This can be used to set custom attributes on the `body` tags, additional `meta` tags, customize the `viewport`, etc. Please note that Docusaurus will rely on the template to be correctly structured in order to function properly, once you do customize it, you will have to make sure that your template is compliant with the requirements from `upstream`. diff --git a/website/docs/lifecycle-apis.md b/website/docs/lifecycle-apis.md index e73395c32c25..0cbf6247d003 100644 --- a/website/docs/lifecycle-apis.md +++ b/website/docs/lifecycle-apis.md @@ -531,17 +531,17 @@ module.exports.getSwizzleComponentList = () => swizzleAllowedComponents; Returns 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. -As an example, to make your theme load a `customCss` object from `options` passed in by the user: +As an example, to make your theme load a `customCss` or `customJs` file path from `options` passed in by the user: ```js {7-9} title="my-theme/src/index.js" const path = require('path'); module.exports = function (context, options) { - const {customCss} = options || {}; + const {customCss, customJs} = options || {}; return { name: 'name-of-my-theme', getClientModules() { - return [customCss]; + return [customCss, customJs]; }, }; }; diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index d92a72095c49..09b2b8c0d993 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -54,6 +54,7 @@ module.exports = { description: 'An optimized site generator in React. Docusaurus helps you to move fast and write content. Build documentation websites, blogs, marketing pages, and more.', }, + clientModules: [require.resolve('./dogfooding/clientModuleExample.ts')], themes: ['@docusaurus/theme-live-codeblock'], plugins: [ [ diff --git a/website/dogfooding/clientModuleExample.ts b/website/dogfooding/clientModuleExample.ts new file mode 100644 index 000000000000..83b5c253ba74 --- /dev/null +++ b/website/dogfooding/clientModuleExample.ts @@ -0,0 +1,16 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment'; + +export function onRouteUpdate({location}: {location: Location}) { + console.log('onRouteUpdate', {location}); +} + +if (ExecutionEnvironment.canUseDOM) { + console.log('client module example log'); +}