前端八股之工程化
1044
Git
1. 经常使用的git命令
git init // 新建 git 代码库
git add // 添加指定文件到暂存区
git rm // 删除工作区文件,并且将这次删除放入暂存区
git commit -m [message] // 提交暂存区到仓库区
git branch // 列出所有分支
git checkout -b [branch] // 新建一个分支,并切换到该分支
git status // 显示有变更文件的状态
2. git pull
和git fetch
的区别
git fetch
只是将远程仓库的变化下载下来,并没有和本地分支合并。
git pull
会将远程仓库的变化下载下来,并和当前分支合并。
3. git rebase
和git merge
的区别
git merge
和git rebase
都是用于分支合并,关键在commit记录的处理上不同:
git merge
会新建一个新的commit对象,然后两个分支以前的commit记录都指向这个新commit记录。这种方法会保留之前每个分支的commit历史git rebase
会先找到两个分支的第一个共同的commit祖先记录,然后将提取当前分支这之后的所有commit记录,然后将这个commit记录添加到目标分支的最新提交后面。经过这个合并后,两个分支合并后的commit记录就变为了线性的记录了
Webpack
1. webpack与grunt、gulp的不同
Grunt、Gulp是**基于任务运⾏**的⼯具:它们会⾃动执⾏指定的任务,就像流⽔线,把资源放上去然后通过不同插件进⾏加⼯,它们包含活跃的社区,丰富的插件,能⽅便的打造各种⼯作流
Webpack是基于模块化打包的⼯具: ⾃动化处理模块,webpack把⼀切当成模块,当 webpack 处理应⽤程序时,它会递归地构建⼀个依赖关系图,其中包含应⽤程序需要的每个模块,然后将所有这些模块打包成⼀个或多个bundle
因此这是完全不同的两类⼯具,⽽现在主流的⽅式是⽤npm script代替Grunt、Gulp,npm script同样可以打造任务流
2. webpack、rollup优劣
webpack适⽤于⼤型复杂的前端站点构建: webpack有强⼤的loader和插件⽣态,打包后的⽂件实际上就是⼀个⽴即执⾏函数,这个⽴即执⾏函数接收⼀个参数,这个参数是模块对象,键为各个模块的路径,值为模块内容。⽴即执⾏函数内部则处理模块之间的引⽤,执⾏模块等,这种情况更适合⽂件依赖复杂的应⽤开发
rollup适⽤于基础库的打包,如vue、d3等: Rollup就是将各个模块打包进⼀个⽂件中,并且通过Tree-shaking来删除⽆⽤的代码,可以最⼤程度上降低代码体积,但是rollup没有webpack如此多的的如代码分割、按需加载等⾼级功能,其更聚焦于库的打包,因此更适合库的开发
3. 有哪些常⻅的Loader
file-loader
:把⽂件输出到⼀个⽂件夹中,在代码中通过相对URL去引⽤输出的⽂件url-loader
:和file-loader类似,但是能在⽂件很⼩的情况下以base64的⽅式把⽂件内容注⼊到代码中去source-map-loader
:加载额外的Source Map⽂件,以⽅便断点调试image-loader
:加载并且压缩图⽚⽂件babel-loader
:把ES6转换成ES5css-loader
:加载CSS,⽀持模块化、压缩、⽂件导⼊等特性style-loader
:把CSS代码注⼊到JavaScript中,通过DOM操作去加载 CSS 注意:在Webpack中,loader的执行顺序是从右向左执行的。因为webpack选择了compose这样的函数式编程方式,这种方式的表达式执行是从右向左的
4. bundle,chunk,module是什么
bundle
:是由webpack打包出来的⽂件;chunk
:代码块,⼀个chunk由多个模块组合⽽成,⽤于代码的合并和分割;module
:是开发中的单个模块,在webpack的世界,⼀切皆模块,⼀个模块对应⼀个⽂件,webpack会从配置的entry中递归开始找出所有依赖的模块。
5. Loader和Plugin的不同
不同的作⽤
Loader直译为"加载器"。Webpack将⼀切⽂件视为模块,但原生只能解析JS/JSON。Loader使webpack能加载和解析⾮JavaScript资源(如CSS/图片),本质是文件转换器。
Plugin直译为"插件"。Plugin通过钩⼦机制参与编译过程,可修改输出产物、优化构建流程、注入环境变量等(如DefinePlugin定义全局常量、HtmlWebpackPlugin生成HTML文件)。
不同的⽤法
Loader在module.rules
中配置,也就是说他作为模块的解析规则⽽存在。 类型为数组,每⼀项都是⼀个Object⾥⾯描述了对于什么类型的⽂件(test),使⽤什么加载(loader)和使⽤的参数(options)
Plugin在plugins
中单独配置。类型为数组,每⼀项是⼀个plugin的实例,参数都通过构造函数传⼊
6. webpack的构建流程
Webpack 的运⾏流程是⼀个串⾏的过程,从启动到结束会依次执⾏以下流程
- 初始化参数:从配置⽂件和Shell语句中读取与合并参数,得出最终的参数;
- 开始编译:⽤上⼀步得到的参数初始化Compiler对象,加载所有配置的插件,执⾏对象的 run ⽅法开始执⾏编译;
- 确定⼊⼝:根据配置中的entry找出所有的⼊⼝⽂件;
- 编译模块:从⼊⼝⽂件出发,调⽤所有配置的Loader对模块进⾏翻译,再找出该模块依赖的模块,再递归本步骤直到所有⼊⼝依赖的⽂件都经过了本步骤的处理;
- 完成模块编译:在经过第4步使⽤Loader翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系;
- 输出资源:根据⼊⼝和模块之间的依赖关系,组装成⼀个个包含多个模块的Chunk,再把每个Chunk转换成⼀个单独的⽂件加⼊到输出列表,这步是可以修改输出内容的最后机会;
- 输出完成:在确定好输出内容后,根据配置确定输出的路径和⽂件名,把⽂件内容写⼊到⽂件系统。
7. webpack的热更新是如何做到的?说明其原理?
核心流程(Webpack5优化版):
- 文件监听:基于
watchOptions
配置,通过轮询或系统API监听文件变化 - 增量编译: • 内存编译:将变更模块保存在内存中(避免磁盘IO) • 缓存复用:Webpack5的持久化缓存极大减少重复编译
- HMR Runtime通信:
• 通过
websocket
(webpack-dev-server)或EventSource
(webpack-hot-middleware)建立连接 • 增量更新协议:仅传输变更模块的hash标识而非完整文件 - 客户端处理:
•
HotModuleReplacementPlugin
注入的runtime代码接收更新通知 • 发起JSONP
请求获取最新模块代码(.hot-update.json
和.hot-update.js
) - 模块热替换:
• 比对依赖图:确定受影响的模块范围
• 执行
module.hot.accept
:应用新模块逻辑并保留应用状态 • 异常降级:HMR失败时自动回退到整页刷新
关键优化(Webpack5+):
• 快速 Hash 匹配:使用contenthash
精确判断文件变更
• 增量编译缓存:通过filesystem
缓存避免重复解析AST
• Tree-shaking级更新:仅重新处理受影响模块的依赖链
• 模块联邦支持:支持跨应用的模块热替换(微前端场景)
原理解释简化版:当修改代码后,Webpack通过内存编译生成更新包,HMR Runtime像快递员一样把更新包发送给浏览器,浏览器像拼积木一样局部替换代码模块,同时保留应用状态(如Vue组件的data状态)。这整个过程通过Websocket和Hash校验实现高效通信。
Vite
1. 为什么Vite比Webpack快?
维度 | Webpack | Vite |
---|---|---|
启动方式 | 全量打包构建依赖图 | 按需编译 + 预构建缓存 |
HMR更新 | 整模块链重新打包 | 精准定位变更模块 |
构建工具 | 自建打包器 | 开发用ESM,生产用Rollup |
编译语言 | JS实现 | 利用esbuild用Go编写 |
模块处理 | 抽象依赖图 | 浏览器原生ESM解析 |
2. vite对比webpack,优缺点在哪
优点
- 更快的冷启动:Vite借助了浏览器对ESM规范的支持,采取了与Webpack完全不同的unbundle机制
- 更快的热更新:Vite采用unbundle机制,所以dev server在监听到文件发生变化以后,只需要通过ws连接通知浏览器去重新加载变化的文件,剩下的工作就交给浏览器去做了。
缺点
- 开发环境下首屏加载变慢:由于unbundle机制,Vite首屏期间需要额外做其它工作。不过首屏性能差只发生在dev server启动以后第一次加载页面时发生。之后再reload页面时,首屏性能会好很多。原因是dev server会将之前已经完成转换的内容缓存起来
- 开发环境下懒加载变慢:跟首屏加载变慢的原因一样。Vite在懒加载方面的性能也比Webpack差。由于unbundle机制,动态加载的文件,需要做resolve、load、transform、parse操作,并且还有大量的http请求,导致懒加载性能也受到影响。
- webpack支持的更广。由于Vit 基于ES Module,所以代码中不可以使用CommonJs;webpack更多的关注兼容性, 而Vite关注浏览器端的开发体验。Vite目前生态还不如Webpack。
3. vite插件常见的hook有哪些?
- config:可用于修改
vite config
,用户可以通过这个hook修改config;例如 vite-aliases这个插件可以帮助我们自动生成别名。它利用的就是这个钩子。 - configResolved:在解析Vit 配置后调用,用于获取解析完毕的config,在这个 hook中不建议修改config。
- configureServer:用于给dev server添加自定义middleware;例如vite-plugin-mock 插件就是在这个生命周期调用的
- configurePreviewServer:与configureServer相同但是作为预览服务器。vite preview插件就是利用这个钩子。
- transformIndexHtml:注入变量,用来转换HTML的内容。vite-plugin-html 插件可以帮助我们在html里注入变量,就是利用这个钩子
- handleHotUpdate:执行自定义 HMR 更新处理