Skip to content

前端工程化

目录

构建工具

Webpack

javascript
// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[contenthash].js',
    clean: true
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env', '@babel/preset-react']
          }
        }
      },
      {
        test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader']
      },
      {
        test: /\.(png|svg|jpg|jpeg|gif)$/i,
        type: 'asset/resource'
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    new MiniCssExtractPlugin({
      filename: '[name].[contenthash].css'
    })
  ],
  optimization: {
    splitChunks: {
      chunks: 'all'
    }
  }
};

说明

  • Webpack 是模块打包工具
  • 支持多种文件类型
  • 可以优化资源加载
  • 支持代码分割

Vite

javascript
// vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';

export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src')
    }
  },
  build: {
    outDir: 'dist',
    minify: 'terser',
    rollupOptions: {
      output: {
        manualChunks: {
          vendor: ['react', 'react-dom'],
          utils: ['lodash', 'axios']
        }
      }
    }
  },
  server: {
    port: 3000,
    proxy: {
      '/api': {
        target: 'http://localhost:8080',
        changeOrigin: true
      }
    }
  }
});

说明

  • Vite 是新一代构建工具
  • 开发环境使用原生 ESM
  • 生产环境使用 Rollup
  • 支持热更新

Rollup

javascript
// rollup.config.js
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import babel from '@rollup/plugin-babel';
import terser from '@rollup/plugin-terser';

export default {
  input: 'src/index.js',
  output: [
    {
      file: 'dist/bundle.js',
      format: 'cjs'
    },
    {
      file: 'dist/bundle.esm.js',
      format: 'esm'
    }
  ],
  plugins: [
    resolve(),
    commonjs(),
    babel({
      babelHelpers: 'bundled',
      presets: ['@babel/preset-env']
    }),
    terser()
  ],
  external: ['react', 'react-dom']
};

说明

  • Rollup 是模块打包器
  • 适合库的开发
  • 支持 Tree Shaking
  • 可以生成多种格式

包管理

npm

bash
# 初始化项目
npm init

# 安装依赖
npm install react react-dom

# 安装开发依赖
npm install --save-dev webpack webpack-cli

# 运行脚本
npm run dev

# 发布包
npm publish

说明

  • npm 是 Node.js 包管理器
  • 使用 package.json 管理依赖
  • 支持脚本命令
  • 可以发布包

yarn

bash
# 初始化项目
yarn init

# 安装依赖
yarn add react react-dom

# 安装开发依赖
yarn add -D webpack webpack-cli

# 运行脚本
yarn dev

# 发布包
yarn publish

说明

  • yarn 是 npm 的替代品
  • 使用 yarn.lock 锁定版本
  • 并行安装依赖
  • 更好的缓存机制

pnpm

bash
# 初始化项目
pnpm init

# 安装依赖
pnpm add react react-dom

# 安装开发依赖
pnpm add -D webpack webpack-cli

# 运行脚本
pnpm dev

# 发布包
pnpm publish

说明

  • pnpm 使用硬链接
  • 节省磁盘空间
  • 更快的安装速度
  • 更严格的依赖管理

代码规范

ESLint

javascript
// .eslintrc.js
module.exports = {
  env: {
    browser: true,
    es2021: true,
    node: true
  },
  extends: [
    'eslint:recommended',
    'plugin:react/recommended',
    'plugin:@typescript-eslint/recommended'
  ],
  parser: '@typescript-eslint/parser',
  parserOptions: {
    ecmaFeatures: {
      jsx: true
    },
    ecmaVersion: 12,
    sourceType: 'module'
  },
  plugins: ['react', '@typescript-eslint'],
  rules: {
    'no-console': 'warn',
    'react/prop-types': 'off',
    '@typescript-eslint/explicit-module-boundary-types': 'off'
  },
  settings: {
    react: {
      version: 'detect'
    }
  }
};

说明

  • ESLint 是代码检查工具
  • 可以自定义规则
  • 支持多种框架
  • 可以自动修复

Prettier

javascript
// .prettierrc
{
  "semi": true,
  "singleQuote": true,
  "tabWidth": 2,
  "trailingComma": "es5",
  "printWidth": 80,
  "bracketSpacing": true,
  "arrowParens": "avoid"
}

说明

  • Prettier 是代码格式化工具
  • 可以统一代码风格
  • 支持多种语言
  • 可以集成到编辑器

TypeScript

typescript
// tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx"
  },
  "include": ["src"]
}

// 类型定义
interface User {
  id: number;
  name: string;
  email: string;
  age?: number;
}

// 使用类型
const user: User = {
  id: 1,
  name: 'John',
  email: '[email protected]'
};

说明

  • TypeScript 是 JavaScript 的超集
  • 添加静态类型
  • 提供更好的开发体验
  • 减少运行时错误

测试

单元测试

javascript
// 使用 Jest
describe('Calculator', () => {
  test('adds 1 + 2 to equal 3', () => {
    expect(add(1, 2)).toBe(3);
  });

  test('subtracts 5 - 3 to equal 2', () => {
    expect(subtract(5, 3)).toBe(2);
  });
});

// 使用 React Testing Library
import { render, screen, fireEvent } from '@testing-library/react';

test('renders button and handles click', () => {
  render(<Button onClick={() => console.log('clicked')}>Click me</Button>);
  
  const button = screen.getByText('Click me');
  fireEvent.click(button);
  
  expect(console.log).toHaveBeenCalledWith('clicked');
});

说明

  • 单元测试测试独立功能
  • 使用 Jest 作为测试框架
  • 使用 React Testing Library 测试组件
  • 可以模拟用户交互

集成测试

javascript
// 使用 Cypress
describe('Login Flow', () => {
  beforeEach(() => {
    cy.visit('/login');
  });

  it('should login successfully', () => {
    cy.get('[data-testid=username]').type('testuser');
    cy.get('[data-testid=password]').type('password123');
    cy.get('[data-testid=submit]').click();
    cy.url().should('include', '/dashboard');
  });

  it('should show error for invalid credentials', () => {
    cy.get('[data-testid=username]').type('wronguser');
    cy.get('[data-testid=password]').type('wrongpass');
    cy.get('[data-testid=submit]').click();
    cy.get('[data-testid=error]').should('be.visible');
  });
});

说明

  • 集成测试测试多个组件
  • 使用 Cypress 进行端到端测试
  • 可以测试用户流程
  • 可以模拟真实环境

端到端测试

javascript
// 使用 Playwright
import { test, expect } from '@playwright/test';

test('complete user journey', async ({ page }) => {
  // 登录
  await page.goto('/login');
  await page.fill('[data-testid=username]', 'testuser');
  await page.fill('[data-testid=password]', 'password123');
  await page.click('[data-testid=submit]');

  // 验证登录成功
  await expect(page).toHaveURL('/dashboard');

  // 创建新项目
  await page.click('[data-testid=new-project]');
  await page.fill('[data-testid=project-name]', 'Test Project');
  await page.click('[data-testid=create]');

  // 验证项目创建成功
  await expect(page.locator('[data-testid=project-list]')).toContainText('Test Project');
});

说明

  • 端到端测试测试完整流程
  • 使用 Playwright 进行测试
  • 可以测试跨浏览器兼容性
  • 可以测试性能

部署

CI/CD

yaml
# GitHub Actions
name: CI/CD

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v2
        with:
          node-version: '16'
      - run: npm ci
      - run: npm run build
      - run: npm test
      - name: Deploy
        if: github.ref == 'refs/heads/main'
        run: |
          # 部署步骤

说明

  • CI/CD 自动化构建和部署
  • 使用 GitHub Actions
  • 可以自动运行测试
  • 可以自动部署

Docker

dockerfile
# Dockerfile
FROM node:16-alpine

WORKDIR /app

COPY package*.json ./
RUN npm ci

COPY . .
RUN npm run build

EXPOSE 3000

CMD ["npm", "start"]

说明

  • Docker 用于容器化应用
  • 可以确保环境一致性
  • 可以快速部署
  • 可以水平扩展

Nginx

nginx
# nginx.conf
server {
    listen 80;
    server_name example.com;

    root /usr/share/nginx/html;
    index index.html;

    location / {
        try_files $uri $uri/ /index.html;
    }

    location /api {
        proxy_pass http://backend:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

    location /static {
        expires 1y;
        add_header Cache-Control "public, no-transform";
    }
}

说明

  • Nginx 是 Web 服务器
  • 可以处理静态文件
  • 可以反向代理
  • 可以配置缓存

最佳实践

1. 项目结构

  • 使用模块化组织代码
  • 遵循约定优于配置
  • 保持目录结构清晰
  • 使用有意义的命名

2. 开发流程

  • 使用 Git Flow
  • 进行代码审查
  • 编写测试用例
  • 持续集成和部署

3. 性能优化

  • 使用代码分割
  • 优化资源加载
  • 使用缓存策略
  • 监控性能指标

4. 安全

  • 使用 HTTPS
  • 防止 XSS 攻击
  • 防止 CSRF 攻击
  • 定期更新依赖

学习资源

在线教程

视频课程

  • 慕课网
  • 极客时间
  • B站技术区
  • YouTube 技术频道

工具推荐

启航团队技术文档