前端八股整理(工程化 02)|CommonJS/ESM、Webpack Loader/Plugin 与Vite 对比
1.CommonJS与ES6 Module的区别
在前端中,可以把编译阶段和运行阶段简单理解成:
编译阶段:代码还没真正执行,打包工具 / JS 引擎先分析代码结构的时候。
运行阶段:代码已经开始一行一行执行的时候。
CommonJS 和 ES6 Module 都是 JavaScript 的模块化规范。它们解决的问题是一个 JS 文件如何引入另一个 JS 文件?一个 JS 文件如何把自己的变量、函数、对象暴露给别人使用?
CommonJS 和ES6 Module最本质的区别在于对于模块依赖的解决是不同的,CommonJS 是"动态的",发生在代码运行阶段.ES6 Module 是"静态"的,发生在代码编译阶段.
在导入一个模块时,CommonJS 获取的是一份导出值的副本,所以CommonJS 允许对导出值进行更改,不会印象导出模块中的值.而在ES6 Module中则是值的动态映射,并且这个映射是只读的。
CommonJS 遇到循环依赖时,拿到的是一个未完成的导出对象,常见表现是 {};ES Module 遇到循环依赖时,导入的是实时绑定,如果太早访问,拿到的是 undefined.两者都应该尽量避免循环依赖,但可以通过"延迟使用导入值"的方式缓解,比如放到函数调用阶段再使用。
2.讲讲webpack中的loader和plugin?
Webpack 中的 loader 和 plugin 都是用来扩展 Webpack 能力的,但它们解决的问题不一样。
webpack 中的 loader 就是预处理器,可以理解为是一种函数,Webpack 默认主要只能处理 JavaScript 和 JSON,但前端项目里还会有 CSS、SCSS、图片、字体、Vue 单文件组件等资源,所以需要 loader 把这些资源转换成 Webpack 能够识别和打包的模块。
比如处理 SCSS 时,一般会经过:
scss 文件
-> sass-loader 编译成 css
-> css-loader 解析 CSS 里的 @import、url() 等依赖
-> style-loader 把 CSS 插入到页面 style 标签中
plugin 是插件,更偏"增强 Webpack 构建流程能力".Plugin 不只是处理某一种文件,它可以介入 Webpack 的整个生命周期,比如打包开始、模块解析、资源生成、打包结束等阶段,在这些阶段做额外的事情。
常见 plugin 例如:
HtmlWebpackPlugin:自动生成 HTML,并把打包后的 JS/CSS 注入进去
MiniCssExtractPlugin:把 CSS 从 JS 中抽离成单独的 CSS 文件
DefinePlugin:定义全局常量,比如 process.env.NODE_ENV
CleanWebpackPlugin:打包前清理 dist 目录
简单来说,loader 主要解决"某种资源怎么转换"的问题,plugin 主要解决"打包流程中额外要做什么事"的问题。
3.webpack和vite的区别
Webpack 本质上是模块打包器。它会从入口文件开始,递归分析整个项目的依赖关系,把 JS、CSS、图片、字体等资源都看成模块,然后通过 loader 转换资源、通过 plugin 扩展构建流程,最后打包成浏览器可以运行的 bundle(打包产物)。
Vite 更像是面向现代 Web 应用的开发构建工具。它在开发环境下利用浏览器原生支持 ES Module 的能力,不需要一开始把整个项目都打包好,而是让浏览器按需请求模块,Vite dev server 再对请求到的模块进行即时转换。所以 Vite 的冷启动和热更新通常更快。
两者最大的区别在开发阶段:
Webpack 通常是:先分析依赖 → 打包 bundle → dev server 提供访问
Vite 通常是:启动 dev server → 浏览器按需请求模块 → Vite 即时转换返回
Webpack 更大而全,生态成熟、可定制性强,适合复杂工程和历史项目;Vite 更轻、更快、更开箱即用,开发阶段基于原生 ESM 按需加载,生产阶段使用 Rollup 打包,更适合现代前端项目。