Mini-css-extract-plugin: Async loading without document context throws errors

Created on 21 Mar 2018  ·  7Comments  ·  Source: webpack-contrib/mini-css-extract-plugin

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.

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.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.

All 7 comments

@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
    })
  ]
}

extract-css-chunks-webpack-plugin

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mike1808 picture mike1808  ·  3Comments

elgs picture elgs  ·  3Comments

dstarosta picture dstarosta  ·  3Comments

grrowl picture grrowl  ·  3Comments

BODhaha picture BODhaha  ·  3Comments