Maison  >  Article  >  interface Web  >  Une brève analyse de la façon dont Node.js + imgcook génère automatiquement des dépendances

Une brève analyse de la façon dont Node.js + imgcook génère automatiquement des dépendances

青灯夜游
青灯夜游avant
2021-12-01 19:33:442493parcourir

Comment utiliser Node.js pour aider imgcook à générer automatiquement des dépendances ? L'article suivant vous présentera la méthode de génération. Elle a une certaine valeur de référence et j'espère qu'elle vous sera utile !

Une brève analyse de la façon dont Node.js + imgcook génère automatiquement des dépendances

imgcook fournit une fonction de type gestion des dépendances dans la version interne de Taobao, qui est utilisée pour introduire d'autres packages de dépendances, tels que axios, underscore, @rax/video, etc., lors de l'écriture de fonctions dans l'éditeur imgcook.

Une brève analyse de la façon dont Node.js + imgcook génère automatiquement des dépendances

Cependant, en termes d'expérience utilisateur, cela reste relativement lourd car l'éditeur ne permet pas à tout le monde de prendre l'habitude de déclarer des dépendances dans package.json, et comme l'éditeur est une interface GUI, vous ouvrez le code de chaque fonction et L'opération de vérification des dépendances est relativement lourde. Cela signifie qu'à chaque fois après avoir développé un module imgcook, s'il dépend d'autres packages (ce qui est requis dans la plupart des cas), vous devez ouvrir les fonctions une par une et confirmer. le numéro de version et effectuer la gestion des dépendances dans la gestion des dépendances. C'est souvent un processus pénible lorsque je l'utilise.

Comment résoudre

imgcook propose le mode de développement du code source du schéma. En modifiant directement le protocole du module (Schéma) dans l'éditeur, vous pouvez remplacer les étapes de fonctionnement de l'interface graphique. Ensuite, en recherchant les dépendances, j'ai constaté que la gestion des dépendances. la fonction se fait via le protocole. imgcook.dependencies est implémenté : 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#12imgcook/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 = &#39;&#39;; 
process.stdin.on(&#39;data&#39;, (buf) => {   
  originJson += buf.toString(&#39;utf8&#39;);   
}); 
process.stdin.on(&#39;end&#39;, () => {   
  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 = &#39;&#39;; 
process.stdin.on(&#39;data&#39;, (buf) => {   
  originJson += buf.toString(&#39;utf8&#39;);   
}); 
process.stdin.on(&#39;end&#39;, () => {   
  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(&#39;@swc/core&#39;); 

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(&#39;@swc/core/visitor&#39;); 

/**  
 * 用于保存通过函数解析, 获得的依赖对象列表  
 */ 
const liveDependencies = []; 

/**  * 定义访问器  */ 
class ImportsExtractor extends Visitor {   
  visitImportDeclaration(node) {     
    let alias = &#39;Default&#39;;     
    liveDependencies.push({       
      alias,       
      packageRax1: node.source.value,       
      versionRax1: &#39;&#39;,       
      packageRaxEagle: node.source.value,       
      versionRaxEagle: &#39;&#39;,       
      checkDepence: true,     
    });     
    return node;   
  } 
} 

// 使用方式 
const importsExtractor = new ImportsExtractor(); 
importsExtractor.visitModule(ast);

ImportsExtractor 继承自 @swc/core/visitor 的 Visitor,由于是要遍历 import 声明语句,它的语法类型名称是 ImportDeclaration,因此只需要实现 visitImportDeclaration(node)

const axios = require(&#39;axios&#39;); 
async function fillVersions(dep) {   
  const pkgJson = await axios.get(`https://registry.npmjs.org/${dep.packageRax1}`, { type: &#39;json&#39; });   
  if (pkgJson.data[&#39;dist-tags&#39;]) {     
    const latestVersion = pkgJson.data[&#39;dist-tags&#39;].latest;     
    dep.versionRax1 = `^${latestVersion}`;     
    dep.versionRaxEagle = `^${latestVersion}`;  
  }  
  return dep; 
}

Puisque le code de la fonction existe également dans le protocole, il suffit alors de traiter le document de protocole original, de scanner le correspondant. dépendances et enregistrez-les sur le nœud, puis cliquez sur "Enregistrer" pour voir que la liste des packages dans la gestion des dépendances a été mise à jour.

Implémenter la fonction

🎜Pour cela, je suis @imgcook/cli🎜 implémente la fonction d'extraction du contenu du protocole du module. La Pull Request spécifique est : imgcook/imgcook-cli#12🎜 et imgcook/imgcook-cli#15🎜, vous pouvez extraire le protocole (schéma) du module correspondant via l'outil de ligne de commande comme suit : 🎜
async function transform() {   
  // ...   
  origin.imgcook.dependencies = newDeps;   
  console.log(JSON.stringify(origin)); 
}
🎜Execute Le contenu du protocole du module sera ensuite affiché sur stdout sur la ligne de commande. 🎜🎜Avec cette fonction, vous pouvez implémenter certains outils de ligne de commande basés sur le programme Unix Pipeline pour coopérer avec la source de données d'imgcook-cli. Par exemple, la sortie JSON via imgcook pull n'est pas facile à lire, vous pourriez donc aussi bien. écrivez un imgcook -prettyprint pour embellir les résultats de sortie, le code est implémenté comme suit : 🎜
$ imgcook pull <id> -o json | ckdeps 
> { ..., "dependencies": [{ ... }] }
🎜Le programme ci-dessus reçoit les données en amont du pipeline (Pipeline) via process.stdin, c'est-à-dire le contenu du protocole du module imgcook, puis dans l'événement end pour analyser et embellir la sortie, exécutez la commande suivante : 🎜<pre class="brush:js;toolbar:false;">#!/usr/bin/env node let originJson = &amp;#39;&amp;#39;; process.stdin.on(&amp;#39;data&amp;#39;, (buf) =&gt; { originJson += buf.toString(&amp;#39;utf8&amp;#39;); }); process.stdin.on(&amp;#39;end&amp;#39;, () =&gt; { transform(); }); async function transform() { const origin = JSON.parse(originJson); console.log(`export default ${JSON.stringify(origin, null, 2)}`); }</pre>🎜 pour voir les résultats de sortie embellis. Il s'agit d'un exemple simple d'un programme de pipeline Unix. 🎜🎜 Voyons ensuite comment réaliser la génération automatique des dépendances de cette manière. Semblable à l'exemple ci-dessus, nous créons un autre fichier ckdeps : 🎜<pre class="brush:js;toolbar:false;">$ imgcook pull &lt;id&gt; -o json | ckdeps | imgcook-save > export default { ... }</pre>🎜Grâce à <code>origin.imgcook.functions, vous pouvez obtenir le contenu du code de la fonction, tel que : 🎜
$ imgcook pull <id> -o json | ckdeps -f | imgcook-save
🎜Ensuite, l'étape suivante est pour analyser content, obtenir l'instruction d'importation dans le code, puis générer l'objet de dépendance correspondant dans origin.imgcook.dependencies, nous devons alors référencer @swc/core pour analysez le code JavaScript : 🎜
$ imgcook pull <id> -o json | ckdeps | imgcook-save | pbcopy
🎜Après avoir obtenu ast, vous pouvez obtenir les informations de l'instruction d'importation via le code. Cependant, comme ast est plus complexe, @swc/core fournit un mécanisme de traversée dédié comme suit : 🎜rrreee🎜Class ImportsExtractor. hérite du Visitor de @swc/core/visitor, car il doit parcourir l'instruction de déclaration d'importation, son nom de type de syntaxe est ImportDeclaration, il n'a donc besoin que de implémentez la méthode visitImportDeclaration(node) , vous pouvez obtenir toutes les instructions d'importation dans la méthode, puis les convertir en objets dépendants en fonction de la structure des nœuds correspondants et les mettre à jour. Après avoir défini l'extracteur, il ne reste plus qu'à alimenter l'extracteur, afin que toutes les dépendances du module puissent être collectées pour la génération ultérieure des dépendances. 🎜🎜Comme vous pouvez le voir dans le code ci-dessus, le numéro de version utilise actuellement une chaîne vide, ce qui entraînera la perte des informations de version dépendantes si nous mettons à jour le contenu du protocole, nous devons donc définir une méthode pour obtenir la version. 🎜🎜Étant donné que les dépendances frontales sont toutes stockées sur NPM Registry, nous pouvons obtenir la version via l'interface HTTP, telle que : 🎜
const axios = require(&#39;axios&#39;); 
async function fillVersions(dep) {   
  const pkgJson = await axios.get(`https://registry.npmjs.org/${dep.packageRax1}`, { type: &#39;json&#39; });   
  if (pkgJson.data[&#39;dist-tags&#39;]) {     
    const latestVersion = pkgJson.data[&#39;dist-tags&#39;].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": [{ ... }] }

然后,开发者只需要把输出的 JSON 拷贝到编辑器中保存。哦,等等,在编辑器中并不能直接使用 JSON 保存,而是需要使用 ECMAScript Module 的方式(export default { ... }),那这样是不是意味着每次都需要手动编辑一下呢,答案是否,Unix Pipeline 的思路非常利于解决这种流程问题,我们只需要再新建一个节点脚本 imgcook-save 即可:

#!/usr/bin/env node 
let originJson = &#39;&#39;; 
process.stdin.on(&#39;data&#39;, (buf) => {  
  originJson += buf.toString(&#39;utf8&#39;);  
}); 
process.stdin.on(&#39;end&#39;, () => {  
  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 {   ... }

这样,我们就可以直接拷贝内容到编辑器。

效果体验

Une brève analyse de la façon dont Node.js + imgcook génère automatiquement des dépendances

比如,我在喔其中一个项目的 created 函数中增加了 axios 的依赖,关闭窗口后点击保存(确保 Schema 保存),然后通过命令:

$ imgcook pull <id> -o json | ckdeps -f | imgcook-save

然后在编辑器中打开 Schema 编辑,复制生成的内容并保存,然后打开“依赖管理”可以看到:

Une brève analyse de la façon dont Node.js + imgcook génère automatiquement des dépendances

通过解析生成的代码已经更新到依赖面板了,这下终于可以解放双手,去做其他的事情了。

One more thing?

是不是这样就结束了呢?在 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 的核心功能。

更多node相关知识,请访问:nodejs 教程!!

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer