{"id":13618104,"url":"https://github.com/symfony/stimulus-bridge","last_synced_at":"2025-04-04T11:08:45.760Z","repository":{"id":37833311,"uuid":"317178763","full_name":"symfony/stimulus-bridge","owner":"symfony","description":"Stimulus integration bridge for Symfony projects","archived":false,"fork":false,"pushed_at":"2025-01-29T18:40:17.000Z","size":394,"stargazers_count":81,"open_issues_count":11,"forks_count":16,"subscribers_count":11,"default_branch":"main","last_synced_at":"2025-03-28T10:04:29.349Z","etag":null,"topics":["javascript","symfony"],"latest_commit_sha":null,"homepage":"https://symfony.com/ux","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/symfony.png","metadata":{"funding":{"github":"fabpot","tidelift":"packagist/symfony/symfony","custom":"https://symfony.com/sponsor"},"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-11-30T09:51:49.000Z","updated_at":"2025-02-05T13:08:27.000Z","dependencies_parsed_at":"2024-04-09T11:40:20.195Z","dependency_job_id":"855f8bae-85a5-4f4c-a6f4-d52983032142","html_url":"https://github.com/symfony/stimulus-bridge","commit_stats":{"total_commits":57,"total_committers":10,"mean_commits":5.7,"dds":0.5789473684210527,"last_synced_commit":"d58dc502386573b93cc7442939b4053620ab7966"},"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/symfony%2Fstimulus-bridge","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/symfony%2Fstimulus-bridge/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/symfony%2Fstimulus-bridge/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/symfony%2Fstimulus-bridge/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/symfony","download_url":"https://codeload.github.com/symfony/stimulus-bridge/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247166167,"owners_count":20894654,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["javascript","symfony"],"created_at":"2024-08-01T20:01:54.541Z","updated_at":"2025-04-04T11:08:45.742Z","avatar_url":"https://github.com/symfony.png","language":"TypeScript","funding_links":["https://github.com/sponsors/fabpot","https://tidelift.com/funding/github/packagist/symfony/symfony","https://symfony.com/sponsor"],"categories":["TypeScript"],"sub_categories":[],"readme":"# Symfony UX Stimulus bridge\n\nThe Stimulus bridge integrates [Stimulus](https://stimulus.hotwired.dev/)\ninto your Symfony app by automatically loading both third-party controllers\nand your own custom controllers. It works by reading a `controllers.json`\nfile that describes your third-party controllers. This file is updated\nautomatically when you install [Symfony UX Packages](https://github.com/symfony/ux).\n\nBefore you start, familiarize yourself with the basics of\n[Stimulus](https://stimulus.hotwired.dev/).\n\n## Installation\n\nIf you don't already have Webpack Encore installed, install it with:\n\n```\ncomposer require encore\n```\n\nIf you didn't already have Webpack Encore installed, this should execute a\nSymfony Flex recipe that will set up everything for you. Finish by\nrunning Encore:\n\n```sh\nnpm encore dev --watch\n```\n\nIf you already had Encore installed (and so the recipe did not run), you\ncan always install things manually.\n\n## Manual Installation\n\nThe Webpack Encore recipe usually handles setting up everything you need.\nBut you can also do it manually. First, install the bridge:\n\n```sh\nnpm add @symfony/stimulus-bridge @hotwired/stimulus --dev\n```\n\nNext, create an `assets/controllers.json` file: Flex will update\nthis whenever you install a UX package:\n\n```json\n{\n    \"controllers\": [],\n    \"entrypoints\": []\n}\n```\n\nNow, enable the Stimulus Bridge in Webpack Encore:\n\n```javascript\n// webpack.config.js\n\n// Provide the location of your controllers.json file\nEncore.enableStimulusBridge('./assets/controllers.json');\n```\n\nFinally, use the package in your JavaScript code. This will register\nany controllers defined in `controllers.json` (these are added\nautomatically when installing UX packages) and any controllers that\nyou add in `assets/controllers/`:\n\n```javascript\n// assets/app.js\n// (or assets/bootstrap.js - and then import it from app.js)\n\nimport { startStimulusApp } from '@symfony/stimulus-bridge';\n\nexport const app = startStimulusApp(require.context(\n    '@symfony/stimulus-bridge/lazy-controller-loader!./controllers',\n    true,\n    /\\.(j|t)sx?$/\n));\n```\n\nThat's it! Now run Encore:\n\n```sh\nnpm encore watch\n```\n\n## Usage: Installing UX Packages\n\nOnce the bridge is installed and enabled, you can use any of the\n[Symfony UX Packages](https://github.com/symfony/ux). After installing\neach one, Symfony Flex will update your `assets/controllers.json` file.\nThat will cause this bridge to automatically import and register that\ncontroller so that you can use it *immediately* without any configuration.\n\n## Usage: Creating Custom Controllers\n\nYou'll also want to create your own custom controllers. The bridge\nautomatically registers any controllers that live in the `assets/controllers/`.\n\nLet's see an example: create a new `assets/controllers/hello_controller.js`\nfile (you may already have this):\n\n```\nimport { Controller } from '@hotwired/stimulus';\n\nexport default class extends Controller {\n    connect() {\n        this.element.textContent = 'Hello Stimulus! Edit me in assets/controllers/hello_controller.js';\n    }\n}\n```\n\nBecause this file is called `hello_controller.js`, it will register a controller\nnamed (`hello`). This follows the standard Stimulus naming conventions. Thanks\nto this, in any template, you can now add an element that uses this:\n\n```twig\n# templates/anything/any_template.html.twig\n\n\u003cdiv data-controller=\"hello\"\u003e\u003c/div\u003e\n```\n\nTry it! When you refresh the page, your controller will be executed and\nthe source will update to:\n\n```html\n\u003cdiv data-controller=\"hello\"\u003e\n    Hello Stimulus! Edit me in assets/controllers/hello_controller.js    \n\u003c/div\u003e\n```\n\nIf the controller lives in a subdirectory - like `assets/controllers/blog/post/author_controller.js` -\nthe name will include `--` in place of each `/`:\n\n```html\n\u003cdiv data-controller=\"blog--post--author\"\u003e\n    \u003cdiv data-blog--post--author-target=\"author\"\u003e...\u003c/div\u003e\n\u003c/div\u003e\n```\n\nSee the [Stimulus Docs](https://stimulus.hotwired.dev/handbook/introduction)\nfor what else Stimulus can do!\n\n## Common Errors\n\nIf you get this error:\n\n\u003e ./assets/bootstrap.js contains a reference to the file @symfony/autoimport.\n\u003e This file can not be found.\n\nRemove the following line in the mentioned file: it's not needed anymore:\n\n```diff\n// assets/bootstrap.js\n\n// ...\n- import '@symfony/autoimport';\n```\n\nIf you get the error:\n\n\u003e Cannot find module '@symfony/stimulus-bridge/webpack-helper'\n\nBe sure to upgrade to `@symfony/webpack-encore` version 1.0.0 or higher.\n\n## The controllers.json File\n\nThe bridge works by reading a `controllers.json` file that is automatically\nupdated by Symfony Flex whenever you download a UX-powered package. For\nexample, after running `composer require symfony/ux-dropzone`, it will\nlook like this:\n\n```json\n{\n    \"controllers\": {\n        \"@symfony/ux-dropzone\": {\n            \"dropzone\": {\n                \"enabled\": true,\n                \"fetch\": \"eager\",\n                \"autoimport\": {\n                    \"@symfony/ux-dropzone/src/style.css\": true\n                }\n            }\n        }\n    },\n    \"entrypoints\": []\n}\n```\n\nEach item under `controllers` will cause a Stimulus controller to be\nregistered with a specific name - in this case the controller would\nbe called `symfony--ux-dropzone--dropzone` (the `/` becomes `--`).\n\nBy default, the new controller will always be included in your\nJavaScript package. You can control that with the `fetch` option,\nordered from least to most lazy:\n\n* `fetch: 'eager'`: controller \u0026 dependencies are included in the JavaScript\n  that's downloaded when the page is loaded.\n* `fetch: 'lazy'`: controller \u0026 dependencies are isolated into a\n  separate file and only downloaded asynchronously if (and when) the `data-controller`\n  HTML appears on the page.\n\n## Lazy Controllers\n\n**NOTE**: When using lazy controllers, you may notice in your browser's console that\nyour controller appears to be initialized and connected *twice*. But actually, the\nfirst initialize and connect are just a result of an internal controller setting\nup your real controller.\n\nYou can also make your own controllers \"lazy\": giving them the same behavior\nas the `lazy-controller` explained above. In this case, your controller isn't\ndownloaded until an element for that controller first appears on the page.\n\nTo activate this, first make sure that you're using the special loader -\n`@symfony/stimulus-bridge/lazy-controller-loader` - when loading your controllers:\n\n```js\n// assets/bootstrap.js\n\nexport const app = startStimulusApp(require.context(\n    '@symfony/stimulus-bridge/lazy-controller-loader!./controllers',\n    true,\n    /\\.(j|t)sx?$/\n));\n```\n\nNext, you can make any controllers lazy by adding a `/* stimulusFetch: 'lazy' */`\ncomment above that controller:\n\n```js\nimport { Controller } from '@hotwired/stimulus';\n\n/* stimulusFetch: 'lazy' */\nexport default class extends Controller {\n    // ...\n}\n```\n\n### Advanced Lazy Controllers\n\nSometimes you may want to use a third-party controller and make it lazy.\nUnfortunately, you can't edit that controller's source code to add\nthe `/* stimulusFetch: 'lazy' */`.\n\nTo handle this, you can use the `lazy-controller-loader` with some\ncustom query options.\n\n```js\n// assets/bootstrap.js\n\nimport { startStimulusApp } from '@symfony/stimulus-bridge';\n\n// example from https://stimulus-components.netlify.app/docs/components/stimulus-clipboard/\n// normal, non-lazy import\n//import Clipboard from 'stimulus-clipboard';\n// lazy import\nimport Clipboard from '@symfony/stimulus-bridge/lazy-controller-loader?lazy=true!stimulus-clipboard';\n\n// example from https://github.com/afcapel/stimulus-autocomplete\n// normal, non-lazy import\n//import { Autocomplete } from 'stimulus-autocomplete';\n// lazy import - it includes export=Autocomplete to handle the named export\nimport { Autocomplete } from '@symfony/stimulus-bridge/lazy-controller-loader?lazy=true\u0026export=Autocomplete!stimulus-autocomplete';\n\nconst app = startStimulusApp(require.context(\n    // your existing code to load from controllers/\n));\n\n// the normal way to manually register controllers\napp.register('clipboard', Clipboard);\napp.register('autocomplete', Autocomplete);\n\nexport { app };\n```\n\n## Writing TypeScript controllers\n\nIf you want to write TypeScript controllers, make sure the target of your TypeScript config is set to `ES6`:\n\n```json\n{\n    \"compilerOptions\": {\n        //...\n        \"target\": \"ES6\",\n    },\n    //...\n}\n```\n\nIf you don't you may face the following issue in your browser console when the controller is called:\n\n```\n# Error thrown in Chrome console:\nUncaught (in promise) TypeError: Class constructor Controller cannot be invoked without 'new'\n\n# Error thrown in Firefox console:\nUncaught (in promise) TypeError: class constructors must be invoked with 'new'\n```\n\nThe error is caused when an ES5 class tries to \"extend\" an ES6 class. If the target is not correctly set, \nTypeScript will transpile the controller to old ES5 code. But Stimulus 3 uses pure ES6 classes. \nThis causes an incompatibility, hence the need to target ES6 explicitly.\n\n## Contributing\n\nThank you for considering contributing to the Symfony's Stimulus Bridge! You can find the [contribution guide here](./CONTRIBUTING.md).","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsymfony%2Fstimulus-bridge","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsymfony%2Fstimulus-bridge","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsymfony%2Fstimulus-bridge/lists"}