前言
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,为后端模板替换mysql2为typeorm,并添加实体类配置; - 保留
pnpm相关配置,确保生成的项目默认使用pnpm安装依赖。
五、脚手架使用流程(最终效果)
- 全局安装脚手架
bash
pnpm install -g admin-management-scaffold
- 创建项目
bash
admin-cli create my-admin-project
- 交互式配置
plaintext
? 请选择后台管理系统模板类型 基础版(极简核心功能)
? 前端是否开启国际化(vue-i18n) No
? 后端是否使用TypeORM(ORM框架) No
? 是否开启ESLint代码校验 Yes
- 启动项目
bash
cd my-admin-project
pnpm install # 根目录统一安装依赖
pnpm dev # 同时启动前端(3000端口)和后端(4000端口)
- 访问项目
- 前端:http://localhost:3000(登录账号:admin/123456)
- 后端接口:http://localhost:4000/api
六、脚手架维护与迭代
- 依赖更新:定期更新模板中的依赖版本(如 Vue3、Koa、Element Plus),确保兼容性;
- 功能扩展:新增前端功能(如数据可视化 ECharts、文件预览)、后端功能(如分页插件、文件上传);
- 问题修复:根据用户反馈修复模板中的 bug(如路由跳转异常、接口报错);
- 文档完善:补充模板使用文档、接口文档(如 Swagger/OpenAPI),降低使用成本。
总结
基于Vue3+TS+Vite+Element Plus+Pinia+Vue Router(前端)、Node+TS+Koa(后端)、pnpm(构建工具)的脚手架,核心价值在于:
- 提效:一条命令生成前后端一体化项目,无需手动配置技术栈和实现基础功能;
- 规范:固化项目结构、代码规范和最佳实践,确保团队开发风格统一;
- 灵活:支持交互式配置,可根据需求开启 / 关闭部分功能,适配不同场景;
- 易维护:模板与脚手架分离,便于后续迭代更新,不影响已生成的项目。
通过该脚手架,开发者可快速聚焦业务开发,无需在项目搭建和基础配置上耗费时间
后台管理系统脚手架(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
使用
- 创建项目
bash
admin-cli create my-admin
- 启动项目
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
发布时可能的报错及解决方案
- 包名重复 :修改
package.json中的name字段,确保全网唯一(可在 npm 官网搜索包名,确认是否已被占用); - 版本号重复 :更新版本号(如从 1.0.0 改为 1.0.1),执行
pnpm version patch(自动升级补丁版本); - 未登录 / 权限不足 :重新执行
npm login,确认账号是否有权限发布(新账号需验证邮箱); - 文件过大 :检查
files字段,删除无用文件,减小包体积; - Node 版本不满足 :升级本地 Node.js 版本至
engines字段指定的版本以上。
步骤 4:发布成功验证
- 访问 npm 官网,搜索你的包名(如
admin-cli-vue3-koa),可看到已发布的包信息; - 在终端执行全局安装命令,验证是否能正常安装:
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安装最新版本。
总结
脚手架发布的核心流程可概括为:
- 准备工作:完善
package.json、本地测试、编写文档、清理无用文件; - 环境配置:切换 npm 官方源、登录 npm 账号;
- 执行发布:
pnpm publish/npm publish; - 后续维护:版本更新、bug 修复、按需撤销包。
通过以上步骤,你的后台管理系统脚手架即可成功发布,其他开发者可通过pnpm install -g 你的包名全局安装,快速使用脚手架生成项目