Heim  >  Artikel  >  Web-Frontend  >  Eine kurze Analyse, wie Node.js + imgcook automatisch Abhängigkeiten generiert

Eine kurze Analyse, wie Node.js + imgcook automatisch Abhängigkeiten generiert

青灯夜游
青灯夜游nach vorne
2021-12-01 19:33:442499Durchsuche

Wie verwende ich Node.js, um imgcook bei der automatischen Generierung von Abhängigkeiten zu unterstützen? Der folgende Artikel stellt Ihnen die Generierungsmethode vor. Sie hat einen gewissen Referenzwert und ich hoffe, dass sie Ihnen hilfreich sein wird!

Eine kurze Analyse, wie Node.js + imgcook automatisch Abhängigkeiten generiert

imgcook stellt in der internen Version von Taobao eine Abhängigkeitsverwaltungsfunktion bereit, mit der beim Schreiben von Funktionen im imgcook-Editor andere Abhängigkeitspakete wie Axios, Underscore, @rax/video usw. eingeführt werden.

Eine kurze Analyse, wie Node.js + imgcook automatisch Abhängigkeiten generiert

In Bezug auf die Benutzererfahrung ist es jedoch immer noch relativ umständlich, da der Editor nicht zulässt, dass sich jeder an die Deklaration von Abhängigkeiten in package.json gewöhnt, und da der Editor eine GUI-Schnittstelle ist, öffnen Sie den Code Die Überprüfung der Abhängigkeiten von jeder Funktion ist relativ umständlich. Dies bedeutet, dass Sie jedes Mal nach der Entwicklung eines imgcook-Moduls, wenn es von anderen Paketen abhängt (was in den meisten Fällen erforderlich ist), die Funktionen einzeln öffnen und bestätigen müssen die Versionsnummer und führen Sie die Abhängigkeitsverwaltung im Abhängigkeitsmanagement durch. Dies ist oft ein mühsamer Prozess, wenn ich es verwende.

So lösen Sie

imgcook bietet einen Schema-Quellcode-Entwicklungsmodus. Durch direktes Ändern des Modulprotokolls (Schema) können Sie die GUI-Operationsschritte ersetzen Die Funktion wird über das Protokoll implementiert. 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; 
}

Da der Code der Funktion auch im Protokoll vorhanden ist, ist es nur erforderlich, das Originalprotokolldokument zu verarbeiten und das entsprechende auszuscannen Abhängigkeiten und speichern Sie sie im Knoten. Klicken Sie dann auf „Speichern“, um zu sehen, dass die Paketliste in der Abhängigkeitsverwaltung aktualisiert wurde.

Implementieren Sie die Funktion

🎜Dafür bin ich @imgcook/cli🎜 implementiert die Funktion zum Abrufen von Modulprotokollinhalten. Die spezifische Pull-Anfrage lautet: imgcook/imgcook-cli#12🎜 und imgcook/imgcook-cli#15🎜, Sie können das Protokoll (Schema) des entsprechenden Moduls wie folgt über das Befehlszeilentool abrufen: 🎜
async function transform() {   
  // ...   
  origin.imgcook.dependencies = newDeps;   
  console.log(JSON.stringify(origin)); 
}
🎜Execute Der Inhalt des Modulprotokolls wird dann auf der Befehlszeile nach stdout ausgegeben. 🎜🎜Mit dieser Funktion können Sie einige Befehlszeilentools basierend auf dem Unix-Pipeline-Programm implementieren, um mit der Datenquelle von imgcook-cli zusammenzuarbeiten. Beispielsweise ist die JSON-Ausgabe über imgcook pull nicht einfach zu lesen, also können Sie es auch tun Schreiben Sie einen imgcook -prettyprint, um die Ausgabeergebnisse zu verschönern. Der Code wird wie folgt implementiert: 🎜
$ imgcook pull <id> -o json | ckdeps 
> { ..., "dependencies": [{ ... }] }
🎜Das obige Programm empfängt die Upstream-Daten der Pipeline (Pipeline) über process.stdin, d. h imgcook-Modulprotokollinhalt und führen Sie dann im end-Ereignis den folgenden Befehl aus, um die Ausgabe zu analysieren und zu verschönern: 🎜<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>🎜, um die verschönerten Ausgabeergebnisse anzuzeigen. Dies ist ein einfaches Beispiel eines Unix-Pipeline-Programms. 🎜🎜 Schauen wir uns als Nächstes an, wie wir die automatische Generierung von Abhängigkeiten auf diese Weise abschließen können. Ähnlich wie im obigen Beispiel erstellen wir eine weitere Datei ckdeps: 🎜<pre class="brush:js;toolbar:false;">$ imgcook pull &lt;id&gt; -o json | ckdeps | imgcook-save > export default { ... }</pre>🎜Über <code>origin.imgcook.functions können Sie den Codeinhalt der Funktion abrufen, z. B.: 🎜
$ imgcook pull <id> -o json | ckdeps -f | imgcook-save
🎜Dann ist der nächste Schritt Um content zu analysieren, die Importanweisung im Code abzurufen und dann das entsprechende Abhängigkeitsobjekt in origin.imgcook.dependencies zu generieren, müssen wir auf @swc/core verweisen Analysieren Sie den JavaScript-Code: 🎜
$ imgcook pull <id> -o json | ckdeps | imgcook-save | pbcopy
🎜Nachdem Sie ast erhalten haben, können Sie die Informationen zur Importanweisung über den Code abrufen. Da ast jedoch komplexer ist, bietet @swc/core einen dedizierten Durchlaufmechanismus wie folgt: 🎜rrreee🎜Klasse ImportsExtractor erbt vom Visitor von @swc/core/visitor, da es die Importdeklarationsanweisung durchlaufen muss, sein Syntaxtypname ist ImportDeclaration, also muss es nur sein Wenn Sie die Methode visitImportDeclaration(node) implementieren, können Sie alle Importanweisungen in der Methode abrufen und sie dann entsprechend der Struktur der entsprechenden Knoten in abhängige Objekte konvertieren und aktualisieren. Nachdem Sie den Extraktor definiert haben, müssen Sie nur noch ast an den Extraktor weiterleiten, sodass alle Abhängigkeiten des Moduls für die nachfolgende Abhängigkeitsgenerierung gesammelt werden können. 🎜🎜Wie Sie dem obigen Code entnehmen können, verwendet die Versionsnummer derzeit eine leere Zeichenfolge, was dazu führt, dass die abhängigen Versionsinformationen verloren gehen, wenn wir den Protokollinhalt aktualisieren. Daher müssen wir eine Methode definieren, um die Version abzurufen. 🎜🎜Da die Front-End-Abhängigkeiten alle in der NPM-Registrierung gespeichert sind, können wir die Version über die HTTP-Schnittstelle abrufen, wie zum Beispiel: 🎜
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 {   ... }

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

效果体验

Eine kurze Analyse, wie Node.js + imgcook automatisch Abhängigkeiten generiert

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

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

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

Eine kurze Analyse, wie Node.js + imgcook automatisch Abhängigkeiten generiert

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

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 教程!!

Das obige ist der detaillierte Inhalt vonEine kurze Analyse, wie Node.js + imgcook automatisch Abhängigkeiten generiert. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:juejin.cn. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen