跳到内容

创建 UX 捆绑包

编辑此页

提示

在阅读本文之前,您可能需要查看 可重用捆绑包的最佳实践

这里有一些技巧使您的捆绑包安装为 UX 捆绑包。

composer.json 文件

您的 composer.json 文件必须包含 symfony-ux 关键字

1
2
3
{
    "keywords": ["symfony-ux"]
}

资源位置

您的资源必须位于以下目录之一,并包含 package.json 文件,以便 Flex 可以在安装/更新期间处理它

  • /assets (推荐)
  • /Resources/assets
  • /src/Resources/assets

package.json 文件

您的 package.json 文件必须包含带有已定义控制器的 symfony 配置,并且还需要将必需的包添加到 peerDependenciesimportmap (importmap 中的包列表应与 peerDependencies 中的包列表相同)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
    "name": "@acme/feature",
    "version": "1.0.0",
    "symfony": {
        "controllers": {
            "slug": {
                "main": "dist/controller.js",
                "fetch": "eager",
                "enabled": true,
                "autoimport": {
                    "@acme/feature/dist/bootstrap4-theme.css": false,
                    "@acme/feature/dist/bootstrap5-theme.css": true
                }
            }
        },
        "importmap": {
            "@hotwired/stimulus": "^3.0.0",
            "slugify": "^1.6.5"
        }
    },
    "peerDependencies": {
        "@hotwired/stimulus": "^3.0.0",
        "slugify": "^1.6.5"
    }
}

在这种情况下,位于 [assets directory]/dist/controller.js 的文件将被公开。

提示

您可以直接在此 dist/controller.js 文件中编写原始 JS,或者您可以使用 TypeScript 编写控制器并将其转换为 JavaScript。

这是一个示例

  1. 将以下内容添加到您的 package.json 文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    {
        "scripts": {
            "build": "babel src --extensions .ts -d dist"
        },
        "devDependencies": {
            "@babel/cli": "^7.20.7",
            "@babel/core": "^7.20.12",
            "@babel/plugin-proposal-class-properties": "^7.18.6",
            "@babel/preset-env": "^7.20.2",
            "@babel/preset-typescript": "^7.18.6",
            "@hotwired/stimulus": "^3.2.1",
            "typescript": "^4.9.5"
        }
    }
  2. 将以下内容添加到您的 babel.config.js 文件 (应位于您的 package.json 文件旁边)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    module.exports = {
        presets: [
            ['@babel/preset-env', {
                "loose": true,
                "modules": false
            }],
            ['@babel/preset-typescript', { allowDeclareFields: true }]
        ],
        assumptions: {
            superIsCallableConstructor: false,
        },
    };
  3. 运行 npm install 安装新的依赖项。
  4. 使用 TypeScript 在 src/controller.ts 中编写您的 Stimulus 控制器。
  5. 运行 npm run build 将您的 TypeScript 控制器转换为 JavaScript。

要在模板中使用您的控制器 (例如,在您的捆绑包中定义的模板),您可以像这样使用它

1
2
3
4
5
6
7
8
9
10
<div
    {{ stimulus_controller('acme/feature/slug', { modal: 'my-value' }) }}
    {#
        will render:
        data-controller="acme--feature--slug"
        data-acme--feature--slug-modal-value="my-value"
    #}
>
    ...
</div>

不要忘记添加 symfony/stimulus-bundle:^2.9 作为 composer 依赖项,以使用 Twig stimulus_* 函数。

提示

控制器命名:在此示例中,PHP 包的名称为 acme/featurepackage.json 中控制器的名称为 slug。因此,Stimulus 的完整控制器名称将为 acme--feature--slug,但使用 stimulus_controller() 函数,您可以使用 acme/feature/slug

每个控制器在 package.json 文件中都有许多选项

已启用:
控制器是否应默认启用。
主文件:
控制器文件的路径。
获取方式:
页面加载时如何包含控制器和依赖项。使用 eager (默认) 将控制器和依赖项包含在页面加载时下载的 JavaScript 中。使用 lazy 将控制器和依赖项隔离到单独的文件中,并且仅在 data-controller HTML 出现在页面上时异步下载。
自动导入:
要与控制器一起导入的文件列表。例如,当有多种 CSS 样式取决于所使用的前端框架时(例如 Bootstrap 4 或 5,Tailwind CSS...)很有用。该值必须是一个对象,其中文件作为键,布尔值作为每个文件的值,以设置是否应导入该文件。

Asset Mapper 的具体说明

要使您的捆绑包的资源与 AssetMapper 一起使用,您必须在 package.json 文件中添加如上的 importmap 配置,并在容器中预置一些配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
namespace Acme\FeatureBundle;

use Symfony\Component\AssetMapper\AssetMapperInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Symfony\Component\HttpKernel\Bundle\AbstractBundle;

class AcmeFeatureBundle extends AbstractBundle
{
    public function prependExtension(ContainerConfigurator $configurator, ContainerBuilder $container): void
    {
        if (!$this->isAssetMapperAvailable($container)) {
            return;
        }

        $container->prependExtensionConfig('framework', [
            'asset_mapper' => [
                'paths' => [
                    __DIR__ . '/../assets/dist' => '@acme/feature-bundle',
                ],
            ],
        ]);
    }

    private function isAssetMapperAvailable(ContainerBuilder $container): bool
    {
        if (!interface_exists(AssetMapperInterface::class)) {
            return false;
        }

        // check that FrameworkBundle 6.3 or higher is installed
        $bundlesMetadata = $container->getParameter('kernel.bundles_metadata');
        if (!isset($bundlesMetadata['FrameworkBundle'])) {
            return false;
        }

        return is_file($bundlesMetadata['FrameworkBundle']['path'] . '/Resources/config/asset_mapper.php');
    }
}
这项工作,包括代码示例,均根据 Creative Commons BY-SA 3.0 许可获得许可。
目录
    版本