美文网首页
react-native-cli指令流程分析

react-native-cli指令流程分析

作者: LaxusJ | 来源:发表于2019-12-26 14:24 被阅读0次

    大体流程

    我们执行一个react-native init或start指令的时候入口在
    react-native-cli/package.json

    "bin": {
        "react-native": "index.js"
      },
    

    从这里可以看到入口指向了react-native-cli/index.js,进入index.js
    分析代码前先看一下文件注释

    react native cli已全局安装在人们的计算机上。这意味着
    很难让他们升级版本因为只安装了一个全局版本,所以很容易打破改变。react native cli的唯一工作是初始化存储库,然后将所有命令转发到react native的本地版本。如果需要添加新命令,请将其添加到本地cli/。修改此文件的唯一原因是添加了更多警告和“react native init”命令的疑难解答信息。不要做破坏性的改变!我们绝对不想告诉人们更新他们的react native cl的全局版本

    所以说全局库中只有init的指令方法,其他指令方法都在本地local-cli中,接下来分析一下代码

    //获取指令参数
    var options = require('minimist')(process.argv.slice(2));
    
    //获取react-native包下的cli路径
    var CLI_MODULE_PATH = function() {
      return path.resolve(
        process.cwd(),
        'node_modules',
        'react-native',
        'cli.js'
      );
    };
    
    //获取react-native包下的package.json路径
    var REACT_NATIVE_PACKAGE_JSON_PATH = function() {
      return path.resolve(
        process.cwd(),
        'node_modules',
        'react-native',
        'package.json'
      );
    };
    ...
    //获取cli文件
    var cli;
    var cliPath = CLI_MODULE_PATH();
    if (fs.existsSync(cliPath)) {
      cli = require(cliPath);
    }
    
    //执行指令
    var commands = options._;
    if (cli) {
      cli.run();
    } else {
      if (options._.length === 0 && (options.h || options.help)) {
        console.log([
          '',
          '  Usage: react-native [command] [options]',
          '',
          '',
          '  Commands:',
          '',
          '    init <ProjectName> [options]  generates a new project and installs its dependencies',
          '',
          '  Options:',
          '',
          '    -h, --help    output usage information',
          '    -v, --version output the version number',
          '',
        ].join('\n'));
        process.exit(0);
      }
    
      if (commands.length === 0) {
        console.error(
          'You did not pass any commands, run `react-native --help` to see a list of all available commands.'
        );
        process.exit(1);
      }
    
      switch (commands[0]) {
      case 'init':
        if (!commands[1]) {
          console.error(
            'Usage: react-native init <ProjectName> [--verbose]'
          );
          process.exit(1);
        } else {
          init(commands[1], options);
        }
        break;
      default:
        console.error(
          'Command `%s` unrecognized. ' +
          'Make sure that you have run `npm install` and that you are inside a react-native project.',
          commands[0]
        );
        process.exit(1);
        break;
      }
    }
    

    前面是获取指令参数和路径信息,然后是require cli文件,开始执行指令,判断如果有cli则执行cli.run,否则执行当前文件的逻辑。

    init指令逻辑

    生成项目会走到init方法,最后执行到run方法

    /**
     * @param name Project name, e.g. 'AwesomeApp'.
     * @param options.verbose If true, will run 'npm install' in verbose mode (for debugging).
     * @param options.version Version of React Native to install, e.g. '0.38.0'.
     * @param options.npm If true, always use the npm command line client,
     *                       don't use yarn even if available.
     */
    function init(name, options) {
      validateProjectName(name);
    
      if (fs.existsSync(name)) {
        createAfterConfirmation(name, options);
      } else {
        createProject(name, options);
      }
    }
    
    function run(root, projectName, options) {
      // E.g. '0.38' or '/path/to/archive.tgz'
      const rnPackage = options.version;
      const forceNpmClient = options.npm;
      const yarnVersion = (!forceNpmClient) && getYarnVersionIfAvailable();
      var installCommand;
      if (options.installCommand) {
        // In CI environments it can be useful to provide a custom command,
        // to set up and use an offline mirror for installing dependencies, for example.
        installCommand = options.installCommand;
      } else {
        if (yarnVersion) {
          console.log('Using yarn v' + yarnVersion);
          console.log('Installing ' + getInstallPackage(rnPackage) + '...');
          installCommand = 'yarn add ' + getInstallPackage(rnPackage) + ' --exact';
          if (options.verbose) {
            installCommand += ' --verbose';
          }
        } else {
          console.log('Installing ' + getInstallPackage(rnPackage) + '...');
          if (!forceNpmClient) {
            console.log('Consider installing yarn to make this faster: https://yarnpkg.com');
          }
          installCommand = 'npm install --save --save-exact ' + getInstallPackage(rnPackage);
          if (options.verbose) {
            installCommand += ' --verbose';
          }
        }
      }
      try {
        execSync(installCommand, {stdio: 'inherit'});
      } catch (err) {
        console.error(err);
        console.error('Command `' + installCommand + '` failed.');
        process.exit(1);
      }
      checkNodeVersion();
      cli = require(CLI_MODULE_PATH());
      cli.init(root, projectName);
    }
    

    后面分别会创建项目、安装yarn依赖、安装react-native依赖,然后获取到react-native的cli路径,执行cli的init方法。

    /**
     * Creates the template for a React Native project given the provided
     * parameters:
     * @param projectDir Templates will be copied here.
     * @param argsOrName Project name or full list of custom arguments
     *                   for the generator.
     * @param options Command line options passed from the react-native-cli directly.
     *                E.g. `{ version: '0.43.0', template: 'navigation' }`
     */
    function init(projectDir, argsOrName) {
      const args = Array.isArray(argsOrName)
        ? argsOrName // argsOrName was e.g. ['AwesomeApp', '--verbose']
        : [argsOrName].concat(process.argv.slice(4)); // argsOrName was e.g. 'AwesomeApp'
    
      // args array is e.g. ['AwesomeApp', '--verbose', '--template', 'navigation']
      if (!args || args.length === 0) {
        console.error('react-native init requires a project name.');
        return;
      }
    
      const newProjectName = args[0];
      const options = minimist(args);
    
      if (listTemplatesAndExit(newProjectName, options)) {
        // Just listing templates using 'react-native init --template'
        // Not creating a new app.
        return;
      } else {
        console.log('Setting up new React Native app in ' + projectDir);
        generateProject(projectDir, newProjectName, options);
      }
    }
    

    至此init指令流程基本分析完毕,有兴趣的童鞋可以跟一下代码

    相关文章

      网友评论

          本文标题:react-native-cli指令流程分析

          本文链接:https://www.haomeiwen.com/subject/jbskoctx.html