第834期webpack编译流程漫谈

Posted 前端早读课

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第834期webpack编译流程漫谈相关的知识,希望对你有一定的参考价值。

前言

今天是节前最后一篇,我们节后(下星期)见。前两天有看见@波波发的一篇新闻稿,说webpack官方中文社区成立,有兴趣的可以去了解下。最后一天早读文章来自@slashhuang授权分享。


正文从这开始~


weback在web构建工具的激烈竞争中逐渐脱引而出。 无论是编译速度、报错提示、可扩展性等都给前端开发者耳目一新的感觉。本篇文章是个人对webpack的一点小研究总结。


webpack在开发者社区的反馈


类似gulp把自己定位为stream building tools一样,webpack把自己定位为module building system。在webpack看来,所以的文件都是模块,只是处理的方式依赖不同的工具而已。


webpack同时也把node的IO和module system发挥的淋漓尽致。 webpack在配合babel(ES6/7)和tsc(typescript)等类似DSL语言预编译工具的时候,驾轻就熟,为开发者带来了几乎完美的体验。


webpack整体架构(以webpack.config主要部分进行划分)

  • entry: 定义整个编译过程的起点

  • output: 定义整个编译过程的终点

  • module: 定义模块module的处理方式

  • plugin 对编译完成后的内容进行二度加工

  • resolve.alias 定义模块的别名


webpack的核心module


无论你是jsx,tsx,html,css,scss,less,png文件,webpack一视同仁为module。并且每个文件[module]都会经过相同的编译工序 loader==> plugin。


关于以上这点,以如下一个简单的webpack.config文件为例。看下webpack会做什么


webpack是如何处理如上webpack.config文件解析


1. 确定webpack编译上下文context


默认情况下就是node启动的工作目录process.cwd(),当然也可以在配置中手动指定context。


webpack在确定webpack.config中entry的路径依赖时,会根据这个context确定每个要编译的文件(assets)的绝对路径。


2.entry和output 确定webpack的编译起点和终点


顾名思义,entry定义webpack编译起点,入口模块。 对应的结果为compolation.assets


output定义webpack编译的终点,导出目录


3. module.loaders 和 module.test 确定模块预编译处理方式


以babel为例,当webpack发现模块名称匹配test中的正则/js[x]?的时候。


它会将当前模块作为参数传入babel函数处理,babel([当前模块资源的引用])。


函数执行的结果将会缓存在webpack的compilation对象上,并分配唯一的id 。


以上的这一步,非常非常关键。唯一的id值决定了webpack在最后的编译结果中,是否会存在重复代码。


而缓存在compilation对象上,则决定了webpack可以在plugin阶段直接拿取模块资源进行二度加工。


4. plugin阶段贯穿于webpack的整个编译流程,一般用来做一些优化操作。


比如webpack.ProvidePlugin,它会在对编译结果再加工的操作过程中进行自定义的变量注入,当模块中碰到比如_这个变量的时候,webpack将从缓存的module中取出underscore模块加载进引用_的文件(compilation.assets)。


比如WebpackNotifierPlugin,它会在编译结果ready的时通知开发者,output已经就绪。


5.resolve.alias的作用就是对module模块提供别名,并没有什么特殊的。


【副作用】 webpack编译过程中的电脑卡慢?


在weback经历以上流程的时候,查看你的内存,你会发现,内存飙升!!!


这一般都是loader阶段,对DSL进行AST抽象语法树分析的时候,由于大量应用递归,内存溢出的情况也是非常常见。


output目录不是一个渐进的编译目录,只有在最后compilation结果ready的时候,才会写入,造成开发者等待的时候,output目录始终为空。


【webpack编译对象compilation】 webpack将编译结果导出到output是怎么做到的


如上,webpack在plugin结束前,将会在内存中生成一个compilation对象文件模块tree。


这个阶段是webpack的done阶段 : webpack写入output目录的分割点。


这棵树的枝叶节点就是所有的module[由import或者require为标志,并配备唯一moduleId],


这棵树的主枝干就是所有的assets,也就是我们最后需要写入到output.path文件夹里的文件内容。


最后,这个compilation对象也是所有webpackPlugin的处理的时候的arguments。


总结


对于开发者来说,整体而言webpack的编译过程细节比较多,但是大体的框架还是比较直观。


里面涉及到的类似DSL,AST的概念及模块缓存等等,在构建工具中还是比较常见的,配合watch模式,debug模式,对于开发者来说实在是一大利器。


一切文件皆为模块也和react的一切dom都可以变为JS一样,对前端世界带来了新的开发理念。


最后,曾经分享过的webpack相关文章:




关于本文

原文:https://github.com/slashhuang/blog/issues/1

以上是关于第834期webpack编译流程漫谈的主要内容,如果未能解决你的问题,请参考以下文章

webpack第2期webpack打包编译性能测试工具及用法

第1075期webpack 应用编译优化之路

第802期 Webpack从入门到上线

第1498期webpack loader机制源码解析

第1147期webpack 为什么这么难用?

第657期彻底解决Webpack打包性能问题