react脚手架简易版

91 阅读1分钟

一、目录结构

image.png

二、源码

package.json

{
  "name": "react-cli-codeman",
  "version": "1.0.0",
  "description": "A simple cli tool",
  "main": "index.js",
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "https://gitee.com/jflyhak/react-cli-codeman"
    },
  "bin": {
    "mycli": "bin/index.js"
  },
  "dependencies": {
    "chalk": "^4.1.2",
    "commander": "^12.1.0",
    "cross-spawn": "^7.0.3",
    "fs-extra": "^11.2.0"
  },
  "devDependencies": {},
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": ""
}

bin/index.js

#!/usr/bin/env node
(async function(){
  const path = require("path");
  const fs = require("fs-extra");
  const commander = require("commander");
  const chalk = require("chalk");
  const packageJson = require("../package.json");
  
  const appPath = process.cwd();
  const craPath = path.resolve(__dirname);
  let projectName;
  let templateName;
  let templatePath;
  
  const program = new commander.Command()
    .version(packageJson.version)
    .description(packageJson.description) 
    .arguments("<project-directory>") 
    .usage(`${chalk.green("<project-directory>")} [options]`)
    .action((name, options) => {
      projectName = name;
      templateName = options.typescript
        ? "cra-template-typescript"
        : "cra-template";
      templatePath = path.resolve(craPath, `../package/${templateName}/template`);
    })
    .option("-t, --typescript", "是否使用ts模板");
  program.parse();
  const appRoot = path.resolve(appPath, projectName);

  // create and copy template files
  try {
    await fs.mkdir(`${appPath}/${projectName}`, { recursive: true });
    console.log(chalk.green(`创建目录${projectName}成功`));
    await fs.copy(templatePath, path.resolve(appPath, projectName));
    console.log(chalk.green(`复制${templateName}模板成功`));
    const appName = path.basename(appRoot);
    const packageJson = {
      name: appName,
      version: "0.1.0",
      private: true,
      scripts: {
        start: "react-scripts start",
        build: "react-scripts build",
        test: "react-scripts test",
        eject: "react-scripts eject",
      },
      browserslist: {
        production: [">0.2%", "not dead", "not op_mini all"],
        development: [
          "last 1 chrome version",
          "last 1 firefox version",
          "last 1 safari version",
        ],
      },
    };
    await fs.writeFileSync(
      path.join(appRoot, "package.json"),
      JSON.stringify(packageJson, null, 2)
    );
    console.log(chalk.green(`创建package.json文件成功`));
  } catch (error) {
    console.log(chalk.red(error));
    process.exit(1);
  }

   // install dependencies
  install( ["react", "react-dom", "react-scripts", 'web-vitals'], isUsingYarn());

  function install(dependencies, useYarn) {
    process.chdir(appRoot);
    const spawn = require("cross-spawn");
    let command;
    let args;
    if (useYarn) {
      command = "yarnpkg";
      args = ["add", "--exact", '--production'];
    } else {
      command = "npm";
      args = ["install", "--save", "--save-exact"];
    }
    args = args.concat(dependencies);
    console.log(chalk.green(`开始安装依赖依赖: ${command} ${args.join(" ")}`));
    const child = spawn(command, args.concat(dependencies), { stdio: "inherit" });
    child.on("close", (code) => {
      if (code !== 0) {
        console.log(chalk.red("依赖安装失败"));
      } else {
        console.log(chalk.green(`${dependencies.join(" ")}: 依赖安装成功`));
      }
    });
  }
  
  function isUsingYarn() {
    return (process.env.npm_config_user_agent || "").indexOf("yarn") === 0;
  }
}());

三、发布到npm

 npm login
 npm publish

image.png

四、本地使用

 npx react-cli-codeman test

image.png