Search code examples
javascriptvue.jswebpackwebpack-4webpack-style-loader

why webpack4 production bundle will always include style-loader, css-loader and vue-loader content?


The exported multiple entry compiled js files in my multi entry point final bundle built with production mode in webpack always include loaders content. How to eliminate them and why they are included?

To reproduce

git clone https://github.com/adamchenwei/boilerplate-webpack-babel-sass-storybook-vuejs.git
git checkout step/3-prod-webpack-build-setup-basic
npm install
npm run build:prod

enter image description here

Any idea will be appreciated. https://webpack.js.org/plugins/module-concatenation-plugin/ did not help either. I read couple SO also seems no solution for it yet.

Thanks

webpack.common.js

const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

function resolve (dir) {
  return path.join(__dirname, '..', dir)
}
module.exports = {
  entry: {
    app: './src/library.js',
    HelloComp: './src/components/HelloComponent/HelloComponent.vue',
    Bye: './src/components/ByeComponent/ByeComponent.vue'
  },
  plugins: [
    new CleanWebpackPlugin(['dist']),
    new HtmlWebpackPlugin({
      title: 'Production'
    })
  ],
  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, 'dist')
  },
  externals: {
    'vue': {
      root: 'vue',
      commonjs2: 'vue',
      commonjs: 'vue',
      amd: 'vue',
      umd: 'vue'
    },
    'vue-router': {
      root: 'vue-router',
      commonjs2: 'vue-router',
      commonjs: 'vue-router',
      amd: 'vue-router',
      umd: 'vue-router'
    },
    'style-loader': {
      root: 'style-loader',
      commonjs2: 'style-loader',
      commonjs: 'style-loader',
      amd: 'style-loader',
      umd: 'style-loader'
    },
    'vue-hot-reload-api': {
      root: 'vue-hot-reload-api',
      commonjs2: 'vue-hot-reload-api',
      commonjs: 'vue-hot-reload-api',
      amd: 'vue-hot-reload-api',
      umd: 'vue-hot-reload-api'
    },
    'vue-loader': {
      root: 'vue-loader',
      commonjs2: 'vue-loader',
      commonjs: 'vue-loader',
      amd: 'vue-loader',
      umd: 'vue-loader'
    }
  }
}

webpack.prod.js

const merge = require('webpack-merge');
const common = require('./webpack.common.js');
const webpack = require('webpack')
const { VueLoaderPlugin } = require('vue-loader')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
// const path = require('path')
// function resolve (dir) {
//   return path.join(__dirname, '..', dir)
// }

const configedAnalyzer = new BundleAnalyzerPlugin({
  // Can be `server`, `static` or `disabled`.
  // In `server` mode analyzer will start HTTP server to show bundle report.
  // In `static` mode single HTML file with bundle report will be generated.
  // In `disabled` mode you can use this plugin to just generate Webpack Stats JSON file by setting `generateStatsFile` to `true`.
  analyzerMode: 'static',
  // Host that will be used in `server` mode to start HTTP server.
  analyzerHost: '127.0.0.1',
  // Port that will be used in `server` mode to start HTTP server.
  analyzerPort: 8887,
  // Path to bundle report file that will be generated in `static` mode.
  // Relative to bundles output directory.
  reportFilename: './../report/bundle_anlaysis.html',
  // Module sizes to show in report by default.
  // Should be one of `stat`, `parsed` or `gzip`.
  // See "Definitions" section for more information.
  defaultSizes: 'gzip',
  // Automatically open report in default browser
  openAnalyzer: true,
  // If `true`, Webpack Stats JSON file will be generated in bundles output directory
  generateStatsFile: true,
  // Name of Webpack Stats JSON file that will be generated if `generateStatsFile` is `true`.
  // Relative to bundles output directory.
  statsFilename: 'stats.json',
  // Options for `stats.toJson()` method.
  // For example you can exclude sources of your modules
  // from stats file with `source: false` option.
  // See more options here: https://github.com/webpack/webpack/blob/webpack-1/lib/Stats.js#L21
  statsOptions: null,
  // Log level. Can be 'info', 'warn', 'error' or 'silent'.
  logLevel: 'info'
})

module.exports = merge(common, {
  mode: 'production',
  module: {
    rules: [
      {
        test: /\.vue$/,
        use: 'vue-loader'
      },
      // IMPORTANT: All js load should come AFTER vue-loader!!!
      {
        test: /\.(js|vue)$/,
        use: 'eslint-loader',
        enforce: 'pre' // kick in before other loader... Q: also before vue-loader I suppose? maybe better move it to top?
      },
      {
        test: /\.css$/,
        use: [
          'vue-style-loader',
          'css-loader'
        ]
      },
      {
        test: /\.scss$/,
        use: [
          'style-loader', // creates style nodes from JS strings
          'css-loader', // translates CSS into CommonJS
          'sass-loader' // compiles Sass to CSS, using Node Sass by default
        ]
      },
      {
        test: /\.js$/,
        use: 'babel-loader'
      }
    ]
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new VueLoaderPlugin(),
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: 'index.html',
      inject: true
    }),
    new CopyWebpackPlugin([{
      // NOTE: it does not really do anything, unless we have a asset folder, that needed no compression
      from: './static/',
      to: './static/',
      toType: 'dir'
    }]),

    // NOTE: honestly, this did not help reduce prod bundle size... but for wtw:
    // https://webpack.js.org/plugins/module-concatenation-plugin/
    new webpack.optimize.ModuleConcatenationPlugin(),

    // NOTE: disable when needed, its just to analyze code
    configedAnalyzer
  ],
  stats: {
    // Examine all modules
    maxModules: Infinity,
    // Display bailout reasons
    optimizationBailout: true
  }
});

Solution

  • Remove style-loader from your externals and make sure to generate actual css files from your css... otherwise webpack has to insert your styles somehow, right?

    To do that use mini-css-extract-plugin.

     {
            test: /\.css$/,
            use: [
              MiniCssExtractPlugin.loader,
              'css-loader'
            ]
          },
          {
            test: /\.scss$/,
            use: [
              MiniCssExtractPlugin.loader,
              'css-loader', // translates CSS into CommonJS
              'sass-loader' // compiles Sass to CSS, using Node Sass by default
            ]
        }
    

    don't forget to add new MiniCssExtractPlugin() to your plugins too. Preferable only for production build.