1. Introduction

Thanks to the Parcel packaging tool, WebPack4 is also pursuing zero-configuration build projects. Vue-cli 3.0, which appeared a while ago, is also based on the idea of webpack4 zero configuration. For some used to Webpack3 developers inevitably some not used to. This article will take you around vuE-CLI, with Webpack4 step by step build vUE project.

Note: This article describes the basic configuration of Webpack4. It is a bit long, please read it patiently. Or just look at itProgram source codeOr,ctrl + w)

2. Project construction

  1. Create the createVue folder, go to that folder, and NPM init initializes the project

  2. Install the WebPack

npm i webpack webpack-cli webpack-dev-server webpack-merge --save-dev

// I am currently using the version
"webpack": "^ 4.16.3"."webpack-cli": "^ 3.1.0"."webpack-dev-server": "^ 3.1.5." ".// Development server
"webpack-merge": "^ 4.1.4." " // WebPack configuration merge
Copy the code
  1. Create corresponding files
createVue
  |--dist
  |--build
      |--webpack.prod.js
      |--webpack.dev.js
      |--webpack.base.js
  |--src
      |--index.js
      |--app.vue
  |--index.html
Copy the code
// webpack.base.js
// Store dev and prod general configuration
const webpack = require('webpack');
const path = require("path");
module.exports = {
  entry: './src/index.js'./ / the entry
  module: {
    rules: []},plugins: [
    // Resolve that the hash behind vender changes every time
    new webpack.HashedModuleIdsPlugin(),
  ],/ / the plugin
};
Copy the code
// webpack.dev.js
// Save the dev configuration
const merge = require('webpack-merge');
const common = require('./webpack.base.js');
const path = require('path');

module.exports = merge(common, {
  devtool: 'inline-source-map'.devServer: { // Development server
    contentBase: '.. /dist'
  },
  output: { / / output
    filename: 'js/[name].[hash].js'.// The hash changes every time you save it
    path: path.resolve(__dirname, '.. /dist')},module: {},
  mode: 'development'});Copy the code
// webpack.prod.js
// Store the proD configuration
const path = require('path');
// Merge configuration files
const merge = require('webpack-merge');
const common = require('./webpack.base.js');

module.exports = merge(common, {
  module: {},
  plugins: [].mode: 'production'.output: {
    filename: 'js/[name].[contenthash].js'.// Contenthash If the file content does not change, the contenthash name does not change
    path: path.resolve(__dirname, '.. /dist')}});Copy the code

Webpack4 adds the mode property, which is set to Development/Production. This is the default configuration

Development: process.env.node_env set to development the following plug-ins are enabled by default to make full use of persistent caching. NamedChunksPlugin: Solidify chunk ID by name NamedModulesPlugin: Solidify Module ID production by name: Setting the value of process.env.node_env to production enables the following plug-ins by default, Including SideEffectsFlagPlugin and UglifyJsPlugin for tree - shaking FlagDependencyUsagePlugin: compile time depends on tag FlagIncludedChunksPlugin: Markup chunks, prevent child chunks loaded ModuleConcatenationPlugin: NoEmitOnErrorsPlugin: Scope hosting (scope hosting) : Scope hosting (scope hosting) : Scope hosting (scope hosting) During the output phase, a compilation error is encountered skipping OccurrenceOrderPlugin: give the shorter value SideEffectsFlagPlugin to the frequently used IDS: Recognize the sideEffects flag of package.json or module.rules (pure ES2015 modules) and safely remove unused onesexportExport UglifyJsPlugin: Remove unreferenced code and compress itCopy the code
// index.js
NPM I vue --save
import Vue from 'vue';
import App from './App.vue'
import './index.scss'
new Vue({
  el: '#app'.render: h= > h(App),
});
Copy the code
<! -- app.vue -->
<template>
  <div id="app">
    hello world
  </div>
</template>

<script>
export default {
  name: 'app'
}
</script>

<style scoped>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
  transform: rotate(0deg);
}
</style>

Copy the code
<! -- index.html -->

      
<html>
  <head>
    <meta charset="UTF-8">
    <title>Suporka Vue App</title>
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>
Copy the code
  1. Install the VUE core parsing plug-in

npm i vue-loader vue-template-compiler --save-dev

// I am currently using the version
"vue-loader": "^ 15.2.6"."vue-template-compiler": "^ 2.5.17".Copy the code

Because the parsing of vue is used in both DEV and PROd, it falls under base configuration

// webpack.base.js

/ /... ellipsis
/ / the vue - loader plug-in
const VueLoaderPlugin = require('vue-loader/lib/plugin');
module.exports = {
  / /... ellipsis
  module: {
    rules: [{test: /\.vue$/.loader: 'vue-loader'}},plugins: [
    // Be sure to introduce this plugin to cast magic
    new VueLoaderPlugin(),
  ]
};
Copy the code
  1. Install the HTML template parsing plug-in

npm i html-webpack-plugin --save-dev

// Current version
"html-webpack-plugin": "^ 3.2.0"
Copy the code

HTML parsing is also a basic configuration, under Base

// webpack.base.js

/ /... ellipsis
/ / HTML plugin
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  / /... ellipsis
  plugins: [
    / /... ellipsis
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, '.. /index.html'),})]};Copy the code
  1. Create the NPM command
"scripts": {
  "start": "webpack-dev-server --hot --open --config build/webpack.dev.js",
  "build": "webpack --config build/webpack.prod.js"
},
Copy the code

— Hot Module hot replacement

–open Enables the local server

At this point NPM start, the project can run normally

3. Function expansion

  1. Add the loader
  • CSS Loader (including pre and post processing)

CSS based loader

"css-loader": "^ 1.0.0"."style-loader": "^ 0.21.0".Copy the code

The CSS processes less

"less": "^ 3.8.0." "."less-loader": "^ 4.1.0." ".Copy the code

The CSS has two sets of sass

"node-sass": "^ 4.9.2." "."sass-loader": "^ 7.1.0".Copy the code

CSS postprocessing PostCSS consists of two modules

"postcss-loader": "^ 2.1.6"."autoprefixer": "^ 9.1.0".Copy the code

Create the postcss.config.js file in the root folder

// postcss.config.js
// Automatically add CSS compatibility properties
module.exports = {
  plugins: [
    require('autoprefixer')]}Copy the code

To install the above dependencies, add the following loader code to the base file

// webpack.base.js

/ /... ellipsis
rules: [
  {
    test: /\.(sa|sc|c)ss$/.use: [
      'style-loader'.'css-loader'.'postcss-loader'.'sass-loader',]}, {test: /\.less$/.use: [
      'style-loader'.'css-loader'.'postcss-loader'.'less-loader',]}]Copy the code
  • Image loader

Install NPM I file-loader –save-dev

Add the base file to the configuration

// webpack.base.js

/ /... ellipsis
rules: [
  / /... ellipsis
  {
    test: /\.(png|svg|jpg|gif)$/.use: [{loader: 'file-loader'.options: {
          limit: 5000.// Separate images to imGS folder
          name: "imgs/[name].[ext]",}},]},]Copy the code

4. Package optimization

  1. Dist folder files are not cleared each time you repack
  • Install the clean-Webpack-plugin
// webpack.prod.js

// Clear files before packing
const CleanWebpackPlugin = require('clean-webpack-plugin');
/ /... ellipsis
plugins: [
  new CleanWebpackPlugin(['dist/*'] and {root: path.resolve(__dirname, '.. / ')}),]Copy the code
  1. The separation of CSS

Webpackage 4 uses the mini-CSs-extract-plugin to separate CSS.

  • After installing the mini-CSS-extract-plugin plugin
// webpack.prod.js

// Separate CSS plugins
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
/ /... ellipsis
plugins: [
  new MiniCssExtractPlugin({
    filename: "css/[name].[hash].css".chunkFilename: 'css/[id].[hash].css'}),]Copy the code

In addition, replace style-loader in each CSS loader with MiniCssExtractPlugin

Image compression using image-webpack-loader, after installation code is as follows:

// webpack.prod.js
/ /... ellipsis
rules: [
  {
    test: /\.(sa|sc|c)ss$/.use: [{loader: MiniCssExtractPlugin.loader,
        options: {
          // you can specify a publicPath here
          // by default it use publicPath in webpackOptions.output
          publicPath: '.. / '}},'css-loader'.'postcss-loader'.'sass-loader',]}, {test: /\.less$/.use: [{loader: MiniCssExtractPlugin.loader,
        options: {
          // you can specify a publicPath here
          // by default it use publicPath in webpackOptions.output
          publicPath: '.. / '}},'css-loader'.'postcss-loader'.'less-loader',]}, {test: /\.(png|svg|jpg|gif)$/.use: [{loader: 'file-loader'.options: {
          limit: 5000.name: "imgs/[hash].[ext]",}},// Image compression
      {
        loader: 'image-webpack-loader'.options: {
          // bypassOnDebug: true,
          mozjpeg: {
            progressive: true.quality: 65
          },
          optipng: {
            enabled: false,},pngquant: {
            quality: '65-90'.speed: 4
          },
          gifsicle: {
            interlaced: false,}},},]},]Copy the code
  1. Use Happypack multiple processes to speed up compilation

You also need to install the Babel two-piece set

"babel-core": "^ 6.26.3"."babel-loader": "^ 7.1.5." "."happypack": "^ 5.0.0".Copy the code

Happypack development production environment is used, configuration into base

// webpack.base.js
/ / use happypack
const HappyPack = require('happypack');
const os = require('os');
const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });
/ /... ellipsis
rules: [
  {
    test: /\.js$/.// pass the.js file processing to the HappyPack instance with id happyBabel
    loader: 'happypack/loader? id=happyBabel'.// Exclude files in node_modules
    exclude: /node_modules/
  },
]
plugins: [
/ /...
new HappyPack({
      // Use id to identify the happypack processing class file
      id: "happyBabel".// How to handle the same usage as the loader configuration
      loaders: [
        {
          loader: "babel-loader? cacheDirectory=true"}].// Share the process pool
      threadPool: happyThreadPool,
      // Allow HappyPack to output logs
      verbose: true}),]Copy the code
  1. Separate infrequently changing files, such as libraries referenced under node_modules
// webpack.prod.js
module.exports = merge(common, {
  / /... ellipsis
  optimization: {
    / / separate chunks
    splitChunks: {
      chunks: 'all'.cacheGroups: {
        vendor: {
          name: "vendor".test: /[\\/]node_modules[\\/]/.priority: 10.chunks: "initial" // Package only the third party that you originally relied on},}},},})Copy the code

If configured this way, there will be an extra vendor.js in the packaged JS folder

  1. Compress CSS and JS code

Install the optimize- CSS -assets-webpack-plugin and uglifyjs-webpack-plugin plugins

// webpack.prod.js
// Compress CSS and JS code
/ /... ellipsis
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
module.exports = merge(common, {
  / /... ellipsis
  optimization: {
    / /... ellipsis
    minimizer: [
      JS / / compression
      new UglifyJsPlugin({
        uglifyOptions: {
          compress: {
            warnings: false.// Remove the warning
            drop_debugger: true./ / remove the debugger
            drop_console: true / / remove the console log}},cache: true.// Enable caching
        parallel: true.// Parallel compression
        sourceMap: false // set to true if you want JS source maps
      }),
      / / compress CSS
      new OptimizeCSSAssetsPlugin({})
    ]
  },
})
Copy the code

Finally, extend the distinction between hash, chunkhash, and contenthash

  • Hash is related to the construction of the entire project. Whenever a file changes in the project, the hash value of the entire project will change and all files will share the same hash value

  • Chunkhash is different from hash. It parses dependent files based on different Entry files, constructs corresponding chunks, and generates corresponding hash values.

  • Contenthash changes the content in more detail, generating the corresponding hash value. Resolve a problem where the file name introduced in the chunkhash file changes due to chunkhash changes

Program source code