整理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作用
- 模块打包。 将不同模块的文件打包整合在一起,并且保证它们之间的引用正确,执行有序。
- 编译兼容。Loader可以编译转换诸如.less, .vue, .jsx这类在浏览器无法识别的格式文件。
- 能力扩展。按需加载,代码压缩等一系列功能。
Webpack按需加载
JSONP
WebPack打包流程
- 读取webpack的配置参数
- 启动webpack,创建Compiler对象并开始解析项目
- 从入口文件(entry)开始解析,并且找到其导入的依赖模块,递归遍历分析,形成依赖关系树
- 对不同文件类型的依赖模块文件使用对应的Loader进行编译,最终转为Javascript文件
- 整个过程中webpack会通过发布订阅模式,向外抛出一些hooks,而webpack的插件即可通过监听这些关键的事件节点,执行插件任务进而达到干预输出结果的目的。
主要依赖于compiler和compilation两个核心对象。compiler对象是一个全局单例,他负责把控整个webpack打包的构建流程。compilation对象是每一次构建的上下文对象,它包含了当次构建所需要的所有信息,每次热更新和重新构建,compiler都会重新生成一个新的compilation对象,负责此次更新的构建过程。
而每个模块间的依赖关系,则依赖于AST语法树。每个模块文件在通过Loader解析完成之后,会通过acorn库生成模块代码的AST语法树,通过语法树就可以分析这个模块是否还有依赖的模块,进而继续循环执行下一个模块的编译解析。 最终Webpack打包出来的bundle文件是一个IIFE(立即调用)的执行函数。
Webpack热更新
模块热替换(hot module replacement 或 HMR)是 webpack 提供的最有用的功能之一。它允许在运行时更新所有类型的模块,而无需完全刷新
- 开启webpack热更新,设置 HotModuleReplacementPlugin
plugins: {
HotModuleReplacementPlugin: new webpack.HotModuleReplacementPlugin()
}
- HMR runtime 通过HotModuleReplacementPlugin 已经注入到我们 chunk 中了
- 开启一个Bundle Server,还开启了 HMR Server,主要用来和 HMR Runtime 中通信
- 在编译结束的时候,通过 compiler.hooks.done,监听并通知客户端
- 客户端接收到之后,就会调用 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访问流程:比如访问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,映射打包代码。
生成环境性能优化:
- 优化打包构建速度。
- babel缓存(babel检查JS代码并转换成底版本的JS)。
- 多线程打包
- externals。让某些库不打包,如使用react和vue时,生产环境设置不打包react/vue,通过CDN引入。
- dll。让某些库不打包,单独打包。
- 优化代码运行性能。
- 通过alies按需引入,splitChunk / code Split 打包成多个小的JS,结合CDN + http2.0 可以同时请求多个JS文件,提高速度。
- 缓存(hash-chunkhash-contenthash),hash每次webpack打包时都会生成一个hash值,chunkhash,同一个entry共享同一个hash,contenthash同一个文件内容共享hash。
- 树摇(tree shaking),清除应用程序中没有使用的代码,需要开始es6,使用生成环境会默认开启。
- 代码分割(code split) 单入口应用webpack每次打包生成chunk,输出成一个bundle,代码分割将一个bundle分割成多个bundle并行加载,提升速度。常用方法:1) 设置入口起点,使用entry配置手动分离代码,2)动态导入,动态import。
- 懒加载/预加载。懒加载在异步中定义,用到时再加载。预加载是浏览器在加载完其他资源后,空闲时再加载。
- PWA。渐进式WEB应用程序(离线可以访问),通过serivceworker和cache来实现。