git clone https://github.com/facebook/create-react-app.git --depth=1
cd create-react-app
yarn install
package.json
"scripts": {
+ "create": "node ./packages/create-react-app/index.js",
}
npm run [command] [-- <args>]
yarn install #安装项止依赖和软链接
npm run create -- aaa #执行创建命令
Installing packages. This might take a couple of minutes. #安装依赖包
Installing react, react-dom, and react-scripts with cra-template... #安装依赖包
Installing template dependencies using yarnpkg... #安装模板依赖
Removing template package using yarnpkg... #移除模板模块
Removing module cra-template... #移除cra-template模块
Success! Created aaa at C:\aprepare\create-react-app\aaa #成功创建
Inside that directory, you can run several commands: #执行命令
cd aaa
yarn start
.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"
}
]
}
package.json
"scripts": {
+ "version": "node ./packages/create-react-app3/index.js --version",
+ "create": "node ./packages/create-react-app3/index.js aaa"
}
packages\create-react-app3\package.json
{
+ "main": "./index.js"
}
packages\create-react-app3\index.js
#!/usr/bin/env node
const { init } = require('./createReactApp');
init();
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
}
npm run create
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
}
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
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
}
npm i lerna -g
lerna init
package.json
{
"name": "root",
"private": true,
"devDependencies": {
"lerna": "^3.22.1"
}
}
lerna.json
{
"packages": [
"packages/*"
],
"version": "0.0.0"
}
yarn workspace
允许我们使用 monorepo
的形式来管理项目yarn.lock
文件。子项目也会被 link
到 node_modules
里面,这样就允许我们就可以直接用 import 导入对应的项目yarn.lock
文件是自动生成的,也完全Yarn来处理.yarn.lock
锁定你安装的每个依赖项的版本,这可以确保你不会意外获得不良依赖package.json
{
"name": "root",
"private": true, // 私有的,用来管理整个项目,不会被发布到npm
+ "workspaces": [
+ "packages/*"
+ ],
"devDependencies": {
"lerna": "^3.22.1"
}
}
lerna create create-react-app3
lerna create react-scripts3
lerna create cra-template3
设置加速镜像
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 |
node.js
命令行解决方案-V
和--version
usage
选项可以修改帮助信息的首行提示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);
spawn
和spawnSync
的跨平台解决方案stdio
流传给父进程或从父进程传入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);