monorepo-cli
Version:
基于 yarn v2 berry 的 monorepo 项目的创建
891 lines (889 loc) • 34.3 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const fs = require("fs");
const fsp = fs.promises;
const path = require("path");
const commander = require("commander");
const program = commander.program;
const utils = require("ph-utils");
const fileUtils = require("ph-utils/lib/file");
const colors = require("ansi-colors");
const https = require("https");
const Spinner = require("ph-terminal-spinner");
const serverUtils = require("ph-utils/lib/server");
const url_1 = require("url");
const pkg = require("./package.json");
const enquirer = require('enquirer');
const Mustache = require('mustache');
/** 模板文件地址 */
const TEMPLATE_PATH = path.join(__dirname, 'templates');
const devDepends = {
typescript: '4.4.3',
prettier: '2.4.1',
eslint: '7.32.0',
'eslint-config-alloy': '4.3.0',
'@typescript-eslint/eslint-plugin': '4.33.0',
'@typescript-eslint/parser': '4.33.0',
'@types/node': '16.10.3',
};
program.version(pkg.version);
const spinner = new Spinner();
const eslintConfig = {
extends: ['alloy'],
rules: {
// 自定义你的规则
'no-eq-null': 'off',
eqeqeq: ['error', 'always', { null: 'ignore' }],
'no-param-reassign': 'off',
'max-params': ['error', 5],
},
};
// eslint prettier git 通用的忽略
const eslintIgnore = ['/.yarn/*', '/**/*.d.ts', '.pnp.js'];
const gitignore = ['node_modules', '*.log', '.idea', '.vscode', '/packages/**/LICENSE', '/**/*.d.ts'];
/**
* 下载更新 yarn 版本到 berry,类似于执行命令 yarn set version berry
* @param yarnPath 下载后的 berry 文件保存目录
* @param rc 下载次数,做失败重连处理,最多4次,超过4次则触发下载失败
* @param cb 下载完成后的回调,参数表示是否失败
*/
function downloadBerry(yarnPath, rc, cb) {
let req = https.get('https://codechina.csdn.net/u011113654/yarn2-berry/-/raw/master/yarn-berry.cjs', (res) => {
res.setEncoding('utf-8');
let savePath = path.join(yarnPath, 'yarn-berry.cjs');
let saveStream = fs.createWriteStream(savePath);
saveStream.on('close', () => {
cb(false);
});
res.pipe(saveStream);
});
req.on('error', () => {
if (rc === 4) {
cb(true);
// console.log('下载 berry 失败,请参考 https://gitee.com/towardly/yarn2-berry 手动下载!')
}
else {
rc++;
downloadBerry(yarnPath, rc, cb);
}
});
}
/**
* https GET 请求
* @param {String} url 请求 url 地址
*/
let get = function (url) {
return new Promise((resolve, reject) => {
https
.get(url, (res) => {
let resData = '';
let statusCode = res.statusCode;
res.setEncoding('utf8');
res.on('data', (chunk) => {
resData += chunk;
});
res.on('end', () => {
if (statusCode >= 200 && statusCode < 300) {
resolve(JSON.parse(resData));
}
else {
reject(new Error(statusCode + ' & ' + res.statusText));
}
});
})
.on('error', (e) => {
reject(e);
});
});
};
/**
* 根据应用包名获取应用的详细信息
* @param {String} packageName 应用包名
*/
function queryPackage(packageName) {
// https://registry.npmjs.org/koa/latest
return get(`https://registry.npm.taobao.org/${packageName}/latest`).then((r) => {
return { name: r.name, version: r.version };
});
}
/**
* 检查依赖版本项
*/
function checkDependencies(pkgs) {
return new Promise((resolve) => {
let dev1 = [];
let dev2 = [];
let len = pkgs.length;
if (len === 0) {
resolve([]);
}
for (let i = 0; i < len; i++) {
let name = pkgs[i];
queryPackage(name)
.then((pka) => {
pka.start = true;
if (name.startsWith('@')) {
dev1.push(pka);
}
else {
dev2.push(pka);
}
})
.catch(() => {
if (name.startsWith('@')) {
dev1.push({ name, version: devDepends[name], start: true });
}
else {
dev2.push({ name, version: devDepends[name], start: true });
}
})
.finally(() => {
if (dev1.length + dev2.length === len) {
dev1 = dev1.sort((a, b) => a.name.localeCompare(b.name));
dev2 = dev2.sort((a, b) => a.name.localeCompare(b.name));
let dev = dev1.concat(dev2);
dev[dev.length - 1].start = false;
resolve(dev);
}
});
}
});
}
/**
* 初始化工作区
* @param workspaceConfig
* @param wsDevs
* @returns
*/
function initWorkspace(workspaceConfig) {
return new Promise((resolve) => {
let wsDevs = [];
// 复制 LICENSE 文件
fs.copyFile(path.join(workspaceConfig.proPath, 'LICENSE'), path.join(workspaceConfig.path, 'LICENSE'), () => { });
// 构造主文件 index.ts
fileUtils.write(path.join(workspaceConfig.path, 'index.ts'), `console.log('${workspaceConfig.name}')`);
// README.md
fileUtils.write(path.join(workspaceConfig.path, 'README.md'), `#${workspaceConfig.name}\r\n---`);
if (workspaceConfig.isTs) {
let tsConfig = {
extends: '../../tsconfig_base.json',
compilerOptions: {
module: 'CommonJS',
outDir: './',
},
files: ['index.ts'],
};
if (!workspaceConfig.isNode) {
tsConfig.compilerOptions = {
module: 'es6',
resolveJsonModule: false,
outDir: './',
};
}
else {
wsDevs.push('@types/node');
}
// 写入 tsconfig.json 文件
fileUtils.write(path.join(workspaceConfig.path, 'tsconfig.json'), tsConfig);
}
resolve(wsDevs);
});
}
/**
* 更新 yarn 版本
* @param proPath
* @returns
*/
function updateYarn(proPath) {
return new Promise((resolve, reject) => {
spinner.start('更新yarn版本为berry');
// 更新 yarn 版本至 berry
const yarnPath = path.join(proPath, '.yarn', 'releases');
fs.mkdir(yarnPath, { recursive: true }, () => { });
fileUtils.write(path.join(proPath, '.yarnrc.yml'), 'yarnPath: ".yarn/releases/yarn-berry.cjs"');
let rc = 0; // 重试次数
// 下载更新 yarn 版本到 berry
downloadBerry(yarnPath, rc, (isError) => {
if (isError === true) {
spinner.fail('更新yarn版本失败');
reject(new utils.BaseError('UpgradeYarnError', 'update yarn to berry error'));
}
else {
spinner.succeed('更新yarn版本成功');
resolve(0);
}
});
});
}
/**
* 初始化工程
* @param proPath 工程目录
* @param config 配置项
* @param proDevs 工程依赖
* @returns
*/
function initProject(proPath, config) {
return new Promise((resolve) => {
let proDevs = [];
if (config.license === true) {
fs.copyFile(path.join(TEMPLATE_PATH, 'LICENSE'), path.join(proPath, 'LICENSE'), () => { });
}
if (config.ts === true) {
proDevs.push('typescript');
// 使用 ts
fs.copyFile(path.join(TEMPLATE_PATH, 'tsconfig_base.json'), path.join(proPath, 'tsconfig_base.json'), () => { });
eslintIgnore.push('/**/*.js');
gitignore.push('/**/*.js');
eslintConfig.extends.push('alloy/typescript');
eslintConfig.rules['@typescript-eslint/no-require-imports'] = 'off';
}
else {
eslintConfig.parser = 'espree';
}
if (config.prettier === true) {
proDevs.push('prettier');
// 需要 prettier
fs.copyFile(path.join(TEMPLATE_PATH, '.prettierrc.js'), path.join(proPath, '.prettierrc.js'), () => { });
fileUtils.write(path.join(proPath, '.prettierignore'), eslintIgnore.join('\r\n'));
}
if (config.eslint === true) {
proDevs.push('eslint');
proDevs.push('eslint-config-alloy');
if (config.ts === true) {
proDevs.push('@typescript-eslint/eslint-plugin');
proDevs.push('@typescript-eslint/parser');
}
// 需要 eslint
fileUtils.write(path.join(proPath, '.eslintignore'), eslintIgnore.join('\r\n'));
fileUtils.write(path.join(proPath, '.eslintrc.js'), 'module.exports = ' + JSON.stringify(eslintConfig, null, 2));
}
// 新建 package.json
// fileUtils.write(path.join(proPath, 'package.json'), pPkg)
// .gitignore
fileUtils.write(path.join(proPath, '.gitignore'), gitignore.join('\r\n'));
resolve(proDevs);
});
}
/**
* 渲染模板文件
* @param from 模板文件路径
* @param data 数据源
* @param to 目标文件
*/
function template(from, data, to) {
fs.readFile(from, 'utf-8', (err, tpl) => {
if (err == null) {
fileUtils.write(to, Mustache.render(tpl, data));
}
});
return Promise.resolve(0);
}
// 定义创建项目的命令
program
.command('create <name>')
.alias('c')
.description('创建 monorepo 项目')
.option('--ts', '是否使用ts,默认为:true', true)
.option('--no-ts', '不使用ts')
.option('-e, --eslint', '是否需要 eslint ,默认为:true', true)
.option('--no-eslint', '不需要 eslint ')
.option('-p, --prettier', '是否需要 prettier 进行格式化,默认为:true', true)
.option('--no-prettier', '不需要prettier')
.option('-n, --node', '是否是NodeJs(Commonjs)项目,而非 WEB(ES Module),默认为:true', true)
.option('--no-node', '不是nodejs项目')
.option('-l, --license', '是否需要 LICENSE 文件,默认为:true', true)
.option('--no-license', '不需要 license 文件,一般私有项目开发时配置')
.option('-t, --tool <tool>', '包管理工具, 默认为:yarn2')
.option('-w --workspace <name>', '新建项目的同时创建工作区')
.option('-d, --director <director>', '创建项目的目录地址,默认为:执行命令的目录')
.action((name, destination) => {
destination.tool = destination.tool === 'npm' ? 'npm' : 'yarn';
const spinner = new Spinner();
const projectPath = path.join(destination.director || process.cwd(), name); // 项目目录
let workspacePath = path.join(projectPath, 'packages'); // 工作区目录
if (!utils.isBlank(destination.workspace)) {
// 创建项目的同时创建工作区
workspacePath = path.join(workspacePath, destination.workspace);
}
// 验证文件是否存在
fsp.access(projectPath, fs.constants.F_OK).then(() => {
console.error(colors.red(`目录 ${projectPath} 已经存在!`));
}, () => {
spinner.start('创建项目目录');
// 创建文件夹
fsp
.mkdir(workspacePath, { recursive: true })
.then(() => {
spinner.succeed('创建项目目录成功');
spinner.start('构建项目文件');
// 初始化项目
return initProject(projectPath, destination);
})
.then((pkgs) => {
spinner.succeed('项目文件构建成功');
spinner.start('检查依赖……');
return checkDependencies(pkgs);
})
.then((pkgs) => {
spinner.succeed('依赖检查成功');
return template(path.join(TEMPLATE_PATH, 'project_package.mtl'), {
name,
packages: pkgs,
}, path.join(projectPath, 'package.json'));
})
.then(() => {
if (destination.tool === 'yarn') {
spinner.start('更新 yarn 版本');
return updateYarn(projectPath);
}
else {
return Promise.resolve(1);
}
})
.then((s) => {
if (s === 0) {
spinner.succeed('更新 yarn 版本成功');
}
// 初始化 工作区文件
if (!utils.isBlank(destination.workspace)) {
spinner.start('初始化工作区文件');
return initWorkspace({
name: destination.workspace,
isTs: destination.ts,
path: workspacePath,
isNode: destination.node,
proPath: projectPath,
});
}
else {
return Promise.resolve(0);
}
})
.then((s) => {
if (s !== 0) {
spinner.succeed('初始化工作区文件成功');
if (s.length !== 0) {
spinner.start('检查工作区依赖');
return checkDependencies(s);
}
else {
return Promise.resolve(0);
}
}
else {
return Promise.resolve(0);
}
})
.then((s) => {
if (s !== 0) {
spinner.succeed('检查工作区依赖成功');
return template(path.join(TEMPLATE_PATH, 'workspace_package.mtl'), {
name: destination.workspace,
author: '',
projectRepository: '',
packages: s,
}, path.join(workspacePath, 'package.json'));
}
else {
return Promise.resolve(1);
}
})
.then((s) => {
if (s === 0) {
spinner.succeed('工作区依赖检查成功');
}
spinner.succeed('添加开发工具成功');
spinner.succeed('初始化项目成功,请先按以下步骤执行,再进行项目开发:');
spinner.stop();
const steps = [
` 1. 进入目录:${projectPath}: cd ${name}\r\n`,
` 2. 编辑 ${name} -- > package.json 中 repository 和 author 字段以自动填充工作区初始化\r\n`,
' 3. 如果需要 LICENSE 文件的话请在项目根目录下放置一份,这样后续构建工作区的时候会自动拷贝到每一个工作区\r\n',
` 4. 安装依赖:${destination.tool === 'npm' ? 'npm' : 'yarn'} install\r\n`,
];
let i = 5;
if (!utils.isBlank(destination.workspace)) {
steps.push(` ${i}. 完善 ${destination.workspace} --> package.json 文件\r\n`);
i++;
}
if (destination.tool === 'yarn') {
steps.push(` ${i}. 添加开发工具支持:yarn dlx @yarnpkg/pnpify --sdk vscode\r\n`);
i++;
}
console.log(colors.green(steps.join('')));
})
.catch((err) => {
console.log(err);
spinner.fail('依赖安装失败');
spinner.stop();
});
});
});
/** 测试文件或目录是否存在 */
function accessTs(p) {
return new Promise((resolve) => {
fs.access(p, fs.constants.F_OK, (err) => {
if (err) {
resolve(false);
}
else {
resolve(true);
}
});
});
}
// 定义构建工作区的命令
program
.command('workspace <name>')
.alias('ws')
.description('构建 monorepo 项目的工作区')
.option('-n, --node', '是否是NodeJs(Commonjs)项目,而非 WEB(ES Module),默认为:true', true)
.option('--no-node', '不是nodejs项目')
.option('-d, --director <director>', '项目的目录地址,默认为:执行命令的目录')
.action((name, config) => {
const proPath = config.director || process.cwd();
const workspacePath = path.join(proPath, 'packages', name);
const spinner = new Spinner();
fsp
.mkdir(workspacePath)
.then(() => {
spinner.start('构建工作区文件');
// 检查项目根目录是否存在 tsconfig_base.json 和 读取根目录 package.json
return accessTs(path.join(proPath, 'tsconfig_base.json'));
})
.then((val) => {
return initWorkspace({
name,
proPath: proPath,
path: workspacePath,
isTs: val,
isNode: config.node,
});
})
.then((s) => {
spinner.succeed('构建工作区文件成功');
spinner.start('检查工作区依赖');
return Promise.all([checkDependencies(s), fileUtils.readJSON(path.join(proPath, 'package.json'))]);
})
.then((vals) => {
let projectRepository = '';
if (vals[1].repository != null) {
const url = new url_1.URL(vals[1].repository.url);
const urlAddr = path.parse(url.pathname);
projectRepository = `${url.host}${urlAddr.dir}/${urlAddr.name}`;
}
return Promise.all([
accessTs(path.join(proPath, '.yarnrc.yml')),
template(path.join(TEMPLATE_PATH, 'workspace_package.mtl'), {
name,
author: vals[1].author,
projectRepository,
packages: vals[0],
}, path.join(workspacePath, 'package.json')),
]);
})
.then((vals) => {
spinner.succeed('工作区依赖检查成功');
spinner.stop();
const steps = [
` 1. 安装依赖:${vals[0] ? 'yarn workspace' : 'npm -w'} ${name} install\r\n`,
` 2. 完善 packages/${name} --> package.json 文件\r\n`,
];
console.log(colors.green(steps.join('')));
spinner.stop();
})
.catch(() => {
console.error(colors.red('错误的项目目录地址'));
spinner.stop();
});
});
/**
* 初始化样式文件
* @param proPath
* @param config
* @param devs
* @returns
*/
function initStyle(proPath, config, devs) {
return new Promise((resolve) => {
spinner.start('初始化样式文件');
if (config.ts === true) {
// 使用 ts
eslintIgnore.push('/**/*.js');
gitignore.push('/**/*.js');
eslintConfig.extends.push('alloy/typescript');
eslintConfig.rules['@typescript-eslint/no-require-imports'] = 'off';
devs.push('@typescript-eslint/eslint-plugin @typescript-eslint/parser');
}
else {
eslintConfig.parser = 'espree';
}
if (config.prettier === true) {
devs.push('prettier');
// 需要 prettier
fs.copyFile(path.join(TEMPLATE_PATH, '.prettierrc.js'), path.join(proPath, '.prettierrc.js'), () => { });
fileUtils.write(path.join(proPath, '.prettierignore'), eslintIgnore.join('\r\n'));
}
// 需要 eslint
fileUtils.write(path.join(proPath, '.eslintignore'), eslintIgnore.join('\r\n'));
fileUtils.write(path.join(proPath, '.eslintrc.js'), 'module.exports = ' + JSON.stringify(eslintConfig, null, 2));
spinner.succeed('样式文件初始化成功');
resolve(0);
});
}
program
.command('js-style')
.description('为工程添加样式')
.option('-p, --prettier', '是否需要 prettier 格式化代码,默认为:true', true)
.option('--no-prettier', '不需要 prettier 格式化代码')
.option('-d, --director <director>', '项目的目录地址,默认为:执行命令的目录')
.addOption(new commander.Option('-t, --tool <package-tool>', '包管理工具')
.default('berry', '默认使用 yarn v2 版本 berry 作为包管理工具')
.choices(['berry', 'npm']))
.action((config) => {
const proPath = config.director || process.cwd();
const devs = ['eslint', 'eslint eslint-config-alloy'];
fsp
.access(path.join(proPath, 'package.json'), fs.constants.F_OK)
.then(() => accessTs(path.join(proPath, 'tsconfig_base.json')))
.then((isTs) => {
config.ts = isTs;
return initStyle(proPath, config, devs);
})
.then(() => {
spinner.start('安装依赖');
let cmd = '';
if (config.tool === 'npm') {
cmd = `npm install ${devs.join(' ')} --save-dev`;
}
else {
cmd = `yarn add ${devs.join(' ')} --dev`;
}
return serverUtils.execPromise(cmd, { cwd: proPath, errorName: 'InstallDependsError' });
})
.then(() => {
spinner.succeed('依赖安装成功');
spinner.start('添加开发工具支持');
if (config.tool === 'berry') {
return serverUtils.execPromise('yarn dlx @yarnpkg/pnpify --sdk vscode', {
cwd: proPath,
errorName: 'EditorSetupError',
});
}
else {
return Promise.resolve(0);
}
})
.then(() => {
spinner.succeed('添加开发工具支持成功');
console.log(colors.green('\r\n添加 eslint 成功 \r\n'));
})
.catch(() => {
spinner.fail('添加 eslint 失败');
});
});
function isWorkspace(proPath) {
return new Promise((resolve) => {
fileUtils
.readJSON(path.join(proPath, 'package.json'))
.then((proPkgInfo) => {
if (proPkgInfo.private === true && proPkgInfo.workspaces != null) {
let projectRepository = '';
if (proPkgInfo.repository != null) {
const url = new url_1.URL(proPkgInfo.repository.url);
const urlAddr = path.parse(url.pathname);
projectRepository = `${url.host}${urlAddr.dir}/${urlAddr.name}`;
}
resolve({ ws: 1, repository: projectRepository, author: proPkgInfo.author });
}
else {
resolve({ ws: 0 });
}
})
.catch(() => {
resolve({ ws: -1 });
});
});
}
/**
* 初始化 fastify app 项目
*/
function initFastify(config, deps) {
return new Promise((resolve) => {
spinner.start('初始化 fastify app 项目');
// 新建存放路径文件的文件夹
fs.mkdir(path.join(config.path, 'routes'), () => { });
// 新建单元测试文件夹
fs.mkdir(path.join(config.path, 'test', 'routes'), { recursive: true }, () => { });
if (config.mongo) {
deps.push('mongoose');
deps.push('fastify-mongoose-next');
fs.mkdir(path.join(config.path, 'models'), () => { });
}
if (config.static) {
// 需要处理静态资源文件, 新建 public 文件夹
fs.mkdir(path.join(config.path, 'public'), () => { });
deps.push('fastify-static');
}
if (config.view) {
// 需要模板渲染引擎, 新建 views 文件夹
fs.mkdir(path.join(config.path, 'views'), () => { });
deps.push('nunjucks');
deps.push('point-of-view');
}
if (config.mysql) {
deps.push('mysql2');
deps.push('fastify-knex-sql');
}
if (config.session) {
deps.push('fastify-cookie');
deps.push('fastify-auth-verify');
deps.push('fastify-pithy-session');
}
// 构建 config.js 和 config_demo.js
fileUtils.write(path.join(config.path, 'config.js'), `module.exports = {\r\n port: 3000,\r\n mysql: '${config.mysqlConn}',\r\n mongo: '${config.mongoConn}'\r\n};`);
fileUtils.write(path.join(config.path, 'config_demo.js'), `module.exports = {\r\n port: 3000,\r\n mysql: '${config.demoMysqlConn}',\r\n mongo: '${config.demoMongoConn}'\r\n};`);
// 重新替换 .gitignore
fs.readFile(path.join(config.path, '.gitignore'), 'utf-8', (err, gitignoreContent) => {
if (err == null) {
gitignoreContent += '\r\n.yarn\r\n.pnp.js\r\n.yarnrc.yml\r\nconfig.js';
fileUtils.write(path.join(config.path, '.gitignore'), gitignoreContent);
}
});
// 复制开发工具配置文件
fs.copyFile(path.join(TEMPLATE_PATH, 'nodemon.json'), path.join(config.path, 'nodemon.json'), () => { });
// 写 server.js 内容
template(path.join(TEMPLATE_PATH, 'fastify_server.txt'), {
mysql: config.mysql,
mongo: config.mongo,
session: config.session,
static: config.static,
view: config.view,
}, path.join(config.path, 'server.js'));
// 新建路由文件夹
setTimeout(() => {
fs.copyFile(path.join(TEMPLATE_PATH, 'api.js'), path.join(config.path, 'routes/api.js'), () => { });
fs.copyFile(path.join(TEMPLATE_PATH, 'root.js'), path.join(config.path, 'routes/root.js'), () => { });
// 复制单元测试所需文件
fs.copyFile(path.join(TEMPLATE_PATH, '.mocharc.js'), path.join(config.path, '.mocharc.js'), () => { });
fs.copyFile(path.join(TEMPLATE_PATH, 'helper.js'), path.join(config.path, 'test/helper.js'), () => { });
fs.copyFile(path.join(TEMPLATE_PATH, 'api.test.js'), path.join(config.path, 'test/routes/api.test.js'), () => { });
if (config.mongo) {
fs.copyFile(path.join(TEMPLATE_PATH, 'mongo_models.js'), path.join(config.path, 'models/index.js'), () => { });
}
}, 200);
spinner.succeed('初始化fastify app 项目成功');
resolve(0);
});
}
program
.command('fastify <name>')
.alias('f')
.description('创建 fastify 项目')
.option('-e, --eslint', '是否需要 eslint ,默认为:true', true)
.option('--no-eslint', '不需要 eslint ')
.option('-p, --prettier', '是否需要 prettier 进行格式化,默认为:true', true)
.option('--no-prettier', '不需要prettier')
.option('-d, --director <director>', '项目的目录地址,默认为:执行命令的目录')
.action((name, config) => {
let asw1;
let mysqlConfig; // mysql 连接选项
let mongoConfig; // mongo 连接选项
let proPath = config.director || process.cwd();
let devs = ['mocha', 'pino-smart', 'nodemon'];
let deps = ['fastify'];
let isApp = true;
let workspaceInfo;
enquirer
.prompt([
{
message: '是否需要处理静态文件?',
type: 'confirm',
initial: false,
name: 'static',
},
{
name: 'view',
type: 'confirm',
initial: false,
message: '是否需要模板渲染引擎?',
},
{
name: 'mongo',
type: 'confirm',
initial: false,
message: '是否需要使用 mongoose 数据库?',
},
{
name: 'mysql',
type: 'confirm',
initial: false,
message: '是否需要使用 mysql 数据库?',
},
{
name: 'session',
type: 'confirm',
initial: false,
message: '是否需要 session 并加入登录校验?',
},
])
.then((a) => {
asw1 = a;
if (a.mysql) {
return enquirer.prompt([
{
header: '-----------------------',
name: 'host',
type: 'input',
message: '请输入mysql数据库host:',
},
{
name: 'user',
type: 'input',
message: '请输入mysql数据库user:',
},
{
name: 'password',
type: 'input',
message: '请输入mysql数据库password:',
},
{
name: 'database',
type: 'input',
message: '请输入mysql数据库database:',
},
]);
}
else {
return Promise.resolve(0);
}
})
.then((a2) => {
if (a2 !== 0) {
mysqlConfig = a2;
}
if (asw1.mongo) {
return enquirer.prompt([
{
header: '-----------------------',
name: 'host',
type: 'input',
message: '请输入mongodb数据库host:',
},
{
name: 'user',
type: 'input',
message: '请输入mongodb数据库user:',
},
{
name: 'password',
type: 'input',
message: '请输入mongodb数据库password:',
},
{
name: 'database',
type: 'input',
message: '请输入mongodb数据库database:',
},
]);
}
else {
return Promise.resolve(0);
}
})
.then((a2) => {
if (a2 !== 0) {
mongoConfig = a2;
}
return isWorkspace(proPath); // 验证是否是 workspace 项目
})
.then((wsInfo) => {
workspaceInfo = wsInfo;
if (wsInfo.ws === 0) {
console.log(colors.red('目录错误!'));
return Promise.reject(new Error('director error'));
}
else if (wsInfo.ws === -1) {
// 非 workspace 项目,新建独立的工程
proPath = path.join(proPath, name);
fs.mkdir(proPath, () => { });
return initProject(proPath, {
ts: false,
license: false,
node: true,
eslint: config.eslint,
prettier: config.prettier,
tool: '',
});
}
else {
// workspace 项目
isApp = false;
// workspace
proPath = path.join(proPath, 'packages', name);
fs.mkdir(proPath, () => { });
return Promise.resolve(0);
}
})
.then(() => initFastify({
...asw1,
path: proPath,
mysqlConn: asw1.mysql
? `mysql://${mysqlConfig.user}:${mysqlConfig.password}@${mysqlConfig.host}:3306/${mysqlConfig.database}`
: '',
demoMysqlConn: asw1.mysql
? `mysql://${mysqlConfig.user}:${mysqlConfig.password}@127.0.0.1:3306/${mysqlConfig.database}`
: '',
mongoConn: asw1.mongo
? ` mongodb://${mongoConfig.user}:${mongoConfig.password}@${mongoConfig.host}:27017/${mongoConfig.database}`
: '',
demoMongoConn: asw1.mongo
? `mongodb://${mongoConfig.user}:${mongoConfig.password}@127.0.0.1:27017/${mongoConfig.database}`
: '',
name,
app: isApp,
}, deps))
.then(() => {
spinner.start('检查依赖……');
return Promise.all([checkDependencies(deps), checkDependencies(devs)]);
})
.then((a) => {
return template(path.join(TEMPLATE_PATH, isApp ? 'project_package.mtl' : 'workspace_package.mtl'), {
name,
projectRepository: workspaceInfo.repository,
author: workspaceInfo.author,
packages: a[1],
deps: a[0],
scripts: [
{
script: '"test": "mocha"',
start: true,
},
{
script: '"dev": "nodemon server.js"',
start: false,
},
],
}, path.join(proPath, 'package.json'));
})
.then(() => {
spinner.succeed('依赖检查成功');
spinner.stop();
console.log(colors.green('\r\n项目构建成功, 请按照以下步骤以次执行:\r\n'));
const steps = [];
if (isApp) {
steps.push(` 1. 编辑 ${name} -- > package.json 中 repository 和 author 字段以自动填充工作区初始化`);
steps.push(' 2. 如果需要 LICENSE 文件的话请在项目根目录下放置一份,这样后续构建工作区的时候会自动拷贝到每一个工作区');
}
else {
steps.push(` 1. 完善 packages/${name} --> package.json 文件`);
steps.push(` 2. 安装项目依赖`);
}
console.log(colors.green(steps.join('\r\n')));
})
.catch(() => {
spinner.fail('构建失败');
});
});
program.parse(process.argv);