Skip to content

Vue + vue-loader 15 + webpack 4 + mini-css-e-p creates multiple css files #113

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
amir20 opened this issue Apr 28, 2018 · 55 comments
Closed

Comments

@amir20
Copy link

amir20 commented Apr 28, 2018

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.

@alexander-akait
Copy link
Member

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

@amir20
Copy link
Author

amir20 commented Apr 30, 2018

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

@alexander-akait
Copy link
Member

@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

@amir20
Copy link
Author

amir20 commented Apr 30, 2018

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.

@amir20
Copy link
Author

amir20 commented Apr 30, 2018

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.

@amir20
Copy link
Author

amir20 commented Apr 30, 2018

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.

@nass600
Copy link

nass600 commented May 1, 2018

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.

@amir20
Copy link
Author

amir20 commented May 1, 2018

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.

@nass600
Copy link

nass600 commented May 2, 2018

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

@eugenioclrc
Copy link

same issue here

@jiubao
Copy link

jiubao commented May 6, 2018

same issue

@alexander-akait
Copy link
Member

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

@nass600
Copy link

nass600 commented May 8, 2018

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

@alexander-akait
Copy link
Member

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

@amir20
Copy link
Author

amir20 commented May 8, 2018 via email

@amir20
Copy link
Author

amir20 commented May 8, 2018

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

@alexander-akait
Copy link
Member

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

@amir20
Copy link
Author

amir20 commented May 8, 2018

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

@amir20
Copy link
Author

amir20 commented May 8, 2018

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?

@alexander-akait
Copy link
Member

@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?

@amir20
Copy link
Author

amir20 commented May 8, 2018 via email

@amir20
Copy link
Author

amir20 commented May 8, 2018

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

@alexander-akait
Copy link
Member

@amir20 vue-cli have issue around this problem?

@amir20
Copy link
Author

amir20 commented May 8, 2018

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

@alexander-heimbuch
Copy link

alexander-heimbuch commented Jun 5, 2018

@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: #85

@amir20
Copy link
Author

amir20 commented Jun 5, 2018

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

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

@Tk-archer
Copy link

@alexander-heimbuch thx, it is actually worked !

@amir20
Copy link
Author

amir20 commented Jun 25, 2018

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.

@amir20
Copy link
Author

amir20 commented Jun 25, 2018

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.

@fabd
Copy link

fabd commented Sep 7, 2018

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.

@luckyyyyy
Copy link

luckyyyyy commented Oct 16, 2018

I ran into the same problem...
image

@amir20
Copy link
Author

amir20 commented Oct 17, 2018

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.

@thaoms
Copy link

thaoms commented Nov 24, 2018

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?

@nwrightau
Copy link

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

@alexander-akait
Copy link
Member

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

@privatenumber
Copy link
Contributor

privatenumber commented Dec 4, 2018

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

@jimblue
Copy link

jimblue commented Dec 5, 2018

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

@amoshydra
Copy link

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

@alexander-akait
Copy link
Member

alexander-akait commented Dec 11, 2018

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.

@alexander-akait
Copy link
Member

/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?

@privatenumber
Copy link
Contributor

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

@alexander-akait
Copy link
Member

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

@privatenumber
Copy link
Contributor

privatenumber commented Dec 11, 2018 via email

@alexander-akait
Copy link
Member

@hirokiosame do you try above examples?

@privatenumber
Copy link
Contributor

privatenumber commented Dec 11, 2018 via email

@jimblue
Copy link

jimblue commented Dec 11, 2018

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

@alexander-akait
Copy link
Member

alexander-akait commented Dec 11, 2018

@jimblue What you mean breaks?

@amir20
Copy link
Author

amir20 commented Dec 11, 2018

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

@alexander-akait
Copy link
Member

@amir20 not related to this issue (see #85), it is bug in webpack and we need fix it in webpack, can't be fixed in plugin

@LoveShoneLiu
Copy link

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

@alexander-akait
Copy link
Member

alexander-akait commented Dec 17, 2019

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

@tarponjargon
Copy link

nwrightau's solution worked for me

@pascencio
Copy link

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

This works perfectly. I have a doubt ...How can I change the final css name?

@alexander-akait
Copy link
Member

Using filename

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests