在故事书中渲染树枝模板
#php #symfony #storybook

Storybook是一个孤立构建UI组件和页面的前端研讨会。成千上万的团队将其用于UI开发,测试和文档。它是开源的。

从历史上看,它需要一个前端框架,例如反应,vue或Angular才能渲染组件。但是我用树枝构建网站,因此我需要一种方法来渲染后端应用程序中的模板。软件包koude0是该用例的解决方案。它于2022年3月发布,正是其名称所暗示的:故事书的服务器端渲染解决方案。

将故事书连接到Symfony应用程序的事情很少,这是一个逐步指南,可以使您开始使用。我假设您已经安装了带有树枝的Symfony应用程序,并且您正在使用webpack encore。但这不是必需的,您可以使用自己喜欢的任何其他前端工具。

创建第一个组件

在我构建的网站中,一个组件是一个单个树枝文件,可以包含在项目的任何其他模板中。如果您使用的是Symfony UX,这也可能是Twig Component。在此示例中,我们将在templates/components文件夹中创建一个简单的按钮组件。此按钮可以具有标签,大小,并且可以是主要的或次要的。

{# templates/components/button.html.twig #}

<button
    type="button"
    class="{{ size }} {{ primary|default(false) ? 'primary' : 'secondary' }}"
    style="{{ style|default('')|escape('html_attr') }}"
>
    {{- label -}}
</button>

我们的目标是在Storybook中提供此组件的预览,并有可能更改其属性。

创建故事

在Storybookjs中,stories是可以孤立显示的组件的个别状态,以进行预览和测试。当使用JavaScript函数在客户端完成渲染时,它们通常用JavaScript编写。对于服务器端渲染,可以用JSON编写故事。需要一个附加的键parameters.server.id来指定预览的路径。

// stories/button.json
{
  "title": "Components/Button",
  "parameters": {
    "server": { "id": "button" }
  },
  "args": { "label": "Button" },
  "argTypes": {
    "label": { "control": "text" },
    "primary": { "control": "boolean" }, 
    "backgroundColor": { "control": "color" },
    "size": {
      "control": { "type": "select", "options": ["small", "medium", "large"] }
    }
  },
  "stories": [
    {
      "name": "Primary",
      "args": { "primary": true }
    },
    {
      "name": "Secondary"
    },
    {
      "name": "Large",
      "args": { "size": "large" }
    }
  ]
}

安装故事书服务器

koude0 documentation建议使用koude4使用server类型来初始化该项目:

npx sb init -t server

Symfony WebPack Encore使用WebPack5,而Storybook默认使用WebPack4,因此我们需要安装@storybook/builder-webpack5软件包:

npm install @storybook/builder-webpack5

这将安装NPM软件包,并使用main.jspreview.js创建一个.storybook文件夹。

文件.storybook/main.js定义了故事的位置和要使用的插件。我们需要添加@storybook/server框架和@storybook/builder-webpack5构建器,因为WebPack Encore使用WebPack5。

// .storybook/main.js
module.exports = {
    "stories": [
        "stories/**/*.stories.mdx",
        "stories/**/*.stories.@(json)"
    ],
    "addons": [/* optional addons */],
    "framework": "@storybook/server",
    "core": {
        // Webpack Encore uses webpack5
        "builder": "@storybook/builder-webpack5"
    }
}

最后一个配置步骤,我们需要配置提供应用程序的URL(默认情况下,Symfony-CLI在端口8000上使用)。 URL是任意的,可以是您想要的任何东西,但是必须匹配Symfony应用程序中定义的路由。 Storybook Server将将URL与parameters.server.id值相连,以使完整的URL输入组件。它必须是一个有效的绝对URL。

// .storybook/preview.js
export const parameters = {
  server: {
    url: `https://localhost:8000/storybook/component`,
  },
};

创建通用的符号控制器

回到Symfony应用程序,我们需要在Storybook配置中定义的URL背后创建一个控制器。它从url和args从查询字符串获取。

<?php # src/Controller/StorybookController.php

namespace App\Controller;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Component\Routing\Annotation\Route;
use Twig\Environment;

#[AsController]
readonly class StorybookController
{
    public function __construct(private Environment $twig) {}

    #[Route(
        '/storybook/component/{id}',
        // The id can contain slashes, so we need to use a regex
        requirements: ['id' => '.+'],
    )]
    public function __invoke(Request $request, string $id): Response
    {
        // $id is the path to the Twig template in the storybook/ directory
        // Args are read from the query parameters and sent to the template
        $template = sprintf('storybook/%s.html.twig', $id);
        $context = ['args' => $request->query->all(), 'id' => $id];
        $content = $this->twig->render($template, $context);

        // During development, storybook is served from a different port than the Symfony app
        // You can use nelmio/cors-bundle to set the Access-Control-Allow-Origin header correctly
        $headers = ['Access-Control-Allow-Origin' => 'http://localhost:6006'];

        return new Response($content, Response::HTTP_OK, $headers);
    }
}

创建一个树枝模板以渲染组件

我们在templates/components/button.html.twig中创建了我们的组件,并在stories/button.json中配置了故事。现在,我们需要创建一个将在故事书的上下文中渲染组件的树枝模板。我们在上一步中创建的控制器将使用此模板。

{# templates/storybook/button.html.twig #}

{{ include('components/button.html.twig', {
    label: args.label|default('Button'),
    size: args.size|default('medium'),
    primary: args.primary|default(false) == 'true',
    style: args.backgroundColor is defined ? 'background-color: #{args.backgroundColor}' : '',
}) }}

跑步的故事书

最后,我们可以运行故事书并查看我们的组成部分。

npm run storybook

> storybook
> start-storybook -p 6006
...
╭───────────────────────────────────────────────────╮
│                                                   │
│   Storybook 6.5 for Server started                │
│   4.56 s for preview                              │
│                                                   │
│    Local:            http://localhost:6006/       │
│    On your network:  http://192.168.1.11:6006/    │
│                                                   │
╰───────────────────────────────────────────────────╯

是时候玩组件并查看其在不同状态的行为。

结论

这是我第一次在故事书上的经历,我对结果非常满意。我希望本文可以帮助您开始,如果您需要说服前端团队,您无需切换到Node即可使用Storybook。 Symfony是一个令人惊叹的框架,用于构建丰富的Web应用程序,并且需要Symfony UX计划挑战前端框架来构建Rich UI。

如果您有任何疑问或反馈,请随时在下面发表评论或在Twitter上与我联系。