-
Notifications
You must be signed in to change notification settings - Fork 116
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
337 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
interface configMap { | ||
[key: string]: { | ||
files: string[]; | ||
npm: string[]; | ||
}; | ||
} | ||
|
||
// todo: 与 select 存在字段耦合,后续考虑抽象出来 | ||
// todo: 部分映射需要补充 | ||
const template: configMap = { | ||
"common-lib": { | ||
files: [], | ||
npm: [], | ||
}, | ||
vue: { | ||
files: [], | ||
npm: ["vue"], | ||
}, | ||
react: { | ||
files: [], | ||
npm: ["react", "react-dom", "@types/react", "@types/react-dom"], | ||
}, | ||
}; | ||
|
||
const buildTool: configMap = { | ||
webpack: { | ||
files: [], | ||
npm: ["webpack"], | ||
}, | ||
vite: { | ||
files: [], | ||
npm: ["vite"], | ||
}, | ||
rollup: { | ||
files: [], | ||
npm: ["rollup"], | ||
}, | ||
}; | ||
const plugins: configMap = { | ||
Babel: { | ||
files: [], | ||
npm: ["@babel/core", "@babel/preset-env", "babel-loader"], | ||
}, | ||
TypeScript: { | ||
files: [], | ||
npm: ["typescript", "@types/node", "ts-loader"], | ||
}, | ||
Eslint: { | ||
files: [], | ||
npm: [], | ||
}, | ||
Prettier: { | ||
files: [], | ||
npm: [], | ||
}, | ||
}; | ||
|
||
const mapForPreset = { template, buildTool, plugins }; | ||
|
||
export { mapForPreset }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import { resolveApp } from "@laconic/utils"; | ||
import fs from "fs-extra"; | ||
import { execSync, exec } from "child_process"; | ||
import { confirm } from "@clack/prompts"; | ||
import chalk from "chalk"; | ||
|
||
import { removeDirectory } from "./fileController"; | ||
import { projectSelect } from "./select"; | ||
import isGitInstalled from "./checkGitInstallation"; | ||
// import { createPackageJson } from "./createFile"; | ||
import { createFiles } from "./createFiles"; | ||
import { type Preset, getFilesForProject, getNpmForPackage } from "./preset"; | ||
import createSuccessInfo from "./createSuccessInfo"; | ||
|
||
// 设置输入模式为原始模式 | ||
process.stdin.setRawMode(true); | ||
|
||
// 监听键盘输入,避免选择阶段需要多次 Ctrl+C 退出 | ||
process.stdin.on("data", (key) => { | ||
// 检测到 Ctrl+C | ||
if (key[0] === 3) { | ||
console.log("⌨️ Ctrl+C pressed - Exiting the program"); | ||
process.exit(1); | ||
} | ||
}); | ||
|
||
// 模板创建主函数 | ||
export default async function createAppTest(projectName: string, options) { | ||
const rootDirectory = resolveApp(projectName); | ||
|
||
// 创建项目文件夹 | ||
if (fs.existsSync(rootDirectory) && !options.force) { | ||
const shouldContinue = await confirm({ | ||
message: | ||
"Whether to overwrite a file with the same name that exists in the current directory ?", | ||
}); | ||
|
||
// 删除已存在文件并创建新文件 | ||
if (shouldContinue === true) { | ||
removeDirectory(projectName, true); | ||
} else process.exit(1); | ||
|
||
execSync(`mkdir ${rootDirectory}`); | ||
} | ||
|
||
// 获取用户选择预设 | ||
const preset: Preset = await projectSelect(); | ||
|
||
console.log(rootDirectory); | ||
// 创建package.json | ||
await createFiles(rootDirectory, { | ||
"package.json": "{}", // todo:具体内容待重构 | ||
}); | ||
|
||
// 拉取模板 | ||
// todo: 新模板未开发,先模拟过程 | ||
console.log("Creating a project..."); | ||
|
||
// 初始化 Git 仓库 | ||
if (isGitInstalled()) exec("git init", { cwd: rootDirectory }); | ||
|
||
// todo: 插件未开发,先模拟过程 | ||
|
||
// 安装插件至 package.json | ||
Object.keys(preset.plugins).forEach(async (plugin) => { | ||
console.log(plugin, "installed"); | ||
// 进入仓库 | ||
// await execSync(`npm install ${plugin}`) | ||
}); | ||
|
||
// 运行生成器创建项目所需文件和结构 | ||
console.log(chalk.blue(`🚀 Invoking generators...`)); | ||
const fileList = getFilesForProject(preset); | ||
console.log("fileList", fileList); | ||
fileList.forEach(async (file) => { | ||
await createFiles(rootDirectory, { | ||
[file]: "", // todo: 写入的内容还待设计,考虑修改 configMap 的 files 为对象 | ||
}); | ||
}); | ||
|
||
// 安装附加依赖 | ||
// todo: npm 安装逻辑需要等待设置包管理工具,目前默认 npm,后续优化 | ||
// todo: configMap 的 npm 也需要改为对象,传入包依赖模式(-S,-D) | ||
const npmList = getNpmForPackage(preset); | ||
console.log("npmList", npmList); | ||
|
||
// 其他剩余操作,如创建 md 文档,或其他首位操作 | ||
console.log("📄 Generating README.md..."); | ||
await createFiles(rootDirectory, { | ||
"README.md": "", | ||
}); | ||
|
||
createSuccessInfo(projectName, "npm"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import fs from "fs-extra"; | ||
import path from "path"; | ||
|
||
/** | ||
* @description 生成一系列指定的文件 | ||
* @param dir 生成目录 | ||
* @param files 文件名 | ||
* @example await createFiles(dir, {'.tsconfig': tsConfig }) | ||
*/ | ||
|
||
async function createFiles(dir, files) { | ||
Object.keys(files).forEach((name) => { | ||
const filePath = path.join(dir, name); | ||
fs.ensureDirSync(path.dirname(filePath)); | ||
fs.writeFileSync(filePath, files[name]); | ||
}); | ||
} | ||
|
||
export { createFiles }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import { mapForPreset } from "./configMap"; | ||
|
||
interface Preset { | ||
template: string; | ||
buildTool: string; | ||
plugins: Record<string, any>; | ||
} | ||
|
||
/** | ||
* @description 处理用户预设 | ||
* @param template 模板 | ||
* @param buildTool 构建工具 | ||
* @param plugins 插件列表 | ||
* @return 用户预设 | ||
*/ | ||
// todo: 目前没有使用到 defaultPreset,后续考虑加入默认配置 | ||
const getPreset = (template: string, buildTool: string, plugins: string[]): Preset => { | ||
const preset: Preset = { | ||
template, | ||
buildTool, | ||
plugins: {}, | ||
}; | ||
|
||
// todo: 插件配置目前设置为空,且没有使用情况,后续优化 | ||
plugins.forEach((plugin) => { | ||
preset.plugins[plugin] = {}; | ||
}); | ||
|
||
return preset; | ||
}; | ||
|
||
const defaultPreset: Preset = { | ||
template: "common-lib", | ||
buildTool: "webpack", | ||
plugins: { | ||
eslint: {}, | ||
}, | ||
// todo: 更多配置随构建需要添加 | ||
}; | ||
|
||
const { template, buildTool, plugins } = mapForPreset; | ||
|
||
/** | ||
* @description 根据配置映射生成预设相关的文件 | ||
* @param preset 用户预设 | ||
*/ | ||
const getFilesForProject = (preset: Preset) => { | ||
let fileList = [...template[preset.template].files, ...buildTool[preset.buildTool].files]; | ||
|
||
// 独立处理 plugins | ||
Object.keys(preset.plugins).forEach((item) => { | ||
fileList = [...fileList, ...plugins[item].files]; | ||
}); | ||
|
||
return fileList; | ||
}; | ||
|
||
/** | ||
* @description 根据配置映射生成预设相关的依赖 | ||
* @param preset 用户预设 | ||
*/ | ||
const getNpmForPackage = (preset: Preset) => { | ||
let npmList = [...template[preset.template].npm, ...buildTool[preset.buildTool].npm]; | ||
|
||
// 独立处理 plugins | ||
Object.keys(preset.plugins).forEach((item) => { | ||
npmList = [...npmList, ...plugins[item].npm]; | ||
}); | ||
|
||
return npmList; | ||
}; | ||
|
||
export { Preset, getPreset, defaultPreset, getFilesForProject, getNpmForPackage }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import { multiselect, select, intro } from "@clack/prompts"; | ||
import chalk from "chalk"; | ||
|
||
import { getPreset } from "./preset"; | ||
|
||
interface Responses { | ||
template: string; | ||
buildTool: string; | ||
plugins: string[]; | ||
} | ||
|
||
/** | ||
* @description 终端交互,获取用户的项目预设 | ||
* @returns 返回用户的项目预设 Responses | ||
*/ | ||
async function projectSelect() { | ||
const responses: Responses = { | ||
template: "", | ||
buildTool: "", | ||
plugins: [], | ||
}; | ||
|
||
intro(chalk.green(" create-you-app ")); | ||
|
||
// 选择模板预设 | ||
responses.template = (await select({ | ||
message: "Pick a template please", | ||
options: [ | ||
{ value: "common-lib", label: "common-lib" }, | ||
{ value: "vue", label: "vue" }, | ||
{ value: "react", label: "react" }, | ||
], | ||
})) as string; | ||
|
||
// 选择构建工具 | ||
responses.buildTool = (await select({ | ||
message: "Pick a build tools for your project", | ||
options: [ | ||
{ value: "webpack", label: "webpack" }, | ||
{ value: "vite", label: "vite" }, | ||
{ value: "rollup", label: "rollup" }, | ||
], | ||
})) as string; | ||
|
||
// 选择插件 | ||
responses.plugins = (await multiselect({ | ||
message: `Pick plugins for your project.(${chalk.greenBright( | ||
"<space>", | ||
)} select, ${chalk.greenBright("<a>")} toggle all, ${chalk.greenBright( | ||
"<i>", | ||
)} invert selection,${chalk.greenBright("<enter>")} next step)`, | ||
options: [ | ||
{ value: "Babel", label: "Babel" }, | ||
{ value: "TypeScript", label: "TypeScript" }, | ||
{ value: "Eslint", label: "Eslint" }, | ||
{ value: "Prettier", label: "Prettier" }, | ||
], | ||
required: false, | ||
})) as string[]; | ||
|
||
return getPreset(responses.template, responses.buildTool, responses.plugins); | ||
} | ||
|
||
export { projectSelect }; |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.