loading

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),根据我们的配置,将图片拷贝到相应的路径,修改打包后文件引用路径,使之指向正确的文件。
最近更新时间: 2022/09/28 16:26:36
最近更新
01
2023/07/03 00:00:00
02
2023/04/22 00:00:00
03
2023/02/16 00:00:00