Build your own web pack development environment from 0

Keywords: Javascript Webpack npm JQuery

Last article: Front-end automated testing

Another serial is coming! This time, we will introduce how to build a web pack development environment from 0, understand its internal mechanism and principle, so that we can master and use web pack more accurately. Let's begin with:

1. What is Webpack?

Web pack is a static module bundler for modern JavaScript applications. When web pack processes applications, it recursively builds a dependency graph that contains each module the application needs, and then packages all these modules into one or more bundles.

Use Webpack as a front-end build tool:

  • Code conversion: TypeScript compiled into JavaScript, SCSS compiled into CSS, etc.
  • File optimization: compress JavaScript, CSS, HTML code, compress and merge pictures, etc.
  • Code segmentation: extract the common code of multiple pages, extract the code of the first screen without the execution part to load asynchronously;
  • Module merging: There will be many modules and files in the project adopting modularization, which need to build functions to classify and merge modules into one file;
  • Auto refresh: monitor the changes of local source code, rebuild and refresh the browser automatically;
  • Code Verification: Before the code is submitted to the warehouse, it is necessary to verify whether the code conforms to the specifications and whether the unit tests pass.
  • Automatic Publishing: After updating the code, the online publishing code is automatically constructed and transmitted to the publishing system.

There are two cores in Web pack applications:

  • 1) Module converter, which is used to convert the original content of the module into new content according to the requirements, can load non-JS modules;
  • 2) Extension plug-ins inject extension logic at a specific time in the Webpack build process to change the build results or do what you want.

2. Initialization project

├── src   # Source directory
│   ├── a-module.js
│   └── index.js

Write a-module.js

module.exports = 'hello';

Write index.js

let a = require('./a-module');
console.log(a);

Here we use CommonJS module to introduce, which is not run on browsers by default. We want to package it through webpack!

3. Quick start of webpack

3.1 installation

npm init -y
npm install webpack webpack-cli --save-dev

webpack supports 0 configuration by default, configuring scripts scripts

"scripts": {
  "build": "webpack"
}

When npm run build is executed, the webpack command under node_modules/.bin is invoked by default, and the webpack-cli parsing user parameters is invoked internally to package. The default entry file is src/index.js.

npx webpack can also be used here. npx is an executable file provided by npm after version 5.2.

We found that a dist directory has been generated, which is the result of the final packaging. main.js can be referenced directly in html, and we are also prompted to default mode to production.

3.2 webpack.config.js

We don't usually use 0 configuration when packing. By default, webpack will look for webpack.config.js or webpackfile.js files in the current directory.

Packaging through configuration files:

const path = require('path');
module.exports = {
    entry:'./src/index.js',
    output:{
        filename:'bundle.js', 
        // Packed Outcome File
        path:path.resolve(__dirname,'dist')// Packed in dist directory
    }
}

3.3 Configure packaged mode

We need to provide the mode l attribute when packaging to distinguish the development environment from the production environment in order to split the configuration file.

├── build
│   ├── webpack.base.js
│   ├── webpack.dev.js
│   └── webpack.prod.js

We can package by specifying different files.

Configure scripts scripts:

"scripts": {
  "build": "webpack --config ./build/webpack.prod",
  "dev": "webpack --config ./build/webpack.dev"
}

You can specify which configuration file to use for packaging by config parameters.

Differentiation by env parameters

"scripts": {
    "build": "webpack --env.production --config ./build/webpack.base",
    "dev": "webpack --env.development --config ./build/webpack.base"
}

Modifying the default export function of webpack.base file will pass environment variables into the parameters of the function.

module.exports = (env)=>{
    console.log(env); // { development: true }
}

Merge configuration files

We can determine whether the current environment is a development environment to load different configurations. Here we need to merge the configurations.
Install webpack-merge:

npm install webpack-merge --save-dev

webpack.dev configuration

module.exports = {
    mode:'development'
}

webpack.prod configuration

module.exports = {
    mode:'production'
}

webpack.base configuration

const path = require('path');
const merge = require('webpack-merge');
// development environment
const dev = require('./webpack.dev');
// production environment
const prod = require('./webpack.prod');
const base = { 
    // Basic configuration
    entry:'./src/index.js',
    output:{
        filename:'bundle.js',
        path:path.resolve(__dirname,'../dist')
    }
}
module.exports = (env) =>{
    if(env.development){
        return merge(base,dev);
    }else{
        return merge(base,prod);
    }
}

In the follow-up development, we will put the public logic into the base, and the configuration in the development and production will be stored separately.

4.webpack-dev-server

Configuring the development server allows you to package in memory and start the service automatically.

npm install webpack-dev-server --save-dev
"scripts": {
    "build": "webpack --env.production --config ./build/webpack.base",
    "dev": "webpack-dev-server --env.development --config ./build/webpack.base"
}

Start the development environment by executing npm run dev:

By default, the service will be started under the current root directory

Configuration of Configuration Development Services

const path = require('path')
module.exports = {
    mode:'development',
    devServer:{
        // Change static file directory location
        contentBase:path.resolve(__dirname,'../dist'),
        compress:true, // Open gzip
        port:3000, // Change port number
    }
}

5. Packaging Html plug-ins

5.1 Single-entry Packaging

Automatically generate html and introduce packaged files

Edit webpack.base file

const HtmlWebpackPlugin = require('html-webpack-plugin');
plugins:[
    new HtmlWebpackPlugin({
        filename:'index.html', // Packed file name
        template:path.resolve(__dirname,'../public/index.html'),
        hash:true, // Add hash stamp after reference resource
        minify:{
            removeAttributeQuotes:true // Delete double quotation marks for attributes
        }
    })
]

5.2 Multi-entry Packaging

Multiple js files are generated according to different entries and introduced into different html:

── src
    ├── entry-1.js
    └── entry-2.js

Multiple entries need to be configured

entry:{
    jquery:['jquery'], // Pack jquery
    entry1:path.resolve(__dirname,'../src/entry-1.js'),
    entry2:path.resolve(__dirname,'../src/entry-2.js')
},
output:{
    filename:'[name].js',
    path:path.resolve(__dirname,'../dist')
},

Generate multiple html files

new HtmlWebpackPlugin({
    filename:'index.html',
    template:path.resolve(__dirname,'../public/template.html'),
    hash:true,
    minify:{
        removeAttributeQuotes:true
    },
    chunks:['jquery','entry1'], // The introduced chunk has jquery,entry
}),
new HtmlWebpackPlugin({
    filename:'login.html',
    template:path.resolve(__dirname,'../public/template.html'),
    hash:true,
    minify:{
        removeAttributeQuotes:true
    },
    inject:false, // inject is false to denote not injecting js files
    chunksSortMode:'manual', // Manual configuration of code block order
    chunks:['entry2','jquery']
})

The above approach is not very elegant. Each time you need to manually add HtmlPlugin, you should dynamically generate html files, like this:

let htmlPlugins = [
  {
    entry: "entry1",
    html: "index.html"
  },
  {
    entry: "entry2",
    html: "login.html"
  }
].map(
  item =>
    new HtmlWebpackPlugin({
      filename: item.html,
      template: path.resolve(__dirname, "../public/template.html"),
      hash: true,
      minify: {
        removeAttributeQuotes: true
      },
      chunks: ["jquery", item.entry]
    })
);
plugins: [...htmlPlugins]

6. Empty packing results

clean-webpack-plugin can be used to manually clear the contents of a folder:

install

npm install --save-dev clean-webpack-plugin
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
new CleanWebpackPlugin({
    // Clear the matching path
    cleanOnceBeforeBuildPatterns: [path.resolve('xxxx/*'),'**/*'],
})

So you can empty the specified directory, and you can see that the basic usage of the webpack plug-in is new Plugin and put it in the plugins.

7. summary

Are there any preliminary impressions or more ideas about the use of webpack? Are the big knives of the gods going to be irrepressible? Next issue will introduce the various configurations that webpack has to meet. Please look forward to it!

Posted by binumathew on Mon, 16 Sep 2019 02:26:21 -0700