webpack
compiler和complation区别
compiler和complation都是继承自Tapable,compiler是每个webpack的配置,对应一个compiler对象,记录整个webpack的生命周期;
在构建过程中,每构建一次会产生一次compilation,是构建周期的产物。complation是通过compiler创建的实例,compilation中stats对象,可以得到webpack打包后的所有module,chunk,assets信息,webpack-bundle-analyzer分析打包结果的插件都是通过分析stats对象来的到分析报告的。
compiler对象包含了webpack环境所有的配置信息,包含options,loaders,plugins这些信息,这个对象在webpack启动时被实例化,它是全局唯一的,可以简单地理解为webpack实例。
compilation对象包含了当前模块资源、编译生成资源、变化的文件等。当webpack以开发模式运行时,每当检测到一个文件变化,一次新的compilation将被创建,compilation对象也提供了很多事件回调提供插件做扩展。
总结:compiler代表了整个webpack从启动到关闭的生命周期,而copilation只是代表了一次新的编译。
loader和plugin区别
loader处理更多js不能处理的东西。文件加载器,加载资源文件,并对这些文件进行一些处理,例如编译、压缩等,最终一起打包到指定的文件中。
loader执行顺序和本身的顺序是相反的,最后一个loader最先执行,第一个loader最后执行。
第一个执行的loader接收源文件内容作为参数,其他loader接收前一个执行的loader的返回值作为参数,最后执行的loader会返回此模块的js源码。
plugin增强webpack在项目自动化构建方面的能力。在webpack运行的生命周期中会广播出许多事件,plugin可以监听这些事件,在合适的时机通过webpack提供的API改变输出结果。
总结:plugin是一个扩展器,它丰富了webpack本身,针对是loader结束后,webpack打包的整个过程,它并不直接操作文件,而是基于事件机制工作,会监听webpack打包过程中的某些节点,执行广泛的任务。
插件常见应用场景:
- 自动清除dist目录,clean-webpack-plugin
- 自动生成应用所需的html文件
- 根据不同环境为代码注入类似api地址这种可能变化的部分
- 拷贝不需要参与打包的文件到输出目录
- 压缩webpack打包后的文件
- 自动发布打包结果到服务器实现自动部署
webpack的基本流程
基本流程分为三个阶段:
- 准备阶段:创建compiler和compilation对象
- 编译阶段:完成modules解析,并生成chunks
- 解析Module,主要包含创建实例、loaders应用和依赖收集
- 生成chunks,找到chunk所需要包含的modules
- 根据chunks生成最终文件
产出阶段:主要的三个步骤:模板hash更新,模板渲染chunk,生成文件。
- 初始化参数,合并配置对象
- 使用配置参数实例化compiler,注册插件,给webpack构建生命周期绑定hook
- 开始编译:执行compiler的run方法开始编译
- compiler.run方法调用compiler.compiler,在compiler内实例化一个compilation类
compilation构建打包:
- 查找入口:根据entry配置,找出全部的入口文件
- 编译模块:根据文件类型和loader配置,使用对应的loader对文件转换处理
- 解析文件的AST语法树
- 找出文件依赖关系
- 递归编译依赖的模块
递归完后得到每个文件的最终结果,根据entry配置生成代码块chunk,输出所有chunk到对应的output路径。
sheel参数优先级高于配置文件。
tapable各种hook钩子组成了webpack的生命周期:
- hook钩子对应tapable的hook
- 生命周期:webpack的执行流程,钩子实际是生命周期,类似entryOption的hook,在生命周期中entry-option
- 参与webpack流程的两个重要模块是compiler和compilation
webpack的工作流程:
webpack打包流程从读取配置文件开始,分别进怀里了准备阶段、模块产出阶段、chunks生成阶段和bundle产出阶段。在各自阶段,分别有不同的角色参与,整个webpack的打包流程是通过compiler来控制的,每次打包的过程是通过compilation来控制的。
普通模式下webpack的compiler和compilation是一一对应的关系,watch模式下,webpack的compiler会因为文件变化而产生多次打包流程,所以compiler和compilation是一对多关系,通过hook compiler的流程,可以得到每次打包过程的回调。
module、chunk和bundle的区别
源文件:module
chunk:webpack会根据文件引用关系生成chunk文件,webpack会对这个chunk文件进行一些操作。一般一个chunk对应一个Bundle.
bundle:webpack处理好chunk文件后,最后会输出bundle文件,这个bundle文件包含了经过加载和编译的最终源文件,所以它可以直接在浏览器运行。
css-loader和style-loader区别
css-loader指挥把css模块加载到js代码中,并不会使用这个模块。
配置多个loader,从后往前执行的
hash、chunkhash、contenthash
hash:和项目构建相关的,同一次构建过程中生成的哈希都是一样的,没有办法区分文件是否更新。通过webpack构建之后,生成对应文件名自动带上对应的md5值,文件内容改变后对应文件hash值也会改变,对应html引用地址也会改变,触发cdn服务器从源服务器上拉去对应数据,进而更新本地缓存。
chunkhash:根据不同的入口文件进行依赖文件解析、构建对应的chunk,生成对应的哈希值。只要不改动公共库的代码,就可以保证其哈希值不受影响。
contenthash:只有文件的内容变了,contenthash值才会改变。通常把项目中css都抽离出来对应的css文件来加以引用,修改了css内容并没有修改js内容,使用chunkhash会重新进行打包,使用contenthash只会重新打包css模块,js不用重新打包。
模块化
commonjs同步代码,在浏览器端会出现多个请求一起发送的情况,应用运行效率低下。nodejs
AMD规范,使用define来进行定义,requirejs,异步加载,模块多了之后难以管理。
es modeule:浏览器端规范,服务端commonjs规范。
es modeule的问题,存在环境兼容性问题,需要使用bable进行转换。
模块打包工具的出现:将css html等资源进行打包。
模块化只是在开发阶段需要,中间需要编译工具对这些模块进行打包,最终生产阶段只需要使用即可。
webpack打包后会将代码生成一个自执行函数,将模块使用参数的方式传入,以此来生成一个私有的作用域。
InstalledModeules = {} //缓存加载过的模块
function __webpack_require__(moduleid){}//用于加载指定模块的函数
retutn __webpack_require__(__webpack_require_.s=0)//开始加载代码中的入口模块
es模块和commonjs模块的区别
commonjs是对模块的浅拷贝,可以对commonjs重新赋值
es module是对模块的引用,只存只读,不能改变其值,指针指向不能变,类似const;
import的接口是只读的,只能修改其变量值,但是可以改变变量内部指针指向,重新赋值会编译报错。
共同点:都可以对引入的对象进行赋值,对对象内部属性的值可以改变。
webpack打包结果分析
//整体是一个自执行函数
(()=>{
//包含引入的所有模块数据
var __webpack_modules__ = []
//用来在导出对象上添加一个标记
__webpack_require__.r = () => {}
})()