webpack 原理、功能

86 阅读6分钟
作用理解

就目前而言,前端网页功能丰富,单页面应用(single page web application)技术流行后,JavaScript的复杂度增和需要一大堆依赖包,还需要解决Scss,Less ......新增样式的扩展写法的编译工作。

所以现代化的前端已经完全依赖于webpack的辅助了。

现在最流行的三个前端框架,可以说和webpack已经紧密相连,框架官方都推出了和自身框架依赖的webpack构建工具。

  • react.js + Webpack
  • vue.js + Webpack
  • AngluarJS + Webpack
webpack工作原理

WebPack可以看做是模块打包机:它做的事情是,分析你的项目结构,找到JavaScrip模块以及其它的一些浏览器不能直接运行的拓展语言(Scss、TypeScript等),并将其转换和打包为合适的格式供浏览器使用。在3.0出现后,Webpack还肩负起了优化项目的责任

webpack打包原理

把一切都视为模块:不管是css、JS、Image还是html都可以互相引用,通过定entry.js,对所有依赖的文件进行跟踪,将各个模块通过loader和plugins处理,然后打包在一起。

按需加载:打包过程中webpack通过Code Splitting功能将文件分为多个chunks,还可以将重复的部分单独提取出来作为commonChunk,从而实现按需加载。把所有依赖打包成一个bundle.js文件,通过代码分割成单元片段并按需加载

webpack的核心概念

一、Entry:入口,Webpack执行构建的第一步将从Entry开始,可抽象成输入。告诉webpack要使用哪个模块作为构建项目的起点,默认为./src/index.js

二、output:出口,告诉webpack在哪里输出它打包好的代码以及如何命名,默认为 ./dist

三、Module:模块,在Webpack里一切皆模块,一个模块对应一个文件。Webpack会从配置的Entry开始递归找出所有依赖的模块。

四、Chunk:代码块,一个Chunk由多个模块组合而成,用于代码合并与分割。

五、Loader:模块转换器,用于把模块原内容按照需求转换成新内容

六、Plugin:扩展插件,在Webpack构建流程中的特定时机会广播出对应的事件,插件可以监听这些事件的发生,在特定时机做对应的事情。

webpack的基本功能

一、代码转换: TypeScript编译成JavaScript、Scss 编译成css等等...... 二、文件优化:压缩JavaScript、CSS、html代码,压缩合并图片等 三、代码分割:提取多个页面的公共代码、提取首屏不需要执行部分的代码让其异步加载 四、模块合并:在采用模块化的项目有很多模块和文件,需要构建功能把模块分类合并成一个文件 五、自动刷新:监听本地源代码的变化,自动构建,刷新浏览器 六、代码校验:在代码被提交到仓库前需要检测代码是否符合规范,以及单元测试是否通过 七、自动发布:更新完代码后,自动构建出线上发布代码并传输给发布系统

gulp/grunt 与 webpack的区别

三者都是前端构建工具,grunt和gulp在早期比较流行,现在webpack相对比较是主流

一些量化的的任务还是会用gulp来处理,比如单独打包css文件。

grunt和gulp是基于任务和流(Task、Stream)的

类似jQuery,找到一个(或一类)文件,对其做一系列链式操作,更新流上的数据,整条链式操作构成了一个任务,多个任务就构成了整个web构建流程。webpack是基于入口的。

webpack会自动地递归解析入口所需要加载的所有资源文件,然后用不同的Loader来处理不同的文件,用Plugin来扩展webpack功能。

webpack解决的问题

以前开发一个html文件可能会引用十几js个文件,而且顺序还不能乱,因为他们存在依赖关系,同时对于ES6+等新语法,less,sass等css预处理都不能很好的解决......此时就需要一个处理这些问题的工具。

Loader机制的作用

webpack默认只能打包js文件,配置里module.rules的执行顺序是由后到前的; 每一个Loader都可以通过URL querystring的方式传入参数,例如 css-loader minimize中的 minimize告诉css-loader要开启css压缩

提高webpack构建速度

一、多入口情况下,使用CommonsChunkPlugin来提取公共代码

二、通过externals配置来提取常用库

三、利用DllPlugin 和 DllReferencePlugin预编译资源模块通过DllPlugin来对那些我们引用但是绝对不会修改npm包来进行预编译,再通过DllReferencePlugin将预编译的模块加载进来。

四、使用Happypack实现多线程加速编译

五、使用webpack-uglife-paralle来提升uglifyPlugin的压缩速度

六、原理上webpack-uglify-parallel采用了多核并行压缩来提升压缩速度

七、使用Tree-shaking和Scope Hoisting来剔除多余代码

webpack构建流程

Webpack的运行流程是一个串行的过程,从启动到结束会依次执行以下流程:

  • 初始化参数:从配置文件和Shell语句中读取与合并参数,取出最终的参数;
  • 开始编译:用上一步得到的参数初始化Compiler对象,加载所有配置的插件,执行对象run方法开始执行编译
  • 确定入口:根据配置中的entry找出所有的入口文件;
  • 编译模块:从入口文件出发,调用所有配置的Loader对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖文件都经过了本步骤的处理;
  • 完成模块编译:在经过第4步使用Loader翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系;
  • 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块Chunk,再把每个Chunk转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会;
  • 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。

以上过程中,Webpack会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用Webpack提供的API改变Webpack运行结果。