马上元旦节了,手写一个《前端脚手架》庆祝一下 !

前言

Hello ! 大家好,我是千寻,马上就要跨年了,提前祝大家马到成功, 新的一年所愿皆能成啊,哈哈 !

OK啊, 咱们步入正题!

步入正题之前, 想给大家推荐一个不错的思想.

一个不错的思想: 工程化思想

就是把多次使用的功能封装成组件、将多项目共用的组件做成 NPM 包、把相似项目抽象封装为脚手架 ------ 拥有这些工程化思想,正是你从初级程序员迈向中级程序员的重要标志。

不知道大家是否跟我一样, 刚开始学习前端的时候,会写一个前端入门必备项目---后台管理系统.

之后在生活中又遇到很多次都要重新写后台管理系统的时候, 拿我来举个例子:

宿管让我写宿舍设备保修系统需要用到;

学校的Web前端课程设计需要用到(当然这是看老师布置的什么作业);

自己写项目需要用到后台管理;

等等等等,真的超级多.........都是重复造轮子的过程...........

根据工程化思想, 这是我们就要想把相似项目抽象封装为脚手架

我以后台管理系统为例, 看看如何封装成一个脚手架 !

一、前期准备:明确技术栈对应的通用配置与功能

1. 前端(Vue3+TS+Vite+Element Plus+Pinia+Vue Router)核心固化内容

React 同理, 我以 Vue3 为例

类别 具体配置 / 功能
项目配置 Vite+TS 配置(vite.config.ts)、TS 配置(tsconfig.json)、环境变量(.env.dev/.env.prod
依赖固化 核心依赖版本锁定(vue@3、typescript@5、element-plus@2、pinia@2、vue-router@4)
通用布局 侧边栏导航(支持折叠 / 多级菜单)、顶部导航栏(用户信息 / 退出 / 主题切换)、面包屑导航
权限控制 路由守卫(动态加载路由)、按钮级权限(自定义指令v-permission)、Token 校验与刷新
状态管理 Pinia 封装(用户信息userStore、菜单状态menuStore、全局配置configStore
网络请求 Axios 封装(TS 类型约束、请求 / 响应拦截、异常处理、BaseURL 配置)
通用组件 分页表格(ElTable + 分页封装)、查询表单(ElForm + 搜索重置)、弹窗表单、文件上传(ElUpload)
工程化规范 ESLint(Vue/TS 规范)、Prettier(代码格式化)、husky+lint-staged(提交校验)

2. 后端(Node+TS+Koa)核心固化内容

类别 具体配置 / 功能
项目配置 TS 配置(tsconfig.json)、Koa 配置(中间件注册、端口配置)、环境变量(.env.dev/.env.prod
依赖固化 核心依赖版本锁定(koa@2、typescript@5、@koa/router@12、koa-body@6、jsonwebtoken@9、mysql2@3)
通用中间件 跨域中间件(koa2-cors)、请求体解析(koa-body)、日志中间件(koa-logger)、异常捕获中间件
业务功能 用户模块(登录 / 退出 / 信息查询)、角色模块(增删改查)、菜单模块(权限分配)、字典模块
工具类 TS 类型约束(请求 / 响应数据类型)、密码加密(bcryptjs)、Token 生成与校验(jsonwebtoken)
数据库 MySQL 连接配置(mysql2)、SQL 语句封装(或 TypeORM/Sequelize 可选)

3. 构建工具(pnpm)配置

  • 固化package.json中的packageManager字段:"packageManager": "pnpm@8.6.0"(锁定 pnpm 版本)
  • 配置pnpm-workspace.yaml(前后端一体化项目的工作区配置,支持根目录统一安装依赖)
  • 固化脚本命令(dev/build/lint/preview

二、脚手架项目结构

基于指定技术栈,调整脚手架目录结构,突出前后端一体化模板:

复制代码
admin-scaffold/
├── bin/
│   └── admin-cli.js          # 脚手架入口(Commander.js+Inquirer.js)
├── templates/                # 前后端一体化模板(核心)
│   ├── base-template/        # 基础版模板(极简核心功能)
│   │   ├── frontend/         # 前端项目(Vue3+TS+Vite+Element Plus)
│   │   │   ├── public/
│   │   │   ├── src/
│   │   │   │   ├── api/      # 接口请求(TS类型约束)
│   │   │   │   │   ├── index.ts  # Axios封装
│   │   │   │   │   └── system/   # 系统模块接口(用户/角色/菜单)
│   │   │   │   ├── assets/   # 样式/图片(全局样式、Element Plus主题定制)
│   │   │   │   ├── components/   # 通用组件(TS类型封装)
│   │   │   │   │   ├── BaseTable/   # 分页表格组件
│   │   │   │   │   ├── BaseForm/    # 查询表单组件
│   │   │   │   │   └── BaseDialog/  # 弹窗组件
│   │   │   │   ├── layout/   # 核心布局组件
│   │   │   │   │   ├── index.vue    # 布局入口
│   │   │   │   │   ├── Sidebar/     # 侧边栏
│   │   │   │   │   ├── Header/      # 顶部导航
│   │   │   │   │   └── Breadcrumb/  # 面包屑
│   │   │   │   ├── pinia/    # Pinia状态管理
│   │   │   │   │   ├── index.ts     # Pinia注册
│   │   │   │   │   ├── userStore.ts # 用户信息存储
│   │   │   │   │   └── menuStore.ts # 菜单状态存储
│   │   │   │   ├── router/   # 路由配置
│   │   │   │   │   ├── index.ts     # 路由注册/守卫
│   │   │   │   │   ├── staticRoutes.ts # 静态路由(登录页/404页)
│   │   │   │   │   └── dynamicRoutes.ts # 动态路由模板
│   │   │   │   ├── types/    # TS类型定义(接口返回值、组件Props等)
│   │   │   │   ├── utils/    # 工具类(格式化、权限判断、Token处理)
│   │   │   │   ├── views/    # 页面视图
│   │   │   │   │   ├── login/       # 登录页
│   │   │   │   │   ├── home/        # 首页
│   │   │   │   │   └── system/      # 系统管理页(用户/角色/菜单)
│   │   │   │   ├── App.vue
│   │   │   │   ├── main.ts
│   │   │   │   └── vite-env.d.ts
│   │   │   ├── .env.dev
│   │   │   ├── .env.prod
│   │   │   ├── eslintrc.cjs
│   │   │   ├── prettier.config.cjs
│   │   │   ├── package.json
│   │   │   ├── tsconfig.json
│   │   │   └── vite.config.ts
│   │   │
│   │   ├── backend/          # 后端项目(Node+TS+Koa)
│   │   │   ├── src/
│   │   │   │   ├── config/   # 配置文件(数据库、端口、JWT密钥)
│   │   │   │   ├── controller/  # 控制器(用户/角色/菜单)
│   │   │   │   ├── middleware/  # 中间件(跨域、异常捕获、Token校验)
│   │   │   │   ├── model/    # 数据模型(TS类型定义+数据库操作)
│   │   │   │   ├── router/   # 路由注册
│   │   │   │   ├── service/  # 业务逻辑层
│   │   │   │   ├── types/    # TS类型定义
│   │   │   │   ├── utils/    # 工具类(密码加密、Token处理)
│   │   │   │   └── app.ts    # Koa应用入口
│   │   │   ├── .env.dev
│   │   │   ├── .env.prod
│   │   │   ├── package.json
│   │   │   └── tsconfig.json
│   │   │
│   │   ├── pnpm-workspace.yaml  # 前后端工作区配置
│   │   └── README.md           # 项目整体说明
│   │
│   └── pro-template/         # 专业版模板(新增数据可视化/国际化等)
│       ├── frontend/         # 扩展ECharts/i18n/vite打包优化
│       ├── backend/          # 扩展分页查询/文件上传/日志持久化
│       └── pnpm-workspace.yaml
├── lib/
│   ├── generator.js          # 项目生成工具(复制模板、替换变量)
│   ├── prompt.js             # 交互询问工具
│   └── utils.js              # 辅助工具
├── package.json              # 脚手架依赖配置
└── README.md                 # 脚手架使用文档

三、核心模块落地

1. 前端模板核心配置(Vue3+TS+Vite)

(1)Vite+TS 配置(vite.config.ts
TypeScript 复制代码
import { defineConfig, loadEnv } from 'vite';
import vue from '@vitejs/plugin-vue';
import path from 'path';
import AutoImport from 'unplugin-auto-import/vite';
import Components from 'unplugin-vue-components/vite';
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers';

// https://vitejs.dev/config/
export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd());
  return {
    plugins: [
      vue(),
      // 自动导入Element Plus组件和API
      AutoImport({
        resolvers: [ElementPlusResolver()],
        imports: ['vue', 'vue-router', 'pinia'],
        dts: path.resolve(__dirname, 'src/types/auto-imports.d.ts'),
      }),
      Components({
        resolvers: [ElementPlusResolver()],
        dts: path.resolve(__dirname, 'src/types/components.d.ts'),
      }),
    ],
    resolve: {
      alias: {
        '@': path.resolve(__dirname, 'src'), // 路径别名
      },
    },
    server: {
      port: 3000,
      proxy: {
        // 接口代理,解决跨域
        '/api': {
          target: env.VITE_API_BASE_URL,
          changeOrigin: true,
          rewrite: (path) => path.replace(/^\/api/, ''),
        },
      },
    },
    build: {
      outDir: 'dist',
      sourcemap: false,
      rollupOptions: {
        output: {
          // 打包分片,优化加载速度
          chunkFileNames: 'static/js/[name]-[hash].js',
          entryFileNames: 'static/js/[name]-[hash].js',
          assetFileNames: 'static/[ext]/[name]-[hash].[ext]',
        },
      },
    },
  };
});
(2)Pinia 状态管理(src/pinia/userStore.ts
TypeScript 复制代码
import { defineStore } from 'pinia';
import { ref } from 'vue';
import { loginApi, getUserInfoApi } from '@/api/system/user';
import { LoginParams, UserInfo } from '@/types/system';

export const useUserStore = defineStore('user', () => {
  // 状态
  const token = ref<string>(localStorage.getItem('token') || '');
  const userInfo = ref<UserInfo | null>(null);

  // 动作:登录
  const login = async (params: LoginParams) => {
    const res = await loginApi(params);
    token.value = res.data.token;
    localStorage.setItem('token', res.data.token);
    return res;
  };

  // 动作:获取用户信息
  const getUserInfo = async () => {
    const res = await getUserInfoApi();
    userInfo.value = res.data;
    return res;
  };

  // 动作:退出登录
  const logout = () => {
    token.value = '';
    userInfo.value = null;
    localStorage.removeItem('token');
  };

  return {
    token,
    userInfo,
    login,
    getUserInfo,
    logout,
  };
});
(3)路由守卫(src/router/index.ts
复制代码
import { createRouter, createWebHistory } from 'vue-router';
import staticRoutes from './staticRoutes';
import { useUserStore } from '@/pinia/userStore';
import { useMenuStore } from '@/pinia/menuStore';
import { ElMessage } from 'element-plus';

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: staticRoutes,
});

// 路由守卫
router.beforeEach(async (to, from, next) => {
  const userStore = useUserStore();
  const menuStore = useMenuStore();

  // 不需要登录的页面直接放行
  if (to.meta.requiresAuth !== true) {
    next();
    return;
  }

  // 有Token,验证有效性并加载用户信息和动态路由
  if (userStore.token) {
    try {
      // 未获取用户信息,先获取
      if (!userStore.userInfo) {
        await userStore.getUserInfo();
        // 加载动态路由
        await menuStore.generateDynamicRoutes();
        // 重新跳转(确保动态路由生效)
        next({ ...to, replace: true });
      } else {
        next();
      }
    } catch (error) {
      // Token失效,退出登录并跳转到登录页
      userStore.logout();
      ElMessage.error('登录状态失效,请重新登录');
      next(`/login?redirect=${to.fullPath}`);
    }
  } else {
    // 无Token,跳转到登录页
    next(`/login?redirect=${to.fullPath}`);
  }
});

export default router;

2. 后端模板核心配置(Node+TS+Koa)

(1)Koa 应用入口(src/app.ts
复制代码
import Koa from 'koa';
import koaBody from 'koa-body';
import cors from 'koa2-cors';
import logger from 'koa-logger';
import router from './router';
import { errorHandler } from './middleware/errorHandler';
import { loadEnv } from './utils/loadEnv';
import { connectDb } from './config/db';

// 加载环境变量
loadEnv();
// 创建Koa实例
const app = new Koa();
const PORT = process.env.PORT || 4000;

// 注册中间件
app.use(cors()); // 跨域
app.use(logger()); // 日志
app.use(koaBody({ multipart: true })); // 请求体解析
app.use(errorHandler()); // 全局异常捕获
app.use(router.routes()).use(router.allowedMethods()); // 路由

// 连接数据库并启动服务
const startServer = async () => {
  try {
    await connectDb();
    app.listen(PORT, () => {
      console.log(`✅ 后端服务启动成功,端口:${PORT}`);
      console.log(`✅ 接口文档地址:http://localhost:${PORT}/api-docs`);
    });
  } catch (error) {
    console.error('❌ 服务启动失败:', error);
    process.exit(1);
  }
};

startServer();
(2)用户登录控制器(src/controller/userController.ts
复制代码
import { Context } from 'koa';
import { loginService, getUserInfoService } from '../service/userService';
import { LoginParams } from '../types/user';
import { generateToken } from '../utils/jwt';
import { encryptPassword, verifyPassword } from '../utils/password';

// 登录
export const login = async (ctx: Context) => {
  const params: LoginParams = ctx.request.body;
  // 验证参数
  if (!params.username || !params.password) {
    ctx.status = 400;
    ctx.body = { code: 400, msg: '用户名和密码不能为空' };
    return;
  }

  // 查询用户
  const user = await loginService(params.username);
  if (!user) {
    ctx.status = 401;
    ctx.body = { code: 401, msg: '用户名或密码错误' };
    return;
  }

  // 验证密码
  const isPasswordValid = await verifyPassword(params.password, user.password);
  if (!isPasswordValid) {
    ctx.status = 401;
    ctx.body = { code: 401, msg: '用户名或密码错误' };
    return;
  }

  // 生成Token
  const token = generateToken({ userId: user.id, username: user.username });

  ctx.body = {
    code: 200,
    msg: '登录成功',
    data: { token, username: user.username },
  };
};

// 获取用户信息
export const getUserInfo = async (ctx: Context) => {
  const { userId } = ctx.state.user; // 从Token中解析的用户ID
  const userInfo = await getUserInfoService(userId);

  ctx.body = {
    code: 200,
    msg: '查询成功',
    data: userInfo,
  };
};
(3)Token 校验中间件(src/middleware/authMiddleware.ts
复制代码
import { Context, Next } from 'koa';
import { verifyToken } from '../utils/jwt';

// Token校验中间件
export const authMiddleware = async (ctx: Context, next: Next) => {
  try {
    // 获取Token
    const token = ctx.headers.authorization?.replace('Bearer ', '');
    if (!token) {
      ctx.status = 401;
      ctx.body = { code: 401, msg: '请先登录' };
      return;
    }

    // 验证Token
    const payload = verifyToken(token);
    ctx.state.user = payload; // 将用户信息挂载到ctx.state
    await next();
  } catch (error) {
    ctx.status = 401;
    ctx.body = { code: 401, msg: '登录状态失效,请重新登录' };
  }
};

3. 工作区配置(pnpm-workspace.yaml

yaml

复制代码
# 前后端一体化工作区配置,支持根目录统一执行脚本
packages:
  - 'frontend'
  - 'backend'

4. 根目录package.json(统一脚本命令)

json

复制代码
{
  "name": "admin-management-project",
  "version": "1.0.0",
  "packageManager": "pnpm@8.6.0",
  "scripts": {
    "dev": "pnpm --parallel dev", // 同时启动前端和后端开发服务
    "dev:frontend": "pnpm -F frontend dev",
    "dev:backend": "pnpm -F backend dev",
    "build": "pnpm --parallel build", // 同时打包前端和后端
    "lint": "pnpm --parallel lint" // 同时校验前端和后端代码
  }
}

四、脚手架交互与生成逻辑优化

1. 交互配置增强(贴合技术栈)

bin/admin-cli.js中增加技术栈专属配置项:

复制代码
const answers = await inquirer.prompt([
  // 原有模板选择
  {
    type: 'list',
    name: 'templateType',
    message: '请选择后台管理系统模板类型',
    choices: [
      { name: '基础版(极简核心功能)', value: 'base-template' },
      { name: '专业版(含数据可视化/国际化)', value: 'pro-template' }
    ],
    default: 'base-template'
  },
  // 新增:前端是否开启国际化
  {
    type: 'confirm',
    name: 'enableI18n',
    message: '前端是否开启国际化(vue-i18n)',
    default: false
  },
  // 新增:后端是否使用TypeORM(默认mysql2原生)
  {
    type: 'confirm',
    name: 'enableTypeORM',
    message: '后端是否使用TypeORM(ORM框架)',
    default: false
  },
  // 原有配置
  {
    type: 'confirm',
    name: 'enableEslint',
    message: '是否开启ESLint代码校验',
    default: true
  }
]);

2. 生成逻辑适配(动态调整模板)

lib/generator.js中,根据用户选择动态调整模板:

  • 若开启enableI18n,为前端模板添加vue-i18n依赖和国际化配置;
  • 若开启enableTypeORM,为后端模板替换mysql2typeorm,并添加实体类配置;
  • 保留pnpm相关配置,确保生成的项目默认使用pnpm安装依赖。

五、脚手架使用流程(最终效果)

  1. 全局安装脚手架

bash

复制代码
pnpm install -g admin-management-scaffold
  1. 创建项目

bash

复制代码
admin-cli create my-admin-project
  1. 交互式配置

plaintext

复制代码
? 请选择后台管理系统模板类型 基础版(极简核心功能)
? 前端是否开启国际化(vue-i18n) No
? 后端是否使用TypeORM(ORM框架) No
? 是否开启ESLint代码校验 Yes
  1. 启动项目

bash

复制代码
cd my-admin-project
pnpm install # 根目录统一安装依赖
pnpm dev     # 同时启动前端(3000端口)和后端(4000端口)
  1. 访问项目

六、脚手架维护与迭代

  1. 依赖更新:定期更新模板中的依赖版本(如 Vue3、Koa、Element Plus),确保兼容性;
  2. 功能扩展:新增前端功能(如数据可视化 ECharts、文件预览)、后端功能(如分页插件、文件上传);
  3. 问题修复:根据用户反馈修复模板中的 bug(如路由跳转异常、接口报错);
  4. 文档完善:补充模板使用文档、接口文档(如 Swagger/OpenAPI),降低使用成本。

总结

基于Vue3+TS+Vite+Element Plus+Pinia+Vue Router(前端)、Node+TS+Koa(后端)、pnpm(构建工具)的脚手架,核心价值在于:

  1. 提效:一条命令生成前后端一体化项目,无需手动配置技术栈和实现基础功能;
  2. 规范:固化项目结构、代码规范和最佳实践,确保团队开发风格统一;
  3. 灵活:支持交互式配置,可根据需求开启 / 关闭部分功能,适配不同场景;
  4. 易维护:模板与脚手架分离,便于后续迭代更新,不影响已生成的项目。

通过该脚手架,开发者可快速聚焦业务开发,无需在项目搭建和基础配置上耗费时间

后台管理系统脚手架(Node.js)发布完整流程

核心前提:脚手架是基于 Node.js 开发的命令行工具,最终发布到npm 仓库 (公共仓库或私有仓库),方便他人通过pnpm/npm全局安装使用。

一、发布前准备(关键步骤,避免发布失败)

1. 完善脚手架项目的package.json配置

package.json是 npm 包的核心配置文件,必须确保关键字段配置正确,以下是完整配置示例(针对本脚手架):

json

复制代码
{
  "name": "admin-cli-vue3-koa", // ① 包名:全网唯一,建议包含技术栈标识,避免重复
  "version": "1.0.0", // ② 版本号:遵循语义化版本(MAJOR.MINOR.PATCH,如1.0.0、1.0.1)
  "description": "基于Vue3+TS+Vite+Element Plus+Pinia+Vue Router+Node+TS+Koa的后台管理系统脚手架", // ③ 包描述
  "keywords": ["admin-cli", "vue3", "koa", "ts", "vite", "element-plus", "pinia"], // ④ 关键词,便于npm搜索
  "homepage": "https://github.com/你的用户名/admin-cli-vue3-koa", // ⑤ 项目主页(可选,如GitHub地址)
  "repository": { // ⑥ 代码仓库(可选,便于他人查看源码)
    "type": "git",
    "url": "git+https://github.com/你的用户名/admin-cli-vue3-koa.git"
  },
  "author": "你的姓名 <你的邮箱@xxx.com>", // ⑦ 作者信息
  "license": "MIT", // ⑧ 许可证(常用MIT,开源可商用)
  "bin": { // ⑨ 命令行入口:关键配置,映射指令到入口文件
    "admin-cli": "./bin/admin-cli.js" // 使用者可通过「admin-cli」命令调用脚手架
  },
  "main": "lib/generator.js", // ⑩ 主入口(脚手架可不填,主要用于模块引入)
  "files": [ // ⑪ 指定发布到npm的文件/目录,避免上传无用文件
    "bin",
    "lib",
    "templates",
    "package.json",
    "README.md"
  ],
  "dependencies": { // ⑫ 脚手架运行依赖,已锁定版本
    "commander": "^11.0.0",
    "inquirer": "^9.2.10",
    "fs-extra": "^11.1.1",
    "chalk": "^5.3.0",
    "ora": "^6.3.1"
  },
  "devDependencies": {}, // ⑬ 开发依赖(如eslint,发布时不会被打包)
  "packageManager": "pnpm@8.6.0", // ⑭ 锁定pnpm版本,与技术栈保持一致
  "engines": { // ⑮ 指定Node.js版本要求,避免兼容性问题
    "node": ">=16.0.0"
  }
}

2. 确保入口文件添加shebang标识

脚手架入口文件bin/admin-cli.js顶部必须添加#!/usr/bin/env node,用于指定脚本的执行环境为 Node.js,否则发布后无法作为命令行工具运行:

复制代码
#!/usr/bin/env node // 必须放在第一行,无空格
const { program } = require('commander');
// 后续代码...

3. 本地测试脚手架(发布前验证功能)

发布前先通过pnpm link(或npm link)将脚手架链接到全局,验证功能是否正常,避免发布后出现 bug:

步骤 1:在脚手架项目根目录执行链接命令

bash

复制代码
# 进入脚手架项目根目录
cd /path/to/admin-cli-vue3-koa
# 链接到全局(pnpm/npm均可,推荐pnpm,与技术栈一致)
pnpm link
# 若用npm:npm link
步骤 2:验证脚手架功能

在任意目录执行脚手架命令,测试是否能正常创建项目:

bash

复制代码
# 查看版本,验证是否链接成功
admin-cli -v
# 尝试创建项目,验证核心功能
admin-cli create test-admin-project
步骤 3:测试通过后解除本地链接(可选)

bash

复制代码
# 解除全局链接
pnpm unlink -g admin-cli-vue3-koa
# 若用npm:npm unlink -g admin-cli-vue3-koa

4. 编写清晰的README.md文档

README.md是用户了解和使用脚手架的关键,需包含以下内容:

  • 脚手架介绍(技术栈、功能亮点);
  • 安装命令;
  • 使用步骤(创建项目、启动项目等);
  • 模板目录结构;
  • 常见问题排查;
  • 版本更新日志。

示例片段:

markdown

复制代码
# admin-cli-vue3-koa
基于Vue3+TS+Vite+Element Plus+Pinia+Vue Router+Node+TS+Koa的后台管理系统脚手架,快速生成前后端一体化项目。

## 安装
```bash
pnpm install -g admin-cli-vue3-koa
# 或 npm install -g admin-cli-vue3-koa

使用

  1. 创建项目

bash

复制代码
admin-cli create my-admin
  1. 启动项目

bash

复制代码
cd my-admin
pnpm install
pnpm dev

功能亮点

  • 前后端一体化初始化
  • 内置权限管理、通用组件、网络请求封装
  • 支持交互式配置(国际化、TypeORM 等)

plaintext

复制代码
### 5. 清理无用文件
删除脚手架项目中的临时文件、日志文件、`node_modules`、`.gitignore`中忽略的文件,确保只保留`files`字段中指定的内容,减小包体积。

## 二、发布到npm公共仓库(核心流程)
### 前提条件
1. 拥有npm账号(无账号可在[npm官网](https://www.npmjs.com/)注册);
2. 本地终端已登录npm账号(若未登录,执行后续登录命令);
3. 确保npm镜像源为**官方源**(淘宝镜像等无法发布包)。

### 步骤1:切换npm官方镜像源
```bash
# 查看当前镜像源
npm config get registry
# 若不是官方源,切换为官方源
npm config set registry https://registry.npmjs.org/

步骤 2:登录 npm 账号

在终端执行登录命令,按照提示输入用户名、密码、邮箱(若开启二次验证,需输入验证码):

bash

复制代码
npm login
# 注意:pnpm无法直接登录npm,必须用npm login

步骤 3:执行发布命令

在脚手架项目根目录执行发布命令,pnpm 和 npm 均可:

bash

复制代码
# 方式1:用pnpm发布(推荐,与技术栈一致)
pnpm publish
# 方式2:用npm发布
npm publish
发布时可能的报错及解决方案
  1. 包名重复 :修改package.json中的name字段,确保全网唯一(可在 npm 官网搜索包名,确认是否已被占用);
  2. 版本号重复 :更新版本号(如从 1.0.0 改为 1.0.1),执行pnpm version patch(自动升级补丁版本);
  3. 未登录 / 权限不足 :重新执行npm login,确认账号是否有权限发布(新账号需验证邮箱);
  4. 文件过大 :检查files字段,删除无用文件,减小包体积;
  5. Node 版本不满足 :升级本地 Node.js 版本至engines字段指定的版本以上。

步骤 4:发布成功验证

  1. 访问 npm 官网,搜索你的包名(如admin-cli-vue3-koa),可看到已发布的包信息;
  2. 在终端执行全局安装命令,验证是否能正常安装:

bash

复制代码
pnpm install -g admin-cli-vue3-koa
# 安装后执行命令,验证功能
admin-cli -v

三、发布到私有仓库(可选,如公司内部仓库)

若脚手架仅用于公司内部团队使用,可发布到私有仓库(如 Verdaccio、Nexus):

步骤 1:配置私有仓库镜像源

bash

复制代码
npm config set registry http://你的私有仓库地址/

步骤 2:登录私有仓库账号

bash

复制代码
npm login --registry=http://你的私有仓库地址/

步骤 3:执行发布命令

bash

复制代码
pnpm publish --registry=http://你的私有仓库地址/

四、发布后的维护与更新

1. 版本更新

当脚手架需要迭代功能(如更新模板、修复 bug)时,需更新版本并重新发布:

步骤 1:更新版本号(语义化版本)

bash

复制代码
# 补丁版本(修复bug,如1.0.0→1.0.1)
pnpm version patch
# 小版本(新增功能,向下兼容,如1.0.1→1.1.0)
pnpm version minor
# 大版本(不兼容更新,如1.1.0→2.0.0)
pnpm version major
步骤 2:重新发布

bash

复制代码
pnpm publish

2. 包的卸载与撤销

(1)卸载全局脚手架

bash

复制代码
pnpm uninstall -g admin-cli-vue3-koa
# 或 npm uninstall -g admin-cli-vue3-koa
(2)撤销已发布的包(仅限发布后 24 小时内)

bash

复制代码
# 撤销指定版本
npm unpublish admin-cli-vue3-koa@1.0.0 --force
# 撤销整个包(谨慎使用,会影响已安装用户)
npm unpublish admin-cli-vue3-koa --force

3. 同步 pnpm 镜像(可选)

若用户使用 pnpm 镜像源(如 pnpm 官方镜像),发布到 npm 公共仓库后,需等待镜像同步(通常几分钟到几小时),用户才能通过pnpm install安装最新版本。

总结

脚手架发布的核心流程可概括为:

  1. 准备工作:完善package.json、本地测试、编写文档、清理无用文件;
  2. 环境配置:切换 npm 官方源、登录 npm 账号;
  3. 执行发布:pnpm publish/npm publish
  4. 后续维护:版本更新、bug 修复、按需撤销包。

通过以上步骤,你的后台管理系统脚手架即可成功发布,其他开发者可通过pnpm install -g 你的包名全局安装,快速使用脚手架生成项目

相关推荐
嚣张丶小麦兜2 小时前
认识vite
前端·javascript·vue.js
玲小珑3 小时前
请求 ID 跟踪模式:解决异步请求竞态条件
前端
开心_开心急了3 小时前
AI+PySide6实现自定义窗口标题栏目(titleBar)
前端
开心_开心急了3 小时前
Ai加Flutter实现自定义标题栏(appBar)
前端·flutter
布列瑟农的星空3 小时前
SSE与流式传输(Streamable HTTP)
前端·后端
GISer_Jing3 小时前
跨境营销前端AI应用业务领域
前端·人工智能·aigc
oak隔壁找我3 小时前
Node.js的package.json
前端·javascript
talenteddriver3 小时前
web: http请求(自用总结)
前端·网络协议·http
全栈派森3 小时前
Flutter 实战:基于 GetX + Obx 的企业级架构设计指南
前端·flutter