facebook / docusaurus

Easy to maintain open source documentation websites.
https://docusaurus.io
MIT License
56.85k stars 8.56k forks source link

Docusaurus Faster - For plugins authors #10572

Open slorber opened 1 month ago

slorber commented 1 month ago

Docusaurus Faster - For plugins authors

Docusaurus Faster sister issue for plugin authors implementing the configureWebpack() lifecycle hook.

How to migrate your code

The general idea is that you shouldn't import Weppack directly, because... It will always be Webpack.

You should avoid this kind of code:

import webpack from 'webpack';

require("webpack");

What you should do instead is use a dynamic value that will be either Webpack or Rspack:

If your plugin doesn't import Webpack directly and only tweaks a bit the config as data, it will probably work out of the box.

Example diff of a typical plugin that needs to be updated

-import webpack from 'webpack';

export default function (context, options) {
  return {
    name: 'custom-docusaurus-plugin',
-   configureWebpack(config, isServer) {
+   configureWebpack(config, isServer, {currentBundler}) {
      return {
        plugins: [
-         new webpack.DefinePlugin({}),
+         new currentBundler.instance.DefinePlugin({}),
        ]
      };
    },
  };
}

Example diff of a Webpack plugin coming from node-polyfill-webpack-plugin v3:

-const {ProvidePlugin} = require('webpack');

class NodePolyfillPlugin {
    apply(compiler) {
-       compiler.options.plugins.push(new ProvidePlugin({...});
+       compiler.options.plugins.push(new compiler.webpack.ProvidePlugin({});
    }
}

Retrocompatibility

For plugins published on npm, the currentBundler is only injected starting Docusaurus v3.6.

If you still want to keep retro compatibility with older v3 versions, you can write defensive code like this:

export default function (context, options) {
  return {
    name: 'custom-docusaurus-plugin',
    configureWebpack(config, isServer, {currentBundler}) {
      const bundler = (currentBundler.instance ?? require("webpack"))
      return {
        plugins: [
          new bundler.DefinePlugin({}),
        ]
      };
    },
  };
}

Using third-party Webpack plugins

It is possible that third-party Webpack plugins published on npm do not work with Rspack.

Usually, the Rspack team tries to provide built-in plugins for most popular Webpack plugins, and you'll need to integrate them with if/else conditions using currentBundler.name = "webpack" | "rspack".

Here's how we do this: https://github.com/facebook/docusaurus/blob/main/packages/docusaurus-bundler/src/currentBundler.ts

As far as I have seen, none of the popular plugins in the Docusaurus community are in this situation. Please let me know what Webpack plugin you are trying to use and we'll figure out a solution.

Examples

Here are a few examples of community plugin PRs to add support:

Good luck!

rohit-gohri commented 3 weeks ago

I think the Retrocompatibility example is reversed:

      const bundler = (require("webpack") ?? currentBundler.instance)

but should be ->

      const bundler = (currentBundler.instance ?? require("webpack"))
slorber commented 3 weeks ago

Definitively, thanks for catching that 😅