Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
c5504a5
feat: 调整服务端目录 增加命令行
aliceDxr May 26, 2023
1d94326
fix: 优化目录结构
aliceDxr May 26, 2023
c6aea1d
feat: 增加对接服务器命令行
aliceDxr May 30, 2023
658ac6f
feat: 增加对接服务端模块
aliceDxr May 30, 2023
8f12673
Merge remote-tracking branch 'upstream/dev' into dev
aliceDxr May 30, 2023
e484e4d
fix: add tinyPro-vue server-side integration
aliceDxr May 30, 2023
12cd43f
fix: fix axios-interceptor errcode, add init cli
aliceDxr May 30, 2023
9d5a9dc
Merge remote-tracking branch 'upstream/dev' into tinyPro-vue-server-side
aliceDxr May 30, 2023
0f4a438
fix: fix mock request errcode
aliceDxr May 30, 2023
16a3c06
Merge remote-tracking branch 'upstream/dev' into tinyPro-vue-server-side
aliceDxr May 30, 2023
2156012
fix: close egg auto start-up
aliceDxr May 30, 2023
acc4d93
fix: add server default port
aliceDxr May 30, 2023
3defa3d
Merge remote-tracking branch 'upstream/dev' into tinyPro-vue-server-side
aliceDxr May 30, 2023
fa00a0b
fix: update version
aliceDxr May 30, 2023
bf929dd
Merge remote-tracking branch 'upstream/dev' into tinyPro-vue-server-side
aliceDxr May 31, 2023
995e4e2
fix: add csrftoken into requestHead
aliceDxr May 31, 2023
a8786b0
fix: fix httprequest header
aliceDxr May 31, 2023
93f30f5
fix: format code
aliceDxr May 31, 2023
c6f6a23
fix: format code
aliceDxr May 31, 2023
62c8b12
Merge remote-tracking branch 'upstream/dev' into tinyPro-vue-server-side
aliceDxr Jun 1, 2023
92704f1
fix: reduce init question add default server settings
aliceDxr Jun 1, 2023
3a40676
Merge remote-tracking branch 'upstream/dev' into tinyPro-vue-server-side
aliceDxr Jun 1, 2023
895b684
fix: add egg database config
aliceDxr Jun 5, 2023
06d030b
fix: update config cli
aliceDxr Jun 5, 2023
67f63b6
fix: update config cli
aliceDxr Jun 5, 2023
4264ce0
fix: use ejs template config
aliceDxr Jun 7, 2023
7a35d17
fix: modify default config
aliceDxr Jun 8, 2023
2d5f787
fix: modify database config
aliceDxr Jun 9, 2023
e2135e5
fix: modify variable name
aliceDxr Jun 9, 2023
d77618e
fix: modify variable name
aliceDxr Jun 9, 2023
d0ec073
fix: modify interface type
aliceDxr Jun 10, 2023
fd54a79
fix: delete useless variable
aliceDxr Jun 10, 2023
9840680
fix: delete useless function
aliceDxr Jun 10, 2023
60017ba
fix: format code
aliceDxr Jun 14, 2023
4bc9e66
Merge remote-tracking branch 'upstream/dev' into tinyPro-vue-server-side
aliceDxr Jun 14, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/toolkits/pro/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"chalk": "^4.1.2",
"cross-spawn": "^7.0.3",
"dotenv": "^16.0.3",
"ejs": "^3.1.9",
"fs-extra": "^10.1.0",
"inquirer": "^8.0.2",
"open": "^8.4.0"
Expand Down
235 changes: 130 additions & 105 deletions packages/toolkits/pro/src/lib/init.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
import * as path from 'path';
import chalk from 'chalk';
import spawn from 'cross-spawn';
import * as dotenv from 'dotenv';
import inquirer, { QuestionCollection } from 'inquirer';
import { cliConfig, logs, fs, user, modules } from '@opentiny/cli-devkit';
import { InitAnswers } from './interfaces';
import { cliConfig, logs, fs } from '@opentiny/cli-devkit';
import { ProjectInfo, ServerFrameworks } from './interfaces';
import utils from './utils';
import * as dotenv from 'dotenv';
dotenv.config();

const log = logs('tiny-toolkit-pro');
const cwd = process.cwd();
const vueTemplatePath = 'tinyvue';
const ngTemplatePath = 'tinyng';
const VUE_TEMPLATE_PATH = 'tinyvue';
const NG_TEMPLATE_PATH = 'tinyng';

/**
* 询问创建项目的描述,使用的技术栈
*
* @returns pbject { description: 项目描述,framework: 框架, name: 项目名称 }
* @returns object { description: 项目描述,framework: 框架, name: 项目名称 ,serverFramework:使用技术栈, dialect:数据库,DB_host:数据库地址,DB_port:数据库端口,database:数据库名称,username:数据库用户名,password:数据库密码,}
*/
const getInitAnswers = (): Promise<InitAnswers> => {
const getProjectInfo = (): Promise<ProjectInfo> => {
const basename = path.basename(utils.getDistPath());
const question: QuestionCollection<InitAnswers> = [
const question: QuestionCollection<ProjectInfo> = [
{
type: 'input',
name: 'name',
Expand All @@ -40,145 +38,175 @@ const getInitAnswers = (): Promise<InitAnswers> => {
name: 'framework',
message: '请选择您希望使用的客户端技术栈:',
choices: [
{ name: 'vue', value: vueTemplatePath },
{ name: 'angular', value: ngTemplatePath },
{ name: 'vue', value: VUE_TEMPLATE_PATH },
{ name: 'angular', value: NG_TEMPLATE_PATH },
],
default: vueTemplatePath,
default: VUE_TEMPLATE_PATH,
prefix: '*',
},
{
type: 'list',
name: 'serverType',
name: 'serverFramework',
message: '请选择您希望使用的服务端技术栈:',
choices: [
{ name: 'Egg.js', value: 'eggJs' },
{ name: 'Spring Cloud', value: 'springCloud' },
{ name: 'Nest.js', value: 'nestJs' },
{ name: 'Dont`t need', value: false },
{ name: 'Egg.js', value: ServerFrameworks.EggJs },
{ name: 'Spring Cloud', value: ServerFrameworks.SpringCloud },
{ name: 'Nest.js', value: ServerFrameworks.NestJs },
{ name: '暂不配置', value: ServerFrameworks.Skip },
],
default: 'eggJs',
default: ServerFrameworks.EggJs,
prefix: '*',
},
] as const;

{
type: 'list',
name: 'dialect',
message: '请选择数据库类型:',
choices: [
{ name: 'mySQL', value: 'mysql' },
{ name: '暂不配置', value: '' },
],
default: 'mysql',
prefix: '*',
when: (answers) => answers.serverFramework !== ServerFrameworks.Skip
},
{
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: string) => 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.prompt(question);
};

/**
* 同步创建项目文件目录、文件
* @answers 询问问题的选择值
* 同步创建服务端项目文件目录、文件
* @answers 询问客户端问题的选择值
* @dbAnswers 询问服务端配置的选择值
*/
const createProjectSync = (answers: InitAnswers) => {
const prefix = cliConfig.getBinName();

// 当前项目名称集合
const dirName = cwd.split(path.sep).pop() as string;
const names = utils.generateNames(dirName);
const fullName = modules.utils.toolkitFullName(dirName);

const data = {
...user.get(),
...names,
// 完整的插件名称 , 如 tiny-plugin-npm
pluginName: fullName.replace('@opentiny/', ''),
// tslint:disable-next-line
prefix,
pluginShortName: dirName,
pluginFullname: fullName,
};
const createServerSync = (answers: ProjectInfo) => {
const { serverFramework, dialect } = answers;
// 复制服务端相关目录
const serverFrom = utils.getTemplatePath(`server/${serverFramework}`);
const serverTo = utils.getDistPath('server');
const defaultConfig = { // 在未配置数据库信息时,使用默认值替换ejs模板
dialect: 'mysql',
host: 'localhost',
port: 3306,
username: 'root',
password: '123456',
database: 'tiny_pro_server'
}
fs.copyTpl(serverFrom, serverTo, dialect ? answers : defaultConfig, {
overwrite: true,
});
};

const {
framework,
description,
name: packageJsonName,
serverType,
} = answers;
/**
* 同步创建客户端项目文件目录、文件
* @answers 询问客户端问题的选择值
* @dbAnswers 询问服务端配置的选择值
*/
const createProjectSync = (answers: ProjectInfo) => {
const { framework, description, name, serverFramework } = answers;
const templatePath =
framework === vueTemplatePath ? vueTemplatePath : ngTemplatePath;
framework === VUE_TEMPLATE_PATH ? VUE_TEMPLATE_PATH : NG_TEMPLATE_PATH;

// 模板来源目录
const from = utils.getTemplatePath(templatePath);

// 复制模板的目标目录
const to = utils.getDistPath(serverType ? 'web' : '');
// 项目名称,跟当前目录保持一致
const to = utils.getDistPath(serverFramework ? 'web' : '');

fs.copyTpl(from, to, data, {
// 改一下名称,兼容其他cli工具的情况
rename(filename: string) {
if (filename === 'tiny.config.js') {
// tslint:disable-next-line: no-parameter-reassignment
filename = `${prefix}.config.js`;
}

return filename;
},
});
// 如果对接服务端,复制相关目录
if (serverType) {
const serverFrom = utils.getTemplatePath(`server/${serverType}`);
const serverTo = utils.getDistPath('server');
fs.copyTpl(serverFrom, serverTo);
}
fs.copyTpl(from, to);
// 将项目名称、描述写入 package.json中
{
try {
const packageJsonPath = path.join(to, 'package.json');
const writeOrReadOptions = { encoding: 'utf8' } as const;

const packageJson = JSON.parse(
fs.readFileSync(packageJsonPath, writeOrReadOptions)
let packageJson = JSON.parse(
fs.readFileSync(packageJsonPath, { encoding: 'utf8' })
);
packageJson.name = packageJsonName;
packageJson.description = description;
packageJson = { ...packageJson, name, description };
fs.writeFileSync(
packageJsonPath,
JSON.stringify(packageJson, null, 2),
{ encoding: 'utf8' }
);
} catch (e) {
log.error('配置项目信息创失败');
}

if (!serverType) {
// 如果不对接服务端,默认开启mock
if (!serverFramework) {
try {
const envPath = path.join(to, '.env');
const envConfig = dotenv.parse(
fs.readFileSync(envPath, writeOrReadOptions)
fs.readFileSync(envPath, { encoding: 'utf8' })
);
envConfig.VITE_USE_MOCK = 'true';
const config = Object.keys(envConfig)
.map((key) => `${key} = ${envConfig[key]}`)
.join('\n');
fs.writeFileSync(envPath, config);
} catch (e) {
log.error('开启mock模式失败');
log.info('请手动配置env信息');
}

fs.writeFileSync(
packageJsonPath,
JSON.stringify(packageJson, null, 2),
writeOrReadOptions
);
} else {
// 如果对接服务端,执行文件复制及相关配置
createServerSync(answers);
}
};

// 安装依赖
export const installDependencies = (
answers: InitAnswers
) => {
export const installDependencies = (answers: ProjectInfo) => {
const prefix = cliConfig.getBinName();

// egg服务端 安装依赖并启动
if (answers.serverType === 'eggJs') {
if (answers.serverFramework === ServerFrameworks.EggJs) {
log.info('正在安装 npm 依赖,安装过程需要几十秒,请耐心等待...');
spawn.sync('npm', ['install'], {
cwd: 'server/',
stdio: 'inherit',
});
log.success('npm 依赖安装成功');
// spawn.sync('npm', ['run','dev'], {
// cwd: 'server/',
// stdio: 'inherit',
// });
// log.success('服务已启动 ...');
}

// npm 依赖安装
log.info('正在安装 npm 依赖,安装过程需要几十秒,请耐心等待...');
spawn.sync('npm', ['install'], {
cwd: answers.serverType ? 'web/' : null,
cwd: answers.serverFramework ? 'web/' : null,
stdio: 'inherit',
});

log.success('npm 依赖安装成功');

/* prettier-ignore-start */
Expand Down Expand Up @@ -213,24 +241,21 @@ export const installDependencies = (

export default async () => {
// 拷贝模板到当前目录
let answers: any = {};
let projectInfo: ProjectInfo;

try {
// 创建项目文件夹及文件
answers = await getInitAnswers();
createProjectSync(answers);
projectInfo = await getProjectInfo();
createProjectSync(projectInfo);
} catch (e) {
log.error('项目模板创建失败');
log.debug(e);
throw e;
}

// 安装依赖
try {
installDependencies(answers);
installDependencies(projectInfo);
} catch (e) {
log.error('npm 依赖安装失败');
log.error('请手动执行 tiny i 或 npm i');
log.debug(e);
throw e;
log.info('请手动执行 tiny i 或 npm i');
}
};
20 changes: 18 additions & 2 deletions packages/toolkits/pro/src/lib/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,28 @@ export interface CliOption {
clientOptions: any;
}

/**
* 服务端类型
*/
export enum ServerFrameworks {
EggJs = 'eggJs',
NestJs = 'nestJs',
SpringCloud = 'springCloud',
Skip = ''
}

/**
* 初始化问题的选项 -> 选择的值
*/
export interface InitAnswers {
export interface ProjectInfo {
description: string;
framework: string;
name: string;
serverType: string | boolean;
serverFramework: ServerFrameworks;
dialect?: string;
host?: string;
port?: Number;
database?: string;
username?: string;
password?: string;
}
Loading