node chrome-devtool 调试:

  1. 在项目根目录执行 node --inspect-brk packages/create-react-app/index.js
  2. chrome地址栏输入 chrome://inspect/#devices

然后就可以在chrome进行断点调试了


流程如下:

一、判断 node 版本

截屏2020-04-17下午3.30.10.png
如果 node 版本低于8,则控制台输出以上内容,并退出执行。

二、使用 commander 库做命令行初始化

截屏2020-04-17下午3.36.42.png

三、判断是否有传入 projectName(项目名称)

截屏2020-04-17下午4.10.36.png
这里的 projectName 就是上面通过 .action(name => { projectName = name})获取的。
如果没有传入的话,直接做一些信息提示,然后退出执行

四、执行 createApp 方法

截屏2020-04-17下午4.33.38.png
createApp 主要做的事情就是一些安全性判断比如:检查项目名是否合法,检查文件是否安全,检查npm版本等,同时在这个方法中,把package.json写到了项目根目录下。

五、执行 run 方法

run 主要做的事情主要有:
一、先根据传入的版本version 和原始目录originalDirectory 去获取要安装的某个 package。
二、默认的 version 为空,获取到的 packageToInstall 值是 react-scripts, 然后将packageToInstall拼接到 allDependencies意为所有需要安装的依赖。
三、如果当前是采用yarn安装方式的话,就判断是否处于离线状态。判断完连着前面的 packageToInstallallDependencies 一起丢给 install 方法,再由install方法去跑安装。

getInstallPackage(); 获取要安装的模版包 默认是 react-scripts
getTemplateInstallPackage(); 获取安装的template,也就是那些 src、public文件
install(); 传参数给install 负责安装 allDependencies
catch(); 错误处理
截屏2020-04-18下午11.10.58.png

六、 install 方法

从run方法中跑到install方法
能看到代码里根据是否使用yarn分成两种处理方法。
if (useYarn) { yarn 安装逻辑 } else { npm 安装逻辑 }
处理方法都是同个逻辑,根据传入的 dependencies 去拼接需要安装的依赖,主要有 react,react-dom,react-script 。再判断verboseisOnline 加一些命令行的参数。
最后再用node跑命令,平台差异的话是借助cross-spawn去处理的

  1. function install(root, useYarn, usePnp, dependencies, verbose, isOnline) {
  2. return new Promise((resolve, reject) => {
  3. let command;
  4. let args;
  5. if (useYarn) {
  6. command = 'yarnpkg';
  7. args = ['add', '--exact'];
  8. if (!isOnline) {
  9. args.push('--offline');
  10. }
  11. if (usePnp) {
  12. args.push('--enable-pnp');
  13. }
  14. [].push.apply(args, dependencies);
  15. args.push('--cwd'); // 将cwd设置为我们要安装的目录路径
  16. args.push(root);
  17. if (!isOnline) {
  18. console.log(chalk.yellow('You appear to be offline.'));
  19. console.log(chalk.yellow('Falling back to the local Yarn cache.'));
  20. console.log();
  21. }
  22. } else {
  23. command = 'npm';
  24. args = [
  25. 'install',
  26. '--save',
  27. '--save-exact',
  28. '--loglevel',
  29. 'error',
  30. ].concat(dependencies);
  31. if (usePnp) {
  32. console.log(chalk.yellow("NPM doesn't support PnP."));
  33. console.log(chalk.yellow('Falling back to the regular installs.'));
  34. console.log();
  35. }
  36. }
  37. if (verbose) {
  38. args.push('--verbose');
  39. }
  40. const child = spawn(command, args, { stdio: 'inherit' });
  41. child.on('close', code => {
  42. if (code !== 0) {
  43. reject({
  44. command: `${command} ${args.join(' ')}`,
  45. });
  46. return;
  47. }
  48. resolve();
  49. });
  50. });
  51. }

七、 总结

1、判断node版本如果小于8就退出,否则执行 createReactApp.js 文件
2、createReactApp.js先做一些命令行的处理响应处理,然后判断是否有传入 projectName 没有就提示并退出
3、根据传入的 projectName 创建目录,并创建package.json。
4、判断是否有特殊要求指定安装某个版本的react-scripts,然后用cross-spawn去处理跨平台的命令行问题,用 yarn或npm安装react, react-dom, react-scripts,以及模板cra-template包。
5、处理完这些之后,输出提示给用户。

八、流程图

create-react-app.png