I'm trying to get mini-css-extract-plugin to play nicely with react-loadable on the server. Everything seems relatively easy except that when I run Loadable.preloadAll() on the server, requireEnsure gets called for every async chunk. If the async chunk has CSS that hasn't been loaded it tries to insert a new link element, a ReferenceError: document is not defined gets thrown.
@ctbarna Thanks for issue. Can you create minimum reproducible test repo?
I can give it a shot but I will admit that I am not well versed in bootstrapping an SSR repo. The gist of the issue is that this creates a browser dependency in the webpackrequireEnsure method.
@ctbarna without reproducible test repo very difficult find problem :disappointed:
I had the same issue. If I'm not mistaken, the plugin uses document.createElement("link") to load the chunks. Running this server-side results in the reference error.
Here is a solution: Bundle your app for the client and additionally bundle your app for the server. When bundling for the server don't use mini-css-extract-plugin. Instead you use loader: 'css-loader/locals'.
When you bundle the client, create a react-loadable.json file using ReactLoadablePlugin. You can use this file on the server to figure out which chunks need to be rendered into <script> tags in your HTML. How you do this is described in the documentation of react-loadable in the "Server Side Rendering" section.
I hope that helped.
@jonasIv Thank you for your solution. It also worked for Nuxt.js but we have lost critical-path CSS.
When bundling for the server don't use mini-css-extract-plugin. Instead you use loader: 'css-loader/locals'.
use extract-css-chunks-webpack-plugin instead mini-css-extract-plugin
webpack.base.config.js
const ExtractCssChunksPlugin = require('extract-css-chunks-webpack-plugin')
{
...
{
test: /\.css$/,
use: [
{
loader: ExtractCssChunksPlugin.loader,
options: {
hot: !isProd,
reloadAll: !isProd
}
},
'postcss-loader',
'css-loader'
]
},
{
test: /\.less$/,
use: [
{
loader: ExtractCssChunksPlugin.loader,
options: {
hot: !isProd,
reloadAll: !isProd
}
},
'css-loader',
'postcss-loader',
'less-loader'
]
}
...
plugins: [
...
new ExtractCssChunksPlugin({
filename: isProd ? 'css/[name].[contenthash:8].css' : '[name].css',
chunkFilename: isProd ? 'css/[name].[contenthash:8].chunk.css' : '[name].chunk.css'
})
]
}
webpack.server.config.js
{
...
plugins: [
new webpack.optimize.LimitChunkCountPlugin({
maxChunks: 1
})
]
}
Most helpful comment
I had the same issue. If I'm not mistaken, the plugin uses
document.createElement("link")to load the chunks. Running this server-side results in the reference error.Here is a solution: Bundle your app for the client and additionally bundle your app for the server. When bundling for the server don't use mini-css-extract-plugin. Instead you use
loader: 'css-loader/locals'.When you bundle the client, create a
react-loadable.jsonfile using ReactLoadablePlugin. You can use this file on the server to figure out which chunks need to be rendered into<script>tags in your HTML. How you do this is described in the documentation of react-loadable in the "Server Side Rendering" section.I hope that helped.