{"id":18707929,"url":"https://github.com/discourse/ember-route-template","last_synced_at":"2025-10-28T06:32:51.803Z","repository":{"id":193819810,"uuid":"688662457","full_name":"discourse/ember-route-template","owner":"discourse","description":null,"archived":false,"fork":false,"pushed_at":"2025-02-23T19:38:33.000Z","size":2289,"stargazers_count":30,"open_issues_count":9,"forks_count":5,"subscribers_count":15,"default_branch":"main","last_synced_at":"2025-03-28T19:08:24.180Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/discourse.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","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":"2023-09-07T20:40:05.000Z","updated_at":"2025-02-14T20:56:13.000Z","dependencies_parsed_at":"2024-11-07T12:22:36.292Z","dependency_job_id":"c97acd2a-4e75-4924-95de-27be71cad8a4","html_url":"https://github.com/discourse/ember-route-template","commit_stats":null,"previous_names":["discourse/ember-route-template"],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/discourse%2Fember-route-template","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/discourse%2Fember-route-template/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/discourse%2Fember-route-template/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/discourse%2Fember-route-template/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/discourse","download_url":"https://codeload.github.com/discourse/ember-route-template/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247242679,"owners_count":20907134,"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":[],"created_at":"2024-11-07T12:20:27.561Z","updated_at":"2025-10-28T06:32:51.725Z","avatar_url":"https://github.com/discourse.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ember-route-template\n\n[eti]: https://github.com/ember-template-imports/ember-template-imports\n[polaris]: https://blog.emberjs.com/ember-5-0-released/#toc_the-journey-towards-ember-polaris\n[resources]: https://github.com/NullVoxPopuli/ember-resources/blob/main/docs/docs/README.md\n[rfc]: https://rfcs.emberjs.com/id/0779-first-class-component-templates/#typescript\n[discourse]: https://discourse.org\n\nProvides an adapter for using [`\u003ctemplate\u003e` tags][eti] and components as route\ntemplates.\n\n## Motivation\n\nSo you have adopted [`\u003ctemplate\u003e` tags][eti] in your app, and everything has\nbeen great. It's time to add a new route to the app. You created a `.gjs` file\nand programmed away, importing components and helper functions left and right,\nmaybe even declaring local JavaScript helpers for use in the template.\n\nWhen you are done, you tested it out in the browser, and everything broke. The\nhorror!\n\nUnfortunately, Ember does not support `\u003ctemplate\u003e` tags as route templates at\nthe moment. This is an obvious coherence gap that needs to be addressed in\n[Polaris edition][polaris], likely by doing away with the controllers and route\ntemplates altogether, in favor of making the route itself a component with a\n`\u003ctemplate\u003e` on it, and using the [resources][resources] pattern for data\nfetching.\n\nIn the meantime though, this can leave you in a tricky situation. As your app\nand your team gets deeper into the `\u003ctemplate\u003e` tag paradigm, it can be awkward\nto author route templates in the old paradigm, and you may even find yourself\nhaving to re-export certain component/modifier/helpers from `app/` and make\nthem globally available, just so they can be used in route templates.\n\nThis addon bridges the gap by shipping a small adapter that turns `\u003ctemplate\u003e`\nand components into the route template format Ember currently expects, so you\ncan use the full feature set of `.gjs` in routes.\n\nEventually, this addon won't be necessary anymore when the new Polaris routing\nparadigm is available.\n\n## Usage\n\n```js\n// app/templates/my-route.gjs\nimport RouteTemplate from 'ember-route-template';\n\n// This adapter converts the `\u003ctemplate\u003e` into a route template\nexport default RouteTemplate(\u003ctemplate\u003eHello world!\u003c/template\u003e);\n```\n\nYour `\u003ctemplate\u003e` will have access to the `{{@model}}` and `{{@controller}}`\narguments, if you need them. Other features like plain function helpers and\nthe ability to import components (etc) into the `\u003ctemplate\u003e` scope works as\nusual:\n\n```js\n// app/templates/my-route.gjs\nimport RouteTemplate from \"ember-route-template\";\n\n// components can be imported as usual\nimport Hello from \"my-app/components/hello\";\n\n// plain functions work, as usual\nfunction stringify(value) {\n  if (typeof value?.name === 'string') {\n    return value.name;\n  } else {\n    return String(value);\n  }\n}\n\n// This adapter converts the `\u003ctemplate\u003e` into a route template\nexport default RouteTemplate(\n  \u003ctemplate\u003e\n    The model is: {{stringify @model}}\n    The controller is: {{stringify @controller}}\n    \u003cHello @message=\"this is great!\" /\u003e\n  \u003c/template\u003e\n);\n```\n\nYou can even convert components into route templates with this adapter (a.k.a.\n\"routable components\"):\n\n```js\n// app/templates/my-route.gjs\nimport RouteTemplate from 'ember-route-template';\nimport Component from \"@glimmer/component\";\n\nclass MyRouteComponent extends Component {\n  \u003ctemplate\u003eHello, {{this.message}}. Why was I screaming?\u003c/template\u003e\n\n  get message() {\n    return String(this.args.model).toUpperCase();\n  }\n}\n\nexport default RouteTemplate(MyRouteComponent);\n```\n\nWith this feature, it eliminates most of the reasons for needing controllers,\nother than for query params (which is another coherence gap Polaris would need\nto address). We suggest exploring moving your non-QP controller logic into a\ncomponent this way, treating controllers as \"QP services\" and nothing else.\n\n## How it works\n\n[Under the hood](./ember-route-template/src/index.ts), the adapter generates\na route template that simply invokes the `\u003ctemplate\u003e` or component you passed\nin with the `@model` and `@controller` arguments appropriately set.\n\nThe hello world example from above is similar to first creating the component\nin the usual global location in `app/components`:\n\n```js\n// app/components/hello-world.gjs\n\u003ctemplate\u003eHello world!\u003c/template\u003e\n```\n\nThen create a route template whose only job is to invoke that component:\n\n```hbs\n{{! app/templates/my-route.hbs }}\n\u003cHelloWorld @model={{@model}} @controller={{this}} /\u003e\n```\n\nWith the adapter from this addon, the main advantage is that it allows you to\nkeep your route `\u003ctemplate\u003e` or component anonymous, without making it globally\navailable in `app/components` since it likely would not make sense to reuse a\nroute specific `\u003ctemplate\u003e` or component elsewhere in the app.\n\nOf course, nothing is stopping you from exporting those values as additional\nnamed exports, if you need to access them from elsewhere.\n\n## TypeScript and Glint\n\nTypeScript and Glint is fully supported, just use the `.gts` extension instead.\n\nOne caveat is that Glint cannot automatically infer the `@model`/`@controller`\narguments, and you will get a type error when trying to access them from the\n`\u003ctemplate\u003e`, which is the usual problem you've always had with template-only\ncomponents in Glint.\n\nAccording to the [RFC][rfc], you can supply a signature like this:\n\n```tsx\n// app/templates/my-route.gts\nimport RouteTemplate from \"ember-route-template\";\n\ninterface MyRouteSignature {\n  Args: {\n    model: string;\n  }\n}\n\nexport default RouteTemplate(\n  // This does not actually work!\n  \u003ctemplate[MyRouteSignature]\u003e\n    Now Glint is supposed to know {{@model}} is a string.\n  \u003c/template\u003e\n);\n```\n\nHowever, as of writing, this feature was never implemented, and the Ember\nTypeScript is considering other alternatives. In the meantime, the adapter\nfunction can accept a generic argument for the signature to make things easier:\n\n```tsx\n// app/templates/my-route.gts\nimport RouteTemplate from \"ember-route-template\";\n\ninterface MyRouteSignature {\n  Args: {\n    model: string;\n  }\n}\n\nexport default RouteTemplate\u003cMyRouteSignature\u003e(\n  \u003ctemplate\u003e\n    Now Glint is supposed to know {{@model}} is a string.\n  \u003c/template\u003e\n);\n```\n\nThis feature is only needed for bare `\u003ctemplate\u003e` tags. Class-based components\ndon't have this issue as they already accept a signature generic:\n\n```tsx\n// app/templates/my-route.gts\nimport RouteTemplate from \"ember-route-template\";\nimport Component from \"@glimmer/component\";\n\ninterface MyRouteSignature {\n  Args: {\n    model: string;\n  }\n}\n\nclass MyRouteComponent extends Component\u003cMyRouteSignature\u003e {\n  \u003ctemplate\u003e\n    Glint knows this is a string: {{@model}}\n  \u003c/template\u003e\n}\n\nexport default RouteTemplate(MyRouteComponent);\n```\n\n## Compatibility\n\n- Ember.js v3.28 or above\n- Embroider or ember-auto-import v2\n\n## Installation\n\n```\nember install ember-route-template\n```\n\n## Contributing\n\nSee the [Contributing](CONTRIBUTING.md) guide for details.\n\n## License\n\nThis project is licensed under the [MIT License](LICENSE.md).\n\n## Thanks\n\nThe development of this addon was initial funded by [Discourse][discourse].\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiscourse%2Fember-route-template","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdiscourse%2Fember-route-template","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiscourse%2Fember-route-template/lists"}