createReactApp函数解读
在create-react-app脚手架的目录为/packages/create-react-app/createReactApp.js
函数定义:创建react app
源码如下:
function createApp(name, verbose, version, template, useYarn, usePnp) {
const unsupportedNodeVersion = !semver.satisfies(
// Coerce strings with metadata (i.e. `15.0.0-nightly`).
semver.coerce(process.version),
'>=14'
);
if (unsupportedNodeVersion) {
console.log(
chalk.yellow(
`You are using Node ${process.version} so the project will be bootstrapped with an old unsupported version of tools.\n\n` +
`Please update to Node 14 or higher for a better, fully supported experience.\n`
)
);
// Fall back to latest supported react-scripts on Node 4
version = 'react-scripts@0.9.x';
}
const root = path.resolve(name);
const appName = path.basename(root);
checkAppName(appName);
fs.ensureDirSync(name);
if (!isSafeToCreateProjectIn(root, name)) {
process.exit(1);
}
console.log();
console.log(`Creating a new React app in ${chalk.green(root)}.`);
console.log();
const packageJson = {
name: appName,
version: '0.1.0',
private: true,
};
fs.writeFileSync(
path.join(root, 'package.json'),
JSON.stringify(packageJson, null, 2) + os.EOL
);
const originalDirectory = process.cwd();
process.chdir(root);
if (!useYarn && !checkThatNpmCanReadCwd()) {
process.exit(1);
}
if (!useYarn) {
const npmInfo = checkNpmVersion();
if (!npmInfo.hasMinNpm) {
if (npmInfo.npmVersion) {
console.log(
chalk.yellow(
`You are using npm ${npmInfo.npmVersion} so the project will be bootstrapped with an old unsupported version of tools.\n\n` +
`Please update to npm 6 or higher for a better, fully supported experience.\n`
)
);
}
// Fall back to latest supported react-scripts for npm 3
version = 'react-scripts@0.9.x';
}
} else if (usePnp) {
const yarnInfo = checkYarnVersion();
if (yarnInfo.yarnVersion) {
if (!yarnInfo.hasMinYarnPnp) {
console.log(
chalk.yellow(
`You are using Yarn ${yarnInfo.yarnVersion} together with the --use-pnp flag, but Plug'n'Play is only supported starting from the 1.12 release.\n\n` +
`Please update to Yarn 1.12 or higher for a better, fully supported experience.\n`
)
);
// 1.11 had an issue with webpack-dev-middleware, so better not use PnP with it (never reached stable, but still)
usePnp = false;
}
if (!yarnInfo.hasMaxYarnPnp) {
console.log(
chalk.yellow(
'The --use-pnp flag is no longer necessary with yarn 2 and will be deprecated and removed in a future release.\n'
)
);
// 2 supports PnP by default and breaks when trying to use the flag
usePnp = false;
}
}
}
run(
root,
appName,
version,
verbose,
originalDirectory,
template,
useYarn,
usePnp
);
}
函数解析
debug代码显示:unsupportedNodeVersion
判断当前运行Node
版本是否大于v14
如果小于,则打印提示信息
1. checkAppName(appName)
function checkAppName(appName) {
const validationResult = validateProjectName(appName);
if (!validationResult.validForNewPackages) { // true取反,为false,不进入
console.error(
chalk.red(
`Cannot create a project named ${chalk.green(
`"${appName}"`
)} because of npm naming restrictions:\n`
)
);
[
...(validationResult.errors || []),
...(validationResult.warnings || []),
].forEach(error => {
console.error(chalk.red(` * ${error}`));
});
console.error(chalk.red('\nPlease choose a different project name.'));
process.exit(1);
}
// TODO: there should be a single place that holds the dependencies
const dependencies = ['react', 'react-dom', 'react-scripts'].sort();
if (dependencies.includes(appName)) {
console.error(
chalk.red(
`Cannot create a project named ${chalk.green(
`"${appName}"`
)} because a dependency with the same name exists.\n` +
`Due to the way npm works, the following names are not allowed:\n\n`
) +
chalk.cyan(dependencies.map(depName => ` ${depName}`).join('\n')) +
chalk.red('\n\nPlease choose a different project name.')
);
process.exit(1);
}
}
if (!validationResult.validForNewPackages)
// true取反,为false,不进入if (dependencies.includes(appName)) {
// false- 执行完检查app名字;
2. 创建项目根目录
- 继续执行
fs.ensureDirSync
(fs为三方库fs-extra
)表示异步创建目录, 至此,当前根目录下就可以看到目录my-app
- 判断
isSafeToCreateProjectIn(root,name)
冲突文件conflicts.length
为0,移除log
文件,返回true
控制台打印如下:
3. 写入package.json
为初始化项目写入package.json配置
const packageJson = {
name: appName,
version: '0.1.0',
private: true,
};
fs.writeFileSync(
path.join(root, 'package.json'),
JSON.stringify(packageJson, null, 2) + os.EOL
);
去刚刚新建的项目目录下查看,可以看到
4. 执行checkThatNpmCanReadCwd
// 不使用用yarn 而且npm执行有问题,报错,异常退出
if (!useYarn && !checkThatNpmCanReadCwd()) {
process.exit(1);
}
process.chdir()方法是过程模块的内置应用程序编程接口,用于更改当前工作目录。
继续执行,执行函数checkThatNpmCanReadCwd
,具体含义查看【create-react-app脚手架核心源码解读(二)】
返回true
5. useYarn
if (!useYarn) {
const npmInfo = checkNpmVersion();
if (!npmInfo.hasMinNpm) {
if (npmInfo.npmVersion) {
console.log(
chalk.yellow(
`You are using npm ${npmInfo.npmVersion} so the project will be bootstrapped with an old unsupported version of tools.\n\n` +
`Please update to npm 6 or higher for a better, fully supported experience.\n`
)
);
}
// Fall back to latest supported react-scripts for npm 3
version = 'react-scripts@0.9.x';
}
} else if (usePnp) {
const yarnInfo = checkYarnVersion();
if (yarnInfo.yarnVersion) {
if (!yarnInfo.hasMinYarnPnp) {
console.log(
chalk.yellow(
`You are using Yarn ${yarnInfo.yarnVersion} together with the --use-pnp flag, but Plug'n'Play is only supported starting from the 1.12 release.\n\n` +
`Please update to Yarn 1.12 or higher for a better, fully supported experience.\n`
)
);
// 1.11 had an issue with webpack-dev-middleware, so better not use PnP with it (never reached stable, but still)
usePnp = false;
}
if (!yarnInfo.hasMaxYarnPnp) {
console.log(
chalk.yellow(
'The --use-pnp flag is no longer necessary with yarn 2 and will be deprecated and removed in a future release.\n'
)
);
// 2 supports PnP by default and breaks when trying to use the flag
usePnp = false;
}
}
}
如果不使用yarn
,使用的是npm
,需要检查npm
的版本,执行的npmInfo
6. 执行run
run(
root,
appName,
version,
verbose,
originalDirectory,
template,
useYarn,
usePnp
);
至此,创建app函数主要源码完成解读