The author | Wang Chengwei

Given the extremely slow compilation of the book project (there are too many modules in the project, which is normal for slow compilation) and the recent lack of demand (a rare hiatus). So I thought I’d do a wave of Webpack updates and see if that would help. Webpack was officially released as v4.0.0 on February 25, 2018, codenamed Legato. Name is not very big, unknown sense li appearance. So let’s cut to the chase and get to the point. (The upgrade configuration in this article is mainly for the VUE project)

Webpack4 update changes

Say the first webpack4 there are a few of the more important update: webpack4 update log (https://github.com/webpack/webpack/releases/tag/v4.0.0)

1. Environment support: Node 4 and Node 6 are no longer officially supported. Supports 93% of ES6 syntax. Because Webpackage 4 uses a lot of the new JS syntax, it has been optimized in the new version of V8.

2.0 Configuration: Inspired by Parcel packaging tools, make it as cheap as possible for developers to run projects. Webpack4 no longer enforces the need for webpack.config.js as a packaged entry configuration file, its default entry is ‘./ SRC /’ and its default exit is ‘./dist’, which is really a good thing for small projects.

3. Mode option: Tells Webpack to use the built-in optimizations for the corresponding mode. Development or production, for example.


     

    module.exports = {

     mode: 'production'

    };

Copy the code

Or pass it from the CLI argument: webpack –mode = production

options describe

development

The value of process.env.node_env is set to development. Enable NamedChunksPlugin and NamedModulesPlugin.
production The value of process.env.node_env is set to production. Enable FlagDependencyUsagePlugin FlagIncludedChunksPlugin, ModuleConcatenationPlugin NoEmitOnErrorsPlugin, OccurrenceOrderPlugin SideEffectsFlagPlugin and UglifyJsPlugin.

Note: if NODE_ENV is set, mode== is not automatically set

mode: development


     

    // webpack.dev.config.js

    module.exports = {

    + mode: 'development'

    - plugins: [

    -   new webpack.NamedModulesPlugin(),

    -   new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("development") }),

    -]

    }

Copy the code

mode: production


     

    // webpack.prod.config.js

    module.exports = {

    +  mode: 'production',

    -  plugins: [

    - new UglifyJsPlugin(/* ... * /),

    -    new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("production") }),

    -    new webpack.optimize.ModuleConcatenationPlugin(),

    -    new webpack.NoEmitOnErrorsPlugin()

    -]

    }

Copy the code

4. Plugin changes: Webpack4 deleted CommonsChunkPlugin plug-in, it USES the built-in API optimization. SplitChunks and optimization runtimeChunk, namely webpack will share the block of code generated for you by default.

5. Rule-loaders: This option is deprecated (rule-loaders is an alias of rule-use. You can use rule-.use.)

6.WebAssembly: Out of the box WebAssembly

Upgrade webPack4 Loader and modify the configuration of the plug-in

To upgrade WebPack 4, you need to update Webpack to V4.0.0 or higher, and then install Webpack – CLI. CNPM is recommended. Sometimes NPM cannot be downloaded.


     

    npm install --save-dev webpack-cli

Copy the code

Loaders and plug-ins related to the project also need to be updated, otherwise an error will be reported. Here are some loaders and plug-ins that require additional configuration.

1. Vue-loader (more details)

(https://vue-loader.vuejs.org/zh/migrating.html#%E5%80%BC%E5%BE%97%E6%B3%A8%E6%84%8F%E7%9A%84%E4%B8%8D%E5%85%BC%E5%AE%B9 %E5%8F%98%E6%9B%B4)

Vue Loader V15 now requires a webpack plugin to work correctly:


     

    // webpack.config.js

    const VueLoaderPlugin = require('vue-loader/lib/plugin')

    module.exports = {

     // ...

     plugins: [

       new VueLoaderPlugin()

     ]

    }

Copy the code

Now Vue Loader V15 uses a different strategy to derive the Loader used by language blocks.

<style lang=”less”> In V14 or lower, it will try to load this block using less-loader and implicitly chain CSS-Loader and VUE style-loader after it, all using inline Loader strings.

In V15, <style lang=”less”> is done loading it as a real *.less file. So, to handle it this way, you need to explicitly provide a rule in your main Webpack configuration:


     

    {

     module: {

       rules: [

    / /... Other rules

         {

           test: /\.less$/,

           use: [

             'vue-style-loader',

             'css-loader',

             'less-loader'

           ]

         }

       ]

     }

    }

Copy the code

The nice thing about this is that this rule also applies to normal *.less imports in JavaScript, and you can configure any options you want for these Loaders. In V14 or lower, if you want to customize the option for a derived Loader, you have to repeat it in the Vue Loader’s own loaders option. In V15 you don’t have to do that anymore. If you are using cli to build a project, when upgrading webpack4, do not forget to delete the style rules in the configuration, as follows:


     

    //webpack.dev.conf.js

    const devWebpackConfig = merge(baseWebpackConfig, {

       mode: 'development',

    -   module: {

    -     rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })

    -},

    // Other configuration...

    })

Copy the code

The webpack.prod.conf.js file is modified as above

Due to the derivation changes in V15, if you import a Vue single-file component within Nodemodules, its <script> portions will be excluded from translation. To ensure that JS translations apply to Nodemodules’ Vue single-file components, you need to whitelist them by using an exclusion function:


     

    {

     test: /\.js$/,

     loader: 'babel-loader',

     exclude: file => (

       /node_modules/.test(file) &&

    ! /\.vue\.js/.test(file)

     )

    }

Copy the code

Vue Loader V15 also deprecates a number of options that should be configured using the rules of the normal Webpack module:

  • loader

  • preLoaders

  • postLoaders

  • postcss

  • cssSourceMap

  • buble

  • extractCSS

  • template

The following options are deprecated and should be configured using the new compilerOptions option:

  • PreserveWhitespace (using compilerOptions. PreserveWhitespace)

  • CompilerModules (use compilerOptions.modules)

  • CompilerDirectives (using compilerOptions. Directives)

The following options have been renamed:

  • TransformToRequire (now renamed transformAssetUrls)

2.CommonsChunkPlugin

Mentioned earlier to webpack4 deleted CommonsChunkPlugin plug-in, you need to use the built-in API optimization. SplitChunks and optimization runtimeChunk alternative, specific alternative configuration is as follows:


     

    //webpack.prod.conf.js

    optimization: {

    // Other configurations

       runtimeChunk: {

         name: 'manifest'

       },

       splitChunks:{

         chunks: 'async',

         minSize: 30000,

         minChunks: 1,

         maxAsyncRequests: 5,

         maxInitialRequests: 3,

         name: false,

         cacheGroups: {

           vendor: {

             name: 'vendor',

             chunks: 'initial',

             priority: -10,

             reuseExistingChunk: false,

             test: /node_modules\/(.*)\.js/

           },

           styles: {

             name: 'styles',

             test: /\.(scss|css)$/,

             chunks: 'all',

             minChunks: 1,

             reuseExistingChunk: true,

             enforce: true

           }

         }

       }

     },

Copy the code

Since the CommonsChunkPlugin is deprecated, the chunksSortMode in the HtmlWebpackPlugin configuration is no longer needed.


     

    plugins: [

    / /...

       new HtmlWebpackPlugin({

         filename: process.env.NODE_ENV === 'testing'? 'index.html': config.build.index,

         template: 'index.html',

         inject: true,

    inlineSource:/(app\.(.+)? \.css|manifest\.(.+)? \.js)$/,

         minify: {

           removeComments: true,

           collapseWhitespace: true,

           removeAttributeQuotes: true

           // more options: https://github.com/kangax/html-minifier#options-quick-reference

         },

    -      chunksSortMode: 'dependency'

       }),

    ]

Copy the code

3. Mini – CSS – extract – the plugin (more details) (https://github.com/webpack-contrib/mini-css-extract-plugin) (webpack4 new plug-in)

The extract-text-webpack-plugin will move all the *.css references in entry chunks into a separate CSS file. Therefore, your styles will no longer be embedded in the JS bundle, but in a separate CSS file (i.e., styles.css). If your style file size is large, this will make preloading faster, because CSS bundles are loaded in parallel with JS bundles. However, the mini-css-extract-plugin is recommended for webpack4. The configuration is as follows:

                                
     

    //webpack.prod.conf.js

    const MiniCssExtractPlugin = require("mini-css-extract-plugin" )

    Plugins:

    // Other configurations

    new MiniCssExtractPlugin ({

    filename: utils.assetsPath( 'css/[name].[contenthash].css'),//"[name].css"

    chunkFilename: utils.assetsPath( 'css/[id].css'),//"[id].css"

    }),

    ]

Copy the code

     

    //webpack.base.conf.js

    const MiniCssExtractPlugin = require("mini-css-extract-plugin")

    const devMode = process.env.NODE_ENV === 'production'

    module: {

       rules: [

    / /...

         {

           test: /\.css$/,

           use: [

             devMode ?  MiniCssExtractPlugin.loader : 'vue-style-loader',

             {

               loader: 'css-loader',

               options: { importLoaders: 1 }

             },

             'postcss-loader'

           ]

         },

       ]

    }

Copy the code

Let’s compress CSS and JS


     

    //webpack.prod.conf.js

    const UglifyJsPlugin = require("uglifyjs-webpack-plugin")

    const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin")

    optimization: {

       minimizer: [

         new UglifyJsPlugin({

           cache: true,

           parallel: true,

           sourceMap: true // set to true if you want JS source maps

         }),

         new OptimizeCSSAssetsPlugin({})

    ].

    }

Copy the code

Here are some things I upgraded during the upgrade process:


     

    "DevDependencies" : {

    / /...

    "Webpack" : "^ 4.27.1",

    "Webpack - cli" : "^ 3.1.2",

    "Webpack dev - server" : "^ 3.1.10",

    "Vue - loader", "^ 15.4.2",

    "Vue - style - loader", "^ 4.1.2",

    "HTML - webpack - plugin" : "^ 3.2.0",

    "HTML - webpack - the inline - source - the plugin" : "0.0.10",

    "Babel - loader", "^ 7.1.3",

    "File - loader" : "^ 2.0.0",

    "Mini - CSS - extract - the plugin" : "^ 0.5.0",

    "Ts - loader", "^ 5.3.1",

    "Url - loader", "^ 1.1.2",

    "Vue - HTML - loader", "^ 1",

    }

Copy the code

NPM run dev can be used to check if there are any problems with plugins and loaders.

Third, the project is running

Look at the console and find:

Component template not recognized, what is the problem? After leafing through a large number of materials, we learned that:

When importing components, in addition to ES6 import, you can also use Webpack require. For example, in the vue file, there is a lot of code like the following:


     

    const KingKong = require('.. /BookHomeCommon/KingKong.vue');

    const BookList = require('.. /BookHomeCommon/BookList.vue');

    const HomeAlert = require('.. /BookHomeCommon/HomeAlert.vue');

    const DoubleElevenToast = require('.. /Activitys/DoudleEleven/DoubleElevenToast.vue');

    const BrandVideo = require('./BrandVideo.vue');

Copy the code

In the update documentation for VUe-Loader V13.0.0:

New

  • Now uses ES modules internally to take advantage of webpack 3 scope hoisting. This should result in smaller bundle sizes.

  • Now uses PostCSS@6.

Breaking Changes

  • The esModule option is now true by default, because this is necessary for ES-module-based scope hoisting to work. This means the export from a *.vue file is now an ES module by default, so async components via dynamic import like this will break:


     

    const Foo = () => import('./Foo.vue')

Copy the code

Note: the above can continue to work with Vue 2.4 + vue-router 2.7, which will automatically resolve ES modules’ default exports when dealing with async components. In earlier versions of Vue and vue-router you will have to do this:


     

    const Foo = () => import('./Foo.vue').then(m => m.default)

Copy the code

Alternatively, you can turn off the new behavior by explicitly using esModule: false in vue-loader options.


Similarly, old CommonJS-style requires will also need to be updated:


     

    // before

    const Foo = require('./Foo.vue')

    // after

    const Foo = require('./Foo.vue').default

Copy the code
  • PostCSS 6 might break old PostCSS plugins that haven’t been updated to work with it yet.

The official document is clear:

  • You can disable the ES module by setting esModule: false in options for vue-loader

  • Import components synchronously, normally using import instead of ES6 syntax files using require (e.g. Export default {… }), now need to add a default attribute to reference. Importing components asynchronously requires dynamic import syntax

  1. If there are components introduced via require, all of them will be required (XXX).default

  2. () => import(XXX)

The esModule configuration in options has been removed from vue-loader v14.0.0. The ES module could not be closed. So what? The project already has a lot of use for const Foo = require(‘./ foo.vue ‘). It takes too much time to modify one by one. In this case, custom Loader is a good solution. The code is as follows:


     

    //compatible-es-module.js

    module.exports = function(content) {

     return content.replace(new RegExp(/require\('\.[/\w\.]+[^(\.png|\.gif|\.jpg)]'\)(\.default)?/,'g'),function(res) {

       return  /(\.default)$/.test(res)  ? res :res + '.default';

     });

    };

    //

    module: {

       rules: [

         {

           test: /\.(vue)$/,

           loader: './compatible-es-module'

         }

       ]

    }

Copy the code

Four,

Webpack3 compile time (webpack3)

This is webpack4:

The compilation speed of 510,000 ms and 210,000 ms increased by more than 50%. (The situation varies with different projects, please refer to the actual situation)

Webpack4 has a lot of new features to learn.

People are always afraid of the unknown. Face your fear, learn to understand it, and you will improve. (Manual yeah)


Last week, FE students performed a sketch called “Coming home for the Spring Festival” at the annual meeting. Please vote for us, thank you very much

The 16th program “Home for Chinese New Year” – sketch