1. webpack5新特性介绍 #

2.持久化缓存 #

2.1 安装 #

cnpm i webpack webpack-cli webpack-dev-server babel-loader @babel/core  @babel/preset-env -D

2.2 webpack.config.js #

const path = require('path');
module.exports = {
    mode: 'development',
    cache: {
        type: 'filesystem',  //  'memory' | 'filesystem'
        cacheDirectory: path.resolve(__dirname, 'node_modules/.cache/webpack'), // 默认将缓存存储在 node_modules/.cache/webpack
    },
    watch: true,
    module: {
        rules: [
            {
                test: /\.js$/,
                use: [
                    {
                        loader: 'babel-loader',
                        options: {
                            presets: [
                                "@babel/preset-env"
                            ]
                        }
                    }
                ]
            }
        ]
    }
}

2.3 package.json #

  "scripts": {
    "build": "webpack",
    "debug": "webpack"
  },

3.资源模块 #

module.exports = {
  module: {
    rules: [ 
      {
        test: /\.png$/,
        type: 'asset/resource'
      },
      {
        test: /\.ico$/,
        type: 'asset/inline'
      },
      {
        test: /\.txt$/,
        type: 'asset/source'
      }
    ]
  },
  experiments: {
    asset: true
  },
};

3.1 老方式 #

3.1.1 src\index.js #

src\index.js

import url from './images/kf.jpg';
let img = new Image();
img.src = url;
document.body.appendChild(img);

3.1.2 webpack.config.js #

webpack.config.js

module: {
        rules: [
            {
                test: /\.(jpg|png|gif)$/,
                type:'asset'
            }
        ]
}

3.2 新方式 #

3.2.1 src\index.js #

src\index.js

let url = new URL('./images/kf.jpg', import.meta.url);
let img = new Image();
img.src = url;
document.body.appendChild(img);

4.URIs #

src\index.js

import data from "data:text/javascript,export default 'title'";
import url from 'https://img.zhufengpeixun.com/zfjg.png';
console.log(data,url);

webpack.config.js

const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
    target: ['es6'],
    plugins:[
        new webpack.experiments.schemes.HttpsUriPlugin()
    ]
}

5.moduleIds & chunkIds的优化 #

5.1 概念 #

5.2 优化 #

可选值 含义 示例
false 不应使用任何内置算法,插件提供自定义算法 Path variable [name] not implemented in this context: [name].js
natural 按使用顺序的数字ID 1
named 方便调试的高可读性id src_two_js.js
deterministic 根据模块名称生成简短的hash值 915
size 根据模块大小生成的数字id 0
const path = require('path');
module.exports = {
    mode: 'development',
    devtool:false,
+    optimization:{
+        moduleIds:'deterministic',
+        chunkIds:'size'
+    },
    module: {
        rules: [
            {
                test: /\.js$/,
                use: [
                    {
                        loader: 'babel-loader',
                        options: {
                            presets: [
                                "@babel/preset-env"
                            ]
                        }
                    }
                ]
            }
        ]
    }
}

6.移除Node.js的polyfill #

6.1 安装 #

cnpm i crypto-js crypto-browserify stream-browserify buffer -D

6.2 src\index.js #

import CryptoJS from 'crypto-js';
console.log(CryptoJS.MD5('zhufeng').toString());

6.3 webpack.config.js #

    resolve:{
        /* fallback:{ 
            "crypto": require.resolve("crypto-browserify"),
            "buffer": require.resolve("buffer"),
            "stream":require.resolve("stream-browserify")
        }, */
        fallback:{ 
            "crypto":false,
            "buffer": false,
            "stream":false
        }
    },

7.更强大的tree-shaking #

1608717220311

7.1 原理 #

1608717379363

7.1.1 作用域 #

// module scope start

    // Block

    { // <- scope start
    } // <- scope end

    // Class

    class Foo { // <- scope start
        //   |       
    }       // <- scope end

  // If else

    if (true) { // <- scope start

    } /* <- scope end */ else { // <- scope start

    } // <- scope end

    // For

    for (;;) { // <- scope start
    } // <- scope end

    // Catch

    try {

    } catch (e) { // <- scope start

    } // <- scope end

    // Function

    function() { // <- scope start
    } // <- scope end

    // Scope

    switch() { // <- scope start
    } // <- scope end

// module scope end

7.1.2 工作过程 #

1608717689228

7.2 开启 #

7.2.1 开发环境 #

webpack.config.js

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  mode: 'development',
   optimization: {
   usedExports: true,
  },
};

7.2.2 生产环境 #

7.2.3 sideEffects #

package.json

{"sideEffects": ["@babel/polyfill"]}
{"sideEffects": ["*.css"]}

7.3 嵌套的 tree-shaking #

7.3.1 src\index.js #

src\index.js

import * as calculator from "./calculator";
console.log(calculator.operators.add);

7.3.2 src\calculator.js #

src\calculator.js

import * as operators from "./operators";
export { operators };

7.3.3 src\operators.js #

src\operators.js

export const add = 'add';
export const minus = 'minus';

7.3.4 webpack.config.js #

webpack.config.js

module.exports = {
    mode: 'production'
}

7.4 内部模块 tree-shaking #

7.4.1 src\index.js #

src\index.js

import { getPostUrl } from './api';
console.log('getPostUrl',getPostUrl);

7.4.2 src\api.js #

src\api.js

import { host } from './constants';

function useHost() {
  return host;
}

export function getUserUrl() {
  return useHost()+'/user';
}
export function getPostUrl() {
    return '/post';
}

7.4.3 src\api.js #

src\api.js

export const host = 'http://localhost';

7.5 CommonJs Tree Shaking #

7.5.1 src\index.js #

src\index.js

let api = require('./api');
console.log(api.getPostUrl);

7.5.2 src\api.js #

src\api.js

function getUserUrl() {
  return '/user';
}
function getPostUrl() {
    return '/post';
}

exports.getPostUrl=getPostUrl;

8.splitChunks #

参考 #