Environmental analysis

The development environment

  • In a development environment, We need a powerful Source Map (easy for developers to debug code) and a localhost Server (local server) with live reloading, hot Module replacement capabilities.

Roughly as follows:

  1. Webpack-dev-server real-time reload, hot replace
  2. Uncompressed code
  3. CSS styles are not extracted into separate files
  4. Map source code to raw files using sourceMap configuration (easy to debug)
  5. Don’t compress HTML

The production environment

  • In the production environment, we shifted our focus to smaller bundles, lighter source maps, and more optimized resources to improve load times.

Roughly as follows:

  1. No need for real-time reloading, hot replacement
  2. Compressing JS and CSS
  3. CSS styles are extracted into separate files
  4. sourceMap.
  5. Optimization of code
  6. Compressed HTML
  7. Resource cache (NamedChunksPlugin, HashedModuleIdsPlugin)
  8. Clear the dist directory files

Resolving common code

In both environments, common configurations need to be merged, so the webpack-Merge merge tool is used to solve the problem of code duplication.

Install webpack – merge

npm i webpack-merge -D
Copy the code

Latest directory, files

Lesson # - 05 | - build | - webpack. Base. Conf., js / / + general configuration | - webpack. Dev. Conf., js / / + development environment configuration | - webpack. Prod. Conf. Js / / + Production | - node - modules | - public | - package. Json | - package - lock. Json | - SRC | - print. Js / / + is used to test the caching | - the favicon. Ico / / + Web page iconCopy the code

Install production environment packages

npm i cross-env copy-webpack-plugin mini-css-extract-plugin optimize-css-assets-webpack-plugin uglifyjs-webpack-plugin -D
Copy the code
  • Cross-env: Configure environment variables on the command line (see package.json)
  • Copy-webpack-plugin: copies resources
  • Mini-css-extract-plugin: Extract to CSS file separately
  • Optimize – CSS -assets-webpack-plugin: compress CSS files
  • Uglifyjs-webpack-plugin: Compress JS files

General configuration

webpack.base.conf.js

const path = require('path')
const webpack = require('webpack')
const { VueLoaderPlugin } = require('vue-loader')

const resolve = (dir) = >  path.resolve(__dirname, dir)
const jsonToStr = (json) = > JSON.stringify(json)
const isProd = process.env.NODE_ENV === 'production'
module.exports = {
  // Entry configuration
  entry: {
    app: ['@babel/polyfill', resolve('.. /src/main.js')]},// Package the output configuration
  output: {
    path: resolve('.. /dist'),
    filename: 'bundle.js'     // Filename is generated relative to path
  },

  // Introduce resource ellipsis suffixes and resource alias configurations
  resolve: {
    extensions: ['.js'.'.json'.'.vue'].alias: {
      The '@': resolve('.. /src')}},// Define module rules
  module: {
    rules: [{test: /\.jsx? $/.loader: 'babel-loader'.// Specify a directory to load the babel-loader to increase the speed of running and packaging
        include: [resolve('.. /src'), resolve('.. /node_modules/webpack-dev-server/client')].// Remove the directory, improve the speed of operation, packaging
        exclude: file= > (
          /node_modules/.test(file) &&
          !/\.vue\.js/.test(file)
        )
      },
      {
        test: /\.(png|svg|jpg|gif)$/.loader: 'file-loader'.options: {
          // Specify the generated directory
          name: 'static/images/[name].[hash:7].[ext]',}}, {test: /\.vue$/.loader: 'vue-loader'}},// Plug-in options
  plugins: [
    // Define environment variables
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': isProd ? jsonToStr('production') : jsonToStr('development')}),new VueLoaderPlugin()
  ]
} 
Copy the code

Development Environment Configuration

webpack.dev.conf.js

const path = require('path')
const webpack = require('webpack')
const merge = require('webpack-merge')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const baseWebpack = require('./webpack.base.conf')

const resolve = (dir) = >  path.resolve(__dirname, dir)
module.exports = merge(baseWebpack, {
  mode: 'development'.devtool: 'cheap-source-map'.// Enable the cheap-source-map mode debugging
  
  // Start the Web server and hot update
  devServer: {
    open: true.hot: true.port: 3002.publicPath: '/'.contentBase: resolve(".. /dist")   // Set the dist directory to the contents of the server preview
  },
  
  // Define module rules
  module: {
    rules: [{test: /\.(css|scss|sass)$/.use: [{loader: 'style-loader'
          },
          {
            loader: 'css-loader'.options: {
              importLoaders: 1}}, {loader: 'sass-loader'.options: {
              implementation: require('dart-sass')}}, {loader: 'postcss-loader'}]}]},// Plug-in options
  plugins: [
    // HTML template and related configuration
    new HtmlWebpackPlugin({
      title: 'Lesson-06'.template: resolve('.. /public/index.html')}),// Hotreplace plugin
    new webpack.HotModuleReplacementPlugin(),
    // The update file name is returned directly during hot loading, not the file ID.
    new webpack.NamedModulesPlugin()
  ]
})
Copy the code

Production Environment Configuration

webpack.prod.conf.js

const path = require('path')
const merge = require('webpack-merge')
const webpack = require('webpack')
const webpackConfig = require('./webpack.base.conf')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CleanWebpackPlugin = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')

const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')

const resolve = (dir) = >  path.resolve(__dirname, dir)

module.exports = merge(webpackConfig, {
  mode: 'production'.devtool: false.// Run and package the output configuration
  output: {
    path: resolve('.. /dist'),
    filename: 'static/js/[name].[chunkhash:8].js'
  },

  // Compress js, CSS resources, and subcontract
  optimization: {
    splitChunks: {
      chunks: 'all'.cacheGroups: {
        libs: {
          name: 'chunk-libs'.// The name of the js file generated after packaging
          test: /[\\/]node_modules[\\/]/.priority: 10.chunks: 'initial' // Package only the third party that you originally relied on
        },
        // The elementUI option is not currently used (see configuration in elementUI)
        elementUI: {
          name: 'chunk-elementUI'.// Unpack elementUI separately
          priority: 21.// The rights are more important than liBS and APP, otherwise they will be packaged into LIBS or APP
          test: /[\\/]node_modules[\\/]element-ui[\\/]/
        },
        // The Commons option is not currently used (see elementUI configuration)
        commons: {
          name: 'chunk-commons'.test: resolve('.. /src/components'), // You can customize your rules
          minChunks: 3.// Minimum public count
          priority: 5.reuseExistingChunk: true}}},runtimeChunk: 'single'.minimizer: [ // Compress js and CSS configurations
      new UglifyJsPlugin({
        sourceMap: false.cache: true.parallel: true
      }),
      new OptimizeCSSAssetsPlugin()
    ]
  },

  // Define module rules
  module: {
    rules: [{test: /\.(scss|sass)$/.use: [{loader: MiniCssExtractPlugin.loader
          },
          {
            loader: 'css-loader'.options: {
              importLoaders: 2.sourceMap: false}}, {loader: 'sass-loader'.options: {
              implementation: require('dart-sass'),
              sourceMap: false}}, {loader: 'postcss-loader'.options: {
              sourceMap: false}}]},]},// Plug-in options
  plugins: [
    // Clear the last build file based on the output export directory
    new CleanWebpackPlugin(),
    // Create an HTML entry without manually importing JS and CSS resources
    new HtmlWebpackPlugin({
      template: resolve('.. /public/index.html'),
      title: 'Lesson-06'.favicon: resolve('.. /favicon.ico'),
      HTML / / compression
      minify: {
        removeComments: true.collapseWhitespace: true.removeAttributeQuotes: true
        // more options:
        // https://github.com/kangax/html-minifier#options-quick-reference}}),// Extract to a separate CSS file
    new MiniCssExtractPlugin({
      filename: 'static/css/[name].[contenthash:8].css'.chunkFilename: 'static/css/[name].[contenthash:8].css'
    }),

    // Copy resources
    new CopyWebpackPlugin([
      {
        from: path.resolve(__dirname, '.. /public'),
        to: path.resolve(__dirname, '.. /dist')}]),// Keep chunk.id stable when chunk has no name (cache chunk)
    new webpack.NamedChunksPlugin(chunk= > {
      if (chunk.name) {
        return chunk.name
      }
      const modules = Array.from(chunk.modulesIterable)
      if (modules.length > 1) {
        const hash = require('hash-sum')
        const joinedHash = hash(modules.map(m= > m.id).join('_'))
        let len = 4
        const seen = new Set(a)while (seen.has(joinedHash.substr(0, len))) len++
        seen.add(joinedHash.substr(0, len))
        return `chunk-${joinedHash.substr(0, len)}`
      } else {
        return modules[0].id
      }
    }),

    // Keep module.id stable when the vender module does not change (cache vender)
    new webpack.HashedModuleIdsPlugin()
  ]
})
Copy the code

Dynamic CDN resource configuration

In the process of referring to the configuration of others, I found a way to customize the CDN configuration in Webpack, mainly by using the ability of htML-webpack-plugin to add custom attributes and link CDN resources into the custom attributes. CDN resource imports are automatically generated by traversing attributes in the index. HTML template.

As follows:

Webpack. Dev. Conf. Js, webpack. Prod. Conf. Js

. omit// Plug-in options
  plugins: [
    // HTML template and related configuration
    new HtmlWebpackPlugin({
      title: 'Lesson-06'.template: resolve('.. /public/index.html'),
      // CDN (custom attributes) loaded resources, do not need to manually add to index.html,
      // The order is loaded by array index
      cdn: {
        css: ['https://cdn.bootcss.com/element-ui/2.8.2/theme-chalk/index.css'].js: [
          'https://cdn.bootcss.com/vue/2.6.10/vue.min.js'.'https://cdn.bootcss.com/element-ui/2.8.2/index.js']}})]... omitCopy the code

public/index.html


      
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title><% = htmlWebpackPlugin.options.title% ></title>
	<! -- import cdn css -->
	<% if(htmlWebpackPlugin.options.cdn) {% >
		<% for(var css of htmlWebpackPlugin.options.cdn.css) { %>
			<link rel="stylesheet" href="<%=css%>">
		<%} % >
	<%} % >
</head>
<body>
	<div id="box"></div>
	<! -- import cdn js -->
	<% if(htmlWebpackPlugin.options.cdn) {% >
		<% for(var js of htmlWebpackPlugin.options.cdn.js) { %>
			<script src="<%=js%>"></script>
		<%} % >
	<%} % >
</body>
</html>
Copy the code

Configure the development and production environment commands

Add dev and build commands to the scripts option of package.json.

package.json

{
  "name": "lesson-06"."version": "1.0.0"."description": ""."main": "main.js"."scripts": {
    "dev": "npx webpack-dev-server --config ./build/webpack.dev.conf.js"."build": "cross-env NODE_ENV=production npx webpack --config ./build/webpack.prod.conf.js"
  },
  "keywords": []."author": ""."license": "ISC"."devDependencies": {
    "@babel/core": "^ 7.4.4." "."@babel/polyfill": "^ 7.4.4." "."@babel/preset-env": "^ 7.4.4." "."autoprefixer": "^ 9.5.1"."babel-loader": "^ 8.0.5"."clean-webpack-plugin": "^ 2.0.1." "."copy-webpack-plugin": "^ 5.0.3." "."cross-env": "^ 5.2.0." "."css-loader": "^ 2.1.1"."dart-sass": "^ 1.19.0"."file-loader": "^ 3.0.1." "."html-webpack-plugin": "^ 3.2.0"."mini-css-extract-plugin": "^ 0.6.0"."optimize-css-assets-webpack-plugin": "^ 5.0.1." "."postcss-loader": "^ 3.0.0"."sass-loader": "^ 7.1.0"."style-loader": "^ 0.23.1"."uglifyjs-webpack-plugin": "^ 2.1.2"."vue-loader": "^ 15.7.0"."vue-template-compiler": "^ 2.6.10"."webpack": "^ 4.30.0"."webpack-cli": "^ 3.3.0"."webpack-dev-server": "^ 3.3.1"."webpack-merge": "^ 2"
  },
  "dependencies": {
    "vue": "^ 2.6.10"}}Copy the code

complete

After the configuration is complete, try running:

  • The development environment
npm run dev
Copy the code
  • The production environment
npm run build
Copy the code

If there are no problems, the local server is started, the production environment directory is generated, and the files (dist in the root directory) are generated. Otherwise, you can go to Github for clone project to view the source code, with comments.

The project address

Source address click on this GitHub