This post details how to modify your Docusaurus site's webpack configuration.
The TLDR presented below is meant as a quick-reference.
TLDR
Create plugins folder: Create a
plugins
folder at your project root.Create a plugin: Create a plugin (e.g.,
my-loaders
) inside theplugins
folder withindex.js
andpackage.json
files:index.js
andpackage.json
file contentsAs noted in the Docusaurus docs for
configureWebpack()
, the return object highlighted below gets merged into the final webpack config./plugins/my-loaders/index.jsmodule.exports = function (context, options) {
return {
name: 'my-loaders',
configureWebpack(config, isServer) {
return {
module: {
rules: [
{
test: /\.m?js/,
resolve: {
fullySpecified: false
}
},
],
},
};
},
};
};/plugins/my-loaders/package.json{
"name": "my-loaders",
"version": "0.0.0",
"private": true
}Update Docusaurus config: Update your Docusaurus configuration file to use the plugin:
/docusaurus.config.jsplugins: [
// ...
'my-loaders'
// ...
]Update project dependency list to use plugin: Specify the plugin as a dependency in the
package.json
at your project root:/package.json{
// ...
"dependencies": {
// ...
"my-loaders": "file:plugins/my-loaders",
// ...
},
// ...
}Install new plugin dependency for project: Execute the following to make use of the new plugin in your project:
npm i
Problem
I recently ran into an issue using giscus, specifically @giscus/react
(version 2.2.0
), as I noted in a GitHub issue. I was able to concoct a janky workaround as a temporary solution (without having to update the @giscus/react
package version), namely by styling the shadow DOM:
giscus-widget::part(iframe) {
color-scheme: dark;
}
The package maintainer sensibly asked me to update to the most recent version, namely v2.2.3
at the time. I updated my version and got the following error:
Module not found: Error: Can't resolve 'react/jsx-runtime' in '/.../node_modules/@giscus/react/dist'
Did you mean 'jsx-runtime.js'?
BREAKING CHANGE: The request 'react/jsx-runtime' failed to resolve only because it was resolved as fully specified
(probably because the origin is strict EcmaScript Module, e.g. a module with javascript mimetype, a '*.mjs' file, or a '*.js' file where the package.json contains '"type": "module"').
The extension in the request is mandatory for it to be fully specified.
Add the extension to the request.
client (webpack 5.73.0) compiled with 1 error
It then became clear that I needed to update my Docusaurus webpack config somehow. But the Docusaurus docs were anything but clear to me. After some rooting around, I figured out a solution that works (at least for now), as detailed below.
Solution
Webpack error
As noted in this GitHub issue comment within the webpack repo:
Since webpack 5.0.0-beta.30, you're required to specify extensions when using
import
s in.mjs
files or any.js
files with apackage.json
with"type": "module"
. You can still disable the behavior withresolve.fullySpecified
set tofalse
if you see any related errors in your project.
The first line of the error message above tells us where to look in order to try to resolve the error:
Module not found: Error: Can't resolve 'react/jsx-runtime' in '/.../node_modules/@giscus/react/dist'
The first line of the referenced file illustrates the problem:
import { jsx as b } from "react/jsx-runtime";
As noted in another GitHub issue comment within the webpack repo, the following webpack configuration will disable the module resolution error due to the import not being fully specified:
{
test: /\.m?js/,
resolve: {
fullySpecified: false
}
}
Great. But for this solution to be of any use we need to know how to update our Docusaurus site's default webpack configuration. How do we do that?
Updating the config
The Docusaurus documentation was not as helpful as I had hoped it would be in trying to update the default webpack configuration. The most helpful information I came across was a GitHub issue thread on the Docusaurus GitHub repo, but the commentary was mixed in its utility. What follows is a quick run through as to how I used the issue thread linked above to resolve the error first mentioned in this post.
Create a plugins folder
Create a plugins
folder at the project root along with a my-loaders
subfolder that has two files, index.js
and package.json
:
module.exports = function (context, options) {
return {
name: 'my-loaders',
configureWebpack(config, isServer) {
return {
module: {
rules: [
{
test: /\.m?js/,
resolve: {
fullySpecified: false
}
},
],
},
};
},
};
};
{
"name": "my-loaders",
"version": "0.0.0",
"private": true
}
Update Docusaurus config to use your plugin
Update your Docusuaurus config to use the my-loaders
plugin created in the previous step:
plugins: [
// ...
'my-loaders'
// ...
]
Specify plugin as a project dependency and install
Now that the plugin has been created and specified for use within your Docusaurus project, it is now time to specify the plugin as a project dependency. Update the package.json
file at your project root with my-loaders
specified as a dependency:
{
// ...
"dependencies": {
// ...
"my-loaders": "file:plugins/my-loaders",
// ...
},
// ...
}
Finally, run the following from your project root to install the new my-loaders
dependency for your project (along with whatever other dependencies you may have added):
npm i
If everything worked out as described above without error, then you should be up and running and good to go.
Final note
We may have achieved the desired result at this point (hopefully), but how did we actually update the default Docusaurus webpack configuration? It seems highly likely this was achieved by means of configureWebpack()
in the my-loaders
plugin. But why did we have to use a plugin and what does configureWebpack()
accomplish?
configureWebpack()
The answer to the question above may be found in the Docusaurus docs, which may now prove to be useful in terms of gaining an understanding as to what is going on underneath the hood:
configureWebpack(config, isServer, utils, content)
modifies the internal webpack config. If the return value is a JavaScript object, it will be merged into the final config usingwebpack-merge
. If it is a function, it will be called and receiveconfig
as the first argument and anisServer
flag as the second argument.
More complete details may be found in the docs, but the important piece of information from the excerpt above is this bit
If the return value is a JavaScript object, it will be merged into the final config.
Is our return value a JavaScript object? Yes, it is:
module.exports = function (context, options) {
return {
name: 'my-loaders',
configureWebpack(config, isServer) {
return {
module: {
rules: [
{
test: /\.m?js/,
resolve: {
fullySpecified: false
}
},
],
},
};
},
};
};
The highlighted object above ultimately gets merged into the final webpack config, thus modifying the default Docusaurus webpack config, as desired. Specifically, the error detailed in the problem statement at the beginning of this post has now been resolved.