1.create-react-app #

1.1 下载 #

git clone https://github.com/facebook/create-react-app.git --depth=1
cd create-react-app
yarn install

1.2 package.json #

package.json

"scripts": {
+  "create": "node ./packages/create-react-app/index.js",
}

1.3 重要步骤 #

1.4 .vscode\launch.json #

.vscode\launch.json

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Launch via NPM",
            "request": "launch",
            "runtimeArgs": [
                "run-script",
                "create"
            ],
            "runtimeExecutable": "npm",
            "skipFiles": [
                "<node_internals>/**"
            ],
            "type": "pwa-node"
        }
    ]
}

2.实现init方法 #

2.1 package.json #

package.json

  "scripts": {
+    "version": "node ./packages/create-react-app3/index.js --version",
+    "create": "node ./packages/create-react-app3/index.js aaa"
  }

2.2 create-react-app3\package.json #

packages\create-react-app3\package.json

{
+ "main": "./index.js"
}

2.3 create-react-app3\index.js #

packages\create-react-app3\index.js

#!/usr/bin/env node
const { init } = require('./createReactApp');
init();

2.4 createReactApp.js #

packages\create-react-app3\createReactApp.js

const {Command} = require('commander');
const chalk = require('chalk');
const packageJson = require('./package.json');
let appName;
async function init() {
    new Command(packageJson.name)
        .version(packageJson.version)
        .arguments('<project-directory>')
        .usage(`${chalk.green('<project-directory>')} [options]`)
        .action(projectDirectory => {
            appName = projectDirectory;
        })
        .parse(process.argv);
    console.log('appName=', appName);
}
module.exports = {
    init
}

2.5 执行命令 #

npm run create

3.实现createApp方法 #

3.1 createReactApp.js #

packages\create-react-app3\createReactApp.js

const {Command} = require('commander');
const chalk = require('chalk');
+const fs = require('fs-extra');
+const path = require('path');
const packageJson = require('./package.json');
let appName;
async function init() {
    new Command(packageJson.name)
        .version(packageJson.version)
        .arguments('<project-directory>')
        .usage(`${chalk.green('<project-directory>')} [options]`)
        .action(projectDirectory => {
            appName = projectDirectory;
        })
        .parse(process.argv);
    console.log('appName=', appName);
+   await createApp(appName);
}
+async function createApp(appName) {
+    const root = path.resolve(appName);
+    fs.ensureDirSync(appName);
+    console.log(`Creating a new React app in ${chalk.green(root)}.`);
+    const packageJson = {
+      name: appName,
+      version: '0.1.0',
+      private: true,
+    };
+    fs.writeFileSync(
+      path.join(root, 'package.json'),
+      JSON.stringify(packageJson, null, 2)
+    );
+    const originalDirectory = process.cwd();
+    process.chdir(root);
+    console.log('root',root);
+    console.log('appName',appName);
+    console.log('originalDirectory',originalDirectory);
+  }
module.exports = {
    init
}

4.实现run方法 #

4.1 createReactApp.js #

packages\create-react-app3\createReactApp.js

const {Command} = require('commander');
const chalk = require('chalk');
const fs = require('fs-extra');
const path = require('path');
+const spawn = require('cross-spawn');
const packageJson = require('./package.json');
let appName;
async function init() {
    new Command(packageJson.name)
        .version(packageJson.version)
        .arguments('<project-directory>')
        .usage(`${chalk.green('<project-directory>')} [options]`)
        .action(projectDirectory => {
            appName = projectDirectory;
        })
        .parse(process.argv);
    console.log('appName=', appName);
    await createApp(appName);
}
async function createApp(appName) {
    const root = path.resolve(appName);
    fs.ensureDirSync(appName);
    console.log(`Creating a new React app in ${chalk.green(root)}.`);
    const packageJson = {
      name: appName,
      version: '0.1.0',
      private: true,
    };
    fs.writeFileSync(
      path.join(root, 'package.json'),
      JSON.stringify(packageJson, null, 2)
    );
    const originalDirectory = process.cwd();
    process.chdir(root);
    console.log('root',root);
    console.log('appName',appName);
    console.log('originalDirectory',originalDirectory);
+   await run(
+        root,
+        appName,
+        originalDirectory
+   );
}
+async function run(root,appName,originalDirectory) {
+    const scriptName = 'react-scripts';
+    const templateName = 'cra-template';
+    const allDependencies = ['react', 'react-dom', scriptName, templateName];
+    console.log('Installing packages. This might take a couple of minutes.');
+    console.log(
+      `Installing ${chalk.cyan('react')}, ${chalk.cyan(
+        'react-dom'
+      )}, and ${chalk.cyan(scriptName)} with ${chalk.cyan(templateName)}`
+    );
+    await install(root, allDependencies);
+}
+function install(root, allDependencies) {
+    return new Promise((resolve) => {
+      const command = 'yarnpkg';
+      const args = ['add', '--exact', ...allDependencies, '--cwd', root];
+      console.log('command:',command,args);
+      const child = spawn(command, args, { stdio: 'inherit' });
+      child.on('close', resolve);
+    });
+}
module.exports = {
    init
}

command: yarnpkg [
  'add',
  '--exact',
  'react',
  'react-dom',
  'react-scripts',
  'cra-template',
  '--cwd',
  'C:\\aprepare\\create-react-app3\\aaa'
]

yarnpkg add --exact react react-dom react-scripts cra-template --cwd C:\\aprepare\\create-react-app3\\aaa

5.执行init初始化命令 #

5.1 createReactApp.js #

packages\create-react-app3\createReactApp.js

const {Command} = require('commander');
const chalk = require('chalk');
const fs = require('fs-extra');
const path = require('path');
const spawn = require('cross-spawn');
const packageJson = require('./package.json');
let appName;
async function init() {
    new Command(packageJson.name)
        .version(packageJson.version)
        .arguments('<project-directory>')
        .usage(`${chalk.green('<project-directory>')} [options]`)
        .action(projectDirectory => {
            appName = projectDirectory;
        })
        .parse(process.argv);
    console.log('appName=', appName);
    await createApp(appName);
}
async function createApp(appName) {
    const root = path.resolve(appName);
    fs.ensureDirSync(appName);
    console.log(`Creating a new React app in ${chalk.green(root)}.`);
    const packageJson = {
      name: appName,
      version: '0.1.0',
      private: true,
    };
    fs.writeFileSync(
      path.join(root, 'package.json'),
      JSON.stringify(packageJson, null, 2)
    );
    const originalDirectory = process.cwd();
    process.chdir(root);
    console.log('root',root);
    console.log('appName',appName);
    console.log('originalDirectory',originalDirectory);
    await run(
        root,
        appName,
        originalDirectory
    );
}
async function run(root,appName,originalDirectory) {
    const scriptName = 'react-scripts';
    const templateName = 'cra-template';
    const allDependencies = ['react', 'react-dom', scriptName, templateName];
    console.log('Installing packages. This might take a couple of minutes.');
    console.log(
      `Installing ${chalk.cyan('react')}, ${chalk.cyan(
        'react-dom'
      )}, and ${chalk.cyan(scriptName)} with ${chalk.cyan(templateName)}`
    );
    await install(root, allDependencies);
+    let data = [root, appName, true, originalDirectory, templateName];
+    let source = `
+    var init = require('react-scripts/scripts/init.js');
+    init.apply(null, JSON.parse(process.argv[1]));
+  `
+    await executeNodeScript({ cwd: process.cwd() }, data, source);
+    console.log('Done.');
+    process.exit(0);
}
+function executeNodeScript({ cwd }, data, source) {
+  return new Promise((resolve) => {
+    const child = spawn( 
+      process.execPath,
+      ['-e', source, '--', JSON.stringify(data)],
+      { cwd, stdio: 'inherit' }
+    );
+    child.on('close', resolve);
+  });
+}
function install(root, allDependencies) {
    return new Promise((resolve) => {
      const command = 'yarnpkg';
      const args = ['add', '--exact', ...allDependencies, '--cwd', root];
      console.log('command:',command,args);
      const child = spawn(command, args, { stdio: 'inherit' });
      child.on('close', resolve);
    });
}
module.exports = {
    init
}

1. monorepo管理 #

1609568943612

1.1 安装 #

npm i lerna -g

1.2 初始化 #

lerna init

lerna-init

1.2.1 package.json #

package.json

{
  "name": "root",
  "private": true,
  "devDependencies": {
    "lerna": "^3.22.1"
  }
}

1.2.2 lerna.json #

lerna.json

{
  "packages": [
    "packages/*"
  ],
  "version": "0.0.0"
}

1.3 yarn workspace #

1.3.1 开启workspace #

package.json

{
  "name": "root",
  "private": true, // 私有的,用来管理整个项目,不会被发布到npm
+  "workspaces": [
+    "packages/*"
+  ],
  "devDependencies": {
    "lerna": "^3.22.1"
  }
}

1.3.2 创建子项目 #

lerna create create-react-app3
lerna create react-scripts3
lerna create cra-template3

1609571583709

1.3.3 添加依赖 #

设置加速镜像

yarn config get registry
yarn config set registry http://registry.npm.taobao.org/
yarn config set registry http://registry.npmjs.org/
作用 命令
查看工作空间信息 yarn workspaces info
给根空间添加依赖 yarn add chalk cross-spawn fs-extra --ignore-workspace-root-check
给某个项目添加依赖 yarn workspace create-react-app3 add commander
删除所有的 node_modules lerna clean 等于 yarn workspaces run clean
安装和link yarn install 等于 lerna bootstrap --npm-client yarn --use-workspaces
重新获取所有的 node_modules yarn install --force
查看缓存目录 yarn cache dir
清除本地缓存 yarn cache clean

2. commander #

const chalk = require('chalk');
const {Command} = require('commander');
console.log('process.argv',process.argv);
new Command('create-react-app')
    .version('1.0.0')
    .arguments('<must1> <must2> [optional]')
    .usage(`${chalk.green('<must1> <must2>')} [optional]`)
    .action((must1,must2,optional,...args) => {
       console.log(must1,must2,optional,args);
    })
    .parse(process.argv);

3. cross-spawn #

const spawn = require('cross-spawn');
const child = spawn('node', ['script.js','one','two','three'], { stdio: 'inherit' });
child.on('close',()=>{
    console.log('child is done!');
});
const result = spawn.sync('node', ['script.js','one','two','three'], { stdio: 'inherit' });
console.log(result);