Now Available React Programming: The Big Nerd Ranch Guide
Front-End ReactBased on our React Essentials course, this book uses hands-on examples to guide you step by step through building a starter app and a complete,...
In the previous two posts on Ember Engines, we started building an Ember “umbrella” application for mounting a couple Ember Engines. You can catch up on the series in Part 1 and Part 2. Ember Engines help a development team to separate UX concerns and split compiled files into separate .js
bundles that can be lazily loaded. When developing Engines, you can create an in-repo-engine
or an Ember Addon as an external repository.
In this post, you will share links and services, like store
and session
, between the parent app and the engines. That way, Engines can integrate with the parent app’s model and authentication layer without duplicating the Model
, Adapter
and Serializer
classes defined in the parent app. The parent application will also control where engine routes are mounted.
Within an Engine, links to internal routes work the same as any other Ember application: {{link-to "Home" "application"}}
, {{#link-to "application"}}{{/link-to}}
, [route].transitionTo('application')
and [controller].transitionToRoute('application')
.
To add external links to an engine app, there are new components and methods: {{#link-to-external}}{{/link-to-external}}
, {{link-to-external}}
, [route].replaceWithExternal
and [route].transitionToExternal
. In the external-admin
engine, add some links to the posts
template:
We now have external links to “home” and “blog”. These will navigate the user to the parent app’s “home” route and the “blog” route from another engine. Now our external-admin
engine needs to export these dependencies to the parent application. You will need to add those keys to the engine definition in external-admin/addon/engine.js
:
const Eng = Engine.extend({
modulePrefix,
- Resolver,
+ Resolver,
+ dependencies: {
+ externalRoutes: [
+ 'home',
+ 'blog'
+ ]
+ }
});
Once you have committed these changes, you have to reinstall the engine in the parent application.
cd ../large-company-site
ember install ember install https://github.com/bignerdranch/ember-engine-external-admin.git
In the parent application’s package.json
file you can check the commit revision hash against the latest revision from your engine’s GitHub page to make sure you loaded the latest:
"external-admin": "git+https://github.com/bignerdranch/ember-engine-external-admin.git#5e3601eebfcb4e82477b1f6e7e75355df8cbd1a1",
The commit hash (everything after “#” sign) tells you which revision of external-admin
your parent app is loading. Packages often use release numbers or tags instead of hashes.
Now that your engine has declared its dependency on the parent app’s links and other engine routes, you need to “inject” these dependencies into the engine. Add the following to large-company-site/app/app.js
:
App = Ember.Application.extend({
modulePrefix: config.modulePrefix,
podModulePrefix: config.podModulePrefix,
- Resolver
+ Resolver,
+ engines: {
+ externalAdmin: {
+ dependencies: {
+ externalRoutes: {
+ home: 'application',
+ blog: 'in-app-blog.posts'
+ }
+ }
+ }
+ }
});
These dependency mappings allow the parent app to fully control the engine’s external routing to the parent app, or to another engine!
Services are shared in exactly the same way as links: by adding a dependency mapping to a local object in the parent application. If you want your engine to retrieve data via the parent application’s store, you can add a dependency to the external-admin/addon/engine.js
:
const Eng = Engine.extend({
modulePrefix,
Resolver,
dependencies: {
+ services: [
+ 'data-store'
+ ],
externalRoutes: [
'home',
'blog'
]
}
});
This data-store
dependency can be accessed like any other service, this.get('dataStore').*
, but it will need to be added to each route, component or controller with Ember.inject.service()
:
export default Ember.[Object Type].extend({
dataStore: Ember.inject.service(),
fakeFunc() {
this.get('dataStore').[store method]()
}
});
Finally, the service dependency needs to mapped from the parent to the engine in large-company-site/app/app.js
:
App = Ember.Application.extend({
modulePrefix: config.modulePrefix,
podModulePrefix: config.podModulePrefix,
Resolver,
engines: {
externalAdmin: {
dependencies: {
+ services: [
+ { 'data-store': 'store' }
+ ],
externalRoutes: {
home: 'application',
blog: 'in-app-blog.posts'
}
}
}
}
});
Here, we mapped the engine’s data-store
service to the parent app’s store
service.
You can use this technique to share any service from your parent app to an engine. The parent application needs to inject all the dependencies required to load an engine, which should be documented in the engine repo’s README.md
. Once you know the dependencies, you can map your routes and services to the engine. And if you make changes to the parent app’s services or routes, you just have to update the dependency mapping in app.js
!.
And best yet, the structure of your build, environment, development or deployment process is not affected by this giant shift. It’s still just an Ember app with some Ember Addons! So whether you are splitting an existing application for better performance or creating teams for a complex ground-up application, Ember Engines are the solution you’ve been waiting for.
Happy building!
Based on our React Essentials course, this book uses hands-on examples to guide you step by step through building a starter app and a complete,...
Svelte is a great front-end Javascript framework that offers a unique approach to the complexity of front-end systems. It claims to differentiate itself from...
Large organizations with multiple software development departments may find themselves supporting multiple web frameworks across the organization. This can make it challenging to keep...