概览
前端工程化是将软件工程的原则、方法和最佳实践应用于前端开发流程,旨在提高效率、保证质量、降低维护成本的一系列技术和工具的总称。随着 Web 应用(尤其是单页应用 SPA、渐进式 Web 应用 PWA)的复杂度日益增加,前端代码库的规模、团队协作的需求、性能优化的挑战都对开发流程提出了更高的要求。
前端工程化的核心目标是解决以下痛点:
- 开发效率低下: 重复性工作多,缺乏自动化工具,环境配置复杂。
- 代码质量参差不齐: 缺乏统一规范,代码风格混乱,潜在错误难以发现。
- 可维护性差: 模块划分不清,耦合度高,难以扩展和重构。
- 协作困难: 不同开发者的编码习惯、环境不一致,集成困难。
- 性能问题: 资源加载慢,代码体积大,缺乏系统性优化手段。
- 部署流程繁琐: 手动部署易出错,发布周期长。
前端工程化并非一套固定的标准,而是一个不断演进的领域,它涵盖了从编码、测试、构建到部署的整个生命周期。下面将详细介绍前端工程化的几个关键方面。
1. 模块化
模块化是指将一个复杂的系统分解为多个独立的、可重用的模块单元,每个模块负责特定的功能。在前端开发中,模块化主要解决全局变量污染、依赖管理混乱、代码组织困难等问题。
模块化规范
目前主流的 JavaScript 模块化规范有:
-
CommonJS (CJS)
-
说明: 主要用于 Node.js 环境。模块加载是同步的。通过
require()
导入模块,通过module.exports
或exports
导出接口。 -
示例:
// math.js
function add(a, b) {
return a + b;
}
const PI = 3.14;
module.exports = {
add,
PI,
};
// 或者使用 exports (注意不能直接给 exports 赋值)
// exports.add = add;
// exports.PI = PI;// main.js
const math = require("./math"); // 同步加载
console.log(math.add(1, 2)); // 输出: 3
console.log(math.PI); // 输出: 3.14
-
-
AMD (Asynchronous Module Definition)
-
说明: 主要用于浏览器环境,解决了 CommonJS 同步加载不适用于浏览器的问题。代表库是 RequireJS。模块加载是异步的,推崇依赖前置。
-
示例:
// math.js
define(function () {
// 定义一个匿名模块
function add(a, b) {
return a + b;
}
const PI = 3.14;
return {
// 导出接口
add,
PI,
};
});// main.js
require(["./math"], function (math) {
// 异步加载依赖,加载完成后执行回调
console.log(math.add(1, 2));
console.log(math.PI);
});
// 也可以先声明依赖
// define(['./math'], function(math) {
// console.log(math.add(1, 2));
// });
-
-
UMD (Universal Module Definition)
- 说明: 兼容 CommonJS 和 AMD,同时支持全局变量模式。使得一个模块可以在多种环境下运行。常用于需要跨平台发布的库。
- 示例 (常见模式):
(function (root, factory) {
if (typeof define === "function" && define.amd) {
// AMD. Register as an anonymous module.
define(["dependency1", "dependency2"], factory);
} else if (typeof module === "object" && module.exports) {
// Node. Does not work with strict CommonJS, but
// only CommonJS-like environments that support module.exports,
// like Node.
module.exports = factory(
require("dependency1"),
require("dependency2")
);
} else {
// Browser globals (root is window)
root.myLib = factory(root.dependency1, root.dependency2);
}
})(typeof self !== "undefined" ? self : this, function (dep1, dep2) {
// 这是模块的主体,使用 dep1 和 dep2
function myMethod() {
// ...
}
// 返回要导出的内容
return {
method: myMethod,
};
});
-
ES6 Modules (ESM)
-
说明: ECMA TC39 制定的官方模块化标准,已在现代浏览器和 Node.js 中原生支持。使用
import
导入和export
导出。模块加载可以是同步也可以是异步(由加载器决定,浏览器中默认异步),具有静态分析特性(可在编译时确定依赖关系),这使得 Tree Shaking 等优化成为可能。 -
示例:
// utils.js
export function log(message) {
// 命名导出
console.log(`[LOG] ${message}`);
}
export const APP_NAME = "My App"; // 命名导出
const privateVar = "secret";
export default function greet(name) {
// 默认导出 (每个模块只能有一个)
return `Hello, ${name}! from ${APP_NAME}`;
}// app.js
import greet, { log, APP_NAME as AppTitle } from "./utils.js"; // 导入默认、命名导出,并重命名
// 或导入整个模块
// import * as utils from './utils.js';
log("App starting...");
console.log(greet("World"));
console.log(`App Title: ${AppTitle}`);
// console.log(utils.greet('World')); // 如果使用 import *<!-- 在浏览器中使用 -->
<script type="module" src="app.js"></script>
-
2. 组件化
组件化是在模块化的基础上,将 UI 界面拆分成更小、独立、可复用的单元(组件),每个组件包含自身的结构 (HTML/Template)、样式 (CSS) 和行为 (JavaScript)。组件化提高了 UI 的复用性、可维护性和可组合性。
实现方式
-
框架/库驱动:
-
React:
-
说明: 使用 JSX 语法描述 UI 结构,通过 Virtual DOM 进行高效更新。组件通常是函数或类,通过 props 接收数据,通过 state 管理自身状态。Hooks API (如
useState
,useEffect
) 提供了函数组件状态管理和副作用处理的能力。 -
示例 (函数组件):
import React, { useState, useEffect } from "react";
import "./Button.css";
function Button({ initialCount = 0, label = "Click Me" }) {
const [count, setCount] = useState(initialCount);
useEffect(() => {
// 示例副作用:当 count 变化时更新文档标题
document.title = `Count: ${count}`;
}, [count]); // 依赖项数组,仅在 count 变化时执行
const handleClick = () => {
setCount(count + 1);
};
return (
<button className="custom-button" onClick={handleClick}>
{label}: {count}
</button>
);
}
export default Button;
-
-
Vue:
-
说明: 采用模板语法(或 JSX),具有响应式数据系统。组件通常定义在单文件组件(.vue 文件)中,包含
<template>
,<script>
,<style>
部分。Vue 3 的 Composition API (如ref
,computed
,onMounted
) 提供了更灵活的逻辑组织方式。 -
示例 (Vue 3 Composition API -
<script setup>
)<template>
<button class="custom-button" @click="increment">
{{ label }}: {{ count }}
</button>
</template>
<script setup>
import { ref, computed, onMounted, defineProps } from "vue";
// 定义 props
const props = defineProps({
initialCount: {
type: Number,
default: 0,
},
label: {
type: String,
default: "Click Me",
},
});
// 响应式状态
const count = ref(props.initialCount);
// 方法
const increment = () => {
count.value++;
};
// 计算属性 (示例)
const doubleCount = computed(() => count.value * 2);
// 生命周期钩子
onMounted(() => {
console.log(`Button component with label "${props.label}" mounted.`);
});
// (不需要显式导出,<script setup> 会自动处理)
</script>
<style scoped>
/* scoped 样式只作用于当前组件 */
.custom-button {
padding: 8px 15px;
background-color: #42b983;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.custom-button:hover {
background-color: #3ca876;
}
</style>
-
-
Angular:
-
说明: 一个功能完备的框架,基于 TypeScript。强调模块化 (NgModules)、依赖注入 (DI) 和组件化。使用 HTML 模板和特定的指令语法。
-
示例 (组件):
// counter.component.ts
import { Component, Input, OnInit } from "@angular/core";
@Component({
selector: "app-counter", // 组件在 HTML 中的标签名
template: `
<button (click)="increment()">{{ label }}: {{ count }}</button>
`, // 内联模板
// templateUrl: './counter.component.html', // 或外部模板文件
styles: [
`
button {
padding: 8px 15px;
background-color: #dd0031;
color: white;
border: none;
}
`,
], // 内联样式
// styleUrls: ['./counter.component.css'] // 或外部样式文件
})
export class CounterComponent implements OnInit {
@Input() label: string = "Click Me"; // 输入属性
@Input() initialCount: number = 0;
count: number = 0;
ngOnInit(): void {
this.count = this.initialCount;
console.log("Counter component initialized");
}
increment(): void {
this.count++;
}
}// app.module.ts (需要声明组件)
import { NgModule } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";
import { AppComponent } from "./app.component";
import { CounterComponent } from "./counter.component"; // 引入组件
@NgModule({
declarations: [
AppComponent,
CounterComponent, // 声明组件
],
imports: [BrowserModule],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
-
-
Svelte / SolidJS 等:
- 说明: Svelte 在编译时处理响应性,生成高效的命令式代码,无运行时框架开销。SolidJS 采用类似 React 的 JSX 和细粒度响应性,但没有 Virtual DOM。
-
-
Web Components:
-
说明: 一套 W3C 标准技术,允许创建可复用的、封装良好的自定义 HTML 元素,不依赖任何特定框架。主要包括:
- Custom Elements: 定义自定义 HTML 标签。
- Shadow DOM: 提供封装的 DOM 和 CSS 作用域。
- HTML Templates (
<template>
和<slot>
): 定义可复用的 HTML 结构。 - ES Modules: 作为模块加载和定义方式。
-
示例:
// simple-counter.js
const template = document.createElement("template");
template.innerHTML = `
<style>
button {
background-color: orange;
color: white;
padding: 5px 10px;
border: none;
border-radius: 3px;
}
span {
margin-left: 10px;
font-weight: bold;
}
</style>
<button>Click Me</button>
<span>Count: 0</span>
`;
class SimpleCounter extends HTMLElement {
constructor() {
super();
this.count = 0;
// 创建 Shadow Root
this.attachShadow({ mode: "open" }); // 'open' 允许外部 JS 访问 Shadow DOM
// 将模板内容克隆到 Shadow Root
this.shadowRoot.appendChild(template.content.cloneNode(true));
// 获取 Shadow DOM 内的元素
this.button = this.shadowRoot.querySelector("button");
this.countSpan = this.shadowRoot.querySelector("span");
}
// 当元素添加到文档 DOM 时调用
connectedCallback() {
this.button.addEventListener("click", this._increment);
this._updateCount(); // 初始化显示
}
// 当元素从文档 DOM 移除时调用
disconnectedCallback() {
this.button.removeEventListener("click", this._increment);
}
// 使用箭头函数绑定 this
_increment = () => {
this.count++;
this._updateCount();
};
_updateCount() {
this.countSpan.textContent = `Count: ${this.count}`;
}
}
// 定义自定义元素
window.customElements.define("simple-counter", SimpleCounter);<!-- 在 HTML 中使用 -->
<simple-counter></simple-counter>
<simple-counter></simple-counter>
<script src="simple-counter.js"></script>
-
3. 构建与优化
构建是将源代码(可能包含 ESNext 语法、TypeScript、JSX、Sass/Less 等)转换、编译、打包成浏览器可识别和执行的静态资源(HTML, CSS, JavaScript)的过程。优化是构建过程中的重要环节,旨在减少资源体积、提高加载速度和运行性能。
主要构建工具
-
Webpack:
-
说明: 功能最强大、生态最完善的模块打包器。基于 Loader 和 Plugin 机制高度可配置,支持代码分割、Tree Shaking、HMR(热模块替换)、资源管理等。适用于大型复杂项目。学习曲线相对较陡。
-
示例 (
webpack.config.js
极简版):// webpack.config.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
mode: "development", // 或 'production'
entry: "./src/index.js", // 入口文件
output: {
filename: "bundle.[contenthash].js", // 输出文件名 (带 hash)
path: path.resolve(__dirname, "dist"), // 输出目录
clean: true, // 清理 dist 目录
},
module: {
rules: [
{
// 处理 JavaScript (ES6+)
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader", // 需要安装 babel-loader @babel/core @babel/preset-env
options: { presets: ["@babel/preset-env"] },
},
},
{
// 处理 CSS
test: /\.css$/,
use: ["style-loader", "css-loader"], // 需要安装 style-loader css-loader
},
],
},
plugins: [
new HtmlWebpackPlugin({
// 生成 HTML 并注入 bundle
template: "./src/index.html",
}),
],
devServer: {
// 开发服务器配置
static: "./dist",
hot: true,
},
devtool: "inline-source-map", // Source Map 配置
};
-
-
Rollup:
-
说明: 更专注于 JavaScript 库的打包。对 ES Modules 支持极好,Tree Shaking 效果出色,能生成更小、更干净的代码。常用于构建供其他项目使用的 npm 包。Vite 的生产构建也基于 Rollup。
-
示例 (
rollup.config.js
极简版 - 构建库):// rollup.config.js
import resolve from "@rollup/plugin-node-resolve"; // 解析 node_modules
import commonjs from "@rollup/plugin-commonjs"; // 转换 CJS 为 ESM
import babel from "@rollup/plugin-babel"; // 使用 Babel
export default {
input: "src/index.js", // 库入口
output: [
{ file: "dist/my-lib.cjs.js", format: "cjs", sourcemap: true }, // CommonJS
{ file: "dist/my-lib.esm.js", format: "es", sourcemap: true }, // ES Module
{
file: "dist/my-lib.umd.js",
format: "umd",
name: "MyLibrary",
sourcemap: true,
}, // UMD
],
plugins: [
resolve(),
commonjs(),
babel({ babelHelpers: "bundled", exclude: "node_modules/**" }), // 需要 Babel 配置
],
};
-
-
Vite:
-
说明: 新一代前端构建工具。开发环境下利用浏览器原生 ES Modules 和 esbuild (Go 编写) 实现极快的冷启动和 HMR。生产环境使用 Rollup 打包。提供开箱即用的配置,开发体验极佳。
-
示例 (
vite.config.js
极简版 - React 项目):// vite.config.js
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react"; // Vite 的 React 插件
import path from "path";
export default defineConfig({
plugins: [react()], // 启用 React 支持 (包括 Fast Refresh)
resolve: {
alias: {
// 配置别名
"@": path.resolve(__dirname, "./src"),
},
},
server: {
// 开发服务器配置
port: 3000,
open: true, // 自动打开浏览器
},
build: {
// 生产构建配置 (基于 Rollup)
sourcemap: true,
},
});
-
-
Rspack:
-
说明: 由 ByteDance Web Infra 团队主导,基于 Rust 开发的高性能构建工具。旨在提供极快的构建速度,同时保持与 Webpack 生态的兼容性。内置了许多 Rust 实现的高性能 Loader 和 Plugin。
-
示例 (
rspack.config.js
极简版):// rspack.config.js
const rspack = require("@rspack/core");
const path = require("path");
/** @type {import('@rspack/cli').Configuration} */
const config = {
mode: "development",
entry: "./src/index.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "dist"),
clean: true,
},
module: {
rules: [
// Rspack 内置了对 JS/TS/JSX/TSX 的处理 (使用 SWC)
{ test: /\.css$/, type: "css" }, // 内置 CSS 处理
{ test: /\.(png|svg)$/, type: "asset/resource" }, // 内置资源处理
],
},
plugins: [
new rspack.HtmlRspackPlugin({ template: "./src/index.html" }), // 内置 HTML 插件
],
devServer: {
hot: true,
port: 8080,
},
// devtool: 'source-map',
};
module.exports = config;
-
核心优化手段
- 代码压缩 (Minification): 移除空格、注释、缩短变量名 (JS: Terser, esbuild, SWC; CSS: cssnano, Lightning CSS)。
- Tree Shaking: 移除未使用的代码 (依赖 ES Modules 的静态结构)。
- 代码分割 (Code Splitting): 将代码拆分成多个 chunk,按需加载或并行加载,减小初始包体积 (入口分割、动态
import()
、公共依赖提取)。 - 图片优化: 压缩图片体积,使用 WebP/AVIF 等现代格式。
- 按需加载 (Lazy Loading): 延迟加载非首屏必需的组件或模块。
- 缓存利用: 通过文件名加 hash 实现浏览器和 CDN 的长期缓存。
4. 自动化测试
自动化测试是通过编写脚本来执行测试用例,验证代码功能是否符合预期。它能有效防止代码回归(即修复了一个 bug 导致另一个 bug 出现),提高代码质量和发布信心。
测试类型
-
单元测试 (Unit Testing):
-
说明: 针对程序中最小的可测试单元(如函数、类、组件的某个方法)进行测试,通常在隔离的环境中进行,速度快。
-
工具: Jest, Vitest, Mocha, Jasmine。
-
示例 (使用 Jest/Vitest):
// sum.js
export function sum(a, b) {
return a + b;
}
// sum.test.js
import { describe, it, expect } from "vitest"; // 或 import {describe, test, expect} from '@jest/globals';
import { sum } from "./sum";
describe("sum function", () => {
it("should add two positive numbers correctly", () => {
expect(sum(1, 2)).toBe(3);
});
it("should add a positive and a negative number correctly", () => {
expect(sum(5, -3)).toBe(2);
});
it("should add two zeros correctly", () => {
expect(sum(0, 0)).toBe(0);
});
});// package.json script (示例)
"scripts": {
"test:unit": "vitest run" // 或 "jest"
}
-
-
端到端测试 (End-to-End Testing / E2E Testing):
-
说明: 模拟真实用户场景,在浏览器环境中测试整个应用的流程,从用户界面交互到后端 API 调用(可选)。速度较慢,但覆盖更全面。
-
工具: Cypress, Playwright, Selenium WebDriver。
-
示例 (使用 Cypress - 概念性):
// cypress/e2e/login.cy.js
describe("Login Flow", () => {
it("should login successfully with valid credentials", () => {
cy.visit("/login"); // 访问登录页面
cy.get('input[name="username"]').type("testuser"); // 输入用户名
cy.get('input[name="password"]').type("password123"); // 输入密码
cy.get('button[type="submit"]').click(); // 点击登录按钮
cy.url().should("include", "/dashboard"); // 断言 URL 跳转到仪表盘
cy.contains("Welcome, testuser").should("be.visible"); // 断言页面包含欢迎语
});
it("should display error message with invalid credentials", () => {
cy.visit("/login");
cy.get('input[name="username"]').type("invaliduser");
cy.get('input[name="password"]').type("wrongpassword");
cy.get('button[type="submit"]').click();
cy.get(".error-message")
.should("be.visible")
.and("contain", "Invalid username or password"); // 断言错误消息
cy.url().should("include", "/login"); // 断言 URL 仍在登录页
});
});// package.json script (示例)
"scripts": {
"test:e2e": "cypress run" // 或 "cypress open" 启动 GUI
}
-
5. 持续集成 (Continuous Integration - CI)
持续集成是一种软件开发实践,团队成员频繁地将其代码变更集成到共享仓库的主干(如 main 或 master 分支)中。每次集成都会通过自动化的构建和测试流程来验证,从而尽早发现和修复集成错误。
CI 工具/平台
- Travis CI
- CircleCI
- GitHub Actions (与 GitHub 深度集成,非常流行)
- Jenkins (老牌开源 CI/CD 服务器,自托管)
- GitLab CI/CD (与 GitLab 深度集成)
CI 流程通常包括:
- 代码提交到版本控制系统 (如 Git)。
- CI 服务器检测到变更,触发 CI 流程。
- 拉取最新代码。
- 安装项目依赖 (
npm install
,yarn install
,pnpm install
,bun install
)。 - 执行代码质量检查 (
npm run lint
)。 - 执行自动化测试 (
npm run test:unit
,npm run test:e2e
)。 - 执行构建 (
npm run build
)。 - (可选) 生成构建产物报告或通知。
示例 (GitHub Actions - .github/workflows/ci.yml
)
name: Frontend CI
on: # 触发条件
push: # 推送到指定分支时
branches: [main, develop]
pull_request: # 创建或更新 Pull Request 到指定分支时
branches: [main]
jobs: # CI 任务
build-and-test: # 任务 ID
runs-on: ubuntu-latest # 运行环境
strategy: # 构建策略 (例如测试不同 Node 版本)
matrix:
node-version: [18.x, 20.x] # 测试 Node 18 和 20
steps: # 任务步骤
- name: Checkout repository # 步骤 1: 拉取代码
uses: actions/checkout@v4 # 使用官方 action
- name: Set up Node.js ${{ matrix.node-version }} # 步骤 2: 设置 Node.js 环境
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: "npm" # 启用 npm 依赖缓存
- name: Install dependencies # 步骤 3: 安装依赖
run: npm ci # 使用 ci 更快更稳定,基于 package-lock.json
- name: Run linters # 步骤 4: 运行代码检查
run: npm run lint
- name: Run unit tests # 步骤 5: 运行单元测试
run: npm run test:unit
- name: Build project # 步骤 6: 执行构建
run: npm run build
# - name: Run E2E tests (可选,可能需要更复杂设置)
# run: npm run test:e2e
6. 持续部署 (Continuous Deployment - CD)
持续部署是持续集成的延伸,它将在 CI 流程中成功构建和测试通过的代码变更,自动部署到生产环境或预发布环境。CD 旨在缩短发布周期,减少手动部署的风险。
CD 工具/平台
- Vercel: 非常适合 Next.js 和其他前端框架,提供无缝的 Git 集成和自动部署。
- Netlify: 类似 Vercel,提供强大的前端托管和部署功能,支持 Functions (Serverless)。
- Heroku: 传统的 PaaS 平台,支持多种语言包括 Node.js 应用部署。
- GitHub Pages: 免费托管静态网站,常用于项目文档或个人博客。
- 云服务商: AWS (S3 + CloudFront, Amplify, ECS/EKS), Google Cloud (Cloud Run, GKE), Azure (Static Web Apps, AKS)。
- Jenkins / GitLab CI/CD: 也可用于编排部署流程。
CD 流程通常是:
- CI 流程成功完成(构建和测试通过)。
- 触发 CD 流程(通常只在特定分支如
main
上触发)。 - 将构建产物(如
dist
目录)部署到目标环境。 - (可选) 运行部署后检查,如冒烟测试。
- (可选) 发送部署成功/失败通知。
示例 (扩展 GitHub Actions 实现部署到 GitHub Pages)
name: Frontend CI/CD
on:
push:
branches: [main] # 只在 main 分支推送时触发部署
# pull_request: ... (CI 部分保持不变)
jobs:
build-test-deploy:
runs-on: ubuntu-latest
permissions: # 需要权限来写入 GitHub Pages
contents: read
pages: write
id-token: write
environment: # 指定部署环境 (用于 GitHub Pages)
name: github-pages
url: ${{ steps.deployment.outputs.page_url }} # 输出部署后的 URL
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 18.x
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Run linters
run: npm run lint
- name: Run unit tests
run: npm run test:unit
- name: Build project # 构建,产物通常在 dist 或 build 目录
run: npm run build
- name: Setup Pages # 配置 GitHub Pages
uses: actions/configure-pages@v4
- name: Upload artifact # 上传构建产物给部署步骤
uses: actions/upload-pages-artifact@v3
with:
path: "./dist" # 指定构建产物的目录
- name: Deploy to GitHub Pages # 执行部署
id: deployment
uses: actions/deploy-pages@v4
注意:需要现在 GitHub 仓库设置中启用 GitHub Pages,并选择部署源为 "GitHub Actions"。
7. 规范化
规范化是指在团队内部或项目中建立一套统一的标准和规则,涵盖代码风格、提交信息、开发流程等方面,以提高代码一致性、可读性和协作效率。
主要规范化工具
-
ESLint:
- 说明: 最流行的 JavaScript/TypeScript 代码检查工具(Linter)。通过配置规则来发现代码中的潜在错误、不合理写法或不符合风格约定的地方。
- 示例 (
.eslintrc.json
):{
"env": {
// 指定代码运行环境
"browser": true,
"es2021": true,
"node": true
},
"extends": [
// 继承推荐的规则集
"eslint:recommended",
"plugin:react/recommended", // React 推荐规则 (需安装 eslint-plugin-react)
"plugin:prettier/recommended" // 集成 Prettier (需安装 eslint-plugin-prettier eslint-config-prettier)
],
"parserOptions": {
// 解析器选项
"ecmaFeatures": { "jsx": true },
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": [
// 使用插件
"react"
],
"rules": {
// 自定义或覆盖规则
"indent": ["error", 2], // 缩进为 2 个空格
"linebreak-style": ["error", "unix"], // 换行符为 LF
"quotes": ["error", "single"], // 使用单引号
"semi": ["error", "always"], // 总是使用分号
"react/prop-types": "off" // 关闭 prop-types 检查 (如果使用 TS 或不关心)
},
"settings": {
// 插件设置 (例如 React 版本)
"react": { "version": "detect" }
}
} package.json
脚本:"scripts": {
"lint": "eslint \"src/**/*.{js,jsx,ts,tsx}\"", // 检查 src 下所有 JS/JSX/TS/TSX 文件
"lint:fix": "eslint \"src/**/*.{js,jsx,ts,tsx}\" --fix" // 尝试自动修复问题
}
-
Prettier:
- 说明: 一个“有主见”的代码格式化工具(Formatter)。它专注于代码的格式,强制应用统一的风格,不关心代码逻辑错误。通常与 ESLint 配合使用(ESLint 负责逻辑和部分风格,Prettier 负责主要格式化)。
- 示例 (
.prettierrc.json
):{
"semi": true, // 句末加分号
"singleQuote": true, // 使用单引号
"tabWidth": 2, // Tab 宽度为 2
"trailingComma": "es5", // 对象/数组末尾逗号 (ES5 标准)
"printWidth": 80, // 行宽限制
"arrowParens": "always" // 箭头函数参数始终带括号
} package.json
脚本:"scripts": {
"format": "prettier --write \"src/**/*.{js,jsx,ts,tsx,css,md,json}\"", // 格式化多种文件类型
"format:check": "prettier --check \"src/**/*.{js,jsx,ts,tsx,css,md,json}\"" // 检查是否符合格式
}
-
Stylelint:
- 说明: 类似于 ESLint,但专注于 CSS、Sass、Less 等样式文件的检查和格式化。
- 示例 (
.stylelintrc.json
):{
"extends": [
"stylelint-config-standard", // 标准规则集
"stylelint-config-prettier" // 禁用与 Prettier 冲突的规则
],
"rules": {
"selector-class-pattern": null, // (可选) 自定义类名规则
"indentation": 2 // 缩进
}
}
-
Husky & lint-staged:
- 说明: Husky 用于方便地管理 Git Hooks(如
pre-commit
,pre-push
)。lint-staged 可以让你只对 Git 暂存区(staged)的文件执行 Linter 和 Formatter。二者结合可以在提交代码前自动检查和格式化,保证入库代码的质量和一致性。 - 示例 (
package.json
配置):需要先安装 husky 和 lint-staged ({
"scripts": {
"prepare": "husky install" // npm/yarn/pnpm install 后自动执行,安装 husky hooks
},
"husky": {
"hooks": {
"pre-commit": "lint-staged" // 在 pre-commit 钩子中运行 lint-staged
}
},
"lint-staged": {
// 配置 lint-staged
"*.{js,jsx,ts,tsx}": [
// 对暂存的 JS/TSX 文件执行
"eslint --fix", // 先用 ESLint 修复
"prettier --write" // 再用 Prettier 格式化
],
"*.{css,scss,less,md,json}": [
// 对其他文件执行
"prettier --write" // 只用 Prettier 格式化
]
}
}npm install -D husky lint-staged
), 然后运行npx husky install
(或让prepare
脚本自动运行)。
- 说明: Husky 用于方便地管理 Git Hooks(如
-
Commitlint:
- 说明: 用于规范 Git 提交信息(Commit Message)的格式,通常遵循 Angular 规范。配合 Husky 的
commit-msg
钩子使用。 - 示例 (
commitlint.config.js
):需要在 Husky 中添加module.exports = { extends: ["@commitlint/config-conventional"] };
commit-msg
钩子:npx husky add .husky/commit-msg 'npx --no -- commitlint --edit "$1"'
(需要安装@commitlint/cli @commitlint/config-conventional
)。
- 说明: 用于规范 Git 提交信息(Commit Message)的格式,通常遵循 Angular 规范。配合 Husky 的
8. 包管理工具
包管理工具负责管理项目的依赖(第三方库、框架、工具),包括安装、更新、删除、版本锁定等。它们确保了开发、测试、生产环境依赖的一致性。
主流包管理工具
-
npm (Node Package Manager):
- 说明: Node.js 自带的默认包管理器,使用
package.json
记录依赖,package-lock.json
锁定依赖版本树,依赖安装在项目的node_modules
目录下。生态最庞大。 - 常用命令:
npm install <package-name> # 安装依赖 (默认添加到 dependencies)
npm install <package-name> --save-dev # 安装开发依赖 (添加到 devDependencies)
npm install # 安装 package.json 中的所有依赖
npm update <package-name> # 更新指定依赖
npm uninstall <package-name> # 卸载依赖
npm run <script-name> # 运行 package.json scripts 中的脚本
npm ci # 清理 node_modules 并严格按照 package-lock.json 安装,速度更快,用于 CI 环境
npm list # 查看已安装依赖
- 说明: Node.js 自带的默认包管理器,使用
-
yarn (Yet Another Resource Negotiator):
- 说明: 由 Facebook (Meta) 等公司推出,旨在解决早期 npm 的性能和一致性问题。使用
yarn.lock
文件锁定版本。Yarn Classic (v1) 与 npm 类似。Yarn Berry (v2+) 引入了 Plug'n'Play (PnP) 机制,尝试去除node_modules
,依赖直接从缓存中加载,安装更快,依赖管理更严格。 - 常用命令 (Yarn Classic v1):
yarn add <package-name> # 安装依赖
yarn add <package-name> --dev # 安装开发依赖
yarn install # 安装所有依赖
yarn upgrade <package-name> # 更新指定依赖
yarn remove <package-name> # 卸载依赖
yarn run <script-name> # 运行脚本 (也可直接 yarn <script-name>)
# Yarn v1 没有完全对应的 npm ci,但 install 已足够稳定
yarn list # 查看依赖 - 常用命令 (Yarn Berry v2+): (部分命令相同,但行为可能基于 PnP)
yarn add <package-name>
yarn add <package-name> -D # 开发依赖
yarn install
yarn up <package-name> # 更新
yarn remove <package-name>
yarn <script-name>
yarn dlx <command> # 类似 npx
- 说明: 由 Facebook (Meta) 等公司推出,旨在解决早期 npm 的性能和一致性问题。使用
-
pnpm (performant npm):
- 说明: 重点解决 npm/yarn 的磁盘空间占用和依赖管理问题。通过将依赖存储在全局的 store 中,并在项目
node_modules
里使用硬链接(hard links)或符号链接(symlinks),极大节省磁盘空间。默认采用更严格的依赖管理,防止“幻影依赖”(项目中可以直接引用未在package.json
中声明的子依赖)。安装速度通常也很快。 - 常用命令:
pnpm add <package-name>
pnpm add <package-name> -D # 开发依赖
pnpm install
pnpm update <package-name>
pnpm remove <package-name>
pnpm run <script-name> # 运行脚本 (也可直接 pnpm <script-name>)
pnpm list
pnpm why <package-name> # 查看为什么安装了某个包
- 说明: 重点解决 npm/yarn 的磁盘空间占用和依赖管理问题。通过将依赖存储在全局的 store 中,并在项目
-
Bun:
- 说明: 一个新兴的、用 Zig 语言编写的 JavaScript 全能工具包,目标是成为一个极速的运行时、打包器、测试运行器和包管理器。其内置的包管理器兼容 npm 的
package.json
,安装速度极快。 - 常用命令:
bun add <package-name>
bun add <package-name> --dev # 开发依赖
bun install
bun update <package-name>
bun remove <package-name>
bun run <script-name> # 运行脚本 (也可直接 bun <script-name>)
- 说明: 一个新兴的、用 Zig 语言编写的 JavaScript 全能工具包,目标是成为一个极速的运行时、打包器、测试运行器和包管理器。其内置的包管理器兼容 npm 的
前端工程化是一个系统工程,上述各个方面相互关联,共同构成了现代前端开发的基石。合理运用工程化手段,可以显著提升开发效率、代码质量和项目的长期健康度。