前端工程化面试题
⭐什么是前端工程化?
前端工程化:将软件工程的方法论应用到前端开发中,通过规范化、工具化、自动化手段提升开发效率、代码质量和可维护性。
核心维度:
| 维度 | 内容 |
|---|---|
| 模块化 | JS 模块(ESM/CJS)、CSS 模块化、组件化 |
| 包管理 | npm/yarn/pnpm 管理依赖 |
| 构建工具 | Webpack、Vite、Rollup 打包编译 |
| 代码规范 | ESLint、Prettier、Stylelint、EditorConfig |
| 版本控制 | Git Flow、语义化版本(semver) |
| 测试 | 单元测试(Vitest/Jest)、E2E(Playwright/Cypress) |
| CI/CD | 自动化构建、测试、部署(GitHub Actions、Jenkins) |
| 性能优化 | 代码分割、懒加载、缓存策略、CDN |
| 监控 | 错误监控(Sentry)、性能监控 |
⭐有哪些前端工程化工具或框架?
| 工具 | 描述 |
|---|---|
| Webpack | 模块打包器,支持 JS、CSS、图片等资源打包,插件生态丰富,适合复杂项目 |
| Vite | 现代开发首选,基于 ESM 的极速开发服务器,生产用 Rollup 打包 |
| Rollup | 专注于 JavaScript 库打包,原生支持 Tree Shaking,输出更小的生产包 |
| esbuild | Go 语言编写,构建速度极快(比 Webpack 快 10-100 倍),常作 Vite 底层转换工具 |
| Parcel | 零配置打包工具,开箱即用,适合小型项目或快速原型 |
| Turbopack | Vercel 推出的 Rust 构建工具,Next.js 的下一代打包器 |
⭐常见的 Webpack Loader 有哪些?各自的作用?
Loader 用于将非 JS 文件转换为 Webpack 可处理的模块。
| Loader | 作用 |
|---|---|
babel-loader | 转译 ES6+/JSX 到 ES5(依赖 @babel/core) |
ts-loader / esbuild-loader | 转译 TypeScript |
css-loader | 解析 CSS 中的 @import 和 url(),转为 JS 模块 |
style-loader | 将 CSS 注入 <style> 标签插入 DOM |
mini-css-extract-plugin | 将 CSS 提取为独立文件(生产环境代替 style-loader) |
sass-loader / less-loader | 编译 Sass/Less 预处理器 |
postcss-loader | 使用 PostCSS 处理 CSS(如自动添加前缀 autoprefixer) |
file-loader | 处理图片、字体等文件,返回 URL |
url-loader | 小文件转 Base64 内联,大文件调用 file-loader |
vue-loader | 解析 .vue 单文件组件 |
raw-loader | 将文件内容作为字符串导入 |
thread-loader | 多线程并行编译,提升构建速度 |
⭐常见的 Webpack Plugin 有哪些?各自的作用?
Plugin 用于扩展 Webpack 功能,在构建流程的特定时机执行任务。
| Plugin | 作用 |
|---|---|
HtmlWebpackPlugin | 自动生成 HTML 文件并注入打包后的 JS/CSS |
MiniCssExtractPlugin | 提取 CSS 为独立文件 |
CleanWebpackPlugin / output.clean | 构建前清除旧文件 |
DefinePlugin | 定义全局常量(如 process.env.NODE_ENV) |
CopyWebpackPlugin | 复制静态资源到输出目录 |
TerserPlugin | 压缩 JS(默认内置) |
CssMinimizerPlugin | 压缩 CSS |
BundleAnalyzerPlugin | 可视化分析打包体积 |
HotModuleReplacementPlugin | 热模块替换(HMR) |
CompressionPlugin | 生成 gzip/brotli 压缩文件 |
SplitChunksPlugin | 代码分割,提取公共模块(内置) |
⭐简述 Vite 相比 Webpack 的优势
开发环境:
- 利用浏览器原生 ESM,无需打包,启动极快(毫秒级 vs 分钟级)
- HMR 只更新改变的模块,响应速度极快
- 冷启动时间不受项目规模影响(Webpack 随项目增大而变慢)
生产环境:
- 基于 Rollup 打包,自动 Tree Shaking
- 配置更简洁,内置支持 TS、CSS 预处理器、静态资源等
开发体验:
- 插件 API 兼容 Rollup 生态
- 内置环境变量支持(
import.meta.env) - 内置 CSS Modules、JSON 导入等
启动时间对比(大型项目)
Webpack: ████████████████████ ~60s
Vite: ██ ~1s
⭐Webpack 的构建流程是什么?
初始化 → 编译 → 输出
- 初始化:读取
webpack.config.js,合并配置,创建 Compiler 实例 - 确定入口:从
entry配置找到入口文件 - 编译模块:
- 从入口文件开始,调用对应 Loader 转换文件内容
- 解析模块依赖(
import/require),递归处理所有依赖
- 生成依赖图:建立完整的模块依赖关系图(Module Graph)
- 代码分割:根据
SplitChunksPlugin配置,将模块分组为 Chunk - 输出文件:将 Chunk 转换为 Bundle,写入
output.path目录 - Plugin 钩子:在各阶段触发对应的 Plugin 生命周期钩子
⭐什么是 Tree Shaking?如何开启?
Tree Shaking:静态分析代码,移除未被引用的"死代码"(dead code),减小打包体积。
原理:依赖 ES Module 的静态导入/导出语法(import/export),在编译阶段可以确定哪些导出被使用。
Webpack 开启条件:
// webpack.config.js
module.exports = {
mode: 'production', // 生产模式自动开启
optimization: {
usedExports: true, // 标记未使用的导出
minimize: true, // 启用压缩(移除标记的代码)
}
}
// package.json - 告知 Webpack 哪些文件有副作用
{
"sideEffects": false, // 所有文件均无副作用(可安全 Tree Shake)
"sideEffects": ["*.css", "*.scss"] // 仅 CSS 文件有副作用
}
注意:CommonJS(require)不支持 Tree Shaking,必须使用 ES Module。
⭐什么是代码分割(Code Splitting)?
代码分割:将打包产物拆分为多个小文件,按需加载,减少首屏加载时间。
三种方式:
1. 多入口(Entry Points)
// webpack.config.js
module.exports = {
entry: {
app: './src/index.js',
admin: './src/admin.js'
}
}
2. 动态导入(Dynamic Import)- 推荐
// 点击时才加载模块
button.addEventListener('click', async () => {
const { Chart } = await import('./chart.js') // 生成独立 chunk
new Chart(data)
})
// Vue 路由懒加载
const routes = [
{ path: '/home', component: () => import('./views/Home.vue') }
]
3. SplitChunksPlugin(提取公共模块)
optimization: {
splitChunks: {
chunks: 'all', // 处理所有 chunk
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors', // 将 node_modules 打包到 vendors.js
chunks: 'all'
}
}
}
}
⭐ESLint 和 Prettier 的区别与配合使用
| 特性 | ESLint | Prettier |
|---|---|---|
| 定位 | 代码质量检查(发现错误) | 代码格式化(统一风格) |
| 关注点 | 语法错误、逻辑问题、最佳实践 | 缩进、引号、分号、换行 |
| 可自动修复 | 部分规则可修复 | 全部自动修复 |
| 配置文件 | .eslintrc.json | .prettierrc |
配合使用(避免冲突):
npm install -D eslint prettier eslint-config-prettier eslint-plugin-prettier
// .eslintrc.json
{
"extends": [
"eslint:recommended",
"plugin:vue/vue3-recommended",
"prettier" // 关闭与 Prettier 冲突的 ESLint 格式规则(放最后)
],
"plugins": ["prettier"],
"rules": {
"prettier/prettier": "error" // 将 Prettier 规则作为 ESLint 错误
}
}
// .prettierrc
{
"semi": false,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "none",
"printWidth": 100
}
⭐什么是 CI/CD?前端如何实践?
CI(持续集成):代码合并时自动运行测试、lint、构建,快速发现问题。 CD(持续交付/部署):构建通过后自动部署到测试或生产环境。
GitHub Actions 示例:
# .github/workflows/deploy.yml
name: CI/CD
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Lint
run: npm run lint
- name: Run tests
run: npm run test
- name: Build
run: npm run build
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
if: github.ref == 'refs/heads/main'
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./dist
⭐前端模块化的发展历程
| 阶段 | 方案 | 特点 |
|---|---|---|
| 无模块化 | 全局变量、命名空间 | 污染全局、依赖混乱 |
| IIFE | 立即执行函数 | 创建独立作用域,手动暴露 API |
| CommonJS | require/module.exports | Node.js 采用,同步加载,不适合浏览器 |
| AMD | define/require(RequireJS) | 异步加载,适合浏览器,语法繁琐 |
| CMD | SeaJS | 懒加载,国内流行 |
| UMD | 兼容 CommonJS + AMD | 用于发布跨环境的库 |
| ES Module | import/export | 语言标准,静态分析,支持 Tree Shaking,现代标准 |
// IIFE(早期)
var MyLib = (function() {
var private = 'secret'
return { public: 'hello' }
})()
// CommonJS(Node.js)
const lib = require('./lib')
module.exports = { foo: 'bar' }
// ES Module(现代)
import { foo } from './lib.js'
export const bar = 'baz'