clarkwinkelmann/flarum-mithril2html

将 Mithril 组件渲染为 HTML,以便在 blade 模板中使用

1.3.0 2022-12-30 17:22 UTC

This package is auto-updated.

Last update: 2024-08-29 06:07:41 UTC


README

使用 Chrome Puppeteer 通过 Spatie Browsershot 将 Mithril 组件渲染为静态 HTML。

按照 Browsershot 指示设置 Node 和无头 Chrome。

此功能旨在与电子邮件或其他离线内容生成一起使用。

由于引入了延迟,因此不建议在队列之外使用此功能。

用法

在你的扩展的 extend.php 中,在注册任何资产之前调用设置扩展器

扩展器可以被多个扩展调用而不会出现问题。一旦已注册,它将不会做任何事情。

return [
    new \ClarkWinkelmann\Mithril2Html\Extend\Setup(),
    
    // Your other extenders
];

创建一个新页面,就像创建一个普通的 Flarum 页面一样

import Page from 'flarum/common/components/Page';

class HelloWorld extends Page {
    view() {
        return <p>Hello World</p>;
    }
}

app.initializers.add('demo', function () {
    app.routes.helloWorld = {
        path: '/hello-world',
        component: HelloWorld,
    };
});

为了节省空间在 forum 包中或为了避免冲突,你可以将你的页面仅添加到 mithril2html 前端。你需要更新你的 webpack 配置以添加一个额外的入口文件,请参阅此包的 webpack.config.js 以获取示例。

如果你创建了一个单独的包(不是 forum),请使用 Flarum 的 Frontend 扩展器进行注册

    (new Frontend('mithril2html'))
        ->js(__DIR__ . '/js/dist/mithril2html.js'),

如果你已经有一个带有导出的论坛包,不幸的是,Flarum 将会覆盖所有 forum 导出以 mithril2html 导出(即使你没有) 。为了解决这个问题,有一个仅针对 JavaScript 的不同扩展器可用

    (new \ClarkWinkelmann\Mithril2Html\Extend\FrontendNoConflict('mithril2html'))
        ->js(__DIR__ . '/js/dist/mithril2html.js'),

然后你可以使用 Renderer 类来渲染组件

$component = new ClarkWinkelmann\Mithril2Html\AnonymousComponent('hello-world');
echo resolve(ClarkWinkelmann\Mithril2Html\Renderer::class)->render($component);
// <p>Hello World</p>

或者,你可以直接使用 blade 指令

@mithril2html(new ClarkWinkelmann\Mithril2Html\AnonymousComponent('hello-world'))

你可以使用组件类来配置额外的选项。该类必须实现 ClarkWinkelmann\Mithril2Html\ComponentInterfaceAnonymousComponent 是一个简单的类,允许自定义所有参数而不创建额外的类。

可以通过组件类自定义的参数有

  • route:不带前导斜杠的 Mithril 路由名称。
  • preload:通过 API 客户端预加载的 API 路由。带有前导斜杠。
  • actor:用于请求的演员。默认为访客。
  • selector:指向要返回的 HTML 的 CSS 选择器。该元素的 innerHTML 将被返回。如果选择器找不到,将抛出异常。

使用自定义组件类有助于在需要预加载时保持事物的整洁

class InvoiceComponent implements ComponentInterface {
    protected $invoice;

    public function __construct(Invoice $invoice)
    {
        $this->invoice = $invoice;
    }

    public function route(): string
    {
        return 'invoice';
    }

    public function preload(): ?string
    {
        return '/invoices/' . $this->invoice->id;
    }

    public function actor(): ?User
    {
        return $this->invoice->user;
    }

    public function selector(): ?string
    {
        return '#content';
    }
}
<p>Below is a summary of your invoice:</p>

@mithril2html(new InvoiceComponent($invoice))

PDF 和截图

虽然这不是此扩展的主要用例,但 Renderer 类还公开了一个 browsershot 方法,它提供了对预配置但未使用的 Browsershot 实例的访问。

在使用该方法时,将忽略 selector 属性,并使用整个页面/视口。必须使用 Browsershot 方法来配置输出。

示例

$component = new ClarkWinkelmann\Mithril2Html\AnonymousComponent('hello-world');
echo resolve(ClarkWinkelmann\Mithril2Html\Renderer::class)->browsershot($component)->landscape()->pdf();

当调用 Renderer::render 时,页面 CSS 不会被加载,但在调用 Renderer::browsershot 时默认加载。可以通过将 false 作为第二个参数传递来禁用此操作,如 $renderer->browsershot($component, false)

已知问题

目前,传递演员将验证基础请求和预加载的 apiDocument,但不会验证组件在页面加载后所做的任何其他 API 请求。

如果您渲染包含用户生成内容的页面且存在跨站脚本攻击(XSS)的风险,攻击者可能通过首先窃取 mithril2html 内部令牌,然后使用该令牌预加载任意的 GET 端点,以管理员身份读取任何 API GET 端点。

测试

集成测试有一些特殊之处,因为它们需要一个可以被 Chrome 访问的运行中的 web 服务器。

在运行测试之前,请先运行 composer test:server 以在端口 8080 上启动 PHP 开发服务器。服务器配置了一个路由脚本,该脚本负责将路由回集成临时文件夹。