3、构建工具入门:Webpack核心概念(Entry、Output、Loader、Plugin)、Vite的优势与基本使用
聊到前端工程化,构建工具是绕不开的一环。我记得刚入行那会儿,项目里还在手动合并JS文件、用Grunt跑任务,那叫一个痛苦。后来Webpack横空出世,彻底改变了前端开发的构建方式。现在Vite又带来了新的体验。这一章,我们就来聊聊这两个工具的核心。
3.1 Webpack:模块打包的基石
Webpack本质上是一个静态模块打包器。它会分析你的项目结构,找到JavaScript模块以及其他浏览器不能直接运行的扩展语言(如SCSS、TypeScript),然后将其打包成合适的格式供浏览器使用。
我个人习惯把Webpack想象成一个工厂流水线。原料(源代码)进来,经过一道道工序(Loader),最后产出成品(打包后的文件)。这个过程中,还可以通过插件(Plugin)来优化、压缩、注入环境变量等。
3.1.1 Entry(入口)
入口就是Webpack开始构建的起点。它告诉Webpack:“嘿,从这里开始找依赖!”
最简单的配置就是一个单入口:
// webpack.config.js
module.exports = {
entry: './src/index.js'
};
如果你做的是多页面应用,也可以配置多个入口。我在项目中遇到过这种情况:一个后台管理系统,登录页和主后台是两套完全独立的页面,用多入口就很合适。
module.exports = {
entry: {
login: './src/login.js',
admin: './src/admin.js'
}
};
3.1.2 Output(输出)
输出告诉Webpack打包后的文件放哪里、叫什么名字。说白了,就是成品仓库。
module.exports = {
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
}
};
对于多入口配置,输出文件名需要动态生成:
module.exports = {
output: {
filename: '[name].[contenthash].js' // 比如 login.abc123.js
}
};
这里[contenthash]是个好东西。文件内容变了,hash才会变。浏览器就能准确判断要不要重新请求这个文件。我曾经因为没加hash,导致用户浏览器缓存了旧代码,线上出了bug排查了半天……嗯,从那以后我再也不敢省略contenthash了。
3.1.3 Loader(加载器)
Webpack原生只认识JavaScript和JSON。但我们的项目里还有CSS、图片、字体、TypeScript……怎么办?Loader就是用来处理这些非JS文件的。
Loader的执行顺序是从右到左,从下到上。这一点很容易踩坑。
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
// 先执行 css-loader(解析CSS),再执行 style-loader(把CSS注入到DOM)
},
{
test: /\.ts$/,
use: 'ts-loader'
}
]
}
};
常用的Loader我列个表,方便你查阅:
| Loader名称 | 用途 |
|---|---|
| babel-loader | 将ES6+语法转译为ES5 |
| css-loader | 解析CSS中的@import和url() |
| style-loader | 将CSS以<style>标签形式插入页面 |
| sass-loader | 将SCSS/SASS编译为CSS |
| file-loader | 处理图片、字体等文件资源 |
| url-loader | 将小文件转为base64内联,减少请求数 |
3.1.4 Plugin(插件)
Loader负责处理单个文件,而Plugin的能力范围更广。它可以监听Webpack构建的生命周期,在特定时机做事情。比如打包前清理dist目录、自动生成HTML文件、压缩代码等。
Plugin的使用方式是通过new关键字实例化:
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
plugins: [
new CleanWebpackPlugin(), // 每次打包前清理dist目录
new HtmlWebpackPlugin({ // 自动生成index.html并引入打包后的JS
template: './public/index.html'
})
]
};
你想想看,如果没有HtmlWebpackPlugin,你得手动在HTML里写script标签,而且每次打包后的文件名带hash,你还得手动改……那画面太美我不敢看。
- Loader:处理文件转换(比如TS→JS,SCSS→CSS)
- Plugin:处理构建流程中的各种任务(优化、资源管理、环境注入)
3.2 Vite:新一代构建工具
Webpack虽然强大,但有个痛点:项目大了以后,启动开发服务器要等很久。我记得有个老项目,Webpack Dev Server启动要40多秒,改一行代码热更新也要等3-5秒。开发体验真的很糟糕。
Vite的出现,就是为了解决这个问题。
3.2.1 Vite的优势
Vite的核心思路是:开发时用ES Module,生产构建用Rollup。说白了就是“开发快,打包稳”。
- 极速冷启动:不需要像Webpack那样先打包整个项目。Vite直接按需加载,启动秒级完成。
- 热更新快:改了哪个模块,只重新编译那个模块。不会像Webpack那样需要重新构建整个依赖图。
- 开箱即用:内置了对TypeScript、JSX、CSS预处理器、CSS Modules的支持。不用像Webpack那样装一堆Loader。
3.2.2 Vite的基本使用
创建一个Vite项目非常简单:
# 使用npm
npm create vite@latest my-project -- --template vue
# 使用yarn
yarn create vite my-project --template react
# 使用pnpm(我个人现在最常用)
pnpm create vite my-project --template vanilla-ts
Vite的配置文件是vite.config.js,比Webpack简洁很多:
// vite.config.js
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
export default defineConfig({
plugins: [vue()],
server: {
port: 3000,
open: true
},
build: {
outDir: 'dist',
sourcemap: false
}
});
你看,不需要配置Loader。Vite内部已经帮你处理好了。需要处理SCSS?直接装个sass依赖就行,不用配任何Loader。
3.2.3 什么时候用Webpack,什么时候用Vite?
这个问题我经常被问到。我的看法是这样的:
| 场景 | 推荐工具 | 原因 |
|---|---|---|
| 全新项目(Vue/React) | Vite | 开发体验好,配置简单 |
| 需要兼容低版本浏览器 | Webpack | 生态更成熟,兼容方案更完善 |
| 老项目维护 | Webpack | 迁移成本高,没必要折腾 |
| 库/组件库开发 | Vite + Rollup | 打包体积小,支持多种输出格式 |
| 需要高度自定义构建流程 | Webpack | Loader和Plugin生态更丰富 |
@vitejs/plugin-legacy虽然能处理大部分兼容问题,但遇到一些奇奇怪怪的第三方库时,还是Webpack的babel-loader更稳。
3.3 本章小结
这一章我们聊了Webpack的四个核心概念:Entry是起点,Output是终点,Loader处理文件,Plugin增强功能。Vite则用ES Module的思路,解决了Webpack在开发阶段的性能痛点。
我个人建议:Webpack要学透,Vite要会用。Webpack的很多设计思想(比如Loader链、插件机制)是前端工程化的通用知识。理解了Webpack,你再看其他构建工具,会发现很多相似之处。
下一章,我们会深入Webpack的高级配置,包括代码分割、懒加载、Tree Shaking这些实战中必用的优化手段。到时候我会分享一些我在大屏项目里用到的具体配置方案,敬请期待。