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-rsbuild): allow to create via CLI options #2903

Merged
merged 2 commits into from
Jul 13, 2024
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
2 changes: 2 additions & 0 deletions packages/create-rsbuild/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@
},
"devDependencies": {
"@clack/prompts": "^0.7.0",
"@types/minimist": "^1.2.5",
"@types/node": "18.x",
"deepmerge": "^4.3.1",
"minimist": "^1.2.8",
"rslog": "^1.2.2",
"typescript": "^5.5.2"
},
Expand Down
154 changes: 112 additions & 42 deletions packages/create-rsbuild/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
text,
} from '@clack/prompts';
import deepmerge from 'deepmerge';
import minimist from 'minimist';
import { logger } from 'rslog';

function cancelAndExit() {
Expand Down Expand Up @@ -67,49 +68,47 @@ function isEmptyDir(path: string) {
return files.length === 0 || (files.length === 1 && files[0] === '.git');
}

export async function main() {
console.log('');
logger.greet('◆ Create Rsbuild Project');

const cwd = process.cwd();
const pkgInfo = pkgFromUserAgent(process.env.npm_config_user_agent);
const pkgManager = pkgInfo ? pkgInfo.name : 'npm';
const packageRoot = path.resolve(__dirname, '..');
const packageJsonPath = path.join(packageRoot, 'package.json');
const { version } = require(packageJsonPath);

const projectName = checkCancel<string>(
await text({
message: 'Project name or path',
placeholder: 'rsbuild-project',
defaultValue: 'rsbuild-project',
validate(value) {
if (value.length === 0) {
return 'Project name is required';
}
},
}),
);

const { targetDir, packageName } = formatProjectName(projectName);
const distFolder = path.isAbsolute(targetDir)
? targetDir
: path.join(cwd, targetDir);
type Argv = {
help?: boolean;
dir?: string;
template?: string;
override?: boolean;
tools?: string | string[];
};

if (fs.existsSync(distFolder) && !isEmptyDir(distFolder)) {
const option = checkCancel<string>(
await select({
message: `"${targetDir}" is not empty, please choose:`,
options: [
{ value: 'yes', label: 'Continue and override files' },
{ value: 'no', label: 'Cancel operation' },
],
}),
);
function logHelpMessage() {
logger.log(`
Usage: create-rsbuild [options]

Options:

-h, --help display help for command
-d, --dir create project in specified directory
-t, --template specify the template to use
--tools select additional tools (biome, eslint, prettier)
--override override files in target directory

Templates:

react react-ts
vue3 vue3-ts
vue2 vue2-ts
lit lit-ts
preact preact-ts
svelte svelte-ts
solid solid-ts
vanilla vanilla-ts
`);
}

if (option === 'no') {
cancelAndExit();
}
async function getTemplate({ template }: Argv) {
if (template) {
const pair = template.split('-');
const language = pair[1] ?? 'js';
return {
framework: pair[0],
language,
};
}

const framework = checkCancel<string>(
Expand Down Expand Up @@ -138,7 +137,18 @@ export async function main() {
}),
);

const tools = checkCancel<string[]>(
return {
framework,
language,
};
}

async function getTools({ tools }: Argv) {
if (tools) {
return Array.isArray(tools) ? tools : [tools];
}

return checkCancel<string[]>(
await multiselect({
message: 'Select additional tools (press enter to continue)',
options: [
Expand All @@ -149,6 +159,66 @@ export async function main() {
required: false,
}),
);
}

export async function main() {
const argv = minimist<Argv>(process.argv.slice(2), {
alias: { h: 'help', d: 'dir', t: 'template' },
});

console.log('');
logger.greet('◆ Create Rsbuild Project');

if (argv.help) {
logHelpMessage();
return;
}

const cwd = process.cwd();
const pkgInfo = pkgFromUserAgent(process.env.npm_config_user_agent);
const pkgManager = pkgInfo ? pkgInfo.name : 'npm';
const packageRoot = path.resolve(__dirname, '..');
const packageJsonPath = path.join(packageRoot, 'package.json');
const { version } = require(packageJsonPath);

const projectName =
argv.dir ??
checkCancel<string>(
await text({
message: 'Project name or path',
placeholder: 'rsbuild-project',
defaultValue: 'rsbuild-project',
validate(value) {
if (value.length === 0) {
return 'Project name is required';
}
},
}),
);

const { targetDir, packageName } = formatProjectName(projectName);
const distFolder = path.isAbsolute(targetDir)
? targetDir
: path.join(cwd, targetDir);

if (!argv.override && fs.existsSync(distFolder) && !isEmptyDir(distFolder)) {
const option = checkCancel<string>(
await select({
message: `"${targetDir}" is not empty, please choose:`,
options: [
{ value: 'yes', label: 'Continue and override files' },
{ value: 'no', label: 'Cancel operation' },
],
}),
);

if (option === 'no') {
cancelAndExit();
}
}

const { framework, language } = await getTemplate(argv);
const tools = await getTools(argv);

const srcFolder = path.join(packageRoot, `template-${framework}-${language}`);
const commonFolder = path.join(packageRoot, 'template-common');
Expand Down
11 changes: 11 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading