webpack

79 阅读7分钟

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 = () => {}
})()