面试总结之前端工程化篇

177 阅读11分钟

1.什么是webpack?

webpack是一个前端的静态模块资源打包工具,能让浏览器也支持模块化。它将根据模块的依赖靠关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源。

webpack的作用

  • webpack核心主要进行javascript资源打包
  • 它可以结合其他插件工具,将多种静态资源css,png,sass分类转换成一个个静态文件,这样可以减少页面的请求
  • 可集成babel工具实现es6转es5,解决兼容性问题
  • 可集成http服务器
  • 可集成模块热加载,当代码改变后自动刷新浏览器等等功能

2.webpack配置有哪些 ?

  • entry。指定Webpack打包的入口文件,可以是单个或多个JavaScript文件。这个配置决定了Webpack从哪个模块开始生成依赖关系图。
  • output。设置Webpack打包后输出的目录和文件名称,包括path、filename和publicPath等。
  • module。配置了不同的loaders来处理不同的模块,例如,对于CSS文件,可以使用css-loader和style-loader。
  • resolve。设置Webpack如何解析模块依赖,包括别名、扩展名等。
  • plugins。使用不同的插件可以增强Webpack的功能,例如,使用html-webpack-plugin可以将打包后的js文件自动引用到HTML文件中。
  • devServer。提供了一个简单的web服务器和实时重载功能,可以通过devServer.contentBase、devServer.port、devServer.proxy等进行配置。
  • optimization。可以使用optimization.splitChunks和optimization.runtimeChunk配置代码拆分和运行时代码提取等优化策略。
  • externals。用于配置排除打包的模块,例如,可以将jQuery作为外置扩展,避免将其打包到应用程序中。
  • devtool。配置source-map类型。
  • context。webpack使用的根目录,string类型必须是绝对路径。
  • target。指定Webpack编译的目标环境。
  • performance。输出文件的性能检查配置。
  • noParse。不用解析和处理的模块。
  • stats。控制台输出日志控制。

3.有哪些常见的 Loader 和 Plugin?

Loader:

  • babel-loader:将ES6+的代码转换成ES5的代码。
  • css-loader:解析CSS文件,并处理CSS中的依赖关系。
  • style-loader:将CSS代码注入到HTML文档中。
  • file-loader:解析文件路径,将文件赋值到输出目录,并返回文件路径。
  • url-loader:类似于file-loader,但是可以将小于指定大小的文件转成base64编码的Data URL格式
  • sass-loader:将Sass文件编译成CSS文件。
  • less-loader:将Less文件编译成CSS文件。
  • postcss-loader:自动添加CSS前缀,优化CSS代码等。
  • vue-loader:将Vue单文件组件编译成JavaScript代码。

Plugin:

  • HtmlWebpackPlugin:生成HTML文件,并自动将打包后的javaScript和CSS文件引入到HTML文件中。
  • CleanWebpackPlugin:清除输出目录。
  • ExtractTextWebpackPlugin:将CSS代码提取到单独的CSS文件中。
  • DefinePlugin:定义全局变量。
  • UglifyJsWebpackPlugin:压缩JavaScript代码。
  • HotModuleReplacementPlugin:热模块替换,用于在开发环境下实现热更新。
  • MiniCssExtractPlugin:与ExtractTextWebpackPlugin类似,将CSS代码提取到单独的CSS文件中。
  • BundleAnalyzerPlugin:分析打包后的文件大小和依赖关系。

4.Loader和Plugin的区别

功能不同

  • Loader本质是一个函数,它是一个转换器。webpack只能解析原生js文件,对于其他类型文件就需要loade进行转换。
  • Plugin它是一个插件,工作原理是:webpack 通过内部的事件流机制保证了插件的有序性,底层是利用发布订阅模式,webpack 在运行过程中会广播事件,插件只需要监听它所关心的事件,在特定的时机对资源做处理

用法不同

  • Loader的配置是在module.rules下进行。类型为数组,每⼀项都是⼀个 Object ,⾥⾯描述了对于什么类型的⽂件( test ),使⽤什么加载( loader )和使⽤的参数( options ) 。
  • Plugin的配置在plugins下。类型为数组,每一项是一个 Plugin 的实例,参数都通过构造函数传入。

5.webpack的构建流程

  1. 初始化参数:解析webpack配置参数,合并shell传入和webpack.config.js文件配置的参数,形成最后的配置结果
  2. 开始编译:上一步得到的参数初始化compiler对象,注册所有配置的插件,插件监听webpack构建生命周期的事件节点,做出相应的反应,执行对象的run方法开始执行编译。
  3. 确定入口:从配置的entry入口,开始解析文件构建ast语法树,找到依赖,递归下去
  4. 编译模块:递归中根据文件类型和loader配置,调用所有配置的loader对文件进行转换,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理
  5. 完成模块编译并输出:递归完事后,得到每个文件结果,包含每个模块以及他们之间的依赖关系,根据entry配置生成代码块chunk
  6. 输出完成:输出所有的chunk到文件系统

6.Webpack的Tree Shaking原理

Webpack的Tree Shaking是一个利用ES6模块静态结构特性来去除生产环境下不必要代码的优化过程。其工作原理在于:

  1. 当Webpack分析代码时,它会标记出所有的import语句export语句
  2. 然后,当Webpack确定某个模块没有被导入时,它会在生成的bundle中排除这个模块的代码。
  3. 同时,Webpack还会进行递归的标记清理,以确保所有未使用的依赖项都不会出现在最终的bundle中。

为了启用Tree Shaking,需要在webpack配置文件中添加如下设置:

javascriptmodule.exports = {  // ...  optimization: {    usedExports: true,    concatenateModules: true,    minimize: true,  },  // ...};

确保你使用的是ES6模块语法(即import和export),因为只有这样才能让Tree Shaking发挥作用。

7.热更新原理

什么是 webpack 热更新?

开发过程中,代码发生变动后,webpack 会重新编译,编译后浏览器替换修改的模块,局部更新,无需刷新整个页面 好处:节省开发时间、提升开发体验

热更新原理

主要是通过websocket实现,建立本地服务浏览器的双向通信。当代码变化,重新编译后,通知浏览器请求更新的模块,替换原有的模块

  1. 通过webpack-dev-server开启server服务,本地 server 启动之后,再去启动 websocket 服务,建立本地服务和浏览器的双向通信
  2. webpack 每次编译后,会生成一个Hash值,Hash 代表每一次编译的标识。本次输出的 Hash 值会编译新生成的文件标识,被作为下次热更新的标识
  3. webpack监听文件变化(主要是通过文件的生成时间判断是否有变化),当文件变化后,重新编译
  4. 编译结束后,通知浏览器请求变化的资源,同时将新生成的 hash 值传给浏览器,用于下次热更新使用
  5. 浏览器拿到更新后的模块后,用新模块替换掉旧的模块,从而实现了局部刷新

8.Babel

Babel 是一个用于将新版本ES6+代码转换为向后兼容版本(ES5)代码的JavaScript编译器。它还为JSX语法提供了编译支持,还有一些其他插件可用于转换特定类型的代码 。

作用

babel 主要用于将新版本的代码转换为向后兼容的 js 语法(Polyfill 方式),以便能够运行在各版本的浏览器或其他环境中

Babel 的流程

3 个阶段: parsing (解析)、transforming (转换)、generating (生成)

  1. 通过babylon将 js 转化成 ast (抽象语法树)
  2. 通过babel-traverse是一个对 ast 进行遍历,使用 babel 插件转化成新的 ast
  3. 通过babel-generator将 ast 生成新的 js 代码

9.npm install 的执行过程

npm install 是 Node.js 包管理器 (npm) 的一个命令,用于安装一个项目所依赖的模块。

执行过程大致如下:

  • 读取 package.json 文件,该文件列出了项目所需要的依赖。
  • 根据 package.json 中的依赖信息以及 node_modules 目录状态,npm 会决定哪些模块需要下载和安装。
  • npm 会查看每个模块的可用版本,并选择符合 package.json 中指定版本范围的最新版本进行安装。
  • 下载所需模块到本地的 node_modules 目录。
  • 如果模块包含子模块(package.json 中 dependencies 或 devDependencies 中的模块),则递归执行上述步骤安装这些子模块。

10.npm run start 的整个过程?

npm run start 是一个常见的命令,用于启动基于 Node.js 的应用程序。这个命令实际上是一个快捷方式,它告诉 npm 运行在 package.json 文件中定义的 start 脚本。

当你执行 npm run start 时,以下是发生的事情:

  • 查找当前目录下的 package.json 文件。
  • 在 package.json 文件中,找到 scripts 对象。
  • scripts 对象中,找到 start 键。
  • 执行与 start 键关联的命令字符串。

11. 什么是Code Splitting

Code Splitting代码分割,是一种优化技术。它允许将一个大的chunk拆分成多个小的chunk,从而实现按需加载,减少初始加载时间,并提高应用程序的性能 。

在Webpack中通过optimization.splitChunks配置项来开启代码分割

12. 如何提高webpack的打包速度

  • 开启持久化缓存(Webpack 5 自带):Webpack 5 内置了文件缓存机制,减少二次构建时间。
  • 开启多线程并行编译:Webpack 默认是单线程执行的,可以用 thread-loaderparallel-webpack 进行多线程处理。
  • 使用DllPlugin和HardSourceWebpackPlugin: DllPlugin可以将第三方库预先打包成单独的文件,减少构建时间。HardSourceWebpackPlugin可以缓存中间文件,加速后续构建过程
  • 使用 ESBuild/SWC 替代 Babel:Babel 解析速度较慢,ESBuild 比 Babel 快 10~100 倍。SWC 也是一个超快的 JS/TS 编译器,比 Babel 快 20 倍
  • 开启 Babel Loader 缓存:如果仍在使用 Babel,可开启缓存减少重复编译。
  • 利用 terser-webpack-plugin 多线程压缩:Webpack 默认 JS 压缩器 terser 是单线程的,可以开启多线程加速。
  • 使用 cache-loader 缓存:cache-loader 可以缓存编译结果,提高二次构建速度。
  • 减少构建体积Tree Shaking(移除无用代码)、CDN 加速(减少 vendor.js 体积)、Gzip 压缩(减少文件大小)
  • 移除不必要的插件: 移除不必要的插件和配置,避免不必要的复杂性和性能开销

13. 如何减少打包后的代码体积

  • 代码分割(Code Splitting):将应用程序的代码划分为多个代码块,按需加载
  • Tree Shaking:配置Webpack的Tree Shaking机制,去除未使用的代码
  • 压缩代码:使用工具如UglifyJS或Terser来压缩JavaScript代码
  • 使用压缩工具:使用现代的压缩工具,如Brotli和Gzip,来对静态资源进行压缩
  • 利用CDN加速:将项目中引用的静态资源路径修改为CDN上的路径,减少图片、字体等静态资源等打包

14. module chunk bundle分别什么意思,有什么区别

在 Webpack 中,modulechunkbundle 是三个核心概念,它们分别代表构建过程中的不同阶段和结构。

定义

  1. Module(模块)
  • 模块是 Webpack 的基本单位,代表项目中的每个文件,如 JavaScript、CSS、图片、字体等。
  1. Chunk(代码块)
  • Chunk 是 Webpack 在构建过程中生成的代码块,由多个模块组成。
  • Webpack 会根据入口文件和动态引入的模块,创建多个 Chunk。
  • 每个 Chunk 通常对应一个或多个最终生成的文件。
  1. Bundle(最终文件)
  • Bundle 是 Webpack 最终生成的打包文件,包含了构建后的代码和资源。
  • 通常是 .js.css 或其他静态资源文件。
  • 文件名可以通过 output.filename 自定义。

关系和构建过程

  1. 从 Module 到 Chunk

    • Webpack 根据依赖关系,将多个模块分组,生成一个或多个 Chunk。
    • 例如,多个模块(moduleA.jsmoduleB.js)可能会被打包到同一个 Chunk 中。
  2. 从 Chunk 到 Bundle

    • 每个 Chunk 会被进一步处理,最终输出为 Bundle 文件(如 main.js)。
    • 动态加载的模块可能会生成独立的 Bundle 文件。

15. Vite

原理

  • Vite 利用浏览器支持原生的es module模块,开发时跳过打包的过程,提升编译效率
  • 当通过 import 加载资源时,浏览器会发出 HTTP 请求对应的文件,Vite拦截到该请求,返回对应的模块文件

Vite 的限制

Vite 主要对应的场景是开发模式(生产模式是用 rollup 打包)

16.Vite 热更新速度

Vite 热更新的速度不会随着模块增多而变慢

Webpack 的热更新原理:一旦某个依赖(比如上面的 a.js)改变,就将这个依赖所处的 整个module 更新,并将新的 module 发送给浏览器重新执行

试想如果依赖越来越多,就算只修改一个文件,热更新的速度会越来越慢

Vite 的热更新原理:如果 a.js 发生了改变,只会重新编译这个文件 a,而其余文件都无需重新编译 所以理论上 Vite 热更新的速度不会随着文件增加而变慢

推荐阅读文章

  1. 学习 Webpack5 之路(基础篇)
  2. 学习 Webpack5 之路(实践篇)
  3. 学习 Webpack5 之路(优化篇)- 近 7k 字