dva-源码解析

dva-cli

dva 的命令行工具 原理就是当运行 dva new my-app 时,dva-cli 就将其项目中的boilerplates文件夹拷贝到process.cwd()目录下。并且运行npm install安装项目依赖。

查看 package.json 入口在bin/dva

// Notify update when process exits
const updater = require('update-notifier');
const pkg = require('../package.json');
updater({ pkg: pkg }).notify({ defer: true });

// dva -v
if (process.argv.slice(2).join('') === '-v') {
  // ...
}

program
  .usage('<command> [options]')
  .on('--help', printHelp)
  .parse(process.argv);

const aliases = {
  g: 'generate',
};
const args = process.argv.slice(3);

// new、generate
let subcmd = program.args[0];
if (aliases[subcmd]) subcmd = aliases[subcmd];

if (!subcmd) {
  program.help();
} else {
  const bin = executable(subcmd);
  if (bin) {
    // 执行文件
    wrap(spawn(bin, args, {stdio: 'inherit', customFds: [0, 1, 2]}));
  } else {
    program.help();
  }
}

function wrap(sp) {
  sp.on('close', function(code) {
    process.exit(code);
  });
}

// 检查是不是有相应 subcmd 的执行文件
function executable(subcmd) {
  var file = join(__dirname, 'dva-' + subcmd);
  if (exists(file)) {
    return file;
  }
}
复制代码

bin/dva 是dva-cli的入口文件,其中定义了-v命令以及执行相应的subcmd命令。如果你输入了dva new my-app,那么将会执行bin/dva-new,下面看下bin/dva-new文件

// 没有定义项目名称
if (!program.args[0]) {
  program.help();
} else {
  const dest = join(process.cwd(), program.args[0]);
  // 如果已经存在该项目
  if (existsSync(dest)) {
    console.error(error('Existing directory here, please run new command for an empty folder!'));
    process.exit(1);
  }
  // 创建目录
  mkdirpSync(dest);
  // 进入目录
  process.chdir(dest);
  require('../lib/init')(program);
}
复制代码

bin/dva-new 检查了命令的有效性,并且创建、进入项目目录,执行dva-init初始化项目,下面去看一下bin/dva-init

program
  .option('--demo', 'Generate dva project for demo')
  .option('--no-install', 'Install dependencies after boilerplate, default: true')
  .parse(process.argv);

require('../lib/init')(program);
复制代码

定义了两个配置项,然后又调用了lib/init,由于lib文件夹是打包出来的,先去看一下src/init文件吧

function init({ demo, install }) {
  const type = demo ? 'demo' : 'app';
  // __dirname 为执行文件所在的目录
  const cwd = join(__dirname, '../boilerplates', type);
  const dest = process.cwd();
  const projectName = basename(dest);

  if (!emptyDir(dest)) {
    error('Existing files here, please run init command in an empty folder!');
    process.exit(1);
  }

  console.log(`Creating a new Dva app in ${dest}.`);
  console.log();

  // vfs:文件流处理工具,将boilerplates中的文件拷贝到process.cwd目录下,
  // 如果install为true的话,则执行src/install
  vfs.src(['**/*', '!node_modules/**/*'], {cwd: cwd, cwdbase: true, dot: true})
    .pipe(template(dest, cwd))
    .pipe(vfs.dest(dest))
    .on('end', function() {
      info('rename', 'gitignore -> .gitignore');
      renameSync(join(dest, 'gitignore'), join(dest, '.gitignore'));
      if (install) {
        info('run', 'npm install');
        require('./install')(printSuccess);
      } else {
        printSuccess();
      }
    })
    .resume();

  function printSuccess() {
    //...
  }
}
复制代码

src/install 会去根据系统安装的依赖管理工具进行install操作

// 好吧 竟然没有yarn
function findNpm() {
  var npms = process.platform === 'win32' ? ['tnpm.cmd', 'cnpm.cmd', 'npm.cmd'] : ['tnpm', 'cnpm', 'npm'];
  for (var i = 0; i < npms.length; i++) {
    try {
      which.sync(npms[i]);
      console.log('use npm: ' + npms[i]);
      return npms[i];
    } catch (e) {
    }
  }
  throw new Error('please install npm');
}
export default function (done) {
  const npm = findNpm();
  // 因为boilerplates/package.json 中没有dva,所以在运行install之后,再安装dva,why?
  // 为什么不干脆将dva写在boilerplates/package.json里呢,
  // 因为这样就可以保证每次安装的dva都是最新版本啊 骚年。
  runCmd(which.sync(npm), ['install'], function () {
    runCmd(which.sync(npm), ['install', 'dva', '--save'], function () {
      console.log(npm + ' install end');
      done();
    });
  });
};
复制代码

在上面我们已经分析了dva new的相关命令,其实dva还支持generate操作(文档上是这么说的),不过。。。我们来看下generate文件

//...
console.log(chalk.red('?  dva generate is disabled since we don\'t have enough time currently.'));
process.exit(0);

require('../lib/generate')(program, {
  cwd: process.cwd(),
});
复制代码

四个字,暂未开放... 这个文档更新有点落后啊。dva-generate中又依赖了dva-ast 其中主要使用了 facebook/jscodeshift这个库,作用是解析js,将js内容解析成 AST 语法树,然后提供一些便利的操作接口,方便我们对各个节点进行更改,比如更改所有的属性名之类的。感兴趣的同学可以自己去研究一下,就送到这里啦~ dva-cli就分析到这里了,接下来我会去分析dva。

转载于:https://juejin.im/post/5bbaa5db5188255c7e401f66

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值