webpack4 常用配置项使用整理

2,545 阅读35分钟

mode

type: string

模式配置,webpack 可根据不同的模式选择不同的 内置优化过程。

production: "生产模式"。 当前模式下,部分配置项的默认值如下:

  • devTool 配置项的值为 false,不生成 .map 文件 ;

  • cache 配置项的值为 false,即 webpack 上一次编译生成的 modules、chunks 不被缓存,每次编译的时候需要重新生成 modules、chunks;

  • output.pathinfo 配置项的值为 false, ***;

  • optimization.flagIncludedChunks 配置项的值为 true,用于标记 子chunk, 详见下面描述;

  • optimization.occurrenceOrder 配置项的值为 true, 告诉 webpack 找出 module 的顺序,导致最小的初始包(仅字面意思,未理解);

  • optimization.sideEffects 配置项的值默认为 true, 用于移除 JavaScript上下文 中的 未引用代码(dead-code);

  • optimization.usedExports 配置项的值为 true, 告诉 webpack 确定每个 module 已使用的导出, 为 使用的导出 生成 导出;

  • optimization.concatenateModules 配置项的值为 true, 用于连接多个module为一个module;

  • optimization.splitChunks.minSize 配置项的值为 30kb,如果将 被分离出的chunk的大小 小于 minSize 值, 代码分离失败;

  • optimization.splitChunks.maxAsyncRequests 配置项的值为 5, 即按序加载时允许的最大并行请求数为 5, 否则代码分离会失败;

  • optimization.splitChunks.maxInitialRequests 配置项的值为3,即入口处的最大并行请求数为 3, 否则代码分离失败;

  • optimization.noEmitOnErrors 的值为 true,如果编译错误,不输出打包文件(??);

  • optimization.minimize 配置项的值为 true,对打包文件进行 压缩、混淆;

development: "开发模式"。当前模式下,部分配置项的默认值如下:

  • devTool 配置项的值默认为 "eval", 使用 eval() 包裹模块代码;

  • cache 配置项的值默认为 true。 webpack 上一次编译生成的 modules、chunks 都会缓存在 内存 中,当源文件发生变化重新编译构建模块依赖图时,如果模块对应的文件没有变化,则直接使用内存中缓存的 module,大大的减少编译时间;

  • output.pathinfo 配置项的值为 true, ***;

  • optimization.splitChunks.maxAsyncRequests 配置项的值为 Infinity,对按需加载时允许的最大并行请求数不做限制;

  • optimization.splitChunks.maxInitialRequests 配置项的值为 Infinity,对入口处允许的最大并行请求数不做限制;

  • optimization.splitChunks.minSize 配置项的值为 10kb,如果将 被分离出的chunk的大小 小于 minSize 值, 代码分离失效;

  • optimization.namedModules 配置项的值为 true,打包文件中以 模块源文件的路径(url) 作为 模块标识符;

  • optimization.namedChunks 配置项的值为 true,打包文件中以 chunk的名称 作为 chunk标识符;

如果未配置 mode, 默认情况下为 "production"。

context

type: string

基础目录,绝对路径,用于从配置中解析 入口起点(entry point) 和 loader。

    context: path.resolve(__dirname, '../')

entry

type: string | [string] | object { : string | [string] } | function

应用程序的入口。 从这个起点开始,应用程序启动执行。

如果 entry 配置项的值的类型为 string, 对应 单页面单入口应用。在编译过程中, 生成 一个模块依赖关系图。

如果 entry 配置项的值的类型为 [string], 对应 单页面多入口应用。应用程序启动时,数组中的入口文件按序执行。在编译过程中,生成 一个模块依赖关系图。

如果 entry 配置项的值为 object, 对应 多页面(单入口/多入口)应用。在编译过程中,生成 多个模块依赖关系图。

如果 entry 配置项的值的类型为 function,则是 动态入口(待研究)。

Resolve

type: object

Resolve配置项 可以设置 源文件、npm包 如何被 解析。

webpack 在 构建依赖关系图 时会通过 resolve 配置项 解析模块的url 来获取 模块源文件的绝对地址。 通过 源文件的绝对地址,读取源文件的内容,然后使用 解析器(parser) 解析源文件的代码结构,获取 依赖模块。

此外,webpack 使用 loader 处理 源文件 时,也会通过 resolve 配置项 解析 loader包 的 入口文件 的绝对地址,然后使用 入口文件 提供的方法处理 源文件 内容。

webpack 会提供 合理的默认值,如果不满足需要,我们也可以自己设置 Resolve配置项。

  • alias | object

    创建 import 或 require 的别名, 确保模块引入变的更加简单。

    在 创建模块 的时候, webpack 会解析模块的 请求路径(request path)。如果 请求路径 中使用了 别名 , webpack 会根据 resolve.alias 配置项,将 请求路径(request path) 转化为 源文件的绝对路径。

    用法详见 官网。

  • aliasFields | [string]

    指定一个字段,根据此规范进行解析, 默认值为 ["browser"]。

  • descriptionFiles

    用于描述的 JSON 文件,默认值为 ["package.json"]

    使用npm包时, 可以通过 package.json文件 获取 npm包 的 入口文件。

  • enforceExtension | boolean

    是否 强制需要文件扩展名。 默认值为 false, 即 不需要。

    如果值为 true,则 不允许无扩展名文件,否则 报错。

    // main.js
    import { func1 } from '../util.1.js' 
    import { func2 } from '../util.2' // enforceExtension:true, 解析模块路径会报错
    
  • enforceModuleExtension | boolean

    对模块是否需要使用的扩展, 默认为 false。

  • extensions | [string]

    可 自动解析的扩展, 默认值为 [".wasm", ".mjs", ".js", ".json"]

  • mainFields | [string]

    当从 npm包 中导入 模块 时(例如,import * as D3 from "d3"),此选项将决定在 package.json 中使用 哪个字段 导入模块。

    如果 target配置项 的值为 webworker, web 或者 没有指定,默认值为:["browser", "module", "main"]。

    对于 其他任意的 target(包括 node),默认值为:["module", "main"]。

    用法详见 官网。

  • mainFiles | [string]

    解析目录时要使用的文件名,默认值: ["index"]。

  • modules | [string]

    告诉 webpack 解析模块时应该搜索的 目录。

    数组中指定的目录的 优先级: 高 -> 低。

    默认值: ["node_modules"]。

    webpack 在解析 npm包 的路径时,会在工作目录下的 node_modules 目录中查找。

    用法详见 官网。

  • unsafeCache | regex | array | boolean

    是否启用 缓存, 默认值为 true。

    如果值为 true,启用 ; 如果值为 false, 禁用。

    webpack 在解析 模块、npm包入口文件 路径时,会把 解析结果(文件绝对路径、描述文件package.json信息等) 缓存起来。等到下次解析 相同模块、npm包 时, 直接使用缓存。

  • cacheWithContext | boolean

    如果启用了 unsafeCache,缓存解析结果的 cache 中 key 中会包含 context配置项 指定的信息。

    默认值为 false。

  • plugins | [object]

    使用的额外的 解析插件。

  • symlinks | boolean

    是否将符号链接(symlink)解析到它们的符号链接位置(symlink location)。

    默认值为 true。

    暂未理解。

  • cachePredicate | function

    指定一个 自定义函数,用于判断 源文件、npm包 的 解析结果 是否会被 缓存。

    如果返回 false, 即使 unsafeCache 的值为 true, 解析结果也 不会被缓存。

    自定义函数使用时会传入一个带有 请求信息 的 对象。

        resolve: {
            cachePredicate: function(params) {
                // params.path 对应 context 配置项的值
                // params.request 对应 请求path : './src/utils/util.1.js'
                return /\/src/.test(params.request)
            }
        }
        
    

resolveLoader

type: object

resolveLoader配置项 用法和 resolve配置项 完全一致, 区别是它 仅 用于 解析webpack的loader包。

即当 webpack 需要解析 loader包 的 入口文件 时,才会用到 resolveLoader配置项。

默认值:

    {
        cacheWithContext: false,
        unsafeCache: true,
        extensions: ['.js', '.json'],
        mainFields: ['loader', 'main'],
        mainFiles: ['index']
        
    }
  • moduleExtensions | ['string']

    解析 loader 时,用到 扩展名(extensions)/后缀(suffixes)。

    具体用法如下:

    {
        module: {
            rules: [{
                test: /\.(css|scss)$/,
                loaders: ['css']
            }]
        },
        resolveLoader: {
            moduleExtensions: ['-loader']
        }
        ...
    }
    

module

type: object

用于处理项目中的 不同类型(.js、.css、.sass、.vue、.png ...) 的模块。

  • noParse | RegExp | [RegExp] | function

    在构建 依赖关系图 时,webpack 会读取 模块源文件 的内容,然后 将源文件内容解析成一颗AST树。 分析 AST树,获取模块的 依赖 的 静态模块、懒加载模块、全局变量。

    如果 模块的url(绝对路径) 匹配 noParse配置项指定的表达式, 那么 模块对应的源文件的代码结构 不会被解析。 不解析大型的library可以 提高构建性能。

    不解析的模块源文件中不应该含有 import、require、define、url、全局变量 等。

    用法:

    module: {
        noParse: /vue|loadsh/
    }
    
    module: {
        // content 为模块源文件的绝对路径
        // vue-D:\study\demo\webpack\webpack-4-demo\node_modules\_vue@2.6.10@vue\dist\vue.runtime.esm.js"
        noParse: function(content) {
            return /vue|loadsh/.test(content)
        }
    }
    

    效果:

    // noParse: /vue/
    
    (window["webpackJsonp"] = window["webpackJsonp"] || []).push([["vendors-main"],{
        "./node_modules/_vue@2.6.10@vue/dist/vue.runtime.esm.js":
            (function(module, __webpack_exports__, __webpack_require__) {...})
    }])
    
    
    
    // 不使用 noParse
    (window["webpackJsonp"] = window["webpackJsonp"] || []).push([["vendors-main"],{
        "./node_modules/_process@0.11.10@process/browser.js": 
            (function(module, exports) {...}),
        "./node_modules/_setimmediate@1.0.5@setimmediate/setImmediate.js":
            (function(module, exports, __webpack_require__) {...}),
        "./node_modules/_timers-browserify@2.0.10@timers-browserify/main.js":
            (function(module, exports, __webpack_require__) {...}),
        "./node_modules/_vue@2.6.10@vue/dist/vue.runtime.esm.js":
            (function(module, __webpack_exports__, __webpack_require__) {...}),
        "./node_modules/_webpack@4.34.0@webpack/buildin/global.js":
            (function(module, exports) {...})
    }])
    
    

    如果 不使用noParse, vue.js 在构建 依赖关系图 时会被 解析为AST树,获取 vue 依赖的全局变量 global、setImmediate,然后构建相应的模块。"browser"、"setImmediate"、"main"、"global" 就是解析vue模块生成的模块。如果使用了 noParse: /vue/, vue模块不会被解析,全局变量对应的模块也不会生成。

  • rules | [object]

    模块(module) 构建时, 使用 源文件url(绝对路径) 来匹配 module.rules 中的规则,为模块选择 处理源文件需要的 loader 和 解析源文件内容需要的 parser。

    module.rules 是一个 array, rules 中的每一个 rule 是一个 object。

    每一个 规则(rule) 可以分成三部分:条件(conditions)、结果(results) 和 嵌套规则(nested rules)。

    条件(conditions) 的 输入值 有两种:

    1. resource - 源文件的path(绝对路径);

    2. issuer - 发布者( issuer - A中引入B,则A是B的issuer )的path(绝对路径);

    如果 module 的 resource属性 匹配 rule.test 、rule.include 、rule.exclude、rule.resource, 或者 module 的 issuer 属性匹配 rule.issuer, 则 模块匹配当前规则rule, 可以使用 rule中的loader 处理模块。

    结果(results) 的 输出值 有两个:

    1. loader - 应用在 resource 上的 loader数组,将 源文件 转化为 浏览器可识别的文件类型;

    2. parser option - 用于构建parser(将源文件代码解析为AST结构, 分析源文件的依赖);

    嵌套规则(nested rules) :

    可以使用属性 rules 和 oneOf 指定 嵌套规则。这些规则用于在 规则条件(rule condition)匹配 时进行取值。

    一个 模块 只有满足 规则(rule) 的 条件(conditions),才能拿到 规则(rule)对应的结果(loader、parser options) 来 处理模块。

    rule 的配置项如下:

    • resource | object

      规则(rule) 的 条件(condition)配置项。如果 模块path(绝对路径) 符合 条件(condition),将使用 当前规则对应的loaders处理模块。

      • test | RegExp | string | function | [RegExp] | [string] | [function]

        条件配置项,不考虑其他配置项的情况下,如果 模块path(绝对路径)满足 test 指定条件,则 匹配 当前规则。

        test 的值一般为 正则表达式,通过 文件后缀 来判断模块是否匹配规则。

        test: /\.css$/
        

        test 的值也可以是 string, 如果 模块path(绝对路径)包含test指定的值(path.indexOf(test) === 0), 则模块匹配当前规则。

        // test的值必须是绝对路径
        test: path.resolve(__dirname, '../src')
        
        // 由于模块path是绝对路径,path.indexOf('src') !== 0, 不匹配
        test: 'src'
        

        如果 test 的值是 string 类型,则必须是 绝对路径。

        test 的值也可以是 function,用户可 自定义条件。

        test: function(request) {
            return /\.css$/.test(request)
        }
        

        如果 test 的值是一个 array( [RegExp]、[string]、[function] ), array 中 条件 之间的关系为 或,只要 模块path(绝对路径) 满足 test中的某一个条件,那么模块就匹配当前规则。

      • include | RegExp | string | function | [RegExp] | [string] | [function]

        条件配置项,不考虑其他配置项的情况下,如果 模块path(绝对路径)满足指定条件,则 匹配 当前规则, 用法和test完全一致。

      • exclude | RegExp | string | function | [RegExp] | [string] | [function]

        条件配置项,不考虑其他配置项的情况下,如果 模块path(绝对路径)不满足指定条件,则 匹配 当前规则。

        exclude的用法和test基本相同, 唯一的区别是如果 exclude 的值是一个 array( [RegExp]、[string]、[function] ), array 中 条件 之间的关系为 且,只有 模块path(绝对路径) 不满足 exclude中的所有条件,模块才能匹配当前规则。

      在实际应用中, test 一般配合 include 或者 exclude 使用,test指定文件类型, include或者exclude指定范围。

      另外,test、include、exclude 之间的关系是 且,模块path(绝对路径)必须全部满足,才能匹配当前规则。

    • test

      Rule.test 是 Rule.resource.test 的 缩写。

      注意,使用 Rule.test 之后就不能再使用 Rule.resource,否则会 报错。

      // 这种也是不允许的
      {
          test: /\.js$/,
          resource: {
              include: [path.resolve(__dirname, '../src')]
          }
      }
      
    • include

      Rule.include 是 Rule.resource.include 的 缩写。

      注意,使用 Rule.include 之后就不能再使用 Rule.resource,否则会 报错

    • exclude

      Rule.exclude 是 Rule.resource.exclude 的 缩写。

      注意,使用 Rule.exclude 之后就不能再使用 Rule.resource,否则会 报错

    • issuer

      不考虑其他配置项的情况下,如果 模块的发布者(issuer)的path(绝对路径) 满足 issuer 指定的条件,那么模块匹配当前规则。

      即,模块B 被 模块A 引用, 如果 模块A(issuer) 满足 issuer 指定的条件, 那么 模块B 匹配当前规则。

      这个选项可以用来将 loader 应用到一个特定模块或一组模块的依赖中

      Rule.issuer 的用法和 Rule.test 完全一致。

    • resourceQuery

      不考虑其他配置项的情况下,如果 模块path(绝对路径) 的 query参数 满足 resourceQuery 指定的条件, 那么模块匹配当前规则。

      // main.js
      import A from './styles/style.css?inline'
      
      // webpackConfig.js
      module: {
          rules: [{
              test: /\.css$/,
              resourceQuery: /inline/
              // resourceQuery: 'inline'   '?inline'.indexOf('inline') !== 0, 匹配失败
          }]
      }
      

      resourceQuery配置项 的用法和 test配置项 的用法 完全一样。

      需要注意的是,在匹配的时候,会拿 模块path(绝对路径) 的 query 部分, 即 '?inline', 与 resourceQuery 对应的值做比较。 如果 resourceQuery 的值为 string,匹配规则为 query.indexOf(resourceQuery) === 0。resourceQuery 提供的值一定要 精确,才能匹配成功。

      一般情况下, resourceQuery配置项 的值为 RegExp 或者 function。

    • use | object | [object] | string | [string] | function

      指定应用于模块的 loader。

      当 模块path(绝对路径) 匹配 规则条件(rule conditions) 时,可使用 use配置项指定的loaders 处理模块。

      use配置项 的值可以是一个 object,具体属性如下:

      • loader | string

        指定使用的 loader 的 名称, 例 loader: 'css-loader'。

        loader 属性是 必要属性, 缺少会报错。

      • options | object

        指定 loader 的 配置项,调整loader的行为。

      • query | object

        指定 loader 的 配置项,调整loader的行为。

        query配置项 的作用和 options 一样, 二者只需一个。同时存在会报错。

          use: {
              loader: 'css-loader',
              options: {
                  minimize: true
              }
          } 
      

      use配置项 的值也可以是一个 string, 如:

          use: 'css-loader?minimize=true'
          
          // 在 webpack 处理过程中,会转化为一个 object
          {
              loader: 'css-loader',
              options: {
                  minimize: true
              }
          } 
      

      use配置项 的值也可以是一个 [object], 每一个 object 含有 loader、 options/query 属性;

          use: [{
              loader: 'style-loader'
          }, {
              loader: 'css-loader',
              options: {
                  minimize: true
              }
          }]
      

      use配置项 的值也可以是一个 **[string]****, 如:

          use: ['style-loader', 'css-loader']
      

      如果 use 配置项的值为 array,即 存在多个loader,webpack会倒序使用loader处理模块。例如, use: ['style-loader', 'css-loader'], webpack 会先使用 css-loader,再使用 style-loader。

      use配置项 的值也可以是一个 function,具体使用参照 官网。

    • loader | string

      rule.loader 是 rule.use: [{loader}] 的缩写。

          loader: 'css-loader'  // 相当于 use: [{loader: ‘css-loader’}]
          
          loader: 'style-loader!css-loader' // 相当于 use: [{loader: ‘style-loader’}, {loader: ‘css-loader’}]
      
    • loaders

      rule.loaders 是 rule.use 的别名,用法和 rule.use 完全一致。

      rule.loader、rule.loaders 只需要提供一个就够了,否则会报错。

    • options | object

      指定 loader 的 配置项,调整loader的行为。

      options配置项必须配合loader配置项 使用, 否则报错。

      rules: [{
          test: /\.css$/,
          loader: 'css-loader',
          options: {
              minimize: true
          }
      }]
      
      // 等价于: 
      rules: [{
          test: /\.css$/,
          use: [{
              loader: 'css-loader',
              options: {
                  minimize: true
              }
          }]
      }]
      

      如果loader 为 'style-loader!css-loader' 这种格式, 使用options会报错。

      同时使用 loaders, options 会报错。

      即只有 rule 使用 单一loader 时,才能使用 options。

    • query | object

      rule.query 用法和 rule.options 完全一致。

    • rules | [object]

      嵌套规则(nested rules)

      rule.rules 的用法和 module.rules 的完全一致。

      示例:

      module: {
          rules: [{
              test: /\.(css|scss)$/,
              loaders: ['style-loader', 'css-loader'],
              rules: [{
                  test: /\.scss$/,
                  loader: 'sass-loader'
              }]
          }]
      }
      

      在上述例子中, .css文件 使用 css-loader、style-loader 处理, .scss文件 会使用 scss-loader、css-loader、style-loader 处理。

      注意: 如果 外层规则(rule) 和 嵌套规则(nested rules) 都有 loader,嵌套规则 的 loader 先于 外层规则 的 loader 运行。

    • oneOf | [obj]

      规则数组,仅使用 第一个匹配的规则 作用于模块。

      示例:

      // webpackConfig.js
      module: {
          rules: [{
              test: /\.css$/,
              oneOf: [{
                  resourceQuery: /inline/,
                  loader: 'url-loader'
              }, {
                  resourceQuery: /external/,
                  loader: 'file-loader'
              }, {
                  loader: ['style-loader', 'css-loader']
              }]
          }]
      }
      
      
      // main.js
      import A from './styles/style.css?inline'
      

      上面的例子中, 模块 A 匹配 oneOf 中的 第一个规则 ,即使用 url-loader 处理源文件,不会再使用 css-loader、style-loader 处理。

      注意: 如果 外层规则(rule) 和 oneOf 都有 loader,oneOf 的 loader 先于 外层规则 的 loader 运行。

    • type | string

      用于设置 匹配模块的类型,常见的值为:'javascript/auto'、 'javascript/dynamic'、'javascript/esm'、'json'、 'webassembly/experimental'。

      构建 parser 会使用这个属性,作用 ???

    • enforce | string

      指定 loader 的种类, 可能的值为:"pre" | "post"。

      如果 未指定值,则为 normal loader。

      在 webpack 中, loader 可分为四类( 按优先级排序): pre loader、inline loader、normal loader、post loader。

          rules: [{
              test: /\.scss$/,
              loader: 'sass-loader'
          }, {
              test: /\.scss$/,
              loader: 'css-loader'
          }, {
              test: /\.scss$/,
              loader: 'style-loader'
          }]
      

      如果未使用 enforce属性 指定 loader 的 优先级,module收集的loaders 将按照 定义顺序倒序执行。 在上面的示例中,对于 .scss 文件, loaders 顺序为 style-loader、css-loader、sass-loader,会导致 编译报错。

          rules: [{
              test: /\.scss$/,
              loader: 'sass-loader',
              enforce: 'pre'
          }, {
              test: /\.scss$/,
              loader: 'css-loader'
          }, {
              test: /\.scss$/,
              loader: 'style-loader',
              enforce: 'post'
          }]
      

      使用 enforce属性 后, loaders 顺序为 css-loader、style-loader、sass-loader, 编译成功。

      内联loader:

      // loader顺序很重要
      import css from 'style-loader!css-loader!sass-loader!./styles/style.scss'
      

      所有 normal loader 可以通过在 请求 中加上 ! 前缀来忽略(覆盖)。

      所有 normal loader 和 pre loader 可以通过在 请求 中加上 -! 前缀来忽略(覆盖)。

      所有 normal loader、pre loader、 post loader 可以通过在 请求 中加上 !! 前缀来忽略(覆盖)。

      rules: [{
          test: /\.scss$/,
          loader: 'sass-loader',
          enforce: 'pre'
      }, {
          test: /\.scss$/,
          loader: 'css-loader'
      }, {
          test: /\.scss$/,
          loader: 'style-loader',
          enforce: 'post'
      }]
      
       // 不使用css-loader处理
      import css from '!./styles/style.scss' 
      
      // 不使用css-loader、sass-loader处理
      import css from '-!./styles/style.scss' 
      
      // 不使用sass-loader、css-loader、style-loader处理
      import css from '!!./styles/style.scss' 
      
      
    • parser | object

      解析器配置项,用于构建解析当前模块的 parser。

      ???

    • sideEffects

      指示模块的哪些部分包含副作用, 详见 tree shaking。

    • resolve | object

      可以在 模块级别 配置 解析(resolve), 详见 官网(webpack.js.org/configurati…)。

optimization

type: object

webpack4 会根据用户选择的模式 mode 进行优化。我们可以 手动设置optimization 覆盖webpack的默认配置来进行优化。

  • minimize | boolean

    告诉 webpack 使用 TerserPlugin 最小化打包文件,对打包文件进行 压缩、混淆。 production模式 下, 默认为 true。

  • minimizer

    允许用户提供 一个或多个自定义 的 TerserPlugin实例 去覆盖 默认的TerserPlugin实例。

    实际用法详见 官方文档 。

  • splitChunks | object

    一个 配置对象,指引 splitChunkPlugin 进行 代码分离。

    默认情况下,会将 第三方模块(node_modules)、被至少2个chunk共享的module 分离为新的 chunk。

    • automaticNameDelimiter | string

      默认情况下,如果未指定代码分离的 chunk 的 name, webpack会为分离的chunk自动生成 name。

      例如, 从 main chunk 分离出 vendors chunk 时, 如果未指定 vendors chunk 的 name, 新生成的 chunk 的名称为 'vendors~main'。

      automaticNameDelimiter 属性会指定生成的名称之间的 连接符, 默认为 '~'。

    • automaticNameMaxLength | number

      生成的chunk名称字符串的最大长度, 默认为 109。

      注意: webpack4 最新版本中,该属性已废弃。

    • chunks | string | function(chunk)

      表明可以选择哪些 chunks 中的 modules 进行分离,默认值为 'async'。

      代码分离之前,源文件会编译打包成两类 chunk:initial chunk (入口文件所在的chunk) 和 async chunk (懒加载module所在的chunk)。代码分离,就是把一些满足分离条件的 module 从 所在的chunk分离出来,然后重新生成 新的chunk。chunks 会告诉我们分离的时候,module 应该从哪类 chunk 中选择。

      如果chunks的值为 'async', 则只能选择 async chunk 中的 module 做代码分离;

      如果chunks的值为 'initial', 则只能选择 initial chunk 中的 module 做代码分离;

      如果chunks的值为 'all', 可以选择所有的 chunk(async chunk 和 initial chunk) 中的 module 做代码分离;

      我们也可以通过自定义一个 function,来筛选chunk进行优化(详见官网)。

    • maxAsyncRequests | number

      按需加载 时的 最大允许并行请求数。

      production模式 下为 5, development模式 下为 Infinity(不做限制)。

      我们通过一个简单的例子来解释:

      // webpack.js
      {
          mode:'production',
          entry: {
            'main': './src/main.js',
          },
          optimization: {
              splitChunks: {
                  chunks: 'all'
                  maxAsyncRequests: 1, // 生产模式下, 默认为 5
                  minSize: 10,
                  cacheGroups: {
                      common: {
                          name: 'common'
                          minChunks: 2,
                          priority: 0
                      }
                  }
              }
          },
          ...
      }
      
      // main.js
      import(/* webpackChunkName: "exp1" */ './examples/example.1.js')
      import(/* webpackChunkName: "exp2" */ './examples/example.2.js')
      
      // example.1.js
      import { func1 } from '../utils/util.1'
      export const example1 = () => {
          func1()
          console.log('example1')
      }
      
      
      // example.2.js
      import { func1 } from '../utils/util.1'
      export const example2 = () => {
          func1()
          console.log('example2')
      } 
      

      第一步,webpack会根据 入口文件main 生成 initial chunk - main chunk;

      第二步,从 initial chunk 中分离出 async chunk - exp1 chunk 和 exp2 chunk;

      第三步,使用 splitChunkPlugin 将 exp1 chunk 和 exp2 chunk 中的 共享module - func1 分离出来(依据common - cache group)。 这样 main.js 中动态加载 example.1.js的时候,需要加载 common chunk 和 exp1 chunk。

      由于 maxAsyncRequests 的 值为 1, 即 按需加载example.1.js 的时候,允许的最大并行请求为 1, 则 代码分离失败,无法将 func1 module 从 exp2 chunk 分离出来。

    • maxInitialRequests | number

      入口点处 的 最大并行请求数。

      production模式 下为 3, development模式 下为 Infinity(不做限制)。

      我们通过一个简单的例子来解释:

      // webpack.js
      {
          mode:'production',
          entry: {
            'main1': './src/main.1.js',
            'main2': './src/main.2.js'
          },
          optimization: {
              splitChunks: {
                  chunks: 'all'
                  maxInitialRequests: 2, // 生产模式下, 默认为3
                  minSize: 10,
                  cacheGroups: {
                      vendors: {
                          name: 'vendors',
                          test: /[\\/]node_modules[\\/]/,
                          priority: 10
                      },
                      common: {
                          name: 'common'
                          minChunks: 2,
                          priority: 0
                      }
                  }
              }
          },
          ...
      }
      
      // main.1.js
      import Vue from 'vue'
      import { func1 } from './utils/util.1.js'
      
      ...
      
      
      // main.2.js
      
      import Vue from 'Vue'
      import { func1 } from './utils/util.1.js'
      import { func2 } from './utils/util.2.js'
      
      ...
      

      上述例子是一个简单的多页面应用。

      第一步, webpack 会将根据 入口文件(main.1.js, main.2.js), 生成两个 initial chunk(main.1 - [vue module, func1 module],main.2 - [vue module, func1 module, func2 module]);

      第二步,使用 splitChunkPlugin插件 进行代码分离, 先将 vue module(满足vendors - cacheGroup) 分离到 vendors chunk, 然后将 func1 module(满足common - cacheGroup) 分离到 common chunk。分离完成以后,加载 main.1 chunk 之前需要先加载 vendors chunk、 common chunk, 这样加载首页的时候就会有 vendors、common、main.1 三个请求。

      由于 maxInitialRequests 的值为 2, 即入口处的并行最大请求数为2, 因此 func1 module 从 main.1 chunk 中分离的时候, 由于已经有 vendors、main.1 两个chunk, 代码分离失败, 不能分离为 新的chunk。

    • minChunks | number

      代码分割前必须共享模块的最小块数。即如果minChunks为3, 则 module 必须被至少三个chunk共享才能被分离出来, 默认值为 1。

      注意: 如果分离出来的chunk的大小小于 minSize,则 代码分离不起作用。

    • minSize | number

      指定生成块的最小大小, 以字节为单位。

      production模式 下默认为 30000字节。

      development模式 下默认为 10000字节。

      如果分离出来的 chunk 的大小小于 minSize, 则 代码分离不起作用。

      注意:代码分离的时候如果满足 minChunks、maxInitialRequests、maxInitialRequests、 cacheGroup(enforce: false) 但是不满足 minSize, 代码分离还是会失效。

    • maxSize | number

      webpack尝试将大于 maxSize 的块拆分成更小的部分。

      一般我们会把第三方库单独打包成一个chunk: vendors。如果第三方库比较大,导致vendors会比较大,导致更大的下载量。 此时,我们可以通过设置 maxSize 属性, 将 vendors chunk 拆成更小的 chunk。

    • name | string | boolean | function: string

      指定 代码分离 以后生成的 新的chunk 的名称,默认值为 true。

      如果 name的值为 true,使用 cacheGroup的属性名、源chunk的名称 来生成 chunk 的名称 如 'vendors~chunk';

      如果 name 的值为 false 则使用 chunk 的 index 作为 chunk 的名称,名称为 数字;

      如果 name 的值为 字符串,会使用当前字符串作为 chunk 的名称;

      如果 name 的值为 函数, 使用 函数 的 返回字符串作为 chunk的 名称;

      如果将name的属性设置为字符串或者返回字符串的函数,源chunk分离出来的多个chunk会合并为一个chunk,可能会导致更大的初始下载量和减慢页面的加载速度。

      一般情况下,name属性更多的使用在 cacheGroup中,详见 官方文档。

    • cacheGroups

      缓存组,用于指定 代码分离策略,将满足条件的 module 从原来所属的 chunk(initial chunk / async chunk) 中分离出来, 构成新的 chunk。cacheGroup 可以 继承/复写splitChunks的任何配置,只有 test、priority、 reuseExistingChunk 是 cacheGroups 特有的。

      cacheGroups的默认值如下:

      {
          ...
          optimization: {
              splitChunks: {
                  cacheGroups: {
                      // 将被至少2个chunk共享的module分离成新的chunk
                      default: {
                          automaticNamePrefix: '',
                          reuseExistingChunk: true,
                          minChunks: 2,
                          priority: -20
                      },
                      // 将引用的第三方库分离成新的chunk
                      vendors: {
                          automaticNamePrefix: 'vendors',
                          test: /[\\/]node_modules[\\/]/,
                          priority: -10
                      }
                  }
              }
          }
      }
      
      • priority | number

        指定 cache group 的 优先级。

        如果一个模块可以属于多个 cache group, 那么它将属于 优先级更高 的 cache group。 例如,一个第三方模块(jquery),既满足 'vendors' 条件, 也满足 'default' 条件,但是由于 'vendors' 的优先级高于 'default', jquery 模块最后会被分离到 vendors chunk 中。

        默认 cache group 的优先级为 负数(vendors: -10, default: -20), 我们可以自定义 cache group, 只要 priority 的值大于-10, 即可先于默认cache group 发挥作用。

      • reuseExistingChunk | boolean

        如果分离出来的module已经存在于某个chunk中,那么重用这个chunk,不需要重新生成一个chunk。 这样可能导致生成的chunk的名称不符合预期。

        我们通过一个简单的例子来说明:

        // webpack
        {
            splitChunks: {
                cacheGroups: {
                    common: {
                        name: 'common',
                        minChunks: 2,
                        priority: 0,
                        reuseExistingChunk: false,
                        enforce: true
                    }
                }
            }
        }
        
        // main.1.js
        import(/* webpackChunkName: "exp1" */ './examples/example.1.js')
        import(/* webpackChunkName: "exp2" */ './examples/example.2.js')
        
        // example.1.js
        import { func2 } from '../utils/util.2'
        export const example1 = () => {
            func2()
            console.log('example1')
        }
        
        // example.2.js
        import { func2 } from '../utils/util.2'
        export const example2 = () => {
            func2()
            console.log('example2')
        }
        
        
        // main.2.js
        import(/* webpackChunkName: "util1" */ './utils/util.1')
        import(/* webpackChunkName: "util2" */ './utils/util.2')
        
        // util.1.js
        export const func1 = () => {
            console.log('func1')
        }
        
        // util.2.js
        export const func2 = () => {
            console.log('func2')
        }
        
        

        上面的例子是一个简单的多页面应用。

        第一步, webpack 会将根据 入口文件(main.1.js, main.2.js), 生成两个 initial chunk(main.1 chunk, main.2 chunk) 和 四个 async chunk(exp1 chunk, exp2 chunk, util1 chunk, util2 chunk);

        第二步,使用 splitChunkPlugin插件 进行 代码分离。由于 util.2 module 被 exp1 chunk, exp2 chunk,util2 chunk 共享, 将会被分离成一个 新的chunk:'common'。

        如果 reuseExistingChunk 的值为 true,由于 common chunk 中的 module 在 util2 chunk 中存在, 所以 util2 chunk 会被复用, common chunk 不会被新建, 最后输出的 chunk 为: main.1, main.2, exp1, exp2, util1, util2。

        如果 reuseExistingChunk 的值为 false,common chunk 会被创建, 最后输出的 chunk 为: main.1, main.2, exp1, exp2, util1, common(exp1、exp2、util2 中的 util.2 module 会分离到 common chunk 中, 导致 util2 chunk 中的 module 为 0, 然后被删除)。

      • test | string | Regexp | function(module, chunks): boolean

        选择满足条件的module来生成chunk,详见 官方文档。。

      • filename | string

        和 output.filename 用法一样。当且仅当是 initial chunk 时,覆盖文件名。(待研究)

      • enforce | boolean

        如果为 true,则始终为当前 cache group 创建 chunk,默认为 false。

        splitChunks: {
            minSize: 30000,
            cacheGroups: {
                common: {
                    name: 'chunk-common',
                    minChunks: 2,
                    enforce: true
                }
            }
        }
        

        webpack 会根据上面的配置项将 被至少2个chunk共享的module 分离为 新的chunk('chunk-common',实际大小为10kb)。如果 enforce 为 false, 由于 chunk-common的实际大小小于minSize(30kb), 代码分离失效,chunk-common块不会生成。此时,我们可以将 enforce 设置为 true,强制令代码分离生效, 生成 chunk-common。

  • runtimeChunk | boolean | object

    webpack 编译打包源文件时,会生成一段 runtime代码, 用于 加载chunk 、加载module、缓存module等。如果 runtimeChunk 配置项的值为 true 或者 object 时, runtime代码 会从被分离成一个单独的 chunk(runTime chunk)。应用加载时, runtime chunk 会首先加载。

    默认情况下为 false,即不分离 runtime chunk。如果 runtimeChunk 的值为对象,对象只有一个name属性,用于声明 runtime chunk 的名称。

    optimization: {
        runTimeChunk: true   // 生成名称为 runtime~main.js 的chunk
    }
    // 如果配置项的值为对象, 对象的属性只有name。 name的类型可以为字符串或者函数
    optimization: {
        runTimeChunk:{
            name: 'runtime'  // 生成名称为 runtime.js 的chunk
        }
    }
        
    optimization: {
        runTimeChunk:{
            name: function(entrypoint) { // entrypoint -> entry chunk, 一般为main chunk
                return `runtime~${entrypoint.name}`  //  entrypoint.name => main
            }
        }
    }
    
  • noEmitOnErrors | boolean

    编译错误时,emit阶段会跳过,即不会输出打包文件到指定位置。production模式 下,默认为 true。

  • namedModules | boolean

    在编译过程中,每一个 module 都会生成一个 标识符 用于标识 module。如果设置为true,在打包文件中会以 模块源文件的路径 作为标识符, 方便我们调试。

    optimization.namedModules: true 等同于 optimization.moduleIds: 'named'

    development模式 下, 默认为 true; production模式 下,默认为 false。

    // main~chunk.js
    (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[2],{
    /***/ "./src/main.js":   // 以'.src/main.js' 标识 main.js 对应的 module
    /***/ (function(module, __webpack_exports__, __webpack_require__) {
            "use strict";
            __webpack_require__.r(__webpack_exports__);
            /* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./node_modules/_vue@2.6.10@vue/dist/vue.runtime.esm.js");
    
            console.log(vue__WEBPACK_IMPORTED_MODULE_0__[/* default */ "a"])
            alert('1')
    
    /***/ })
    
    },[["./src/main.js",0,1]]]);
    
    
  • namedChunks | boolean

    如果设置为 true,在打包文件中使用 chunk的名称 来标识 chunk,方便我们调试。

    optimization.namedChunks: true 等同于 optimization.chunkIds: named。

    development模式 下,默认为 true,production模式 下,默认为 false。

    // main~chunk.js
    // namedChunks: false, 以数字作为chunk的标识符;
    (window["webpackJsonp"] = window["webpackJsonp"] || []).push([["2"],{
        ...
    },[["Vtdi","0","1"]]]);
    
    // namedChunks: true, 以chunk的名称作为chunk的标识符
    (window["webpackJsonp"] = window["webpackJsonp"] || []).push([["main"],{
        ...
    },[["Vtdi","runtime~main","chunk-vendors"]]]);
    
    
  • modulesId | boolean | string

    告诉webpack使用哪种算法来生成 module id。 在最后的打包文件中,会使用 module id 来标识每一个 module。

    值 说明
    false 使用内置的算法生成 module id, module id 为 数字
    natural 使用 module 在 modules列表 中的 index 作为 id,main.js 对应的 module id 为 0
    named 使用 源文件url 作为 module id
    hashed 使用 源文件url 通过 md5算法 生成的 hash值 的 前四位 作为 module id
    size 将 modules 按照 最小的初始下载大小排序, module 的 index 即为 module id(未理解)
    total-size 将 modules 按照 最小的总下载大小排序, module 的 index 即为 module id(未理解)

    moduleIds: 'hash' 比较常用。

  • chunkIds

    告诉 webpack 使用那种算法来生成 chunk id。 在最后的打包文件中,会使用 chunk id 来标识 chunk。

    值 说明
    false 将 chunks列表 中的 chunk 按照 name 从小到大排序, chunks列表 中 chunk的index 即为 chunk id
    natural 将 chunks列表 中的 chunk 按照 加载顺序 从小到大排序, chunks列表 中 chunk的index 即为 chunk id
    named 将 chunk 的名称作为 chunk id,方便调试
    size 将 chunks 按照 最小的初始下载大小排序, chunk 的 index 即为 chunk id(未理解)
    total-size 将 chunks 按照 最小的总下载大小排序, chunk 的 index 即为 chunk id(未理解)
  • removeAvailableModules | boolean

    如果 children chunk 中含有 parent chunk 已经存在的 module,将 module 从 children chunk 中移除。

    我们通过一个简单的例子来说明:

    // main.js
    import { func1 } from './utils/util.1'
    func1()
    import(/* webpackChunkName: "example1" */ './examples/example.1.js').then(res => {
      res.example1()
    })
    
    
    // example1.js
    import { func1 } from '../utils/util.1'
    export const example1 = () => {
        func2()
        console.log('example1')
    } 
    

    我们在使用 webpack 编译打包源文件的时候,会先将源文件打包为一个 initial chunk(main)。如果有需要 动态导入 的 module,则会创建一个 新的chunk,即 async chunk(example1)。此时 main chunk 为 example1 chunk 的 parent。

    如果 removeAvailableModules 为 true, webpack 会检查 example1 chunk 中包含的 module(util.1) 是否也存在于 main chunk 中, 如果存在,删除 example1 chunk 中的对应 module,即 example1打包文件 中不包含 utils.1 模块。

    如果将 removeAvailableModules 属性设置为false,webpack 将不会检查 子chunk 中是否存在 重复module 并移除, 即 'main'打包文件 和 'example1'打包文件 中都含有 utils.1 模块。

    不管是 production模式 还是 development模式,removeAvailableModules 默认为 true。

  • nodeEnv | string

    告诉 webpack 将 process.env.NODE_ENV 设置为给定的 字符串值(production / development)。

    默认为 mode配置项 的值, 如果未指定 mode 的值,设置为 'production'。

  • mangleWasmImports

    默认值为 false。

  • removeEmptyChunks | boolean

    默认为 true,如果生成的 chunk 中没有 module,则将 chunk 移除。

    在使用 spiltChunkPlugin 做 代码分离 的时候,可能会出现 收集的module被分离为新的chunk而导致自己的modules列表为空 的情况。此时, 没有module的chunk就会被移除。

  • mergeDuplicateChunks | boolean

    默认为 true,告诉 webpack 合并包含相同 modules 的 chunk。

    mergeDuplicateChunks 配置项会指引 MergeDuplicateChunksPlugin 对 源文件编译打包以后的chunks 做优化,将 包含相同modules 的 chunks 做合并处理。优化以后的 chunks 才会使用 splitChunkPlugin 做 代码分离。

    我们通过一个简单的小例子来说明一下:

    // webpack.js
    {
        entry: {
            'main1': './src/main.1.js',
            'main2': './src/main.2.js'
        },
        optimization: {
            mergeDuplicateChunks: true
        }
    }
    
    
    // main.1.js
    import(/* webpackChunkName: "exp1" */ './examples/example.1.js')
    
    
    // main.2.js
    import(/* webpackChunkName: "example1" */ './examples/example.1.js')
    

    源文件会通过 webpack 打包成两类 chunk: initial chunk(main.1 chunk, main.2 chunk), async chunk(exp1 chunk,example1 chunk);

    如果 mergeDuplicateChunks 的值为 true, 对生成的 chunks 优化。上述 chunks 中, exp1 chunk 和 example chunk 中的 module 完全一致, example chunk 会合并到 exp1 chunk 中。合并完成以后,example1 chunk 会被 删除。 这样使用 splitChunkPlugin 进行 代码分离 的 chunks 为: main.1 chunk、main.2 chunk、exp1 chunk。

    如果 mergeDuplicateChunks 的值为 false, 则 不作合并优化,使用 splitChunkPlugin 进行 代码分离 的 chunks 为: main.1 chunk、main.2 chunk、exp1 chunk、 example1 chunk。

  • flagIncludedChunks | boolean

    production模式 下,默认为 true。

    假设存在两个 chunkA(id = 'A'), chunkB(id = 'B')。如果 chunkA 是 chunkB 的 子集(即chunkA中的module在chunkB中都存在), 那么 chunkB 的 id = 'B,A'。

    我们通过一个简单的小例子来说明:

        // main.js
        import(/* webpackChunkName: "exp1" */ './examples/example.1.js')
        import(/* webpackChunkName: "exp2" */ './examples/example.2.js')
        
        // example.1.js
        import { example3 } from './example.3.js'
        export const example1 = () => {
            example3()
            console.log('example1')
        } 
        
        // example.2.js
        export const example2 = () => {
            import(/* webpackChunkName: "exp3" */ './examples/example.3.js')
            console.log('example2')
        }
        
        
        // example.3.js 
        export const example3 = () => {
            console.log('example3')
        }
    

    上面的例子中,会生成三个 async chunk:exp1 chunk、 exp2 chunk、 exp3 chunk。由于 exp3 chunk 中的 modules 在 exp1 chunk 中都存在, 所以 exp3 chunk 为 exp1 chunk 的子集, exp1 chunk 的 id 为 'exp1, exp3'。

    应用启动的时候, 会通过 动态添加script的方式 加载 exp1 chunk、exp2 chunk。由于 exp1 chunk 的 id 为 'exp1, exp3', 所以会认为 exp1、exp2、exp3 都已经加载了。 这样当我们需要加载 exp3 chunk 的时候,就不要通过动态添加script的方式来加载了,直接使用 缓存 即可。

  • occurrenceOrder | boolean

    告诉 webpack 找出 module 的顺序,导致最小的初始包。

    optimization.occurrenceOrder: true 等同于 optimization.chunkIds: 'total-size'。

    optimization.occurrenceOrder: true 也等同于 optimization.moduleIds: 'size'。

    production模式 下默认为 true。

  • providedExports | boolean

    默认为 true。 告诉 webpack 找出 module 的 输出 来生成更有效的代码。

    我们通过一个简单的例子来说明:

        // main.js
        import { add, sub } from '../utils/util.js'
        add()
        sub()
        
        // util.js
        export const add = () => { 
            console.log('add')
        }
        
        export const sub = () => {
            console.log('sub')
        }
    

    启动应用后,我们会加载 main module、 util module, 然后缓存到 installedModules 中, installedModules 的结构为:

        installedModules = {
            'main.js': {
                i: 'main.js',   // module id
    			l: true,        // module 是否已加载
    			exports: {}     // module 输出
            },
            'util.js': {
                i: 'util.js',
                l: true,
                exports: {
                    add: function() {...},
                    sub: function() {...}
                }
            }
        }
    

    如果 providedExports 的值为 true, 则会对 util module 的输出的名称进行 优化, 即 installedModules['util.js'].exports = {a: function(...) {}, b: function() {...}};

    如果 providedExports 的值为 false, installedModules['util.js'].exports = {add: function(...) {}, sub: function() {...}};

  • usedExports | boolean

    production模式 下为 true。告诉 webpack 确定每个 module 已使用的导出, 为 使用的导出 生成 导出。

    我们通过一个简单的例子来说明:

    // main.js
    import { add, sub } from '../utils/util.js'
    add()
    
    // util.js
    export const add = () => { 
        console.log('add')
    }
    
    export const sub = () => {
        console.log('sub')
    }
    

    启动应用后,我们会加载 main module、 util module, 然后缓存到 installedModules 中, installedModules 的结构为:

        installedModules = {
            'main.js': {
                i: 'main.js',   // module id
    			l: true,        // module 是否已加载
    			exports: {}     // module 输出
            },
            'util.js': {
                i: 'util.js',
                l: true,
                exports: {
                    add: function() {...},
                    sub: function() {...}
                }
            }
        }
    

    在上面的示例中, util module 的输出,只有 add 被用到。

    如果 usedExport 为 true, 那么 installedModules['util.js'].exports = { add: function() {...}};

    如果 usedExport 为 false, 那么 util module 的 所有输出 还是会出现中 exports 中。

    注意:如果 usedExport 为 true, sub 方法不会出现在 exports 中。 sub方法代码 尽管没有使用, 但还是会被打包。 使用 tree shaking 才能在打包过程中去除 未使用的代码。

  • concatenateModules | boolean

    连接多个module为一个module。

    production模式 下默认为 true。

    示例:

        // main.js
        import { add } from './utils/util.1.js'
        
        // util.1.js
        export const add = () => {
            console.log('add')
        }
    

    如果 concatenateModules 为true, util.1 module 和 main module 会合并为一个 module;

    如果 concatenateModules 为 false, 不做 合并。

    ES6模块才可以被合并。模块合并 发生在 代码分离 之后。

  • sideEffects | boolean

    用于移除 JavaScript上下文 中的 未引用代码(dead-code) - tree shaking。

    product模式 下默认为 true。

    为了 tree shaking 生效, 我们需要:

    • 使用 ES2015 模块语法(即 import 和 export);

    • 在项目 package.json 文件中,添加一个 "sideEffects" 入口。

    详细用法见: 官方文档。

  • portableRecords | boolean

    告诉 webpack 生成 具有相对路径的记录,以便能够 移动上下文文件夹。

    默认情况下,optimize.portableRecords 被禁用。

    如果至少有一个记录选项( recordsPath,recordsInputPath,recordsOutputPath)提供,则自动启用。

output

type: Obect

用于指示 webpack 如何以及在何处输出打包文件、资源以及其他使用webpack打包或者加载的文件。

  • path | string

    指定 打包文件 的 输出目录,即打包后 文件在硬盘中的存储位置。

    输出目录是一个 绝对路径。

  • publicPath | string

    此选项指定在浏览器中所引用的 输出目录(path)对应的公开URL。

    publicPath 并不会对 生成文件的路径 造成影响,主要是 对页面里面引入的资源的路径做对应的补全。

    {
        output: {
            path: path.resolve(__dirname, '../dist'), // 打包文件会输出到path指定的位置
            publicPath: '/'  // 浏览器会访问 publicPath 指定位置的文件
        }
    }
    
  • pathinfo | boolean

    告诉 webpack 在 chunk 中引入 所包含模块信息的相关注释。

    默认值 是 false,并且 不应该用于生产环境(production),但是 对阅读开发环境(development)中的生成代码(generated code)极其有用。

    这些注释也会被添加至经过 tree shaking 后生成的 bundle 中。

  • filename | string | function

    指定 输出的打包文件 的 文件名, 默认值为 空。

    我们可以使用以下常用方式为每一个 打包文件 提供 唯一 的 文件名:

    • 'bundle.js' - 指定 入口文件(main.js) 所在的 chunk 的 文件名, 仅适用于单页面应用;

    • '[name].js' - 使用 chunk 的 name;

    • '[name].[hash].js' - 使用 compilation 的 hash,所有chunk文件名中hash值一样;

    • '[name].[chunkhash].js' - 使用 chunk 内容的 hash,每个chunk文件名中的hash值都不一样;

    • '[name].[id].js' - 使用 chunk 的 id;

    • [name].[contenthash].js - 使用提取内容的 hash,一般应用于将 css 提取为单独的文件。

    我们也可以将 filename 指定一个 function 来返回输出的文件名, 返回值 的格式和上面一样。

    常用命名方式: [name].[chunkhash].js

  • chunkFilename | string

    指定 非入口chunk(不包含runtime code) 的文件名。

    如果未指定, 使用 '[id].js' 或者 filename指定的文件名。

  • chunkLoadTimeout | number

    chunk请求超时的时间,单位为 毫秒,默认为 120000。

    我们会通过 动态添加script元素 的方式来进行 懒加载。如果在指定时间内未获取到指定的chunk, 则认为 超时。

  • crossOriginLoading | boolean | string

    告诉 webpack 是否启用 chunk 的 跨域加载, 默认值为 false。

    如果值为 false, 禁用;如果值为 字符串,在 动态添加script元素 的方式来进行 懒加载时,会给 script元素 添加 crossorigin 属性。

    'anonymous' - 无需凭据 即可启用 跨域加载;

    'use-credentials' - 使用凭证 启用 跨域加载';

  • jsonpScriptType | string

    在 动态添加script元素 的方式来进行 懒加载时,指定 script元素 的类型,即 设置type属性的值。

    如: jsonpScriptType: 'text/javascript'

  • library | string | object

    常用于 开发类库, 需和 libraryTarget属性 配合使用。

    如果是 string,将 入口文件的返回值 赋值给 library属性 指定的 变量。

    如果是 object, 则用于给每个 target(libraryTarget) 起不同的名称。

    output: {
      library: {
        root: "MyLibrary",
        amd: "my-library",
        commonjs: "my-common-library"
      },
      libraryTarget: "umd"
    }
    
  • libraryTarget | string

    配置如何暴露 library。 假设 output.library: 'myLibrary':

    • 'var'

      类库加载完毕以后,入口文件的返回值 将分配给一个 使用var定义的变量。

      // 编译打包以后的输出文件: main.js
      var myLibrary = (function(modules){
      
          return xxx
          
      })([...modules])
      
    • 'assign'

      类库加载完毕以后,入口文件的返回值 将分配个一个 不使用var定义的变量。

      // 编译打包以后的输出文件: main.js
      myLibrary = (function(modules){
      
          return xxx
          
      })([...modules])
      
      
    • 'this'

      类库加载完毕以后,入口文件的返回值 将作为 当前上下文this 的一个 属性,属性名为 myLibrary。

      // 编译打包以后的输出文件: main.js
      // this 一般为 window
      this["myLibrary"] = (function(modules){
      
          return xxx
          
      })([...modules])
      
    • 'window'

      类库加载完毕以后,入口文件的返回值 将作为 window对象 的一个 属性,属性名为 myLibrary。

      // 编译打包以后的输出文件: main.js
      window["myLibrary"] = (function(modules){
      
          return xxx
          
      })([...modules])
      
    • 'self'

      类库加载完毕以后,入口文件的返回值 将作为 self 的一个 属性,属性名为 myLibrary。

      // 编译打包以后的输出文件: main.js
      self["myLibrary"] = (function(modules){
      
          return xxx
          
      })([...modules])
      
    • 'global'

      类库加载完毕以后,入口文件的返回值 将作为 globalObject属性指定的全局变量 的一个 属性,属性名为 myLibrary。

      // 编译打包以后的输出文件: main.js
      // globalObject 默认为 window
      window["myLibrary"] = (function(modules){
      
          ...
          
      })([...modules])
      
    • 'commonjs'

      输出的类库符合 commonJs规范。

      入口文件的返回值 将作为 exports 的一个 属性,属性名为 myLibrary。

      // 编译打包以后的文件: main.js
      exports["myLibrary"] = (function(modules){
      
          return xxx
          
      })([...modules])
      
      
      
    • commonjs2

      输出的类库符合 commonJs规范。

      入口文件的返回值 会被分配给 module.exports。

      // 编译打包以后的文件: main.js
      module.exports = (function(modules){
      
          return xxx
          
      })([...modules])
      
    • amd

      输出的类库 符合 AMD规范。

      // 编译打包以后的文件: main.js
      define("MyLibrary", [], function() { return (function(modules){
      
          return xxx
          
      })([...modules])}
      
    • umd

      输出的类库 符合 UMD规范。

      // 编译打包以后的输出文件:main.js
      (function(root, factory){
          if(typeof exports === 'object' && typeof module === 'object')
              module.exports = factory();
          else if(typeof define === 'function' && define.amd)
              define([], factory);
          else if(typeof exports === 'object')
              exports["my-common-library"] = factory();
          else
              root["MyLibrary"] = factory();
      }(window, function() {
          return  (function(modules){
      
              ...
          
          })([...modules])
      }))
      
    • jsonp

      将 入口起点 的 返回值,包裹到一个 jsonp 包装容器中。

      MyLibrary((function(modules){
      
          return xxx
          
      })([...modules]))
      

      需配合 extenals配置项 使用。

    • system

      输出类库格式:

      System.register("MyLibrary", [], function(__WEBPACK_DYNAMIC_EXPORT__) {
      
      	return {
      
      		execute: function() {
      			__WEBPACK_DYNAMIC_EXPORT__((function(modules) {
      			
      			    return xxx
      			    
      			}([...modules])));
      		}
      	};
      });
      

      系统模块 要求在执行 类库时,需要 浏览器 中存在 全局变量System。

  • globalObject | string

    和 library、libraryTarget 一起使用,指示将 入口文件的返回值 分配给哪个 全局对象。

    默认值为 window。

    // webpack.js
    output: {
        library: 'myLibrary',
        libraryTarget: 'global',
        globalObject: 'self'
    }
    
    // 编译打包以后的文件: main.js
    self["myLibrary"] = (function(modules){
        
        return xxx
            
    })([...modules])
    
  • libraryExport | string | [string]

    用于指定 具体的入口文件的返回值。

    常见的使用方式:

    • 未指定值
    // webpack.js
    outout: {
        library: 'myLibrary',
        libraryTarget: 'var'
    }
    
    // main.js
    var myLibrary = (function(modules){
        
        return xxx
            
    })([...modules])
    
    
    • 'default'
    // webpack.js
    outout: {
        library: 'myLibrary',
        libraryTarget: 'commonjs2',
        libraryExport: 'default'
    }
    
    // main.js
    module.exports = (function(modules){
        
        return xxx
            
    })([...modules])["default"]
    
    • 'myModule'
    // webpack.js
    outout: {
        library: 'myLibrary',
        libraryTarget: 'amd',
        libraryExport: 'myModule'
    }
    
    // main.js
    define("MyLibrary", [], function() { return (function(modules){
        
        return xxx
            
    })([...modules])["myModule"]})
    
    • ['myModule', 'mySubModule']
    // webpack.js
    outout: {
        library: 'myLibrary',
        libraryTarget: 'umd',
        libraryExport: ['myModule', 'mySubModule'
    }
    
    // main.js
    (function(root, factory){
        if(typeof exports === 'object' && typeof module === 'object')
    	    module.exports = factory();
        else if(typeof define === 'function' && define.amd)
    	    define([], factory);
        else if(typeof exports === 'object')
    	    exports["my-common-library"] = factory();
        else
    	    root["MyLibrary"] = factory();
    }(window, function() {
        return  (function(modules){
        
            return xxx
            
        })([...modules])["myModule"]["mySubModule"]
    }))
    
    
  • auxiliaryComment | string | object

    在和 output.library 和 output.libraryTarget 一起使用时,此选项允许用户向 导出容器(export wrapper) 中插入 注释。

    具体用法详见: 官网。

  • jsonpFunction | string

    当 输出多个chunk 时, webpack 会构建一个 全局方法, 用于 安装chunk。

    jsonpFunction 可用于指定 安装chunk 的 方法名。

    如果 未指定, 则方法名为:'webpackJsonp'。

    如果 指定(如:'myFunction'), 则方法名为 'myFunction'。

    // 未指定
    (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[0],[...modules])
    
    // jsonpFunction: 'myFunction'
    (window["myFunction"] = window["myFunction"] || []).push([[0],[...modules])
    
  • sourceMapFilename

    配置 source map 的命名方式。默认使用 '[file].map'。

    只在 devtool 启用了 SourceMap 选项时才使用。

  • strictModuleExceptionHandling | boolean

    如果一个模块在导入时抛出异常,告诉 webpack 从 模块实例缓存 中 删除 这个模块。

    默认值为 false, 即 不删除。

    如果设置为 true, 删除。

    // strictModuleExceptionHandling: true
    function __webpack_require__(moduleId) {
    	// Check if module is in cache
    	if(installedModules[moduleId]) {
    		return installedModules[moduleId].exports;
    	}
    	// Create a new module (and put it into the cache)
    	var module = installedModules[moduleId] = {
    		i: moduleId,
    		l: false,
    		exports: {}
    	};
    
    	// Execute the module function
    	var threw = true;
    	try {
    	    // 导入模块
    		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
    		threw = false;
    	} finally {
    	    // 导入模块时, 如果发生异常,将模块实例从installedModules缓存中删除
    		if(threw) delete installedModules[moduleId];
    	}
    
    	// Flag the module as loaded
    	module.l = true;
    
    	// Return the exports of the module
    	return module.exports;
    }
    
    
    
    // strictModuleExceptionHandling: false
    
    function __webpack_require__(moduleId) {
    	// Check if module is in cache
    	if(installedModules[moduleId]) {
    		return installedModules[moduleId].exports;
    	}
    	// Create a new module (and put it into the cache)
    	var module = installedModules[moduleId] = {
    		i: moduleId,
    		l: false,
    		exports: {}
    	};
    
    	// Execute the module function
    	modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
    
    	// Flag the module as loaded
    	module.l = true;
    
    	// Return the exports of the module
    	return module.exports;
    }
    
    
  • umdNamedDefine| boolean

    会对 UMD 的构建过程中的 AMD 模块进行命名。否则就使用 匿名 的 define。

    // webpack.js
    output: {
        libraryTarget: 'umd',
        umdNamedDefine: true,
        library: 'myLibrary'
        
    }
    
    // main.js
    (function(root, factory){
        if(typeof exports === 'object' && typeof module === 'object')
    	    module.exports = factory();
        else if(typeof define === 'function' && define.amd)
            // 如果 umdNamedDefine: false, 则define([], factory)
    	    define(["myLibrary"], factory);
        else if(typeof exports === 'object')
            exports["myLibrary"] = factory();
        else
    	    root["MyLibrary"] = factory();
    }(window, function() {
        return  (function(modules){
        
            ...
            
        })([...modules])
    }))
    
    
  • futureEmitAssets | boolean

    告诉 webpack 在 输出文件到指定位置 时,使用 未来的版本, 它允许输出以后 释放内存。

    在 webpack5 中 移除,作为一个 默认行为。

output剩余配置项使用较少, 后续整理。

devtool

type: string | boolean

该配置项用以控制是 否生成source map 以及 怎样生成source map。

不同的值会明显影响到 构建(build) 和 重新构建(rebuild) 的速度。

source map 是一个 信息文件,里面储存着 位置信息。也就是说,转换后的代码 的每一个位置,所对应的 转换前的位置。 source map 文件的 内容结构 如下:

{
    // source map 的版本
	"version": 3,
	// 转换前的文件名, 是一个数组, 可能存在文件合并
	"sources": ["webpack:///./src/examples/example.1.js"],
	// 转换前的所有变量名和属性名
	"names": ["a", "example1", "alert"],
	// 记录位置信息的字符串(一个 ; 代表一个行映射, 一个 , 代表一个列映射)
	"mappings": ";;;;;;AAAA;AAAA;AAAA,IAAMA,IAAI,KAAV;AACO,IAAMC,WAAW,SAAXA,QAAW,GAAM;AAC1BC,UAAMF,CAAN;AACH,CAFM,C",
	// 转换后的文件名
	"file": "exp1.js",
	// 转换前的内容
	"sourcesContent": ["const a = '123'\r\nexport const example1 = () => {\r\n    alert(a)\r\n} "],
	// 转换前的文件所在的目录。如果与转换前的文件在同一目录,该项为空
	"sourceRoot": ""
}

devtool 的各个配置项,其实是由几个 关键字: eval, source-map, cheap, module, inline, hidden, nosources 组合生成的。这几个关键字的含义如下:

  • eval

    使用 eval() 包裹模块代码。

  • source-map

    生成 .map 文件,在 调试 时用于 追踪转换前的代码。

  • cheap

    需配合 'source-map' 一起使用, Source Map 中只有 生成的代码(generated code) 和 转换后的代码(transformed code) 之间的 行映射关系, 没有 列映射关系。

  • module

    需配合 'source-map' 一起使用,Source map 中存在 生成的代码(generated code) 和 源代码(riginal source) 之前的 行映射 关系、列映射 关系。

  • inline

    需配合 'source-map' 一起使用,不单独生成 .map 文件,.map 文件作为 DataUrl 嵌入 **打包文件(bundle)**中。

  • hidden

    需配合 'source-map' 一起使用,会生成 .map文件,但 不会为 bundle 添加引用注释。

  • nosources

    需配合 'source-map' 一起使用,会生成 .map文件,但是 sourcesContent 的内容为空,无法追踪转换以后的代码或者源代码。

具体用法详见: 官网。

devServer

type: object

我们通过使用 webpack-dev-server 来快速开发应用程序。

devServer配置项 用于指引 wepack-dev-server 的行为。

当我们通过 Node.js API 来使用 dev-server, devServer 中的选项将被忽略。将选项作为第二个参数传入: new WebpackDevServer(compiler, devServer)。

  • inline | boolean

    development模式 下,webpack-dev-server 会 监听源文件是否发生变化。 如果发生变化,会 自动刷新页面。

    默认值为 true, 即为 inline模式。 如果 inline 的值为 false, 则为 iframe模式。

    inline模式 和 iframe模式 的原理相同, 都是 浏览器 和 服务器 之间建立 websocket连接。当源文件发生变化时,通知浏览器 重新加载页面 进行更新。

    inline模式 下, 浏览器端 建立websocket连接的逻辑代码 会和我们的 应用代码 打包到一起, 会增加编译时间;

    iframe模式 下,浏览器端 建立websocket连接的逻辑代码 和 我们的应用代码 是分开的。 当我们通过 localhost:port/webpack-dev-server/ 访问应用时, 服务端会返回一个 html页面。html页面 中会包含一个 live.bundle.js 的文件, 负责 建立与服务器之间的websocket连接, 并 动态建立一个iframe用于加载实际应用。当源文件发生变化时, 页面不刷新, 会通知 iframe 重新更新。

    iframe模式 下无法启用 HMR。

  • hot | boolean

    设置为 true,将启用 HMR 功能。

    若想触发 HRM 功能,需满足三个条件:

    • hot配置项 的值为 true;

    • 启用 inline模式;

    • 必须显示声明 module.hot.accept('url', callback), 否则只能刷新页面;

  • hotOnly | false

    默认情况为 false,当 HMR 失败以后,浏览器端通过 重新加载页面 来 响应服务端更新。

    如果设置为 true, 当 HMR 失败以后, 浏览器端无法响应服务端更新。

    如果未显示声明 module.hot.accept('url', callback), HMR 就会失败, 若此时 hotOnly 的值为 true, 则 浏览器端无法响应服务端更新。

  • open | boolean

    设置为true, dev-server 自动打开 默认浏览器 启动应用。

  • useLocalIp

    设置为true,dev server 会以 本地IP 打开默认浏览器。

    使用时,open = true。

  • openPage | string

    指定 dev-server 自动打开 默认浏览器 以后的 默认跳转页面。

  • host | string

    指定要使用的 host, 默认是 localhost。

  • port | string

    指定监听的 端口号, 默认是 8080。

  • liveReload

    默认情况下,dev-server 将在 检测到参与编译打包的文件文件更改 时 重新加载/刷新页面。 即如果如果一个文件 未参与编译打包过程, 那么它发生变化时 不会触发重新加载/刷新页面。

    通过将 liveReload 设置为 false 来 禁用 它(修改什么文件也 不会触发重新加载/刷新页面)。

  • contentBase | boolean | string | [string] | number

    告诉服务器从哪里提供内容,默认值为 当前工作目录。

  • watchContentBase

    告诉 dev-server 监视 devServer.contentBase选项 所服务的文件, 默认情况下 禁用 它。

    默认情况下, 如果一个文件 参与编译打包过程,那么当这个文件发生变化时,才会 触发重新加载/刷新页面, 否则 无效。

    设置为 true 后 启用,即使某个文件 未参与编译打包,当它发生变化时,也会 触发重新加载/刷新页面。

  • watchOptions | object

    一个配置项集合,用于自定义 watch mode。

    • aggregateTimeout | number

      在 第一个文件 修改以后,延迟重新编译 的过程。这允许 webpack 将在这个时间段内的所有修改 聚合 到一个重新编译的过程中。

      传递的值以 毫秒 为单位。

    • ignored | RegExp

      不监听 满足 ignored 条件的文件的变化。

    • poll | boolean | number

      通过传递 true 或者 以毫秒为单位的数值指定轮询间隔 来 启用轮询,检查文件变化。

      当 文件监听不起作用 时,可以尝试启用 poll 功能。

  • writeToDisk | boolean | function:filePath

    默认为 false, 即 不将编译打包以后的内容写入磁盘。

    如果设置为 true,会将 编译打包以后的内容 写入 output配置项 指定的位置。

    如果设置为 function,该 function 是一个 filter function, 将 满足条件的文件名对应的文件写入磁盘。

    具体用法详见 官网文档。

  • lazy | boolean

    如果设置为 true, dev-server会进入 懒惰模式, 仅在请求时编译该bundle。 这意味着 webpack不会监视任何文件更改。

    ???

    注意:使用 lazy模式 时, 必须提供 filename, 否则报错。

  • filename | string

    此选项可让您减少 lazy模式 下的 编译。 默认情况下,在 lazy模式 下,每个请求都会产生 新的编译。 使用 filename,只能在请求某个文件时进行编译。

    ???

  • overlay | boolean | object

    当存在 编译错误或者警告 时,将 错误或者警告 以 全屏覆盖 的形式在浏览器中展示。

    默认 禁用, 具体用法详见 官网文档 。

  • proxy | object | [object, function]

    在 前后端分离 的开发过程中,使用 proxy 可以有效的帮我们解决 跨域请求问题。

    通常,我们会在 proxy配置项 中指定每个 API请求 对应的 代理。

    {
        devServer: {
            proxy: {
                'test': {
                    target: 'http://localhost:3000',
                    changeOrigin: true,
                    router: {...}
                },
                
            }
        }
    }
    
    • target | string

      指定一个 服务器地址。

      dev-server 接收到一个 API Request 以后,会向 匹配的test 对应的 服务器 重新发出 Request, 将 response 通过 dev-server 返回给 Client。

    • changeOrigin | boolean

      默认值为 false。

      如果指定为 true,??

    • pathRewrite | object | function

      重写 Request API。

      如果 pathRewrite 的值为 object, 则 key 为一个 RegExp,value 为 string, Request API 中 匹配RegExp 的会被 string 替换;

      如果 pathRewrite 的值为 function, 可自定义返回新的 Request API。

    • router | object | function

      如果请求的 host 或者 host + path 能匹配 router 配置项中的属性 key,则使用对应的属性值 value 覆盖 proxy.target。

    其他配置项及详细用法详见: http-proxy-middle

  • progress | boolean

    在 控制台 输出 进度信息,仅适用于 CLI模式。

  • allowedHosts | array

    将允许访问 dev server 的 服务列入白名单。

剩余配置项应使用较少,后续整理。

target

type: string | function(compiler)

webpack 能够为 多种环境 编译构建, 可通过 target配置项 指定一个 具体的环境。

如果 target 的值为 字符串, 可以支持以下环境:

  • web

    webpack编译打包的代码 应用于 web环境(浏览器)。对于需要 懒加载的chunk,会通过 动态添加script元素的方式加载,然后通过一个 全局方法(webpackJsonp) 来安装。

  • webworker

    webpack编译打包以后的代码 应用于 web worker环境。使用 chunk 时,通过 importScripts 方法加载。

    // chunk.js
    self["webpackChunk"]([0],{
        5:  (function(module, __webpack_exports__, __webpack_require__) {
            
            ...
            
        })
    });
    
    // 加载
    importScripts('./chunk.js')
    
  • node

    webpack编译打包以后的代码 应用于 node环境。 非入口chunk的代码符合CMD规范。使用 chunk 时,通过 require 方法加载。

    // chunk.js, 符合cmd规范
    exports.ids = [0];
    exports.modules = {
        6: (function(module, __webpack_exports__, __webpack_require__) {
            
            ...
            
        })
    
    }
    
    // 加载
    require('./chunk')
    
    
    
  • async-node

    webpack编译打包以后的代码 应用于 node环境。 非入口chunk的代码符合CMD规范。使用 chunk 时,通过 fs模块异步加载。

    // chunk.js, 符合cmd规范
    exports.ids = [0];
    exports.modules = {
        6: (function(module, __webpack_exports__, __webpack_require__) {
            
            ...
            
        })
    
    }
    
    // 加载
    let filename = require('path').join(__dirname, "/", 'chunk.js')
    require('fs').readFile(filename, 'utf-8',  function(err, content) {
        ...
    }
    
  • node-webkit

    webpack编译打包以后的代码 应用于 node-webkit环境。

    node-webkit 是一个基于 Chromium 和 Node.js 的 Web 运行环境,可让你直接在 DOM 中调用 Node.js 模块,并可使用任何现有的 Web 技术来编写本地应用。

  • electron-main

    webpack编译打包以后的代码 应用于 electron 主进程。

  • electron-renderer

    webpack编译打包以后的代码 应用于 electron render进程。

  • elentron-preload

    webpack编译打包以后的代码 应用于 electron render进程。

externals

type: string | array | object | function | RegExp

在某些情况下,我们是 不希望将依赖的类库 打包到最后输出的 bundle 中的。此时, 我们通过通过 externals配置项指定不参与编译打包的类库。

一般情况下,如果 应用程序中引入了类库,webpack 会把 类库 也 打包到输出文件 中。在 运行打包后的代码 时,会 先运行类库代码,拿到 类库 的 输出结果(exports), 然后使用 类库的结果 进行下一步操作。 ,

如果使用了 externals配置项 指定 不参与编译打包的类库,那我们在 运行打包以后的代码 时,由于 打包代码中并没有类库的代码,直接使用类库的输出结果会报错。此时我们必须 先准备好类库(先加载或者安装npm包),才能使用 类库的输出结果 进行下一步操作。

示例:

// config.js
{
    externals: {
        jquery: 'jQuery' 
    }
}

// main.js
import $ from 'jquery'

console.log($)

在上面的 示例 中,应用程序中引入的类库名(jquery) 必须和 externals配置项 中的 属性名 完全一致, 否则 externals配置项 将 无效。在 运行打包代码 时,会使用 变量jQuery 或者 通过 require('jQuery') 的方式获取 类库 的 输出结果。

使用 externals配置项 时, 会受到 output.libraryTarget配置项 和 output.globalObject配置项 的影响。

如果 output.libraryTarget 的值为 'var'、'assign', 应用程序 会通过 变量jQuery 来获取类库输出结果, 此时 当前上下文环境中 必须 存在 已定义 变量jQuery(先加载类库), 打包结果如下:

// main.js
(function(modules){
        ...
        
        return __webpack_require__(__webpack_require__.s = "./src/main.js");
        
    }({
        'main': {
            ...
            var jquery__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("jquery")
            ...
        },
        'jquery': (function(module, exports) {
            module.exports = jQuery   // jQuery在使用main.js前,必须已经存在
        })
    }))

如果 output.libarayTarget 的值为 'window', 应用程序 会通过 window["jQuery"] 来获取类库输出结果, 此时 window 对象中必须存在 已定义的属性: jQuery。

// main.js
(function(modules){
        ...
        
        return __webpack_require__(__webpack_require__.s = "./src/main.js");
        
    }({
        'main': {
            ...
            var jquery__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("jquery")
            ...
        },
        'jquery': (function(module, exports) {
            // window.jQuery在使用main.js前,必须已经存在
            (function() { module.exports = window["jQuery"]; }())   
        })
    })
})

如果 output.libarayTarget 的值为 'this', 应用程序 会通过 this["jQuery"] 来获取类库输出结果, 此时 当前上下文环境对象中 必须存在 已定义的属性: jQuery。

// main.js
(function(modules){
        ...
        
        return __webpack_require__(__webpack_require__.s = "./src/main.js");
        
    }({
        'main': {
            ...
            var jquery__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("jquery")
            ...
        },
        'jquery': (function(module, exports) {
            // this.jQuery在使用main.js前,必须已经存在
            (function() { module.exports = this["jQuery"]; }())   
        })
    })
})

如果 output.libarayTarget 的值为 'self', 应用程序 会通过 self["jQuery"] 来获取类库输出结果, 此时 webworker上下文环境对象中 必须存在 已定义的属性: jQuery。

// main.js
(function(modules){
        ...
        
        return __webpack_require__(__webpack_require__.s = "./src/main.js");
        
    }({
        'main': {
            ...
            var jquery__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("jquery")
            ...
        },
        'jquery': (function(module, exports) {
            // self.jQuery在使用main.js前,必须已经存在
            (function() { module.exports = self["jQuery"]; }())   
        })
    })
})

如果 output.libarayTarget 的值为 'global' 且 output.globalObject 的值为 'window', 应用程序 会通过 window["jQuery"] 来获取类库输出结果, 此时 window 必须存在 已定义的属性: jQuery。

// main.js
(function(modules){
        ...
        
        return __webpack_require__(__webpack_require__.s = "./src/main.js");
        
    }({
        'main': {
            ...
            var jquery__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("jquery")
            ...
        },
        'jquery': (function(module, exports) {
            // this.jQuery在使用main.js前,必须已经存在
            (function() { module.exports = this["jQuery"]; }())   
        })
    })
})

如果 output.libarayTarget 的值为 'commonjs' 、'commonjs2', 应用程序 会通过 require('jQuery') 来获取类库输出结果, 此时 jQuery包 必须已经安装。

// main.js
(function(modules){
        ...
        
        return __webpack_require__(__webpack_require__.s = "./src/main.js");
        
    }({
        'main': {
            ...
            var jquery__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("jquery")
            ...
        },
        'jquery': (function(module, exports) {
            // 在使用main.js前,jQuery包必须已经安装
           module.exports = require("jQuery");  
        })
    })
})

如果 output.libarayTarget 的值为 'amd',打包结果如下:

// main.js
define(['jQuery'], function(__WEBPACK_EXTERNAL_MODULE_jquery__) {
    return (function(modules){
        ...
        
        return __webpack_require__(__webpack_require__.s = "./src/main.js");
        
    }({
        'main': {
            ...
            var jquery__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("jquery")
            ...
        },
        'jquery': (function(module, exports) {
            module.exports = __WEBPACK_EXTERNAL_MODULE_jquery__;
        })
    }))
})

// requireConfig.js
require.config({
    paths:{
        "jQuery":'../lib/jquery.min'  // 这个配置项是必须存在的, 否则会找不到jQuery
    }
});

// 使用
require('./main.js', function() {...})

如果 output.libarayTarget 的值为 'umd',打包结果如下:

// main.js
(function(root, factory) {
    if(typeof exports === 'object' && typeof module === 'object')
        // cmd规范,应用与node环境,通过require加载类库
		module.exports = factory(require("jQuery"));  
	else if(typeof define === 'function' && define.amd)
	    // amd规范, 使用requirejs加载类库, 必须有关于jQuery的require.config配置
		define(["jQuery"], factory);  
	else {
	    // 一般为通过script元素的方式加载类库
		var a = typeof exports === 'object' ? factory(require("jQuery")) : factory(root["jQuery"]);
		for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];
	}
    
}(window, function(__WEBPACK_EXTERNAL_MODULE_jquery__) {
    return (function(modules){
        ...
        
        return __webpack_require__(__webpack_require__.s = "./src/main.js");
        
    }({
        'main': {
            ...
            var jquery__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("jquery")
            ...
        },
        'jquery': (function(module, exports) {
            module.exports = __WEBPACK_EXTERNAL_MODULE_jquery__;
        })
    }))
}))

externals配置项 的值的类型可以是 Object, 如下:

externals: {
    // 根据output.libraryTarget的值选择使用类库的方式
    jQuery: 'jQuery',  
    // 通过requirejs方式使用类库输出, 如果libraryTarget的值不是amd, 则没有意义
    vue: 'amd Vue',
    // 根据 output.libraryTarget 的值选择 加载类库时类库的名称 或者 应用类库输出结果时使用的变量
    // 如果未指定, 则为 undefined
    react: {
        // module.exports = React_var
        // 如果 libraryTarget: var 且 未指定 var: xxxx,  module.exports = undefined
        var: 'React_var',  
        // module.exports = require('React_common')
        // 如果 libraryTarget: commonjs 且 未指定 commonjs: xxxx,  module.exports = require (undefined)
        commonjs: 'React_common', 
        commonjs2: 'React_common2', 
        // define(['React_amd'], function(obj) {...})
        //  如果 libraryTarget: amd 且 未指定 amd: xxxx,  define([undefined], function(obj) {...})
        amd: 'React_amd',
        // amd、commonjs的集合
        umd: 'React_umd',
        // module.exports = window[React_window]
        // 如果 libraryTarget: window 且 未指定 window: xxxx, module.exports = window[undefined]
        window: 'React_window', 
        // module.exports = self[React_window]
        // 如果 libraryTarget: self 且 未指定 self: xxxx, module.exports = self[undefined]
        self: 'React_self',   // module.exports = self[React_self]
        // module.exports = this[React_window]
        // 如果 libraryTarget: this 且 未指定 this: xxxx, module.exports = this[undefined]
        this: 'React_this'   
    }
}

externals配置项 的值的类型可以是 string, 如:

externals: 'jQuery'

// 等价与:

externals: {
    jQuery: 'jQuery'
}

// 不支持 externals: 'amd jQuery'

externals配置项 的值的类型可以是 RegExp, 如:

externals: /^(jquery|\$)$/i

externals配置项 的值的类型可以是 function, 如:

// request 对应 import $ from 'jquery' 中的就juqery
externals: function(context, request, callback) {
    if ( /^(jquery|\$)$/i.test(request)){
      return callback(null, 'commonjs ' + request);
    }
    callback();
 }

externals配置项 的值的类型可以是 array, 数组元素的类型可以是上面的任意一种。

performance

type: object

用于配置如何展示性能提示。例如,如果一个资源超过 250kb,webpack 会对此输出一个警告来通知你。

  • hints | false | 'warning' | 'error'

    打开或关闭提示, 默认值为 'warning'。

    如果 hints 的值为 false, 关闭提示。

    如果 hints 的值为 warning, 当输出文件的体积超过指定体积时,输出 警告信息, 依然完成编译打包工作, 适用于 开发模式。

    如果 hints 的值为 error, 当输出文件的体积超过指定体积时,中断编译打包,并输出 错误信息, 适用于 生产模式。

  • maxEntrypointSize | int

    指定 入口文件 的 最大体积, 默认值为 250000 bytes。

    如果 超过最大体积 且 hints 的值 不是false, 输出 警告/错误 信息。

  • maxAssetSize | int

    指定 单个资源(包括入口文件) 的 最大体积,默认值为 250000 bytes。

  • assetFilter | function

    自定义 哪些文件的 体积超过最大体积 时,输出 警告/错误 信息。