Skip to content
On this page

npm 实战案例

本章将通过实际项目案例展示如何在真实场景中应用npm,包括完整的项目搭建、依赖管理、工作流配置等。

案例一:全栈Web应用项目

项目结构设计

fullstack-app/
├── package.json
├── .npmrc
├── .nvmrc
├── .gitignore
├── README.md
├── frontend/
│   ├── package.json
│   ├── src/
│   ├── public/
│   └── vite.config.js
├── backend/
│   ├── package.json
│   ├── src/
│   ├── routes/
│   └── middleware/
├── shared/
│   ├── package.json
│   └── types/
├── scripts/
│   ├── setup.js
│   └── health-check.js
└── docker/
    ├── Dockerfile.frontend
    ├── Dockerfile.backend
    └── docker-compose.yml

根目录package.json配置

json
{
  "name": "fullstack-app",
  "private": true,
  "version": "1.0.0",
  "description": "Full-stack application with npm workspaces",
  "workspaces": [
    "frontend",
    "backend",
    "shared"
  ],
  "scripts": {
    "dev": "concurrently \"npm run dev --workspace=frontend\" \"npm run dev --workspace=backend\"",
    "dev:frontend": "npm run dev --workspace=frontend",
    "dev:backend": "npm run dev --workspace=backend",
    "build": "npm run build --workspaces",
    "build:frontend": "npm run build --workspace=frontend",
    "build:backend": "npm run build --workspace=backend",
    "test": "npm run test --workspaces",
    "test:frontend": "npm run test --workspace=frontend",
    "test:backend": "npm run test --workspace=backend",
    "lint": "npm run lint --workspaces",
    "format": "prettier --write . && npm run format --workspaces",
    "setup": "node scripts/setup.js",
    "health": "node scripts/health-check.js",
    "docker:build": "docker-compose -f docker/docker-compose.yml build",
    "docker:up": "docker-compose -f docker/docker-compose.yml up -d",
    "docker:down": "docker-compose -f docker/docker-compose.yml down"
  },
  "devDependencies": {
    "concurrently": "^7.6.0",
    "prettier": "^2.8.0"
  },
  "engines": {
    "node": ">=16.14.0",
    "npm": ">=8.0.0"
  },
  "volta": {
    "node": "18.12.1"
  },
  "keywords": [
    "fullstack",
    "javascript",
    "react",
    "express",
    "monorepo"
  ],
  "author": "Development Team",
  "license": "MIT"
}

共享包配置 (shared/package.json)

json
{
  "name": "@fullstack-app/shared",
  "version": "1.0.0",
  "description": "Shared types and utilities for fullstack app",
  "main": "dist/index.js",
  "module": "dist/index.mjs",
  "types": "dist/index.d.ts",
  "exports": {
    ".": {
      "import": "./dist/index.mjs",
      "require": "./dist/index.js",
      "types": "./dist/index.d.ts"
    },
    "./types": {
      "import": "./dist/types.mjs",
      "require": "./dist/types.js",
      "types": "./dist/types.d.ts"
    }
  },
  "files": [
    "dist/",
    "README.md"
  ],
  "scripts": {
    "build": "tsup src/index.ts --format cjs,esm --dts",
    "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
    "lint": "eslint src/ --ext .ts",
    "test": "vitest run",
    "test:watch": "vitest"
  },
  "devDependencies": {
    "typescript": "^4.9.0",
    "tsup": "^6.5.0",
    "eslint": "^8.30.0",
    "vitest": "^0.26.0",
    "@types/node": "^18.11.18"
  }
}

前端配置 (frontend/package.json)

json
{
  "name": "@fullstack-app/frontend",
  "version": "1.0.0",
  "description": "Frontend application",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "preview": "vite preview",
    "lint": "eslint src/ --ext .ts,.tsx,.js,.jsx",
    "lint:fix": "eslint src/ --ext .ts,.tsx,.js,.jsx --fix",
    "format": "prettier --write \"src/**/*.{ts,tsx,js,jsx,json,css,md}\"",
    "test": "vitest",
    "test:ui": "vitest --ui",
    "test:run": "vitest run",
    "test:coverage": "vitest run --coverage",
    "type-check": "tsc --noEmit"
  },
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "axios": "^1.2.0",
    "@fullstack-app/shared": "workspace:*"
  },
  "devDependencies": {
    "@vitejs/plugin-react": "^3.0.0",
    "vite": "^4.0.0",
    "typescript": "^4.9.0",
    "@types/react": "^18.0.26",
    "@types/react-dom": "^18.0.10",
    "eslint": "^8.30.0",
    "prettier": "^2.8.0",
    "vitest": "^0.26.0",
    "@vitest/ui": "^0.26.0",
    "@testing-library/react": "^13.4.0",
    "@testing-library/jest-dom": "^5.16.5"
  },
  "volta": {
    "node": "18.12.1"
  }
}

后端配置 (backend/package.json)

json
{
  "name": "@fullstack-app/backend",
  "version": "1.0.0",
  "description": "Backend API server",
  "main": "dist/index.js",
  "scripts": {
    "dev": "nodemon --exec ts-node src/index.ts",
    "build": "tsc",
    "start": "node dist/index.js",
    "start:prod": "NODE_ENV=production node dist/index.js",
    "lint": "eslint src/ --ext .ts",
    "lint:fix": "eslint src/ --ext .ts --fix",
    "test": "jest",
    "test:watch": "jest --watch",
    "test:coverage": "jest --coverage",
    "migrate": "ts-node scripts/migrate.ts",
    "seed": "ts-node scripts/seed.ts",
    "type-check": "tsc --noEmit",
    "security": "npm audit --audit-level moderate"
  },
  "dependencies": {
    "express": "^4.18.2",
    "cors": "^2.8.5",
    "helmet": "^6.0.1",
    "bcryptjs": "^2.4.3",
    "jsonwebtoken": "^9.0.0",
    "mongoose": "^6.8.1",
    "@fullstack-app/shared": "workspace:*"
  },
  "devDependencies": {
    "@types/express": "^4.17.15",
    "@types/node": "^18.11.18",
    "@types/bcryptjs": "^2.4.2",
    "@types/jsonwebtoken": "^9.0.1",
    "typescript": "^4.9.4",
    "nodemon": "^2.0.20",
    "ts-node": "^10.9.1",
    "eslint": "^8.30.0",
    "jest": "^29.3.1",
    "@types/jest": "^29.2.4",
    "supertest": "^6.3.3",
    "@types/supertest": "^2.0.12"
  },
  "volta": {
    "node": "18.12.1"
  }
}

案例二:CLI工具开发

CLI项目结构

my-cli-tool/
├── package.json
├── bin/
│   └── my-cli
├── src/
│   ├── cli.js
│   ├── commands/
│   │   ├── init.js
│   │   ├── build.js
│   │   └── deploy.js
│   └── utils/
│       ├── logger.js
│       └── config.js
├── templates/
│   ├── react/
│   └── vue/
├── docs/
└── tests/

CLI工具package.json

json
{
  "name": "my-cli-tool",
  "version": "1.0.0",
  "description": "A custom CLI tool for project scaffolding",
  "bin": {
    "my-cli": "./bin/my-cli"
  },
  "scripts": {
    "dev": "node ./bin/my-cli",
    "build": "echo 'No build needed for CLI tool'",
    "test": "jest",
    "test:watch": "jest --watch",
    "lint": "eslint src/ --ext .js",
    "lint:fix": "eslint src/ --ext .js --fix",
    "prepublishOnly": "npm test && npm run lint",
    "release:patch": "npm version patch && npm publish",
    "release:minor": "npm version minor && npm publish",
    "release:major": "npm version major && npm publish"
  },
  "dependencies": {
    "commander": "^9.4.1",
    "inquirer": "^8.2.5",
    "chalk": "^4.1.2",
    "fs-extra": "^11.1.0",
    "handlebars": "^4.7.7",
    "minimist": "^1.2.7"
  },
  "devDependencies": {
    "jest": "^29.3.1",
    "eslint": "^8.30.0",
    "prettier": "^2.8.1"
  },
  "keywords": [
    "cli",
    "scaffolding",
    "generator",
    "tool"
  ],
  "author": "Developer",
  "license": "MIT",
  "engines": {
    "node": ">=14.0.0"
  },
  "files": [
    "bin/",
    "src/",
    "templates/",
    "README.md",
    "LICENSE"
  ],
  "publishConfig": {
    "access": "public"
  }
}

CLI入口文件 (bin/my-cli)

bash
#!/usr/bin/env node

// 检查Node.js版本
const semver = require('semver');
const packageJson = require('../package.json');

if (!semver.satisfies(process.version, packageJson.engines.node)) {
  console.error(`Node.js ${packageJson.engines.node} is required. Current version: ${process.version}`);
  process.exit(1);
}

// 执行CLI
require('../src/cli.js');

CLI核心实现 (src/cli.js)

javascript
#!/usr/bin/env node

const { Command } = require('commander');
const chalk = require('chalk');
const { initCommand } = require('./commands/init');
const { buildCommand } = require('./commands/build');
const { deployCommand } = require('./commands/deploy');

const program = new Command();

program
  .name('my-cli')
  .description(chalk.blue('CLI tool for project scaffolding and management'))
  .version(require('../package.json').version);

program.addCommand(initCommand);
program.addCommand(buildCommand);
program.addCommand(deployCommand);

// 处理未知命令
program.on('command:*', () => {
  console.error(chalk.red(`\nError: unknown command: ${program.args.join(' ')}\n`));
  program.outputHelp();
  process.exit(1);
});

// 全局错误处理
process.on('unhandledRejection', (reason, promise) => {
  console.error(chalk.red('Unhandled Rejection at:'), promise, 'reason:', reason);
  process.exit(1);
});

program.parse(process.argv);

案例三:库/包开发

库项目结构

my-awesome-lib/
├── package.json
├── tsconfig.json
├── rollup.config.js
├── src/
│   ├── index.ts
│   ├── utils/
│   │   ├── helper.ts
│   │   └── validator.ts
│   └── types/
│       └── index.ts
├── dist/
├── docs/
├── benchmarks/
└── tests/
    ├── unit/
    ├── integration/
    └── fixtures/

库package.json

json
{
  "name": "my-awesome-lib",
  "version": "1.0.0",
  "description": "An awesome utility library",
  "main": "dist/cjs/index.js",
  "module": "dist/esm/index.mjs",
  "browser": "dist/umd/my-awesome-lib.min.js",
  "types": "dist/types/index.d.ts",
  "exports": {
    ".": {
      "import": "./dist/esm/index.mjs",
      "require": "./dist/cjs/index.js",
      "types": "./dist/types/index.d.ts"
    },
    "./utils": {
      "import": "./dist/esm/utils/index.mjs",
      "require": "./dist/cjs/utils/index.js"
    }
  },
  "files": [
    "dist/",
    "README.md",
    "LICENSE",
    "package.json"
  ],
  "scripts": {
    "prebuild": "npm run clean",
    "build": "rollup -c",
    "build:dev": "rollup -c -w",
    "build:umd": "rollup -c --environment FORMAT:umd",
    "build:min": "rollup -c --environment MINIFY:true",
    "clean": "rimraf dist",
    "test": "jest",
    "test:unit": "jest tests/unit/",
    "test:integration": "jest tests/integration/",
    "test:watch": "jest --watch",
    "test:coverage": "jest --coverage",
    "lint": "eslint src/ --ext .ts",
    "lint:fix": "eslint src/ --ext .ts --fix",
    "format": "prettier --write \"src/**/*.{ts,js,json,md}\"",
    "format:check": "prettier --check \"src/**/*.{ts,js,json,md}\"",
    "type-check": "tsc --noEmit",
    "bench": "node benchmarks/index.js",
    "docs": "typedoc --out docs/api src/",
    "prepublishOnly": "npm run test && npm run build && npm run type-check",
    "release": "standard-version",
    "release:minor": "standard-version --release-as minor",
    "release:patch": "standard-version --release-as patch",
    "release:major": "standard-version --release-as major"
  },
  "devDependencies": {
    "@rollup/plugin-typescript": "^11.0.0",
    "@rollup/plugin-commonjs": "^24.0.0",
    "@rollup/plugin-node-resolve": "^15.0.1",
    "rollup": "^3.9.1",
    "rollup-plugin-terser": "^7.0.2",
    "typescript": "^4.9.4",
    "jest": "^29.3.1",
    "ts-jest": "^29.0.3",
    "@types/jest": "^29.2.4",
    "eslint": "^8.30.0",
    "prettier": "^2.8.1",
    "rimraf": "^3.0.2",
    "typedoc": "^0.23.24",
    "standard-version": "^9.5.0",
    "@types/node": "^18.11.18"
  },
  "keywords": [
    "utility",
    "javascript",
    "typescript",
    "library"
  ],
  "author": "Library Author",
  "license": "MIT",
  "engines": {
    "node": ">=14.0.0"
  },
  "sideEffects": false,
  "publishConfig": {
    "access": "public"
  }
}

案例四:微前端架构

微前端项目结构

micro-frontend-platform/
├── package.json
├── nx.json
├── .npmrc
├── host/
│   ├── package.json
│   └── src/
├── micro-app1/
│   ├── package.json
│   └── src/
├── micro-app2/
│   ├── package.json
│   └── src/
├── shared-components/
│   ├── package.json
│   └── src/
├── shared-utils/
│   ├── package.json
│   └── src/
└── gateway/
    ├── package.json
    └── src/

微前端根package.json

json
{
  "name": "micro-frontend-platform",
  "private": true,
  "version": "1.0.0",
  "workspaces": [
    "host",
    "micro-app1", 
    "micro-app2",
    "shared-components",
    "shared-utils",
    "gateway"
  ],
  "scripts": {
    "dev": "concurrently \"npm run dev --workspace=host\" \"npm run dev --workspace=micro-app1\" \"npm run dev --workspace=micro-app2\"",
    "dev:host": "npm run dev --workspace=host",
    "dev:micro-apps": "concurrently \"npm run dev --workspace=micro-app1\" \"npm run dev --workspace=micro-app2\"",
    "build": "npm run build --workspaces",
    "build:all": "npm run build:shared && npm run build:micro-apps && npm run build:host",
    "build:shared": "npm run build --workspace=shared-components && npm run build --workspace=shared-utils",
    "build:micro-apps": "npm run build --workspace=micro-app1 && npm run build --workspace=micro-app2",
    "build:host": "npm run build --workspace=host",
    "test": "npm run test --workspaces",
    "lint": "npm run lint --workspaces",
    "format": "prettier --write . && npm run format --workspaces",
    "deploy": "npm run deploy --workspaces",
    "analyze": "npm run analyze --workspaces"
  },
  "devDependencies": {
    "concurrently": "^7.6.0",
    "prettier": "^2.8.0"
  },
  "engines": {
    "node": ">=16.14.0",
    "npm": ">=8.0.0"
  }
}

微前端共享组件package.json

json
{
  "name": "@micro-platform/shared-components",
  "version": "1.0.0",
  "description": "Shared UI components for micro-frontend platform",
  "main": "dist/cjs/index.js",
  "module": "dist/esm/index.mjs",
  "types": "dist/types/index.d.ts",
  "exports": {
    ".": {
      "import": "./dist/esm/index.mjs",
      "require": "./dist/cjs/index.js",
      "types": "./dist/types/index.d.ts"
    },
    "./button": {
      "import": "./dist/esm/components/button.mjs",
      "require": "./dist/cjs/components/button.js"
    }
  },
  "files": [
    "dist/",
    "README.md"
  ],
  "scripts": {
    "build": "vite build",
    "dev": "vite build --watch",
    "test": "jest",
    "test:watch": "jest --watch",
    "lint": "eslint src/ --ext .ts,.tsx",
    "format": "prettier --write \"src/**/*.{ts,tsx,js,jsx,json,css,md}\"",
    "storybook": "storybook dev -p 6006",
    "build-storybook": "storybook build"
  },
  "peerDependencies": {
    "react": ">=16.8.0",
    "react-dom": ">=16.8.0"
  },
  "devDependencies": {
    "@storybook/react-vite": "^7.0.0",
    "@storybook/addon-essentials": "^7.0.0",
    "vite": "^4.3.0",
    "typescript": "^4.9.0",
    "jest": "^29.5.0",
    "eslint": "^8.30.0"
  }
}

案例五:CI/CD自动化流程

GitHub Actions工作流

yaml
# .github/workflows/test.yml
name: Test Suite
on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  test:
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        node-version: [16.x, 18.x, 20.x]
        include:
          - node-version: 18.x
            os: ubuntu-latest
            run-coverage: true

    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'npm'
          
      - name: Install dependencies
        run: npm ci
        env:
          CI: true
          
      - name: Run linting
        run: npm run lint
        env:
          CI: true
          
      - name: Run type checking
        run: npm run type-check
        env:
          CI: true
          
      - name: Run tests
        run: |
          if [ "${{ matrix.run-coverage }}" = "true" ]; then
            npm run test:coverage
          else
            npm run test
          fi
        env:
          CI: true
          
      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v3
        if: matrix.run-coverage
        with:
          file: ./coverage/lcov.info
          flags: unittests
          name: codecov-umbrella
          fail_ci_if_error: false
yaml
# .github/workflows/release.yml
name: Release
on:
  push:
    branches: [main]
  workflow_dispatch:

permissions:
  contents: read
  id-token: write

jobs:
  release:
    runs-on: ubuntu-latest
    if: "!contains(github.event.head_commit.message, 'skip ci')"
    
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
          token: ${{ secrets.GITHUB_TOKEN }}
          
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '18'
          registry-url: 'https://registry.npmjs.org/'
          
      - name: Install dependencies
        run: npm ci
        
      - name: Run tests
        run: npm test
        
      - name: Run type checking
        run: npm run type-check
        
      - name: Run security audit
        run: npm audit --audit-level moderate
        
      - name: Build
        run: npm run build
        
      - name: Release
        run: |
          if npx semantic-release; then
            echo "Release successful"
          else
            echo "No release needed"
          fi
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
        continue-on-error: true

这些实战案例展示了如何在不同类型和规模的项目中有效使用npm,包括全栈应用、CLI工具、库开发、微前端架构和CI/CD流程。