Webpack

151 阅读8分钟

整理Webpack 以及前端一些常用知识

Webpack

webpack 是一种前端资源构建工具, 一个静态模块打包器(module bundler)。它将根据模块的依赖关系进行静态分析, 打包生成对应的静态资源(bundle)。比如将less/sass转换成css,ES6/7转换成浏览器能识别的语法。底层是通过Node.js编写。

分为五个模块:1)Entry(入口,打包的起点,形成chunk),2)Output(输出bundle),Loader(转换文件),Plugins(注入钩子,也可以转换文件),Mode(模式development和production)

Webpack懒加载和预加载:懒加载通过import放到异步函数中(onclick等),预加载在浏览器空闲了再去加载(webpackPrefetch:true)。

Webpack中loader和plugins的区别

loader是转换文件。plugins是插件,可以对打包进行优化和压缩。

常用的plugins:1)DllPlugin,将所有第三方库的依赖打包到一个bundle的dll文件中。2)splitChunks,分割代码块。3)htmlWebpackPlugin(pwa)。 常用的loader: babel-loader, image-loader: 图片压缩, less-loader, sass-loader。

WebPack作用

  1. 模块打包。 将不同模块的文件打包整合在一起,并且保证它们之间的引用正确,执行有序。
  2. 编译兼容。Loader可以编译转换诸如.less, .vue, .jsx这类在浏览器无法识别的格式文件。
  3. 能力扩展。按需加载,代码压缩等一系列功能。

Webpack按需加载

JSONP

WebPack打包流程

  1. 读取webpack的配置参数
  2. 启动webpack,创建Compiler对象并开始解析项目
  3. 从入口文件(entry)开始解析,并且找到其导入的依赖模块,递归遍历分析,形成依赖关系树
  4. 对不同文件类型的依赖模块文件使用对应的Loader进行编译,最终转为Javascript文件
  5. 整个过程中webpack会通过发布订阅模式,向外抛出一些hooks,而webpack的插件即可通过监听这些关键的事件节点,执行插件任务进而达到干预输出结果的目的。

主要依赖于compiler和compilation两个核心对象。compiler对象是一个全局单例,他负责把控整个webpack打包的构建流程。compilation对象是每一次构建的上下文对象,它包含了当次构建所需要的所有信息,每次热更新和重新构建,compiler都会重新生成一个新的compilation对象,负责此次更新的构建过程。

而每个模块间的依赖关系,则依赖于AST语法树。每个模块文件在通过Loader解析完成之后,会通过acorn库生成模块代码的AST语法树,通过语法树就可以分析这个模块是否还有依赖的模块,进而继续循环执行下一个模块的编译解析。 最终Webpack打包出来的bundle文件是一个IIFE(立即调用)的执行函数。

Webpack热更新

模块热替换(hot module replacement 或 HMR)是 webpack 提供的最有用的功能之一。它允许在运行时更新所有类型的模块,而无需完全刷新

  1. 开启webpack热更新,设置 HotModuleReplacementPlugin
plugins: {
    HotModuleReplacementPlugin: new webpack.HotModuleReplacementPlugin()
}
  1. HMR runtime 通过HotModuleReplacementPlugin 已经注入到我们 chunk 中了
  2. 开启一个Bundle Server,还开启了 HMR Server,主要用来和 HMR Runtime 中通信
  3. 在编译结束的时候,通过 compiler.hooks.done,监听并通知客户端
  4. 客户端接收到之后,就会调用 module.hot.check 等,发起 http 请求去服务器端获取新的模块资源解析并局部刷新页面

优化页面加载时间

白屏时间: 用户点击链接或输入url到页面出现的时间。白屏时间对用户的体验和耐心,有研究说页面渲染时间大于3秒会流失大部分用户。 影响白屏时间:

  • DNS Lookup: 浏览器从DNS服务器中进行域名查询。此时如果有CDN,就会向CDN请求资源。(DNS)
  • TCP 三次握手,利用TCP自带的机制提供可靠的数据传输服务。(校验和,序列号,确认应答,超时重传,连接管理,流量控制,拥塞控制。)
  • TCP连接成功后,Web服务器接收请求,开始处理响应数据。(服务端优化,redies缓存,强缓存,协商缓存,数据库存储优化,GZIP压缩等等)
  • 客户端解析渲染页面,JS会阻塞DOM的解析和渲染,CSS会阻塞DOM渲染。(尽可能精简HTML代码结构,优化CSS结构,合理放置JS或开启异步)
  • script开启defer/ async。 defer是再JS加载完后去执行,async是空闲时执行。

CDN(内容分发网络)

内容分发网络(Content delivery network或Content distribution network,缩写:CDN)是指一种通过互联网互相连接的电脑网络系统,利用最靠近每位用户的服务器,更快、更可靠地将音乐、图片、视频、应用程序及其他文件发送给用户,来提供高性能、可扩展性及低成本的网络内容传递给用户。

为什么需要CDN: 让终端用户离服务器更近,提高访问速度。HTTP传输时延对web的访问速度的影响很大,在绝大多数情况下是起决定性作用的,这是由TCP/IP协议的一些特点决定的。物理层上的原因是光速有限、信道有限,协议上的原因有丢包、慢启动、拥塞控制等。提高访问速度直观的方式就是多设置几个服务器,让终端用户离服务器更近。CDN是一共公共服务,有很多台位于不同地域,接入不同运营商的服务器,本质是让用户访问到CDN服务器,不用直接访问网站。

CDN原理: CDN做了两件事:一是让用户访问最近节点,二是从缓存或者源站获取资源。CDN有一个源站的概念,源站就是网站真实服务器,从源站获取资源称为回源。 CDN.png CDN访问流程:比如访问Site not found · GitHub Pages

  • 浏览器检查本地有无缓存,有则使用,没有向DNS查询,或者一个CNAME记录,igithub.map.fastly.ne
  • 向这个CNAME进行DNS查询,返回IP地址,这一步给出了离用户最新的边缘节点
  • 浏览器根据返回的IP,进行HTTP请求
  • 边缘服务器检查自己的cache里有没有请求的资源,有则返回给用户,没有则向CDN中心服务器请求
  • CDN中心服务器检查自己的cache里面有没有这个资源,有则返回给边缘服务器,没有则回源;
  • 中心服务器把http请求发到源站地址上,源站返回后返回给请求方;

sourceMap

sourceMap是一项将编译、打包、压缩后的代码映射回源代码的技术,用于在开发中找错。本质上webpack会生成一个map.js(包括sources, name, file等字段)的文件,保存映射关系,通过这个文件找到原始文件。

在转化后的文件底部加上//@ sourceMappingURL=/path/to/file.js.map

Tree-shaking

目的:使得项目最终构建的(bundle)只包括所需要的代码。该算法首先会标记所有相关的语句,然后通过摇动语法树来删除所有的 Dead Code。它在思想上类似于 GC(Garbage Collection)中的标记清除算法。

  • 利用 ES Module 可以进行静态分析的特点来检测模块内容的导出、导入以及被使用的情况,保留 Live Code
  • 消除不会被执行和没有副作用(Side Effect) 的 Dead Code,即 DCE 过程

Webpack优化

开发环境性能优化:

  • 优化打包构建速度,HMR(热加载),只有改变的文件修改,其他使用缓存。
  • 优化代码调试 Souece-map,映射打包代码。

生成环境性能优化:

  • 优化打包构建速度。
  1. babel缓存(babel检查JS代码并转换成底版本的JS)。
  2. 多线程打包
  3. externals。让某些库不打包,如使用react和vue时,生产环境设置不打包react/vue,通过CDN引入。
  4. dll。让某些库不打包,单独打包。
  • 优化代码运行性能。
  1. 通过alies按需引入,splitChunk / code Split 打包成多个小的JS,结合CDN + http2.0 可以同时请求多个JS文件,提高速度。
  2. 缓存(hash-chunkhash-contenthash),hash每次webpack打包时都会生成一个hash值,chunkhash,同一个entry共享同一个hash,contenthash同一个文件内容共享hash。
  3. 树摇(tree shaking),清除应用程序中没有使用的代码,需要开始es6,使用生成环境会默认开启。
  4. 代码分割(code split) 单入口应用webpack每次打包生成chunk,输出成一个bundle,代码分割将一个bundle分割成多个bundle并行加载,提升速度。常用方法:1) 设置入口起点,使用entry配置手动分离代码,2)动态导入,动态import。
  5. 懒加载/预加载。懒加载在异步中定义,用到时再加载。预加载是浏览器在加载完其他资源后,空闲时再加载。
  6. PWA。渐进式WEB应用程序(离线可以访问),通过serivceworker和cache来实现。