@adobe/helix-pipeline

中文文档
18.0.14发布于 2022/02/23Apache-2.0TypeScriptES Module近 30 天下载 2万

此工程为创建超媒体处理管道提供了辅助功能和默认执行.

此软件包已被标记为弃用

no longer supported

中文使用文档
文档目录20 节
  1. 螺旋马克下
  2. 管道解剖
  3. 建设管道
  4. 主要函数
  5. (可选) Wrapper 函数
  6. 处理前函数
  7. 处理后的职能
  8. 处理错误
  9. 扩展点
  10. 背景解剖学
  11. 这个 request 对象
  12. 这个 content 对象
  13. content.document 细节
  14. content.sections 细节
  15. 这个 response 对象
  16. 这个 error 对象
  17. 公用事业
  18. 生成一个虚拟 DOM utils.vdom
  19. 推断内容类型 utils.types
  20. 检查管道上下文

螺旋管

此工程为创建超媒体处理管道提供了辅助功能和默认执行.

它使用还原器和续作来创建一个简单的处理管道,可以进行HTML,JSON等超媒体的处理前和后处理.

目录

状态

codecov CircleCI GitHub license GitHub issues npm Known Vulnerabilities

螺旋马克下

螺旋管支持一些 标记下延。 。 。 .

管道解剖

管道由下列主要部分组成:

  • 预处理功能.
  • 主要响应生成函数.
  • 一个可选的包装功能.
  • 后处理功能.
  • 错误处理函数 .

管道的每个步骤都是处理单个上下文对象,最终可以用来还原http响应.

以下关于上下文的解剖学.

一般情况下,每个支持的内容类型都有一个管线,管线由文件名确定,例如:

  • html.pipe.js - 创建 HTML 文档 text/html 内容类型
  • json.pipe.js - 创建 JSON 文档 application/json 内容类型

建设管道

可以通过创建导出函数的 CommonJS 模块来创建管道构建器 pipe 它接受以下参数并返回管道函数.

  • cont:作为管道的继续而执行的主要功能.
  • context页:1 上下文 (前称有效载荷),是管道中积累的.
  • action页:1 动作 成为额外的管道引用论据的持有者.

这个项目的主要条目为管道建设提供了辅助功能和一些辅助功能,这样就可以建造这样的基本管道:

// the pipeline itself
const pipeline = require("@adobe/hypermedia-pipeline");

module.exports.pipe = function(cont, context, action) {
    action.logger.debug("Constructing Custom Pipeline");

    return pipeline()
        .use(adjustContent)
        .use(cont)            // execute the continuation function
        .use(cleanupContent)
}

在典型的管道中,您将添加额外的处理步骤作为 .use(require('some-module'))。 。 。 .

主要函数

主要功能一般是转换 request 财务报告和审定财务报表 content 属性 context 改为 a response 对象.

在大多数情景中,主要功能都是从HTL,JST,或JSX等诱发语言的模板中编译而来.

通常情况下,文件类型的每个内容变异都有一个模板(并因此有一个主要功能). 内容变化由选择者识别(文件扩展名前的文件名块,如: example.navigation.html 选择者是 navigation) (中文(简体) ). 如果没有提供选择器,模板是管道的默认模板.

可能的模板名称的例子包括:

  • html.jsx (编为: html.js) – HTML 管道默认.
  • html.navigation.jst (编为: html.navigation.js) 使导航.
  • dropdown.json.js (没有编译) – 创建纯JSON输出.
  • dropdown.html.htl (编为: dropdown.html.js– 使降下部分.

(可选) Wrapper 函数

有时需要以模板特定的方式预先处理上下文. 这种包装功能(为简洁起见,常被称作"Pre-JS")可以使管道的上下文完全转变.

相较于处理请求,内容和响应的管道专用预处理功能,包装器功能的焦点是执行主模板功能所需的业务逻辑. 这使得可以将:

  1. 演示文稿(主要功能中,常以声明模板表示).
  2. 商业逻辑(在包装功能中,常以必备代码来表示).
  3. 内容类型的具体实施(在编审中,以功能代码表示).

简单执行一个包接功能就像这样:

// All wrapper functions must export `pre`
// The functions takes the following arguments:
// - `cont` (the continuation function, i.e. the main template function)
// - `context` (the context of the pipeline)
// - `action` (the action of the pipeline)
module.exports.pre = (cont, context, action) => {
    const {request, content, response} = context;
    
    // modifying the context content before invoking the main function
    content.hello = 'World';
    const modifiedcontext = {request, content, response};

    // invoking the main function with the new context. Capturing the response
    // context for further modification

    const responsecontext = cont(modifiedcontext, action);

    // Adding a value to the context response
    const modifiedresponse = modifiedcontext.response;
    modifiedresponse.hello = 'World';

    return Object.assign(modifiedcontext, modifiedresponse);
}

处理前函数

处理前功能意在:

  • 解析和处理请求参数.
  • 获取并解析请求的内容 .
  • 转换请求的内容 .

处理后的职能

处理后的职能旨在:

  • 处理和改变反应.

处理错误

在默认状态下, 管道将处理所有正常的函数, 但会跳过 error handlers (单位:千美元).error()) (中文(简体) ). 当管道在 错误状态 正常处理功能暂停,直到管道结束,或 错误状态 已经清除。 期间 错误状态, (中文(简体) ), 错误处理器 将被执行. 输油管执行在 错误状态 若为 context.error 定义。 一个 错误状态 当处理函数抛出例外时,或者当它设置了例外时,可以发生 context.error 对象直接.

示例

new pipeline()
  .use(doSomething)
  .use(render)
  .use(cleanup)
  .error(handleError)
  .use(done);

如果在上述例子中 doSomething 导致错误,随后, render 财务报告和审定财务报表 cleanup 将不援引。 不过 handleError 会的 若为 handleError 清除错误状态(即设置) context.error = null页:1 done 函数将再次被引用.

如果在上述例子中,没有任何函数造成错误,则 handleError 永远不会被引用.

扩展点

除可在 once 函数,管道创建者可以曝光命名的扩展点. 这些扩展点允许管道的用户在扩展点之前、之后或之后注入额外的功能。 为了使扩展点独立于执行(即函数的名称),管道作者应使用 expose(name) 函数以曝光特定扩展点.

示例

new pipeline()
  .use(doSomething).expose('init')
  .use(render)
  .use(cleanup).expose('cleanup')
  .use(done);

在这个例子中,两个扩展点, init 财务报告和审定财务报表 cleanup 已定义。 注意扩展点的名称如何与函数的名称(即. cleanup),但不一定是相同的(即:. init 文选. doSomething) (中文(简体) ).

通用扩展点

建立扩展点是管道作者的责任,但为了实现扩展点标准化,确定了以下共同名称:

  • fetch 用于回收原始内容的管道步骤,即Markdown文档.
  • parse 用于描述原始内容并将其转化为诸如Markdown AST等文档结构的管道步骤.
  • meta 用于提取内容结构元数据的管道步骤.
  • html 用于将Markdown文档变成(HTML)DOM的管道步骤.
  • esi 用于扫描 ESI 标记生成的输出并设置适当的信头的管道步骤.

使用扩展点

使用扩展点的最简单方式是扩大 以上描述的折叠函数。而不是仅仅输出一个 pre 函数,可以导出 :

  • (单位:千美元) before 对象.
  • a 一个 after 对象.
  • (单位:千美元) replace 对象.

每一个这些物体都可以有对应为管道所定义的命名扩展点的密钥.

示例

module.exports.before = {
  html: (context, action) => {
    // will get called before the "html" pipeline step
  }
}

module.exports.after = {
  fetch: (context, action) => {
    // will get called after the "fetch" pipeline step
  }
}

module.exports.replace = {
  meta: (context, action) => {
    // will get called instead of the "meta" pipeline step
  }
}

所有正在使用 before 财务报告和审定财务报表 after 扩展点需要遵循所有其他管道功能所遵循的相同接口,即它们可以访问 context 财务报告和审定财务报表 action 他们应该返回一个修改的 context 对象.

使用这些扩展点执行自定义标记下的内容节点和处理404个错误的更复杂的例子可见于 螺旋-克力融合测试。 。 。 .

背景解剖学

存在以下主要属性 :

  • request
  • content
  • response
  • error

也见 上下文计划。 。 。 .

这个 request 对象

  • params:请求参数地图.
  • headers: HTTP 头图.

也见 请求计划。 。 。 .

这个 content 对象

  • body: 未解析的内容正文作为 string。 。 。 .
  • mdast: 解析 标记AST。 。 。 .
  • meta: 映射元数据属性,包括:
    • title: 文件标题.
    • intro:平正文字介绍或说明.
    • type:文档的内容类型.
    • image:文档中第一个图像的URL.
  • document: 一个 DOM 兼容 Document 代表(HTML)文件见下文) (中文(简体) ).
  • sections[]: 该文件的主要部分,作为强化的MDAST(见下文) (中文(简体) ).
  • html: 作为 HTML 渲染的内容的字符串 .
  • children: HTML 递归内容的顶级元素阵列.

也见 内容计划。 。 。 .

content.document 细节

对于更喜欢使用已渲染的 HTML 而非输入 Markdown AST 的开发者, content.document 提供与 API 兼容的 HTML 的描述 window.document 在浏览器中查找对象.

最常用的用法可能是叫 content.document.innerHTML,它给出了页面的全部 HTML,但其他功能如:

  • content.document.getElementsByClassName
  • content.document.querySelector
  • content.document.querySelectorAll

也可查阅。 请注意一些职能,如:

  • content.document.getElementsByClassName
  • content.document.getElementByID

由于默认管道生成的 HTML 不注入类名或ID 属性,所以使用较少.

从 Markdown AST 生成(Virtual) DOM 节点的工具作为公用类提供,以便用于自定义 pre.js 脚本,和 说明如下:。 。 。 .

content.sections 细节

默认管道从Markdown文档中取出段落,使用两个"数学断开",如 *** 或者说 --- 并嵌入了 YAML 块作为区域标记。 如果文档中找不到章节, 则全部 content.mdast 将等于 content.sections[0]。 。 。 .

content.sections 是数组 section 节点,带有 type (竖起)和 children (节点阵)属性. 此外,每个科有一个 types 属性,是一系列衍生内容类型。 Helix项目(和Hypermedia Pipeline)在声明的内容打字上使用隐含打字方式,这意味着作者的任务不是明确声明某节或文档的内容类型,而是让模板解释某节的内容来理解它所处理的内容类型.

这个 types 属性是一组字符串值,根据孩子节点的发生来描述该节的种类。 这样很容易复制 types 输入 class hTML 元素的属性,这样CSS的表达式匹配了章节的类型,就可以轻松地写入. 遵循模式 type 值可以找到:

  • has-<type>:对于该节中至少发生一次的每一种内容,例如有标题
  • has-only-<type>: 对于只包含单一类型内容的段落, 例如: has- only-image
  • is-<type-1>-<type-2>-<type3>, (中文(简体) ), is-<type-1>-<type-2>,以及 is-<type-1> 对于本节中最常见的三类儿童。 例如,一个有标题和描述的画廊 is-image-text-heading。您可以使用 utils.types。 。 。 .
  • nb-<type>-<occurences>:本节中每种类型的发生次数.

每个部分都有额外的内容衍生元数据属性,特别是:

  • title:该节中第一个标题的值.
  • intro:本节第一段的价值.
  • image: 一节中第一个图像的URL.
  • meta: 解析了该区段的YAML元数据(作为一个对象).

这个 response 对象

  • body: 未分解的反应机构 string。 。 。 .
  • headers: HTTP 响应头的映射.
  • status: HTTP 状态代码.

也见 响应计划。 。 。 .

这个 error 对象

此对象仅在管道处理过程中出错时设置. 管道中的任何步骤都可能使 error 对象。 后续步骤如果遇到 error 对象.

或者,步骤可以试图处理 error 对象,例如通过生成格式化错误消息并将其放入 response.body。 。 。 .

唯一的已知财产 error 为:

  • message: 错误消息.

公用事业

生成一个虚拟 DOM utils.vdom

VDOM 是一个转换的帮助类 医生 使用自定义匹配器函数或表达式将下沉标记为 DOM 节点 .

它可用于下列情况:

  • 您只需要代表一个 section 中显示的文档.
  • 您已经更改到 content.mdast 并想要在 HTML 中反映它们.
  • 您想要自定义某些 Markdown 元素的 HTML 输出.

开始

在大多数情况下,你可以简单地访问一个从 action.transformer 属性。 该设备将在 parse 步骤并用于 html 步骤,所以注册 after.parse 财务报告和审定财务报表 before.html 是调整生成的 HTML 的理想点.

或者,装入 VDOM 帮助通过 :

const VDOM = require('@adobe/helix-pipeline').utils.vdom;

简单转换

content.document = new VDOM(content.mdast).getDocument();

此替换 content.document 并重新授予Markdown AST代表. 可在更改为 content.mdast 已经做了.

使用时 action.transformer,不需要使用此手册.

content.document = new VDOM(content.sections[0]).getDocument();

这只使用第一节的内容来渲染文档.

匹配节点

Markdown AST 中的节点可以用两种方式匹配: 选择- 声明或使用上游函数.

action.transformer.match('heading', () => '<h1>This text replaces your heading</h1>');
content.document = vdom.getDocument();

每个带有该类型的节点 heading 将变为 <h1>This text replaces your heading</h1>· ;

action.transformer.match(function test(node) {
  return node.type === 'heading';
}, () => '<h1>This text replaces your heading</h1>');
content.document = vdom.getDocument();

而不是选择语句,您也可以提供返回的上游函数 true 或者说 false。上面的两个例子将具有相同的行为.

创建 DOM 节点

第二个论点 match 是一个节点生成函数,应当返回以下三个选项之一:

  1. 1个DOM 节点。 。 。 .
  2. (单位:千美元) String 包含 HTML 标记.
action.transformer.match('link', (_, node) => {
  return {
    type: 'element',
    tagName: 'a',
    properties: {
      href: node.url,
      rel: 'nofollow'
    },
    children: [
      {
        type: 'text',
        value: node.children.map(({ value }) => value)
      }
    ]
  }
}

以上:注射 rel="nofollow" 使用HTAST.

const h = require('hyperscript');

action.transformer.match('link', (_, node) => h(
    'a',
    { href: node.url, rel: 'nofollow' },
    node.children.map(({ value }) => value),
  );

上方: 使用同样方法 上标 (它创造了DOM元素)明显短.

action.transformer.match('link', (_, node) => 
  `<a href="${node.url}" rel="nofollow">$(node.children.map(({ value }) => value)).join('')</a>`;

上层:平面 Strings可以使用ES6中的字符串模板来构建相同的结果.

处理儿童节点

以上例子只是处理终端节点(或几乎终端节点). 在现实中,你需要确保匹配节点的所有子节点也被处理. 为此,处理器函数的签名为您提供了一个 handlechild 函数.

// match all "emphasis" nodes
action.transformer.match('emphasis', (h, node, _, handlechild) => {
  // create a new HTML tag <i class="its-not-semantic…">
  const i = h(node, 'i', { className: 'its-not-semantic-html-but-i-like-it' });
  // make sure all child nodes of the markdown node are processed
  node.children.forEach((childnode) => handlechild(h, childnode, node, i));
  // return the i HTML element
  return i;
});

这个 handlechild 函数调用 :

  • h: DOM- 节点生成函数.
  • childnode:待处理的儿童节点.
  • node:要处理的节点(通常是当前节点)的母节点.
  • i: DOM节点将是新创建的 DOM节点的新父节点.

推断内容类型 utils.types

除了每一节自动推断的内容类型外, utils.types 页:1 TypeMatcher 工具类,允许将段落内容与简单的表达式语言相匹配,从而丰富 section[].types 数值.

const TypeMatcher = require('@adobe/hypermedia-pipeline').utils.types;

const matcher = new TypeMatcher(content.sections);
matcher.match('^heading', 'starts-with-heading');
content.sections = matcher.process();

在上述例子中,所有设有 heading 因为第一个孩子会得到价值 starts-with-heading 附录 types 阵列. ^heading 是内容表达语言的一个例子,它允许将内容与简单的正则表达式类似语法相匹配.

内容表达式语言
  • ^heading - 第一个元素是 heading。 。 。 .
  • paragraph$ - 最后一个元素是 paragraph。 。 。 .
  • heading image+ - 一个 heading 随后是一个或多个 image编号.
  • heading? image - 可选 heading 随后是1个 image。 。 。 .
  • heading paragraph* image - 一个 heading 编号 paragraphs(也没有任何段落),后为 image。 。 。 .
  • (paragraph|list) - 一个 paragraph 或一个 list。 。 。 .
  • ^heading (image paragraph)+$ - 一个 heading,然后是双 image 财务报告和审定财务报表 paragraph但至少一个.

检查管道上下文

当运行在非生产时,即运行在 OpenWhisk 动作之外,例如 hlx up,管道倾销启用。 管道倾销使开发人员能够方便地检查 Context 用于调试管道的功能并生成现实的测试案例.

管道处理的每个阶段都会产生一个像 $PWD/logs/debug/context_dump_34161BE5KuR0nuFDp/context-20180902-1418-05.0635-step-2.json 内部 debug 目录。 这些垃圾场将在 node 进程结束, 这样在停止后 hlx up 页:1 debug 目录将再次被清除 。 这个 -step-n 在文件名中表示已登录的管道步骤.

简单的例子可能是这样的:

步骤 0:

{}

步骤1:

{
  "request": {}
}

步骤2:

{
  "request": {},
  "content": {
    "body": "---\ntemplate: Medium\n---\n\n# Bill, Welcome to the future\n> Project Helix\n\n## Let's talk about Project Helix\n![](./moscow/assets/IMG_0167.jpg)\n",
    "sources": [
      "https://raw.githubusercontent.com/trieloff/soupdemo/master/hello.md"
    ]
  }
}

步骤3(仅限):

@@ -1,6 +1,58 @@
 {
   "content": {
-    "body": "Hello World"
+    "body": "Hello World",
+    "mdast": {
+      "type": "root",
+      "children": [
+        {
+          "type": "paragraph",
+          "children": [
+            {
+              "type": "text",
+              "value": "Hello World",
+              "position": {
+                "start": {
+                  "line": 1,
+                  "column": 1,
+                  "offset": 0
+                },
+                "end": {
+                  "line": 1,
+                  "column": 12,
+                  "offset": 11
+                },
+                "indent": []
+              }
+            }
+          ],
+          "position": {
+            "start": {
+              "line": 1,
+              "column": 1,
+              "offset": 0
+            },
+            "end": {
+              "line": 1,
+              "column": 12,
+              "offset": 11
+            },
+            "indent": []
+          }
+        }
+      ],
+      "position": {
+        "start": {
+          "line": 1,
+          "column": 1,
+          "offset": 0
+        },
+        "end": {
+          "line": 1,
+          "column": 12,
+          "offset": 11
+        }
+      }
+    }
   },
   "request": {}
 }

步骤5(仅提及):

@@ -52,7 +52,49 @@
           "offset": 11
         }
       }
-    }
+    },
+    "sections": [
+      {
+        "type": "root",
+        "children": [
+          {
+            "type": "paragraph",
+            "children": [
+              {
+                "type": "text",
+                "value": "Hello World",
+                "position": {
+                  "start": {
+                    "line": 1,
+                    "column": 1,
+                    "offset": 0
+                  },
+                  "end": {
+                    "line": 1,
+                    "column": 12,
+                    "offset": 11
+                  },
+                  "indent": []
+                }
+              }
+            ],
+            "position": {
+              "start": {
+                "line": 1,
+                "column": 1,
+                "offset": 0
+              },
+              "end": {
+                "line": 1,
+                "column": 12,
+                "offset": 11
+              },
+              "indent": []
+            }
+          }
+        ]
+      }
+    ]
   },
   "request": {}
 }

步骤6(仅指):

@@ -92,9 +92,19 @@
              "indent": []
            }
          }
-        ]
+        ],
+        "title": "Hello World",
+        "types": [
+          "has-text",
+          "has-only-text"
+        ],
+        "intro": "Hello World",
+        "meta": {}
      }
-    ]
+    ],
+    "meta": {},
+    "title": "Hello World",
+    "intro": "Hello World"
  },
  "request": {}
}

步骤9(仅指):

@@ -169,7 +169,11 @@
        "search": "",
        "hash": ""
      }
-    }
+    },
+    "html": "<p>Hello World</p>",
+    "children": [
+      "<p>Hello World</p>"
+    ]
  },
  "request": {}
}

步骤10(仅指):

@@ -175,5 +175,9 @@
      "<p>Hello World</p>"
    ]
  },
-  "request": {}
+  "request": {},
+  "response": {
+    "status": 201,
+    "body": "<p>Hello World</p>"
+  }
}

版本与发布记录

@adobe/helix-pipeline 共发布 492 个版本,首次发布于 2018/11/29;过去 12 个月发布了 0 个版本。

版本发布日期距今
18.0.14latest2022/02/234 年前
18.0.132022/02/234 年前
18.0.122022/02/214 年前
18.0.112022/02/214 年前
18.0.102022/02/214 年前
18.0.92022/02/114 年前

关于 @adobe/helix-pipeline 的常见问题

@adobe/helix-pipeline 是什么?

此工程为创建超媒体处理管道提供了辅助功能和默认执行.注意:该包已被作者标记为弃用——no longer supported

如何安装 @adobe/helix-pipeline?

在项目目录运行 npm install @adobe/helix-pipeline,或使用 pnpm add / yarn add / bun add。

@adobe/helix-pipeline 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@adobe/helix-pipeline 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@adobe/helix-pipeline 可以商用吗?

@adobe/helix-pipeline 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@adobe/helix-pipeline 的下载量有多少?

根据 npm 官方下载统计,@adobe/helix-pipeline 在 2026/10/05 – 2026/11/03 这 30 天内被下载 19,848 次,日均约 662 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@adobe/helix-pipeline 还在维护吗?

最新版本 18.0.14 发布于 2022/02/23(4 年前);至今共发布 492 个版本,其中过去 12 个月发布了 0 个;首次发布于 2018/11/29。作者已将其标记为弃用,新项目建议寻找替代方案。