npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

cy-react-native-cli

v1.2.0

Published

创建 react-native 项目的 cli 工具

Readme

1. 说明

创意 react-native 项目生成器 根据官方的 react-native init AwesomeProject 生成项目,集成mobx,react-native-router-flux路由,react-native-root-toast弹窗.

可选安装列表:

'react-native-syan-image-picker(图片选择,拍照)',

'react-native-general-actionsheet',

2. 使用

安装: npm i cy-react-native-cli -g
使用: cy init <projectName>
卸载: npm uninstall cy-react-native-cli -g

3. 开发

  1. 如果你有安装过,先卸载全局包,否则会冲突 npm uninstall cy-react-native-cli -g
  2. 使用 npm i 安装依赖
  3. 运行 npm link
  4. 运行 npm run nodemon,目录自行替换,最好选择其他盘符.如果在当前目录下测试会因为生成的文件夹里有 .git 导致本项目 git diff 被污染.

3.1. commit 规范

standard-version 是一个版本和 changelog 自动化工具,请先安装

npm install -g standard-version

你的 commit 信息应该遵循 Angular 规范,形如

feat: 增加 -y 跳过询问

feat 可以被替换为以下的几种类型选项:

feat: 新增feature
fix: 修复bug
docs: 仅仅修改了文档,比如README, CHANGELOG, CONTRIBUTE等等
style: 仅仅修改了空格、格式缩进、逗号等等,不改变代码逻辑
refactor: 代码重构,没有加新功能或者修复bug
perf: 优化相关,比如提升性能、体验
test: 测试用例,包括单元测试、集成测试等
build: 构建系统或者包依赖更新
ci: CI 配置,脚本文件等更新
chore: 改变构建流程、或者增加依赖库、工具等
revert: 回滚到上一个版本

如果你记不住这么多类型,也可以安装commitizen,用 git cz 取代 git commit

当你的 commit 信息符合规范, standard-version 才会根据 commit 自动生成 CHANGELOG.md 版本变动信息

3.2. script 说明

"nodemon": 进入一个不相干的目录,使用 nodemon 执行入口文件,并监听文件变动自动刷新.注意: 在 nodemon 的环境下不能使用 inquirer 的交互
"publish": 发布 npm 包
"git-push": "git push --follow-tags origin --all", push 所有分支和 tag
"minor": "standard-version -r minor",   生成一个次要版本. 1.0.0 => 1.1.0
"patch": "standard-version -r patch"    生成一个小版本. 1.0.0 => 1.0.1

4. 实现方式

在这之前你应该先阅读基于node.js的脚手架工具开发经历,明白node工程下package.json中的bin字段可以定义命令名和关联执行文件,了解命令行交互的基本原理.

4.1. 让命令全局执行

nodejs内置了对命令行操作的支持,node工程下package.json中的bin字段可以定义命令名和关联的执行文件。

  "bin": {
    "cy-cli": "./bin/www.js",
    "cy": "./bin/www.js"
  },
  

经过这样配置的nodejs项目,在使用-g选项进行全局安装的时候,会自动在系统的[prefix]/bin目录下创建相应的符号链接(symlink)关联到执行文件。如果是本地安装,这个符号链接会生成在./node_modules/.bin目录下。这样做的好处是可以直接在终端中像执行命令一样执行nodejs文件。关于prefix,可以通过npm config get prefix获取。 在 www.js 编写入口逻辑

    #!/usr/bin/env node
    
    require('../src/index')()
    

注意这里 #!/usr/bin/env node 必须放在首行,有空格空行都不行.在当前的目录下执行 npm link,将 cy 和 cy-cli 命令链接到全局环境。接着打开其他不相干的盘符目录如 g:\Temp\tttttttttttemp,执行 cy 即可执行 src/index.js 开始开发.你也可以执行我写好的脚本 npm run nodemon,目录自行替换

4.2. 生成项目,获取模版

接下来是利用 commander 来处理命令行,inquire 提问,相关使用方式可参见前面提到的文章.

模版/template并不是一整个固定的项目,而是项目的部分文件. 固定模版将难以更新 react-native 版本,为了获取到最新版的 react-native,我们需要先通过 npx react-native init [projectName] 拉取最新的 react-native 项目,然后把/template的内容增量替换原文件. 这样做的坏处是模版文件不够直观,编辑器会不认模版语法 <% %>.如果你也使用 JetBrains 系编辑器,可以在/template右键 => Mark Directory as => Excluded 让编辑器忽略语法检查

具体流程:

  1. 询问一些项目基本情况,选择要集成的插件,并将这些信息通过 Promise链 传递下去.
  2. 通过 download-git-repo 下载自己写的模版,用于替换官方的 react-native 项目.出于开发的考虑我用的是 src/template 下的本地模版,这样不用每次都去下载文件.
  3. 通过 npx react-native init [projectName] 拉取最新的 react-native 项目.
  4. git 仓库创建,并提交一个 init 的 commit.这么做可以直观看到我们对原始项目的改动
  5. 修改 package.jsonscripts,添加一些常用脚本.
  6. 安装必装依赖项(路由等)和第一步的可选插件

4.3. 使用 metalsmith + ejs 处理模板

现在我们需要在 react-native 原始项目的基础上替换模版,工具是metalsmith . 它最大的一个特点就是 EVERYTHING IS PLUGIN,所以,metalsmith本质上就是一个胶水框架,通过黏合各种插件来完成生产工作。

    const metalsmith = Metalsmith(process.cwd())
        .metadata(metadata)
        .clean(false)
        .source(src)
        .destination(dest)
        // 复制动态路径里的内容
        .use(copyDynamicPathFile(src))
        // 移除 template.ignore 中列出的文件
        .use(removeIgnore(src))
        

这段代码很好理解: 初始化 metalsmith,传入需要的参数 metadata,读取源目录中的所有文件,定义输出目录,接着调用一系列操作文件的插件.

4.4. 插件 - copyDynamicPathFile

react-native 会根据你的项目名生成动态路径如 android\app\src\main\java\com\rn61test\MainApplication.java,这里的rn61test就是你的项目名. 所以我们不能在 template 下直接建立对应的文件替换

return async function (files, metalsmith, done) {
    const meta = metalsmith.metadata()
    const dynamicPath = 'dynamicPathFile\\'

    // 复制 java 相关
    let mainActivityJava = files[dynamicPath + 'MainActivity.java']
    let mainApplicationJava = files[dynamicPath + 'MainApplication.java']

    mainActivityJava && (files['android\\app\\src\\main\\java\\com\\' + meta.projectName + '\\MainActivity.java'] = mainActivityJava)
    mainApplicationJava && (files['android\\app\\src\\main\\java\\com\\' + meta.projectName + '\\MainApplication.java'] = mainApplicationJava)

    done()
}

获取文件内容,在 files 中添加对应文件,非常简单

4.5. 插件 - removeIgnore

templates.ignore 中定义需要移除的文件,调用插件对所有文件匹配,匹配成功则移除. 目前我只实现了 文件/文件夹 的移除,注释.

4.6. ejs 编译文件

let {render} = require('consolidate').ejs

// ...
        .use((files, metalsmith, done) => {
            const meta = metalsmith.metadata()
            Object.keys(files).forEach(async fileName => {

                // 指定格式的文件才用模版编译
                let reg = new RegExp(/\.(js|md|json|gradle|xml|java|plist|m|h)/)
                let content = files[fileName].contents.toString() // 获取文件中的内容

                if (reg.test(fileName)) {
                    if (content.includes('<%')) { // 文件中用<% 我才需要编译
                        // console.log(fileName + ' --- 编译中')
                        content = await render(content, meta) // 用数据渲染模板
                        files[fileName].contents = Buffer.from(content) // 渲染好的结果替换即可
                    }
                }

            })
            done()
        })
        .build(err => {
            err ? reject(err) : resolve(context)
        })

4.7. 参考文档

5. 模版文件

要了解模版文件的改变👉 template/README.md

6. Babel

目前 babel 版本是 7,安装下面的包:

npm i @babel/core @babel/cli @babel/preset-env @babel/node @babel/core -D
npm i core-js regenerator-runtime

index.js加上

import "core-js/stable";
import "regenerator-runtime/runtime";

script 添加脚本

"watch": "npm run compile -- --watch",
"nodemon": "g: && cd g:\\Temp\\tttttttttttemp && cross-env NODE_ENV=development nodemon  --ignore E:\\enzo\\code\\android\\cy-cli\\temp\\*  --watch E:\\enzo\\code\\android\\cy-cli\\* E:\\enzo\\code\\android\\cy-cli\\bin\\www.js init aaa -y",

www.js 入口改成

#!/usr/bin/env node
require('../dist/index')()

babel 配置有问题,开发时要同时开启 watch 编译,nodemon 重启服务.效率比较低.所以没启用

7. TODO

增加自动升级 package.json/android/ios 版本号,并根据 git commit 信息生成 CHANGELOG.md

修改为插件化开发,可参考

8. 其他工具

美化我们的脚手架

  • ora - 显示spinner
  • chalk - 给枯燥的终端界面添加一些色彩

9. License

MIT