# @artsy/stitch 中文文档

规范地址：https://npmcn.com/package/%40artsy/stitch/

版本：6\.5\.0
npm 元数据更新时间：2025-11-18T23:32:00.651Z
中文译文更新时间：2026-11-06T21:25:12.532Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40artsy/stitch
原文对照：https://npmcn.com/package/%40artsy/stitch/?lang=original
项目主页：https://github.com/artsy/stitch#readme
源码仓库：https://github.com/artsy/stitch

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：119 kB，37 个文件
- 模块格式：CommonJS
- TypeScript 类型：包内自带
- 运行依赖：2 个
- peer 依赖：react ^16\.5\.0，react-dom ^16\.5\.0，styled-components 4\.0\.3
- 首次发布：2017-08-26T00:28:21.055Z
- 最新版本发布：2022-04-13T13:52:14.561Z
- 近 30 天下载量：8189（2026-10-07 至 2026-11-05，npm 官方下载统计）
- 已发布版本数：58（近 12 个月 0 个）

## 中文简介

帮助您的组件和模板依赖和平共处

## 安装

```sh
npm install @artsy/stitch
```

也可以使用：`pnpm add @artsy/stitch`、`yarn add @artsy/stitch`、`bun add @artsy/stitch`

## README

# @ artsy/ stitch (英语)

[![Build Status](https://travis-ci.com/artsy/stitch.svg?token=gy99gfdxXxqG3ydmn6xq&branch=main)](https://travis-ci.com/artsy/stitch)

帮助您的组件和模板依赖和平共处

### 概览

在Artsy,我们有一些已经生产了一段时间的Node.js应用. [强制](https://github.com/artsy/force)例如"CoffeeScript"和"Jade"在"CoffeeScript"让许多意义大了;"CoffeeScript"解决了JavaScript Pre-ES6的许多问题,"Jade"让与"HTML"的合作更加优雅了. 随着时间的推移和新技术的出现,这些解决方案开始感到负担更重,开始与我们的许多开发者一起建立功能,我们的许多开发者渴望开始使用新一代的工具,如React.js. 怎么会? 重建往往受到资源的限制,如果不进行重建,就很难合并新旧技术,特别是在视图层.

这个图书馆是试图帮助那些逐渐过渡的人 摆脱像Jade,EJS和 [许多其他](https://github.com/tj/consolidate.js),对反应(或其他) [类似反应的 libs](https://github.com/developit/preact)) (中文(简体) ). 它所做的是提供一套灵活的常规,用于处理特快中通常看到的布局代码,但只要把原始的HTML送去给客户端的任何地方就会起作用.

如果你使用一个温和的库 支持 [合并.js](https://github.com/visionmedia/consolidate.js)这个图书馆对你很有用.

### 安装

```sh
yarn install @artsy/stitch
```

### 实例情景 / 本库的目标是谁

-   您的UI 以 Jade/ Pug 或其他基于布局的引擎构建,您使用"块"功能. 如何在保持后向相容性的同时将 React 组件注入到每个组件中?
-   或者,您会使用一个依赖于服务器端的调温库 。 怎样做同样的事情?
-   您的应用程序大部建于 Backbone,每个视图由 Handlebars 模板支持. 你仍然想使用你现有的观点 / UI 同时逐渐向反应移动 如何将每个背骨视图在你的反射组件内“交出”——反之亦然?
-   你已经有了一个服务器侧式,基于EJS的应用程序,你愿意开始利用React的同形"通用"渲染. 如何在服务器上渲染React组件,然后在客户端上再加水?
-   你有一个新的应用软件 完全在React中建立 但出于某种原因 需要保持部分布局相互隔离.
-   .

出道后,斯地奇以灵活性为目标.

## 使用量

**目录**

-   [基本示例](https://npmcn.com/package/%40artsy/stitch/#readme-basic)
-   [运通.js](https://npmcn.com/package/%40artsy/stitch/#readme-expressjs-and-pug)
-   [布局和复杂的UI](https://npmcn.com/package/%40artsy/stitch/#readme-layouts-and-other-complex-ui-configurations)
-   [Isomorphic / "Universal" 渲染](https://npmcn.com/package/%40artsy/stitch/#readme-isomorpic-or-universal-rendering)
-   [预编模板](https://npmcn.com/package/%40artsy/stitch/#readme-precompiling-templates)
-   [预览和其他自定义渲染器](https://npmcn.com/package/%40artsy/stitch/#readme-custom-renderers)
-   [`<StyledComponents />` 支助](https://npmcn.com/package/%40artsy/stitch/#readme-styled-components-support)
-   [SSR 中间软件](https://npmcn.com/src/internal/README.md)
-   [完整 API](https://npmcn.com/package/%40artsy/stitch/#readme-full-api)
-   [解决问题](https://npmcn.com/package/%40artsy/stitch/#readme-troubleshooting)
-   [发展](https://npmcn.com/package/%40artsy/stitch/#readme-development)

(如果你想直接跳进去,看 [完整实例项目](https://github.com/artsy/stitch/tree/main/examples/6-isomorphic-react-styled-components-backbone-pug-webpack). ) (中文(简体) )

#### 基本示例

以最基本的形式来说,这个库是一个单一的函数,它接受一条通往您布局的路径,一些数据,并返回一串被缝合的已渲染出,可以发送给客户端的原始html:

```html
<div>
  {{title}}
</div>
```

```js
const html = await stitch({
  layout: "templates/layout.handlebars",
  data: {
    title: "Hello!",
  },
})

console.log(html)

// => Outputs:
/*
<div>
  Hello!
</div>
*/
```

通过添加"块",可以开始组装更复杂的布局. 块代表一个模板的路径或返回字符串的函数/反应类:

```html
// templates/layout.handlebars

<html>
  <head>
    <title>
      {{title}}
    </title>
  </head>
  <body
    {{{body}}}
  </body>
</html>
```

```js
// index.js

const html = await stitch({
  layout: "templates/layout.handlebars",
  data: {
    title: "Hello World!",
  },
  blocks: {
    body: props => {
      return <h1>{props.title}</h1>
    },
  },
})

console.log(html)

// => Outputs:
/*
<html>
  <head>
    <title>Hello World!</title>
  </head>
  <body>
    <h1>
      Hello World!
    </h1>
  </body>
</html>
*/
```

您可以根据需要添加尽可能多的块, 这些块可以通过密钥访问 。 每个块都经过评估和编译,再注入布局. 记住任何接受路径到模板的字段也可以接受一个组件(作为类或无国籍功能组件),模板格式可以混合并匹配. 这允许在看似不相容的取景系统中有很大的灵活性.

#### 运通.js和Pug

**记着!** 以下每种用途 [代理/ 等待](https://medium.com/@Abazhenov/using-async-await-in-express-with-node-8-b8af872c0016),默认可在节点QQ 7.6.0中获取。 如果你的环境还没有支持 Aync / 等待,请查看 [解决问题](https://npmcn.com/package/%40artsy/stitch/#readme-troubleshooting) 以下一节以使用ES6承诺为例.

```js
// index.js

import express from "express"
import { stitch } from "@artsy/stitch"

import Body from "./components/Body"
import Footer from "./components/Footer"

const app = express()

app.get("/", async (req, res, next) => {
  try {
    const html = await stitch({
      layout: "templates/mainLayout.pug",
      data: {
        title: "Hello World!",
        description:
          "An example showing how to take a view structure based in .pug and interpolate with React",
      },
      blocks: {
        head: "templates/head.pug",
        body: Body,
        footer: Footer,
      },
    })

    res.send(html)
  } catch (error) {
    next(error)
  }
})

app.listen(3000, () => {
  console.log("Listening on port 3000.")
})
```

```pug
//- templates/mainLayout.pug

html
  head
    != head
  body
    != body

    footer
      != footer
```

```pug
//- templates/head.pug

title= title
meta( property='og:title', content= title )
meta( name='description', content= description )
```

```js
// components/Body.js

export default function Body({ title, description }) {
  return (
    <div>
      <h3>{title}</h3>
      <p>{description}</p>
    </div>
  )
}
```

```js
// components/Footer.js

export default function Footer() {
  return <h4>Hello footer!</h4>
}
```

#### 布局和其他复杂的 UI 配置

这个系统真正开始发光的地方是 当有一个基础布局被子线扩展。 例如,说您有一个 Express app 上载了一些子应用程序,每个子应用程序都有自己的布局,使用块(或包括等)"扩展"主布局:

```pug
//- templates/mainLayout.pug

html
  head
    include partials/head
    block head

  body
    include partials/body
    block body
```

```pug
//- apps/home/templates/homeLayout.pug

extends ../../../templates/mainLayout.pug

block head
  != head

block body
  if locals.isAuthenticated
    div
      | Logged-in

  != body
```

```js
// apps/home/routes.js

...

const html = await stitch({
  basePath: __dirname,
  layout: 'templates/homeLayout.pug',
  data: {
    title: 'Hello how are you?',
    description: 'Views extending views extending views...'
  },

  // Can also define locals, which are passed down to components under
  // the `props.locals` key
  locals: {
    isAuthenticated: req.locals.userIsAuthenticated
  },
  blocks: {
    head: 'templates/head.pug',
    body: Body
  }
})

res.send(html)
```

#### Isomorpic (或"Universal") 渲染

报告更深入地阐述了这一点 [异态反应- pug- webpack 示例](https://github.com/artsy/stitch/tree/main/examples/6-isomorphic-react-styled-components-backbone-pug-webpack) 但简而言之,由于 `data` 对象在渲染之前被注入到模板中, 使其在客户端上可用就如同 `JSON.stringifying` 内容:

```pug
// - templates/layout.pug

html
  body
    script.
      var __BOOTSTRAP__ = {JSON.stringify(data)}

    != app
```

```js
const html = await stitch({
  layout: "templates/layout.pug",
  blocks: {
    app: App,
  },
  data: {
    name: "Z",
  },
})

res.send(html)
```

```js
export default class App extends Component {
  componentDidMount () {
    console.log(`Hello ${this.props.name}, <App /> is mounted on the client.`)
  },

  render () {
    return (
      <div>
        Hello {this.props.name}
      </div>
    )
  }

}
```

```js
// client.js

React.render(<App {...window.__BOOTSTRAP__} />)
```

#### 预编模板

如果你有一堆老式的 Backbone 视图,你不想在搬去React时扔出去, 但还是想注入他们的标记 _输入_ 您的后期安装到客户端的响应应用程序 ? 这个图书馆很容易:

```js
// apps/login/index.js

...

const html = await stitch({
  layout: 'templates/loginLayout.pug',
  blocks: {
    app: App
  },
  templates: {
    login: 'templates/login.pug'
  }
})
```

```js
// components/Body.js

import React from "react"
import Login from "./Login"

export default function App(props) {
  const {
    templates: { login },
  } = props

  return (
    <div>
      <Login template={login} />
    </div>
  )
}
```

```js
// components/Login.js

import React, { Component } from 'react'
import LoginView from '../views/LoginView'

export default class Login extends Component {
  componentDidMount () {
    this.loginView = new LoginView()
    this.loginView.render()
  }

  componentWillUnmount () {
    this.loginView.remove()
  }

  render () {
    return (
      <div>
        <div dangerouslySetInnerHtml={{
          __html: this.props.template
        }}>
      </div>
    )
  }
}
```

```html
// templates/login.handlebars

<div id="login">
  <button>
    Login
  </button>
</div>
```

```js
// views/LoginView.js

var LoginView = Backbone.View.extend({
  el: '#login',

  events: {
    'click button': 'handleLoginClick'
  },

  handleLoginClick: function () {
    ...
  },

  render: function() {
    ...
  }
})

module.exports = LoginView
```

模板是预编译的,从您的 React 组件内部可以调取 html , 必要时在 `props.templates` 键.

#### 自定义渲染器

如果您喜欢使用 React 以外的渲染引擎, 没有问题 -- -- 只要在自定义渲染函数中通过返回字符串:

```js
import renderToString from "preact-render-to-string"

const html = await stitch({
  layout: "templates/loginLayout.pug",
  config: {
    componentRenderer: renderToString,
  },
  blocks: {
    body: App,
  },
})
```

此外,如果您想要覆盖任何默认的模板引擎(例如,将返回什么) `require('handlebars')`) 您可以通过更新实现 `config.engines`数字 :

```js
const html = await stitch({
  layout: "templates/loginLayout.pug",
  config: {
    engines: {
      handlebars: (filePath, locals) => {
        return customHandlebarsRenderer(filePath, locals)
      },
      pug: (filePath, locals) => {
        return customPugRenderer(filePath, locals)
      },
    },
  },
  blocks: {
    body: App,
  },
})
```

#### 样式组件支持

如果您的 React 应用程序使用 [`styled-components`](https://www.styled-components.com/),确保您安装 [bail-plugin 类组件](https://github.com/styled-components/babel-plugin-styled-components) 并允许服务器端通过配置渲染 :

```js
import styled from "styled-components"

const html = await stitch({
  layout: "templates/layout.pug",
  config: {
    styledComponents: true,
  },
  blocks: {
    body: props => {
      const Layout = styled.div`
        background: purple;
        border: 1px solid black;
        color: white;
        width: 100%;
      `

      return <Layout>Hello Styled Components!</Layout>
    },
  },
})
```

最后,请在您的布局模板中显示您的样式 :

```pug
html
  head
    != css

  body
    #react-root
      != body
```

## 完整 API

```js
const html = await stitch({

  /**
   * Sets a base path from which to fetch templates.
   *
   * @type {String}
   */
  basePath: process.cwd(),

  /**
   * Path to layout template file / component.
   *
   * @type {String|Component}
   */
  layout: <REQUIRED>

  /**
   * Block sections to pass to template / components. A "block" typically
   * represents a discreet section (header, body, footer, etc) but can be
   * anything.
   */
  blocks: {
    /**
     * @type {String|Component}
     */
  },

  /**
   * Locals represent Express.js locals as they flow through the `req` / `res`
   * cycle. These values could be passed to the following section, `data`, but
   * for the sake of clarity and isolation they're typically passed along here.
   *
   * Accessible from within components via `props.locals` and from within a
   * template via `locals`
   */
  locals: {
    /**
     * @type {*}
     */
  },

  /**
   * Data that is passed to templates and components. Embedded directly
   * within template code, but also accessible via `data` (useful for
   * JSON.stringify'ing and passing down the wire for rehydration). In a
   * component, it represents `props` and is accessible as such.
   */
  data: {
    /**
     * @type {*}
     */
  },

  /**
   * Templates / Components that are precompiled and passed along as rendered
   * html strings. From within your component, template html is accessible via
   * `props.templates`
   */
  templates: {
    /**
     * @type {String|Component}
     */
  },

  config: {

    /**
     * Configuration for layout renderer. Right now components are rendered via
     * ReactDOM, but any kind of engine can be passed in and accommodated
     * assuming it returns a string of rendered markup.
     *
     * @type {Function}
     */
    componentRenderer: ReactDOM.renderToString,

    /**
     * If you would like to override any default template engines pass in a
     * key matching the extension and a function, e.g.,
     *
     * engines: {
     *   pug: (filePath, locals) => string
     * }
     */
    engines: {
      /**
       * @type {Function}
       */
    },

    /**
     * If your project uses <StyledComponents /> and you would like to extract
     * styles from your component during server-side renders, set this to true.
     *
     * See https://www.styled-components.com/docs/advanced#server-side-rendering
     * for more information.
     *
     * @type {Boolean}
     */
    styledComponents: false
  }
})
```

## 解决问题

> 帮帮我! 我的观点不能改变,有 `Unexpected token (` 在我的操纵台上.

所有的例子都假设你让 [代理/ 等待](https://medium.com/@Abazhenov/using-async-await-in-express-with-node-8-b8af872c0016),在节点的版本中默认出现 `7.6.0`. 如果你得到这个错误,它很可能是在使用一个尚未支持这个特性的更老版本. 没有恐惧 - 即兴/等待 只是围着承诺的一圈:

```js
stitch({ layout: "layout.ejs" })
  .then(html => {
    res.send(html)
  })
  .catch(error => {
    next(error)
  })
```

> Async / 等待在我的"节点"版本中被支持,但我在浏览器里没有看到任何东西,控制台里也没有出错!

你还记得使用 `await` 关键字在前面 `stitch`很容易忘记:

## 发展

### 承诺和部署

这个项目使用 [自动释放](https://github.com/intuit/auto-release#readme) 可以在每张公关上自动发布。 每个公关应该有一个符合以下内容的标签

-   版本: 三维
-   版本: 补丁
-   版本: 次要
-   版本: 主要

没有释放发生在一个 `Trivial` 更新.

## 常见问题

### @artsy/stitch 是什么？

帮助您的组件和模板依赖和平共处

### 如何安装 @artsy/stitch？

在项目目录运行 npm install @artsy/stitch，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：react（^16\.5\.0）、react-dom（^16\.5\.0）、styled-components（4\.0\.3）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @artsy/stitch 支持 TypeScript 吗？

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

### @artsy/stitch 支持 ESM 还是 CommonJS？

以 CommonJS 形式发布，可以直接 require\(\)；在 ES Module 项目中也可以用 import 引入（Node\.js 会把 module\.exports 作为默认导出）。

### @artsy/stitch 可以商用吗？

@artsy/stitch 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @artsy/stitch 的下载量有多少？

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

### @artsy/stitch 还在维护吗？

最新版本 6\.5\.0 发布于 2022/04/13（4 年前）；至今共发布 58 个版本，其中过去 12 个月发布了 0 个；首次发布于 2017/08/26。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

