webpack-contrib / mini-css-extract-plugin

Lightweight CSS extraction plugin

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

CSS bundle not generated on production mode

JMSantos94 opened this issue · comments

I am having issues configuring this plugin on mode: 'production'. The CSS bundle is not generated. However, for some reason everything works as expected if I switch to mode: 'development'. Is this expected?

Here is a minimal setup to test this out:

webpack.config.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const path = require('path');

module.exports = {
    mode: 'production',
    entry: [
        path.resolve(__dirname, 'src/index.js')
    ],
    output: {
        filename: '[name].[chunkhash].js'
    },
    plugins: [
        new MiniCssExtractPlugin({
            filename: '[name].[chunkhash].css'
        })
    ],
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    "css-loader"
                ]
            }
        ]
    }
};
src/index.js
import './styles.css'
styles.css
body {
    background-color: blue;
}

Here is what I am using:

OS: Arch
webpack: 4.1.1
mini-css-extract-plugin: 0.2.0
css-loader: 0.28.10
node: 8.9.4
yarn: 1.5.1

Note: I tried this in a more complicated configuration using html-webpack-plugin, babel-loader, etc. Everything works normally on development, but it doesn't on production. Let me know if you would like me to provide that configuration as well!

Can't confirm this. Try NODE_ENV=production webpack --progress

On "production" mode I have this errors
This fixed only if I switch mode to "development"

editor_styles.css
Conflict: Multiple assets emit to the same filename editor_styles.css

ERROR in chunk style_litres [entry]
style_litres.css
Conflict: Multiple assets emit to the same filename style_litres.css

ERROR in chunk style [entry]
style.css
Conflict: Multiple assets emit to the same filename style.css```

@VictorKolb your entry seems to be wrong, should be:

entry: {
    "someName": path.resolve(__dirname, 'src/index.js')
},

But the main issue will be inside your css imports i guess.

@VictorKolb Please provide more info about your setup. Is the name hardcoded e.g 'name: 'styles.css' or the like ?

@michael-ciniawsky, @vertic4l Thanks for your answers!
if there were errors in the configuration, then in the "development" mode, I would also receive errors, but everything works correctly.

My configuration for the scss build looks something like this:

const litresCss = new MiniCssExtractPlugin({ filename: '[name].css' });
const coverEditorCss = new MiniCssExtractPlugin({ filename: '[name].css' });
const mainCss = new MiniCssExtractPlugin({ filename: '[name].css' });


const config  = {
  entry: {
    style_litres: `./styles_litres/main.scss`,
    style: `./styles/main.scss`,
    editor_styles: `./styles/editor_styles.scss`,
  },

  context: path.resolve(`${__dirname}/../../dev`),

  resolve: {
    modules: [path.resolve(`${__dirname}/../../dev`), 'node_modules'],
  },

  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, '../../assets/bundles'),
  },

  plugins: [
    litresCss,
    coverEditorCss,
    mainCss
  ],

  module: {
    rules: [
      {
        test: /\.scss$/,
        include: path.resolve(__dirname, `../../../dev/styles_litres/main.scss`),
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          {
            loader: 'postcss-loader',
            options: { config: { path: path.resolve(__dirname, '../postcss.config.js') } },
          }, 'sass-loader', 'import-glob-loader',
        ],
      },

      {
        test: /\.scss$/,
        include: path.resolve(__dirname, `../../../dev/styles/main.scss`),
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          {
            loader: 'postcss-loader',
            options: { config: { path: path.resolve(__dirname, '../postcss.config.js') } },
          }, 'sass-loader', 'import-glob-loader',
        ],
      },


      {
        test: /\.scss$/,
        include: path.resolve(__dirname, `../../../dev/editor_styles.scss`),
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          {
            loader: 'postcss-loader',
            options: { config: { path: path.resolve(__dirname, '../postcss.config.js') } },
          }, 'sass-loader', 'import-glob-loader',
        ],
      },
    ],
  },
}

I just switched from ExtractTextPlugin, because webpack 4 didn't work with it

@VictorKolb Your configuration is soooo wrong...

@vertic4l maybe because I try copy my ExtractTextPlugin config and just replace it with MiniCssExtractPlugin?

@VictorKolb Even if you copied it, you didnt understand how this all works out.

const config  = {
  entry: {
    'style_litres': './styles_litres/main.scss',
    'style': './styles/main.scss',
    'editor_styles': './styles/editor_styles.scss',
  },

  context: path.resolve(__dirname, '../../dev'),

  resolve: {
    modules: [path.resolve(__dirname, '../../dev'), 'node_modules'],
  },

  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, '../../assets/bundles'),
  },

  plugins: [
    new MiniCssExtractPlugin({
            // Options similar to the same options in webpackOptions.output
            // both options are optional
            // TODO: switch to [contenthash] as soon as MiniCssExtractPlugin supports it
            filename: "[name].[chunkhash].css"
        }),
  ],

  module: {
    rules: [
      {
        // that's your main setup for compiling scss
        test: /\.scss$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {
                config: {
                    path: path.resolve(__dirname, '../postcss.config.js')
                }
            },
          },
          'sass-loader',
          'import-glob-loader'
        ],
      }
    ],
  },
}

you should have ONE rule for scss. If you really need 3 separate css files in the end than using 3 entry points seems to be ok.

But it seems like you want to include main.scss in 2 others... so you would need 2 entry points,
and import main.scss inside the other 2 scss files.

  1. .css can't be used as an entrypoint (this will generate an extra .js file)
  2. Use only one plugin instance and one module.rules[i].scss (without include)
  3. Use Code Splitting to get logical chunks (import()) instead of mutliple module.rules[i].scss

entry.js

import('./file1.scss')
import('./file2.scss')
import('./file3.scss')
  1. For (S)CSS usage only, consider using gulp or the like instead (easier) :)

@vertic4l, thanks you! I just figured out how this should work! As I thought it is differences between ExtractTextPlugin and MiniCssExtractPlugin. With ExtractTextPlugin i must describe rule 3 time, otherwise it did't work correctly. Yes, it is very weird.

@michael-ciniawsky, I don't want importing my scss file inside js. And it is just part of config, I use webpack for js compiling too.

Thank you, guys!

@vertic4l, @VictorKolb I would not say that the configuration is completely wrong. Its obviously was the modification form extract-text plugin. And in extract-text - this was a correct way to specify several output css files based on different config(loaders or includes).

@vertic4l can you elaborate how the same example(both less and sass in same project) can be done with mini-css-extract-plugin?

For me that seems like really separate rules.

After trying a bunch of things. I went with the simplest configuration I could go with (the one on the README.md), and it worked all fine on development but not on production. This time I set the logs as verbose: stats: 'verbose', and found this piece of information:

    Entrypoint mini-css-extract-plugin = *
    chunk    {0} * (mini-css-extract-plugin) 43.3 KiB [entry] [rendered]
        > !!/home/jose/projects/js-project/node_modules/css-loader/index.js!/home/jose/projects/js-project/src/styles/styles.css mini-css-extract-plugin
        [0] ./node_modules/css-loader/lib/css-base.js 2.21 KiB {0} [depth 1] [built]
            ModuleConcatenation bailout: Module is not an ECMAScript module
            cjs require ../../node_modules/css-loader/lib/css-base.js [1] ./node_modules/css-loader!./src/styles/styles.css 1:27-83
        [1] ./node_modules/css-loader!./src/styles/styles.css 41.1 KiB {0} [depth 0] [built]
            ModuleConcatenation bailout: Module is not an ECMAScript module
            single entry !!/home/jose/projects/js-project/node_modules/css-loader/index.js!/home/jose/projects/js-project/src/styles/styles.css  mini-css-extract-plugin

I fixed it by changing my imports from ES6 modules to CommonJS.

src/index.js
require('./styles.css');

Thanks @developer-lindner for your suggestion of using --progress, it pointed me on the right direction.

when I use
@babel/plugin-transform-modules-commonjs,
Seems to have solved it.

seems like there is no definitive guide for upgrading babel from 6 to 7..

I think the possible problem is that Webpack will do the tree shaking for production mode. So can declare sideEffects as true for your css rule. Pls refer to: #275 (comment)

I had the same problem with css/scss in production mode.
Problem with default styles.
I replaced import with require in main.ts and everything fine.
import './assets/css/styles.scss'; to => require('./assets/css/styles.scss');