@gaonengwww/tiny-toolkit-pro
Version:
TinyPro Vue:开箱即用、前后端分离的 Vue 后台管理模板
507 lines • 43.6 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.installDependencies = void 0;
const yaml_1 = require("yaml");
const path = __importStar(require("path"));
const dotenv = __importStar(require("dotenv"));
const fs_extra_1 = require("fs-extra");
const chalk_1 = __importDefault(require("chalk"));
const cross_spawn_1 = __importDefault(require("cross-spawn"));
const inquirer_1 = __importDefault(require("inquirer"));
const cli_devkit_1 = require("@opentiny/cli-devkit");
const properties_parser_1 = require("properties-parser");
const interfaces_1 = require("./interfaces");
const utils_1 = __importDefault(require("./utils"));
const fs_1 = require("fs");
const log = (0, cli_devkit_1.logs)('tiny-toolkit-pro');
const VUE_TEMPLATE_PATH = 'tinyvue';
const DEFAULT_PROJECT_NAME = 'tiny-pro';
/**
* 询问创建项目的描述,使用的技术栈
*
* @returns object { description: 项目描述,framework: 框架, name: 项目名称 ,serverFramework:使用技术栈, dialect:数据库,DB_host:数据库地址,DB_port:数据库端口,database:数据库名称,username:数据库用户名,password:数据库密码,}
*/
const getProjectInfo = () => {
const question = [
{
type: 'input',
name: 'name',
message: '请输入项目名称:',
default: DEFAULT_PROJECT_NAME,
// 必填校验
validate: (input) => Boolean(input),
},
{
type: 'input',
name: 'description',
message: '请输入项目描述:',
default: '基于TinyPro套件创建的中后台系统',
},
{
type: 'list',
name: 'framework',
message: '请选择您希望使用的客户端技术栈:',
choices: [{ name: 'vue', value: VUE_TEMPLATE_PATH }],
default: VUE_TEMPLATE_PATH,
prefix: '*',
},
{
type: 'list',
name: 'serverFramework',
message: '请选择您希望使用的服务端技术栈:',
choices: [
// { name: 'Egg.js', value: ServerFrameworks.EggJs },
{ name: 'SpringBoot', value: interfaces_1.ServerFrameworks.SpringBoot },
{ name: 'Nest.js', value: interfaces_1.ServerFrameworks.NestJs },
{ name: '暂不配置', value: interfaces_1.ServerFrameworks.Skip },
],
default: interfaces_1.ServerFrameworks.NestJs,
prefix: '*',
when: (answers) => answers.framework === VUE_TEMPLATE_PATH,
},
{
type: 'list',
name: 'buildTool',
message: '请选择你想要的构建工具: ',
choices: [
{ name: 'Vite', value: interfaces_1.BuildTool.Vite },
{ name: 'Webpack', value: interfaces_1.BuildTool.Webpack },
{ name: 'Rspack', value: interfaces_1.BuildTool.Rspack },
{ name: 'Farm', value: interfaces_1.BuildTool.Farm },
],
default: interfaces_1.BuildTool.Vite,
prefix: '*',
},
{
type: 'list',
name: 'serverConfirm',
message: '请确保已安装数据库服务(参考文档 https://www.opentiny.design/tiny-cli/docs/toolkits/pro#database):',
choices: [
{ name: '已完成数据库服务安装,开始配置', value: true },
{ name: '暂不配置服务端', value: false },
],
prefix: '*',
when: (answers) => answers.framework === VUE_TEMPLATE_PATH &&
answers.serverFramework !== interfaces_1.ServerFrameworks.Skip,
},
{
type: 'input',
name: 'redisHost',
message: '请输入Redis地址:',
default: 'localhost',
prefix: '*',
when: (answers) => answers.serverConfirm,
},
{
type: 'input',
name: 'redisPort',
message: '请输入Redis端口:',
default: 6379,
prefix: '*',
when: (answers) => answers.serverConfirm,
},
{
type: 'list',
name: 'dialect',
message: '请选择数据库类型:',
choices: [
{ name: 'MySql', value: 'mysql' },
{ name: '暂不配置', value: '' },
],
default: 'mysql',
prefix: '*',
when: (answers) => answers.serverConfirm,
},
{
type: 'input',
name: 'host',
message: '请输入数据库地址:',
default: 'localhost',
prefix: '*',
when: (answers) => answers.dialect,
},
{
type: 'input',
name: 'port',
message: '请输入数据库端口:',
default: 3306,
prefix: '*',
when: (answers) => answers.host,
},
{
type: 'input',
name: 'database',
message: '请输入数据库名称:',
prefix: '*',
validate: (input) => Boolean(input),
when: (answers) => answers.host,
},
{
type: 'input',
name: 'username',
message: '请输入登录用户名:',
default: 'root',
prefix: '*',
when: (answers) => answers.host,
},
{
type: 'password',
name: 'password',
message: '请输入密码:',
prefix: '*',
when: (answers) => answers.host,
},
];
return inquirer_1.default.prompt(question);
};
/**
* 同步创建服务端项目文件目录、文件
* @answers 询问客户端问题的选择值
* @dbAnswers 询问服务端配置的选择值
*/
const createServerSync = (answers) => {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
const { name, serverFramework } = answers;
// 复制服务端相关目录
const serverFrom = utils_1.default.getTemplatePath(`${serverFramework}`);
const serverTo = utils_1.default.getDistPath(`${name}/${serverFramework}`);
if (serverFramework == interfaces_1.ServerFrameworks.SpringBoot) {
console.log('springboot的服务端配置');
// 拷贝 SpringBoot 模板代码到目标目录
(0, fs_extra_1.copySync)(serverFrom, serverTo);
// ===== 1. 定义统一的配置对象(从用户输入中提取,不写死)=====
const config = {
DB_HOST: (_a = answers.host) !== null && _a !== void 0 ? _a : 'localhost',
DB_PORT: Number((_b = answers.port) !== null && _b !== void 0 ? _b : 3306),
DB_USERNAME: (_c = answers.username) !== null && _c !== void 0 ? _c : 'root',
DB_PASSWORD: (_d = answers.password) !== null && _d !== void 0 ? _d : 'root',
DB_NAME: (_e = answers.database) !== null && _e !== void 0 ? _e : 'mydb',
DB_SYNCHRONIZE: false,
DB_AUTOLOADENTITIES: true,
AUTH_SECRET: 'secret',
REDIS_SECONDS: 7200,
REDIS_HOST: (_f = answers.redisHost) !== null && _f !== void 0 ? _f : 'localhost',
REDIS_PORT: Number((_g = answers.redisPort) !== null && _g !== void 0 ? _g : 6379),
EXPIRES_IN: '2h',
PAGINATION_PAGE: 1,
PAGINATION_LIMIT: 10,
SERVER_PORT: 3000, // 可以改为 answers.serverPort || 3000,如果将来要支持动态端口
};
// ===== 2. 拷贝模板后,设置 Spring Boot 配置文件路径 =====
const propertiesFilePath = path.join(serverTo, 'src/main/resources/application.properties');
if (!(0, fs_1.existsSync)(propertiesFilePath)) {
log.error(`❌ 未找到 Spring Boot 配置文件:${propertiesFilePath}`);
return;
}
if (!(0, fs_1.existsSync)(propertiesFilePath)) {
log.error(`❌ 未找到 Spring Boot 配置文件:${propertiesFilePath}`);
return;
}
// ✅ 1. 使用 createEditor 读取 properties 文件
const editor = (0, properties_parser_1.createEditor)(propertiesFilePath);
// ✅ 3. 使用 editor.set(...) 方法逐一设置每一个配置项
editor.set('server.port', config.SERVER_PORT.toString()); // 动态端口
editor.set('spring.datasource.url', `jdbc:mysql://${config.DB_HOST}:${config.DB_PORT}/${config.DB_NAME}?allowMultiQueries=true&serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&allowPublicKeyRetrieval=true&useSSL=false`);
editor.set('spring.datasource.username', config.DB_USERNAME);
editor.set('spring.datasource.password', config.DB_PASSWORD);
editor.set('spring.datasource.driver-class-name', 'com.mysql.cj.jdbc.Driver');
// HikariCP 配置
editor.set('spring.datasource.hikari.pool-name', 'HikariCPDatasource');
editor.set('spring.datasource.hikari.minimum-idle', '5');
editor.set('spring.datasource.hikari.idle-timeout', '180000');
editor.set('spring.datasource.hikari.maximum-pool-size', '10');
editor.set('spring.datasource.hikari.auto-commit', 'true');
editor.set('spring.datasource.hikari.max-lifetime', '180000');
editor.set('spring.datasource.hikari.connection-timeout', '30000');
// MyBatis-Plus
editor.set('mybatis-plus.mapper-locations', 'classpath:mappers/*.xml');
editor.set('mybatis-plus.type-aliases-package', 'com.TinyPro.entity.po');
editor.set('mybatis-plus.configuration.map-underscore-to-camel-case', 'true');
editor.set('mybatis-plus.configuration.default-enum-type-handler', 'org.apache.ibatis.type.EnumOrdinalTypeHandler');
// JPA (如同时使用)
editor.set('spring.jpa.hibernate.ddl-auto', 'update');
editor.set('spring.jpa.database-platform', 'org.hibernate.dialect.MySQL8Dialect');
editor.set('spring.jpa.properties.hibernate.dialect', 'org.hibernate.dialect.MySQL8Dialect');
editor.set('spring.jpa.properties.hibernate.dialect.storage_engine', 'innodb');
editor.set('spring.jpa.properties.hibernate.globally_quoted_identifiers', 'true');
editor.set('spring.jpa.hibernate.naming.physical-strategy', 'org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl');
// JWT
editor.set('jwt.secret', '0Zi4SA==');
// Redis
editor.set('spring.data.redis.host', config.REDIS_HOST);
editor.set('spring.data.redis.port', config.REDIS_PORT.toString());
// ✅ 4. 保存修改后的内容到原 .properties 文件
editor.save(propertiesFilePath);
log.success(`✅ Spring Boot 配置文件已更新:${propertiesFilePath}`);
}
else if (serverFramework == interfaces_1.ServerFrameworks.NestJs) {
const config = {
DATABASE_HOST: answers.dialect && ((_h = answers.host) !== null && _h !== void 0 ? _h : 'localhost'),
DATABASE_PORT: answers.dialect && Number((_j = answers.port) !== null && _j !== void 0 ? _j : 3306),
DATABASE_USERNAME: answers.dialect && ((_k = answers.username) !== null && _k !== void 0 ? _k : 'root'),
DATABASE_PASSWORD: answers.dialect && ((_l = answers.password) !== null && _l !== void 0 ? _l : 'root'),
DATABASE_NAME: answers.dialect && answers.database,
DATABASE_SYNCHRONIZE: false,
DATABASE_AUTOLOADENTITIES: true,
AUTH_SECRET: 'secret',
REDIS_SECONDS: 7200,
REDIS_HOST: (_m = answers.redisHost) !== null && _m !== void 0 ? _m : 'localhost',
REDIS_PORT: Number((_o = answers.redisPort) !== null && _o !== void 0 ? _o : 6379),
EXPIRES_IN: '2h',
PAGINATION_PAGE: 1,
PAGINATION_LIMIT: 10,
};
const envStr = objToEnv(config);
const overwriteDockerComposeConfig = {
// @see https://hub.docker.com/_/mysql
// This variable is mandatory and specifies the password that will be set for the MySQL root superuser account.
MYSQL_ROOT_PASSWORD: config.DATABASE_PASSWORD,
MYSQL_DATABASE: config.DATABASE_NAME,
MYSQL_USER: config.DATABASE_USERNAME === 'root' ? undefined : config.DATABASE_NAME,
MYSQL_PASSWORD: config.DATABASE_USERNAME === 'root'
? undefined
: config.DATABASE_PASSWORD,
};
(0, fs_extra_1.copySync)(serverFrom, serverTo);
(0, fs_1.writeFileSync)(path.join(serverTo, '.env'), envStr);
const dockerComposeYaml = (0, fs_1.readFileSync)(path.join(serverTo, 'docker-compose.yml')).toString();
const yaml = (0, yaml_1.parse)(dockerComposeYaml);
const { services } = yaml;
const mysql = services.mysql;
mysql.environment = overwriteDockerComposeConfig;
(0, fs_1.writeFileSync)(path.join(serverTo, 'docker-compose.yml'), (0, yaml_1.stringify)(yaml));
}
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const objToEnv = (obj) => {
return Object.entries(obj)
.map(([key, value]) => {
const v = typeof value === 'string' ? `'${value}'` : value;
return [key, '=', v].join(' ');
})
.join('\n');
};
const packageJsonProcess = (buildTool, packages, currentPath) => {
const match = (pattern, items) => {
return items.filter((item) => pattern.test(item));
};
const removeDeps = () => {
const devDeps = interfaces_1.devDependencies[buildTool];
devDeps.forEach((devDep) => {
if (typeof devDep === 'string') {
packages.devDependencies[devDep] = undefined;
}
if (devDep instanceof RegExp) {
const deps = match(devDep, Object.keys(packages.devDependencies));
if (!deps.length) {
return;
}
deps.forEach((dep) => {
if (packages.devDependencies[dep]) {
packages.devDependencies[dep] = undefined;
}
});
}
});
const dependencies = interfaces_1.removeDependencies[buildTool];
dependencies.forEach((dep) => {
if (typeof dep === 'string') {
if (!packages.dependencies[dep]) {
return;
}
packages.dependencies[dep] = undefined;
}
if (dep instanceof RegExp) {
const keys = match(dep, Object.keys(packages.devDependencies));
keys.forEach((key) => {
if (!packages.dependencies[key]) {
return;
}
packages.dependencies[key] = undefined;
});
}
});
};
const replaceScript = (name, command) => {
packages.scripts[name] = command;
};
const removeScripts = () => {
const scripts = interfaces_1.removedCommand;
scripts.forEach((script) => {
replaceScript(script, undefined);
});
};
const replaceBuildCommand = () => {
const command = interfaces_1.buildCommand[buildTool];
replaceScript('build', command);
};
const replaceDevCommand = () => {
const command = interfaces_1.devCommand[buildTool];
replaceScript('start', command);
};
const remove = () => {
const removedPaths = interfaces_1.buildConfigs[buildTool];
const paths = removedPaths
.filter((removedPath) => (0, fs_1.existsSync)(path.join(currentPath, removedPath)))
.map((p) => path.join(currentPath, p));
if (!paths.length) {
return;
}
let willRemovePath = '';
try {
paths.forEach((removePath) => {
willRemovePath = removePath;
(0, fs_1.rmSync)(removePath, { recursive: true, force: true });
});
}
catch (_a) {
log.error(`删除${willRemovePath}错误`);
}
};
removeDeps();
removeScripts();
replaceBuildCommand();
replaceDevCommand();
return remove;
};
/**
* 同步创建客户端项目文件目录、文件
* @answers 询问客户端问题的选择值
* @dbAnswers 询问服务端配置的选择值
*/
const createProjectSync = (answers) => {
const { description, name, serverConfirm, buildTool, serverFramework } = answers;
const templatePath = interfaces_1.VueVersion.Vue3;
// 模板来源目录
const from = utils_1.default.getTemplatePath(templatePath);
// 复制模板的目标目录
const to = utils_1.default.getDistPath(serverConfirm ? `${name}/web` : name);
cli_devkit_1.fs.copyTpl(from, to);
// 将项目名称、描述写入 package.json中
if (serverFramework == interfaces_1.ServerFrameworks.NestJs) {
try {
const packageJsonPath = path.join(to, 'package.json');
let packageJson = JSON.parse(cli_devkit_1.fs.readFileSync(packageJsonPath, { encoding: 'utf8' }));
packageJson = Object.assign(Object.assign({}, packageJson), { name, description });
const remove = packageJsonProcess(buildTool, packageJson, to);
cli_devkit_1.fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2), {
encoding: 'utf8',
});
remove();
}
catch (e) {
log.error(e);
log.error('配置项目信息创建失败');
}
}
// 如果不对接服务端,全部接口采用mock
if (!serverConfirm) {
try {
const envPath = path.join(to, '.env');
const envConfig = dotenv.parse(cli_devkit_1.fs.readFileSync(envPath, { encoding: 'utf8' }));
delete envConfig.VITE_MOCK_IGNORE;
const config = Object.keys(envConfig)
.map((key) => `${key} = ${envConfig[key]}`)
.join('\n');
cli_devkit_1.fs.writeFileSync(envPath, config);
}
catch (e) {
log.error(e);
log.error('开启mock模式失败');
log.info('请手动配置env信息');
}
}
else {
console.log('执行文件复制及相关配置( WIP: 后台接口暂未全量完成,部分接口还是使用mock )');
// 如果对接服务端,执行文件复制及相关配置( WIP: 后台接口暂未全量完成,部分接口还是使用mock )
createServerSync(answers);
}
};
// 安装依赖
const installDependencies = (answers) => {
const prefix = cli_devkit_1.cliConfig.getBinName();
const { name, serverFramework, serverConfirm } = answers;
// egg服务端 安装依赖并启动
if (serverConfirm && serverFramework === interfaces_1.ServerFrameworks.EggJs) {
log.info('正在安装服务端 npm 依赖,安装过程需要几十秒,请耐心等待...');
const installServiceResult = cross_spawn_1.default.sync('npm', ['install'], {
cwd: `${name}/${serverFramework}/`,
stdio: 'inherit',
});
if (installServiceResult.status === 0) {
log.success('服务端 npm 依赖安装成功');
}
else {
throw new Error(installServiceResult.error);
}
}
// npm 依赖安装
log.info('正在安装客户端 npm 依赖,安装过程需要几十秒,请耐心等待...');
const installClientResult = cross_spawn_1.default.sync('npm', ['install'], {
cwd: serverConfirm ? `${name}/web` : `${name}/`,
stdio: 'inherit',
});
if (installClientResult.status === 0) {
log.success('客户端 npm 依赖安装成功');
}
else {
throw new Error(installClientResult.error);
}
/* prettier-ignore-start */
console.log(chalk_1.default.yellow('\n--------------------初始化成功,请按下面提示进行操作--------------------\n'));
if (serverConfirm) {
console.log(chalk_1.default.green(`${chalk_1.default.yellow(`$ cd ${name}/web && npm run start`)} # 开启web开发环境`));
console.log(chalk_1.default.green(`${chalk_1.default.yellow(serverFramework === interfaces_1.ServerFrameworks.SpringBoot
? `请查看 ${name}/${serverFramework}/README_CN.md `
: `$ cd ${name}/${serverFramework} && npm run dev`)} # 开启server开发环境`));
}
else {
console.log(chalk_1.default.green(`${chalk_1.default.yellow(`$ cd ${name} && ${prefix} start`)} # 可一键开启项目开发环境`));
}
console.log(chalk_1.default.green(`${chalk_1.default.yellow(`$ ${prefix} help`)} # 可查看当前套件的详细帮助`));
console.log(chalk_1.default.green(`\n建议将现有初始化的代码提交一次到master分支, 方便后续切换到 ${chalk_1.default.yellow('daily/x.y.z')} 分支进行开发`));
console.log(chalk_1.default.yellow('\n-------------------- 技术支持:官方小助手微信opentiny-official --------------------\n'));
};
exports.installDependencies = installDependencies;
exports.default = async () => {
// 拷贝模板到当前目录
let projectInfo;
try {
// 创建项目文件夹及文件
projectInfo = await getProjectInfo();
createProjectSync(projectInfo);
}
catch (e) {
log.error(e);
log.error('项目模板创建失败');
return;
}
log.info('初始化成功,请运行npm i或tiny i 安装依赖');
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5pdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9saWIvaW5pdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLCtCQUF3QztBQUN4QywyQ0FBNkI7QUFDN0IsK0NBQWlDO0FBQ2pDLHVDQUFvQztBQUNwQyxrREFBMEI7QUFDMUIsOERBQWdDO0FBQ2hDLHdEQUF3RDtBQUN4RCxxREFBMkQ7QUFDM0QseURBQWlEO0FBQ2pELDZDQVdzQjtBQUN0QixvREFBNEI7QUFDNUIsMkJBQXFFO0FBRXJFLE1BQU0sR0FBRyxHQUFHLElBQUEsaUJBQUksRUFBQyxrQkFBa0IsQ0FBQyxDQUFDO0FBQ3JDLE1BQU0saUJBQWlCLEdBQUcsU0FBUyxDQUFDO0FBQ3BDLE1BQU0sb0JBQW9CLEdBQUcsVUFBVSxDQUFDO0FBRXhDOzs7O0dBSUc7QUFDSCxNQUFNLGNBQWMsR0FBRyxHQUF5QixFQUFFO0lBQ2hELE1BQU0sUUFBUSxHQUFvQztRQUNoRDtZQUNFLElBQUksRUFBRSxPQUFPO1lBQ2IsSUFBSSxFQUFFLE1BQU07WUFDWixPQUFPLEVBQUUsVUFBVTtZQUNuQixPQUFPLEVBQUUsb0JBQW9CO1lBQzdCLE9BQU87WUFDUCxRQUFRLEVBQUUsQ0FBQyxLQUFhLEVBQUUsRUFBRSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUM7U0FDNUM7UUFDRDtZQUNFLElBQUksRUFBRSxPQUFPO1lBQ2IsSUFBSSxFQUFFLGFBQWE7WUFDbkIsT0FBTyxFQUFFLFVBQVU7WUFDbkIsT0FBTyxFQUFFLHFCQUFxQjtTQUMvQjtRQUNEO1lBQ0UsSUFBSSxFQUFFLE1BQU07WUFDWixJQUFJLEVBQUUsV0FBVztZQUNqQixPQUFPLEVBQUUsa0JBQWtCO1lBQzNCLE9BQU8sRUFBRSxDQUFDLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsaUJBQWlCLEVBQUUsQ0FBQztZQUNwRCxPQUFPLEVBQUUsaUJBQWlC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