• 浅析webpack中mode的取值及不同取值的作用/打包方式及摇树优化(tree-shaking)的理解


      Mode 用来指定当前的构建环境是:production、development、还是none。设置 mode 可以使用 webpack 的内置函数,默认值是 production。

      mode 的内置函数功能如下:

      模式(mode):提供 mode 配置选项,告知 webpack 使用相应模式的内置优化。

      用法:只在配置中提供 mode 选项:

    module.exports = {
        mode: 'production'
    };

      或者从 CLI 参数中传递:

    webpack --mode=production

    一、mode取值

    1、development:会将 process.env.NODE_ENV 的值设为 development。启用 NamedChunksPlugin 和 NamedModulesPlugin。

    // webpack.development.config.js
    module.exports = {
    + mode: 'development'
    - plugins: [
    -  new webpack.NamedModulesPlugin(),
    -  new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("development") }),
    - ]
    }
    

    2、production:会将 process.env.NODE_ENV 的值设为 production。启用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin 和 UglifyJsPlugin。

    // webpack.production.config.js
    module.exports = {
    + mode: 'production',
    - plugins: [
    -  new UglifyJsPlugin(/* ... */),
    -  new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("production") }),
    -  new webpack.optimize.ModuleConcatenationPlugin(),
    -  new webpack.NoEmitOnErrorsPlugin()
    - ]
    }

      production模式下会启用UglifyJsPlugin插件(移除未使用的内容和文件压缩)

    二、mode取值的区别

      分别用 production 和 development 打包,编译的区别如下:

    1、development打包后,一些没有依赖的方法、变量、文件会保留;而 production 则会移除。

    2、production 打包后,代码会进行压缩,比 development 的文件小。

    三、mode不同值的打包

    1、none模式下的模块打包

      在没有任何优化处理的情况下,按照webpack默认的情况下打包出模块,它会将模块打包至数组之中,调用模块的时候,就是直接调用模块在此数组中的一个序号,然后没有进行压缩、混淆之类的优化。

      但是无论是在开发环境development下,还是在正式环境production下,这个代码都是不过关的。对于开发环境,此代码可读性太差,对于正式环境,此代码不够简洁。因此为了减少一次重复操作,webpack4提供的development/production可以很大程度上帮我们做一大部分的事情,我们要做的,就是在这些事的基础上增加功能。

    2、development模式下,webpack做了哪些打包工作

      development是告诉程序,我现在是开发状态,也就是打包出来的内容要对开发友好。在此mode下,就做了以下插件的事情,其他什么都没有做,所以这些插件可以省略。

    //webpack.config.js
    module.exports = {
      mode:'development',
      devtool:'eval',
      plugins: [
        new webpack.NamedModulesPlugin(),
        new webpack.NamedChunksPlugin(),
        new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("development") })
      ]
    }

      我们看看NamedModulesPlugin和NamedChunksPlugin这两个插件都做了啥,原本我们的webpack并不会给打包的模块加上名字,一般都是按照序号来,从0开始,然后加载第几个模块,这个对机器来说无所谓,查找载入很快,但是对于人脑来说就是灾难了,所以这个时候给各个模块加上姓名,便于开发的时候查找。

      没有NamedModulesPlugin,模块就是一个数组,引用也是按照在数组中的顺序引用,新增模块都会导致序号的变化。有了NamedModulesPlugin,模块都拥有了姓名,而且都是独一无二的key,不管新增减少多少模块,模块的key都是固定的。

      除了NamedmodulesPlugin,还有一个NamedChunksPlugin,这个是给配置的每个chunks命名,原本的chunks也是数组,没有名字。NamedChunksPlugin其实就是提供了一个功能,你可以自定义chunks的名字,假如我在不同的包中有相同的chunk名,怎么办?这个时候就要在进行进一步的区分了,我们可以用所有的依赖模块名加上本模块名,因为Chunk.modules已经废弃了,现在用其他的方法来代替chunk.mapModules,然后重命名chunk的名字

    new webpack.NameChunksPlugin( (chunk) => {
       return chunk.mapMudoles( m => {
          return path.relative(m.context,m.request);
       }).join('_')
    })

      总结:development也就给我们省略了命名的过程,但是其他还是要我们自己加的。

    3、production

      在正式版本中,所省略的插件们,如下所示,我们会一个个分析

    //webpack.config.js
    module.exports = {
       mode:'production',
       plugins: [
          new UglifyJsPlugin(/*...*/),
          new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("production") }),
          new webpack.optimize.ModuleConcatenationPlugin(),
          new webpack.NoEmitOnErrorsPlugin()
       ]
    }

    (1)UglifyJsPlugin

      我们第一个需要处理的就是混淆&压缩js了吧,这个时候就要请出UglifyJs了,他在webpack中的名字是:const UglifyJsPlugin = require('uglifyjs-webpack-plugin');这样,就可以使用他了。不过 new UglifyJsPlugin() 这个插件我们可以在 optimize 中配置,效果是一样的,那么我们是不是不用在导入一个新的插件了,这样反而会拖慢webpack的打包速度

    optimization: {
       minimize: true
    }

      将插件去除,混淆压缩放入optimization,这样webpack速度快的起飞了,只有第一次打包会慢,之后在打包就快了

    (2)ModuleConcatenationPlugin

      webpack.optimize.ModuleConcatenationPlugin() 这个插件的作用是什么呢?此插件仅适用于由webpack直接处理的ES6模块,在使用转译器(transpiler)时,你需要禁用对模块的处理(例如Babel中的modules选项)。

    (3)NoEmitOnErrorsPlugin

      最后一个插件就是webpack.NoEmitOnErrorsPlugin(),这个就是用于防止程序报错,就算有错误也给我继续编译,很暴力的做法。

    四、摇树优化

    1、概念

      一个模块可能有多个方法,只要其中的某个方法使用到了,则整个文件都会被打包到bundle中去,tree shaking 就是只把用到的的方法打入 bundle,没用到的方法会在 uglify 阶段被擦除掉。
    • 代码不会被执行,不可到达
    • 代码执行的结果不会被用到
    • 代码只会影响死变量(只写不读)
      比如:
    if (false) {
      console.log('这段代码永远不会执行')
    }

      摇树是一种消除死代码的方法,应用程序的依赖项是树状结构,树的每个节点都代表了一个依赖项,这些依赖项为应用程序提供了不同的功能,通过消除不需要的依赖项来减少树的节点,这个过程叫摇树。只能适用于es6模块的导入,不适用于commonJS的require,因为es6的模块是静态引入。

    (1)应用程序采用按需加载的方式导出,没有被引用的模块不会被打包进来,减少包大小,缩小应用的加载时间。

    (2)es6的模块是静态分析

    (3)webpack自带tree shaking,只需要加些配置

    // webpack.config.js
    optimization: {
        // 使用tree-shaking
        usedExports: true, // mode为production时,默认开启
    },

    2、示例

    // print.js:导出了两个函数
    export const add = (a, b) => {
      console.log(a + b);
    }
    export const minus = (a, b) => {
      console.log(a - b);
    }
    
    // index.js:只引用了其中一个函数
    import { add } from "./print";
    add(1, 2);

      tree-shaking结果:

      mode:development,依然将未引入的函数打包了,只是有一句注释标记未被引用,这样做是为了在开发模式下调试方便,如果把代码删除,程序报错时,位置定位不准。

      mode:production,打包后的代码被压缩,且未被引入的函数没有打包。

    参考文章:https://blog.csdn.net/qq_40677590/article/details/106817327

  • 相关阅读:
    使用java中的注解@see
    MacOS软件默认安装路径
    学习MACD指标
    go CD 用虚拟机快速增加一个新agent
    git推送本地分支到远程分支
    git如何切换远程仓库
    git命令查看远程分支
    Java 学习札记(一)JDK安装配置
    Oracle 基本操作符
    C# 常用控件属性及方法介绍
  • 原文地址:https://www.cnblogs.com/goloving/p/15002124.html
Copyright © 2020-2023  润新知