在前两节的基础和高级配置中,我们学习了怎么样去配置Webpack实现不同目的的构建打包,其中多次提及了entry,loader,plugin,module,chunk,bundle等这样的名词,那么它们都是些什么?有什么区别和联系?
module,chunk和bundle
在官网里是这样介绍Webpack的:
我们在官网首页也可以看到这么一个图片去阐述Webpack的作用:
我们可以通过这张图去理解module,chunk和bundle的区别和联系:
- 其中左边部分可以理解为
module,就是各个源码文件,webpack的世界中,一切皆模块,只要可以被引用的都是模块。 - 中间部分就是
chunk,多模块合并成的,如:entry,import(),splitChunk等都会产生chunk,做依赖分析 。 - 右边部分就是
bundle,即最终输出的文件。 
Webpack的结构
先来看一下Webpack配置文件输出的配置对象的完整结构:
|-- webpack.config.js
    |-- entry # 定义构建依赖图的入口
    |-- output # 定义输出bundle的名字和位置
    |-- module # 定义loader
    |-- plugins # 定义插件
    |-- mode # 选择开发 or 生成模式
    |-- devServer # 开发环境启动服务
    |-- optimization # 手动配置优化项
entry(入口)
__入口起点(entry point)__指示 webpack 应该使用哪个模块,来作为构建其内部 依赖图(dependency graph) 的开始。进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的。
在前两节介绍了entry的两种配置方式:
单入口
用法: entry: string | [string]
module.exports = {
  entry: './path/to/my/entry/file.js'
};
多入口
用法:entry: { <entryChunkName> string | [string] } | {}
每一对键值对都是一个单独入口,是独立分离的依赖图,因此会产生不同的chunk。
module.exports = {
  entry: {
    app: './src/app.js',
    adminApp: './src/adminApp.js'
  }
};
为什么需要多入口?
如果我们的程序是多页面程序,那么就需要在Webpack配置多入口。在多页面应用程序中,server 会拉取一个新的 HTML 文档给客户端。页面重新加载此新文档,并且资源被重新下载。然而,使用 optimization.splitChunks 为页面间共享的应用程序代码创建 bundle。由于入口起点数量的增多,多页应用能够复用多个入口起点之间的大量代码/模块,从而可以极大地从减少重复代码的数量,减少最终打包后的体积。
output(输出)
output 属性告诉 webpack 在哪里输出它所创建的 bundle,以及如何命名这些文件。
注意,即使可以存在多个 entry 起点,但只能指定一个 output 配置。
单入口
module.exports = {
  output: {
    filename: 'bundle.js',
  }
};
此配置将一个单独的 bundle.js 文件输出到 dist 目录中。
多入口
如果配置中创建出多于一个 chunk,则应该使用 占位符来确保每个文件具有唯一的名称。
module.exports = {
  entry: {
    app: './src/app.js',
    search: './src/search.js'
  },
  output: {
    filename: '[name].js',
    path: __dirname + '/dist'
  }
};
loader
webpack 只能理解 JavaScript 和 JSON 文件。loader 让 webpack 能够去处理其他类型的文件,并将它们转换为有效模块,以供应用程序使用,以及被添加到依赖图中。
在 webpack 的配置中,loader 有两个属性:
test:识别出哪些文件会被转换。use:定义出在进行转换时,应该使用哪个 loader。
module.exports = {
  module: {
    rules: [
      { test: /\.css$/, use: 'css-loader' },
      { test: /\.ts$/, use: 'ts-loader' }
    ]
  }
};
plugin(插件)
loader 用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。包括:打包优化,资源管理,注入环境变量。 插件目的在于解决 loader 无法实现的其他事。 想要使用一个插件,只需要 require() 它,然后把它添加到 plugins 数组中。多数插件可以通过选项(option)自定义。也可以在一个配置文件中因为不同目的而多次使用同一个插件,这时需要通过使用 new 操作符来创建一个插件实例。
onst HtmlWebpackPlugin = require('html-webpack-plugin'); // 通过 npm 安装
const webpack = require('webpack'); // 用于访问内置插件
module.exports = {
  module: {
    rules: [
      { test: /\.txt$/, use: 'raw-loader' }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({template: './src/index.html'})
  ]
};
原理浅析
webpack 插件是一个具有 apply 方法的 JavaScript 对象。apply 方法会被 webpack compiler 调用,并且在整个编译生命周期都可以访问 compiler 对象。
ConsoleLogOnBuildWebpackPlugin.js:
const pluginName = 'ConsoleLogOnBuildWebpackPlugin';
class ConsoleLogOnBuildWebpackPlugin {
  apply(compiler) {
    compiler.hooks.run.tap(pluginName, compilation => {
      console.log('webpack 构建过程开始!');
    });
  }
}
module.exports = ConsoleLogOnBuildWebpackPlugin;
mode(模式)
通过选择 development, production 或 none 之中的一个,来设置 mode 参数,就会启用 webpack 内置在相应环境下的优化。其默认值为 production。
用法:string = 'production': 'none' | 'development' | 'production'
| 模式 | 功能 | development | 会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 development. 为模块和 chunk 启用有效的名。 | production | 会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 production。为模块和 chunk 启用确定性的混淆名称,FlagDependencyUsagePlugin,FlagIncludedChunksPlugin,ModuleConcatenationPlugin,NoEmitOnErrorsPlugin 和 TerserPlugin 。 | none | 不使用任何默认优化选项 | 
|---|
optimization(优化)
从 webpack 4 开始,会根据你选择的mode来执行不同的优化,不过所有的优化还是可以手动配置和重写。
下面介绍一下我们前两节的配置使用到的optimization相关插件。
minimizer(压缩)
通过提供一个或多个定制过的 TerserPlugin 实例, 覆盖默认压缩工具(minimizer),将产出代码进行压缩。
用法:[TerserPlugin] 或 [function (compiler)]
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
  optimization: {
    minimizer: [
      // 压缩JS
      new TerserPlugin({
        cache: true,
        parallel: true,
        sourceMap: true, // 如果在生产环境中使用 source-maps,必须设置为 true
        terserOptions: {
          // https://github.com/webpack-contrib/terser-webpack-plugin#terseroptions
        }
      }),
      // 压缩CSS
      new OptimizeCSSAssetsPlugin({}),
    ],
  }
};
splitChunks(分割代码块)
在Webpack 4以前,chunks都是通过依赖图进行连接的,用CommonsChunkPlugin避免重复的依赖的chunk,但是想要更进一步的优化是没有其他任何办法的。
Webpack 4以后,CommonsChunkPlugin删除了,而改为optimization.splitChunks,来自定义代码块的分割,实现更精细的代码分割和复用,更好地完成按需加载。
默认值
webpack将根据以下条件自动分割代码块chunk:
- 可以共享新块,或者模块来自node_modules文件夹
 - 新的块 >= 20kb(在min + gz之前)
 - 当按需加载块时,并行请求的最大数量 <= 30
 - 初始页面加载时并行请求的最大数量 <= 30
 
自定义
我们来回顾一下前两节optimization.splitChunks的配置:
chunks:选择哪些块进行优化
取值:string = 'all' | 'async' | 'initial'
'async': 异步 chunk,只对异步导入的文件处理'initial': 入口 chunk,对于异步导入的文件不处理'all': 在异步和非异步块之间也可以共享块
cacheGroups:缓存分组
cacheGroups结构是一个对象,每个属性就对应于一个chunk的配置,key就是这个chunk的名字,可配置的项有:
name:chunk的名字priority:一个模块可以属于多个缓存组,优化将优先选择具有较高的缓存组priority,数值越大,优先级越高test:控制此缓存组选择的模块,省略它会选择所有模块。它可以匹配绝对模块资源路径或块名称。匹配块名称时,将选择块中的所有模块minSize:模块的大小限制minChunks:模块最少复用的次数,只有大于等于这个值才会被抽取出来
module.exports = {
 optimization: {
    // 分割代码块
    splitChunks: {
      chunks: 'all',
      // 缓存分组
      cacheGroups: {
          // 第三方模块
          vendor: {
              name: 'vendor', // chunk 名称
              priority: 1, // 权限更高,优先抽离
              test: /node_modules/,
              minSize: 0,  // 大小限制
              minChunks: 1  // 最少复用过几次
          },
          // 公共的模块
          common: {
              name: 'common', // chunk 名称
              priority: 0, // 优先级
              minSize: 0,  // 公共模块的大小限制
              minChunks: 2  // 公共模块最少复用过几次
          }
      }
    }
  }
};
      常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
 - 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
 
- 提示下载完但解压或打开不了?
 
- 找不到素材资源介绍文章里的示例图片?
 
- 模板不会安装或需要功能定制以及二次开发?
 
                    
    
发表评论
还没有评论,快来抢沙发吧!