最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • Webpack从手把手配置到原理浅析(三):基本概念

    正文概述 掘金(ScarlettLL)   2021-01-03   760

    在前两节的基础和高级配置中,我们学习了怎么样去配置Webpack实现不同目的的构建打包,其中多次提及了entry,loader,plugin,module,chunk,bundle等这样的名词,那么它们都是些什么?有什么区别和联系?

    module,chunk和bundle

    在官网里是这样介绍Webpack的:

    我们在官网首页也可以看到这么一个图片去阐述Webpack的作用: Webpack从手把手配置到原理浅析(三):基本概念 我们可以通过这张图去理解module,chunkbundle的区别和联系:

    • 其中左边部分可以理解为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 只能理解 JavaScriptJSON 文件loader 让 webpack 能够去处理其他类型的文件,并将它们转换为有效模块,以供应用程序使用,以及被添加到依赖图中。 在 webpack 的配置中,loader 有两个属性:

    1. test :识别出哪些文件会被转换。
    2. 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, productionnone 之中的一个,来设置 mode 参数,就会启用 webpack 内置在相应环境下的优化。其默认值为 production。 用法:string = 'production': 'none' | 'development' | 'production'

    模式功能
    development会将 DefinePluginprocess.env.NODE_ENV 的值设置为 development. 为模块和 chunk 启用有效的名。production会将 DefinePluginprocess.env.NODE_ENV 的值设置为 production。为模块和 chunk 启用确定性的混淆名称,FlagDependencyUsagePluginFlagIncludedChunksPluginModuleConcatenationPluginNoEmitOnErrorsPluginTerserPluginnone不使用任何默认优化选项

    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的名字,可配置的项有:

    • namechunk的名字
    • 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  // 公共模块最少复用过几次
              }
          }
        }
      }
    };
    

    起源地下载网 » Webpack从手把手配置到原理浅析(三):基本概念

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元