CcbeanBlog CcbeanBlog
首页
  • 前端文章

    • JavaScript
    • HTML+CSS
    • Vue
    • React
  • 系列笔记

    • React使用学习
    • Vue2源码探究
  • Node文章

    • 基础
    • 问题
    • 框架
  • 系列笔记

    • 数据结构与算法
  • 构建工具文章

    • webpack
  • 系列笔记

    • Webpack5使用学习
  • MySQL
  • Linux
  • 网络
  • 小技巧
  • 杂记
  • 系列笔记

    • Protobuf Buffers
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Ccbean

靡不有初,鲜克有终
首页
  • 前端文章

    • JavaScript
    • HTML+CSS
    • Vue
    • React
  • 系列笔记

    • React使用学习
    • Vue2源码探究
  • Node文章

    • 基础
    • 问题
    • 框架
  • 系列笔记

    • 数据结构与算法
  • 构建工具文章

    • webpack
  • 系列笔记

    • Webpack5使用学习
  • MySQL
  • Linux
  • 网络
  • 小技巧
  • 杂记
  • 系列笔记

    • Protobuf Buffers
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 邂逅Webpack
  • Webpack的配置和处理CSS资源
  • Webpack加载和处理其它资源
  • Webpak模块化原理
  • Webpack中的source-map
  • Webpack中的babel
  • Webpack中的DevServer和HMR
  • Webpack环境分离和代码分离
  • Webpack中的DLL、Terser和ScopeHoisting
    • DLL
      • 认识DLL
      • 打包一个DLL库
      • 使用一个DLL库
    • Terser
      • 认识Terser
      • 命令行中单独使用Terser
      • Webpack中使用Terser
    • CSS压缩
    • Scope Hoisting
  • Webpack中的TreeShaking以及其它优化
  • Webpack打包分析
  • Webpack自定义Loader
  • Webpack自定义Plugin
  • 分析React和Vue脚手架
  • Gulp的使用
  • Rollup的使用
  • Vite的使用
  • Webpack5使用学习
ccbean
2022-06-08
目录

Webpack中的DLL、Terser和ScopeHoisting

# Webpack中的DLL、Terser和ScopeHoisting

# DLL

# 认识DLL

DLL全称是动态链接库(Dynamic Link Library),是软件在Windows中实现共享函数库的一种实现方式;这是DLL名称的由来。

webpack中也有内置DLL的功能,可以实现JS代码的共享,将不经常改变的代码进行单独的编译,抽取成一个共享的库;

之后在项目编译时,就不需要再编译这部分公共共享代码。

如项目中用到了React、ReactDOM,那么就可以把它们编译成一个DLL库,之后只需要引用使用就可以,不需要每次都进行编译。

DLL库的使用分为两步:

  1. 打包一个DLL库
  2. 项目中引入DLL库

要注意的是,在升级到webpack4之后,React和Vue脚手架都移除了DLL库,Vue作者解释如下:

https://github.com/vuejs/vue-cli/issues/1205

dll option will be removed. Webpack 4 should provide good enough perf and the cost of maintaining DLL mode inside Vue CLI is no longer justified.

# 打包一个DLL库

在Webpack中可使用DllPlugin (opens new window)打包一个DLL库。

此插件用于在单独的 webpack 配置中创建一个 dll-only-bundle。 此插件会生成一个名为 manifest.json 的文件,这个文件中包含了从 require 和 import 中 request 到模块 id 的映射。

manifest.json 文件是用于让 DllReferencePlugin (opens new window) 能够映射到相应的依赖上。

此插件与 output.library (opens new window) 的选项相结合可以暴露出(也称为放入全局作用域)dll 函数。

这里我们使用React做相关测试,将react、react-dom打包到一个DLL库中。

配置如下:








 




 










 
 
 
 



const path = require('path')
const webpack = require('webpack')
const TerserPlguin = require('terser-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')

module.exports = {
  entry: {
    react: ['react', 'react-dom']
  },
  output: {
    path: path.resolve(__dirname, './dll'),
    filename: 'dll_[name].js',
    library: 'dll_[name]'
  },
  optimization: {
    minimizer: [
      new TerserPlguin({
        extractComments: false
      })
    ]
  },
  plugins: [
    new CleanWebpackPlugin(),
    new webpack.DllPlugin({
      name: 'dll_[name]',
      path: path.resolve(__dirname, './dll/[name].manifest.json')
    })
  ]
}
  • entry中配置react: ['react', 'react-dom'],两个包为入口文件
  • output中配置library: 'dll_[name]',将入口文件导出的模块与dll_[name]进行绑定,打包库时,常用library配置,详见output.library (opens new window)
  • 使用插件new webpack.DllPlugin({...}),options中设置了name和path
    • name 表示暴露出的 DLL 的函数名,这里是dll_[name],与output.library保持相同,可以暴露出dll 函数,也就是将dll函数放入全局作用域。此处在全局作用域中可通过dll_[name]访问到暴露出来的模块。
    • path表示manifest.json 输出文件的 绝对路径

这里使用了new CleanWebpackPlugin()插件而不是使用output.clean,原因是测试中发现使用后者会出现没有生成manifest.json文件的情况。

执行npm run build可看到在dll目录中生成dll.react.js和react.manifest.json。

在dll_react.js中可看到我们配置的output.library和DllPlugin插件的name结合暴露在全局作用域中的变量:

var dll_react;
(()=>{var e={448:(e,n,t)=>{"use strict";
  // ...
  dll_react = t;
})();                       

注意,此时,变量dll_react只与入口文件所导出的react-dom绑定。

# 使用一个DLL库

DllReferencePlugin (opens new window)插件可以通过manifest.json将DLL库映射到需要使用的项目中。

这里我们使用上面生成的React的DLL库。

如果使用了react和react-dom,使用了splitChunks的情况下,可以打包到一个独立的chunk中。

但是现在我们有了dll_react.js,不再需要单独去打包它们,可以直接去引用dll_react即可,需要两步:

  1. 通过DllReferencePlugin插件告知要使用的DLL库;
  2. 通过AddAssetHtmlPlugin (opens new window)插件,将打包的DLL库引入到打包的HTML模块中;

首先安装插件:

npm i add-asset-html-webpack-plugin -D

然后在Webpack中配置如下:

const webpack = require('webpack');
const AddAssetHtmlPlugin = require("add-asset-html-webpack-plugin");

module.exports = {
  // ...
  plugins: [
    new webpack.DllReferencePlugin({
      context: path.resolve(__dirname, '../'), // manifest (或者是内容属性)中请求的上下文
      manifest: path.resolve(__dirname, "../dll/react.manifest.json")
    }),
    new AddAssetHtmlPlugin({
      filePath: path.resolve(__dirname, '../dll/dll_react.js'),
      outputPath: 'js',
      publicPath: 'js'
    })
  ],
  // ...
}

DllReferencePlugin插件会引用DLL库中的react、react-dom的代码

AddAssetHtmlPlugin插件会将dll_react.js移动到build/js目录,同时在打包的index.html中添添加一个script标签引入dll_react.js文件,如下:








 









<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <title>Document</title>
    <script defer="defer" src="js/dll_react.js"></script>
    <script defer="defer" src="main.bundle.js"></script>
    <script defer="defer" src="index.bundle.js"></script>
    <link href="css/main.eb45b5.css" rel="stylesheet" />
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>

AddAssetHtmlPlugin和CopyWebpackPlugin (opens new window)类似,都是将文件复制到构建目录中,不同的是,AddAssetHtmlPlugin除了将文件复制到build目录外,还会在HTML文件中添加引入的标签。

# Terser

# 认识Terser

A JavaScript mangler/compressor toolkit for ES6+.

Terser (opens new window)是一个用于JavaScript ES6+的mangler(绞肉机)/compressor(压缩机)的工具包。

mangler绞肉机该如何理解呢?这里以一个函数为例,假如有一个函数:

function getAuthInfoFromCloud(options) {
  return fetch('api/auth', data)
}

那么经过mangler,这个函数被转换成如下代码:

function a(o) {
  return f('api/auth', d)
}

把大代码绞成了小代码,但代码还是原来的功能,没有什么不同。就好像去菜市场买一块肉包饺子,让热心老板用绞肉机给你绞成肉馅,肉还是你的肉,为了包饺子,没啥不一样。

再经过compressor压缩机,代码会被转化成如下结构:

function a(o){return f('api/auth',d)}

早期我们会使用uglify-js来丑化、压缩我们的JavaScript代码,但是目前已经不再维护,并且不支持ES6+的语法。

Terser是从uglify-es Fork 过来的,并且保留它原来的大部分API以及适配uglify-es和uglify-js@3。

也就是说,Terser可以帮助我们丑化、压缩代码,让打包的bundle变得更小。

# 命令行中单独使用Terser

Terser是一个独立的工具,可以单独安装:

# 全局安装
npm install terser -g

# 局部安装
npm install terser

可以在命令行中使用Terser:

terser [input files] [options]

# 如
terser js/file.js -o foo.min.js -c -m

Terser有很多可配置参数,开发中常用的是mangle options (opens new window)和compress options (opens new window)对代码进行丑化压缩。

下面会在命令行中使用几个常见的配置看绞肉和压缩效果。

测试代码abc.js如下:

const greet = 'Hello world';

console.log(greet);

function sum(arg1, arg2) {
  return arguments[0] + arguments[1];
}

console.log(sum(10, 20));

function getAuthInfoFromCloud(reqOptions) {
  if (1 === 2) {
    return 'Dead Code'
  } 
  return fetch(reqOptions)
}

const info = {
  nickname() {
    return 'ccbean';
  }
}

class Person {
  constructor() {
    this.name = 'ccbean'
  }

  sayHi() {
    return 'hello'
  }
}

执行:

npx terser .\src\abc.js -o ./src/abc.min.js

得到文件abc.min.js,默认情况下,Terser会使用默认的转换参数,并移除代码中的空格:

const greet="Hello world";console.log(greet);function sum(arg1,arg2){return arguments[0]+arguments[1]}console.log(sum(10,20));function getAuthInfoFromCloud(reqOptions){if(1===2){return"Dead Code"}return fetch(reqOptions)}const info={nickname(){return"ccbean"}};class Person{constructor(){this.name="ccbean"}hi(){return"hello"}}

格式化后如下:

const greet = "Hello world";
console.log(greet);
function sum(arg1, arg2) {
  return arg1 + arg2;
}
console.log(sum(10, 20));
function getAuthInfoFromCloud(reqOptions) {
  if (1 === 2) return "Dead Code";
  return fetch(reqOptions);
}
const info = { nickname: () => "ccbean" };
class Person {
  constructor() {
    this.name = "ccbean";
  }
  sayHi() {
    return "hello";
  }
}

如果需要对代码做特殊处理,可以配置具体的参数。在开发中,我们通常不会手动去设置这些参数,而是直接使用默认defaults开启的参数。

使用如下Compress参数处理:

  • defaults:默认为true。传入false,会关闭大部分开启的压缩转换。当只想启用一些压缩选项而禁用其余选项时会有用。

  • arrows:默认值是true;class或者object中的函数,转换成箭头函数;

  • arguments:默认值是false,将函数中使用 arguments[index]转成对应的形参名称;

  • dead_code:默认值是true;移除不可达的代码(tree shaking);不会用到的代码会被移除。

  • hoist_funs:默认值为false;提升函数声明

# 多个参数使用逗号隔开
npx terser .\src\abc.js -o ./src/abc.min.js -c defaults=false,arrows,dead_code=false,hoist_funs=true,arguments=true

手动格式化后,得到输出如下:

// 函数提升了
function sum(arg1, arg2) {
  return arg1 + arg2;
}
function getAuthInfoFromCloud(reqOptions) {
  if (1 === 2) return "Dead Code";  // 关闭了deda_code,没被移除
  return fetch(reqOptions);
}
const greet = "Hello world";
console.log(greet);
console.log(sum(10, 20));
const info = { nickname: () => "ccbean" };
class Person {
  constructor() {
    this.name = "ccbean";
  }
  sayHi() {
    return "hello";
  }
}

只输入-c表示全部使用compress的默认参数。如:

npx terser .\src\abc.js -o ./src/abc.min.js -c

格式化后结果如下:

const greet = "Hello world";
function sum(arg1, arg2) {
  return arguments[0] + arguments[1];
}
function getAuthInfoFromCloud(reqOptions) {
  return fetch(reqOptions);
}
console.log(greet), console.log(sum(10, 20));
const info = { nickname: () => "ccbean" };
class Person {
  constructor() {
    this.name = "ccbean";
  }
  sayHi() {
    return "hello";
  }
}

上面的代码只是默认做了压缩,但是没有进行绞肉(丑化),使用mangle进行丑化。

使用如下Mangle参数处理:

  • toplevel:默认值是false;顶层作用域中的变量名称,进行丑化(转换);

  • keep_classnames:默认值是false,是否保持依赖的类名称;

  • keep_fnames:默认值是false,是否保持原来的函数名称;

npx terser .\src\abc.js -o ./src/abc.min.js -c arguments=true -m toplevel=true,keep_classnames=true,keep_fnames=false

执行后,代码如下:

const n="Hello world";function o(n,o){return n+o}function c(n){return fetch(n)}console.log(n),console.log(o(10,20));const e={nickname:()=>"ccbean"};class Person{constructor(){this.name="ccbean"}sayHi(){return"hello"}}

手动格式化:

const n = "Hello world";
function o(n, o) {
  return n + o;
}
function c(n) {
  return fetch(n);
}
console.log(n), console.log(o(10, 20));
const e = { nickname: () => "ccbean" };
class Person { // keep_classnames为true,类名没变
  constructor() {
    this.name = "ccbean";
  }
  sayHi() {
    return "hello";
  }
}

可以看到,代码中的标识符经过Mangle丑化后,变得很简单。

# Webpack中使用Terser

开发中,一般不需要手动的通过terser来处理我们的代码,可以直接通过webpack来处理:

  • 在webpack中有一个minimizer属性,在production模式下,默认就是使用TerserPlugin,根据Webpack开启的默认参数来处理我们的代码的;
  • 如果想要定制化,也可以自己来创建TerserPlugin的实例,覆盖Webpack默认的相关的配置;

首先,设置optimization.minimize (opens new window)为true,这个配置的作用是告知 webpack 使用 TerserPlugin (opens new window) 或其它在 optimization.minimizer (opens new window)定义的插件压缩bundle。 也就是让其对我们的代码进行压缩,production模式下默认已经打开了。

然后,在minimizer创建一个TerserPlugin,并传入压缩相关的配置:

  • extractComments:默认值为true,表示会将注释抽取到一个单独的文件中;在开发中,我们不希望保留这个注释时,可以设置为false;
  • parallel:使用多进程并发运行提高构建的速度,默认值是true,并发运行的默认数量: os.cpus().length - 1;
  • terserOptions:设置terser相关的配置:
    • compress:设置压缩相关的选项;
    • mangle:设置丑化相关的选项,可以直接设置为true;
    • toplevel:顶层变量是否进行转换;
    • keep_classnames:保留类的名称;
    • keep_fnames:保留函数的名称;

在webpack.prod.config中进行配置:

const { merge } = require('webpack-merge');
const baseConfig = require('./webpack.base');
const TerserPlugin = require('terser-webpack-plugin');

module.exports = merge(baseConfig, {
  mode: "production",
  // ...
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        extractComments: false,
        terserOptions: {
          compress: {
            arguments: true
          },
          mangle: true,
          toplevel: true,
          keep_classnames: true,
          keep_fnames: true
        }
      })
    ]
  }
})

index.js代码如下:

const greet = 'Hello world';

console.log(greet);

function sum(arg1, arg2) {
  return arguments[0] + arguments[1];
}

console.log(sum(10, 20));

function getAuthInfoFromCloud(reqOptions) {
  if (1 === 2) {
    return 'Dead Code'
  } 
  return fetch(reqOptions)
}

getAuthInfoFromCloud({ url: 'http://httpbin.org', method: 'get' });

const info = {
  nickname() {
    return 'ccbean';
  }
}

info.nickname();

class Person {
  constructor() {
    this.name = 'ccbean'
  }

  sayHi() {
    return 'hello'
  }
}

new Person()

执行npm run build生成index.5eafed.bundle.js:

(()=>{function _defineProperties(e,n){for(var r=0;r<n.length;r++){var t=n[r];t.enumerable=t.enumerable||!1,t.configurable=!0,"value"in t&&(t.writable=!0),Object.defineProperty(e,t.key,t)}}console.log("Hello world"),console.log(function sum(e,n){return e+n}(10,20)),function getAuthInfoFromCloud(e){return fetch(e)}({url:"http://httpbin.org",method:"get"});new(function(){function Person(){!function _classCallCheck(e,n){if(!(e instanceof n))throw new TypeError("Cannot call a class as a function")}(this,Person),this.name="ccbean"}return function _createClass(e,n,r){return n&&_defineProperties(e.prototype,n),r&&_defineProperties(e,r),Object.defineProperty(e,"prototype",{writable:!1}),e}(Person,[{key:"sayHi",value:function sayHi(){return"hello"}}]),Person}())})();

手动格式化后:

(() => {
  function _defineProperties(e, n) {
    for (var r = 0; r < n.length; r++) {
      var t = n[r];
      (t.enumerable = t.enumerable || !1),
        (t.configurable = !0),
        "value" in t && (t.writable = !0),
        Object.defineProperty(e, t.key, t);
    }
  }
  console.log("Hello world"),
    console.log(
      (function sum(e, n) {
        return e + n;
      })(10, 20)
    ),
    (function getAuthInfoFromCloud(e) {
      return fetch(e);
    })({ url: "http://httpbin.org", method: "get" });
  new ((function () {
    function Person() {
      !(function _classCallCheck(e, n) {
        if (!(e instanceof n))
          throw new TypeError("Cannot call a class as a function");
      })(this, Person),
        (this.name = "ccbean");
    }
    return (
      (function _createClass(e, n, r) {
        return (
          n && _defineProperties(e.prototype, n),
          r && _defineProperties(e, r),
          Object.defineProperty(e, "prototype", { writable: !1 }),
          e
        );
      })(Person, [
        {
          key: "sayHi",
          value: function sayHi() {
            return "hello";
          },
        },
      ]),
      Person
    );
  })())();
})();

一般情况下,我们不需要手动配置Terser,Webpack在production模式下,默认会开启Terser等相关优化插件对代码做优化:

例如,配置:

const { merge } = require('webpack-merge');
const baseConfig = require('./webpack.base');

module.exports = merge(baseConfig, {
  mode: "production",
})

执行构建后可得到如下代码:

(()=>{function e(e,n){for(var t=0;t<n.length;t++){var o=n[t];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}console.log("Hello world"),console.log(function(e,n){return arguments[0]+arguments[1]}(10,20)),fetch({url:"http://httpbin.org",method:"get"}),new(function(){function n(){!function(e,n){if(!(e instanceof n))throw new TypeError("Cannot call a class as a function")}(this,n),this.name="ccbean"}var t,o;return t=n,(o=[{key:"sayHi",value:function(){return"hello"}}])&&e(t.prototype,o),Object.defineProperty(t,"prototype",{writable:!1}),n}())})();

格式化后:

(() => {
  function e(e, n) {
    for (var t = 0; t < n.length; t++) {
      var o = n[t];
      (o.enumerable = o.enumerable || !1),
        (o.configurable = !0),
        "value" in o && (o.writable = !0),
        Object.defineProperty(e, o.key, o);
    }
  }
  console.log("Hello world"),
    console.log(
      (function (e, n) {
        return arguments[0] + arguments[1];
      })(10, 20)
    ),
    fetch({ url: "http://httpbin.org", method: "get" }),
    new ((function () {
      function n() {
        !(function (e, n) {
          if (!(e instanceof n))
            throw new TypeError("Cannot call a class as a function");
        })(this, n),
          (this.name = "ccbean");
      }
      var t, o;
      return (
        (t = n),
        (o = [
          {
            key: "sayHi",
            value: function () {
              return "hello";
            },
          },
        ]) && e(t.prototype, o),
        Object.defineProperty(t, "prototype", { writable: !1 }),
        n
      );
    })())();
})();

可见,默认模式下,Webpack已经做了相关设置,如果不需要特殊配置,使用默认即可。

# CSS压缩

CSS压缩通常是去除无用的空格等,因为很难去修改选择器、属性的名称、值等;

可以使用插件css-minimizer-webpack-plugin (opens new window)来进行CSS压缩,这个插件是使用cssnano (opens new window)工具来优化、压缩CSS,,它也可以单独使用;

安装插件:

npm install css-minimizer-webpack-plugin -D

在optimization.minimizer中配置:

const { merge } = require('webpack-merge');
const baseConfig = require('./webpack.base');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const TerserPlugin = require('terser-webpack-plugin');
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");

module.exports = merge(baseConfig, {
  mode: "production",
  module: {
    rules: [
      {
        test: /\.css/i,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader'
        ]
      }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/[name].[contenthash:6].css',
      chunkFilename: 'css/[name].[contenthash:6].css'
    })
  ],
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        extractComments: false,
        terserOptions: {
          compress: {
            arguments: true
          },
          mangle: true,
          toplevel: true,
          keep_classnames: true,
          keep_fnames: true
        }
      }),
      new CssMinimizerPlugin()
    ]
  }
})

执行npm run build,可看到将style.css:

body {
  background: blue;
}

div {
  font-size: 20px;
  color: wheat;
}

进行了压缩,转成了main.2471b6.css:

body{background:blue}div{color:wheat;font-size:20px}

# Scope Hoisting

Scope Hoisting从webpack3开始增加的一个新功能;作用是对作用域进行提升,并且让webpack打包后的代码更小、运行更快。

默认情况下webpack打包会有很多的函数作用域,包括一些(比如最外层的)IIFE,无论是从最开始的代码运行,还是加载一个模块,都需要执行一系列的函数;

比如main.js中引用了一个util模块,有如下代码:

import { sum, mul } from "./util.js";

sum(2, 2)
mul(2, 2)

那么在构建后,util函数也会有自己的作用域闭包,在main中调用时,就要通过__webpack_require__()函数去加载这个模块:

(() => {
  "use strict";
  var e = {
      "./src/util.js": (e, r, _) => {
        function sum(e, r) {
          return e + r;
        }
        function mul(e, r) {
          return e * r;
        }
        _.r(r), _.d(r, { mul: () => mul, sum: () => sum });
      },
    },
    r = {};
  function __webpack_require__(_) {
    var u = r[_];
    if (void 0 !== u) return u.exports;
    var t = (r[_] = { exports: {} });
    return e[_](t, t.exports, __webpack_require__), t.exports;
  }
  (__webpack_require__.d = (e, r) => {
    for (var _ in r)
      __webpack_require__.o(r, _) &&
        !__webpack_require__.o(e, _) &&
        Object.defineProperty(e, _, { enumerable: !0, get: r[_] });
  }),
    (__webpack_require__.o = (e, r) =>
      Object.prototype.hasOwnProperty.call(e, r)),
    (__webpack_require__.r = (e) => {
      "undefined" != typeof Symbol &&
        Symbol.toStringTag &&
        Object.defineProperty(e, Symbol.toStringTag, { value: "Module" }),
        Object.defineProperty(e, "__esModule", { value: !0 });
    });
  var _ = {};
  (() => {
    __webpack_require__.r(_);
    var e = __webpack_require__(/*! ./util.js */ "./src/util.js");
    (0, e.sum)(2, 2), (0, e.mul)(2, 2);
  })();
})();

当模块之前的依赖关系复杂时,就会有大量的上述情况,整个代码会变得很繁琐,也会带来一定的性能损耗。

通过Scope Hoisting可以将函数合并到一个模块中来运行,解决这个问题:

  • 使用Scope Hoisting非常的简单,webpack已经内置了对应的插件ModuleConcatenationPlugin (opens new window):
  • 在production模式下,默认这个模块就会启用;
  • 在development模式下,需要自己来打开该模块;






















 




const path = require('path');
const webpack = require('webpack');
const { merge } = require('webpack-merge');
const baseConfig = require('./webpack.base');

process.env.NODE_ENV = 'development'

module.exports = merge(baseConfig, {
  mode: "development",
  devtool: 'source-map',
  module: {
    rules: [
      {
        test: /\.css/i,
        use: [
          'style-loader',
          'css-loader'
        ]
      }
    ]
  },
  plugins: [
    new webpack.optimize.ModuleConcatenationPlugin()
  ]
})

开发模式下,执行npm run build后,代码如下:

(() => {
  "use strict";
  var __webpack_require__ = {};

  (() => {
    __webpack_require__.r = (exports) => {
      if (typeof Symbol !== "undefined" && Symbol.toStringTag) {
        Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
      }
      Object.defineProperty(exports, "__esModule", { value: true });
    };
  })();

  var __webpack_exports__ = {};
  __webpack_require__.r(__webpack_exports__);

  function sum(num1, num2) {
    return num1 + num2;
  }
  function mul(num1, num2) {
    return num1 * num2;
  }

  sum(2, 2);
  mul(2, 2);
})();

可以看到,代码是在一个作用域中,不需要再去其它作用域中加载。

当然,插件也会自动判断作用域能不能提升,如果不可提升,则不会提升。比如一个的模块在多个地方引用,就不会对这个模块进行提升。

编辑 (opens new window)
上次更新: 2022/06/12, 11:22:42
Webpack环境分离和代码分离
Webpack中的TreeShaking以及其它优化

← Webpack环境分离和代码分离 Webpack中的TreeShaking以及其它优化→

最近更新
01
阅读精通正则表达式总结
09-29
02
项目搭建规范的配置
07-15
03
Vite的使用
07-03
更多文章>
Theme by Vdoing | Copyright © 2018-2023 Ccbeango
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式