webpack 知识点
# Babel 的原理
babel 的转译过程也分为三个阶段,这三步具体是:
- 解析Parse: 将代码解析生成抽象语法树( 即AST ),即词法分析与语法分析的过程
- 转换Transform: 对于AST 进行变换一系列的操作,babel 接受得到AST 并通babel-traverse 对其进行遍历,在此过程中进行添加、更新及移除等操作。
- 生成Generate: 将变换后的AST 再转换为JS 代码, 使用到的模块是babel-generator
# node_modules问题
假如npm安装了一个模块A、依赖c的0.0.1版本,又安装了一个模块B,依赖c的0.0.2版本。请问node_module是怎么保证A、B正确的找到对应的c版本的包的?
如果 c 的两个版本一样,c 会被安装到和 A,B的同一级目录;不一样则会被安装到 A,B的目录下面,存在多版本;对于这种直接书写模块名的引用,webpack查找模块的方式和node一致,都是先找当前目录的node_modules中是否有这个模块,然后再找上一级目录的node_modules,一直找到根目录。这么做,就能保证webpack能顺利找到模块了。
# webpack 编译过程
- 初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数;
- 开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译;
- 确定入口:根据配置中的 entry 找出所有的入口文件;
- 编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理;
- 完成模块编译:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系;
- 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会;
- 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统
# 首屏加载优化
- 路由懒加载:改为用import引用,以函数的形式动态引入,可以把各自的路由文件分别打包,只有在解析给定的路由时,才会下载路由组件;
- 三方库按需加载:引用实际上用到的组件 ;
- 组件重复打包:CommonsChunkPlugin配置来拆包,把使用2次及以上的包抽离出来,放进公共依赖文件,首页也有复用的组件,也会下载这个公共依赖文件;
- gzip: 拆完包之后,再用gzip做一下压缩,关闭sourcemap。
- UglifyJsPlugin: 生产环境,压缩混淆代码,移除console代码
- CDN部署静态资源:静态请求打在nginx时,将获取静态资源的地址进行重定向CDN内容分发网络
- 移动端首屏加载可以使用骨架屏,自定义loading,首页单独做服务端渲染。
# webpack 热更新机制
启动本地server,让浏览器可以请求本地的静态资源
页面首次打开后,服务端与客户端通过 websocket建立通信渠道,把下一次的 hash(当前页面对应模块的hash) 返回前端
客户端获取到hash,这个hash将作为下一次请求服务端 hot-update.js(执行更新dom方法) 和 hot-update.json(模块变化后的内容)的hash
修改页面代码后,Webpack 监听到文件修改后,开始编译,编译完成后,发送 build 消息给客户端
客户端获取到hash,成功后客户端构造hot-update.js script链接,然后插入主文档
hot-update.js 插入成功后,执行hotAPI 的 createRecord 和 reload方法,获取到 Vue 组件的 render方法,重新 render 组件, 继而实现 UI 无刷新更新。
# loader和plugin
- loader 它就是一个转换器,将A文件进行编译形成B文件,主要是对资源进行加载/转译的预处理工作,其本质是一个函数,在该函数中对接收到的内容进行转换,返回转换后的结果。某种类型的资源可以使用多个 loader,执行顺序是从右到左,从下到上。
- plugin ,它就是一个扩展器,来操作的是文件,针对是loader结束后,webpack打包的整个过程,它并不直接操作文件,会监听webpack打包过程中的某些节点(run, build-module, program),主要是扩展 webpack 的功能,其本质是监听整个打包的生命周期。webpack 基于事件流框架 Tapable, 运行的生命周期中会广播出很多事件,plugin 可以监听这些事件,在合适的时机通过 webpack 提供的 API 改变输出结果。
- Babel 能把ES6/ES7的代码转化成指定浏览器能支持的代码。
- css-loader 的作用是把 css文件进行转码,将css文件变成commonjs一个模块加载到js中,里面的内容是样式字符串
- style-loader: 创建style标签,将js中的样式资源(就是css-loader转化成的字符串)拿过来,添加到页面head标签生效
- 先使用 css-loader 转码,然后再使用 style-loader插入到文件
# 为什么 Vite 启动这么快
- Webpack 会先打包,然后启动开发服务器,请求服务器时直接给予打包结果。
- 而 Vite 是直接启动开发服务器,请求哪个模块再对该模块进行实时编译。
- Vite 将开发环境下的模块文件,就作为浏览器要执行的文件,而不是像 Webpack 那样进行打包合并。
- 由于 Vite 在启动的时候不需要打包,也就意味着不需要分析模块的依赖、不需要编译。因此启动速度非常快。当浏览器请求某个模块时,再根据需要对模块内容进行编译。
# webpack有几种hash
hash:是整个项目的hash值,其根据每次编译内容计算得到,每次编译之后都会生成新的hash,即修改任何文件都会导致所有文件的hash发生改变。 chunkHash:根据不同的入口文件(Entry)进行依赖文件解析、构建对应的chunk,生成对应的哈希值(来源于同一个chunk,则hash值就一样)。 contentHash:根据文件内容生成hash值,文件内容相同hash值就相同
# tree-shaking原理
利用ES Module做静态分析,通过分析ast语法树,对每个模块维护了一个作用域,收集模块内部使用的变量,然后分析作用域,将import进来未被使用的模块删除,最后递归处理文件。
# url-loader和file-loader
- url-loader 允许你有条件地将文件转换为内联的 base-64 URL (当文件小于给定的阈值),这会减少小文件的 HTTP 请求数。如果文件大于该阈值,会自动的交给 file-loader 处理。
- webpack 最终会将各个模块打包成一个文件,因此我们样式中的 url 路径是相对入口 html 页面的,而不是相对于原始 css 文件所在的路径。这就会导致图片引入失败。file-loader 可以解析项目中的 url 引入(不仅限于 css),根据我们的配置,将图片拷贝到相应的路径,修改打包后文件引用路径,使之指向正确的文件。
- 01
- 2023/07/03 00:00:00
- 02
- 2023/04/22 00:00:00
- 03
- 2023/02/16 00:00:00