This repo implements a new three-stage build system for Ember apps:
-
The first stage achieves backward compatibility by building each classic Ember Addon package into a new v2 package format. This makes each package much more static and analyzable. The eventual goal is to do less and less work in this stage, as addons publish to NPM natively in v2 format.
-
The second stage takes a collection of v2-formatted addons plus an application and "compiles out" all Ember-specific conventions, such that the output can be understood by any tool that can handle standards-compliant Javascript. This stage is setup with good inputs and outputs that make it much easier to benefit from incremental improvements to our dependency analysis. The immediate goal is not to implement every possible optimization, but rather to make a good place for those optimizations to happen.
-
The third stage ("final packaging") can be handled by existing tools like Webpack, Rollup, or Parcel with only a small amount of configuration. Not because we want to force every Ember developer to choose and configure one of these tools! But because a stable, standards-compliant API between stage 2 and 3 improves our ability to innovate and experiment with taking the best parts of wider JS ecosystem tooling.
You can read more about the motivation and key ideas in the intro to the SPEC.
We are rapidly nearing a 1.0 release, and several large, heavily-tested Ember apps are shipping to production with Embroider. So if you are excited to adopt Embroider, it is a reasonable choice. The main risks to be aware of if you choose to use Embroider in production are:
- you're likely to discover some Ember addons don't work or break your build
- Embroider's own configuration options are subject to change, so you'll need to read the CHANGELOG.md when updating the Embroider packages.
Alternatively, it is totally safe to stick with the traditional build pipeline and wait for the official cutover point when EmberCLI starts generating new apps with Embroider by default.
The v2 Addon Format RFC is the official spec for the packages that Embroider natively handles. Addon authors should see ADDON-AUTHOR-GUIDE.md for advice on how to get their addons ready for Embroider.
-
Add dependencies:
yarn add --dev @embroider/core @embroider/compat @embroider/webpack webpack
-
Edit
ember-cli-build.js
:-return app.toTree(); +const { Webpack } = require('@embroider/webpack'); +return require('@embroider/compat').compatBuild(app, Webpack);
Alternatively, if you are passing optional extra broccoli trees into
app.toTree()
, you can rewrite like:-return app.toTree(extraTreeHere); +const { Webpack } = require('@embroider/webpack'); +return require('@embroider/compat').compatBuild(app, Webpack, { + extraPublicTrees: [extraTreeHere] +});
-
Use
ember serve
,ember test
, andember build
as usual.
You can pass options into Embroider by passing them into the compatBuild
function like:
return require('@embroider/compat').compatBuild(app, Webpack, {
// staticAddonTestSupportTrees: true,
// staticAddonTrees: true,
// staticHelpers: true,
// staticModifiers: true,
// staticComponents: true,
// splitAtRoutes: ['route.name'], // can also be a RegExp
// packagerOptions: {
// webpackConfig: { }
// }
});
The options are documented in detail in Core Options, Compat Options, and Webpack Options.
The recommended steps when introducing Embroider into an existing app are:
- First make it work with no options. This is the mode that supports maximum backward compatibility.
- Enable
staticAddonTestSupportTrees
andstaticAddonTrees
and test your application. This is usually safe, because most code in these trees gets consumed viaimport
statements that we can analyze. But you might find exceptional cases where some code is doing a more dynamic thing. - Enable
staticHelpers
andstaticModifiers
and test. This is usually safe because addon helpers and modifiers get invoked declaratively in templates and we can see all invocations. - Enable
staticComponents
, and work to eliminate any resulting build warnings about dynamic component invocation. You may need to addpackageRules
that declare where invocations like{{component someComponent}}
are gettingsomeComponent
from. - Once your app is working with all of the above, you can enable
splitAtRoutes
and add the@embroider/router
and code splitting should work.
If you are serving your assets from a different origin (like a CDN) from where your index.html content will
be served from, you can use the publicAssetURL option to specify the base URL. In pre-Embroider Ember apps,
this was accomplished by configuring the fingerprint: { prepend: ... }
option handled by broccoli-asset-rev.
return require('@embroider/compat').compatBuild(app, Webpack, {
packagerOptions: {
publicAssetURL: EmberApp.env() === 'production' ? 'https://your-cdn-here.com/' : '/', // This should be a URL ending in "/"
},
});
see ANALYZING.md
see CONTRIBUTING.md
This project is licensed under the MIT License.
Thanks to Cardstack for sponsoring Embroider's development.