01 Preliminary study of Webpack – guide learning

Disadvantages of traditional programming

Before the use of object-oriented programming, the page needs to introduce multiple JS, resulting in multiple requests, affecting loading, need to pay attention to the order of reference, when using JS can not be directly seen from the hierarchy of the file, once the error debugging is very troublesome

// /index.html
<div id="root"></div>
<script src="./header.js"></script>
<script src="./index.js"></script>

// /header.js
function Header() {
  var root = document.getElementById('root')
  var header = document.createElement('div')
  header.innerText = 'header'
  root.appendChild(header)
}

// /index.js
new Header()
Copy the code

Programming with Webpack (module packaging tool)

Solve the disadvantages of traditional programming

  • Create project folder mkdir webpack-test
  • Rmdir webpack-test # Delete folder
  • CD webpack-test # go to the project folder
  • NPM init # Initialize the package manager
  • NPM init -y # generates a default configuration item instead of asking for it step by step
  • NPM install webpack-cli –save-dev # install webpack-cli
  • NPM uninstall webpack-cli –save-dev # Uninstall webpack-cli
  • NPM install webpack –save webpack
  • NPM info webpack # View webpack information
  • NPM install [email protected] -s # Installs the webpack with the specified version number

Create file write code:

// /index.html
<div id="root"></div>

// /header.js
function Header() {
  var root = document.getElementById('root')
  var header = document.createElement('div')
  header.innerText = 'header'
  root.appendChild(header)
}
export default Header

// /index.js
import Header from './header.js'
new Header()
Copy the code

NPX webpack index.js # compile the index.js file to generate./dist/main.js

// / add the compiled file <script SRC = to index.html"./dist/main.js"></script>
Copy the code

Different modes of module introduction

  • ES Module Indicates the mode of importing modules
exportDefault Header // Export import Header from'./header.js'/ / introductionCopy the code
  • CommonJS module introduction mode
Module. exports = Header // exports var Header = require('./header.js') / / introductionCopy the code

The appendix

  • Webpack official documentation
  • Webpack Chinese document

02 Initial Webpack – Configuration

The installation of the webpack

  • It is best not to install WebPack globally, in case different projects use different versions of WebPack and cannot run at the same time!
  • To install webpack directly in the project, you can not use the global webpack command, you can add NPX in front of it, indicating that the current directory to find webpack, for example: NPX webpack -v
// package.json
{
  "private": true, // indicates that the project is private and will not be sent to NPM's online repository"main": "index.js", // If the project is not referenced externally, there is no need to expose a JS file to the externally, the line can be deleted"scripts": {// Configure the NPM command to simplify commands entered on the command line"build": "webpack"// Instead of adding NPX, webpack will be found in the project directory first; Use NPM run build instead of NPX webpack}}Copy the code

Configuration file for WebPack

  • The default webpack configuration file is webpack.config.js
  • NPX webpack –config wconfig. js # make webpack pack with wconfig.js file as configuration file
// webpack.config.js
const path = require('path'Path module.exports = {entry:'./index.js', // package entry file // entry: {//'./index.js'
  // },
  output: {
    filename: 'main.js'Path: path.resolve(__dirname,'dist') // The path to the packaged file (specify an absolute path); The resolve method of path concatenates the current path (__dirname) with the specified folder name (dist)}, mode:'production', // Configure packaged mode (production/development); Production mode (compressed)/ development mode (not compressed)}Copy the code

Webpack packages the output information

Hash: d8f9a3dacac977cc0968 Package the corresponding unique hash value
Version: webpack 4.40.2 Package the version of Webpack used
Time: 208ms # Time spent packing
Built at: 2019-09-20 16:38:59 The current time of packaging
  Asset       Size  Chunks             Chunk Names
# Generated file file size file id file name
main.js  930 bytes       0  [emitted]  main
Entrypoint main = main.js # Packaged entry files
[0] ./index.js 36 bytes {0} [built] # All the files that are packed

WARNING in configuration # Warning: No packaging mode specified (production mode will be used by default)
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/
Copy the code

03 Core Concepts of WebPack – Loader

Webpack knows how to package js files by default. Loader tells WebPack how to package other different types of files

Package image type files

file-loader

Use file-loader to package some image files (run NPM I file-loader -d to install file-loader)

// webpack.config.js
module.exports = {
  module: {
    rules: [{
      // test: /\.jpg$/,
      test: / \. (JPG | PNG | GIF) $/, / / configuration to allow matching multiple file types to use: {loader:'file-loader',
        options: {
          name: '[name]_[hash].[ext]'// Set the name of the packaged file (name: the original name of the file;hash: hash value; Ext: file suffix; Final result: file name _ hash value. File suffix), if not specified, the file will be named with the hash value outputPath:'static/img/'// Configure the path location of packaged files}}}]}}Copy the code

url-loader

Similar to file-loader, you can also use url-loader to package some image files (again, install first)

// webpack.config.js
module.exports = {
  module: {
    rules: [{
      test: /\.(jpg|png|gif)$/,
      use: {
        loader: 'url-loader',
        options: {
          name: '[name]_[hash].[ext]',
          outputPath: 'static/img/'.limit: 10240 // Unlike file-loader, it can be configuredlimitParameter (in bytes) when the file is larger thanlimitValue, will generate a separate file, less thanlimit}}}}}Copy the code

Note: Url-loader depends on file-loader. To use url-loader, you need to install file-loader

Package style file

In webpack configuration, loader is sequential. Loader is executed from bottom to top and from right to left

Package CSS/SASS

Note: If Node-sass cannot be installed, use CNPM or viewSolution when Node-sass cannot be installed

// webpack.config.js
module.exports = {
  module: {
    rules: [{
      test: /\.css$/, //.css files end with style-loader and CSs-loader (style-loader and CSs-loader are required) use: ['style-loader'.'css-loader'] // css-loader will help us analyze the relationship between multiple CSS files, merge multiple CSS into one CSS; Style-loader mounts the CSS processed by csS-loader to the head section of the page}, {test: /\.scss$/, // Files at the end of.scss are packaged using style-loader and CSs-loader and sass-loader (style-loader and CSS-loader and sass-loader and Node-sass need to be installed) use: ['style-loader'.'css-loader'.'sass-loader'] // Execute sass-loader to translate sass code into CSS code; It is then processed by CSS-loader. }]}} // index.js // import CSS from js'./index.css'
Copy the code

The vendor prefix is automatically added when packaging

// webpack.config.js
module.exports = {
  module: {
    rules: [{
      test: /\.css/,
      use: ['postcss-loader'] / / need to perform the NPM I install postcss postcss - loader - D - loader}].}} / / postcss config. Js / / in the root directory to create the file. The module exports = { plugins: [ require('autoprefixer'NPM I -d autoprefixer]}Copy the code

Add configuration items to loader

// webpack.config.js
module.exports = {
  module: {
    rules: [{
      test: /\.css/,
      use: ['style-loader', {
        loader: 'css-loader', options: { importLoaders: 1 // Sometimes a style file is imported from another style file. This requires the importLoaders field to be configured. }} Specify n loaders after the current loader to process imported resources.'sass-loader']]}}}Copy the code

CSS packaging modularity (avoid global introduction)

// webpack.config.js
module.exports = {
  module: {
    rules: [{
      test: /\.css$/,
      use: ['style-loader', {
        loader: 'css-loader',
        options: {
          modules: trueAvatar {width: 100px; height: 100px; } // index.js import style from'./index.css'
var img = new Image()
img.src = ' '
img.classList.add(style.avatar)
Copy the code

Package font files

// webpack.config.js
module.exports = {
  module: {
    rules: [{
      test: /\.(eot|ttf|svg)$/,
      use: ['file-loader']]}}}Copy the code

04 The core concept of WebPack – Plugin

Plugin can do something for you when WebPack is running at a certain point (similar to vue’s lifecycle function)

HTML – webpack – plugin (v3.2.0)

  • Time: Start running after packing
  • Function: An HTML file will be generated automatically after packaging, and the JS generated by packaging will be automatically introduced into the HTML file
  • Install: NPM I html-webpack-plugin-d
  • Use:
// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  plugins: [new HtmlWebpackPlugin({
    template: 'index.html'// Specify the template file to generate HTML (if not, a default HTML file with no other content will be generated)})]}Copy the code

The clean – webpack – plugin (v3.0.0)

  • Clean-webpack-plugin upgrade 3.0 pit
  • Time: Start running before packaging
  • Delete directory (default: delete directory specified by path under output)
  • Install: NPM I clean-webpack-plugin -d
  • Use:
// webpack.config.js
const { CleanWebpackPlugin } = require('clean-webpack-plugin')

module.exports = {
  plugins: [new CleanWebpackPlugin({
    cleanOnceBeforeBuildPatterns: [path.resolve(__dirname, 'dist')] // Delete path from output})]}Copy the code

05 Core concept of Webpack – entry&Output

Packaging a single file

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

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

Packaging multiple files

// webpack.config.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  entry: {
    index1: './src/a.js',
    index2: './src/b.js'
  },
  output: {
    publicPath: 'http://cdn.com.cn'// In the automatically generated HTML file, the import file path will be preceded by the filename:'[name].[hash].js'Resolve (__dirname,) path: path.resolve(__dirname,'dist')
  },
  plugins: [new HtmlWebpackPlugin()]
}
Copy the code

06 Core concept of Webpack -sourceMap

  • SourceMap is a mapping that maps packaged files to source files, making it easy to find error codes
  • Configure DevTool to control how sourceMap is generated
// webpack.config.js
module.exports = {
  devtool: 'source-map'
  // devtool: 'cheap-module-eval-source-map'// devTool:'cheap-module-source-map'}}Copy the code
  • Possible values for devtool:
devtool explain
none Don’t generate sourceMap
source-map Generate the.map file
inline-source-map Instead of generating a.map file, sourceMap will be merged into the generated file
cheap-source-map Only the wrong rows are told, not the wrong columns
cheap-module-source-map In addition to the business code error, there are also some errors in the Loader
eval Instead of generating a.map file, eval is used to generate the mapping in the packaged file

07 Core Concepts of WebPack -WebpackDevServer

–watch

Add –watch to the webpack command, and Webpack will listen for packaged files and automatically repack them whenever they change

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

webpack-dev-server

  • NPM I webpack-dev-server -d # install webpack-dev-server
  • configuration
// webpack.config.js
module.exports = {
  devServer: {}
}

// package.json
{
  "scripts": {
    "wdserver": "webpack-dev-server"}}Copy the code
  • NPM run wdServer # Compile the project into memory and start a service
  • DevServer has a number of configurable parameters:
open: true// Automatically opens the current project in the browser when the service is started (default)false) port: 8888 // Custom service port number (default 8080) contentBase:'./static'// Specify the requested path of the resource (default current path) for example: /static/img. PNG devServer:'./static'Use <img SRC = in /index.html"img.png"/> then it will go to the /static folder to find img. PNG instead of going to the root directory to find img. PNGCopy the code
  • Reference documentation

express & webpack-dev-middleware

Build your own services manually with Express and Webpack-dev-Middleware

  • NPM I Express webpack-dev-middleware -d # Install express and Webpack-dev -middleware packages
  • Create server.js in the root directory
// server.js(webpack in node) const express = require('express')
const webpack = require('webpack')
const webpackDevMiddleware = require('webpack-dev-middleware')
const webpackConfig = require('./webpack.config.js')
const complier = webpack(webpackConfig)

const app = express()

app.use(webpackDevMiddleware(complier, {}))

app.listen(3000, () => {
  console.log('server is running at port 3000')})Copy the code
  • Configure the NPM command
// package.json
{
  "scripts": {
    "nodeserver": "node server.js"}}Copy the code
  • NPM run nodeserver # Compile the project and start the service (after success, enter localhost:3000 in your browser to access the project)

The appendix

Use WebPack on the command line

Webpack index.js -o main.js # Compile index.js to output main.js


The core concept – HotModuleReplacementPlugin webpack 08

HotModuleReplacementPlugin webpack is bringing a plug-in, do not need to install separately

configuration

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

module.exports = {
  devServer: {
    hot: true// Let webpack-dev-server enable hot Module replacement hotOnly:true/ / even hot module replacement function has no effect, nor the browser automatically refresh}, plugins: [new webpack. HotModuleReplacementPlugin ()]}Copy the code

In the CSS

If you change the style file, the page does not reload entirely, but just updates the style

// /index.html <! DOCTYPE html> <html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge"/ > < title > HTML templates < / title > < / head > < body > < / body > < / HTML >Copy the code
// /src/index.css
div {
  width: 100px;
  height: 100px;
}
div:nth-of-type(odd) {
  background-color: rgb(255, 0, 0);
}
Copy the code
// /src/index.js
import './index.css'

var btn = document.createElement('button')
btn.innerText = 'button'
document.body.appendChild(btn)

btn.onclick = () => {
  var item = document.createElement('div')
  item.innerText = 'item'
  document.body.appendChild(item)
}
Copy the code
// /package.json
{
  "name": "webpack-test"."version": "1.0.0"."description": ""."private": false."scripts": {
    "wdserver": "webpack-dev-server"
  },
  "keywords": []."author": ""."license": "ISC"."devDependencies": {
    "css-loader": "^ 3.2.0"."html-webpack-plugin": "^ 3.2.0"."style-loader": "^ 1.0.0"."webpack": "^ 4.41.1"."webpack-cli": "^ 3.3.9"."webpack-dev-server": "^ 3.8.2"}}Copy the code
// /webpack.config.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const webpack = require('webpack')

module.exports = {
  entry: {
    main: './src/index.js'
  },
  output: {
    publicPath: '/',
    filename: '[name].[hash].js',
    path: path.resolve(__dirname, 'dist')
  },
  mode: 'production',
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader'.'css-loader']
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: 'index.html'
    }),
    new webpack.HotModuleReplacementPlugin()
  ],
  devServer: {
    hot: true,
    hotOnly: true}}Copy the code

Use in js

Changing the code in the number.js file simply removes the element with id number from the page and reexecutes the number() method without affecting the rest of the page or reloading the entire page

// /index.html <! DOCTYPE html> <html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge"/ > < title > HTML templates < / title > < / head > < body > < / body > < / HTML >Copy the code
// /src/counter.js
function counter() {
  var div = document.createElement('div')
  div.setAttribute('id'.'counter')
  div.innerText = 1
  div.onclick = function() {
    div.innerText = parseInt(div.innerText, 10) + 1
  }
  document.body.appendChild(div)
}

export default counter
Copy the code
// /src/number.js
function number() {
  var div = document.createElement('div')
  div.setAttribute('id'.'number')
  div.innerText = 20
  document.body.appendChild(div)
}

export default number
Copy the code
// /src/index.js
import counter from './counter'
import number from './number'Counter () number() // Instead of writing the overloaded code for CSS, that is because csS-loader has already written this code for CSSif (module.hot) {
  module.hot.accept('./number', () = > {/ / monitoring by a code change, it will execute the following code document. The body. The removeChild (document. GetElementById ('number'))
    number()
  })
}
Copy the code
// /package.json
{
  "name": "webpack-test"."version": "1.0.0"."description": ""."private": false."scripts": {
    "wdserver": "webpack-dev-server"
  },
  "keywords": []."author": ""."license": "ISC"."devDependencies": {
    "html-webpack-plugin": "^ 3.2.0"."webpack": "^ 4.41.1"."webpack-cli": "^ 3.3.9"."webpack-dev-server": "^ 3.8.2"}}Copy the code
// /webpack.config.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const webpack = require('webpack')

module.exports = {
  entry: {
    main: './src/index.js'
  },
  output: {
    publicPath: '/',
    filename: '[name].[hash].js',
    path: path.resolve(__dirname, 'dist')
  },
  mode: 'production',
  plugins: [
    new HtmlWebpackPlugin({
      template: 'index.html'
    }),
    new webpack.HotModuleReplacementPlugin()
  ],
  devServer: {
    hot: true,
    hotOnly: true}}Copy the code

Core concept of WebPack 09 – Using Babel for ES6 syntax

Babel’s official website

The use of Babel

Click to go to the official website (select Webpack)

  1. NPM I -d babel-loader @babel/core @babel/preset-env # Install babel-loader and @babel/core and @babel/preset-env
  • Babel-loader: is a bridge between Webpack and Babel, so that webpack and Babel can get through, babel-loader does not convert JS ES6 syntax into ES5 syntax
  • @babel/core: is the core syntax library of Babel, which allows Babel to recognize the contents of JS code and convert them
  • @babel/preset-env: Preset to ES6 grammar to ES5 grammar, which contains all the translation rules for ES6 grammar to ES5 grammar
  1. configuration
// webpack.config.js
module.exports = {
  module: {
    rules: [{
      test: /\.js$/, exclude: /node_modules/, // Exclude: /node_modules/, //'babel-loader',
      options: {
        presets: ['@babel/preset-env'}}]}}Copy the code

The above steps are syntactically translated (e.g., let/const/ arrow function /… ), but some new variables and methods are not translated (e.g. Promise /.map()/…). At this point, I’m going to use @babel/ Polyfill

@babel/polyfill

Using the @ Babel/polyfill

  1. NPM i-d @babel/polyfill
  2. Import ‘@babel/polyfill’ # import @babel/polyfill at the first line of the entry file index.js

After configuration like the above, you will find that the packaged file is very large because some unused ES6 syntax is also packaged, so you need to do the following

  • Reference documentation
  • NPM i-d core-js # Install core-js(v3.3.2)
  • Delete import ‘@babel/polyfill’ from entry file index.js
  • configuration
// webpack.config.js
module.exports = {
  module: {
    rules: [{
      test: /\.js$/,
      exclude: /node_modules/,
      loader: 'babel-loader',
      options: {
        presets: [
          [
            '@babel/preset-env',
            {
              corejs: 3,
              useBuiltIns: 'usage', targets: {// Specify the environment in which the project is running by targets.'67'}}]]}}}Copy the code

If you are writing business code, you can use the method above to package it with Polyfill. If you are developing components or libraries, using plugin-transform-Runtime polyfill will pollute the global environment. Plugin-transform-runtime will be used as a closure to help the component import content


The core concept of WebPack – package the React framework code

@ Babel/preset – react document

// /index.html <! DOCTYPE html> <html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge"/> <title> HTML template </title> </head> <body> <div id="app"></div>
  </body>
</html>
Copy the code
// /src/index.js
import React, { Component } from 'react'
import ReactDom from 'react-dom'

class App extends Component {
  render() {
    return <div>Hello World</div>
  }
}

ReactDom.render(<App />, document.getElementById('app'))
Copy the code
// /.babelrc
{
  "presets": [["@babel/preset-env",
      {
        "corejs": 3."useBuiltIns": "usage"."targets": {
          "chrome": 67}}],"@babel/preset-react"]}Copy the code
// /package.json
{
  "name": "webpack-test"."version": "1.0.0"."description": ""."private": false."scripts": {
    "wdserver": "webpack-dev-server"
  },
  "keywords": []."author": ""."license": "ISC"."devDependencies": {
    "@babel/core": "^ 7.6.4." "."@babel/polyfill": "^ 7.6.0"."@babel/preset-env": "^ 7.6.3." "."@babel/preset-react": "^ 7.6.3." "."@babel/runtime-corejs3": "^ 7.6.3." "."babel-loader": "^ 8.0.6"."clean-webpack-plugin": "^ 3.0.0"."core-js": "^ 3.3.2 rainfall distribution on 10-12"."html-webpack-plugin": "^ 3.2.0"."react": "^ 16.10.2"."react-dom": "^ 16.10.2"."webpack": "^ 4.41.1"."webpack-cli": "^ 3.3.9"."webpack-dev-server": "^ 3.8.2"}}Copy the code
// /webpack.config.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const webpack = require('webpack')

module.exports = {
  entry: {
    main: './src/index.js'
  },
  output: {
    publicPath: '/',
    filename: '[name].[hash].js',
    path: path.resolve(__dirname, 'dist')
  },
  mode: 'development',
  devtool: 'cheap-module-eval-source-map',
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader'
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: 'index.html'
    }),
    new CleanWebpackPlugin({
      cleanOnceBeforeBuildPatterns: [path.resolve(__dirname, 'dist')]
    }),
    new webpack.HotModuleReplacementPlugin()
  ],
  devServer: {
    hot: true,
    hotOnly: true}}Copy the code

Advanced concepts for Webpack -TreeShaking

  • TreeShaking is a static reference based on ES6. It scans all ES6 exports to find the contents that are imported and adds them to the final code to exclude unused code
  • TreeShaking only supports ES Module import and does not support CommonJS import
  • For production use, you need to configure “sideEffects”: false in package.json (TreeShaking all modules)
  • If the imported library does not export anything (e.g. Import ‘@babel/polyfill’), “sideEffects” needs to be configured: [“@babel/polyfill”], so that TreeShaking does not process @babel/polyfill
  • If you import style files (e.g. Import ‘./style.css’), you need to configure “sideEffects”: [“*.css”]
  • To use TreeShaking in your development environment, you need to configure it in webpack.config.js
module.exports = {
  optimization: {
    usedExports: true}}Copy the code

Advanced concepts of Webpack – differentiated packaging of DEV&PROd mode

  1. NPM I -d webpack-merge # Install the webpack-merge module, which merges the common Webpack configuration code with the webPack configuration code in the development/production environment

  2. /build/webpack.common.js # store the common Webpack configuration code

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

module.exports = {
  entry: {
    main: './src/index.js'
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: 'index.html'
    }),
    new CleanWebpackPlugin({
      cleanOnceBeforeBuildPatterns: [path.resolve(process.cwd(), 'dist')] // __dirname => process.cwd()
    })
  ],
  output: {
    filename: '[name].[hash].js',
    path: path.resolve(__dirname, '.. /dist') // dist => .. /dist } }Copy the code
  1. /build/webpack.dev.js
const merge = require('webpack-merge')
const commonConfig = require('./webpack.common.js')

const devConfig = {
  mode: 'development'
}
module.exports = merge(commonConfig, devConfig)
Copy the code
  1. /build/webpack.prod.js # store the production webpack configuration code
const merge = require('webpack-merge')
const commonConfig = require('./webpack.common.js')

const prodConfig = {
  mode: 'production'
}
module.exports = merge(commonConfig, prodConfig)
Copy the code
  1. /package.json
{
  "scripts": {
    "dev": "webpack-dev-server --config ./build/webpack.dev.js"."build": "webpack --config ./build/webpack.prod.js"}}Copy the code
  1. Run the command
  • NPM run dev #
  • NPM Run Build # Production mode

The appendix

  • Process.cwd () # directory where the node command is executed
  • __dirname # The directory in which js is executed
  • path.join(path1, path2, path3, …) Join path fragments together to form a new path
  • path.resolve([from…] To) # Parse a path or sequence of path fragments into an absolute path, equivalent to performing the CD operation

13 Advanced Concept of Webpack -CodeSplitting

  • CodeSplitting: Code split, code split has nothing to do with Webpack
  • NPM i-s LoDash # Install LoDash

Manual code splitting (configuring multiple entry files)

// /src/lodash.js
import _ from 'lodash'
window._ = _
Copy the code
// /src/index.js
console.log(_.join(['a'.'b'.'c'])) // output a,b,c console.log(_. Join (['a'.'b'.'c'].'* * *'A ***b***cCopy the code
// /build/webpack.common.conf.js
module.exports = {
  entry: {
    lodash: './src/lodash.js',
    main: './src/index.js'}}Copy the code

Automatic code segmentation

The SplitChunksPlugin plugin is used at the bottom of code splitting in WebPack

Implementing synchronous code splitting in WebPack (Configuration Optimization required)

// /src/index.js
import _ from 'lodash'

console.log(_.join(['a'.'b'.'c'])) // output a,b,c console.log(_. Join (['a'.'b'.'c'].'* * *'A ***b***cCopy the code
// /build/webpack.common.conf.js
module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'all'}}}Copy the code

Asynchronous code splitting in Webpack (import, etc., no configuration required)

// /src/index.js
function getComponent() {
  return import('lodash').then(({ default: _ }) => {
    var element = document.createElement('div')
    element.innerHTML = _.join(['hello'.'world'].The '-')
    return element
  })
}

getComponent().then(element => {
  document.body.appendChild(element)
})
Copy the code

Import (‘lodash’). The name of the split and packaged file is [id].[hash].js. Using the import (/ * webpackChunkName: “Lodash” */ ‘lodash’) to alias the packaged file to improve its identification (the resulting filename is called: Vendors ~lodash.[hash].js, meaning it follows vendors group rules, entry is main), details are searchable view the configuration of SplitChunksPlugin this way is called magic annotations, See the Magic Comments website for more details

Note: If “Support for the experimental syntax ‘dynamicImport’ isn’t currently enabled” is displayed, You can install @babel/plugin-syntax-dynamic-import to solve this problem

@babel/plugin-syntax-dynamic-import

// npm i -D @babel/plugin-syntax-dynamic-import Install the module package

// /.babelrc # configuration
{
  "plugins": ["@babel/plugin-syntax-dynamic-import"]}Copy the code

The appendix

  • The name of the output file after packaging
// /build/webpack.common.conf.js
module.exports = {
  output: {
    filename: '[name].[hash].js'// Name the entry file according to filename:'[name].chunk.js'Resolve (__dirname, // non-entry file named according to chunkFilename.'.. /dist')}}Copy the code

Advanced concepts of Webpack -SplitChunksPlugin

SplitChunksPlugin official website address

// webpack.common.conf.js module.exports = {optimization: {splitChunks: {chunks:'async'// async: code splitting only applies to asynchronous code; All: applies to both synchronous and asynchronous code. Initial: valid only for synchronization code minSize: 30000, // unit: bytes; // If the packed library is larger than maxSize, the code segmentation will be performed only when the library is larger than minSize, and the code segmentation will not be performed when the library is smaller than maxSize. MaxAsyncRequests (" chunks "); // Code segmentation is performed only when a module is used at least minChunks: // maxAsyncRequests can be carried out in maximum number of modules. If more than maxAsyncRequests, only the former maxAsyncRequests can be carried out in code partition. MaxInitialRequests: // maxInitialRequests can only be split for js files automaticNameDelimiter:'~', // Package builder names between the linker name:true, // Make the names in cacheGroups valid, vendors: {vendors: {test: /[\\/]node_modules[\\/]/, // If modules are imported from node_modules, package them to vendors set priority: -10 // Specify the priority of the group. If a library complies with the rules of multiple groups, it is packed into the group with the highest priority. Default: {minChunks: 2, priority: -20, reuseExistingChunk:true// If a module has already been packaged (a module is referenced by multiple files), the package will ignore the module and use the previously packaged module}}}}}Copy the code

Note: Some configurations on SplitChunksPlugin need to be used in conjunction with configurations in cacheGroups (e.g. chunks) to take effect.

// webpack.common.conf.js
module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          priority: -10,
          filename: 'vendors.js'// after filename is configured, the package takes the value of filename as the filename, and the resulting file is vendors. Js}, default:false}}}}Copy the code

Advanced concepts for webpack -LazyLoading&Chunk

LazyLoading

LazyLoading: LazyLoading is not a concept in webpack, but in ES; When will it be executed and when will the corresponding module be loaded

  • In the following synchronous code writing method, js files corresponding to the partitioned module are directly introduced into HTML through script tags when packaging, and these JS files will be loaded when the page starts to load, resulting in slow page loading
// /src/index.js
import _ from 'lodash'

document.addEventListener('click', () => {
  var element = document.createElement('div')
  element.innerHTML = _.join(['hello'.'world'].The '-')
  document.body.appendChild(element)
})
Copy the code
  • The following asynchronous code is written to implement lazy loading behavior, loading the required modules only when the interface is clicked
// /src/index.js
function getComponent() {
  return import(/* webpackChunkName: "lodash"* /'lodash').then(
    ({ default: _ }) => {
      var element = document.createElement('div')
      element.innerHTML = _.join(['hello'.'world'].The '-')
      return element
    }
  )
}

document.addEventListener('click', () => {
  getComponent().then(element => {
    document.body.appendChild(element)
  })
})
Copy the code

With ES7 async and await, the above code can be written as follows with the same effect

// /src/index.js
async function getComponent() {
  const { default: _ } = await import(/* webpackChunkName: "lodash"* /'lodash')
  const element = document.createElement('div')
  element.innerHTML = _.join(['hello'.'world'].The '-')
  return element
}

document.addEventListener('click', () => {
  getComponent().then(element => {
    document.body.appendChild(element)
  })
})
Copy the code

Chunk

Each JS file generated after packaging is a chunk


Advanced concepts for Webpack – packaging analysis

Webpack packages analysis tools

GitHub repository address for webPack to package analysis tools

  1. Configuring packaging Commands
// /package.json
{
  "scripts": {
    "build": "webpack --profile --json > stats.json"}}Copy the code
  1. NPM run build # Run command
  • After packaging, a stats.json file is generated in the root directory, which contains information that describes the packaging process
  • To view detailed analysis, upload stats.json to the analysis package description file url

Appendix:

GUIDES/Code Splitting/Bundle Analysis GUIDES/Code Splitting/Bundle Analysis

  • Webpack-chart: Webpack Stats interactive pie chart.
  • Webpack-visualizer: Visualize and analyze your bundles to see which modules take up space and which are likely to be reused.
  • Webpack-bundle-analyzer: a plugin and CLI tool that presents bundle content as a convenient, interactive, scalable tree graph.
  • Webpack Bundle Optimize Helper: This tool analyzes your bundles and suggests actionable improvements to reduce bundle size.

Google chrome’s own coverage tool

  • F12 Open the Console of Google Browser, click the three points in the upper right corner, select More Tools/Coverage, click the first record button to start capturing the usage rate of code on the record page, refresh the page to view
  • Load the page to be executed code, if you let it download when the page is loaded, will waste page execution efficiency, using coverage can know which code to use this tool to, which is not used to, such as the following this code, click the interaction can be put into an asynchronous loading module, Thus improving the efficiency of page execution

Rewrite the front:

// /src/index.js
document.addEventListener('click', () => {
  var element = document.createElement('div')
  element.innerHTML = 'hello world'
  document.body.appendChild(element)
})
Copy the code

After the rewrite:

// /src/handleClick.js
function handleClick() {
  const element = document.createElement('div')
  element.innerHTML = 'hello world'
  document.body.appendChild(element)
}
export default handleClick

// /src/index.js
document.addEventListener('click', () => {
  import('./handleClick.js').then(({ default: func }) => {
    func()
  })
})
Copy the code
  • So the default for WebPack to do chunks is async, not all or INITIAL; Because WebPack believes that only asynchronously loading components like this can really improve web packaging performance, synchronous code can only add a cache, and the actual performance improvement is very limited
// /build/webpack.common.conf.js
module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'async'// Default (async) only split asynchronous code}}}Copy the code

Preloading & Prefetching

Official website address of Preloading modules

  • If all code is written to asynchronous components and you wait to load modules when an event is triggered, this will result in slow operation interaction, so you need to introduce the concepts of Preloading and Prefetching
  • Use it by writing magic notes
/* webpackPrefetch: true */
/* webpackPreload: true* /Copy the code
// /src/handleClick.js
function handleClick() {
  const element = document.createElement('div')
  element.innerHTML = 'hello world'
  document.body.appendChild(element)
}
export default handleClick

// /src/index.js
document.addEventListener('click', () => {
  import(/* webpackPrefetch: true* /'./handleClick.js').then(({ default: func }) => {
    func()
  })
})
Copy the code
  • Handleclick.js is loaded automatically when the main JS load is complete and the network bandwidth is free. When the click is triggered, handleclick.js will still be loaded, but it is retrieved from the cache
  • Difference: Downloading code for asynchronous component interaction when the home page (main JS) is loaded and the network is idle; Preloading is loaded with the main service file
  • Note: webpackPrefetch has some compatibility issues in some browsers

Advanced concepts of Webpack -CSS file code segmentation

  • MiniCssExtractPlugin official website address
  • The old version of MiniCssExtractPlugin does not support HMR, so it is best to use it only in the production environment. If you put it in the development environment, you need to manually refresh the page after changing the style, which will reduce the efficiency of development. The new release supports the use of HMR in development environments

Using the step

1. Install the module package

npm install –save-dev mini-css-extract-plugin

2. The configuration

// /build/webpack.common.conf.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = {
  plugins: [
    new MiniCssExtractPlugin({})
  ],
  module: {
    rules: [
      {
        test: / \. CSS $/, use: [MiniCssExtractPlugin loader, / / using the MiniCssExtractPlugin. Don't need to style - loader loader'css-loader'}]}}Copy the code

Note: This will need to be configured if TreeShaking is used (excluding unused code)

// /package.json
{
  "sideEffects": ["*.css"]}Copy the code

3. Package the output

// /package.json
{
  "scripts": {
    "build": "webpack --config ./build/webpack.prod.conf.js"}}Copy the code

npm run build

CSS packaging extension

The name of the package file

// /build/webpack.common.conf.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = {
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].css'// If the packed CSS is referenced directly by the page, the filename rule is named chunkFilename:'[name].chunk.css'// If the packaged CSS is referenced indirectly, it is named after the rule of chunkFilename})]}Copy the code

Package file compression

  1. NPM I -D optimize- CSS -assets-webpack-plugin
  2. Introduce and use
// /build/webpack.prod.conf.js
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
module.exports = {
  optimization: {
    minimizer: [new OptimizeCSSAssetsPlugin({})]
  }
}
Copy the code

Packaging of multiple CSS

  • An entry file introduces multiple CSS files, which are packaged into a single CSS by default
// /src/index.js
import './index1.css'
import './index2.css'
Copy the code
  • Multiple entry files import different CSS files. Packaging generates multiple CSS files by default. You can configure them to combine into one CSS file
// /build/webpack.prod.conf.js
module.exports = {
  optimization: {
    splitChunks: {
      cacheGroups: {
        styles: {
          name: 'styles', // The name of the packed filetest: /\.css$/, // Match all.css ending files and put them in this group to pack chunks:'all'// Whether the load is synchronous or asynchronous, all package to this group.true// Ignore default parameters (e.g. MinSize /maxSize/...) } } } } }Copy the code
  • Multiple entry files introduce packaging of multiple CSS files

Package the CSS files into different files based on the entry file


Advanced concepts of Webpack – browser caching

  • Hash: This is engineering level and changes the value of any file you modify
  • Chunkhash: it will perform dependency resolution according to different entry files (i.e., for the same entry file, the corresponding CSS changes, even if the corresponding JS does not change, its chunkhash value will change)
  • Contenthash: It is content-specific and its value remains unchanged as long as the source code remains unchanged
// /build/webpack.prod.conf.js
module.exports = {
  output: {
    filename: '[name].[contenthash].js',
    chunkFilename: '[name].[contenthash].js'}}Copy the code

Note:

With older versions of WebPack, even without any changes to the source code, it is possible to pack contenthash values differently between the two times. This is because there are associations between the generated files. These associations, called manifests, exist in individual files and can be extracted with additional configuration

// /build/webpack.common.conf.js
module.exports = {
  optimization: {
    runtimeChunk: {
      name: 'runtime'// The runtime.js file is used to store the associated code between files}}}Copy the code

The appendix

  • If the file is too large, Webpack will report a warning and you can configure it to ignore the warning
// /build/webpack.common.conf.js
module.exports = {
  performance: false
}
Copy the code

Advanced concept of Webpack -Shimming

Automatically import dependent libraries

  • Sometimes we introduce a library that may depend on other libraries
  • When we call the method from the imported library, XXX is not defined, even though the dependent library is loaded in the current JS
  • In this case, you need to use a plug-in that comes with WebPack, ProvidePlugin
  • What it does is :(toString, automatically importing the jquery module into the module, and then naming the jquery module from ‘jquery’
// /src/jquery.ui.js
export function ui() {$('body').css('background-color', _.join(['green'].' '))}Copy the code
// /src/index.js
import { ui } from './jquery.ui'
ui()
Copy the code
// /build/webpack.common.conf.js
const webpack = require('webpack')
module.exports = {
  plugins: [new webpack.ProvidePlugin({
    $: 'jquery', _ :'lodash',
    _join: ['lodash'.'join'] // If you want to use _join directly instead of lodash's join method, you can configure it as})]}Copy the code

Change the this pointer in the module

  • The “this” in a module refers to the module itself. If you want to change the “this” reference, you can use the imports- Loader module
  1. NPM I-D imports- Loader # Install the module package
  2. use
// /build/webpack.common.conf.js
module.exports = {
  module: {
    rules: [{
      test: /\.js$/,
      exclude: /node_modules/,
      use: [{
        loader: 'babel-loader'
      }, {
        loader: 'imports-loader? this=>window'}}}}]]Copy the code
  1. When loading a js file, it first goes to the import-loader, which changes this to window, and then passes it to babel-Loader for compilation

conclusion

These actions are called Shimming for changing the default behavior of webPack packaging, or implementing effects that webPack cannot implement in its original packaging.


Advanced concepts of Webpack – environment variables

Use of environment variables

// /build/webpack.prod.conf.js
const prodConfig = {
  // ...
}
module.exports = prodConfig
Copy the code
// /build/webpack.dev.conf.js
const devConfig = {
  // ...
}
module.exports = devConfig
Copy the code
// /build/webpack.common.conf.js
const merge = require('webpack-merge')
const devConfig = require('./webpack.dev.conf.js')
const prodConfig = require('./webpack.prod.conf.js')
const commonConfig = {
  // ...
}
module.exports = (env) => {
  if (env && env.production) {
    return merge(commonConfig, prodConfig)
  } else {
    return merge(commonConfig, devConfig)
  }
}
Copy the code
// package.json
{
  "scripts": {
    "dev": "webpack-dev-server --config ./build/webpack.common.conf.js"."build": "webpack --env.production --config ./build/webpack.common.conf.js"}}Copy the code
  • Add –env.production to the package command, which gives production true by default
  • You can also specify specific values, such as –env.production= ABC

21 Webpack -Library packing

  • Authoring Libraries website link

Sample code and configuration

// /src/index.js
export function add(a, b) {
  return a + b
}
export function minus(a, b) {
  return a - b
}
export function multiply(a, b) {
  return a * b
}
export function division(a, b) {
  return a / b
}
Copy the code
// /webpack.config.js
const path = require('path')
module.exports = {
  mode: 'production',
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'js-math.js',
    library: 'jsMath',
    libraryTarget: 'umd'}}Copy the code

Configuration details and usage examples

To configure the library: ‘jsMath’

  • Packaged JS supports script tag introduction
  • The generated code from the package is mounted to the global variable jsMath
// /dist/index.html
<script src="./js-math.js"></script>
<script>
  console.log(jsMath.add(2, 4)) // 6
</script>
Copy the code

Configuration libraryTarget: ‘umd’

  • U: stands for universally
  • The packaged code is available in ES2015/CommonJS/AMD environments
  • Script tag reference is not supported
// ES2015 module import:
import jsMath from 'js-math'
jsMath.add(2, 3)

// CommonJS module require:
const jsMath = require('js-math')
jsMath.add(2, 3)

// AMD module require:
require(['js-math'].function(jsMath) {
  jsMath.add(2, 3)
})
Copy the code

Some other values for libraryTarget

  • LibraryTarget values can also be used in conjunction with library values
libraryTarget: 'var'// Use libraryTarget as a global variable for library values:'this'// Mount library values to this object using libraryTarget:'window'// Mount the library value to the window object using libraryTarget:'umd'// enable it to be used in ES2015/CommonJS/AMDCopy the code

Introduce other libraries into custom libraries

  • Sometimes we introduce other libraries in our custom libraries, such as:
  • import _ from 'lodash'
  • If someone else is using our library at the same time they’re using LoDash
  • When the final package is packaged, two copies of LoDash are created in the code, resulting in duplicate code
  • Solution: Set externals
  • Externals website link
// /webpack.config.js
module.exports = {
  // externals: ['lodash'Externals: {// specify lodash: {root:'_'// indicates that if loDash is introduced via the script tag, a global variable named _ must be injected into the page in order to execute commonjs correctly:'lodash'// const lodash = require(const lodash = require('lodash')}}}Copy the code

Publishing libraries for others to use (not attempted)

  1. Configure the entrance
// /package.json
{
  "main": "./dist/js-math.js"
}
Copy the code
  1. Go to the NPM website to register an NPM account

  2. Run NPM adduser # to adduser information NPM publish # to upload the library to NPM

  3. NPM install js-math #


22 Webpack actual combat -PWA packaging

Introduction and use of PWA

  • PWA :(Progressive Web Application) pages can still be accessed even if the server is down
  1. NPM i-d workbox-webpack-plugin #

  2. Configuration:

// /build/webpack.prod.conf.js
const WorkboxPlugin = require('workbox-webpack-plugin')

module.exports = {
  plugins: [
    new WorkboxPlugin.GenerateSW({
      clientsClaim: true,
      skipWaiting: true}})]Copy the code
// /src/index.js
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker
      .register('/service-worker.js')
      .then(registration => {
        console.log('service-worker registed')
      })
      .catch(error => {
        console.log('service-worker register error')})})}Copy the code
  1. Precach-manifest.js and service-worker.js are added after the project is packed

  2. Start a service, access the packaged project, disconnect the service, refresh the browser, and the project is still accessible

The appendix

Start a local service

  1. NPM i-d HTTP-server #

  2. Configuration command to start a service in the dist directory

// /package.json
{
  "scripts": {
    "httpServer": "http-server dist"}}Copy the code
  1. NPM run httpServer # Run the following command to open a browser:http://127.0.0.1:8080/index.html Note: you must add /index.html after the access address, otherwise an error may occur

Webpack -TypeScript packaging

Introduce TypeScript

  • The TypeScript’s official website
  • TypeScript is a Microsoft product that regulates a set of JavaScript syntax
  • TypeScript is a superset of JavaScript that supports all of the syntax in JavaScript, but also provides some additional syntax
  • The biggest advantage of TypeScript is that it normalizes our code and makes it easy to report errors to our code
  • Writing iN TypeScript improves the maintainability of JavaScript code
  • The usual TypeScript file suffix is.ts or.tsx

Package TypeScript code with Webpack

  1. NPM I -d typescript TS-loader # Install module package

  2. Write code and configuration

// /src/index.tsx
class Greeter {
  greeting: string
  constructor(message: string) {
    this.greeting = message
  }
  greet() {
    return 'Hello, ' + this.greeting
  }
}

let greeter = new Greeter('world') / /letGreeter = new greeter (123) // If a string is not greeter, an error is reported. Greeter = new greeter (123)Copy the code
// /webpack.config.js
const path = require('path')

module.exports = {
  mode: 'production',
  entry: './src/index.tsx',
  module: {
    rules: [
      {
        test: /\.tsx? $/, use:'ts-loader',
        exclude: /node_modules/
      }
    ]
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'main.js'}}Copy the code
// /tsconfig.json
{
  "compilerOptions": {
    "outDir": "./dist"// When packing TypeScript code with ts-loader, place the generated TypeScript file in the./dist directory (not necessary, since webpack.config.js is already configured)."module": "es6", // refers to the ES Module reference (i.e., if you import other modules in the index.tsx file, you need to import... This way to introduce)"target": "es5"When TypeScript syntax is packaged, what form is the final syntax converted to"allowJs": true// Allow js modules in TypeScript syntax}}Copy the code
  1. NPM run build # Package code

Include other libraries in TypeScript (lodash as an example)

While there are nice error messages when writing TypeScript code, sometimes when you introduce other libraries into TypeScript code and call methods of other libraries without an error message, you need to perform the following steps:

  1. NPM I -d @types/lodash # Additional installation of the @types/lodash module package is required
  2. Import * as _ from ‘lodash’ instead of import _ from ‘lodash’

If you are not sure whether DefinitelyTyped files are supported by the corresponding library, you can search DefinitelyTyped on GitHub. When you open it, there is a link for TypeSearch. Go to the TypeSearch page and search. And then you can install it


24 Webpack actual combat – Request forwarding

  • Devserver. proxy official website link
  • Use WebpackDevServer to realize request forwarding in the development environment
  • To rely on WebpackDevServer, install the Webpack-dev-server module
// / SRC /index.js // use axios to simulate the request import axios from'axios'
axios.get('/api/data.json').then(res => {
  console.log(res)
})
Copy the code
// /webpack.config.js
module.exports = {
  devServer: {
    proxy: {
      // '/api': 'http://... '// Short, if the request begins with/API, proxy it to http://... For the request'/api': {
        target: 'http://... ', // If the requested address begins with/API, proxy it to http://... Make a request secure:false// If the request address is HTTPS, you need to configure pathRewrite: {// rewrite some request paths'data.json': 'data-test.json'
        },
        changeOrigin: trueHeaders: {// request headers: {// request headers: {// request headers:'www... ',
          cookie: '123... '
        }
      }
    }
  }
}
Copy the code

25 Webpack Real – Single page application routing

  • DevServer. HistoryApiFallback website links
// /src/home.js
import React, { Component } from 'react'

class Home extends Component {
  render() {
    return <div>HomePage</div>
  }
}

export default Home
Copy the code
// /src/list.js
import React, { Component } from 'react'

class List extends Component {
  render() {
    return <div>ListPage</div>
  }
}

export default List
Copy the code
// /src/index.js
import React, { Component } from 'react'Install the react library import {BrowserRouter, Route} from'react-router-dom'// Install the react-router-dom library import ReactDom from'react-dom'// Install the react-dom library import Home from'./home.js'
import List from './list.js'

class App extends Component {
  render() {
    return (
      <BrowserRouter>
        <div>
          <Route path="/" exact component={Home} />
          <Route path="/list" component={List} />
        </div>
      </BrowserRouter>
    )
  }
}

ReactDom.render(<App />, document.getElementById('root') // We need to write a container with id root in the HTMLCopy the code
// /webpack.config.js
module.exports = {
  devServer: {
    historyApiFallback: trueNote: this method is only applicable to the development environment, the online use requires the backend to do the route mapping processing}}Copy the code
  • Other configuration. See website link devServer historyApiFallback website links

26 WebPack Battle-ESLint configuration

  • ESLint official website link
  • ESLint Chinese language links

The use of ESLint

  1. NPM I -d esLint # Install module packages
  2. NPX esLint –init # Start esLint and make some choices based on the project situation to generate the esLint configuration file.eslintrc.js
//.eslintrc.js module.exports = {env: {// specifies the environment in which the code runs. Global variables vary from runtime to runtime, specifying the runtime so that ESLint can recognize specific global variables. It also enables browser syntax support for the corresponding environment:true,
    es6: true,
  },
  extends: [
    'plugin:vue/essential'.'airbnb-base',
  ],
  globals: {
    Atomics: 'readonly',
    SharedArrayBuffer: 'readonly',
  },
  parserOptions: {
    ecmaVersion: 2018,
    sourceType: 'module',
  },
  plugins: [
    'vue',], rules: {// Here rules can be defined in detail to override the rule in extends},};Copy the code
  1. Perform testing
  • NPX eslint./ SRC # Check whether all files in the./ SRC directory conform to the rule
  • NPX eslint. / SRC /index.js # Check whether a file conforms to the rule

other

  • During initialization, Airbnb, Standard, and Google standards can be selected only when “To Check syntax, find Problems, and Enforce code style” is selected
  • The esLint configuration file (.eslintrc.js) is best formatted in JavaScript, as json does not support code comments and is very weak when you need to handle different situations based on environment variables
  • Run NPX eslint… To check commands, add –fix (i.e. : NPX eslint –fix…) Some code style issues (such as semicolons after code) can be fixed automatically, but code errors will not be fixed
  • If you use VSCode, you can install the ESLint plug-in, which will automatically prompt error messages in your code

Configure ESLint in WebPack

  • Eslint-loader official website link
  • NPM I -d eslint-loader # Install module package
  • Configuration eslint – loader
// /webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: ['babel-loader', {
          loader: 'eslint-loader'// Use eslint-loader to check options before babel-loader processing: {fix:trueNPX eslint --fix... cache:true// ESLint can reduce the loss of packaging process performance // force:'pre'// Wherever eslint-loader is placed, force it to execute first}}]}]}, devServer: {overlay:true// With this configured, esLint checks for errors that will float in the browser when the project is opened}}Copy the code
  • Real projects typically don’t configure esLint-Loader in Webpack because it slows down packaging
  • ESLint checks are generally done on project submission and only if the test passes will the project be submitted

27 Webpack Combat – Performance optimization

Improve packing speed

1. Keep up with the technology of iterative (webpack/node/NPM/yarn /…).

  • Use the newer version of the tool whenever possible, because there are more optimizations in the newer version

2. Apply loader to as few modules as possible

  • You can configure exclude and include to reduce the use of loader
// /webpack.config.js
const path = require('path'Module.exports = {module: {rules: [{exclude: // / exclude: // // // include: path.resolve(__dirname,).'./src') // Specify the directory to apply the rule}]}}Copy the code

3. Plugins are as lean and reliable as possible

  • Try to use official recommended plug-ins, official optimization is better

4. Set resolve properly

// /webpack.config.js
module.exports = {
  resolve: {
    extensions: ['.js'.'.jsx'], // When we import a component without specifying a suffix (e.g. Import Child from)'./child/child'/child/child.jsx = /child/child.jsx = /child/child.jsx'index'.'child'], // When we import a folder path (e.g. Import Child from) after configuring this item'./child/'), it will automatically find the index in the folder first, if not, then child. The configuration is not too many. Otherwise, the performance may be affectedaliasChild: path.resolve(__dirname,'./src/child') // You can write: import Child from'child'}}}Copy the code

5. Use the DllPlugin to speed up packaging

  • DllPlugin official website link

5.1 Package library Files separately

  • Take LoDash and jquery as an example:
// /build/webpack.dll.js
const path = require('path')

module.exports = {
  mode: 'production',
  entry: {
    vendors: ['lodash'.'jquery']
  },
  output: {
    filename: '[name].dll.js',
    path: path.resolve(__dirname, '.. /dll'),
    library: '[name]'// Package to generate a library and expose the global variable [name](i.e., vendors)}}Copy the code
// /package.json
{
  "scripts": {
    "build:dll": "webpack --config ./build/webpack.dll.js"
  },
  "dependencies": {
    "jquery": "^ 3.4.1 track"."lodash": "^ 4.17.15"}}Copy the code
  • NPM run build: DLL # Run the package command and output the/DLL /vendors. Dl.js file
  • / DLL /vendors. DLL. Js is the new library file generated by packaging all the libraries, which contains the source code for LoDash and jquery

5.2 Use plug-ins to introduce new library files generated by separate packaging into production packaged code

  • NPM I -d add-asset-html-webpack-plugin # Install and configure the module package
// /webpack.config.js
const path = require('path')
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin')

module.exports = {
  plugins: [
    new AddAssetHtmlWebpackPlugin({
      filepath: path.resolve(__dirname, './dll/vendors.dll.js') // Refers to the content to be added to the index.html generated by HtmlWebpackPlugin})]}Copy the code
// /package.json
{
  "scripts": {
    "build": "webpack"}}Copy the code
  • NPM run build # Runs the package command, which copies vendor.dll. js to the /dist/ directory and introduces vendor.dll. js to the /dist/index.html file

At this point, the third party modules are only packaged once and introduced into production packaging. The goal in the production packaging code has been achieved, but import _ from ‘lodash’ in/SRC /index.js is still using the library in node_modules. When importing a third-party module, import it from a DLL file, not node_modules

5.3 Build mappings. When using modules, load them from DLL files

// /build/webpack.dll. Js // This configuration file generates a package similar to the library const path = require('path')
const webpack = require('webpack') module.exports = { plugins: [new webpack.dllplugin ({// Use webpack plugin to analyze the generated library file // Put some third-party module mapping relationship in the library file corresponding to path:'[name]'Path: path.resolve(__dirname,'.. /dll/[name].manifest.json') // The absolute path to the output of the analysis result file})]}Copy the code
  • / DLL /[name].dll. Js library file and/DLL /[name].manifest.json mapping file
  • With this mapping file, the source code is analyzed when the business code is packaged
  • If/DLL /[name].dll. Js is used, then/DLL /[name].dll. Js is used instead of importing modules into node_modules
  • The next step is to configure webpack by combining global variables with the generated/DLL /[name].manifest.json mapping file
// /webpack.config.js
module.exports = {
  plugins: [
    new webpack.DllReferencePlugin({
      manifest: path.resolve(__dirname, './dll/vendors.manifest.json')]}})Copy the code
  • NPM run build # Run the package command and the package time will be reduced

5.4 Packaging Generates multiple new library files

  • Configure multiple entry files
// /build/webpack.dll.js
module.exports = {
  entry: {
    vendors: ['lodash'.'jquery'],
    react: ['react'.'react-dom']}}Copy the code
  • Combining with the configuration of 5.3, the packaging output file: / DLL/vendors. DLL. Js/DLL/vendors. The manifest. The json/DLL/react. DLL. Js/DLL/react. The manifest. The json

  • Then configure /webpack.config.js

// /webpack.config.js
module.exports = {
  plugins: [
    new AddAssetHtmlWebpackPlugin({
      filepath: path.resolve(__dirname, './dll/vendors.dll.js')
    }),
    new webpack.DllReferencePlugin({
      manifest: path.resolve(__dirname, './dll/vendors.manifest.json')
    }),
    new AddAssetHtmlWebpackPlugin({
      filepath: path.resolve(__dirname, './dll/react.dll.js')
    }),
    new webpack.DllReferencePlugin({
      manifest: path.resolve(__dirname, './dll/react.manifest.json')]}})Copy the code
  • Finally, run the NPM run build package

Note: if there are a lot of packaging generated DLL file, you need to in/webpack config. Add a lot of js plugin, in order to simplify the code, can use the node to analyze DLL file folder, circulation processing, the code is as follows:

// /webpack.config.js
const fs = require('fs'Const plugins = [new HtmlWebpackPlugin({template:'./src/index.html'
  })
]

const files = fs.readdirSync(path.resolve(__dirname, './dll'))
files.forEach(file => {
  if (/.*\.dll.js/.test(file)) {
    plugins.push(new AddAssetHtmlWebpackPlugin({
      filepath: path.resolve(__dirname, './dll', file)
    }))
  }
  if (/.*\.manifest.json/.test(file)) {
    plugins.push(new webpack.DllReferencePlugin({
      manifest: path.resolve(__dirname, './dll', file)
    }))
  }
})

module.exports = {
  plugins
}
Copy the code
  • After the configuration is complete, run NPM run build: DLL again to generate the DLL file and mapping file
  • Finally, execute the NPM run build package again

6. Control the package file size

  • Do not introduce unused module packages
  • Configure tree-shaking to not package imported but unused modules when packaging
  • SplitChunks should be configured to split the code properly and separate large files into smaller ones

7. Thread -loader/parallel-webpack/happypack multi-process packaging

  • Webpack runs via nodeJs by default and is a single-process package
  • Multi-process packaging can be configured using techniques such as Thread-loader/parallel-webpack/happypack

8. Use sourceMap wisely

  • The more detailed the sourceMap generated by packaging, the slower the packaging, and you can configure different Sourcemaps for different environments

9. Analyze packaging results with STATS

  • According to the results of packaging analysis, do the corresponding optimization

10. In-memory compilation in the development environment

  • The development environment uses Webpack-dev-server. After starting the service, the compiled files will be put into the memory, and the reading speed of the memory is much faster than that of the hard disk, which can greatly improve the performance of Webpack in the development environment

11. Remove useless plug-ins from the development environment

  • For example, the development environment does not need to compress the code

28 WebPack Actual combat – Multi-page packaging configuration

  • HTML – webpack – plugin making address

Multi-page packaging configuration

  1. Create js for multiple pages
// /src/index.js
console.log('home page')

// /src/list.js
console.log('list page')
Copy the code
  1. Configuration webpack
/ / / build/webpack.com mon. Conf. Js module. Exports = {entry: {/ / configure multiple the main entrance to the file:'./src/index.js',
    list: './src/list.js'}, plugins: new HtmlWebpackPlugin({template:'src/index.html',
      filename: 'index.html',
      chunks: ['runtime'.'vendors'.'main'] // Different pages import different entry files (vendors, if there are runtime or vendors, then don't)}), new HtmlWebpackPlugin({template:'src/index.html',
      filename: 'list.html',
      chunks: ['runtime'.'vendors'.'list']]}})Copy the code
  1. NPM run build # will import main.js in index.html and list.js in list.html

As mentioned above, if you manually add code every time you add a page, this will result in a lot of duplicate code. Let’s start optimizing the packaged configuration code:

Optimize the multi-page packaging configuration code

// /build/webpack.common.conf.js
const fs = require('fs') const makePlugins = configs => {// Custom makePlugins are used to dynamically generate plugins const plugins = [// We can initially save some basic plugins such as: CleanWebpackPlugin] // Depending on the entry file, Generating different HTML // object.keys () methods returns an array of enumerated properties for the given Object object.keys (configs.entry).foreach (item => {plugins.push(new) HtmlWebpackPlugin({ template:'src/index.html',
      filename: `${item}.html ', chunks: [item]}))}) // Dynamically add and use some third-party DLL libraries generated by the package const files = fs.readdirsync (path.resolve(__dirname,'.. /dll'))
  files.forEach(file => {
    if (/.*\.dll.js/.test(file)) {
      plugins.push(new AddAssetHtmlWebpackPlugin({
        filepath: path.resolve(__dirname, '.. /dll', file)
      }))
    }
    if (/.*\.manifest.json/.test(file)) {
      plugins.push(new webpack.DllReferencePlugin({
        manifest: path.resolve(__dirname, '.. /dll', file)
      }))
    }
  })

  returnPlugins} const configs = {// Put a bunch of exported configurations from module.exports into the configs variable entry: {index:'./src/index.js',
    list: './src/list.js'} / /... } configs.plugins = makePlugins(configs) {makePlugins = makePlugins(configs) Exports = configs. Plugins module.exports = configsCopy the code
  • If you need to add pages, just configure an entry file

29 Basic principle of WebPack – Programming Loader

  • Loader is essentially a function that takes an argument that refers to the source code imported into the file
  • Note: this function cannot be written as an arrow function, because this is used. Webpack will make some changes to this when calling loader, after which the methods in this can be used. If this function is written as an arrow function, there will be a problem with this pointing

How to write a Loader

// /src/index.js
console.log('hello world ! ')
Copy the code
// /loaders/replaceLoader.js
module.exports = function(source) {
  return source.replace('hello'.'hello'// Perform a substitution on the source code}Copy the code
// /package.json
{
  "scripts": {
    "build": "webpack"
  },
  "devDependencies": {
    "webpack": "^ 4.29.0"."webpack-cli": "^ 3.2.1." "}}Copy the code
// /webpack.config.js
const path = require('path')

module.exports = {
  mode: 'development',
  entry: {
    main: './src/index.js'
  },
  module: {
    rules: [{
      test: /\.js$/,
      use: [
        path.resolve(__dirname, './loaders/replaceLoader.js')
      ]
    }]
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].js'}}Copy the code
  • NPM run build # package the output, run the output file to see the printed ‘hello’ is replaced by ‘hello’, this is a simple loader

In/loaders/replaceLoader js, besides back to after processing by the return of the source code, you can also use this. The callback do return processing

  • This. Callback website link
  • This.callback () is similar to return, but can pass multiple arguments
// /loaders/replaceLoader.js
module.exports = {
  const result = source.replace('hello'.'hello')
  this.callback(null, result)
}
Copy the code

Loader configures parameter transmission

  • This. Query website link
// /loaders/replaceLoader.js
module.exports = function(sourceConsole. log(this.query) {name: console.log(this.query) {name: console.log(this.query)'xiaoli' }
  return source.replace('hello'.'hello')}Copy the code
// /webpack.config.js
const path = require('path')

module.exports = {
  module: {
    rules: [{
      test: /\.js$/,
      use: [{
        loader: path.resolve(__dirname, './loaders/replaceLoader.js'),
        options: {
          name: 'xiaoli'}}]}}Copy the code
  • It is recommended that the loader-utils module be used to analyze the passed content because the parameters can sometimes be weird (for example, an object may be passed and a string may be received)

Analyze loader configuration using loader-utils

  • NPM I -d loader-utils # Install the module package
  • Use:
// /loaders/replaceLoader.js
const loaderUtils = require('loader-utils')

module.exports = {
  const options = loaderUtils.getOptions(this)
  console.log(options) // { name: 'xiaoli'}}Copy the code

Asynchronous operations are performed in loader

If the loader calls an asynchronous operation (such as a delayed return), the package will report an error saying that the loader is not returning the content, so use this.async().

// /loaders/replaceLoaderAsync.js
module.exports = function(source) {
  const callback = this.async()
  setTimeout(() => {
    const result = source.replace('hello'.'hello') callback(null, result) // This.callback()}, 1000)}Copy the code

Use of multiple loaders

// /loaders/replaceLoaderAsync.js
module.exports = function(source) {
  const callback = this.async()
  setTimeout(() => {
    const result = source.replace('hello'.'hello')
    callback(null, result)
  }, 1000)
}
Copy the code
// /loaders/replaceLoader.js
module.exports = function(source) {
  const result = source.replace('world'.'the world')
  this.callback(null, result)
}
Copy the code
// /webpack.config.js
module.exports = {
  module: {
    rules: [{
      test: /\.js$/,
      use: [{
        loader: path.resolve(__dirname, './loaders/replaceLoader.js')
      }, {
        loader: path.resolve(__dirname, './loaders/replaceLoaderAsync.js'}]}]}}Copy the code

Simplify the introduction of loaders

// /webpack.config.js module.exports = { resolveLoader: {// When you import a loader, it looks for modules in node_modules. If it can't find one, it goes to loaders to look for modules: ['node_modules'.'./loaders']
  },
  module: {
    rules: [{
      test: /\.js$/,
      use: [{
        loader: 'replaceLoader'
      }, {
        loader: 'replaceLoaderAsync'}}}}]]Copy the code

30 Webpack basic principle – write Plugin

The difference between loader and plugin:

  • The loader is used to process the module, when we import a new JS file (or other format file) in the source code, we can use the Loader to process the referenced file
  • The htML-webpack-plugin is used to do some processing at specific moments when we are packaging (for example, an HTML file is automatically generated at the end of packaging)
  • Loader is a function
  • Plugin is a class

A simple plugin to write and use

// /plugins/ copyright-webpackplugin. Js class CopyrightWebpackPlugin {// constructorconstructor() {
    console.log('Plugin used'} // When the plug-in is called, the apply method is executed, which accepts a parameter compiler, Apply (Compiler) {}} module.exports = CopyrightWebpackPluginCopy the code
// /src/index.js
console.log('hello world ! ')
Copy the code
// /package.json
{
  "name": "plugin"."version": "1.0.0"."description": ""."main": "index.js"."scripts": {
    "build": "webpack"
  },
  "keywords": []."author": ""."license": "ISC"."devDependencies": {
    "webpack": "^ 4.41.2"."webpack-cli": "^ 3.3.10"}}Copy the code
// /webpack.config.js
const path = require('path')
const CopyrightWebpackPlugin = require('./plugins/copyright-webpack-plugin.js')

module.exports = {
  mode: 'development',
  entry: {
    main: './src/index.js'
  },
  plugins: [new CopyrightWebpackPlugin()],
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].js'}}Copy the code
  • NPM run build # Run the package command and you can see the output of “plug-in used” on the command line

The plugin and transfer

// /webpack.config.js
const CopyrightWebpackPlugin = require('./plugins/copyright-webpack-plugin.js')

module.exports = {
  plugins: [new CopyrightWebpackPlugin({
    name: 'li'})]}Copy the code
// /plugins/copyright-webpack-plugin.js class CopyrightWebpackPlugin {constructor(options) {// Receive arguments via options console.log(options) } apply(compiler) {} } module.exports = CopyrightWebpackPluginCopy the code

Generate additional files at the end of the package

  • Compiler Hooks
  • Compiler. hooks have something like vUE lifecycle functions in them (which are hook functions that automatically execute at certain times)
// /plugins/ CopyrightWebpackPlugin {apply(compiler) {// emit is the time when you put packaged resources into the target folder compiler.hooks.emit.tapAsync('CopyrightWebpackPlugin', (compilation, callback) => {
      console.log('Plug-in executed')
      callback()
    })
  }
}

module.exports = CopyrightWebpackPlugin
Copy the code
  • At this point, it is possible to run the code at the specified time of packaging
  • Next, at the specified time, add files to the package contents
// /plugins/copyright-webpack-plugin.js
class CopyrightWebpackPlugin {
  apply(compiler) {
    compiler.hooks.emit.tapAsync('CopyrightWebpackPlugin', (compilation, callback) => {// All generated content is stored in compilation.assets // At emit time, Add a copyright. TXT file to the compilation. Assets ['copyright.txt'] = {// The contents of the filesource: function() {
          return 'copyright text ... '}, // File size size:function() {
          return 18
        }
      }
      callback()
    })
  }
}
Copy the code

Debug with Node

  • –inspect # enable the node debugging tool
  • –inspect-brk # break a breakpoint on the first line of webpack.js
  • Run directly node node_modules/webpack/bin/webpack webpack js is equivalent to run
// /package.json
{
  "scripts": {
    "debug": "node --inspect --inspect-brk node_modules/webpack/bin/webpack.js"}}Copy the code
  • After running NPM run Debug, open the browser console and click the green icon in the upper left corner to start node debugging

The appendix

Other packing moments

  • Done (asynchronous time) indicates that the packaging is complete

  • Compile (synchronization time)

  • The synchronization time is TAP and has no callback

  • Asynchronous time is tapAsync with callback

compiler.hooks.compile.tap('CopyrightWebpackPlugin', (compilation) => {
  console.log('Compile is always executed')})Copy the code

31 Webpack base principle -Bundler source code preparation – module analysis

1. Read the entry file of the project

2. Analyze the code in the entry file

// /src/word.js
export const word = 'hello'
Copy the code
// /src/message.js
import { word } from './word.js'// we need to write the.js suffix because we don't use webpack const message = 'say${word}`

export default message
Copy the code
// /src/index.js
import message from './message.js'

console.log(message)
Copy the code
  • BabelParser website link

NPM i@babel /parser # Parses code to generate abstract syntax trees

  • Link to babelTraverse

NPM I @ Babel /traverse # helps us find import nodes quickly

// // bundler.js // this file is the packaging tool // nodeJs // a module used to read files const fs = require('fs')
const path = require('path'Const parser = require(const parser = require(const parser = require('@babel/parser'// The default export is the ESModule export, if you want to useexportDefault const traverse = require(const traverse = require('@babel/traverse'). Default const moduleAnalyser = filename => {// Read the entry file with UTF-8 encoding const Content = fs.readfilesync (filename,'utf-8'// console.log(content) // Parser. parse(content, {parser.parse) // console.log(content) // Parser.parse (content, {parser.parse)sourceType: 'module'// console.log(ast.program.body) const dependencies = {} To find the Node type = = ='ImportDeclaration'The elements, And do the traverse(AST, { ImportDeclaration({ node }) { // console.log(node) const dirname = path.dirname(filename) const newFile ='/'+ path.join(dirname, Node.source. value) dependencies[node.source.value] = newFile}}) // console.log(dependenciesreturn}} // call moduleAnalyser('./src/index.js')
Copy the code
  • Babel-core website link
  • Babel-preset -env official website link
  • After analyzing the code, you also need to turn the ES6 code into code that the browser can run
  • NPM I @babel/core
  • NPM I @babel/preset-env # Install @babel/preset-env
  • The transformFromAst() method in babelCore converts the AST abstract syntax tree into code that the browser can run
// /bundler.js
const babel = require('@babel/core')

const moduleAnalyser = filename => {
  const { code } = babel.transformFromAst(ast, null, {
    presets: ["@babel/preset-env"}) // code is the code that the browser can runreturn{code}} const moduleInfo = moduleAnalyser('./src/index.js')
console.log(moduleInfo)
Copy the code

The appendix

  • Highlight code on the command line

NPM I cli – highlight – g / / cli installation – highlight the node bundler. Js | highlight / / runtime behind plus | highlight


32 Webpack -Bundler source code -DependenciesGraph

  • Build on the code in the previous section
// /bundler.js
const fs = require('fs')
const path = require('path')
const parser = require('@babel/parser')
const traverse = require('@babel/traverse').default
const babel = require('@babel/core')

const moduleAnalyser = filename => {
  const content = fs.readFileSync(filename, 'utf-8')
  const ast = parser.parse(content, {
    sourceType: 'module'
  })

  const dependencies = {}
  traverse(ast, {
    ImportDeclaration({ node }) {
      const dirname = path.dirname(filename)
      const newFile = '/' + path.join(dirname, node.source.value)
      dependencies[node.source.value] = newFile
    }
  })

  const { code } = babel.transformFromAst(ast, null, {
    presets: ["@babel/preset-env"]})return{ filename, dependencies, code } } const makeDependenciesGraph = entry => { const entryModule = moduleAnalyser(entry) const graphArray = [ EntryModule] // Loops through dependencies within dependenciesfor(let i = 0; i < graphArray.length; i++) {
    const item = graphArray[i]
    const { dependencies } = item
    if (dependencies) {
      for(let j inDependencies) {grapharray. push(moduleAnalyser(dependencies[j]))}}} graphArray.forEach(item => { graph[item.filename] = { dependencies: item.dependencies, code: item.code } })returnConst graphInfo = makeDependenciesGraph()'./src/index.js')
console.log(graphInfo)
Copy the code
  • Move on to the next section, generating code

33 Webpack base principle -Bundler source code – generated code

  • Build on the code in the previous section
// /bundler.js
const fs = require('fs')
const path = require('path')
const parser = require('@babel/parser')
const traverse = require('@babel/traverse').default
const babel = require('@babel/core')

const moduleAnalyser = filename => {
  const content = fs.readFileSync(filename, 'utf-8')
  const ast = parser.parse(content, {
    sourceType: 'module'
  })

  const dependencies = {}
  traverse(ast, {
    ImportDeclaration({ node }) {
      const dirname = path.dirname(filename)
      const newFile = '/' + path.join(dirname, node.source.value)
      dependencies[node.source.value] = newFile
    }
  })

  const { code } = babel.transformFromAst(ast, null, {
    presets: ["@babel/preset-env"]})return {
    filename,
    dependencies,
    code
  }
}

const makeDependenciesGraph = entry => {
  const entryModule = moduleAnalyser(entry)
  const graphArray = [ entryModule ]

  for(let i = 0; i < graphArray.length; i++) {
    const item = graphArray[i]
    const { dependencies } = item
    if (dependencies) {
      for(let j in dependencies) {
        graphArray.push(
          moduleAnalyser(dependencies[j])
        )
      }
    }
  }

  const graph = {}
  graphArray.forEach(item => {
    graph[item.filename] = {
      dependencies: item.dependencies,
      code: item.code
    }
  })
  return graph
}

const generateCode = entry => {
  const graph = JSON.stringify(makeDependenciesGraph(entry))
  return `
    (function(graph) {
      function require(module) {
        function localRequire(relativePath) {
          return require(graph[module].dependencies[relativePath])
        }
        var exports = {}
        (function(require, exports, code) {
          eval(code)
        })(localRequire, exports, graph[module].code)
        return exports
      }
      require('${entry}')
    })(${graph})
  `
}

const code = generateCode('./src/index.js')
console.log(code)
Copy the code
  • Node bundler runs the following code in a browser:
  • Uncaught SyntaxError: Uncaught SyntaxError: Uncaught SyntaxError: Uncaught SyntaxError: Invalid or unexpected token
(function(graph) {
  function require(module) {
    function localRequire(relativePath) {
      return require(graph[module].dependencies[relativePath]);
    };
    var exports = {};
    (function(require, exports, code) {
      eval(code); }) (localRequire, exports, graph[module].code);
    return exports;
  };
  require('./src/index.js'); ({})"./src/index.js": {"dependencies": {"message.js":"./src\\message.js"},"code":"\"use strict\"; \n\nvar _message = _interopRequireDefault(require(\"message.js\")); \n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { \"default\": obj }; }\n\nconsole.log(_message[\"default\"]);"},"./src\\message.js": {"dependencies": {"./word.js":"./src\\word.js"},"code":"\"use strict\"; \n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n}); \nexports[\"default\"] = void 0; \n\nvar _word = require(\"./word.js\"); \n\nvar message = \"say \".concat(_word.word); \nvar _default = message; \nexports[\"default\"] = _default;"},"./src\\word.js": {"dependencies": {},"code":"\"use strict\"; \n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n}); \nexports.word = void 0; \nvar word = 'hello'; \nexports.word = word;"}});
Copy the code
  • Run output: “Say hello”

Scaffolding tool configuration analysis – Createreact & Vuecli 3

CreateReactApp

  • Create-React-app
  • NPX create-react-app my-app # create project
  • CD my-app # Go to the project folder
  • NPM start # Start the project
  • NPM run eject # shows some configuration hidden by React.

VueCLI3

  • VueCLI3 website link
  • NPM i-g@vue /cli # Install VueCLI
  • Vue create my-project # create project
  • CD my-project # go to the project folder
  • NPM Run Serve # launch project
  • /vue.config.js # Create vue.config.js in the root directory and write the webpack configuration according to the official website documentation

This work is originalUse the signature – Non-commercial – No Deductive 4.0 International license agreement