Home > Web Front-end > JS Tutorial > body text

A brief analysis of how Node.js + imgcook automatically generates dependencies

青灯夜游
Release: 2021-12-01 19:33:44
forward
2473 people have browsed it

How to use Node.js Assist imgcook to automatically generate dependencies? The following article will introduce you to the generation method. It has certain reference value and I hope it will be helpful to you!

A brief analysis of how Node.js + imgcook automatically generates dependencies

imgcook provides a dependency management-like function in the internal version of Taobao, which is used to introduce other dependency packages when writing functions in the imgcook editor, such as axios, underscore, @rax/ video etc.

A brief analysis of how Node.js + imgcook automatically generates dependencies

However, in terms of user experience, it is still relatively cumbersome because the editor does not allow everyone to form the habit of declaring dependencies in package.json, and because the editor is a GUI interface , so it is relatively cumbersome to open the code from each function and check the dependencies. This means that every time after developing an imgcook module, if it depends on other packages (required in most cases), you need to open them one by one. Function and confirm the version number and add it in dependency management. This is often a painful process when I use it.

How to solve

imgcook provides Schema source code development mode. By directly modifying the module protocol (Schema) in the editor, you can replace the GUI operation steps, and then through Searching for dependencies, I found that the dependency management function is implemented through imgcook.dependencies in the protocol:

{
  "alias": "Axios",   
  "packageRax1": "axios",
  "versionRax1": "^0.24.0",
  "packageRaxEagle": "axios",   
  "versionRaxEagle": "^0.24.0",   
  "checkDepence": true 
}
Copy after login

Since the code of the function also exists in the protocol, does it only need to process the original protocol? document, scan out the corresponding dependencies and save them to the node, then click "Save" to see that the package list in dependency management has been updated.

Implementation function

To this end, I implemented the function of pulling module protocol content in @imgcook/cli. The specific Pull Request is: imgcook/imgcook-cli#12 and imgcook/imgcook-cli#15, you can use the command line tool to pull the protocol (Schema) of the corresponding module as follows:

$ imgcook pull <id> -o json
Copy after login

After execution, the module protocol content will be output to stdout on the command line.

With this function, some command line tools can be implemented, based on the Unix Pipeline program, to cooperate with the data source of imgcook-cli. For example, the JSON output through imgcook pull is not easy to read, then You might as well write an imgcook-prettyprint to beautify the output results. The code is implemented as follows:

#!/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)); 
});
Copy after login

The above program receives the upstream data of the pipeline (Pipeline) through process.stdin, which is the imgcook module protocol content. Then parse and beautify the output in the end event. Run the following command:

$ imgcook pull <id> -o json | imgcook-prettyprint
Copy after login

to see the beautified output. This is a simple example of a Unix Pipeline program.

Next, let’s take a look at how to complete the automatic generation of dependencies in this way. Similar to the above example, we create another file 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)); 
}
Copy after login

Through origin.imgcook.functions, we can get the code content of the function, such as:

{   
  "content": "export default function mounted() {\n\n}",   
  "name": "mounted",   
  "type": "lifeCycles" 
}
Copy after login

Then The next step is to get the import statement in the code by parsing content, and then generate the corresponding dependency object into origin.imgcook.dependencies, then we need to reference @swc/core Parse JavaScript code:

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) 
}));
Copy after login

After obtaining ast, you can obtain the import statement information through the code. However, because ast is more complicated, @swc/core provides a dedicated traversal mechanism as follows:

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);
Copy after login

ClassImportsExtractor inherits from Visitor of @swc/core/visitor. Since it is to traverse the import declaration statement, its syntax type name is ImportDeclaration, so You only need to implement the visitImportDeclaration(node) method to obtain all import statements within the method, and then convert them into dependent objects according to the structure of the corresponding node and update them. After defining the extractor, the only thing left is to feed ast to the extractor, so that all the dependencies of the module can be collected for subsequent dependency generation.

As you can see from the above code, the version number currently uses an empty string, which will cause the dependent version information to be lost if we update the protocol content, so we need to define a method to obtain the version.

Since the front-end dependencies are all stored on NPM Registry, we can obtain the version through the HTTP interface, such as:

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; 
}
Copy after login

我们按照 https://registry.npmjs.org/${packageName} 的规则,就能拿到存储在 Registry 中的包信息,然后 data[&#39;dist-tags&#39;].latest 代表的是 latest 标签对应的版本,简单来说就是当前包的最新版本,然后再基于这个版本号增加一个 ^ 版本前缀即可(你也可以按照自己的诉求修改最终的版本以及 NPM Registry)。

最后一步,就是把我们从函数代码中抓取的依赖信息更新,并输出出来:

async function transform() {   
  // ...   
  origin.imgcook.dependencies = newDeps;   
  console.log(JSON.stringify(origin)); 
}
Copy after login

然后通过运行:

$ imgcook pull <id> -o json | ckdeps 
> { ..., "dependencies": [{ ... }] }
Copy after login

然后,开发者只需要把输出的 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)}`);
}
Copy after login

最后完整的命令是:

$ imgcook pull <id> -o json | ckdeps | imgcook-save 
> export default {   ... }
Copy after login

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

效果体验

A brief analysis of how Node.js + imgcook automatically generates dependencies

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

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

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

A brief analysis of how Node.js + imgcook automatically generates dependencies

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

One more thing?

是不是这样就结束了呢?在 macOS 中,提供了 pbcopy 命令,可以复制 stdin 到剪贴板,那么跟 imgcook 的例子结合一下:

$ imgcook pull <id> -o json | ckdeps | imgcook-save | pbcopy
Copy after login

这样就省掉了自己拷贝的工作,命令执行完直接打开编辑器 ⌘V 即可。

最后的最后,我要升华一下主题,在 @imgcook/cli 支持了输出 JSON 文本的功能后,就意味着 imgcook 接入了 Unix Pipeline 的生态,通过这种方式,我们可以在这个过程中构建很多有趣实用的工具,并与很多 Unix 工具协作使用(比如 bpcopy、grep、cat、sort 等)。

本文只是通过依赖的自动生成为例,使用 Unix Pipeline 的方式,验证了其可行性以及和 imgcook 编辑器配合使用的体验,目前来说,我可以通过这种方式,弥补不少编辑器上的体验缺失,让我更方便地使用 imgcook 的核心功能。

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

The above is the detailed content of A brief analysis of how Node.js + imgcook automatically generates dependencies. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:juejin.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!