用Node.js如何实现自动生成依赖,具体怎么做
Admin 2022-07-28 群英技术资讯 959 次浏览
这篇文章主要介绍了用Node.js如何实现自动生成依赖,具体怎么做相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇用Node.js如何实现自动生成依赖,具体怎么做文章都会有所收获,下面我们一起来看看吧。
imgcook 在淘宝内部版本提供了类似依赖管理的功能,用于在 imgcook 编辑器编写函数时引入其他依赖包,比如 axios、underscore、@rax/video 等。

不过从使用体验上,还是较为繁琐,因为编辑器并没有让大家形成像在 package.json 声明依赖的习惯,而且因为编辑器是 GUI 界面,所以从每个函数打开代码,并查看依赖的操作是比较繁琐的,这就导致每次开发完一个 imgcook 模块后,如果依赖了其他包(大部分情况下都需要),就需要一个个打开函数并确认版本号,并在依赖管理中添加,这在我使用的过程中,往往是一次痛苦的过程。
imgcook 提供了 Schema 源码开发模式,通过在编辑器中直接修改模块协议(Schema)就能替代 GUI 的操作步骤,然后通过搜索 dependencies,我发现依赖管理功能是通过协议中的 imgcook.dependencies 实现的:
{
"alias": "Axios",
"packageRax1": "axios",
"versionRax1": "^0.24.0",
"packageRaxEagle": "axios",
"versionRaxEagle": "^0.24.0",
"checkDepence": true
}由于函数的代码也存在协议中,那么是不是只需通过处理原协议文档,扫描出对应的依赖并保存到节点中,再点击“保存”就可以看到依赖管理中的包列表被更新了。
为此我在 @imgcook/cli 中实现了拉取模块协议内容的功能,具体 Pull Request 有:imgcook/imgcook-cli#12 和 imgcook/imgcook-cli#15,可以通过命令行工具拉取对应模块的协议(Schema)如下:
$ imgcook pull <id> -o json
执行后会把模块协议内容输出到命令行中的 stdout。
有了这个功能后,就可以实现一些命令行工具,基于 Unix Pipeline 程序,与 imgcook-cli 的数据源形成协作,举个例子,通过 imgcook pull 输出的 JSON 并不易读,那么不妨写一个 imgcook-prettyprint 来美化输出结果,代码实现如下:
#!/usr/bin/env node
let originJson = '';
process.stdin.on('data', (buf) => {
originJson += buf.toString('utf8');
});
process.stdin.on('end', () => {
const origin = JSON.parse(originJson);
console.log(JSON.stringify(origin, null, 2));
});上面的程序通过 process.stdin 接收管线(Pipeline)上游的数据,即 imgcook 模块协议内容,然后在 end 事件中解析并美化输出,运行如下命令:
$ imgcook pull <id> -o json | imgcook-prettyprint
就能看到美化后的输出结果了,这就是一个 Unix Pipeline 程序的简单示例。
接下来就来看下如何通过这种方式,完成依赖的自动生成。与上面例子类似,我们再创建一个文件 ckdeps:
#!/usr/bin/env node
let originJson = '';
process.stdin.on('data', (buf) => {
originJson += buf.toString('utf8');
});
process.stdin.on('end', () => {
transform();
});
async function transform() {
const origin = JSON.parse(originJson);
const funcs = origin.imgcook?.functions || [];
if (funcs.length === 0) {
process.stdout.write(originJson);
return;
}
console.log(JSON.stringify(origin));
}通过 origin.imgcook.functions,可以获取到函数的代码内容,比如:
{
"content": "export default function mounted() {\n\n}",
"name": "mounted",
"type": "lifeCycles"
}那么接下来就是通过解析 content,获取到代码中的 import 语句,再生成对应的依赖对象到 origin.imgcook.dependencies 中,那么我们需要引用 @swc/core 来解析 JavaScript 代码:
const swc = require('@swc/core');
await Promise.all(funcs.map(async ({ content }) => {
const ast = await swc.parse(content);
// the module AST(Abstract Syntax Tree)
}));获取到 ast 后,就能通过代码获取 import 语句的信息了,不过由于 ast 比较复杂,@swc/core 提供了专用的遍历机制如下:
const { Visitor } = require('@swc/core/visitor');
/**
* 用于保存通过函数解析, 获得的依赖对象列表
*/
const liveDependencies = [];
/** * 定义访问器 */
class ImportsExtractor extends Visitor {
visitImportDeclaration(node) {
let alias = 'Default';
liveDependencies.push({
alias,
packageRax1: node.source.value,
versionRax1: '',
packageRaxEagle: node.source.value,
versionRaxEagle: '',
checkDepence: true,
});
return node;
}
}
// 使用方式
const importsExtractor = new ImportsExtractor();
importsExtractor.visitModule(ast);类 ImportsExtractor 继承自 @swc/core/visitor 的 Visitor,由于是要遍历 import 声明语句,它的语法类型名称是 ImportDeclaration,因此只需要实现 visitImportDeclaration(node) 方法,即可在方法内获得所有的 import 语句,再按照对应节点的结构转换成依赖对象并更新就好。定义好抽取器后,剩下的事情就是把 ast 喂给抽取器,这样就能把模块所有的依赖都收集起来,用于后面依赖的生成。
从上面的代码可以看到,版本号目前使用了空字符串,这会导致我们如果更新协议内容,依赖的版本信息会丢失,因此我们需要定义一种获取版本的方法。
由于前端的依赖都是存储在 NPM Registry 上的,因此我们可以通过 HTTP 接口来获取版本,比如:
const axios = require('axios');
async function fillVersions(dep) {
const pkgJson = await axios.get(`https://registry.npmjs.org/${dep.packageRax1}`, { type: 'json' });
if (pkgJson.data['dist-tags']) {
const latestVersion = pkgJson.data['dist-tags'].latest;
dep.versionRax1 = `^${latestVersion}`;
dep.versionRaxEagle = `^${latestVersion}`;
}
return dep;
}我们按照 https://registry.npmjs.org/${packageName} 的规则,就能拿到存储在 Registry 中的包信息,然后 data['dist-tags'].latest 代表的是 latest 标签对应的版本,简单来说就是当前包的最新版本,然后再基于这个版本号增加一个 ^ 版本前缀即可(你也可以按照自己的诉求修改最终的版本以及 NPM Registry)。
最后一步,就是把我们从函数代码中抓取的依赖信息更新,并输出出来:
async function transform() {
// ...
origin.imgcook.dependencies = newDeps;
console.log(JSON.stringify(origin));
}然后通过运行:
$ imgcook pull <id> -o json | ckdeps
> { ..., "dependencies": [{ ...<updated dependencies> }] }然后,开发者只需要把输出的 JSON 拷贝到编辑器中保存。哦,等等,在编辑器中并不能直接使用 JSON 保存,而是需要使用 ECMAScript Module 的方式(export default { ... }),那这样是不是意味着每次都需要手动编辑一下呢,答案是否,Unix Pipeline 的思路非常利于解决这种流程问题,我们只需要再新建一个节点脚本 imgcook-save 即可:
#!/usr/bin/env node
let originJson = '';
process.stdin.on('data', (buf) => {
originJson += buf.toString('utf8');
});
process.stdin.on('end', () => {
transform();
});
async function transform() {
const origin = JSON.parse(originJson);
console.log(`export default ${JSON.stringify(origin, null, 2)}`);
}最后完整的命令是:
$ imgcook pull <id> -o json | ckdeps | imgcook-save
> export default { ... }这样,我们就可以直接拷贝内容到编辑器。

比如,我在喔其中一个项目的 created 函数中增加了 axios 的依赖,关闭窗口后点击保存(确保 Schema 保存),然后通过命令:
$ imgcook pull <id> -o json | ckdeps -f | imgcook-save
然后在编辑器中打开 Schema 编辑,复制生成的内容并保存,然后打开“依赖管理”可以看到:

通过解析生成的代码已经更新到依赖面板了,这下终于可以解放双手,去做其他的事情了。
是不是这样就结束了呢?在 macOS 中,提供了 pbcopy 命令,可以复制 stdin 到剪贴板,那么跟 imgcook 的例子结合一下:
$ imgcook pull <id> -o json | ckdeps | imgcook-save | pbcopy
这样就省掉了自己拷贝的工作,命令执行完直接打开编辑器 ⌘V 即可。
最后的最后,我要升华一下主题,在 @imgcook/cli 支持了输出 JSON 文本的功能后,就意味着 imgcook 接入了 Unix Pipeline 的生态,通过这种方式,我们可以在这个过程中构建很多有趣实用的工具,并与很多 Unix 工具协作使用(比如 bpcopy、grep、cat、sort 等)。
本文只是通过依赖的自动生成为例,使用 Unix Pipeline 的方式,验证了其可行性以及和 imgcook 编辑器配合使用的体验,目前来说,我可以通过这种方式,弥补不少编辑器上的体验缺失,让我更方便地使用 imgcook 的核心功能。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
node的异步机制是基于“事件”的,所有的I/O、网络通信、数据库查询都以非阻塞的方式执行,返回结果由事件循环来处理。Node在同一时刻只会处理一个事件,完成后立即进入事件循环检查后面事件。这样CPU和内存在同一时间集中处理一件事,同时尽量让耗时的I/O等操作并行执行。
Nodejs中怎么操作文件?下面本篇文章带大家聊聊怎么使用Nodejs读写文件,希望对大家有所帮助!
Webpack是一款模块打包工具。它为不同的依赖创建模块,将其整体打包成可管理的输出文件。这一点对于单页面应用(如今Web应用的事实标准)来说特别有用。
本文主要介绍了TypeScript 接口继承的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
这篇文章给大家分享的是vue实现购物车全选反选功能的方法。小编觉得挺实用的,因此分享给大家做个参考,文中示例代码介绍的非常详细,感兴趣的朋友接下来一起跟随小编看看吧。
成为群英会员,开启智能安全云计算之旅
立即注册Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008