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 主要通过以下方式工作:
-
共享模块:
- exposes:在一个应用中暴露出某些模块,供其他应用使用。
- remotes:其他应用可以远程加载这些暴露出来的模块。
-
自动依赖管理:
- 不同的应用可以共享相同的依赖库(如 React、Vue 等)。如果这些库已经加载过,Webpack 会自动处理模块的共享和版本控制,避免重复加载。
应用场景
-
微前端架构:
- 在微前端架构中,不同的子应用可以使用 Module Federation 共享一些公共的模块,减少应用间的重复代码和依赖。
-
跨应用共享组件:
- 假设你有多个前端应用(如购物网站、用户管理系统等),你可以通过 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 },
},
});
优点
-
减少重复代码:
- 在微前端应用中,多个子应用可以共享同一个依赖,而无需每个应用单独打包,从而减少了冗余代码和流量。
-
提高性能:
- 共享模块可以在首次加载时加载一次,后续直接从缓存加载,避免重复下载和加载相同的资源。
-
支持动态加载:
- 远程模块可以按需动态加载,减少了初始页面加载的体积。
-
解耦独立部署:
- 每个应用可以独立开发和部署,只需要确保共享的模块版本兼容。不同团队可以独立开发和发布应用,而无需依赖于其他应用的发布周期。
缺点
-
配置复杂:
- 虽然 Webpack 提供了强大的功能,但是配置比较复杂,特别是在涉及多个应用和共享模块时,需要精心设计和管理模块和依赖。
-
版本管理问题:
- 共享模块时,必须管理好版本依赖,确保不同应用之间共享的模块版本兼容。否则可能会遇到版本冲突或不兼容的问题。
-
调试难度:
- 动态加载和远程应用的调试可能会比单一构建的应用更困难,尤其是多个应用间的状态和资源管理。
总结
Webpack 的 Module Federation 是一个强大的功能,特别适用于微前端架构和大型应用的模块化。通过模块联邦,可以让不同的应用或子应用共享代码和依赖,从而提升性能,减少冗余,并使得各个团队能够独立开发和发布自己的模块。