阅读本文需要 7 分钟,编写本文耗时 2.5 小时。
其实现代前端框架的本质就是一个使用 js 编写的 node 命令行工具(cli)
比如 umi、 react-script、vue-cli、ng、ionic 等,我们在使用他们进行项目开发的时候,都是使用如 umi dev
的命令去启动我们的开发服务,这里有两个关键字,“启动” 和 “服务”。
关于开发服务,我们会在明天的内容中说明,今天我先简单的介绍一下 cli 的开发过程。
使用 node 执行 js
新建一个 js 文件 src/index.js
console.log('Hello Malita!'); 复制代码
在终端中执行 node src/index.js
。
Hello Malia! 复制代码
我们可以看到在控制态中打印了 Hello Malia!
。
使用命令
每次执行都要输入 node src/index.js
有些太长了,而且有时候文件名字取的复杂了,也很不好记忆,因此我们可以在 package.json
中增加使用脚本入口 scripts
。
"scripts": { "hello": "node src/index.js" }, 复制代码
这样我们只需要在终端中使用 npm run hello
的命令,就相当于 node src/index.js
。
值得注意的是 hello
只是我们取的速记别名,你可以使用任意的别名,所以在使用 scripts
的时候,我们需要关注的是别名真正对应的脚本。
这个是在当前项目中有效的命令,那如果是不在当前项目中的命令,而是在第三方依赖中的命令的话,又该如何声明呢?
声明自己的命令
声明命令不是什么黑魔法,这就是 node 的用法说明,只要在 package.json
里面配置上 bin
属性就可以实现。
"bin": { "malita": "./bin/malita.js" }, 复制代码
编写 bin/malita.js
注意开头要添加脚本的解释程序,比如我们这里使用的是 node
#!/usr/bin/env node console.log('Hello Malia!') 复制代码
bin
中配置的 malita
就是我们提供给其他用户的命令速记符号。
这个“速记符”是提供给其他用户使用的,我们本地开发的时候,可以使用 package.json
的 scripts
中的命令即可。
使用 link 调试
bin
声明的命令需要被安装到 node_modules
的 .bin
目录下才能找到,比如我们在当前项目直接执行 malita
会提示我们 sh: malita: command not found
。
因此我们可以新建一个测试仓库,来关联测试。
$ mkdir examples/app $ cd examples/app $ npm init -y $ npm link malita $ npx malita Hello Malia! 复制代码
npx 是 npm 自带的一个工具,它会自动查找当前依赖包中的可执行文件,如果没找到,就会找你全局安装的命令,如果还是没找到,那它就会从远程服务器上下载你需要的依赖。
如果你按上面的步骤执行,看到控制台有正确打印,说明你的配置都是正确的。这样你就可以继续阅读下面的内容了。
使用 pnpm monorepo 自动 link
平时开发测试都要手动 link 比较麻烦,有时候还容易忘记执行 link,而且由于 link 的绑定与你执行 link 的目录相关的。像我有个同名包,有多个版本的本地仓库,我经常忘记我当前 link 的哪个仓库。所以我们需要引入一种新的方式,来帮助我们自动执行 link,我们称之为 workspace
。
我们使用最近比较流行的 pnpm 来完成。
你可以通过命令安装 pnpm
curl -fsSL https://get.pnpm.io/install.sh | PNPM_VERSION=7.0.0-rc.2 sh - 复制代码
更多安装方法,请查看 pnpm 官网
新建配置文件 pnpm-workspace.yaml
packages: - 'packages/*' - 'examples/*' 复制代码
声明我们的 packages
和 examples
下的包,都是我们的 workspace
。在这里面的所有子包,都可以被整个工作区中的其他包引用。 就算 npm 上不存在我们的子包,只要我们的工作区内存在,就不会出现找不到子包的问题。 还有一个好处就是不管 npm 上我们的子包是什么版本,开发的时候,我们都可以直接使用我们本地的代码。
不像单包管理那样,还要等子包修改完,编译构建上传到 npm 之后,我们再下载使用它。
新建 packages/malita
文件夹,将我们前面创建的 bin
、src
、package.json
移动到这里面。
修改根目录下的 package.json
,增加 "private": true,
。
在 examples/app
中使用 malita
{ "name": "@examples/app", "scripts": { "start": "malita" }, "dependencies": { "malita": "workspace:*" } } 复制代码
然后在根目录下执行安装,并启动用例,查看效果
$ pnpm i // 等待安装完成 $ cd examples/app $ pnpm start Hello Malia! 复制代码
如果控制台成功打印,那说明你前面的步骤都正确执行了。
到此处,你应该要很清晰的知道,上面这个打印是如何被执行的,如果你有疑问或者疑惑,建议你再回头看看文章,或者在评论区讨论
编写帮助命令
前面讲了这么多,只是为了让读者清晰的知道整个代码逻辑是如何被执行的,从现在开始我们才真正的进入框架的开发工作中。
命令行开发毕竟不是我们的重点,所以这里我们使用一个 完成的 node 命令行解决方案 commander.js
commander
$ cd packages/malita/ $ pnpm i commander dependencies: + commander 9.1.0 复制代码
编写我们的入口文件 bin/malita.js
#!/usr/bin/env node const { program } = require('commander'); program .version(require('../package.json').version, '-v, -V', '输出当前框架的版本') .description('这是21天短文,挑战手写前端框架的产物框架') .usage('<command> [options]') .parse(process.argv) 复制代码
在用例中执行
$ cd examples/app $ npx malita -V 0.0.1 复制代码
增加 help 命令
program.command('help') .alias('-h') .description('帮助命令') .action(function(name, other) { console.log(` 这是21天短文,挑战手写前端框架的产物框架 malita 支持的命令: version, -v,-V 输出当前框架的版本 help,-h 输出帮助程序 Example call: $ malita <command> --help`) }).parse(process.argv); 复制代码
在用例中执行
$ cd examples/app $ npx malita help 这是21天短文,挑战手写前端框架的产物框架 malita 支持的命令: version, -v,-V 输出当前框架的版本 help,-h 输出帮助程序 Example call: $ malita <command> --help 复制代码
将新的框架版本发布到 npm 上
$ cd packages/malita $ npm publish npm ERR! code E403 npm ERR! 403 403 Forbidden - PUT https://registry.npmjs.org/malita - You cannot publish over the previously published versions: 0.0.1. 复制代码
这个错误是说已经存在一个这个版本的包了,npm 上的包的每一次更新都需要对应一次版本号的提升,所以我们修改 packages/malita/package.json
中的 "version": "0.0.2",
之后再次执行发包
$ cd packages/malita $ npm publish npm notice npm notice 📦 malita@0.0.2 npm notice === Tarball Contents === npm notice 705B bin/malita.js npm notice 581B package.json npm notice 32B src/index.js npm notice === Tarball Details === npm notice name: malita npm notice version: 0.0.2 npm notice filename: malita-0.0.2.tgz npm notice package size: 800 B npm notice unpacked size: 1.3 kB npm notice shasum: 60c926f7714570a9a5228179d5a3df383680bc70 npm notice integrity: sha512-VifOKdtdspHlS[...]dyA+jFEwR9Nhw== npm notice total files: 3 npm notice + malita@0.0.2 复制代码
到这里,你就成功的在 npm 上发布了一个拥有一个 help 命令的 cli 工具了,后续我们会完善它,使它成为一个基本可用的前端框架。
本篇文章旨在帮助你了解前端框架命令的执行流程,这在你遇到 Bug ,需要定位问题的时候,你就能有一个很清晰的定位步骤。 当你知道它是如何执行的,你甚至可以根据这个思路,去阅读你现在项目中所使用的前端框架的源码,比如 vue-cli 或者 umi。
今天的内容就到这里了,明天就会真正进入我们的框架开发工作中。前期我总共花了 4 天的篇幅来详细的说明了,编写框架的基础知识,有大部分的内容都属于常识性的知识点。 正所谓磨刀不误砍柴工,希望这些简单常识,对你有所帮助。
感谢观看,如果你有任何疑问,欢迎在评论区和我互动。