Mini-css-extract-plugin: Vue + vue-loader 15 + webpack 4 + mini-css-e-p creates multiple css files

Created on 28 Apr 2018  ·  53Comments  ·  Source: webpack-contrib/mini-css-extract-plugin

I am losing my mind. I have googled for hours and don't know what else to try. I am moving from EWP to this module and I can't get to produce one css file. I have also updated to latest vue-loader.

Webpack Confg

const ManifestPlugin = require("webpack-manifest-plugin");
const CleanWebpackPlugin = require("clean-webpack-plugin");
const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const { VueLoaderPlugin } = require("vue-loader");
var MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
  context: __dirname + "/assets",
  entry: {
    "details-page": "./js/details-page.js",
    index: "./js/index.js",
    common: "./js/common.js",
    styles: "./css/styles.css"
  },
  optimization: {
    concatenateModules: true,
    // runtimeChunk: true,
    minimizer: [
      new OptimizeCssAssetsPlugin({
        cssProcessorOptions: {
          safe: true
        }
      })
    ],
    splitChunks: {
      cacheGroups: {
        commons: {
          test: /[\\/]node_modules[\\/]/,
          name: "vendors",
          chunks: "all"
        },
        "styles-compiled": {
          name: "styles-compiled",
          test: /\.css$/,
          chunks: "all",
          enforce: true
        }
      }
    }
  },
  output: {
    path: __dirname + "/clashleaders/static/",
    filename: "js/[name].js"
  },
  resolve: {
    extensions: [".js", ".vue", ".json"],
    alias: {
      vue$: "vue/dist/vue.esm.js"
    }
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: ["babel-loader"]
      },
      {
        test: /\.vue$/,
        loader: "vue-loader"
      },
      {
        test: /.*flags.*\.(svg)$/,
        loader: "file-loader",
        options: {
          name: "[name]-[hash].[ext]",
          outputPath: "flags/",
          publicPath: "/static/flags/"
        }
      },
      {
        test: /\.svg$/,
        exclude: [/flags/],
        use: {
          loader: "svg-url-loader"
        }
      },
      {
        test: /\.(sass|scss|css)$/,
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: "css-loader",
            query: {
              importLoaders: 1
            }
          },
          {
            loader: "postcss-loader",
            options: {
              ident: "postcss",
              plugins: loader => [
                require("postcss-import")(),
                require("postcss-cssnext")({
                  features: {
                    customProperties: { warnings: false }
                  }
                }),
                require("postcss-font-magician")()
              ]
            }
          },
          "sass-loader"
        ]
      }
    ]
  },
  plugins: [
    new ManifestPlugin(),
    new MiniCssExtractPlugin({
      filename: 'css/[name].[contenthash].css'
    }),
    new CleanWebpackPlugin([
      __dirname + "/clashleaders/static/css",
      __dirname + "/clashleaders/static/js",
      __dirname + "/clashleaders/static/flags"
    ]),
    new VueLoaderPlugin()
  ]
};

if (process.env.NODE_ENV === "production") {
  module.exports.devtool = "#source-map";
  module.exports.output.filename = "js/[name].[chunkhash].js";
}

Version
[email protected]
[email protected]

Bug
NODE_ENV='production' webpack --progress --mode production
Produces this...

screen shot 2018-04-28 at 2 15 14 pm

When I do ag --css "player-comparison" which is a class that I know is in one of the vue files I get

screen shot 2018-04-28 at 2 16 32 pm

Does this make sense? Wouldn't it make sense to get all css files in the combined css. My config and package files.

question discuss

Most helpful comment

Please don't write same issue, it is clogs thread, just add :+1: on top post, thanks!

All 53 comments

@amir20 very interesting, can you create minimum reproducible test repo?

@evilebottnawi I was able to reproduce this by creating a really simple Vue application. Here is the repo: https://github.com/amir20/vue-mini-css.

There are three entry points. One CSS file and two other javascript files.

app/
├── css
│   └── styles.css
└── js
    ├── components
    │   ├── comp1.vue
    │   └── comp2.vue
    ├── entry1.js
    └── entry2.js

After doing npm run build, it should create styles-compiled.css with all css in one place. However, it does not do that.

I have done some research since then and I am pretty sure the fix requires fixing the test in cacheGroup to something else from test: /\.css$/,. I don't believe that captures vue styles.

@amir20 how about this https://github.com/thecrypticace/webpack-css-chunks-test/blob/master/webpack.config.js#L61, looks some people extract css from vue doing this setup

I saw that as well. My goal was to create one css file. That creates two. I imagine I could put the two rules together, but does it make sense to go through all these configurations to do this? I imagine having a bunch of vue files with css is a common pattern that many people plan to do.

Hmmmmm. I can't get that to work either...

diff --git a/webpack.config.js b/webpack.config.js
index ef5453d..7c75bce 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -17,11 +17,29 @@ module.exports = {
           name: "vendors",
           chunks: "all"
         },
-        "styles-compiled": {
-          name: "styles-compiled",
-          test: /\.css$/,
+        extractVueStyles: {
+          test: m => {
+            return /\.vue\?vue&type=style/.test(m.identifier());
+          },
+          name: "vue-styles",
           chunks: "all",
-          enforce: true
+
+          // enforce: false
+          // results in no vue-styles chunk
+          // Only a bundle.css file
+          enforce: false
+        },
+        extractOtherStyles: {
+          test: m => {
+            return m.constructor.name == "CssModule";
+          },
+
+          // enforce: false
+          // results in no other-styles chunk
+          // Only a bundle.css file
+          name: "other-styles",
+          chunks: "all",
+          enforce: false
         }
       }
     }

Am I doing something wrong? :( That produces no files now.

Doing enforce: true gets me closer to having everything in other-styles.css. I have to go to work now but I'll check back soon.

Exact same problem here. My configuration differs in using MiniCssExtractPlugin.loader in the vue rules:

{
    test: /\.vue$/,
    loader: [
        {
            loader: 'vue-loader',
            options: {
                loaders: {
                    scss: [
                        'vue-style-loader',
                        MiniCssExtractPlugin.loader,
                        'css-loader?sourceMap',
                        'sass-loader?sourceMap'
                    ],
                    css: [
                        'vue-style-loader',
                        MiniCssExtractPlugin.loader,
                        'css-loader?sourceMap'
                    ]
                }
            }
        },
        {
            loader: 'eslint-loader',
            options: eslintOptions
        }
    ]
},
{
    test: /\.(css|scss)$/,
    use: [
        MiniCssExtractPlugin.loader,
        'css-loader?sourceMap',
        'sass-loader?sourceMap'
    ]
}

Still can get to merge all my the generated css in one file.

I am still not sure how to do this. I am waiting for vue-cli to integrate with vue-loader v15 and how they plan to do it.

@sokra Anything we are oversighting in order to make this work that you know about?

same issue here

same issue

Please don't write same issue, it is clogs thread, just add :+1: on top post, thanks!

I think I sorted it out finally, at least is working for me:

optimization: {
    splitChunks: {
        cacheGroups: {
            default: false,
            common: false,
            styles: {
                name: 'app',
                test: /\.(s?css|vue)$/, // chunks plugin has to be aware of all kind of files able to output css in order to put them together
                chunks: 'initial',
                minChunks: 1,
                enforce: true
            }
        }
    }
}

/cc @amir20 looks on https://github.com/webpack-contrib/mini-css-extract-plugin/issues/113#issuecomment-387309221 solution, it is works for you?

I’ll give it a try today.

Sent from my iPad

On May 8, 2018, at 2:28 AM, Evilebot Tnawi notifications@github.com wrote:

/cc @amir20 looks on #113 (comment) solution, it is works for you?


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.

I think it worked (kinda). I validated by doing ag --css ".player-comparison" which is a css that I know is part of vue.

However, I said "kinda" because my javascript now isn't executing. 👎 I need to debug more to understand what's going on.

Here is the diff for the curious

diff --git a/webpack.config.js b/webpack.config.js
index b54a754..655fb5b 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -31,8 +31,9 @@ module.exports = {
         },
         "styles-compiled": {
           name: "styles-compiled",
-          test: /\.css$/,
-          chunks: "all",
+          test: /\.(s?css|vue)$/,
+          chunks: "initial",
+          minChunks: 1,
           enforce: true
         }
       }

@amir20 can you create minimum reproducible test repo, it is help to solve your problem faster

Still working on it. I am not sure if mini-css-extract is the problem or something else I did.

Ok I have applied the changes to my old test repo at https://github.com/amir20/vue-mini-css/commit/375389e5ff297c3e2002d28b513d0484ea1cdd70

I think the problem is that all the javascript goes styles-compiled.js. You can see that here. Is that to be expected? I am guessing the pattern *.vue will also compile the javascript which is not what we want.

Does that make sense?

@amir20 sorry i am not familiar with vue and vue-loader, but i can ivnestigate what is wrong, https://github.com/amir20/vue-mini-css is minimum reproducible test repo?

Yup. I created that when I created this issue. I am pretty sure the pattern vue will also capture the output of all JavaScript files that vue components.

Sent via my iPhone

On May 8, 2018, at 8:14 AM, Evilebot Tnawi notifications@github.com wrote:

@amir20 sorry i am not familiar with vue and vue-loader, but i can ivnestigate what is wrong, https://github.com/amir20/vue-mini-css is minimum reproducible test repo?


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.

@evilebottnawi might be worth asking vue-loader or vue-cli folks in this issue? The reason people are starting to have this issue is because in the migrations documentation for v15 of vue-loader, the suggested solution is to use mini-css-extract. However, the still don't have a suggested solution and at the very top they say vue-cli will soon use the latest version.

@amir20 vue-cli have issue around this problem?

I don’t think so. Since they haven’t implemented the new version yet, there isn’t anything that is “broken”?

@amir20 Thanks for your investigations. I managed to get rid of the JS extraction problem by removing the JavaScript in the styles cacheGroup:

test: module => module.nameForCondition && /\.(s?css|vue)$/.test(module.nameForCondition()) && !/^javascript/.test(module.type)

See this issue for more details: https://github.com/webpack-contrib/mini-css-extract-plugin/issues/85

I just tried it. It looks like it might have worked.

I'll try it on my actual project this week and update back.

@alexander-heimbuch thx, it is actually worked !

Sadly, after a lot of effort, I am unable to figure out why javascript is not executing at all. I figured out when I remove <style scoped></style> in my components everything works. I suspect it has something to do with the test pattern above. I'll see if I can make the changes to my sample repo to reproduce this.

I hope there is an easier way to configure webpack 4 with mini-css-extran.

Hmm. I think I found the problem.

  optimization: {
    // concatenateModules: true,
    // runtimeChunk: true,
    splitChunks: {
      cacheGroups: {
        commons: {
          test: /node_modules/,
          chunks: "initial",
          name: "vendors"
        },
        "styles-compiled": {
          name: "styles-compiled",
          test: module =>
            module.nameForCondition &&
            /\.(s?css|vue)$/.test(module.nameForCondition()) && !/^javascript/.test(module.type),
          chunks: "all",
          enforce: true
        }
      }
    }
  },

This produces styles-compiled.css AND styles-compiled.js. Both need to be included for the javascript to work. Does anybody know of a solution where it doesn't have to produce a js file? @alexander-heimbuch ?

The contents of styles-compiled.js is only (window["webpackJsonp"] = window["webpackJsonp"] || []).push([["styles-compiled"],[]]);. So I could inline that. But that doesn't feel efficent.

I ran into the same problem

styles: {
     name: 'styles',
     test: m => m.constructor.name === 'CssModule',
     chunks: 'all',
     minChunks: 1,
     enforce: true
}

Css has been merged into one file, but will generate a redundant js file
There is an urgent need for a solution to merge or remove this extra js file;

A similar issue:

My webpack 3 build which does not use any dynamic loading (ExtractTextPlugin), resulted in one concatenated CSS file of all the styles from my .vue files, per bundle (edit: eg. "utils.js", "page1.js" "page2.js" resulted in "utils.css", "page1.css", "page2.css" -- where "utils" was my common / root bundle used across the site).

I couldn't make that work in Webpack 4. I tried many snippets I found online, always ended up with ONE styles file, even though my 3 javascript bundles are being output. And, there would be indeed this extra "styles.js" file which Webpack 3 + ExtractTextPlugin didn't produce.

I ran into the same problem...
image

For everybody who is coming to this issue. I solved this problem by inlining styles.js. I am currently on a flask app so I did something like <script>{{ inline_path("styles-compiled.js") | safe }}</script>

I don't know of any other solution where styles.js can be part of the main chunk. Hope this helps.

Any news on this one?
Removing the redundant file is not an option because without including it my entry js doesn't even run?

How is this actually getting almost to none attention? This means you can't bundle your css in anyway?

Having the same issue, have tried many MANY approaches. The only thing that's done anything remotely useful is the one below.

This gives me the desired result (of merging the inline style outputs from vue components into one file) but still there are JS versions of these styles being generated resulting in inline styles on the page AND these. Not sure how fix this, this whole process has been a nightmare.

Here's my current vue.config.js, can post my webpack.config as well: http://jsfiddle.net/av42ky7d/

I think I sorted it out finally, at least is working for me:

optimization: {
    splitChunks: {
        cacheGroups: {
            default: false,
            common: false,
            styles: {
                name: 'app',
                test: /\.(s?css|vue)$/, // chunks plugin has to be aware of all kind of files able to output css in order to put them together
                chunks: 'initial',
                minChunks: 1,
                enforce: true
            }
        }
    }
}

Guys before write here please create minimum reproducible test repo and add link on this repo in post, it is help to solve your issue(s).

I believe this is a similar issue. For me, even if I'm able to extract all the CSS out into one file, it breaks the component entry files.

Minimal reproduction repo: https://github.com/hirokiosame/test-build

Related to #85 and #45 !
With more than 80 👍, it seems to be a problem for many of us...
I'm trying to found a fix for 2 days non stop, made so many tests... 😭😭😭
I hope someone can find a fix soon ! ❤️Vue

I am quite urgently in need for a way to concatenate all my css files now..
at the moment, I am running this script to do the concatenation manually

https://gist.github.com/amoshydra/f0a79123fd184088e7e674333d0fc191

node concatenate-css.js dist/css/*.css dist/style.css

At the moment, I can't apply any cacheGroups without breaking my builds

Here two problem:

  1. One people want to have one file.
  2. Other people want multiple files.

What is problem here? Don't do this in future - don't write difference issues in one issue. It is hard to understand what is problem you want to solve.

So only top issue was solved here, other will be ignored - one problem = one issue.

/cc @amir20 sorry for big delay, a lot of work, problem still exists? If yes can you create latest actual repository and describe in readme what you have and what you expected?

@evilebottnawi I believe this repo reproduces his issue https://github.com/hirokiosame/test-build

@hirokiosame what you expected? All in one file or each component create own css file?

All in one file

On Tue, Dec 11, 2018 at 1:39 Evilebot Tnawi notifications@github.com
wrote:

@hirokiosame https://github.com/hirokiosame what you expected? All in
one file or each component create own css file?


You are receiving this because you were mentioned.

Reply to this email directly, view it on GitHub
https://github.com/webpack-contrib/mini-css-extract-plugin/issues/113#issuecomment-446135703,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABBp7goC1O2aV7cytEAbW_bR1MuwhQAVks5u331agaJpZM4TrkdF
.

>

Kind regards,
Hiroki Osame

@hirokiosame do you try above examples?

Yes, I've tried the various webpack configs.

Try cloning the repo. I wrote this in the ReadMe, and it's also
communicated in the thread above, but once the CSS is outputted in one
file, the JS breaks.

On Tue, Dec 11, 2018 at 1:44 Evilebot Tnawi notifications@github.com
wrote:

@hirokiosame https://github.com/hirokiosame do you try above examples?


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/webpack-contrib/mini-css-extract-plugin/issues/113#issuecomment-446137112,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABBp7uZ4kmVFDDpJ3AmRxQjZHfWs-IY1ks5u335mgaJpZM4TrkdF
.

>

Kind regards,
Hiroki Osame

Ya exact same problem as @hirokiosame !
When CSS is bundled to one file the JS breaks.

@jimblue What you mean breaks?

@evilebottnawi I used to have a repo to show this bug. I think I have deleted it and gotten a new laptop since so I don't have the work anymore.

The bug is simple. I don't think there is any need to have a lot of conversations about this. When creating a single css file, a javascript file is also created that is required for the whole thing to run. That's the bug. So the final files are 1. styles.css, 2. styles.js and 3. scripts.js. To fix the bug, styles.js needs to be included in script.js.

The contents of the JS file is (window.webpackJsonp=window.webpackJsonp||[]).push([[0],[]]);.

Hope this helps. The bug is pretty big in my opinion and there it should be very easy to reproduce.

@amir20 not related to this issue (see https://github.com/webpack-contrib/mini-css-extract-plugin/issues/85), it is bug in webpack and we need fix it in webpack, can't be fixed in plugin

i have a same question, any one has the answer?

Please open issue in vue-loader, if somebody thinks what we have bug on our side, please open new an issue with reproducible test repo

nwrightau's solution worked for me

Was this page helpful?
0 / 5 - 0 ratings