From defda5881f00cc68b4e99760f42d963110f3950d Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Fri, 6 Oct 2023 13:11:54 -0400 Subject: [PATCH 01/10] Rough first draft of the start of https://github.com/emberjs/rfcs/pull/977 --- text/0977-template.md | 141 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 text/0977-template.md diff --git a/text/0977-template.md b/text/0977-template.md new file mode 100644 index 0000000000..05309d5bf8 --- /dev/null +++ b/text/0977-template.md @@ -0,0 +1,141 @@ +--- +stage: accepted +start-date: 2023-10-06 +release-date: # In format YYYY-MM-DDT00:00:00.000Z +release-versions: +teams: # delete teams that aren't relevant + - cli + - data + - framework + - learning +prs: + accepted: https://github.com/emberjs/rfcs/pull/977 +project-link: +suite: +--- + + + +# v2 App Format + +## Summary + +This RFC defines a new app format, +building off the prior work in [v2 Addon format](https://github.com/emberjs/rfcs/pull/507), +that is designed to make Ember apps more compatible with the rest of the JavaScript ecosystem. This RFC will define conventions of the app such that it is _possible_ to confidently build an ember app without ember-cli (e.g.: in jsbin). + +## Motivation + +Ember has a long-standing tradition of pioneering developer-friendly conventions, allowing developers to build powerful web applications with minimal configuration. Over the years, we have embraced the philosophy of "convention over configuration," making it easy for developers to get started and achieve consistency across Ember projects. + +However, as the JavaScript ecosystem evolves, it becomes increasingly important for Ember to adapt and interoperate seamlessly with the broader web development landscape. The introduction of a v2 app format is driven by several key motivations: + +1. Compatibility with the JavaScript Ecosystem + +Ember's success lies not only in its robust features but also in its ability to integrate effortlessly with other JavaScript libraries and tools. With the v2 app format, we aim to make Ember applications more compatible with the rest of the JavaScript ecosystem. This means that developers should feel confident in building Ember applications without the need for specialized tooling like ember-cli. Whether it's experimenting with code in an environment like jsbin or integrating Ember into projects that use native packagers like Vite, Webpack, or Turbopack, the v2 app format should empower developers to work seamlessly with Ember in diverse contexts. + + +2. Improved Insight into App Initialization + +Ember's boot process lacks clear, documented specifications. This lack of clarity means that developers often struggle to comprehend the precise steps involved in booting an Ember app manually (if they ever attempt to do so). + +The v2 app format aims to rectify this by providing comprehensive documentation that outlines the intricacies of an Ember app's initialization process. By shedding light on the sequence of steps necessary to bootstrap an Ember application, developers will gain a deeper understanding of the framework's internal mechanisms. This newfound knowledge will empower developers to confidently control and customize the app initialization process, enabling them to tailor Ember apps to their specific needs. + +3. Performance and Optimization + +Performance is a critical concern for modern web applications. The v2 app format is designed to deliver tangible benefits to Ember developers and users. Most importantly, all capabilities of a chosen packager (be that Vite, Webpack, turbopack, etc) would become available to Ember (module federation, alternative SSR methods, etc). + +4. Interoperability with Native Packagers + +Embracing native packagers such as Vite, Webpack, and Turbopack is crucial for staying current with JavaScript ecosystem trends. The v2 app format is designed to accommodate these packagers seamlessly, ensuring that Ember applications can harness the benefits of these tools while maintaining compatibility. + +5. Future-Proofing + +Lastly, the v2 app format positions Ember to take advantage of ongoing and future developments in the wider JavaScript ecosystem related to code bundling and optimization. By aligning with industry trends, Ember remains a forward-looking framework, ready to embrace new technologies and practices. + +## Detailed design + +How much of this should be "the path/migration to" as opposed to "this is the end state, details can be part of implementation"? + +1. start with embroider-strictest +2. all blueprint addons must be either in the v2 format, or non-addons entirely (such as qunit-dom's recent change to real type=module package) +3. use Vite w/ embroider +4. remove unneeded dependencies + - ember-auto-import + - replaced by _the packager's_ own way of processing dependencies + (requires all consumed dependencies to _not_ be v1 addons) + - broccoli-asset-rev + - replaced by _the packager's_ production build mode + - ember-cli-babel + - replaced by actual babel + - ember-cli-clean-css + - replaced by _the packager's_ production build mode + - ember-cli-htmlbars + - replaced by [babel-plugin-ember-template-compilation](https://github.com/emberjs/babel-plugin-ember-template-compilation/) and embroider-provided build plugins + - ember-cli-inject-live-reload + - replaced by _the packager's_ development mode + - ember-cli-sri + - replaced by _the packager's_ production build mode + - ember-cli-terser + - replaced by _the packager's_ production build mode + - ember-fetch + - requires work in `@ember/test-helpers` and `ember-fetch` to make this smooth. + - ember-load-initializers + - tbd + - ember-resolver + - tbd + - loader.js + - require / AMD has been private for a long time, and folks should not be using it. + + +> This is the bulk of the RFC. + +> Explain the design in enough detail for somebody +familiar with the framework to understand, and for somebody familiar with the +implementation to implement. This should get into specifics and corner-cases, +and include examples of how the feature is used. Any new terminology should be +defined here. + +## How we teach this + +> What names and terminology work best for these concepts and why? How is this +idea best presented? As a continuation of existing Ember patterns, or as a +wholly new one? + +> Would the acceptance of this proposal mean the Ember guides must be +re-organized or altered? Does it change how Ember is taught to new users +at any level? + +> How should this feature be introduced and taught to existing Ember +users? + +## Drawbacks + +> Why should we *not* do this? Please consider the impact on teaching Ember, +on the integration of this feature with other existing and planned features, +on the impact of the API churn on existing apps, etc. + +> There are tradeoffs to choosing any path, please attempt to identify them here. + +## Alternatives + +> What other designs have been considered? What is the impact of not doing this? + +> This section could also include prior art, that is, how other frameworks in the same domain have solved this problem. + +## Unresolved questions + +> Optional, but suggested for first drafts. What parts of the design are still +TBD? From 095a2f9958e66d1f3a530ac3a16e220521d3c78d Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Sat, 4 Nov 2023 11:02:03 -0400 Subject: [PATCH 02/10] Update text/0977-template.md Co-authored-by: MrChocolatine <47531779+MrChocolatine@users.noreply.github.com> --- text/0977-template.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0977-template.md b/text/0977-template.md index 05309d5bf8..9ead02c803 100644 --- a/text/0977-template.md +++ b/text/0977-template.md @@ -70,7 +70,7 @@ Lastly, the v2 app format positions Ember to take advantage of ongoing and futur How much of this should be "the path/migration to" as opposed to "this is the end state, details can be part of implementation"? 1. start with embroider-strictest -2. all blueprint addons must be either in the v2 format, or non-addons entirely (such as qunit-dom's recent change to real type=module package) +2. all blueprint addons must be either in the v2 format, or non-addons entirely (such as qunit-dom's recent change to real `type=module` package) 3. use Vite w/ embroider 4. remove unneeded dependencies - ember-auto-import From ceab8f96c013bcce1e39f58a9eee6e3a8bba4bb4 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Sat, 4 Nov 2023 11:02:10 -0400 Subject: [PATCH 03/10] Update text/0977-template.md Co-authored-by: MrChocolatine <47531779+MrChocolatine@users.noreply.github.com> --- text/0977-template.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0977-template.md b/text/0977-template.md index 9ead02c803..53d258ea37 100644 --- a/text/0977-template.md +++ b/text/0977-template.md @@ -71,7 +71,7 @@ How much of this should be "the path/migration to" as opposed to "this is the en 1. start with embroider-strictest 2. all blueprint addons must be either in the v2 format, or non-addons entirely (such as qunit-dom's recent change to real `type=module` package) -3. use Vite w/ embroider +3. use Vite with Embroider 4. remove unneeded dependencies - ember-auto-import - replaced by _the packager's_ own way of processing dependencies From 490c1666a4a9eba88b7a070e6022506bcc4b7ee1 Mon Sep 17 00:00:00 2001 From: Chris Manson Date: Tue, 5 Nov 2024 13:07:49 +0000 Subject: [PATCH 04/10] fix file name --- text/{0977-template.md => 0977-v2-app-format.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename text/{0977-template.md => 0977-v2-app-format.md} (100%) diff --git a/text/0977-template.md b/text/0977-v2-app-format.md similarity index 100% rename from text/0977-template.md rename to text/0977-v2-app-format.md From b3ee0f5df72bbed4e24a74ffb8ac42c6d2c9edbd Mon Sep 17 00:00:00 2001 From: Chris Manson Date: Wed, 13 Nov 2024 07:28:38 +0000 Subject: [PATCH 05/10] update content --- text/0977-v2-app-format.md | 46 +++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/text/0977-v2-app-format.md b/text/0977-v2-app-format.md index 53d258ea37..98641fb22e 100644 --- a/text/0977-v2-app-format.md +++ b/text/0977-v2-app-format.md @@ -33,39 +33,46 @@ suite: Leave as is ## Summary This RFC defines a new app format, -building off the prior work in [v2 Addon format](https://github.com/emberjs/rfcs/pull/507), -that is designed to make Ember apps more compatible with the rest of the JavaScript ecosystem. This RFC will define conventions of the app such that it is _possible_ to confidently build an ember app without ember-cli (e.g.: in jsbin). +building off the prior work in [v2 Addon format](https://rfcs.emberjs.com/id/0507-embroider-v2-package-format), +that is designed to make Ember apps more compatible with the rest of the JavaScript ecosystem. This RFC will define conventions of the app and clearly identify functionality that is considered "compat" and could be considered optional in the near future. ## Motivation -Ember has a long-standing tradition of pioneering developer-friendly conventions, allowing developers to build powerful web applications with minimal configuration. Over the years, we have embraced the philosophy of "convention over configuration," making it easy for developers to get started and achieve consistency across Ember projects. +When ember-cli was created there was no existing JS tooling that met the needs of the Ember Framework. Over the years we have added more and more developer-friendly conventions to our build system that many Ember applications and addons depend on. As the JavaScript tooling story has gotten a lot better of the years Ember has fallen behind because our custom-built tools have not been keeping up with the wider community. Efforts have been started to improve the situation with the advent of [Embroider](https://github.com/embroider-build/embroider) but the current stable release of Embroider still runs inside ember-cli and is somewhat bound in performance and capability by the underlying technology [broccolijs](https://github.com/broccolijs/broccoli). -However, as the JavaScript ecosystem evolves, it becomes increasingly important for Ember to adapt and interoperate seamlessly with the broader web development landscape. The introduction of a v2 app format is driven by several key motivations: +Over the past year the Ember Core Tooling team have been working hard to invert the control between the bundler and ember-cli, which means that instead of ember-cli running the bundler as part of its build system the whole Ember build process will essentially become a plugin to the bundler. This means that we can more effectively make use of bundler innovations, performance improvements, and we are more capable of adapting to whatever next generation of build systems come to the Javascript ecosystemm. -1. Compatibility with the JavaScript Ecosystem +With the Ember build system as a plugin to bundlers (such as Vite or Webpack) we also have the ability to only intervene on things that are Emberisims (i.e. not-standard) and as we work to make Ember more standard we can eventually turn off these compat plugins. -Ember's success lies not only in its robust features but also in its ability to integrate effortlessly with other JavaScript libraries and tools. With the v2 app format, we aim to make Ember applications more compatible with the rest of the JavaScript ecosystem. This means that developers should feel confident in building Ember applications without the need for specialized tooling like ember-cli. Whether it's experimenting with code in an environment like jsbin or integrating Ember into projects that use native packagers like Vite, Webpack, or Turbopack, the v2 app format should empower developers to work seamlessly with Ember in diverse contexts. +This RFC is not going to describe a new blueprint where you don't need any compatibility plugins to run an Ember app, this RFC instead is going to propose a new blueprint that has all the compatibility plugins turned on so that it is easiest for most people to upgrade to. +## Key Ideas -2. Improved Insight into App Initialization +Much like the [v2 Addon format RFC](https://rfcs.emberjs.com/id/0507-embroider-v2-package-format#key-ideas) we want the new app blueprint to rely on ES Modules and not leave anything hidden or automatic. This not noly makes it easier for developers to know where things are coming from, it also makes it easier for bundlers to know what to do with Ember applications. -Ember's boot process lacks clear, documented specifications. This lack of clarity means that developers often struggle to comprehend the precise steps involved in booting an Ember app manually (if they ever attempt to do so). +Each of the following sections go into detail of all the changes between the current blueprint and the new proposal which is currently being developed at https://github.com/embroider-build/app-blueprint -The v2 app format aims to rectify this by providing comprehensive documentation that outlines the intricacies of an Ember app's initialization process. By shedding light on the sequence of steps necessary to bootstrap an Ember application, developers will gain a deeper understanding of the framework's internal mechanisms. This newfound knowledge will empower developers to confidently control and customize the app initialization process, enabling them to tailor Ember apps to their specific needs. +## Detailed design -3. Performance and Optimization +In this section I'm going to go through each of the changes in the new proposed blueprint, in each section I will do my best to explain the reasoningin for why it needs to be like this but if you have any questions or comments please feel free to comment on the RFC and we will try to update that section. -Performance is a critical concern for modern web applications. The v2 app format is designed to deliver tangible benefits to Ember developers and users. Most importantly, all capabilities of a chosen packager (be that Vite, Webpack, turbopack, etc) would become available to Ember (module federation, alternative SSR methods, etc). +### Entrypoint -> index.html -4. Interoperability with Native Packagers +### App Entrypoint -> app/app.js -Embracing native packagers such as Vite, Webpack, and Turbopack is crucial for staying current with JavaScript ecosystem trends. The v2 app format is designed to accommodate these packagers seamlessly, ensuring that Ember applications can harness the benefits of these tools while maintaining compatibility. +TODO add a comment about eagerness with the compat module import -5. Future-Proofing +### Application Config -> app/config/environment.js and config/environment.js + +### Test Entrypoint -> tests/index.html and tests/test-helper.js + +### Explicit Babel Config -> babel.config.cjs + +### Ember Pre-Build Config -> ember-cli-build.js + +### Explicit Bundler Config -> vite.config.mjs -Lastly, the v2 app format positions Ember to take advantage of ongoing and future developments in the wider JavaScript ecosystem related to code bundling and optimization. By aligning with industry trends, Ember remains a forward-looking framework, ready to embrace new technologies and practices. -## Detailed design How much of this should be "the path/migration to" as opposed to "this is the end state, details can be part of implementation"? @@ -135,7 +142,10 @@ on the impact of the API churn on existing apps, etc. > This section could also include prior art, that is, how other frameworks in the same domain have solved this problem. +In this section I'll + ## Unresolved questions -> Optional, but suggested for first drafts. What parts of the design are still -TBD? +### Application config + +In the current design of the new build we are still using the node-generated config that all ember developers are used to. We have considered unifying the `config/environemnt.js` and `app/config/environment.js` files to reduce complexity in the learning story but From 2e5faf1f053c91cd7a86c9c9fbca16f9ba631dbf Mon Sep 17 00:00:00 2001 From: Chris Manson Date: Wed, 13 Nov 2024 16:13:11 +0100 Subject: [PATCH 06/10] start filling out some of the sections --- text/0977-v2-app-format.md | 72 ++++++++++++++++++++++++++++++++++---- 1 file changed, 65 insertions(+), 7 deletions(-) diff --git a/text/0977-v2-app-format.md b/text/0977-v2-app-format.md index 98641fb22e..ece34257f6 100644 --- a/text/0977-v2-app-format.md +++ b/text/0977-v2-app-format.md @@ -34,32 +34,90 @@ suite: Leave as is This RFC defines a new app format, building off the prior work in [v2 Addon format](https://rfcs.emberjs.com/id/0507-embroider-v2-package-format), -that is designed to make Ember apps more compatible with the rest of the JavaScript ecosystem. This RFC will define conventions of the app and clearly identify functionality that is considered "compat" and could be considered optional in the near future. +and is designed to make Ember apps more compatible with the rest of the JavaScript ecosystem. This RFC will define conventions of the app and clearly identify functionality that is considered "compatibility integrations" and could be considered optional in the near future. ## Motivation -When ember-cli was created there was no existing JS tooling that met the needs of the Ember Framework. Over the years we have added more and more developer-friendly conventions to our build system that many Ember applications and addons depend on. As the JavaScript tooling story has gotten a lot better of the years Ember has fallen behind because our custom-built tools have not been keeping up with the wider community. Efforts have been started to improve the situation with the advent of [Embroider](https://github.com/embroider-build/embroider) but the current stable release of Embroider still runs inside ember-cli and is somewhat bound in performance and capability by the underlying technology [broccolijs](https://github.com/broccolijs/broccoli). +When ember-cli was created there was no existing JS tooling that met the needs of the Ember Framework. Over the years we have added more and more developer-friendly conventions to our build system that many Ember applications and addons depend on. As the wider JavaScript tooling story has evolved over the years Ember has fallen behind, this is mainly because our custom-built tools have not been keeping up with the wider community and we haven’t been able to directly use any more advanced tooling in our apps. Efforts have been started to improve the situation with the advent of [Embroider](https://github.com/embroider-build/embroider) but the current stable release of Embroider still runs inside ember-cli and is somewhat bound in terms of performance and capability by the underlying technology [broccolijs](https://github.com/broccolijs/broccoli) and some other architectural decisions. -Over the past year the Ember Core Tooling team have been working hard to invert the control between the bundler and ember-cli, which means that instead of ember-cli running the bundler as part of its build system the whole Ember build process will essentially become a plugin to the bundler. This means that we can more effectively make use of bundler innovations, performance improvements, and we are more capable of adapting to whatever next generation of build systems come to the Javascript ecosystemm. +Over the past year the Ember Core Tooling team have been working hard to invert the control between bundlers and ember-cli, which means that instead of ember-cli running a bundler (such as Webpack) as part of its build system the whole Ember build process will essentially become a plugin to the bundler. This means that we can more effectively make use of bundler innovations, performance improvements, and we are more capable of adapting to whatever next generation of build systems come to the Javascript ecosystem. -With the Ember build system as a plugin to bundlers (such as Vite or Webpack) we also have the ability to only intervene on things that are Emberisims (i.e. not-standard) and as we work to make Ember more standard we can eventually turn off these compat plugins. +With the Ember build system as a plugin to bundlers (such as Vite or Webpack) we also have the ability to only intervene on things that are Emberisims (i.e. not-standard) and as we work to make Ember more standard we can eventually turn off these ”compatibility plugins”. Compatibility plugins will need to be powered by an “ember prebuild” that collects information about your app and addons and output metadata that the bundler plugins will consume. The intention is that this prebuild will be done automatically for you as part of the bundler plugin setup and you should not have to worry about preforming extra steps. -This RFC is not going to describe a new blueprint where you don't need any compatibility plugins to run an Ember app, this RFC instead is going to propose a new blueprint that has all the compatibility plugins turned on so that it is easiest for most people to upgrade to. +This RFC is not going to describe a new blueprint where you don't need any compatibility plugins (or an ember prebuild) to run an Ember app, this RFC instead is going to propose a new blueprint that has all the compatibility plugins turned on so that it is easiest for most people to upgrade to. Any discussion about a minimal “compatibility-free” blueprint should happen in a later RFC. ## Key Ideas -Much like the [v2 Addon format RFC](https://rfcs.emberjs.com/id/0507-embroider-v2-package-format#key-ideas) we want the new app blueprint to rely on ES Modules and not leave anything hidden or automatic. This not noly makes it easier for developers to know where things are coming from, it also makes it easier for bundlers to know what to do with Ember applications. +Much like the [v2 Addon format RFC](https://rfcs.emberjs.com/id/0507-embroider-v2-package-format#key-ideas) we want the new app blueprint to rely on ES Modules and not leave anything hidden or automatic. This not only makes it easier for developers to know where things are coming from, it also makes it easier for bundlers to know what to do with Ember applications. Each of the following sections go into detail of all the changes between the current blueprint and the new proposal which is currently being developed at https://github.com/embroider-build/app-blueprint ## Detailed design -In this section I'm going to go through each of the changes in the new proposed blueprint, in each section I will do my best to explain the reasoningin for why it needs to be like this but if you have any questions or comments please feel free to comment on the RFC and we will try to update that section. +In this section I'm going to go through each of the changes in the new proposed blueprint, in each section I will do my best to explain the reasoning for why it needs to be like this but if you have any questions or comments please feel free to comment on the RFC and we will try to update that section. ### Entrypoint -> index.html +A lot of modern bundlers make use of your index.html file as the main entrypoint to kick off bundling. Any files that are referenced in your index.html would then end up getting bundled. + +This already an issue for an Ember app because the index.html that is traditionally found at `app/index.html` is ultimately not used directly. Information in the index.html file is used to generate the real file that is used at the end of the pipeline. + +This new blueprint proposes to remove this oddity and both allow bundlers to look directly at the source index.html instead of the output build artifact and will remove almost all ember build customisations that targed the index.html. We still intend to support `{{content-for}}` entries in the index.html with a few caveats that I will explain in more detail in the next section, but the support for `{{content-for}}` will need to be provided by a bundler plugin that has the ability to replace content in the index.html. + +The index.html will also have an inline script tag that performs the application boot. This process used to be hidden away in a `{{content-for “app-boot”}}` section in one of the javascript files automatically added to the index.html during the build pipeline. This explicit inline application boot significantly improves the visibility of how the application actually boots and should allow developers to customise that process without our build system needing to provide a way to handle those customisations. Incidently this now means that if you are using an addon to customise the `{{content-for “app-boot”}}` then this will no longer work. If Embroider discovers that an app is trying to customise the app-boot in any way it will throw this error: + +> Your app uses at least one classic addon that provides content-for 'app-boot'. This is no longer supported. +> +> With Embroider, you have full control over the app-boot script, so classic addons no longer need to modify it under the hood. +> +> The following code is used for your app boot: +> +> {{inline-custom-app-boot-code}} +> +> 1. If you want to keep the same behavior, copy and paste it to the app-boot script included in app/index.html. +> 2. Once app/index.html has the content you need, remove the present error by setting "useAddonAppBoot" to false in the build options. + +The embedded boot section in the index.html will look like the following: + +``` + +``` + +This boot section touches app/app.js and the new app/config/environment.js files which are both described in sections below. + +#### content-for in index.html + +The way that `{{content-for}}` works in ember-cli currently is under-specified and cronically under documented. The highest level summary is that anyone can currently add `{{content—for “any-string“}}` and as long as any active ember-addon provided a value for that specific content-for section the exact string that the addon provided would be injected at that point in the document. While we are familiar with sections like `{{content-for “head”}}` there is no pre-defined list and the common sections are only common due to convention. This makes it **extremely** hard for a modern build system that doesn’t understand ember-addons to be able to know what to do with these sections. + +We are proposing that we codify the conventional sections as the default set, and the ember prebuild will be able to collate the text each addon wants to add to these sections + +- head +- test-head +- head-footer +- test-head-footer +- body +- test-body +- body-footer +- test-body-footer +- config-module +- app-boot + +If you are using any other custom `{{content-for}}` section then you will need to explicitly pass this to your embroider config via a `availableContentForTypes` configuration + ### App Entrypoint -> app/app.js +In a classic build ember-cli would collect all the of the modules in your app into an entrypoint in the build that would go through and define each of the modules in the require.js AMD registry. There is already an RFC that describes the fact that we want to deprecate this AMD registry, but the key thing for this RFC is that we are trying to think of our app as series of real ES Modules we need to provide some way for the built-in discovery of these modules that allows Ember to still resolve those modules by name (for Dependency Injection concerns like services) + +We are providing this with the virtual module `'@embroider/virtual/compat-modules';`. This means that any bundler plugin that wants to support Ember needs to be able to support virtual module imports. The contents of this file can be obtained by asking the Embroider resolver which collates the list of modules during the Ember prebuild. + +We then pass the list of modules to an updated version of the Ember Resolver (that has already been released ) + +TODO add an example and keep describing + TODO add a comment about eagerness with the compat module import ### Application Config -> app/config/environment.js and config/environment.js From fa33cedb5de61382f2f59697226f20dcb9f44a53 Mon Sep 17 00:00:00 2001 From: Chris Manson Date: Fri, 15 Nov 2024 18:14:44 +0100 Subject: [PATCH 07/10] finalise my changes --- text/0977-v2-app-format.md | 297 ++++++++++++++++++++++++++++--------- 1 file changed, 228 insertions(+), 69 deletions(-) diff --git a/text/0977-v2-app-format.md b/text/0977-v2-app-format.md index ece34257f6..85c39b06b6 100644 --- a/text/0977-v2-app-format.md +++ b/text/0977-v2-app-format.md @@ -110,100 +110,259 @@ If you are using any other custom `{{content-for}}` section then you will need t ### App Entrypoint -> app/app.js -In a classic build ember-cli would collect all the of the modules in your app into an entrypoint in the build that would go through and define each of the modules in the require.js AMD registry. There is already an RFC that describes the fact that we want to deprecate this AMD registry, but the key thing for this RFC is that we are trying to think of our app as series of real ES Modules we need to provide some way for the built-in discovery of these modules that allows Ember to still resolve those modules by name (for Dependency Injection concerns like services) +In a classic build ember-cli would collect all the of the modules in your app into an entrypoint in the build that would go through and define each of the modules in the require.js AMD registry. There is already an [RFC that describes the fact that we want to deprecate this AMD registry](https://github.com/emberjs/rfcs/blob/strict-es-module-support/text/0938-strict-es-module-support.md), but the key thing for this RFC is that we are trying to think of our app as series of real ES Modules we need to provide some way for the built-in discovery of these modules that allows Ember to still resolve those modules by name (for Dependency Injection concerns like services) We are providing this with the virtual module `'@embroider/virtual/compat-modules';`. This means that any bundler plugin that wants to support Ember needs to be able to support virtual module imports. The contents of this file can be obtained by asking the Embroider resolver which collates the list of modules during the Ember prebuild. -We then pass the list of modules to an updated version of the Ember Resolver (that has already been released ) +We then pass the list of modules to an updated version of the Ember Resolver (that has already been released) which means that the Ember Resolver no longer needs to rely on requirejs.entries to find all of the parts of your application. This set of compat modules also needs to be passed into the `loadInitializers()` from `ember-load-initializers` so that doesn't use AMD for initalizer discovery either. Here is an example of the difference in the `app/app.js` file: -TODO add an example and keep describing +```diff + import Application from '@ember/application'; ++import compatModules from '@embroider/virtual/compat-modules'; + import Resolver from 'ember-resolver'; + import loadInitializers from 'ember-load-initializers'; + import config from 'current-blueprint/config/environment'; -TODO add a comment about eagerness with the compat module import + export default class App extends Application { + modulePrefix = config.modulePrefix; + podModulePrefix = config.podModulePrefix; +- Resolver = Resolver; ++ Resolver = Resolver.withModules(compatModules); + } -### Application Config -> app/config/environment.js and config/environment.js +-loadInitializers(App, config.modulePrefix); ++loadInitializers(App, config.modulePrefix, compatModules); +``` -### Test Entrypoint -> tests/index.html and tests/test-helper.js +One very important thing to note is that because we're moving from AMD to real ESM modules we now have a timing change for any code that is executing in the module scope, this code will now be executed eagerly and will not wait until the module is actually consumed by your app. This change happens because AMD inherently lazily executes module code only when that module is consumed, and ES modules are inherently a static graph of modules. -### Explicit Babel Config -> babel.config.cjs +For the most part this change should not affect many people and most of the problems that we noticed related to this change came from addons that had code that had errors in it but was never cleaned up. It was never noticed before because the code was not being exercised by tests or consumers of the addons so most of the time the fix was to just delete the previously inert code. -### Ember Pre-Build Config -> ember-cli-build.js +### Application Config -> app/config/environment.js and config/environment.js -### Explicit Bundler Config -> vite.config.mjs +In a Classic build ember-cli automatically generated a module `app/config/environment.js` in your application build pipeline that is customisable with the config `storeConfigInMeta`. If `storeConfigInMeta` is true (which is the default) then the contents of this module will look for a `` tag in your html and parse out the your previously serialised config object and return the value as the default export from the module. This is what people recieve when they import from `app-name/config/environment`. +This is another example of an Ember-specific complexity in the build system that can be confusing for other build systems. In the new blueprint we propose making the `app/config/environment.js` file exist in your source, and the contents will clearly be loading the config from meta: +```js +import loadConfigFromMeta from '@embroider/config-meta-loader'; -How much of this should be "the path/migration to" as opposed to "this is the end state, details can be part of implementation"? - -1. start with embroider-strictest -2. all blueprint addons must be either in the v2 format, or non-addons entirely (such as qunit-dom's recent change to real `type=module` package) -3. use Vite with Embroider -4. remove unneeded dependencies - - ember-auto-import - - replaced by _the packager's_ own way of processing dependencies - (requires all consumed dependencies to _not_ be v1 addons) - - broccoli-asset-rev - - replaced by _the packager's_ production build mode - - ember-cli-babel - - replaced by actual babel - - ember-cli-clean-css - - replaced by _the packager's_ production build mode - - ember-cli-htmlbars - - replaced by [babel-plugin-ember-template-compilation](https://github.com/emberjs/babel-plugin-ember-template-compilation/) and embroider-provided build plugins - - ember-cli-inject-live-reload - - replaced by _the packager's_ development mode - - ember-cli-sri - - replaced by _the packager's_ production build mode - - ember-cli-terser - - replaced by _the packager's_ production build mode - - ember-fetch - - requires work in `@ember/test-helpers` and `ember-fetch` to make this smooth. - - ember-load-initializers - - tbd - - ember-resolver - - tbd - - loader.js - - require / AMD has been private for a long time, and folks should not be using it. - - -> This is the bulk of the RFC. - -> Explain the design in enough detail for somebody -familiar with the framework to understand, and for somebody familiar with the -implementation to implement. This should get into specifics and corner-cases, -and include examples of how the feature is used. Any new terminology should be -defined here. +export default loadConfigFromMeta('app-name'); +``` -## How we teach this +The serialising of the config into the index.html is still being handled by `{{content-for 'head'}}` and is not going to change as a result of this RFC. -> What names and terminology work best for these concepts and why? How is this -idea best presented? As a continuation of existing Ember patterns, or as a -wholly new one? +One restriction in the new blueprint is that we don't have an automatic implementation for when `storeConfigInMeta` is set to `false`. Our reasoning is that if you have set this setting then you are likely doing something custom and you would need to update `app/config/environment.js` to reflect your custom setup. We don't need to provide any customisation here because this is a user-owned module and you can edit it as you please. -> Would the acceptance of this proposal mean the Ember guides must be -re-organized or altered? Does it change how Ember is taught to new users -at any level? +### Test Entrypoint -> tests/index.html and tests/test-helper.js -> How should this feature be introduced and taught to existing Ember -users? +The `tests/index.html` will have the same treatment as the main `index.html` where the test boot code will now be exposed directly in an inline script so that test booting is not hidden deep in the build pipeline. -## Drawbacks +```html + +``` + +To facilitate this new API the test-helper needs to be changed to essentially "wrap" its contents in a function that can be called rather than it running as a side effect of the import: + +```diff + import Application from 'current-blueprint/app'; + import config from 'current-blueprint/config/environment'; + import * as QUnit from 'qunit'; + import { setApplication } from '@ember/test-helpers'; + import { setup } from 'qunit-dom'; +-import { start } from 'ember-qunit'; ++import { start as qunitStart } from 'ember-qunit'; + ++export function start() { + setApplication(Application.create(config.APP)); + setup(QUnit.assert); + +-start(); ++qunitStart(); + ++} +``` -> Why should we *not* do this? Please consider the impact on teaching Ember, -on the integration of this feature with other existing and planned features, -on the impact of the API churn on existing apps, etc. +This also allows us to load qunit, load all the test files, and then start qunit once all the tests are loaded. The loading of the test files is now also made explicit with the line: -> There are tradeoffs to choosing any path, please attempt to identify them here. +```js +import.meta.glob("./**/*.{js,gjs,gts}", { eager: true }); +``` + +`import.meta.glob` is described in detail in the [Introduce a Wildcard Module Import API RFC](https://rfcs.emberjs.com/id/0939-import-glob). It is natively supported in Vite but it would need to be implemented in any other build system that wants to support building an Ember app. -## Alternatives +### Explicit Babel Config -> babel.config.cjs -> What other designs have been considered? What is the impact of not doing this? +In a classic build ember-cli-babel manages all configurations to babel in a way that is entirely hidden to the end-user. This is nice considering that users don't need to manage this file themselves, but it is also problematic because if anyone wants to customise their babel config they need to rely on extension points provided by both ember-cli and ember-cli-babel and in some cases those extension points may not even be available e.g. it is currently impossible for an app to configure an ast-transform for the ember-template-compiler and people workaround this issue by creating an in-repo addon that does this configuration for them. + +In the new blueprint we will have an explicit `babel.config.cjs` that will come pre-configured with all the babel-plugins that ember-cli-babel would have configured for you. + +Here is the full contents of the proposed babel file: + +```js +const { + babelCompatSupport, + templateCompatSupport, +} = require('@embroider/compat/babel'); + +module.exports = { + plugins: [ + [ + 'babel-plugin-ember-template-compilation', + { + compilerPath: 'ember-source/dist/ember-template-compiler.js', + enableLegacyModules: [ + 'ember-cli-htmlbars', + 'ember-cli-htmlbars-inline-precompile', + 'htmlbars-inline-precompile', + ], + transforms: [...templateCompatSupport()], + }, + ], + [ + 'module:decorator-transforms', + { + runtime: { + import: require.resolve('decorator-transforms/runtime-esm'), + }, + }, + ], + [ + '@babel/plugin-transform-runtime', + { + absoluteRuntime: __dirname, + useESModules: true, + regenerator: false, + }, + ], + ...babelCompatSupport(), + ], + + generatorOpts: { + compact: false, + }, +}; +``` -> This section could also include prior art, that is, how other frameworks in the same domain have solved this problem. +You can see that there are two functions being imported from `@embroider/compat/babel`: `babelCompatSupport()` and `templateCompatSupport()`. This collects any extra babel config that is provided by any installed v1 ember-addon and makes sure that it still works with this new config. When an app no longer has any v1 ember-addons these functions can be removed but we will likely be leaving them in the default blueprint for the foreseeable future because they cost nothing if they are not being used. + +### Ember Pre-Build Config -> ember-cli-build.js + +To enable the current stable version of embroider you need to update your Ember Application in `ember-cli-build.js` in a `compatBuild()` function. That function took a plugin for your bundler and an optional config that allowed you to turn on each of the "static flags" of embroider one-by-one + +The "Inversion of Control" version of the blueprint will not use `compatBuild()` since the bundling is not controlled by ember-cli any more. We have implemented a new `prebuild()` function that only takes your Ember application and an optional config: + +```diff + 'use strict'; + + const EmberApp = require('ember-cli/lib/broccoli/ember-app'); ++const { prebuild } = require('@embroider/compat'); + + module.exports = function (defaults) { + const app = new EmberApp(defaults, { + // Add options here + }); + +- return app.toTree(); ++ return prebuild(app); + }; +``` + +Other than not accepting a bundler config as one of the options, the other change in this prebuild function is that **all the static flags are turned on by default**. Also some flags, like `staticEmberSource`, are forced to be on and will throw an error if you try to set them to false. + +### Explicit Bundler Config -> vite.config.mjs + +If you are using the current stable relase of Embroider then Embroider is generating a Webpack config for you automaically. It is possible for you to make some changes via config but the majority of the Webpack config file is hidden from you. + +This RFC proposes that we don't hide the bundler config any more, if you are using Webpack then you will have a Webpack config that will need to have an Embroider plugin configured. + +The blueprint will default to using Vite as a bundler but we will provide the option for Webpack to help people who have customised their Webpack builds by configuring Embroider to transition to the new blueprint format without needing to migrate to Vite. + +Here is the current version of the proposed vite config: + +```js +import { defineConfig } from 'vite'; +import { + resolver, + hbs, + scripts, + templateTag, + optimizeDeps, + compatPrebuild, + assets, + contentFor, +} from '@embroider/vite'; +import { babel } from '@rollup/plugin-babel'; + +const extensions = [ + '.mjs', + '.gjs', + '.js', + '.mts', + '.gts', + '.ts', + '.hbs', + '.json', +]; + +export default defineConfig(({ mode }) => { + return { + resolve: { + extensions, + }, + plugins: [ + hbs(), + templateTag(), + scripts(), + resolver(), + compatPrebuild(), + assets(), + contentFor(), + + babel({ + babelHelpers: 'runtime', + extensions, + }), + ], + optimizeDeps: optimizeDeps(), + server: { + port: 4200, + }, + build: { + outDir: 'dist', + rollupOptions: { + input: { + main: 'index.html', + ...(shouldBuildTests(mode) + ? { tests: 'tests/index.html' } + : undefined), + }, + }, + }, + }; +}); + +function shouldBuildTests(mode) { + return mode !== 'production' || process.env.FORCE_BUILD_TESTS; +} +``` + +## How we teach this + +All of the guides will need to be updated to make sure that we reference the build system correctly. We will also need to make sure that the system we use that automatically builds the tutorial for us can work with the new build system and blueprint. + +It will also probably be worthwhile getting Embroider API documentation added to https://api.emberjs.com/ as one of the listed projects on the left-hand side. + +## Drawbacks -In this section I'll +The only drawback I can see is that this is going to be quite a large change. ## Unresolved questions -### Application config +### Webpack examples -In the current design of the new build we are still using the node-generated config that all ember developers are used to. We have considered unifying the `config/environemnt.js` and `app/config/environment.js` files to reduce complexity in the learning story but +While developing the layout of this new blueprint we have been exclusively working with Vite so we don't have any examples of the "Inversion of Control" layout for a Webpack blueprint. We don't see this as a requirement for progressing with this RFC as we are relatively sure that we will be able to achieve the same layout and only have to swap out the Vite config for a Webpack config. From 822917ff622f4915957150874f271c7f92b8fe25 Mon Sep 17 00:00:00 2001 From: Chris Manson Date: Fri, 22 Nov 2024 18:11:30 +0000 Subject: [PATCH 08/10] add sections based on feedback --- text/0977-v2-app-format.md | 50 +++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/text/0977-v2-app-format.md b/text/0977-v2-app-format.md index 85c39b06b6..532324f189 100644 --- a/text/0977-v2-app-format.md +++ b/text/0977-v2-app-format.md @@ -52,6 +52,14 @@ Much like the [v2 Addon format RFC](https://rfcs.emberjs.com/id/0507-embroider-v Each of the following sections go into detail of all the changes between the current blueprint and the new proposal which is currently being developed at https://github.com/embroider-build/app-blueprint +### Removal of requirejs support + +The default build system that will be used in this new blueprint will be Vite and for the most part Vite requires that your app is described in terms of ES Modules. The default build from `ember-cli` would express all of your modules using AMD and requirejs `define()` statements. There is an open RFC for [Strict ES Module Support](https://github.com/emberjs/rfcs/pull/938) that removes Ember's reliance on AMD to define modules and that RFC would be a requirement for this one i.e. when building with Vite you essentially have no requirejs module support. This means that any addon or application that interacts with requirejs would need to be updated for people to upgrade to this new blueprint. + +### Top level await added + +Since we are now using ES Modules througout the whole application it now becomes possible to use [top-level-await](https://v8.dev/features/top-level-await) in the module-scope of any of your files. This opens up a lot of possibliites for Ember developers and is a great example of how adopting standards helps to bring improvments from the wider ecosystem to Ember developers. + ## Detailed design In this section I'm going to go through each of the changes in the new proposed blueprint, in each section I will do my best to explain the reasoning for why it needs to be like this but if you have any questions or comments please feel free to comment on the RFC and we will try to update that section. @@ -276,7 +284,7 @@ Other than not accepting a bundler config as one of the options, the other chang ### Explicit Bundler Config -> vite.config.mjs -If you are using the current stable relase of Embroider then Embroider is generating a Webpack config for you automaically. It is possible for you to make some changes via config but the majority of the Webpack config file is hidden from you. +If you are using the current stable release of Embroider then Embroider is generating a Webpack config for you automatically. It is possible for you to make some changes via config but the majority of the Webpack config file is hidden from you. This RFC proposes that we don't hide the bundler config any more, if you are using Webpack then you will have a Webpack config that will need to have an Embroider plugin configured. @@ -351,12 +359,48 @@ function shouldBuildTests(mode) { } ``` +### Application metadata -> package.json + +In the [v2 Addon format RFC](https://rfcs.emberjs.com/id/0507-embroider-v2-package-format) we introduced the fact that the package.json `ember-addon` MetaData object should be versioned to identify which addons have been upgraded to the new spec. We will be reusing that concept for v2 apps by requiring the following section to be added to the package.json + +```json +{ + "ember-addon" { + "type": "app", + "version": 2 + } +} +``` + +This will opt Embroider into modern resolving rules so that it can interoperate properly with bundlers. + +### Exports -> package.json + +[Package Exports](https://webpack.js.org/guides/package-exports/) is an addition to the ESM resolving rules that all modern bundlers support. It allows you to configure paths that should be importable from ouside your package, as well as giving you a standard way to "redirect" imports that target your package. + +We already use these semantics in Ember applications when we expect `import SomeComponent from 'app-name/components/some-component'` to actually import the file path `/path/to/app-name/app/components/some-component.js`. In this example you can see that the `/app/` subpath has been added to the location. In ember-cli this semantic is handled in broccoli by actually rewriting paths, but this is one of the main reasons why tooling gets confused by our import paths because it's not using a standard method to define our import paths. + +The new blueprint will add the following exports section to the package.json by default: + +```json +{ + "./tests/*": "./tests/*", + "./*": "./app/*" +} +``` + +This essentially "redirects" all requests to modules in the `app` folder, with the exepction of any path that has `app-name/tests/` at the start. This means that importing your test helpers like `import superHelper from 'app-name/tests/helpers/super-helper'` won't try to import from the path `/path/to/app-name/app/tests/helpers/super-helper.js` + ## How we teach this All of the guides will need to be updated to make sure that we reference the build system correctly. We will also need to make sure that the system we use that automatically builds the tutorial for us can work with the new build system and blueprint. It will also probably be worthwhile getting Embroider API documentation added to https://api.emberjs.com/ as one of the listed projects on the left-hand side. +The majority of this RFC is written from the perspective of someone that is running `ember new` for the first time on a brand new app, but we will need to make sure to write both upgrade guides and appropriate codemods for anyone that is wanting to upgrade their apps from the old blueprints to this new default. We also need to put some consideration into the experience of people using [ember-cli-update](https://github.com/ember-cli/ember-cli-update) to upgrade Ember versions when we make this the new default. + +It's also important to note that this RFC does not represent the new bluerpint for a Polaris application. This is just upgrading our build system to use more modern and standard tools. Any communication around this RFC change should be explicit that this is a **part** of what is needed for Polaris but this blueprint update is not giving you all of polaris. This is a single step in that direction. + ## Drawbacks The only drawback I can see is that this is going to be quite a large change. @@ -366,3 +410,7 @@ The only drawback I can see is that this is going to be quite a large change. ### Webpack examples While developing the layout of this new blueprint we have been exclusively working with Vite so we don't have any examples of the "Inversion of Control" layout for a Webpack blueprint. We don't see this as a requirement for progressing with this RFC as we are relatively sure that we will be able to achieve the same layout and only have to swap out the Vite config for a Webpack config. + +### package.json meta key + +The way that Embroider is currently implemented the Ember MetaData in package.json is set with the key `ember-addon` even for applications. On the one hand it seems good that the applications and addons use the same key for this, but on the other hand it may be confusing that the key for the metadata has the word `addon` in it. We could move both addons and apps to just use the metadata key `ember` but that could create chrun with very little benefit. From 42195cf0f2abd31d2f7589f27fae192047465ed1 Mon Sep 17 00:00:00 2001 From: Chris Manson Date: Sat, 7 Dec 2024 00:11:01 +0000 Subject: [PATCH 09/10] implement feedback into the RFC --- text/0977-v2-app-format.md | 101 ++++++++++++------------------------- 1 file changed, 32 insertions(+), 69 deletions(-) diff --git a/text/0977-v2-app-format.md b/text/0977-v2-app-format.md index 532324f189..91a9b49061 100644 --- a/text/0977-v2-app-format.md +++ b/text/0977-v2-app-format.md @@ -40,9 +40,9 @@ and is designed to make Ember apps more compatible with the rest of the JavaScri When ember-cli was created there was no existing JS tooling that met the needs of the Ember Framework. Over the years we have added more and more developer-friendly conventions to our build system that many Ember applications and addons depend on. As the wider JavaScript tooling story has evolved over the years Ember has fallen behind, this is mainly because our custom-built tools have not been keeping up with the wider community and we haven’t been able to directly use any more advanced tooling in our apps. Efforts have been started to improve the situation with the advent of [Embroider](https://github.com/embroider-build/embroider) but the current stable release of Embroider still runs inside ember-cli and is somewhat bound in terms of performance and capability by the underlying technology [broccolijs](https://github.com/broccolijs/broccoli) and some other architectural decisions. -Over the past year the Ember Core Tooling team have been working hard to invert the control between bundlers and ember-cli, which means that instead of ember-cli running a bundler (such as Webpack) as part of its build system the whole Ember build process will essentially become a plugin to the bundler. This means that we can more effectively make use of bundler innovations, performance improvements, and we are more capable of adapting to whatever next generation of build systems come to the Javascript ecosystem. +Over the past year the Ember Core Tooling team have been working hard to invert the control between bundlers and ember-cli, which means that instead of ember-cli running a bundler (such as Webpack in the current Embroider stable version) as part of its build system the whole Ember build process will essentially become a plugin to the bundler. This means that we can more effectively make use of bundler innovations, performance improvements, and we are more capable of adapting to whatever next generation of build systems come to the Javascript ecosystem. -With the Ember build system as a plugin to bundlers (such as Vite or Webpack) we also have the ability to only intervene on things that are Emberisims (i.e. not-standard) and as we work to make Ember more standard we can eventually turn off these ”compatibility plugins”. Compatibility plugins will need to be powered by an “ember prebuild” that collects information about your app and addons and output metadata that the bundler plugins will consume. The intention is that this prebuild will be done automatically for you as part of the bundler plugin setup and you should not have to worry about preforming extra steps. +With the Ember build system as a plugin to bundlers we have the ability to only intervene on things that are Emberisims (i.e. not-standard) and as we work to make Ember more standard we can eventually turn off these ”compatibility plugins”. Compatibility plugins will need to be powered by an “ember prebuild” that collects information about your app and addons and output metadata that the bundler plugins will consume. The intention is that this prebuild will be done automatically for you as part of the bundler plugin setup and you should not have to worry about preforming extra steps. This RFC is not going to describe a new blueprint where you don't need any compatibility plugins (or an ember prebuild) to run an Ember app, this RFC instead is going to propose a new blueprint that has all the compatibility plugins turned on so that it is easiest for most people to upgrade to. Any discussion about a minimal “compatibility-free” blueprint should happen in a later RFC. @@ -52,13 +52,21 @@ Much like the [v2 Addon format RFC](https://rfcs.emberjs.com/id/0507-embroider-v Each of the following sections go into detail of all the changes between the current blueprint and the new proposal which is currently being developed at https://github.com/embroider-build/app-blueprint +### Focus on Vite + +The new app blueprint will default to using Vite to power local development and build for production. Vite has been on a meteoric rise in popularity over the past few years, and it represents the state of the art when it comes to Developer Ergonomics. Standardising on such a popular build system will bring the Ember community a lot of benefits but the key areas of improvement that we expect developers to experience are: + +- significantly improved rebuild speeds during local development +- the ability to use "standard" vite plugins with your Ember apps +- significant improvements to debugability of your code in development because Vite serves ES Modules directly to your browser in development + ### Removal of requirejs support The default build system that will be used in this new blueprint will be Vite and for the most part Vite requires that your app is described in terms of ES Modules. The default build from `ember-cli` would express all of your modules using AMD and requirejs `define()` statements. There is an open RFC for [Strict ES Module Support](https://github.com/emberjs/rfcs/pull/938) that removes Ember's reliance on AMD to define modules and that RFC would be a requirement for this one i.e. when building with Vite you essentially have no requirejs module support. This means that any addon or application that interacts with requirejs would need to be updated for people to upgrade to this new blueprint. ### Top level await added -Since we are now using ES Modules througout the whole application it now becomes possible to use [top-level-await](https://v8.dev/features/top-level-await) in the module-scope of any of your files. This opens up a lot of possibliites for Ember developers and is a great example of how adopting standards helps to bring improvments from the wider ecosystem to Ember developers. +Since we are now using ES Modules througout the whole application it now becomes possible to use [top-level-await](https://v8.dev/features/top-level-await) in the module-scope of any of your files. This opens up a lot of possibilities for Ember developers and is a great example of how adopting standards helps to bring improvements from the wider ecosystem to Ember developers. ## Detailed design @@ -258,6 +266,8 @@ module.exports = { You can see that there are two functions being imported from `@embroider/compat/babel`: `babelCompatSupport()` and `templateCompatSupport()`. This collects any extra babel config that is provided by any installed v1 ember-addon and makes sure that it still works with this new config. When an app no longer has any v1 ember-addons these functions can be removed but we will likely be leaving them in the default blueprint for the foreseeable future because they cost nothing if they are not being used. +For people who are familiar with Babel config files you may have noticed that we have not included `@babel/preset-env` in this config. While our browser support has classically been handled by babel and `@babel/preset-env`, Vite has a config option [`build.target`](https://vite.dev/config/build-options#build-target) that controls what browsers you would like to down-compile your code for. This `build.target` config is passed to esbuild which is ultimately in charge of making sure your code runs in your stated targets i.e. in your `config/targets` file. While we are still going to read your `config/targets` file and pass that to the `build.target` config, it's worth noting that esbuild does not support the same range of browsers that `@babel/preset-env` does. This isn't a problem for the default blueprint because it supports all browsers that are part of Ember's official support matrix. We also don't see this as a blocker for adoption of this new blueprint because any applications that have a wider browser support matrix than Vite's `build.target` can provide can just manually configure `@babel/preset-env` in their babel config, now that it's significantly easier to edit your babel config. + ### Ember Pre-Build Config -> ember-cli-build.js To enable the current stable version of embroider you need to update your Ember Application in `ember-cli-build.js` in a `compatBuild()` function. That function took a plugin for your bundler and an optional config that allowed you to turn on each of the "static flags" of embroider one-by-one @@ -286,79 +296,30 @@ Other than not accepting a bundler config as one of the options, the other chang If you are using the current stable release of Embroider then Embroider is generating a Webpack config for you automatically. It is possible for you to make some changes via config but the majority of the Webpack config file is hidden from you. -This RFC proposes that we don't hide the bundler config any more, if you are using Webpack then you will have a Webpack config that will need to have an Embroider plugin configured. - -The blueprint will default to using Vite as a bundler but we will provide the option for Webpack to help people who have customised their Webpack builds by configuring Embroider to transition to the new blueprint format without needing to migrate to Vite. +This RFC proposes that we don't hide the bundler config any more, we will instead have a standard Vite config file that configures the required Embroider plugins. Here is the current version of the proposed vite config: ```js import { defineConfig } from 'vite'; -import { - resolver, - hbs, - scripts, - templateTag, - optimizeDeps, - compatPrebuild, - assets, - contentFor, -} from '@embroider/vite'; +import { extensions, classicEmberSupport, ember } from '@embroider/vite'; import { babel } from '@rollup/plugin-babel'; -const extensions = [ - '.mjs', - '.gjs', - '.js', - '.mts', - '.gts', - '.ts', - '.hbs', - '.json', -]; - -export default defineConfig(({ mode }) => { - return { - resolve: { +export default defineConfig({ + plugins: [ + classicEmberSupport(), + ember(), + // extra plugins here + babel({ + babelHelpers: 'runtime', extensions, - }, - plugins: [ - hbs(), - templateTag(), - scripts(), - resolver(), - compatPrebuild(), - assets(), - contentFor(), - - babel({ - babelHelpers: 'runtime', - extensions, - }), - ], - optimizeDeps: optimizeDeps(), - server: { - port: 4200, - }, - build: { - outDir: 'dist', - rollupOptions: { - input: { - main: 'index.html', - ...(shouldBuildTests(mode) - ? { tests: 'tests/index.html' } - : undefined), - }, - }, - }, - }; + }), + ], }); - -function shouldBuildTests(mode) { - return mode !== 'production' || process.env.FORCE_BUILD_TESTS; -} ``` +This config is defining 2 "compound plugins" that contain all the functionality needed for an Ember app to be built with Vite. We have split them into `classicEmberSupport()` and `ember()` to communicate that some of the plugins could be considered optional if you aren't using classic Ember features e.g. you have converted all your templates to GJS files. + ### Application metadata -> package.json In the [v2 Addon format RFC](https://rfcs.emberjs.com/id/0507-embroider-v2-package-format) we introduced the fact that the package.json `ember-addon` MetaData object should be versioned to identify which addons have been upgraded to the new spec. We will be reusing that concept for v2 apps by requiring the following section to be added to the package.json @@ -403,13 +364,15 @@ It's also important to note that this RFC does not represent the new bluerpint f ## Drawbacks -The only drawback I can see is that this is going to be quite a large change. +### Upgradability -## Unresolved questions +If developers are using ember-cli-update to upgrade their apps there might be a case where in an upcoming version of Ember they will be "opted in" to an Embroider build with Vite. We don't expect this process to be automatic but we do think that we can get most applications across this line with the use of tooling and codemods. One way to mitigate this problem is that we could maintain a "classic blueprint" until the next Ember major release that people could switch to while they are figuring out how to upgrade to Embroider and Vite. -### Webpack examples +### Webpack support -While developing the layout of this new blueprint we have been exclusively working with Vite so we don't have any examples of the "Inversion of Control" layout for a Webpack blueprint. We don't see this as a requirement for progressing with this RFC as we are relatively sure that we will be able to achieve the same layout and only have to swap out the Vite config for a Webpack config. +The blueprint will default to using Vite as a bundler, and we plan to document the process to add support for more bundlers as part of the implementation of this RFC. We had originally intended to provide support for Webpack as a bundler to help people who have already upgraded to the current stable Embroider version and customised their Webpack builds but Webpack support is not trivial to implement. The Ember Tooling Team believes that the benefits of having Vite as the default build experience are so great that we should not delay the implementation of this RFC while we try to backport the Inversion of control implementation of Embroider to Webpack. + +## Unresolved questions ### package.json meta key From fab41119776394da478e089cb75edad653ed810a Mon Sep 17 00:00:00 2001 From: Chris Manson Date: Tue, 10 Dec 2024 18:22:39 +0000 Subject: [PATCH 10/10] update ember-cli-build section --- text/0977-v2-app-format.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/text/0977-v2-app-format.md b/text/0977-v2-app-format.md index 91a9b49061..d865c35ad2 100644 --- a/text/0977-v2-app-format.md +++ b/text/0977-v2-app-format.md @@ -270,27 +270,27 @@ For people who are familiar with Babel config files you may have noticed that we ### Ember Pre-Build Config -> ember-cli-build.js -To enable the current stable version of embroider you need to update your Ember Application in `ember-cli-build.js` in a `compatBuild()` function. That function took a plugin for your bundler and an optional config that allowed you to turn on each of the "static flags" of embroider one-by-one +To enable the current stable version of embroider you need to wrap your Ember Application defined in `ember-cli-build.js` in a `compatBuild()` function. The `compatBuild()` function takes a plugin that runs your bundler (i.e. Webpack) as part of the ember-cli pipeline and an optional config that allows you to turn on each of the "static flags" of embroider one-by-one. -The "Inversion of Control" version of the blueprint will not use `compatBuild()` since the bundling is not controlled by ember-cli any more. We have implemented a new `prebuild()` function that only takes your Ember application and an optional config: +In the "Inversion of Control" version of the blueprint we intend to keep the same `compatBuild()` API but the job of the builder will be very different. Instead of Vite running as part of the ember-cli pipeline we are only running a prebuild that collects information about your application and its addons to make that available to the Embroider Vite plugin. When running directly in Vite the builder argument to `compatBuild()` will be inert and will do nothing. + +To continue to support commands like `ember build` or `ember test` we need some way for ember-cli to interact with Vite and allow Vite to build the application and run tests against the built output. Running `ember test` will essentially run Vite once (as a "one shot build" with no watching functionality) using the builder imported from `@embroider/vite` and then run `ember test --path {outdir}` where `{outdir}` will target the build output from Vite. This allows us to continue to support testem and any CI process that people have defined to use `ember build` without needing to update. Here is an example of an updated `ember-cli-build.js` file: ```diff - 'use strict'; - const EmberApp = require('ember-cli/lib/broccoli/ember-app'); -+const { prebuild } = require('@embroider/compat'); - ++const { compatBuild } = require('@embroider/compat'); ++const { builder } = require('@embroider/vite'); + module.exports = function (defaults) { - const app = new EmberApp(defaults, { - // Add options here - }); - + let app = new EmberApp(defaults, {}); - return app.toTree(); -+ return prebuild(app); ++ return compatBuild(app, builder, { /* optional Embroider options */ }); }; ``` -Other than not accepting a bundler config as one of the options, the other change in this prebuild function is that **all the static flags are turned on by default**. Also some flags, like `staticEmberSource`, are forced to be on and will throw an error if you try to set them to false. +The other change that will happen in the next Embroider major release (and will be true for the new blueprint) is that the options passed to `compatBuild()` will have **all the static flags turned on by default**. + +Also some flags, like `staticEmberSource`, `staticAddonTrees`, and `staticAddonTestSuportTrees` are forced to be on and will throw an error if you try to set them to false. This error will give guidance wherever possible and link to relevant documentation. ### Explicit Bundler Config -> vite.config.mjs