Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(create-mako): refactor create-mako #1751

Merged
merged 1 commit into from
Jan 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"build": "pnpm --filter @umijs/mako build && pnpm --filter @umijs/mako src:build && pnpm biome:format",
"build:debug": "pnpm --filter @umijs/mako build:debug && pnpm --filter @umijs/mako src:build && pnpm biome:format",
"build:profile": "pnpm --filter @umijs/mako build:profile && pnpm --filter @umijs/mako src:build && pnpm biome:format",
"build:create-mako": "pnpm --filter create-mako build",
"build:client": "pnpm --filter client build",
"biome:check": "biome check .",
"biome:format": "biome check --write .",
Expand All @@ -17,7 +18,7 @@
"release:mako": "pnpm --filter @umijs/mako release",
"release:bundler-mako": "esno scripts/release-bundler-mako.ts",
"release:rsc": "esno scripts/release-rsc.ts",
"release:create-mako": "esno scripts/release-create-mako.ts"
"release:create-mako": "pnpm --filter create-mako release"
},
"license": "MIT",
"devDependencies": {
Expand Down
1 change: 1 addition & 0 deletions packages/create-mako/bin/create-mako.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
#!/usr/bin/env node

require('../dist/cli');
19 changes: 9 additions & 10 deletions packages/create-mako/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,15 @@
"create-mako": "./bin/create-mako.js"
},
"license": "MIT",
"dependencies": {
"glob": "^10.3.15",
"inquirer": "^9.3.1",
"yargs-parser": "^21.1.1"
},
"devDependencies": {
"@types/inquirer": "^9.0.7",
"@types/node": "^20.12.5",
"@types/yargs-parser": "^21.0.3",
"typescript": "^5.4.3"
"@umijs/clack-prompt": "^0.0.3",
"@umijs/tools": "^0.1.3",
"gradient-string": "^3.0.0",
"picocolors": "^1.1.1",
"tsx": "^4.19.2",
"typescript": "^5.6.3",
"yargs-parser": "^21.1.1"
Comment on lines +10 to +16
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

将运行时依赖从 devDependencies 移动到 dependencies

在代码中使用的包(如 @umijs/clack-promptgradient-stringpicocolorsyargs-parser)是运行时依赖,应放在 dependencies 中。如果它们仅存在于 devDependencies,当用户安装该包时,这些依赖不会被安装,导致运行时错误。

修复如下:

  "devDependencies": {
-   "@umijs/clack-prompt": "^0.0.3",
-   "@umijs/tools": "^0.1.3",
-   "gradient-string": "^3.0.0",
-   "picocolors": "^1.1.1",
    "tsx": "^4.19.2",
    "typescript": "^5.6.3",
-   "yargs-parser": "^21.1.1"
  },
+ "dependencies": {
+   "@umijs/clack-prompt": "^0.0.3",
+   "gradient-string": "^3.0.0",
+   "picocolors": "^1.1.1",
+   "yargs-parser": "^21.1.1"
+ },

Committable suggestion skipped: line range outside the PR's diff.

},
"engines": {
"node": ">= 16"
Expand All @@ -26,8 +25,8 @@
],
"scripts": {
"format": "biome check --write .",
"dev": "father dev",
"build": "father build"
"build": "utools bundle --patch-dirname",
"release": "utools release"
Comment on lines +28 to +29
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

缺少 utools 作为开发依赖

scripts 中使用了 utools,但未在 devDependencies 中声明,可能导致构建或发布过程中的错误。

建议在 devDependencies 中添加 utools

  "devDependencies": {
    "tsx": "^4.19.2",
    "typescript": "^5.6.3",
+   "utools": "^适当的版本号"
  },

请根据项目要求填写 utools 的正确版本号。

Committable suggestion skipped: line range outside the PR's diff.

},
"repository": "[email protected]:umijs/mako.git"
}
169 changes: 56 additions & 113 deletions packages/create-mako/src/cli.ts
Original file line number Diff line number Diff line change
@@ -1,130 +1,73 @@
import fs from 'fs';
import path, { resolve } from 'path';
import { globSync } from 'glob';
import type { QuestionCollection } from 'inquirer';
import yargs from 'yargs-parser';
import path from 'path';
import * as p from '@umijs/clack-prompt';
import { instagram } from 'gradient-string';
import yargsParser from 'yargs-parser';
import { create } from './create';

const args = yargs(process.argv.slice(2));
const baseTemplatesPath = path.join(__dirname, '../templates');
async function run(cwd: string) {
const argv = yargsParser(process.argv.slice(2), {
alias: {
version: ['v'],
help: ['h'],
template: ['t'],
},
boolean: ['version', 'help'],
});
Comment on lines +9 to +16
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

缺少对 --npm-client 参数的解析

当前的 yargsParser 配置中,没有解析 --npm-client-n 参数,导致 argv.packageManager 始终为 undefined,无法正确传递给 create 函数。

建议在 alias 中添加对 packageManager 参数的映射,修复如下:

  const argv = yargsParser(process.argv.slice(2), {
    alias: {
      version: ['v'],
      help: ['h'],
      template: ['t'],
+     packageManager: ['npm-client', 'n'],
    },
    boolean: ['version', 'help'],
  });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const argv = yargsParser(process.argv.slice(2), {
alias: {
version: ['v'],
help: ['h'],
template: ['t'],
},
boolean: ['version', 'help'],
});
const argv = yargsParser(process.argv.slice(2), {
alias: {
version: ['v'],
help: ['h'],
template: ['t'],
packageManager: ['npm-client', 'n'],
},
boolean: ['version', 'help'],
});


type InitOptions = {
projectName: string;
template: string;
};
console.log(
instagram(`
███╗ ███╗ █████╗ ██╗ ██╗ ██████╗
████╗ ████║██╔══██╗██║ ██╔╝██╔═══██╗
██╔████╔██║███████║█████╔╝ ██║ ██║
██║╚██╔╝██║██╔══██║██╔═██╗ ██║ ██║
██║ ╚═╝ ██║██║ ██║██║ ██╗╚██████╔╝
╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝
`),
);

async function init({ projectName, template }: InitOptions) {
let templatePath = path.join(baseTemplatesPath, template);
if (!fs.existsSync(templatePath)) {
console.error(`Template "${template}" does not exist.`);
process.exit(1);
// Check if the version flag is set
if (argv.version) {
const pkgPath = path.join(__dirname, '../package.json');
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
console.log(`${pkg.name}@${pkg.version}`);
return;
}
let files = globSync('**/*', { cwd: templatePath, nodir: true });

// Use the project name entered by the user as the target folder name.
let cwd = path.resolve(process.cwd(), projectName);
// Check if the help flag is set
if (argv.help) {
console.log(`Usage: create-mako [project-name] [options]

// Ensure the target directory exists; if it does not, create it.
if (!fs.existsSync(cwd)) {
fs.mkdirSync(cwd, { recursive: true });
}

let npmClient = (() => {
let script = process.argv[1];
if (script.includes('pnpm/')) {
return 'pnpm';
} else {
return 'npm';
}
})();
Options:
--version, -v Show version number
--help, -h Show help
--template, -t Specify a template for the project
--npm-client, -n Specify the npm client to use (pnpm, yarn, npm)

// Copy files
for (let file of files) {
let source = path.join(templatePath, file);
let dest = path.join(cwd, file);
console.log(`Creating ${file}`);
let destDir = path.dirname(dest);
if (!fs.existsSync(destDir)) {
fs.mkdirSync(destDir, { recursive: true });
}
fs.copyFileSync(source, dest);
Examples:
create-mako Create a new project
create-mako myapp Create a new project named 'myapp'
create-mako myapp --template=minimal Create a new project named 'myapp' using the 'minimal' template`);
return;
}

console.log();
console.log('Done, Run following commands to start the project:');
console.log();
console.log(` cd ${path.basename(cwd)}`);
console.log(` ${npmClient} install`);
console.log(` ${npmClient} run dev`);
console.log(` # Open http://localhost:3000`);
console.log();
console.log('Happy coding!');
}

type InitQuestion = {
name: string;
template: string;
};

async function checkEmptyDir(name: string) {
const inquirer = (await import('inquirer')).default;
const cwd = process.cwd();
const exist = fs.existsSync(resolve(cwd, name));
if (exist && fs.readdirSync(resolve(cwd, name)).length > 0) {
const answersContinue = await inquirer.prompt([
{
type: 'confirm',
name: 'continue',
message:
'The current directory is not empty. Do you want to continue creating the project here?',
default: false,
},
]);

if (!answersContinue.continue) {
p.intro('Creating a new MAKO project...');
create({
cwd: cwd,
name: argv._[0] as string | undefined,
template: argv.template,
packageManager: argv.packageManager,
})
.then(() => {
p.outro('Create success!');
})
.catch((err) => {
p.cancel(`Create failed, ${err.message}`);
Comment on lines +64 to +65
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

使用 p.cancel 处理错误可能不合适

p.cancel 通常用于用户取消操作。这里在捕获错误时使用 p.cancel,可能不符合预期。建议使用 p.outrop.error 来显示错误信息。

根据 @umijs/clack-prompt 的实际 API,修改如下:

      .catch((err) => {
-       p.cancel(`Create failed, ${err.message}`);
+       p.error(`Create failed, ${err.message}`);
        process.exit(1);
      });

或:

      .catch((err) => {
-       p.cancel(`Create failed, ${err.message}`);
+       p.outro(`Create failed, ${err.message}`);
        process.exit(1);
      });

请根据 @umijs/clack-prompt 的实际方法选择合适的替代方案。

Committable suggestion skipped: line range outside the PR's diff.

process.exit(1);
}
}
}

async function main() {
const inquirer = (await import('inquirer')).default;

let name: string = args._[0] as string;
let { template } = args;
let questions: QuestionCollection[] = [];
if (!name) {
let answers = await inquirer.prompt<InitQuestion>([
{
type: 'input',
name: 'name',
message: 'Project name:',
default: 'mako-project',
},
]);
name = answers.name;
}
await checkEmptyDir(name);
if (!template) {
const templates = globSync('**/', {
cwd: baseTemplatesPath,
maxDepth: 1,
}).filter((dir) => dir !== '.');
questions.push({
type: 'list',
name: 'template',
message: 'Select a template:',
choices: templates,
default: 'react',
});
}
if (questions.length > 0) {
let answers = await inquirer.prompt<InitQuestion>(questions);
template = template || answers.template;
}
return init({ projectName: String(name), template });
}

main().catch((err) => {
run(process.cwd()).catch((err) => {
console.error(err);
process.exit(1);
});
Loading
Loading