一些常见的webpack/vite面试题汇总,后续不断更新。。。

306 阅读13分钟

webpack官网:webpack.docschina.org/

vite官网:vitejs.dev/

vite中文官网:vitejs.cn/

§ 说一下webpack常见的Loader有哪些?

raw-loader:加载文件原始内容(UTF-8)

file-loader:把文件输出到一个文件夹中,在代码中通过相对URL去引用输出的文件(处理图片和文字)

source-map-loader:加载额外的Source Map文件,用来方便断点调试

svg-inline-loader:将压缩后的SVG内容注入到代码中

image-loader:加载并且压缩图片文件

json-loader:加载JSNON文件

babel-loader:将ES6转换为ES5

ts-loader:将TypeScript转换为JavaScript

awesome-typescript-loader:将TypeScript转换为JavaScript,性能高于ts-loader

sass-loader:将SCSS/SASS代码转换为CSS

css-loader:加载CSS,支持模块化,压缩,文件导入等特性

style-loader:把CSS代码注入到JavaScript中,通过DOM操作去加载CSS

postcss-loader:扩展CSS语法,使用下一代CSS,可以配合autoprefixer插件自动补齐CSS3的前缀

vue-loader:加载vue.js单文件组件

§ 说一下webpack常见的Plugin有哪些?

define-plugin:定义环境变量

ignore-plugin:忽略部分文件

html-webpack-plugin:简化HTML文件创建(依赖于html-loader)

web-webpack-plugin:可方便地为单页面引用输出HTML,比html-webpack-plugin好用

uglifyjs-webpack-plugin:在webpack4之前,不支持ES6压缩

terser-webpack-plugin:支持压缩ES6(webpack4)

webpack-parallel-uglify-plugin:多进程执行代码压缩,提升构建速度

mini-css-extract-plugin:分离样式文件,CSS 提取为独立文件,支持按需加载

serviceworker-webpack-plugin:为网页应用增加离线缓存功能

clean-webpack-plugin:目录清理,每次 npm run build 打包后自动删除上次打包后的dist文件夹

§ 说一下webpack中的Loader和Plugin的区别?

loader本质就是一个函数,在该函数中对接收到的内容进行转换,然后返回转换后的结果

因为webpack只认识JavaScript,所以loader的作用就是对其他类型的资源进行转译的预处理工作

plugin是插件,plugin基于事件流框架Tapable,插件可以扩展webpack的功能,在webpack运行的生命周期中会生成很多事件,plugin可以接收这些事件,在合适的时机,通过webpack提供的API改变输出结果

loader需要在module.rules中配置,由于作为模块的解析规则,所以类型是输入。输入的每一项都是一个Object。loader中内部包含了test类型文件,loader和options参数等属性

plugin 在 plugins 中单独配置,类型为数组,每一项是一个 Plugin 的实例,参数都通过构造函数传入

§ webpack的作用是什么?

目前前端页面功能丰富,特别是SPA单页面应用(single page web application)技术流行之后,JavaScript的复杂度增加和需要一大堆依赖包,还需要解决scss,less等,webpack的作用就是扩展写法和编译工作。目前前端主流框架都已经完全依赖于webpack的辅助了

§ webpack的工作原理?

webpack的主要作用是模块打包,webpack的工作原理是分析你的项目结构,找到JavaScript模块以及其他的一些浏览器不能直接运行的扩展语言,比如Scss,TypeScript等,然后将其转换或者打包成浏览器认识的语言

§ webpack的打包原理?

把一切都当作模块处理,不管是css还是js还是image还是html,都可以相互引用,通过定义entry.js,对所有依赖的文件进行跟踪,将各个模块通过loader和plugin处理,最后打包在一起。其次是按需加载,在打包过程中webpack通过code splitting功能将文件分为多个chunks,还可以将重读的部分单独提取出来作为commonChunk,从而实现按需加载,最后把所有依赖的文件打包成一个bundle.js,通过代码分割成单元片段并按需加载

§ webpack的核心里面?

Entry:入口,weback执行构建的第一步是从Entry开始,可以理解为输入,告诉webpack要使用哪个模块作为构建项目的起点,默认为根目录src下面的index.js

output:出口,告诉webpack在哪里输出它,打包好的代码以及如何明明,默认为dist文件夹

Module:模块,在webpack中一切都是模块,一个模块对应着一个文件,webpack会从配置的入口(Entry)开始递归查找出所有依赖的模块

Chunk:代码块,一个Chunk由多个模块组合而成,用于代码合并和分割

Loader:模块转换器,用于把模块原内容按照需求转换成新内容

Plugin:扩展插件,在webpack构建流程中的特定时机,会广播出对应的事件,插件可以监听这些事件的发生,在特定的时际做对应的事情

§ webpack的基本功能有哪些?

代码转换:TypeScript编译成JavaScript,SCSS编译成CSS等

文件优化:压缩JavaScript,CSS,HTML代码,压缩合成图片等

代码分割:提取多个页面的公共代码,提取首屏不需要执行部分的代码,让其异步加载

模块合并:在采用模块化的项目由很多模块和文件,需要构建功能把模块分类合并成一个文件

自动刷新:监听本地源代码的变化,自动构建,刷新浏览器

代码校验:在代码呗提交到仓库钱需要检测代码是否符合规范,以及单元测试是否通过

自动发布:更新完代码后,自动构建出线上发布代码并传输给发布系统

§ 什么是bundle,什么是chunk,什么是module

bundle:是由webpack打包出来的文件

chunk:是指webpack在进行模块依赖分析的时候,代码分割出来的代码块

module:是开发中的单个模块

§ ExtractTextPlugin插件的作用是什么?

ExtractTextPlugin插件的作用是提取出 JavaScript 代码里的 CSS 到一个单独的文件

§ sourceMap的作用是什么?

sourceMap是一个映射关系,将打包后的文件映射到源代码中,作用是用于定位报错位置

配置方法:

devtool:'source-map'

加不同前缀的含义:

inline:不胜澈给映射关系文件,打包进main.js

cleap:1.只精确到位,不精确到列,打包速度快,2.只管业务代码,不管第三方模块

module:不仅管业务代码,而且还管第三方代码

eval:执行效率最快,性能最好

§ 讲一下HMR模块热更新

HMR借助webpack.HotModuleReplacementPlugin(),devServer开启hot,我们可以实现之刷新css,不影响js,或者js中实现热更新,只更新指定的js模块

if (module.hot) {
  module.hot.accept(’./library.js’, function() {
    // Do something with the updated library module…
  });
}

§ webpack如何配置多个入口文件?

entry: {
  home: resolve(__dirname, "src/home/index.js"),
  about: resolve(__dirname, "src/about/index.js")
}

用于描述入口的对象。你可以使用如下属性:

dependOn: 当前入口所依赖的入口。它们必须在该入口被加载前被加载。

filename: 指定要输出的文件名称。

import: 启动时需加载的模块。

library: 指定 library 选项,为当前 entry 构建一个 library。

runtime: 运行时 chunk 的名字。如果设置了,就会创建一个新的运行时 chunk。在 webpack 5.43.0 之后可将其设为 false 以避免一个新的运行时 chunk。

publicPath: 当该入口的输出文件在浏览器中被引用时,为它们指定一个公共 URL 地址

§ 什么是长缓存?在webpack中如何做到长缓存优化?

浏览器在用户访问页面的时候,为了加快加载速度,会对用户访问的静态资源进行存储,但是每一次代码升级或者更新,都需要浏览器去下载新的代码,最方便和最简单的更新方式就是引入新的文件名称

在webpack中,可以在output给出输出的文件制定chunkhash,并且分离经常更新的代码和框架代码,通过NameModulesPlugin或者HashedModulesPlugin使再次打包文件名不变

§ 什么是Tree-sharking?

Tree-sharking指打包中去除那些引入了但在代码中没用到的死代码。在wepack中js treeshaking通过UglifyJsPlugin来进行,css中通过purify-CSS来进行

§ webpack-dev-server 和 http服务器的区别?

webpack-dev-server使用内存来存储webpack开发环境下的打包文件,并且可以使用模块热更新,比传统的http服务对开发更加有效

§ 介绍一下webpack和vite的区别:

底层:

webpack是基于nodejs构建,js是以毫秒计数,

vite是基于esbulid预构建依赖,esbulid是采用go语言编写的,go语言是纳秒级别的

因为js是毫秒级别,go语言是纳秒级别的,所以从本质上讲,vite比webpack打包要快很多

1.webpack是先打包再启动开发服务器

webpack是先打包,再启动开发服务器,请求服务器时,直接给予打包后的结果

2.vite是直接启动开发服务器,然后按需编译依赖文件

vite时直接启动开发服务器,请求哪个模块再对哪个模块进行实时编译

原理:

vite是将开发环境下的模块文件作为浏览器要执行文件,vite启动的时候不需要打包,也不需要分析模块依赖,编译,所以启动速度非常快,当浏览器请求需要的模块时,再对指定的模块进行编译,这种按需编译的模块,所以极大的缩短了时间

HMR热更新原理:

webpack:重新将该模块的所有依赖重新编译

vite:当某个模块内容改变时,让浏览器重新请求该模块

§ 说一下 webpack module 联邦是什么

Webpack Module Federation(模块联邦)Webpack 5 引入的一个新特性,用于支持微前端架构以及跨应用共享模块的功能。它的核心目标是允许不同 Webpack 构建的应用之间共享代码和资源,而不需要每个应用都重复打包相同的模块,从而减少冗余、提升性能并优化开发体验。

基本概念

Module Federation 让你在多个独立的 Webpack 构建中共享模块(如 JavaScript、CSS、React 组件等)。这对于微前端架构尤为重要,因为它可以让不同的应用(无论是子应用还是主应用)之间共享一些公共模块,而不需要在每个应用中单独打包。

模块联邦的关键点

  • 共享模块:不同应用可以共享模块(例如 React、Vue、某些第三方库或自定义组件),从而避免重复加载相同的代码。
  • 动态加载:可以动态地加载共享模块,而不需要在构建时就确定所有依赖关系。
  • 远程加载:一个应用可以远程加载另一个应用的代码,并在运行时直接使用它。

Module Federation 的核心功能

Module Federation 主要通过以下方式工作:

  1. 共享模块

    • exposes:在一个应用中暴露出某些模块,供其他应用使用。
    • remotes:其他应用可以远程加载这些暴露出来的模块。
  2. 自动依赖管理

    • 不同的应用可以共享相同的依赖库(如 React、Vue 等)。如果这些库已经加载过,Webpack 会自动处理模块的共享和版本控制,避免重复加载。

应用场景

  1. 微前端架构

    • 在微前端架构中,不同的子应用可以使用 Module Federation 共享一些公共的模块,减少应用间的重复代码和依赖。
  2. 跨应用共享组件

    • 假设你有多个前端应用(如购物网站、用户管理系统等),你可以通过 Module Federation 在它们之间共享 UI 组件、逻辑模块等,而不需要每个应用独立构建这些组件。

工作原理

1. 主应用暴露模块

在主应用的 Webpack 配置中,你可以使用 exposes 来暴露模块供其他应用使用。

// webpack.config.js for host (主应用)
module.exports = {
  // 在 Module Federation 插件中设置 exposes
  plugins: [
    new webpack.container.ModuleFederationPlugin({
      name: 'host', // 主应用名称
      exposes: {
        './Button': './src/Button', // 暴露 src/Button 模块
      },
      shared: ['react', 'react-dom'], // 公共依赖,避免重复加载
    }),
  ],
};
2. 远程应用加载模块

在远程应用的 Webpack 配置中,你可以使用 remotes 来指定要加载的模块(即远程应用的模块)。

// webpack.config.js for remote (远程应用)
module.exports = {
  plugins: [
    new webpack.container.ModuleFederationPlugin({
      name: 'remote', // 远程应用名称
      remotes: {
        host: 'host@http://localhost:3000/remoteEntry.js', // 从主应用加载模块
      },
      shared: ['react', 'react-dom'], // 公共依赖
    }),
  ],
};
3. 加载和使用共享模块

在应用中,你可以直接加载和使用远程暴露的模块:

// 远程应用中动态加载主应用暴露的模块
import('host/Button').then(Button => {
  const button = new Button();
  document.body.appendChild(button.render());
});
4. 公共依赖共享

使用 shared 选项,可以在多个应用之间共享一些公共依赖(如 react, lodash 等),避免每个应用重复打包和加载相同的库。

// webpack.config.js
new webpack.container.ModuleFederationPlugin({
  name: 'app',
  remotes: {
    otherApp: 'otherApp@http://localhost:3001/remoteEntry.js',
  },
  shared: {
    react: { singleton: true }, // 共享 React,保证只有一个实例
    'react-dom': { singleton: true },
  },
});

优点

  1. 减少重复代码

    • 在微前端应用中,多个子应用可以共享同一个依赖,而无需每个应用单独打包,从而减少了冗余代码和流量。
  2. 提高性能

    • 共享模块可以在首次加载时加载一次,后续直接从缓存加载,避免重复下载和加载相同的资源。
  3. 支持动态加载

    • 远程模块可以按需动态加载,减少了初始页面加载的体积。
  4. 解耦独立部署

    • 每个应用可以独立开发和部署,只需要确保共享的模块版本兼容。不同团队可以独立开发和发布应用,而无需依赖于其他应用的发布周期。

缺点

  1. 配置复杂

    • 虽然 Webpack 提供了强大的功能,但是配置比较复杂,特别是在涉及多个应用和共享模块时,需要精心设计和管理模块和依赖。
  2. 版本管理问题

    • 共享模块时,必须管理好版本依赖,确保不同应用之间共享的模块版本兼容。否则可能会遇到版本冲突或不兼容的问题。
  3. 调试难度

    • 动态加载和远程应用的调试可能会比单一构建的应用更困难,尤其是多个应用间的状态和资源管理。

总结

Webpack 的 Module Federation 是一个强大的功能,特别适用于微前端架构和大型应用的模块化。通过模块联邦,可以让不同的应用或子应用共享代码和依赖,从而提升性能,减少冗余,并使得各个团队能够独立开发和发布自己的模块。