UNPKG

@pplancq/create-react-app

Version:
153 lines (130 loc) 5.74 kB
#!/usr/bin/env node const { execSync } = require('child_process'); const { Command } = require('commander'); const { cpSync, existsSync, readFileSync, renameSync, rmSync, writeFileSync, mkdirSync } = require('fs'); const { resolve } = require('path'); const NPM = 'npm'; const YARN = 'yarn'; const PNPM = 'pnpm'; const runCommand = (command, options = { stdio: 'inherit' }) => { try { execSync(command, options); } catch (e) { console.error(`Failed to execute ${command}`, e); process.exit(-1); } }; const getPackageManager = () => { switch (true) { case process.env.npm_config_user_agent.includes(YARN): return YARN; case process.env.npm_config_user_agent.includes(PNPM): return PNPM; default: return NPM; } }; const main = async () => { const chalk = await import('chalk').then(m => m.default); let projectName = ''; const packageJson = JSON.parse(readFileSync(resolve(__dirname, './package.json'), { encoding: 'utf-8' })); const cli = new Command(packageJson.name); cli .version(packageJson.version) .argument('<project-name>') .usage(chalk.green('<project-name>')) .action(name => { projectName = name; }) .parse(process.argv); const packageManager = getPackageManager(); if (!/^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(projectName)) { console.error(`The project name '${projectName}' is not valid.`); console.error( 'A valid npm project name must start with a lowercase letter, a number, a hyphen, or a tilde, and can include dots, hyphens, tildes, or underscores.', ); console.error( "If the project name starts with '@', it must be followed by a valid scope name and a '/'. Please check and try again.", ); process.exit(-1); } const reactTemplate = '@pplancq/react-template'; const repoDir = resolve(process.cwd(), `./${projectName}`); const templateDir = resolve(repoDir, `./node_modules/${reactTemplate}`); if (existsSync(repoDir)) { console.error(`\nThe directory ${chalk.green(projectName)} is already exist.`); console.error('Either try using a new directory name, or remove the files listed above.'); process.exit(-1); } console.info(`\nCreating a new App React in ${chalk.green(repoDir)}.`); console.info(`\nInstall react template from ${chalk.green(reactTemplate)}`); mkdirSync(repoDir); runCommand(`cd ${repoDir} && npm init -y`, { stdio: 'ignore' }); if (packageManager === YARN) { runCommand(`cd ${repoDir} && yarn config set nodeLinker node-modules`, { stdio: 'ignore' }); } runCommand(`cd ${repoDir} && ${packageManager} ${packageManager === YARN ? 'add' : 'install'} ${reactTemplate}`); cpSync(templateDir, repoDir, { recursive: true, dereference: true }); renameSync(`${repoDir}/_gitignore`, `${repoDir}/.gitignore`); const repoPackageJson = JSON.parse(readFileSync(resolve(repoDir, 'package.json'), { encoding: 'utf-8' })); repoPackageJson.name = projectName; repoPackageJson.description = projectName; const { _prepare, _postinstall, ...scripts } = repoPackageJson.scripts; repoPackageJson.scripts = { ...scripts, prepare: _prepare, postinstall: _postinstall }; repoPackageJson.version = '0.1.0'; delete repoPackageJson.author; delete repoPackageJson.repository; delete repoPackageJson.bugs; delete repoPackageJson.keywords; delete repoPackageJson.engines; writeFileSync(resolve(repoDir, 'package.json'), JSON.stringify(repoPackageJson, null, 2), { encoding: 'utf-8' }); rmSync(`${repoDir}/node_modules`, { recursive: true }); rmSync(`${repoDir}/LICENSE`); rmSync(`${repoDir}/CHANGELOG.md`); rmSync(`${repoDir}/README.md`); renameSync(`${repoDir}/_README.md`, `${repoDir}/README.md`); let readme = readFileSync(resolve(repoDir, 'README.md'), { encoding: 'utf-8' }); switch (packageManager) { case YARN: rmSync(`${repoDir}/yarn.lock`); readme = readme.replaceAll('npm install', 'yarn'); readme = readme.replaceAll('npm', 'yarn'); break; case PNPM: rmSync(`${repoDir}/pnpm-lock.yaml`); readme = readme.replaceAll('npm', 'pnpm'); break; default: rmSync(`${repoDir}/package-lock.json`); } writeFileSync(resolve(repoDir, 'README.md'), readme, { encoding: 'utf-8' }); console.info('\nInitialized a git repository.'); runCommand(`cd ${repoDir} && git init --initial-branch=main`, { stdio: 'ignore' }); console.info('\nInstalling packages. This might take a couple of minutes.'); runCommand(`cd ${repoDir} && ${packageManager} install`); if (packageManager === PNPM) { runCommand(`cd ${repoDir} && ${packageManager} install -D vite`); } console.info('\nCreated git commit.'); runCommand(`cd ${repoDir} && git add . && git commit --no-verify --message "Initial commit"`, { stdio: 'ignore', }); console.info(`\n${chalk.yellow('Success \\o/')} Created ${chalk.green(projectName)} at ${chalk.green(repoDir)}`); console.info('Inside that directory, you can run several commands:'); const logCommand = command => { console.info(`\n ${chalk.cyan(command)}`); }; logCommand(`${packageManager} start`); console.info(' Starts the development server.'); logCommand(`${packageManager} run build`); console.info(' Bundles the app into static files for production.'); logCommand(`${packageManager} test`); console.info(' Starts the test runner.'); logCommand(`${packageManager} run remove:demo`); console.info(' Remove the demo application.'); console.info('\nWe suggest that you begin by typing:'); console.info(`\n ${chalk.cyan('cd')} ${projectName}`); logCommand(`${packageManager} start`); console.info('\nHappy hacking!'); }; main();