-
Notifications
You must be signed in to change notification settings - Fork 26.5k
Description
[x] feature request
This is a summary of a design discussion with @tbosch and @vsavkin.
Applications commonly need to support multiple variants out of the same code base. That is, we need to serve a slight variation of our application under certain circumstances, but at the same time still need to serve the original version.
Common use cases:
- experiments, e.g. shipping a slightly different app to 1% of your users
- special events (on Black Friday, serve a different app)
- shipping an admin version to some users
- incrementally rolling out a feature
- etc.
All of these have in common that we only want to surgically vary a specific part of our app under some circumstances, but not wholesale replace or fork the code base. Another consideration is that we'll have many of these variants available concurrently, and an individual app download might need to include multiple variations at the same time (admin user on Black Friday or so). Yet another thing is that disabled variants should have no effect on the served code of the rest of the application at all, i.e. they can be used for code hiding of unlaunched features.
The basic idea is to encapsulate variants in source files, with the source files patching global symbols on load, and in that way changing how the application behaves. The server side chooses to serve the appropriate combination of source files to a user, depending on what variants apply to them, or the client side lazily loads particular variants as needed.
There are two use cases we should support initially:
- changing how a single component behaves
- adding an entire route to the application
Components
For components, from the user side we'll support syntax like this:
@Component({
...,
overrides: OriginalComponent,
})
class ComponentVariant implements OriginalComponent { ... }
Worth noting: ComponentVariant
must be assignment compatible to OriginalComponent
(e.g. implement its interface), as it will be injected in place of OriginalComponent
across the application. Also, ComponentVariant
must have the same content view projection as OriginalComponent
, so it can be a drop in from the Angular 2 component side of things.
Routes
For routes, the basic idea is to lazily load routes that contain variants:
export const routes: Routes = [
...,
{path: '', loadChildren: 'some-id'},
];
The module loader then has a chance to inspect 'some-id'
and load the appropriate module (or even have the server side return the appropriate module). There will likely be a nicer API wrapping this, but it might be specific to the module loader used.