Chapter 2 module packaging

2.3 commonJs and ES6 Module differences

  • Commonjs, loaded during code execution; The ES6 Module loads during code compilation

    • You can use if to determine if a commonJs is loaded
    • Es6 Module imports and exports are declarative and must be in the top scope of the module, not in an IF statement
  • Comonjs imports an object, while ES6 Module supports importing variables directly, reducing the reference level and making the program more efficient

// commonjs
module.exports = {
  name: 'a'
}
// es6 module
export name = 'a'
Copy the code
  • Commonjs imports a value copy of the exported value, whereas ES6 Modlue is a dynamic map of the exported value and the map is read-only

In the following code, count cannot be reassigned

import {count, add} from './calculator.js'

console.log(count, 1)

add(1.2)

console.log(count, 2)

// Cannot use import statement outside a module
// count = 3;

console.log(count, 3)
Copy the code

How do I handle circular dependencies

  1. commonJs

A depends on B, B depends on C, and C depends on B

// foo.js
const bar = require('./bar.js');
console.log('value of bar:', bar);
module.exports = 'foo.js'

// bar.js
const foo = require('./foo.js');
console.log('value of foo:', foo);
module.exports = 'bar.js'

// index.js
require('./foo.js')

// Output result:
value of foo: {}
value of bar: bar.js
Copy the code
  • Explanation:
  1. Index.js imports foo.js and starts executing foo.js
  2. The first sentence of foo.js introduces bar.js, at which point foo.js stops executing and starts executing bar.js
  3. A reference to foo.js is made in bar.js, where the loop is generated. Instead of jumping back to foo.js for execution, it takes its exported value directly. And because foo.js has not been executed to export line 13, the export value is the default {}.
  • From webpack’s perspective:
function __webpack_require__(moduleId) {
  if(installedModules[moduleId]) {
    return installedModules[moduleId].exports
  }else {
    var module = installedModules[moduleId] = {
      id: moduleId,
      loaded: false.exports: {}}... }}Copy the code

When index.js references foo.js, it executes webpack_require and initializes a module object installedModules[‘ foo.moduleid ‘], whose exports={}, InstalledModules [‘ foo.moduleid ‘] exists, and its exports are {}

  1. es6 module

Similarly, in ES6Module, you can’t get the correct export value of foo.js, except that es6Module exports undefined instead of the empty {} object. However, because es6Module import is a reference, it can better support circular dependencies, but the developer needs to ensure that. (For solutions to dependency conflicts, please refer to the original book P32)

2.4 Loading Other Modules

2.4.1 Modular Files

A file in a script tag

<script src="./jquery.js"></script>
Copy the code

How to introduce jquery and other modular files into Webpack, directly

import './jquery.js'
Copy the code

This code executes jquery.js directly

2.4.4 Loading the NPM Module

  • Each NPM module has an entry file, which is maintained in the main field of package.json within the module.

  • In addition to loading the module directly, you can also load a js file inside the NPM package as <package_name>/, for example:

Import all from ‘lodash/fp/all.js’ so that webPack ends up packing node_module/lodash/fp/all.js instead of the entire Lodash library.

2.5 Module Packaging Principle

  1. Webpack initializes, defining things like the webPack_require function and installedModules object
  2. Loading entry module
  3. Exports: executes module code and exports to module.exports; When the require function is encountered, surrender execution and go to Webpack_require to load other modules
  4. In webpack_require, check whether the current module exists in installedModules. If so, return directly. If not, enter 3
  5. After all modules are loaded, go back to the entry module and continue to the end.

Chapter 3 Resource input and output

  • Module, Chunk, and bundle

    • Module, a code module developed and written by a coder
    • Chunk: Chunks of webpack packaging, usually one chunk for each module
    • Bundle: a bundle is a file that has been packaged. Usually, one chunk is a bundle. However, if the loader\plugin is used to split the code, a chunk may correspond to multiple bundles. For example, an index entry file will be split into an index. CSS file.
  • Fielname, chunkfilename

    • Filename: indicates the name of the entry file

    • Chunkfilename, filename that is not in the entry but is packaged out

  • publicpath

Chapter 4 Preprocessor Loader

  • Configure the format in Webpack
module.exports = { ... .module: {
    rules: [{test: /.css/,
        use: ['style-loader'.'css-loader'] // Loader is used from back to front}}}]Copy the code
  • Commonly used loader

    • bable-loader
    • Url-loader, processing images

Chapter 5 style processing

  • Css-loader: identifies CSS files
  • Style-loader: adds the packed CSS content to the header’s style tag
  • postcss-loader\less-loader\sass-loader
  • stylelint
  • css moduels

Options of CSS-loader: enable module:true.

Chapter 6 code sharding

6.3 optimization. SplitChunks

module.exports = { ... .optimization: {... .splitChunks: {
        // chunks default to 'async' and only split asynchronous modules. Modules loaded as import('lodash')
        // all Splits all synchronous and asynchronous modules.
        chunks: 'all'.name: false.By default, there are two rules, vendors and default
        // vendors extract all eligible modules from node_modules
        // default extracts modules that are referenced multiple times
        cacheGroups: {
          react: {
            test: /react/,
            name: 'react'.priority: 20,},},},}}Copy the code

Chapter 7 Production Environment Configuration

7.2 Enabling the Production Mode

The Webpack configuration mode is production, which automatically adds many configuration items suitable for production environment, reducing manual work. Such as:

  • Code that marks Treeshaking as dead is removed
  • Code sharding is enabled by default
  • Automatically set process.env.node_env
  • Automatically turn on code compression

7.3 Environment Variables

Custom environment variables can be set through DefinePlugin and are typically used for publicPath packaging address differentiation.

7.4 the source – the map

7.4.3 security

Make sure you use source-map readability to track bugs once you go live, but also make sure you don’t let anyone see through your code. Source-map provides three solutions:

  • hidden-source-map

Webpack also generates the complete map file, but does not add a reference to the map file in the bundle. You can upload the map file to Sentry to see the problem.

  • nosources-source-map

The generated environment code still has a map, but does not expose the code content. For errors, you can still view the error stack of the source code from the console. It’s basically enough to catch automatic errors.

  • Open whitelist for. Map files

Only. Map files can be viewed on the Intranet, but not on the Internet.

7.5 Resource Compression

7.5.1 compression js

Webpack4 recommends terser-webpack-plugin instead of Uglifyjs.

module.exports = { ... .optimization: {
    minimize: true.minimizer: [
      // This is only used in production mode
      new TerserPlugin({
        terserOptions: {
          parallel: true // The default value is false}}]}}Copy the code

7.5.2 compress CSS

Extract the styles to the CSS file using mini-CSS-extract-plugin, and then compress them using optimization-CSs-assets-webpack-plugin.

7.6 the cache

7.6.1 resources hash

See the difference between Contenthash and Chunkhash in Webpack

7.6.2 Output dynamic HTML

The HTML-webpack-plugin can automatically map the hash names of static resources such as JS and CSS to the corresponding positions of HTML files after packaging.

7.7 Bundle Volume Monitoring and Analysis

  • Vscode plug-in Import Cost

  • Webpack – bundle – analyzer plug-in

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; module.exports = { ... , plugin: [ ..., new BundleAnalyzerPlugin(), ] }Copy the code
{... , "scripts": { ... , "build": "node scripts/build.js", "analyz": "NODE_ENV=production npm_config_report=true yarn build", } }Copy the code
  • Unused -webpack-plugin (unused)
const UnusedWebpackPlugin = require('unused-webpack-plugin'); module.exports = { ... , plugin: [ ..., new UnusedWebpackPlugin({ directories: [path.join(__dirname, 'src')], root: __dirname }) ] }Copy the code

Webpack speed analysis

  • Install the speed-measure-webpack-plugin

npm install --save-dev speed-measure-webpack-plugin

  • Importing plug-ins, creating plug-in objects
const SpeedMeasurePlugin = require('speed-measure-webpack-plugin') // Import plug-ins
const smp = new SpeedMeasurePlugin() // Create a plug-in object
Copy the code
  • Use the plug-in’s wrap() method to wrap the configuration
module.exports = smp.wrap({
  entry: {
    index: './src/index.js'.search: './src/search.js',},output: {
    path: path.join(__dirname, 'dist'), //__dirname(directory name of the current module) + dist
    filename: '[name]_[chunkhash:8].js'.// Add file fingerprint chunkhash to output file name after packaging
  },
plugpins: [],... });Copy the code

Chapter 8 packaging optimization

Packaging optimization has two directions:

  1. Packing speed
  2. Packaging volume

Packing speed:

8.1 Happypack (not recommended)

8.2 Narrowing the packaging scope

Packing volume:

8.3 Dynamic link Library and DllPlugin

DllPlugin and splitChunks are similar in that they are used to extract common modules. But there are essential differences:

  • SplitChunks, which extract modules according to certain rules during packaging
  • Dllplugin completely separates vendor and has a separate webpack.vendor.config.js for configuration. This part of code is completely ignored during actual construction.

In summary, both extract common modules (such as code in node_module) as a result of packaging, but dllPlugin is faster than splitchunks in terms of build speed.

Use one or the other, not both. (Splitchunks is recommended)

8.4 the tree – shaking

  • Tree-shaking relies on es6 Module compile-phase analysis and can flag dead code.

  • Tree-shaking is only valid for es6 Modules. Sometimes tree-shaking does not work for dependent NPM packages, perhaps because the library is exported in the CommonJS way. Although we reference import, inside the NPM package, in the packaged code, we use require.

  • Tree-shaking, just marking dead code, really removing dead code is done with compression tools such as Terser-webpack-plugin or UglifyPlugin. In webpack4, setting mode to production can achieve the same effect.

runtimeChunk

The Runtime consists of two parts:

  1. The running environment of Webpack (specific function is module parsing, loading), such as webpack_require in the packaged code, this part of the code is basically unchanged.

  2. A list containing the Chunks mapping.

It is extracted from app.js separately to avoid changes in mapping relationships and affect changes in the contents of main.js files. Since the ID of each chunk is basically hash based on content, every change will affect it. If it is not extracted, app.js will change every time. The cache is invalidated. Once runtimeChunk is set, WebPack will generate runtimeChunk files. Then every time you change the so-called runtime code file, the hash value of app.js at build time does not change. If the hash value of app.js is changed every time the project is updated, then the client browser needs to reload the changed app.js every time. If the project optimization subcontracting is not done well, the first loading will be time-consuming, resulting in poor user experience. Now that runtimeChunk is set, the problem is solved. The goal is to avoid invalidation of the browser cache due to frequent file changes, so it’s a better use of the cache. Improve user experience.

module.exports = {
  / /...
  optimization: {
    runtimeChunk: {
      name: (entrypoint) = > `runtime~${entrypoint.name}`,,}}}Copy the code

Chapter 9 development environment tuning

9.2 Module Hot Update

9.2.2 principle

A webpack-dev-server (WDS) service is installed locally, and the packaged code is stored directly in memory. The browser and node service communicate via websocket.

When the code is updated, WDS pushes the update event to the browser, along with the hash built this time, allowing the browser to compare with the last resource. The browser will request WDS to obtain the list of updated files after comparing the hash and knowing that the source code has been updated. The request name is [hash].hot-update.json.