diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index c1432c37..c1f895ec 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -68,6 +68,7 @@ ## 🎨 Bootstrap Admin UI * [Getting started](bootstrap-admin-ui/getting-started.md) +* [Assets](bootstrap-admin-ui/assets.md) * Components * [Copy to clipboard](bootstrap-admin-ui/components/copy-to-clipboard.md) diff --git a/docs/bootstrap-admin-ui/assets.md b/docs/bootstrap-admin-ui/assets.md new file mode 100644 index 00000000..e84e5c57 --- /dev/null +++ b/docs/bootstrap-admin-ui/assets.md @@ -0,0 +1,82 @@ +--- +description: >- + How the Bootstrap Admin UI package loads its stylesheets, scripts and Stimulus controllers. +--- + +# Assets + +## Prebuilt assets (default) + +The package ships prebuilt assets in its `public/` directory, installed by `assets:install` under `public/bundles/syliusbootstrapadminui/`. +They are loaded through the following hookables of the admin base layout: + +| Hook | Hookable | Content | +|---------------------------------|--------------|---------------------------------------------------------------------------------------| +| `sylius_admin.base#stylesheets` | `styles` | Tabler/Bootstrap styles of the admin panel | +| `sylius_admin.base#stylesheets` | `symfony_ux` | Stylesheets of the Symfony UX packages (Tom Select, Live Components) | +| `sylius_admin.base#javascripts` | `javascripts`| Scripts of the admin panel | +| `sylius_admin.base#javascripts` | `symfony_ux` | A Stimulus application with the Symfony UX controllers and the package's controllers | + +Nothing else is needed: this works whether your application uses Webpack Encore, AssetMapper or no frontend tooling at all. + +## Using your own Stimulus application (AssetMapper) + +If your application starts its own Stimulus application, for instance with AssetMapper, disable both `symfony_ux` hookables and load your importmap instead. +Follow the [Using AssetMapper](../getting-started.md#using-assetmapper) guide. + +## Stimulus controllers + +The package provides the following Stimulus controllers: + +| Identifier | Used by | +|---------------------|------------------------------------------------------------------------------| +| `copy-to-clipboard` | the [copy to clipboard](components/copy-to-clipboard.md) components | +| `theme-switcher` | the theme switcher of the navbar | + +They are registered by the prebuilt `symfony_ux` Stimulus application. When you disable it, register them in your own application by adding the `@sylius/bootstrap-admin-ui` package to your `assets/controllers.json` file: + +{% code title="assets/controllers.json" lineNumbers="true" %} +```json +{ + "controllers": { + "@sylius/bootstrap-admin-ui": { + "copy-to-clipboard": { + "enabled": true, + "fetch": "eager" + }, + "theme-switcher": { + "enabled": true, + "fetch": "eager" + } + } + } +} +``` +{% endcode %} + +{% hint style="warning" %} +If they are not registered, the matching components are still rendered but do nothing (for instance, the dark/light theme button of the navbar), and no error is reported. +{% endhint %} + +### Versions without the `@sylius/bootstrap-admin-ui` controllers package + +Older versions of the package do not expose their controllers to AssetMapper, so the `controllers.json` entry above fails. Register the controllers directory yourself instead: StimulusBundle then registers them with their file names (`copy-to-clipboard`, `theme-switcher`). + +{% code title="config/packages/asset_mapper.yaml" lineNumbers="true" %} +```yaml +framework: + asset_mapper: + paths: + assets/: '' + vendor/sylius/bootstrap-admin-ui/assets/controllers: sylius-bootstrap-admin-ui/controllers +``` +{% endcode %} + +{% code title="config/packages/stimulus.yaml" lineNumbers="true" %} +```yaml +stimulus: + controller_paths: + - '%kernel.project_dir%/assets/controllers' + - '%kernel.project_dir%/vendor/sylius/bootstrap-admin-ui/assets/controllers' +``` +{% endcode %} diff --git a/docs/bootstrap-admin-ui/components/copy-to-clipboard.md b/docs/bootstrap-admin-ui/components/copy-to-clipboard.md index a840d939..7abb7df7 100644 --- a/docs/bootstrap-admin-ui/components/copy-to-clipboard.md +++ b/docs/bootstrap-admin-ui/components/copy-to-clipboard.md @@ -132,33 +132,26 @@ Register the controller **once in the application's existing Stimulus applicatio ### AssetMapper -Follow the [AssetMapper setup](../../getting-started.md#using-assetmapper) to disable the package's `symfony_ux` entrypoint when starting your own Stimulus application. Expose the controller source directory to AssetMapper: - -```yaml -# config/packages/asset_mapper.yaml -framework: - asset_mapper: - paths: - '%kernel.project_dir%/vendor/sylius/bootstrap-admin-ui/assets/controllers': 'sylius/bootstrap-admin-ui/controllers' -``` - -Add a local importmap entry (this does not install another JavaScript package): - -```bash -php bin/console importmap:require '@sylius/bootstrap-admin-ui/copy-to-clipboard' --path=./vendor/sylius/bootstrap-admin-ui/assets/controllers/copy-to-clipboard-controller.js -``` - -In the module where your application already starts Stimulus: - -```js -import { startStimulusApp } from '@symfony/stimulus-bundle'; -import CopyToClipboardController from '@sylius/bootstrap-admin-ui/copy-to-clipboard'; - -const app = startStimulusApp(); -app.register('copy-to-clipboard', CopyToClipboardController); +Follow the [AssetMapper setup](../../getting-started.md#using-assetmapper) to disable the package's `symfony_ux` entrypoint when starting your own Stimulus application. + +The package exposes its controllers to AssetMapper. Enable the controller in your `assets/controllers.json` file, StimulusBundle then registers it with the `copy-to-clipboard` identifier: + +{% code title="assets/controllers.json" lineNumbers="true" %} +```json +{ + "controllers": { + "@sylius/bootstrap-admin-ui": { + "copy-to-clipboard": { + "enabled": true, + "fetch": "eager" + } + } + } +} ``` +{% endcode %} -If `app` is already exported by another module, import and reuse it instead of calling `startStimulusApp()` again. The application's importmap must also provide `@hotwired/stimulus`, as in a normal Symfony Stimulus installation. +See the [Assets](../assets.md#stimulus-controllers) page for the other controllers of the package. The application's importmap must also provide `@hotwired/stimulus`, as in a normal Symfony Stimulus installation. ### Webpack Encore / an existing Sylius Stimulus application diff --git a/docs/bootstrap-admin-ui/getting-started.md b/docs/bootstrap-admin-ui/getting-started.md index 0e8925f4..8f43bb62 100644 --- a/docs/bootstrap-admin-ui/getting-started.md +++ b/docs/bootstrap-admin-ui/getting-started.md @@ -15,6 +15,8 @@ Install the package using Composer and Symfony Flex: composer require sylius/bootstrap-admin-ui ``` +The package works out of the box with its prebuilt assets. If your application starts its own Stimulus application (for instance with AssetMapper), read the [Assets](assets.md) page. + ## Configuring the CRUD templates CRUD templates are split into configurable blocks. diff --git a/docs/getting-started.md b/docs/getting-started.md index 57da928a..9e42092d 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -76,30 +76,101 @@ Now, it's your turn! ### Using AssetMapper -To prevent duplicate Ajax calls, disable the auto-initialized Stimulus app and Symfony UX stylesheets from the `sylius/bootstrap-admin-ui` package, so you can take control of Stimulus initialization in your own code. +By default, the `sylius/bootstrap-admin-ui` package loads prebuilt assets that start their own Stimulus application (the `symfony_ux` hookables). +If your application uses [AssetMapper](https://symfony.com/doc/current/frontend/asset_mapper.html) and starts its own Stimulus application, disable these prebuilt assets to avoid running two Stimulus applications (and duplicate Ajax calls), and take control of Stimulus initialization in your own code. -#### Disabling Stimulus app & Symfony UX stylesheets from third party package +#### Preparing Stimulus for AssetMapper -First, you need to disable the Stimulus App started by the `sylius/bootstrap-admin-ui` package and add a custom javascript app hook for the asset mapper. +StimulusBundle needs an `assets/controllers.json` file and an `assets/controllers/` directory. +When the StimulusBundle recipe was applied on a Webpack Encore project, the `assets/controllers/` directory may not exist. In this case, Symfony Flex fails with `The "assets/controllers" directory does not exist` and does not add `@symfony/stimulus-bundle` to your `importmap.php`. + +Create the directory if needed: + +```bash +mkdir -p assets/controllers +touch assets/controllers/.gitignore +``` + +Then declare the Symfony UX controllers used by the admin panel, with the same autoimported stylesheets as the prebuilt assets: + +{% code title="assets/controllers.json" lineNumbers="true" %} +```json +{ + "controllers": { + "@symfony/ux-autocomplete": { + "autocomplete": { + "enabled": true, + "fetch": "eager", + "autoimport": { + "tom-select/dist/css/tom-select.default.css": false, + "tom-select/dist/css/tom-select.bootstrap4.css": false, + "tom-select/dist/css/tom-select.bootstrap5.css": true + } + } + }, + "@symfony/ux-live-component": { + "live": { + "enabled": true, + "fetch": "eager", + "autoimport": { + "@symfony/ux-live-component/dist/live.min.css": true + } + } + }, + "@sylius/bootstrap-admin-ui": { + "copy-to-clipboard": { + "enabled": true, + "fetch": "eager" + }, + "theme-switcher": { + "enabled": true, + "fetch": "eager" + } + } + }, + "entrypoints": [] +} +``` +{% endcode %} + +{% hint style="info" %} +The `@sylius/bootstrap-admin-ui` entry registers the Stimulus controllers shipped with the package (used by the [copy to clipboard](bootstrap-admin-ui/components/copy-to-clipboard.md) components and the theme switcher of the navbar). +Without it, these components are rendered but do nothing, without any error. +{% endhint %} + +Make sure StimulusBundle and Stimulus are in your `importmap.php`: + +```bash +php bin/console importmap:require @symfony/stimulus-bundle @hotwired/stimulus +``` + +The `@symfony/ux-autocomplete` and `@symfony/ux-live-component` packages also need their importmap entries (such as `tom-select` and the `tom-select/dist/css/*.css` files). Symfony Flex adds them when it installs these packages; if one is missing, add it with `php bin/console importmap:require`. + +#### Disabling the prebuilt Stimulus app & Symfony UX stylesheets + +Disable the `symfony_ux` hookables of the `sylius/bootstrap-admin-ui` package and add your own hookable that loads your importmap entrypoint. + +Load the importmap in the `sylius_admin.base#stylesheets` hook (in the ``) rather than in the `sylius_admin.base#javascripts` one (at the end of the ``): +the stylesheets imported by your JavaScript (Tom Select, Live Components, your own CSS) are then loaded before the page is rendered, which avoids a flash of unstyled content. +Hookables are rendered by descending priority, and the package stylesheets use the default priority (`0`): a negative priority makes sure your stylesheets come after them and can override them. {% tabs %} {% tab title="YAML" %} -{% code lineNumbers="true" %} +{% code title="config/packages/sylius_bootstrap_admin_ui.yaml" lineNumbers="true" %} ```yaml -# config/packages/sylius_bootstrap_admin_ui.yaml -# ... sylius_twig_hooks: hooks: # ... - # Disabling Symfony UX stylesheets 'sylius_admin.base#stylesheets': + # Disabling Symfony UX stylesheets symfony_ux: - enabled: false - - 'sylius_admin.base#javascripts': + enabled: false + # New hookable, rendered after the package stylesheets app: - priority: 200 - template: 'base/javascripts/app.html.twig' + template: 'base/stylesheets/app.html.twig' + priority: -100 + + 'sylius_admin.base#javascripts': # Disabling Stimulus App symfony_ux: enabled: false @@ -122,20 +193,20 @@ return static function (ContainerConfigurator $containerConfigurator): void { 'symfony_ux' => [ 'enabled' => false, ], + // New hookable, rendered after the package stylesheets + 'app' => [ + 'template' => 'base/stylesheets/app.html.twig', + 'priority' => -100, + ], ], - + 'sylius_admin.base#javascripts' => [ - // New hook - 'app' => [ - 'priority' => 200, - 'template' => 'base/javascripts/app.html.twig', - ], - // Disabling Stimulus App + // Disabling Stimulus App 'symfony_ux' => [ 'enabled' => false, ], ], - ], + ], ]); }; ``` @@ -143,7 +214,7 @@ return static function (ContainerConfigurator $containerConfigurator): void { {% endtab %} {% endtabs %} -{% code title="base/javascripts/app.html.twig" lineNumbers="true" %} +{% code title="templates/base/stylesheets/app.html.twig" lineNumbers="true" %} ```twig {{ importmap('app') }} ``` @@ -165,3 +236,5 @@ const app = startStimulusApp(); import './bootstrap.js'; // ... ``` + +The controllers declared in `assets/controllers.json` and the ones in your `assets/controllers/` directory are registered automatically. diff --git a/src/BootstrapAdminUi/assets/package.json b/src/BootstrapAdminUi/assets/package.json new file mode 100644 index 00000000..fcc2f98e --- /dev/null +++ b/src/BootstrapAdminUi/assets/package.json @@ -0,0 +1,24 @@ +{ + "name": "@sylius/bootstrap-admin-ui", + "description": "Stimulus controllers of the Sylius Bootstrap Admin UI package.", + "license": "MIT", + "private": true, + "symfony": { + "controllers": { + "copy-to-clipboard": { + "main": "controllers/copy-to-clipboard-controller.js", + "name": "copy-to-clipboard", + "webpackMode": "eager", + "fetch": "eager", + "enabled": true + }, + "theme-switcher": { + "main": "controllers/theme-switcher-controller.js", + "name": "theme-switcher", + "webpackMode": "eager", + "fetch": "eager", + "enabled": true + } + } + } +} diff --git a/src/BootstrapAdminUi/src/Symfony/SyliusBootstrapAdminUiBundle.php b/src/BootstrapAdminUi/src/Symfony/SyliusBootstrapAdminUiBundle.php index ff4fb436..d785b31b 100644 --- a/src/BootstrapAdminUi/src/Symfony/SyliusBootstrapAdminUiBundle.php +++ b/src/BootstrapAdminUi/src/Symfony/SyliusBootstrapAdminUiBundle.php @@ -13,6 +13,7 @@ namespace Sylius\BootstrapAdminUi\Symfony; +use Symfony\Component\AssetMapper\AssetMapperInterface; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; @@ -42,6 +43,18 @@ public function prependExtension(ContainerConfigurator $container, ContainerBuil $loader->load('services.php'); + if ($this->isAssetMapperAvailable($builder)) { + // Exposes the bundle Stimulus controllers to AssetMapper, + // so they can be enabled from the application "assets/controllers.json" file. + $builder->prependExtensionConfig('framework', [ + 'asset_mapper' => [ + 'paths' => [ + dirname(__DIR__, 2) . '/assets/controllers' => '@sylius/bootstrap-admin-ui/controllers', + ], + ], + ]); + } + if (!isset($bundles['SyliusAdminUiBundle'])) { return; } @@ -51,4 +64,19 @@ public function prependExtension(ContainerConfigurator $container, ContainerBuil 'hook_name_section_separator' => '#', ]); } + + private function isAssetMapperAvailable(ContainerBuilder $builder): bool + { + if (!interface_exists(AssetMapperInterface::class)) { + return false; + } + + /** @var array $bundlesMetadata */ + $bundlesMetadata = $builder->getParameter('kernel.bundles_metadata'); + if (!isset($bundlesMetadata['FrameworkBundle'])) { + return false; + } + + return is_file($bundlesMetadata['FrameworkBundle']['path'] . '/Resources/config/asset_mapper.php'); + } }