从react-start到co源码(二)

react作为当前十分流行的前端框架,相信很多前端er都有蠢蠢欲动的学习它的想法。工欲善其事,必先利其器。这篇文章就简单的给大家介绍一下如何我快速的搭建一个react前端开发环境。主要针对于react小白,大神不喜勿喷。
从标题可以看出,这里不会仅仅只介绍一下react的开发环境如何搭建。我将这个系列分成三篇介绍:

接下来就开始介绍如何去开发一个简单的react-start脚手架,从而一键生成react开发环境。

目录结构

首先来看一下脚手架的目录结构,基本结构如下:

-bin
  |--reactGenerator
-commander
  |--init.js
-config.json
-package.json

bin/reactGenerator:定义基本的命令

commander/init.js:定义命令所对应的操作

config.json:脚手架的一些配置文件

package.json:项目的包文件

项目依赖

package.json文件中可以看出,项目的基本依赖主要有如下几个:

"dependencies": {
  "chalk": "^1.1.3","co": "^4.6.0","co-prompt": "^1.0.0","commander": "^2.9.0","ora": "^0.4.1"
}

chalk:给命令行输出添加颜色

co:执行generator函数

co-prompt:用于命令行交互

commander:定义命令行操作和执行指定的命令

ora:一个很有趣的命令行loading动画

定义命令

命令的基本定义主要是在reactGenerator中,了解该文件之前,请确保自己对commander这个库有基本的了解,不了解的同学请自行前往github
下面就是reactGenerator的完整内容:

#!/usr/bin/env node

const program = require('commander')
const package = require('../package')

// 定义版本号
program.version(package.version)

// 定义使用的方法
program.usage('<command>')

// 定义脚手架的初始化工作
program
  .command('init')
  .alias('i')
  .description('generator a react project')
  .action(() => {
    require('../commander/init')()
  })

// 解析参数
program.parse(process.argv)

// 如果没有输入命令 显示帮助的内容
if (!program.args.length) {
  program.help()
}

在这个文件中我们只定义一个init操作,当我们全局安装脚手架工具的时候,我们就可以通过如下命令创建我们的项目。

react-to-start init 或者 react-to-start i

其中react-to-start是你在package.jsonbin字段中指定的。

"bin": {
  "react-to-start": "bin/reactGenerator"
}

初始化项目

初始化项目主要使用的是init命令,这个命令的基本定义如下:

const co = require('co')
const chalk = require('chalk')
const prompt = require('co-prompt')
const ora = require('ora')
const fs = require('fs')
const exec = require('child_process').exec
const config = require('../config.json')

const init = () => {
  co(function* () {
    let templateName = yield prompt('what is your template name?  ')
    let projectName =  yield prompt('what is your project name?  ')
    let branchesName = config.branchesName

    if (!branchesName.includes(templateName)) {
      process.stdout.write(chalk.red(`\n ${templateName} does not exit,you can choose one of the template  listed below`))
      branchesName.forEach((name,index) => {
        process.stdout.write(chalk.green(` \n ${index + 1}. ${name} \n`))
      })
      process.exit(1)
    }

    // 如果说有对应的template 拼接git url进行下载
    let git = ''

    fs.exists('./.git',function(exists) {
      if (exists) {
        git = `git clone ${config.templateUrl} ${projectName} && cd ${projectName} && git checkout ${templateName}`
      } else {
        git = `git init && git clone ${config.templateUrl} ${projectName} && cd ${projectName} && git checkout ${templateName}`
      }

      // 使用 ora 打印出 loading + log
      let spinner = ora(`is downloading the template for ${templateName}...`)
      // 开始 loading 动画
      spinner.start()

      exec(git,(error,stdout,stderr) => {
        spinner.stop()
        if (error) {
          console.log(error)
          process.exit()
        }
        process.stdout.write(chalk.green('\n $$$ Generation completed! To use step by step as following: '))
        process.stdout.write(chalk.green(`\n 1. cd ${projectName} `))
        process.stdout.write(chalk.green(`\n 2. npm install \n`))
        process.exit(0)
      })
    })
  })
}

module.exports = init

这个初始化命令的定义十分简单,有点nodejs基础且了解co的同学都会很轻松的读懂,这里就不在多述(感冒好难受的说)。

脚手架配置

脚手架所对应的模板目录就是在上篇文章中所讲的内容,不了解的同学请戳从react-start到co源(一)如下就是配置文件:

{
  "templateUrl": "https://github.com/pavoooo/template.git","branchesName": ["react"]
}

templateUrl就是模板地址(暂存在我的github上),branchesName就是项目的名称,在github中以分支表示。

以上就是脚手架的基本架构,有点头晕,有的地方写的可能有点粗糙。有疑问的同学欢迎留言或者到我的githubissue。晚安。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...
在平时工作中的某些场景下,你可能想在整个组件树中传递数据,但却不想手动地通过 props 属性在每一层传递属性,contextAPI 应用而生。
楼主最近入职新单位了,恰好新单位使用的技术栈是 react,因为之前一直进行的是 vue2/vue3 和小程序开发,对于这些技术栈实现机制也有一些了解,最少面试...
我们上一节了了解了函数式组件和类组件的处理方式,本质就是处理基于 babel 处理后的 type 类型,最后还是要处理虚拟 dom。本小节我们学习下组件的更新机...
前面几节我们学习了解了 react 的渲染机制和生命周期,本节我们正式进入基本面试必考的核心地带 -- diff 算法,了解如何优化和复用 dom 操作的,还有...
我们在之前已经学习过 react 生命周期,但是在 16 版本中 will 类的生命周期进行了废除,虽然依然可以用,但是需要加上 UNSAFE 开头,表示是不安...
上一小节我们学习了 react 中类组件的优化方式,对于 hooks 为主流的函数式编程,react 也提供了优化方式 memo 方法,本小节我们来了解下它的用...
开源不易,感谢你的支持,❤ star me if you like concent ^_^
hel-micro,模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 ,欢迎关注与了解
本文主题围绕concent的setup和react的五把钩子来展开,既然提到了setup就离不开composition api这个关键词,准确的说setup是由...
ReactsetState的执行是异步还是同步官方文档是这么说的setState()doesnotalwaysimmediatelyupdatethecomponent.Itmaybatchordefertheupdateuntillater.Thismakesreadingthis.staterightaftercallingsetState()apotentialpitfall.Instead,usecom