Narrow the file search

1 include & exclude

1) action

  • Limit compilation range

2) useage

module: {
        rules: [
            {
                test: /\.js$/,
                use: ['babel-loader? cacheDirectory'],
                include: path.resolve(__dirname, 'src'),
                exclude: /node_modules/
            }
        ]
    }
Copy the code

‘babel-loader? cacheDirectory’

You can also speed up babel-loader by as much as 2x by using the cacheDirectory option. This will cache transformations to the filesystem.

QA

The command line warning

[BABEL] Note: The code generator has deoptimised the styling of “/Users/xxx/Documents/xxx/webpack_test/test3/node_modules/lodash/lodash.js” as it exceeds the max of “500KB”.

If you exclude the range, no error will be reported

2 resolve.modules

1) action

  • Tell webpack what directories should be searched when resolving modules.

2) useage

resolve: {
    modules: [path.resolve('node_modules'), path.resolve('lib')]}Copy the code

3) note

  • Absolute and relative paths can both be used, but be aware that they will behave a bit differently.

  • A relative path will be scanned similarly to how Node scans for node_modules, by looking through the current directory as well as it’s ancestors (i.e. ./node_modules, .. /node_modules, and on).

  • With an absolute path, it will only search in the given directory.

  • If you want to add a directory to search in that takes precedence over node_modules/:

modules: [path.resolve(__dirname, "src"), "node_modules"]
Copy the code

4) QA

Module not found: Error: Can’t resolve ‘ajax’ in ‘/Users/xxx/Documents/xxx/webpack_test/test3/src’

You can add properties to the array when you need to specify a module directory other than node_modules

3 resolve.mainFields

1) action

  • The resolveto. MainFields in the Webpack configuration is used to configure which entry file to use for the third-party module.

Json file that describes the properties of the module. There are fields that describe where the entry file is located. Resolve-.mainfields configurates which field to use as the description of the entry file.

The reason there can be multiple field description entry files is because some modules can be used in multiple environments at the same time, requiring different code for different runtime environments. Take the Isomorphic-FETCH API, which is an implementation of Promise but can be used in both browsers and node.js environments.

2) useage

In order to reduce the search step, you can set it as few as possible while specifying the entry file description fields for third-party modules. Since most third-party modules use the main field to describe the location of the entry file, you can configure Webpack like this:

Module. exports = {resolve: {mainFields: [module.exports = {resolve: {mainFields: ['main'],}};Copy the code

4 resolve.alias

1) action

  • Configuration items use aliases to map the original import path to a new import path
  • This optimization affects the use of tree-shaking to remove invalid code

2) useage

alias: {
    "bootstrap": "bootstrap/dist/css/bootstrap.css"
}
Copy the code

5 resolve.extensions

1) action

  • When the import statement does not have a file suffix, Webpack will automatically try to ask if the file exists after the suffix
  • The default extension is Extensions: [‘.js’, ‘.json’]

2) useage

3) note

  • The list of suffixes is as small as possible
  • The highest frequency goes forward
  • Use suffixes whenever possible in export statements

6 module.noParse

1) action

  • The module.noParse configuration allows Webpack to ignore recursive parsing of files that are not modular

2) useage

module: {
    noParse: [/react\.min\.js/]
}
Copy the code

2) note

Omitted files should not contain modular statements such as import, require, define, etc

2 DLL

1 action

DLL files are called dynamic link libraries. In a dynamic link library, functions and data can be called to other modules

  • Package the base module into a separate dynamically linked library
  • When the module to be imported is in the dynamically connected library, the module cannot be repackaged and is retrieved from the dynamically connected library

2 usage

Define plugin –> Reference plugin (DllReferencePlugin)

This example uses jquery as an example

1) define the DLL

  • Used to package out a dynamic link library
  • It needs to be built separately

webpack.jquery.config.js

module.exports = {
    entry: ["jquery"].output: {
        filename: "vendor.js".path: path.resolve(__dirname, "dist"),
        libraryTarget: 'var'.// The way of packing, hou
        library: "vendor_lib_vendor"// Name of the DLL
    },
    plugins: [
        new webpack.DllPlugin({
            name: "vendor_lib_vendor"./ / define a DLL
            path: path.resolve(__dirname, "dist/vendor-manifest.json")]}});Copy the code

Json scripts added to package.json

"dll": "webpack --config webpack.jquery.config.js --mode development"
Copy the code

After the above files are configured, when running NPM run DLL on the terminal, two files will be generated in the dist directory, respectively vendor.js and vendor-manifest.json. Vendor. js contains the code for the packaged jquery file, and vendor-manifest.json is used for the association. With the DLL defined, it’s time to apply the packaged DLL.

2) refer to DLL

DllPlugin is introduced into the webpack.config.js configuration file

plugins: [
        new webpack.DllReferencePlugin({
            context: __dirname,
            manifest: require("./dist/vendor-manifest.json")})],Copy the code

3) use the DLL

App.html is added at the bottom of app.html

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

3 note

LibraryTarget and library

They are needed when using Webpack to build a library that can be imported and used by other modules.

  • Output. libraryTarget configures how the library is exported.
  • Output. library Configures the name of the exported library. They are usually used together.

Output. LibraryTarget is an enumeration of strings and supports the following configurations.

1) var (default)

A written library will be assigned via var to a variable named by the library.

If output. Library =’LibraryName’ is configured, output and use the following code:

// Webpack output code var LibraryName = lib_code; // Lib_code is a self-executing function that returns a value. // Use the library method libraryname.dosomething ();Copy the code

2) commonjs

The libraries you write will be exported through the CommonJS specification.

If output. Library =’LibraryName’ is configured, output and use the following code:

// exports of Webpack code ['LibraryName'] = lib_code; // use the library method require('library-name-in-npm') ['LibraryName'].doSomething(); // Library-name-in-npm is the name of the module when it is published to the NPM repository.Copy the code

3) commonjs2

The libraries you write will be exported through the CommonJS2 specification, and the output and use code is as follows:

// module. Exports = lib_code; // use the library method require('library-name-in-npm').doSomething();
Copy the code

CommonJS2 is similar to the CommonJS specification. The difference is that CommonJS can only export with exports. CommonJS2 adds module.exports to CommonJS. When output.libraryTarget is commonJs2, it makes no sense to configure output.library.

4) this

The written library will be assigned this to the name specified by the library, and the output and usage code will be as follows:

// Webpack output code this['LibraryName'] = lib_code; Use the method of library / / this. LibraryName. DoSomething ();Copy the code

5) window

The library will be assigned to the name specified by the library through the window, that is, the library will be mounted to the window, output and use the following code:

// Webpack output code window['LibraryName'] = lib_code; Use the method of library / / the window. The LibraryName. DoSomething ();Copy the code

6) global

The written library will be assigned to the name specified by the library via global, that is, the library will be mounted to global, output and use the following code:

// Webpack output code global['LibraryName'] = lib_code; / / the method of using a library global. LibraryName. DoSomething ();Copy the code

Three HappyPack

1 action

The HappyPack allows Webpack to split tasks into multiple sub-processes for concurrent execution, which then send the results to the main process.

2 usage

install

Since WebPack 4.0 has just been released, the responding plug-in has not been updated yet, but you can add a @next to install the upcoming release

npm i happypack@next -D
Copy the code

webpack.config.js

module: {
        rules: [{test: /\.css$/.use: 'happypack/loader? id=css'.// Pass processing of.js files to HappyPack instance Babel
                // The HappyPack is used to process a particular class of files
                include: path.resolve('./src'),
                exclude: /node_modules/
            },
            {
                test: /\.js/.use: 'happypack/loader? id=babel'.include: path.resolve('./src'),
                exclude: /node_modules/}},plugins: [
        new HtmlWebPackPlugin({
            template: './src/index.html'
        }),
        new HappyPack({
            id: 'babel'.loaders: ['babel-loader']// The same configuration as in rules
        }),
        new HappyPack({
            id: 'css'.loaders: ['style-loader'.'css-loader']// The same configuration as in rules}),]Copy the code

Four ParallelUglifyPlugin

1.action

  • Serialized compression of JS files can be changed to enable parallel execution of multiple child processes

2 usage

insatll

npm install webpack-parallel-uglify-plugin -D
Copy the code

webpackage.config.js

new ParallelUglifyPlugin({
            workerCount: os.cpus().length - 1.// Start several subprocesses to perform compression concurrently. The default is the number of CPU cores of the current running computer minus 1
            uglifyJS: {
                output: {
                    beautify: false.// No formatting is required
                    comments: true.// Do not reserve comments
                },
                compress: {
                    warnings: false.// No warning is printed when UglifyJs removes unused code
                    drop_console: true.// Delete all 'console' statements, compatible with Internet Explorer
                    collapse_vars: true.// Insert variables that are defined but used only once
                    reduce_vars: true.// Extract static values that occur multiple times but are not defined as variables to reference}}})Copy the code

5 The server automatically refreshes

1 File Listening

1) action

  • You can listen for file changes and recompile when the file changes

2) useage

watch: true, 
watchOptions: {
    ignored: /node_modules/,
    aggregateTimeout: 300, 
    poll: 1 
}
Copy the code

3) note

watch

WatchOptions are only meaningful if the listening mode is enabled (watch is true)

aggregateTimeout

Listen for changes and wait 300(ms) before performing the action to prevent files from being updated too quickly and compiling too frequently

poll

Determine whether a file has changed by constantly asking if the file has changed. The default is 1000 times per second

File Listening Process

Webpack regularly gets the update time of the file and compares it to the last time it was saved. Inconsistency means a change has occurred, and poll is used to configure how many times to ask per second.

When detecting that the file does not change, the file is cached and then notified to the listener after a period of time. The waiting time is configured using aggregateTimeout.

Webpack will only listen to the files that the entry depends on. We need to minimize the number of files we need to listen to and the frequency of checking. Of course, lower frequency will result in lower sensitivity.

2 Refresh the browser automatically

1) use

devServer: {
    inline: true
},
Copy the code

2) note

Webpack is responsible for listening for file changes, and webpack-dev-server is responsible for refreshing the browser. These files are packaged into the chunk, which initiates WebSocket connections to the server on behalf of clients

3 Hot replacement of modules

1) action

  • Hot Module Replacement is a technology that updates only the specified Module without refreshing the entire web page.
  • The principle is that when a source code changes, only the changed module is recompiled and the corresponding old module in the browser is replaced with the new output module

2) advantage

  • Faster response, shorter time
  • Do not refresh the page to keep the running state of the page
  • Listen to fewer files
  • Ignore the files in node_modules

2) use

webpack.config.js

devServer: {
   hot:true// Set hot totrue} / / need plugins plugins: [new webpack. NamedModulesPlugin (), / / display module. The relative path of new webpack HotModuleReplacementPlugin () / / start heat load function]Copy the code

code

if (module.hot) {
    module.hot.accept('./hot.js', () = > {let hot = require('./hot');
        document.getElementById('app2').innerHTML = hot + '1'; })}Copy the code

3 note

Modules that require hot loading need to be introduced into the module during initialization, otherwise HMR will not be triggered.

Chapter VI Distinguishing the environment

1 action

In the development of web pages, there will be more than a set of running environment, for example, in the development process of convenient development and debugging environment. A runtime environment published online for use by users.

The differences between an online environment and a development environment are as follows:

  • The code on the line is compressed
  • The development environment may print a log that only the developer can see
  • The back-end data interface may differ between a development environment and an online environment

2 usage

package.json

  • cross-envCross-platform setting environment variables (no && after)
"scripts": {
    "build-dev": "cross-env NODE_ENV=development webpack --mode development"."build-prod": "cross-env NODE_ENV=production webpack --mode production"
}
Copy the code

webpack.config.js

  • Distinguish between production and development environments based on environment variables, and thenwebpack.base.config.jsMerge, and the production (or development) environment takes precedencewebpack.base.config.jsThe configuration.
let merge = require('webpack-merge');
let base = require('./webpack.base.config');
let other = null;
if (process.env.NODE_ENV === 'development') {
    other = require('./webpack.dev.config');
} else {
    other = require('./webapack.prod.config');
}
module.exports = merge(base, other);
Copy the code

webpack.base.config.js

  • The basic configuration
  • webpack.DefinePluginDefining environment variables
Basic configuration... plugins: [new webpack.DefinePlugin({
        __isDevelopment__: JSON.stringify(process.env.NODE_ENV == 'development')})]Copy the code

webpack.dev.config.js

  • In order tooutputFor example, if the parameters of the development and production environments are different, overridewebpack.base.config.jsInside the configuration
const path = require('path');
module.exports = {
    output: {
        path: path.resolve('./dist'),
        filename: "[name].dev.[hash:2].js"}};Copy the code

webpack.prod.config.js

  • (inoutputFor instance)
const path = require('path');
module.exports = {
    output: {
        path: path.resolve('./dist'),
        filename: "[name].prod.[hash:8].js"}};Copy the code

base.js

  • In the configuration filewebpack.DefinePluginDefined variables (__isDevelopment__) is available in both the entry file and other files referenced by the entry file__isDevelopment__The value of the
let env = null;
if (__isDevelopment__) {
    env = 'dev';
} else {
    env = 'prod';
}
module.exports = env;
Copy the code

index.js

let env = require('./base.js');
if (__isDevelopment__) {
    console.log('dev');
} else {
    console.log('prod');
}
console.log('env', env);

/*
prod
env prod
*/
Copy the code

3 note

webpack.DefinePlugin

The reason for wrapping a string in json.stringify (‘production’) when defining the value of an environment variable is that the value of the environment variable needs to be a string wrapped in double quotes, and the value of json.stringify (‘production’) is exactly equal to ‘”production”‘.

Seven CDN

CDN is also called content delivery network. By deploying resources to all parts of the world, users can obtain resources from the nearest server according to the principle of proximity during access, thus accelerating resource acquisition speed.

  • HTML file is not cached, put on your own server, turn off your server cache, static resource URL to the CDN server address
  • For static JavaScript, CSS, and image files, CDN and cache are enabled, and the file names have HASH values
  • Different static resources are allocated to different CDN servers so that parallel loading does not block

Eight Tree Shaking

1 action

Tree Shaking can be used to weed out dead code that is not useful in JavaScript.

2 useage

  • It relies on static ES6 modularization syntax, such as importing and exporting via import and export
  • Do not compile ES6 modules
use: {
    loader: 'babel-loader'.query: {
        presets: [["env", {
                    modules: false // Turn off Babel's module conversion and keep the original ES6 modularized syntax}]."react"]}},Copy the code

3 note

Note that it relies on static ES6 modularized syntax, such as importing and exporting via import and export. That is, Tree Shaking doesn’t make sense if your project code is running in an environment that doesn’t support ES6 syntax.

Extract common code

Why do I need to extract common code

Large sites have multiple pages, each with the same technology stack and style code, containing a lot of common code, which can be problematic if all of them are included

The same resources are repeatedly loaded, wasting user traffic and server costs; Too many resources are required to load each page. As a result, the first screen of the page is loaded slowly, affecting the user experience. If common code can be separated into separate files for loading, it can be optimized to reduce network traffic and reduce server costs

2 How to Extract

1) classification

Different types of files have different code blocks:

  • Base class library, convenient long-term caching
  • Common code between pages
  • Each page generates a separate file

2) usage

webpack.config.js

Optimization: {splitChunks: {cacheGroups: {Commons: {// common code chunks between pages:'initial',
                    minChunks: 2,
                    maxInitialRequests: 5, // The default limitis too small to showcase the effect minSize: 0 // This is example is too small to create commons chunks }, vendor: {// base class library chunks:'initial'.test: /node_modules/,
                    name: "vendor",
                    priority: 10,
                    enforce: true}}}},Copy the code

./src/pageA.js

require('./utils/utility1.js');
require('./utils/utility2.js');
require('react');
Copy the code

./src/pageB.js

require('./utils/utility2.js');
require('./utils/utility3.js');
Copy the code

./src/pageC.js

require('./utils/utility2.js');
require('./utils/utility3.js');
Copy the code

utils/utility1.js

module.exports = 1;
Copy the code

utils/utility2.js

module.exports = 2;
Copy the code

utils/utility3.js

module.exports = 3;
Copy the code

The result of the package

The generated results of the above three codes are as follows:

Ten Scope Hoisting

1 action

In Webpack3, the following applies in the case of Scope reactometer, as a new application:

  • Code volume is smaller because function declaration statements generate a lot of code
  • The code has a smaller memory overhead at run time because fewer functions are created in scope

2 useage

package.json

 "build": "webpack --display-optimization-bailout --mode development".Copy the code

webpack.config.js

plugins: [
    new ModuleConcatenationPlugin()
    ],
Copy the code

./h.js

export default 'scope hoist'
Copy the code

./index.js

import str from './h.js'
console.log(str);
Copy the code

3 note

ES6 syntax must be used otherwise it will not work (the –display-optimization-bailout argument prompts)

Chapter XI Code separation

Code separation is one of the most compelling features of WebPack. This feature makes it possible to separate code into different bundles, which can then be loaded on demand or in parallel. There are three common methods of code separation:

  • Entry starting point: Manually separate the code using the Entry configuration.
  • Prevent duplication: Use splitChunks to de-duplicate and separate chunks.
  • Dynamic import: Code is separated by inline function calls to modules.

Entry starting points and prevention of repetition have been mentioned above, so let’s focus on dynamic imports

1 action

When optimizing for on-demand loading of a single-page application, the following principles are generally applied:

  • Divide web site functions into one chunk for each category
  • For the first time to open the page needs to directly load the function, as soon as possible to show to the user
  • Certain function points that rely on large amounts of code can be loaded on demand
  • The segmented code needs to be loaded on demand

2 usage

  • useimport(module)The grammar of the
  • Import an asynchronous load module is an ES7 syntax
  • Import is a natural breaking point in WebPack
document.getElementById('play').addEventListener('click'.function(){
    import('./vedio.js').then(function(video){
        let name = video.getName();
        console.log(name);
    });
});
Copy the code

Reference documentation

  • Webpack official documentation
  • Chinese version of webpack official document
  • webpackGitHub