React官方脚手架
- 以5.0.1版本为例
- 创建项目执行过程
源码解读debug
创建项目create-react-app my-app,前面/packages/create-react-app源码解读,详细可以从create-react-app之pacakage/create-react-app核心源码解读(一)
相当于在packages/react-scripts运行命令:
yarn init
以下scripts/init.js,代码从上到下按需执行解析
1. 进入函数
const appPackage = require(path.join(appPath, 'package.json'));
debug代码如下:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uRdNi6cc-1658403349318)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e7e16091a7954e5099162f9b55e7f229~tplv-k3u1fbpfcp-watermark.image?)]](https://i-blog.csdnimg.cn/blog_migrate/c5389d9fdaf9c9710047810a6e42a7ce.png)
- 接着执行,
useyarn返回false,因为前面使用的npm安装的依赖 templateName的值为cra-template;templatePath运行值为'my-app/node_modules/cra-template';templateJsonPath运行值'my-app/node_modules/cra-template/template.json'- 获取
templateJson读取值为:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GLsDDf3F-1658403349320)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/91c9690e6e9c4e848d8efe29c3678710~tplv-k3u1fbpfcp-watermark.image?)]](https://i-blog.csdnimg.cn/blog_migrate/15227cdac286f094df9835d0f64af89a.png)
2. templatePackageToReplace
执行返回false
3. 新建项目my-app的package.json中添加scripts,具体源码如下:
appPackage.scripts = Object.assign(
{
start: 'react-scripts start',
build: 'react-scripts build',
test: 'react-scripts test',
eject: 'react-scripts eject',
},
templateScripts
);
到这里是不是很眼熟,create-react-app脚手架初始化的项目,package.json中就是这样
4. 设置 eslint config
appPackage.eslintConfig = {
extends: 'react-app',
};
5. 设置browers list
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a9bkHHnE-1658403349320)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f37d096d8e974071819bdc8162b581cf~tplv-k3u1fbpfcp-watermark.image?)]](https://i-blog.csdnimg.cn/blog_migrate/a93359729daf9904de1a95749bba5a95.png)
6. 异步写入package.json
fs.writeFileSync(
path.join(appPath, 'package.json'),
JSON.stringify(appPackage, null, 2) + os.EOL
);
执行完成后,就去新建的项目my-app下查看如下:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YfCIbDzM-1658403349321)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/7eeead3d8aa74863b33cc6303c6c33b8~tplv-k3u1fbpfcp-watermark.image?)]](https://i-blog.csdnimg.cn/blog_migrate/e11cb3b6a8c181d245258d970d2d49ef.png)
- 判断是否存在
README.md,返回false
8. 拷贝模版项目到新建项目目录下
在create-react-app/packages目录下可以看到有cra-template为初始化项目模版
templateDir运行值为'my-app/node_modules/cra-template/template'appPath运行值为'/Users/coco/project/shiqiang/create-react-app/packages/my-app'- 源码执行拷贝
const templateDir = path.join(templatePath, 'template');
if (fs.existsSync(templateDir)) {
fs.copySync(templateDir, appPath);
} else {
console.error(
`Could not locate supplied template: ${chalk.green(templateDir)}`
);
return;
}
运行完,去my-app下查看,此时的目录如下:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IZf2FE1w-1658403349321)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3149ca457315447681c4173274d7fdab~tplv-k3u1fbpfcp-watermark.image?)]](https://i-blog.csdnimg.cn/blog_migrate/d6088938f2f15a8382b859042ea45e10.png)
不存在.gitignore文件
9. 判断是否存在.gitignore
源码如下:
const gitignoreExists = fs.existsSync(path.join(appPath, '.gitignore'));
if (gitignoreExists) {
// Append if there's already a `.gitignore` file there
const data = fs.readFileSync(path.join(appPath, 'gitignore'));
fs.appendFileSync(path.join(appPath, '.gitignore'), data);
fs.unlinkSync(path.join(appPath, 'gitignore'));
} else {
// Rename gitignore after the fact to prevent npm from renaming it to .npmignore
// See: https://github.com/npm/npm/issues/1862
fs.moveSync(
path.join(appPath, 'gitignore'),
path.join(appPath, '.gitignore'),
[]
);
}
返回false,于是进入else,运行完成,新建项目gitignore替换为.gitignore
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FakKYryk-1658403349322)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0ffee6076190403e8c81c833133c43e6~tplv-k3u1fbpfcp-watermark.image?)]](https://i-blog.csdnimg.cn/blog_migrate/50643f5c4ecef57b65acf0877a37eb82.png)
10. 初始化git repo
源码如下:
function tryGitInit() {
try {
execSync('git --version', { stdio: 'ignore' });
if (isInGitRepository() || isInMercurialRepository()) {
return false;
}
execSync('git init', { stdio: 'ignore' });
return true;
} catch (e) {
console.warn('Git repo not initialized', e);
return false;
}
}
yarnornpm
if (useYarn) {
command = 'yarnpkg';
remove = 'remove';
args = ['add'];
} else {
command = 'npm';
remove = 'uninstall';
args = [
'install',
'--no-audit', // https://github.com/facebook/create-react-app/issues/11174
'--save',
verbose && '--verbose',
].filter(e => e);
}
- 安装其他模板依赖项(如果存在)
const dependenciesToInstall = Object.entries({
...templatePackage.dependencies,
...templatePackage.devDependencies,
});
if (dependenciesToInstall.length) {
args = args.concat(
dependenciesToInstall.map(([dependency, version]) => {
return `${dependency}@${version}`;
})
);
}
debug数据:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sinIYTHz-1658403349322)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1bc4cccd2eed4fcab39676aa0fc361fb~tplv-k3u1fbpfcp-watermark.image?)]](https://i-blog.csdnimg.cn/blog_migrate/3af53f101fd6bd876de452613482939e.png)
args运行数据:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PVgLaZfV-1658403349323)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6c06bc59d12a4eb2987cac9e29fca75d~tplv-k3u1fbpfcp-watermark.image?)]](https://i-blog.csdnimg.cn/blog_migrate/04b957cd1016c6455cfc5d3db094a87d.png)
11. 判断是否安装react
- 源码如下:
if ((!isReactInstalled(appPackage) || templateName) && args.length > 1) {
console.log();
console.log(`Installing template dependencies using ${command}...`);
const proc = spawn.sync(command, args, { stdio: 'inherit' });
if (proc.status !== 0) {
console.error(`\`${command} ${args.join(' ')}\` failed`);
return;
}
}
- 函数
isReactInstalled
function isReactInstalled(appPackage) {
const dependencies = appPackage.dependencies || {};
return (
typeof dependencies.react !== 'undefined' &&
typeof dependencies['react-dom'] !== 'undefined'
);
}
- 关键打印信息:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KTibyfm4-1658403349323)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/138b047ee60d4ebe96d7ad3c222ce4ae~tplv-k3u1fbpfcp-watermark.image?)]](https://i-blog.csdnimg.cn/blog_migrate/136ba18874e012ff32dbaf1e6af0d7ae.png)
12. 子进程执行安装命令
- 源码如下:
const proc = spawn.sync(command, args, { stdio: 'inherit' });
- 控制台运行信息如下:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WdJ6v5U4-1658403349324)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f9774a075a734e0b80553f1f30697bbc~tplv-k3u1fbpfcp-watermark.image?)]](https://i-blog.csdnimg.cn/blog_migrate/fe48e04f603ac115db7442ddeddd52bf.png)
13. 执行删除,删除node_modules目录下的cra-template
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JsjGCYba-![1658403349324)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/73ccab30be82492e8dba4f2f1bf04244~tplv-k3u1fbpfcp-watermark.image?)]](https://i-blog.csdnimg.cn/blog_migrate/5e4c890e42c61004549daa41492c444c.png)
14. 显示最优雅的 cd 方式
- 源码如下:
let cdpath;
if (originalDirectory && path.join(originalDirectory, appName) === appPath) {
cdpath = appName;
} else {
cdpath = appPath;
}
运行后cdpath值为my-app
15. 成功信息提示打印
- 源码如下:
const displayedCommand = useYarn ? 'yarn' : 'npm';
console.log();
console.log(`Success! Created ${appName} at ${appPath}`);
console.log('Inside that directory, you can run several commands:');
console.log();
console.log(chalk.cyan(` ${displayedCommand} start`));
console.log(' Starts the development server.');
console.log();
console.log(
chalk.cyan(` ${displayedCommand} ${useYarn ? '' : 'run '}build`)
);
console.log(' Bundles the app into static files for production.');
console.log();
console.log(chalk.cyan(` ${displayedCommand} test`));
console.log(' Starts the test runner.');
console.log();
console.log(
chalk.cyan(` ${displayedCommand} ${useYarn ? '' : 'run '}eject`)
);
console.log(
' Removes this tool and copies build dependencies, configuration files'
);
console.log(
' and scripts into the app directory. If you do this, you can’t go back!'
);
console.log();
console.log('We suggest that you begin by typing:');
console.log();
console.log(chalk.cyan(' cd'), cdpath);
console.log(` ${chalk.cyan(`${displayedCommand} start`)}`);
if (readmeExists) {
console.log();
console.log(
chalk.yellow(
'You had a `README.md` file, we renamed it to `README.old.md`'
)
);
}
console.log();
console.log('Happy hacking!');
- 控制台打印信息如下:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h6EXEnvb-1658403349324)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3f0239cddb11432b982d626e4d23bd08~tplv-k3u1fbpfcp-watermark.image?)]](https://i-blog.csdnimg.cn/blog_migrate/167aa3f868b65e88e150bf9bb233dd63.png)
至此,新建项目react-scripts中的完成

本文详细解析了使用create-react-app创建React项目的步骤,包括从源码层面理解项目初始化过程,如设置package.json,配置eslint,拷贝模板文件,安装依赖等。最后,文章展示了项目创建成功后的目录结构及控制台输出信息。
567

被折叠的 条评论
为什么被折叠?



