Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”

This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.

The introduction

Webpack is the most commonly used project builder on the front end, but is often discouraged by its cumbersome configuration. This article will walk you through the basics of configuring WebPack step by step

What is the Webpack

Webpack is by far the most common front resources build tools, in Webpack view, front end all resource files (. CSS/js/JSX/img/PNG/sass…). Will be treated as modules. Depending on the structure of your project, Webpack packs ES6 and other extension languages that browsers can’t use directly, such as typescript, Sass, Vue, etc., with Loaders processing into a language that browsers can read so that it works correctly on the browser

Installation and use

  1. Create a folder and usenpm init -yInitialize the NPM
mkdir webpack
cd webpack
npm init -y
Copy the code
  1. The installationwebpack,webpack-cli
npm install webpack webpack-cli -D
Copy the code
  1. newsrcFolder, newindex.htmlandindex.js, modifyindex.js
// index.js
console.log('hello webpack! ')
Copy the code
  1. Enter on the consolenpx webpack
npx webpack
Copy the code

You can see that the dist folder is generated in the root directory of the project, and there is main.js in it, indicating that webpack is successfully packaged!

Webpack basic configuration

Create the webpack configuration file webpack.config.js in the project root directory

Entrance to the entry

Entry specifies the entry file that WebPack builds, which determines the module from which WebPack starts generating the dependency graph

// webpack.config.js
module.exports = {
  / / the entry
  entry: {
    main: './src/index.js'}}Copy the code

Multiple entry configuration:

// webpack.config.js
module.exports = {
  / / the entry
  entry: {
    one: './src/one.js'.two: './src/two.js'}}/ / or
module.exports = {
  / / the entry
  entry: {
    main: [
      './src/one.js'.'./src/two.js']}}Copy the code

Export output

The Output field specifies where WebPack should output the file it builds, Path, and how to name filename

// webpack.config.js
const path = require('path')

module.exports = {
  / / the entry
  entry: {
    main: './src/index.js'
  },
  / / export
  output: {
    path: path.resolve(__dirname, 'dist'),    // ./dist
    filename: 'main.js'}}Copy the code

Pattern mode

Provides the mode configuration option to tell WebPack to use the built-in optimizations for the corresponding mode.

  1. development

The value of process.env.node_env is set to development. Enable NamedChunksPlugin and NamedModulesPlugin.

module.exports = {
  // ...
  mode: 'development'
}
Copy the code
  1. production

The value of process.env.node_env is set to production. Enable FlagDependencyUsagePlugin FlagIncludedChunksPlugin…

module.exports = {
  // ...
  mode: 'production'
}
Copy the code

You can also specify the packaging mode when you run the packaging command

npx webpack --mode developmenet
Copy the code

Loader

Loaders is one of the core concepts of Webpack, because webPack can only handle JS files by default, so when you encounter other file types CSS/JPG/PNG /ts… For example, convert ES6 to ES5 that can be read by the browser, convert TypeScript to JavaScript, convert Sass to CSS. It is similar to the machines on a factory assembly line, which process and package raw materials step by step to produce a usable product

Loaders configuration has only a few simple items (* is mandatory) :

  • Test: matches the regular expression of the corresponding file format (*)
  • Use: Loader to use (*)
  • Include /exclude: files to be processed or files not to be processed

Use file-loader to package JPG/PNG/GIF images

const path = require('path')

module.exports = {
  mode: 'development'.entry: {
    main: './src/index.js'
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'main.js'
  },
  module: {
    rules: [{test: /.(jpg|png|gif)$/,
        use: {
          loader: 'file-loader'.options: {    // Provide additional configuration for loader (optional)
            // placeholder []
            name: '[name].[ext]'.// Use the original filename and suffix
            // Can also be [name]_[hash].[ext] filename _ hash
            outputPath: 'images/'    // Output path}}}]}}Copy the code

Run NPX webpack and you can see the image in the dist directory

Use url-loader to package images

Url-loader converts the image format to Base64

const path = require('path')

module.exports = {
  mode: 'development'.entry: {
    main: './src/index.js'
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'main.js'
  },
  module: {
    rules: [{test: /.(jpg|png|gif)$/,
        use: {
          loader: 'url-loader'.options: {
            name: '[name].[ext]'.// Use the original filename and suffix
            outputPath: 'images/'.limit: 2048    // Limit files to 2048 bytes, i.e. 2KB
            // If so, use file-loader}}}]}}Copy the code

If we want to change the image style to 300px width and height, we usually create an index. CSS file, write the style and import it in the index.js file

.avatar {
  width: 300px;
  height: 300px;
}
Copy the code

In the index.js file

import image from './psc.jpg'
import './index.css'

const img = new Image()
img.src = image
img.className += 'avatar'

const app = document.getElementById('app')
app.appendChild(img)
Copy the code

If you run NPX webpack, you can see the console error:

This is because WebPack cannot parse.cssFile, at this point we need the corresponding Loader to handle this type of file CSS file

Use CSS-loader and style-loader to package styles

Install CSS-loader and style-loader

npm install css-loader style-loader -D
Copy the code
// webpack.config.js
{
  test: /.css$/,
  use: [
    'style-loader'.'css-loader'.'postcss-loader'.'sass-loader']}Copy the code

Note that the plugin array is executed from bottom up/right to left

Use sass-Loader to process SCSS files

npm install sass sass-loader -D
Copy the code
body {
  .avatar {
    width: 300px;
    height: 300px; }}Copy the code

Execution sequence: Sass -loader converts sASS files to CSS files, and then submits them to CSS-loader and style-loader

module.exports = {
  // ...
  {
    test: /.scss$/,
    use: [
      'style-loader'.'css-loader'.'sass-loader']}}Copy the code

Prefixes the CSS3 properties with the browser

For some CSS3 properties, we want to prefix it with the corresponding browser (for example, -webkit-) to ensure that it works correctly across browsers. Postcss-loader automatically prefixes the browser for us

npm install postcss postcss-loader autoprefixer -D
Copy the code
// webpack.config.js
// ...
{
  test: /.css$/,
  use: [
    'style-loader'.'css-loader'.'postcss-loader'.'sass-loader']}Copy the code

New postcss. Config. Js

// postcss.config.js
module.exports = {
  plugins: [
    require('autoprefixer')  // Introduce the Autoprefixer plugin]}Copy the code

The plugin is internally prefixed by the browserslist property in package.json, so we need to configure package.json accordingly

// package.json
"browserslist": [
  "1%" >.// Browsers compatible with 1% of the market are required
  "last 2 versions"   // Need to be compatible with both versions
]
Copy the code

Babel processing ES6

Install the loader

npm install -D babel-loader @babel/core @babel/preset-env
Copy the code

Note: There are three modules to install, don’t miss out =.=

const path = require('path')

const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')

module.exports = {
  mode: 'development'.entry: {
    main: './src/index.js'
  },
  output: {
    filename: 'bundle.js'.path: path.resolve(__dirname, 'dist')},module: {
    rules: [{test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader'.options: {
            presets: ['@babel/preset-env'}}}, {test: /.(jpg|png|gif)$/,
        use: {
          loader: 'url-loader'.options: {
            name: '[name]_[hash].[ext]'.outputPath: 'images/'}}}]},plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    new CleanWebpackPlugin()
  ]
}
Copy the code

Package the output main.js/bundle.js

As you can see, there is a problem here: Babel can only convert ES6 syntax, not new apis. Global objects such as Generator, Set, Maps, Proxy, Symbol, Promise, Async, and some methods defined on global objects such as Object.assign cannot be converted. For these, we can use Babel-polyfill

Babel handles the new ES6 API

Install (be careful to use –save, because the online environment is also needed) :

npm install @babel/polyfill --save
Copy the code

Introduce babel-polyfill in the index.js file

import '@babel-polyfill'
Copy the code

Packaged outputmain.js As you can see, there is a lot more code in main.js. The size of the packed JS file is 405KB, while the size of the code before babel-polyfill was only 264 Bytes. Why are the sizes of the packed files so different?The reason is thatwebpackthebabel-polyfillThe whole thing is packed in. whilebabel-polyfillAnd certainly all of themA new API ES6The gasket, the file must not be small.

We can add the useBuiltIns configuration to babel-Loader to tell babel-Polyfill to package only the ES6 code used to avoid unnecessary packaging and reduce the volume of packaging output.

// webpack.config.js
modules.exports = {
  // ...
  module: {
    rules: [{test: /\.js$/,
        use: {
          loader: 'babel-loader'.options: {
            presets: [['@babel/preset-env',
                {
                  useBuiltIns: 'usage'}}}}}Copy the code

After entering the command, you can see that the size of the packaged output code is 192KB, which is significantly smaller

Plugin

Plugin is another core concept of WebPack, which can extend the functionality of WebPack when it reaches a certain stage. Two commonly used plugins are recommended

  1. html-webpack-plugin

The HTML-webpack-plugin automatically generates HTML files after packaging and injects the packed results into HTML.

The installation

npm install html-webpack-plugin -D
Copy the code

use

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

module.exports = {
  mode: 'development'.entry: {
    main: './src/index.js'
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'main.js'
  },
  module: {
    rules: [{test: /.(jpg|png|gif)$/,
        use: {
          loader: 'file-loader'.options: {    // Provide additional configuration for loader (optional)
            // placeholder []
            name: '[name].[ext]'.// Use the original filename and suffix
            // Can also be [name]_[hash].[ext] filename _ hash
            outputPath: 'images/'    // Output path}}}]},plugins: [
    new HtmlWebpackPlugin()
  ]
}
Copy the code

Receive Template Configuration

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

module.exports = {
  mode: 'development'.entry: {
    main: './src/index.js'
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'main.js'
  },
  module: {
    rules: [{test: /.(jpg|png|gif)$/,
        use: ['file-loader']}}]},plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'}})]Copy the code

Here we let the process of importing the index.js file after packaging be injected into index.html automatically

  1. clean-webpack-plugin

Each time before the NPM run build we need to manually delete the dist folder. The clean-webpack-plugin can automatically delete the dist folder before exporting the packaged file

The installation

npm install clean-webpack-plugin -D
Copy the code

use

const path = require('path')

const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')

module.exports = {
  mode: 'development'.entry: './src/index.js'.output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js'
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    new CleanWebpackPlugin()
  ]
}
Copy the code

SourceMap

The browser actually executes the webpack-processed main.js or bundle.js file at runtime, and the problem is that if there is an error in the code, the browser in the console points to the packaged main.js file, which means that if we make an error at line 5 of the source code, You don’t know what line you’re pointing to in packaged code. That’s where SourceMap comes in. SourceMap is a technology that maps compiled, packaged, and compressed code back to the source code, pointing it exactly where the source code is

Configuration SourceMap

// Development environment
module.exports = {
  mode: 'development'.devtool: 'cheap-module-source-map'.entry: './src/index.js'.output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'main.js'
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    new CleanWebpackPlugin()
  ]
}
Copy the code

WebpackDevServer

We need to re-run NPX Webpack every time we change the code to see the effect of the changes. Is there any way in WebPack that we can automatically package the changes after we save them? Webpack-dev-server can start a server locally and have the packaged output file run on the server, so that after we change the code save, webpack-dev-server will automatically package for us

The installation

npm install webpack-dev-server -D
Copy the code

Add the following command to package.json

// package.json
"scripts": {
  "watch": "webpack --watch"."start": "webpack serve"
}
Copy the code

Run NPM run start to start the Webpack server at localhost:8080

Open: Automatically opens the browser

// webpack.config.js
devServer: {
  contentBase: './dist'.// webpack-dev-server3
  open: true
}
Copy the code

After running NPM run start, you can see that Webpack automatically opens the browser for us and visits localhost:8080

Use WebpackDevServer to implement request forwarding

HTTP requests are often used during development, and the proxy can forward the request to another URL when you request an interface

// webpack.config.js
module.exports = {
  // ...
  devServer: {
    contentBase: './dist'.proxy: {
      '/api': {
        target: 'http://localhost:3000'}}}}Copy the code
axios.get('/api/users').then(res= > {
  // ...
})
Copy the code

This time, if send the request to the/API/users, is the agent to request to http://localhost:3000/api/users.

The HMR module is hot replaced

There is no need to refresh the page, save and update. This means that content already rendered to the page does not disappear, but is automatically applied directly to the page based on the modified code

const path = require('path')

const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')

module.exports = {
  mode: 'development'.entry: {
    main: './src/index.js'
  },
  devserver: {
    contentBase: './dist'.open: true.hot: true    / / open HMR
  },
  output: {
    filename: 'bundle.js'.path: path.resolve(__dirname, 'dist')},module: {
    rules: [{test: /.(jpg|png|gif)$/,
        use: {
          loader: 'url-loader'.options: {
            name: '[name]_[hash].[ext]'.outputPath: 'images/'}}}]},plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    new CleanWebpackPlugin()
  ]
}
Copy the code

Note: HMR is turned on by default in Webpack4

conclusion

This article introduces the following basic configuration of Webpack, hoping to help the front end of the small white start Webpack, Webpack configuration process looks very complex, from the webpack official website can also see configuration items are also very much, but do not be scared by its cumbersome surface, mainly clear webpack logic, Step by step to configure the corresponding items, in fact, Webpack is also (zhen) this (de) like (nan)

Finally, if this article has been helpful to you, leave a like