# webpack原理

原理

webpack是一个javascript文件的静态模块打包器。

webpack就像一个生产线,要经过一系列流程处理后才能将源文件转换为要输出的结果。这条生产线上的每一个流程的功能都是单一的,多个流程之前有依赖关系,只有完成当前处理后才能交给下一个流程处理。插件就像是插入到生产线中的一个功能,在特定的时机对生产线上的资源做处理。webpack内部通过Tapable来组织这条生产线。在运行的过程中会广播对应的事件,插件只需要监听自己所关心的事件,就能加入到这条生产线中,去改变生产线的运作。

webpack的事件流机制保证了插件的有序性,使得整个系统的扩展性很好。

# webpack 构建流程

构建流程

webpack的打包过程是一个串行的过程,从启动到结束,会一个接一个流程的走下去,最终打包出需要的bundle。下面就是要执行的流程

  • 1、初始化参数:从配置文件和Shell语句中读取并合并参数,得出最终的配置对象
  • 2、开始编译:用上一步得到的得到的参数初始化Compiler对象,加载所有配置的插件,执行对象的run方法,开始编译
  • 3、确定入口:根据配置中的entry找到所有入口文件
  • 4、构建模块:从入口文件开始,开始构建模块,调用所有配置的loader对模块进行处理,使用acorn这个库生成ast语法树,再遍历ast语法树收集该模块依赖的模块,再处理依赖的模块,直到所有模块都经过构建。
  • 5、输出资源:通过compilation.seal方法依次对每个模块和chunk进行整理,生成编译后的源码,合并、拆分。每一个chunk对应一个入口文件,开始生成最后的js。再通过MainTemplate.render(处理入口文件模块)和ChunkTemplate.render(处理异步加载的模块)方法将模块处理成带有__webpack__require()的格式,然后将处理完的js输出到outputpath

对应的webpack事件

  • entry-options:初始化参数
  • compile:开始编译
  • make:分析入口文件,创建模块对象
  • build-module:构建模块,调用loader处理模块
  • after-compile:完成所有的模块构建,结束编译
  • emitCompiler开始输出生成的assets,插件有最后的机会修改assets
  • after-emit:输出完成

# webpack打包优化

# 优化打包速度

# 开启tree-shaking

开启 tree-shaking 的方式

  • 1、将mode改为production模式,将会自动开启tree shakinguglifyjs
  • 2、通过optimization配置去开启一些优化的功能, 又叫Scope Hoisting
    module.exports = {
      mode: 'none',
      entry: './src/index.js',
      output: {
        filename: 'bundle.js'
      },
      optimization: {
        // 模块只导出被使用的成员
        usedExports: true, // 用来标记 '枯树叶'
        // 尽可能合并每一个模块到一个函数中 提升运行效率
        concatenateModules: true, 
        // 压缩输出结果
        minimize: true // 用来摇下 '枯树叶',
        sideEffects: true // 要去除没有副作用的引用
      }
    }
    

tree shaking还需要配置一些其他的东西:

  • 1、tree shaking依赖的是es6 module规范,而@babel/preset-env会将es6 module转化为commonjs代码,这样tree shaking就不会生效,所以需要在@babel/preset-env这个插件中将module改为false,不转为commonjs代码。
{
  "presets": [
    ["@babel/preset-env",
      {
        "modules": false // 不转为commonjs
      }
    ]
  ]
}
  • 2、sideEffects:用来标识代码是否有副作用或者哪些代码有副作用,从而为tree shaking提供更大的压缩空间。需要在package.json中写明所有文件都没有副作用还是哪些文件有副作用。
"sideEffects": false // 表示所有文件都没有副作用
"sideEffects": [ // 表示哪些文件是有副作用的
  "./src/extend.js",
  "*.css"
]

# 缩小文件查找范围

TIP

  • 1、采用include exclude来减少loader搜索时的转换时间。
  • 2、采用alias取别名的方式来缩小import vue时,webpack的查找范围,不用的话webpack就会采用向上递归的方式去node_modules目录下找。
  • 3、增加noParse, 告诉webpack不解析模块中的依赖, 比如jquery、moment
  • 4、采用webpack.IgnorePlugin 插件,忽略掉第三方包的指定目录,比如moment的语言包
  • 5、增加extensions字段定义文件后缀,告诉webpack优先查找哪些文件

# 用thread-loader开启多进程loader转换

TIP

thread-loader这个loader放在其他loader的前面(左边),放置在这个loader之后的loader就会在一个单独的worker池中worker pool运行,当项目比较复杂,文件比较多时,添加这个loader会减少转换时间。如果项目比较简单,文件比较少,反而会增加时间。

# 配置loader缓存

TIP

babel-loader中可以通过设置cacheDirectory来开启缓存,babel-loader?cacheDirectory=true,就会将每次的编译结果写进硬盘文件,不支持cacheDirectory的可以使用cache-loader,再次构建会先比较,如果文件没有改变则会直接使用缓存。

# 优化体积

# 开启Scope Hoisting

TIP

Scope Hoisting也叫作用域提升,是在webpack3中新推出的功能。Scope Hoisting的原理是将所有的模块按照引用顺序放在一个函数作用域里,然后适当的重名一些变量防止命名冲突,以此减少了代码运行时作用域,从而减少了内存。这个功能在production模式下默认开启,也是只支持es6 module,不支持commonjs

上次更新: 7/17/2021, 8:17:34 PM