This commit is contained in:
hufeixiong
2022-01-14 09:48:18 +08:00
parent 94175c8de7
commit 387423ce62
12 changed files with 822 additions and 26 deletions

View File

@@ -0,0 +1,107 @@
/*
* @Author: yehuozhili
* @Date: 2022-01-13 16:16:53
* @LastEditors: yehuozhili
* @LastEditTime: 2022-01-14 09:16:58
* @FilePath: \dooringx-cli\src\createPlugin.ts
*/
import chalk from 'chalk';
import fs from 'fs-extra';
import inquirer from 'inquirer';
import path from 'path';
import modifyTemplate from './modifyTemplate';
import { deleteFolder, doAction } from './utils';
export async function createPlugin(name: string, option: string) {
createApp(name, option);
}
async function createApp(projectName: string, option: string) {
let root = path.resolve(projectName);
const isExist = fs.existsSync(root);
if (isExist) {
const choices = ['y', 'n'];
let sign = 'y';
const result = await inquirer.prompt({
name: 'sign',
type: 'list',
message: `${projectName} already exists , continue ?`,
choices,
});
sign = result.sign;
if (sign === 'n') {
return;
}
}
fs.ensureDirSync(projectName); // 没有则创建文件夹
console.log(`create a new app in ${chalk.green(root)}`);
const packageJson = {
name: projectName,
version: '0.0.1',
private: true,
};
// 写入package.json
fs.writeFileSync(path.join(root, 'package.json'), JSON.stringify(packageJson, null, 2));
process.chdir(root);
// 复制项目模板,安装项目依赖等
await run(root, projectName, option);
}
async function run(root: string, projectName: string, _option: string) {
const template = 'dooringx-plugin-template';
const templateName = template;
const allDependencies = [templateName];
console.log('Installing packages. This might take a couple of minutes');
console.log(`Installing ${chalk.cyan(templateName)} ...`);
try {
await doAction(root, allDependencies);
} catch (e) {
console.log(`Installing ${chalk.red(templateName)} failed ...`, e);
}
console.log(`Installing ${chalk.cyan(templateName)} succeed!`);
const templatePath = path.dirname(
require.resolve(`${templateName}/package.json`, { paths: [root] })
);
// 复制文件到项目目录
const tempDir = path.join(root, 'temp');
const templateDir = path.join(templatePath, `template`);
if (fs.existsSync(templatePath)) {
await modifyTemplate(templateDir, 'temp', {
projectName: projectName,
basicProject: template,
});
fs.copySync(tempDir, root);
deleteFolder(tempDir);
} else {
console.error(`Could not locate supplied template: ${chalk.green(templatePath)}`);
return;
}
let tempPkg = fs.readFileSync(root + '/template.json').toString();
let pkg = fs.readFileSync(root + '/package.json').toString();
const tempPkgJson = JSON.parse(tempPkg);
let pkgJson = JSON.parse(pkg);
pkgJson = { ...pkgJson };
pkgJson.main = tempPkgJson?.main;
pkgJson.scripts = tempPkgJson?.scripts;
pkgJson.dependencies = {
...tempPkgJson?.dependencies,
};
pkgJson.devDependencies = {
...tempPkgJson?.devDependencies,
};
fs.writeFileSync(path.join(root, 'package.json'), JSON.stringify(pkgJson, null, 2));
fs.unlinkSync(path.join(root, 'template.json'));
fs.unlinkSync(path.join(root, 'package-lock.json'));
console.log(`🎉 Successfully created project ${projectName}.`);
console.log('👉 Get started with the following commands:');
console.log(`${chalk.cyan(`cd ${projectName}`)}`);
console.log(`${chalk.cyan('npm install')}`);
process.exit(0);
}

View File

@@ -0,0 +1,28 @@
/*
* @Author: yehuozhili
* @Date: 2021-06-10 20:45:06
* @LastEditors: yehuozhili
* @LastEditTime: 2022-01-13 17:07:39
* @FilePath: \dooringx-cli\src\index.ts
*/
import { Command } from 'commander';
import { createPlugin } from './createPlugin';
const packageJson = require('../package.json');
let program = new Command();
program
.command('create <project-name>')
.description('create project')
.alias('c')
.action(() => {
console.log('in progress');
});
program
.command('plugin <project-name>')
.description('create plugin project')
.alias('p')
.action((name, options) => {
createPlugin(name, options);
});
program.version(packageJson.version).parse(process.argv);

View File

@@ -0,0 +1,63 @@
import MetalSmith from 'metalsmith';
import { ejs } from 'consolidate';
import { promisify } from 'util';
import * as path from 'path';
/**
*
* @param {*} fromPath 源路径
* @param {*} toPath 目标路径
*/
async function handleTemplate(fromPath: string, toPath: string, config: any) {
await new Promise((resovle, reject) => {
MetalSmith(__dirname)
.source(fromPath)
.destination(path.join(path.resolve(), toPath))
.use(async (_files, metal, done) => {
let result = {
license: 'MIT',
version: '0.0.1',
...config,
};
const data = metal.metadata();
Object.assign(data, result);
//@ts-ignore
done();
})
.use((files, metal, done) => {
Object.keys(files).forEach(async (file) => {
let content = files[file].contents.toString();
if (
file.includes('.js') ||
file.includes('.json') ||
file.includes('.txt') ||
file.includes('.md')
) {
if (content.includes('<%')) {
let { render } = ejs;
//@ts-ignore
render = promisify(render);
try {
content = await render(content, metal.metadata());
} catch (e) {
console.log(e);
}
files[file].contents = Buffer.from(content);
}
}
});
//@ts-ignore
done();
})
.build((err) => {
if (!err) {
resovle(true);
} else {
console.log(err);
reject(false);
}
});
});
}
export default handleTemplate;

View File

@@ -0,0 +1,84 @@
/*
* @Author: yehuozhili
* @Date: 2021-06-10 20:45:06
* @LastEditors: yehuozhili
* @LastEditTime: 2022-01-14 09:15:23
* @FilePath: \dooringx-cli\src\utils.ts
*/
import spawn from 'cross-spawn';
import * as fs from 'fs-extra';
/**
* 使用npm安装或卸载项目依赖
* @param {*} root 项目路径
* @param {*} allDependencies 项目依赖
* @param {*} action npm install 或 npm uninstall
*/
export async function doAction(
root: string,
allDependencies: string | string[],
action = 'install'
) {
typeof allDependencies === 'string' ? (allDependencies = [allDependencies]) : null;
return new Promise((resolve) => {
const command = 'npm';
const args = [
action,
'--save',
'--save-exact',
'--loglevel',
'error',
...allDependencies,
'--cwd',
root,
];
const child = spawn(command, args, { stdio: 'inherit' });
child.on('close', resolve);
});
}
export async function buildAction(
root: string,
script: string,
cwd: string,
isLerna: boolean,
name: string
) {
return new Promise((resolve) => {
if (isLerna) {
const command = `lerna exec npm run `;
const args = [script, `--scope=${name}`, '--loglevel', 'error'];
const child = spawn(command, args, { stdio: 'inherit', cwd: cwd });
child.on('close', resolve);
} else {
const command = 'npm run ';
const args = [script, '--loglevel', 'error'];
const child = spawn(command, args, { stdio: 'inherit', cwd: root });
child.on('close', resolve);
}
});
}
export async function copyFolder(workPath: string, targetPath: string) {
return fs.copy(workPath, targetPath);
}
/**
* 删除文件、文件夹
* @param {*} path 要删除资源的路径
*/
export function deleteFolder(path: string) {
let files = [];
if (fs.existsSync(path)) {
if (!fs.statSync(path).isDirectory()) {
fs.unlinkSync(path);
} else {
files = fs.readdirSync(path);
files.forEach(function (file) {
let curPath = path + '/' + file;
deleteFolder(curPath);
});
fs.rmdirSync(path);
}
}
}