Skip to content

Commit

Permalink
[BUGFIX lts] Ensure custom modifier managers are not invoked in SSR.
Browse files Browse the repository at this point in the history
Prior to this change, custom modifier managers were invoked during
non-interactive rendering invocations as well as interactive. In
practice, that resulted in custom modifiers erroring whenever they ran
in FastBoot / SSR environments.

This change, ensures that the interactive / non-interactive state is
threaded through to the required infrastructure to avoid invoking _any_
hooks on custom modifier managers when running in non-interactive modes.

(cherry picked from commit a3c0b5e)
  • Loading branch information
rwjblue committed Jun 4, 2019
1 parent 84ee752 commit 9261888
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 9 deletions.
39 changes: 34 additions & 5 deletions packages/@ember/-internals/glimmer/lib/modifiers/custom.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Factory } from '@ember/-internals/owner';
import { Dict, Opaque, Simple } from '@glimmer/interfaces';
import { Tag } from '@glimmer/reference';
import { CONSTANT_TAG, Tag } from '@glimmer/reference';
import { Arguments, CapturedArguments, ModifierManager } from '@glimmer/runtime';

export interface CustomModifierDefinitionState<ModifierInstance> {
Expand All @@ -18,17 +18,23 @@ export function capabilities(_managerAPI: string, _optionalFeatures?: {}): Capab

export class CustomModifierDefinition<ModifierInstance> {
public state: CustomModifierDefinitionState<ModifierInstance>;
public manager = CUSTOM_MODIFIER_MANAGER;
public manager: ModifierManager<unknown | null, CustomModifierDefinitionState<ModifierInstance>>;

constructor(
public name: string,
public ModifierClass: Factory<ModifierInstance>,
public delegate: ModifierManagerDelegate<ModifierInstance>
public delegate: ModifierManagerDelegate<ModifierInstance>,
isInteractive: boolean
) {
this.state = {
ModifierClass,
name,
delegate,
};

this.manager = isInteractive
? CUSTOM_INTERACTIVE_MODIFIER_MANAGER
: CUSTOM_NON_INTERACTIVE_MODIFIER_MANAGER;
}
}

Expand Down Expand Up @@ -67,12 +73,15 @@ export interface ModifierManagerDelegate<ModifierInstance> {
implements a set of hooks that determine modifier behavior.
To create a custom modifier manager, instantiate a new CustomModifierManager
class and pass the delegate as the first argument:
```js
let manager = new CustomModifierManager({
// ...delegate implementation...
});
```
## Delegate Hooks
Throughout the lifecycle of a modifier, the modifier manager will invoke
delegate hooks that are responsible for surfacing those lifecycle changes to
the end developer.
Expand All @@ -81,7 +90,7 @@ export interface ModifierManagerDelegate<ModifierInstance> {
* `updateModifier()` - invoked when the arguments passed to a modifier change
* `destroyModifier()` - invoked when the modifier is about to be destroyed
*/
class CustomModifierManager<ModifierInstance>
class InteractiveCustomModifierManager<ModifierInstance>
implements
ModifierManager<
CustomModifierState<ModifierInstance>,
Expand Down Expand Up @@ -119,4 +128,24 @@ class CustomModifierManager<ModifierInstance>
}
}

const CUSTOM_MODIFIER_MANAGER = new CustomModifierManager();
class NonInteractiveCustomModifierManager<ModifierInstance>
implements ModifierManager<null, CustomModifierDefinitionState<ModifierInstance>> {
create() {
return null;
}

getTag(): Tag {
return CONSTANT_TAG;
}

install() {}

update() {}

getDestructor() {
return null;
}
}

const CUSTOM_INTERACTIVE_MODIFIER_MANAGER = new InteractiveCustomModifierManager();
const CUSTOM_NON_INTERACTIVE_MODIFIER_MANAGER = new NonInteractiveCustomModifierManager();
6 changes: 4 additions & 2 deletions packages/@ember/-internals/glimmer/lib/resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ const BUILTIN_MODIFIERS = {
};

export default class RuntimeResolver implements IRuntimeResolver<OwnedTemplateMeta> {
public isInteractive: boolean;
public compiler: LazyCompiler<OwnedTemplateMeta>;

private handles: any[] = [
Expand All @@ -114,10 +115,11 @@ export default class RuntimeResolver implements IRuntimeResolver<OwnedTemplateMe
public componentDefinitionCount = 0;
public helperDefinitionCount = 0;

constructor() {
constructor(isInteractive: boolean) {
let macros = new Macros();
populateMacros(macros);
this.compiler = new LazyCompiler<OwnedTemplateMeta>(new CompileTimeLookup(this), this, macros);
this.isInteractive = isInteractive;
}

/*** IRuntimeResolver ***/
Expand Down Expand Up @@ -290,7 +292,7 @@ export default class RuntimeResolver implements IRuntimeResolver<OwnedTemplateMe
let managerFactory = getModifierManager<ModifierManagerDelegate<Opaque>>(modifier.class);
let manager = managerFactory!(owner);

return new CustomModifierDefinition(name, modifier, manager);
return new CustomModifierDefinition(name, modifier, manager, this.isInteractive);
}
}

Expand Down
1 change: 1 addition & 0 deletions packages/@ember/-internals/glimmer/lib/setup-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ export function setupEngineRegistry(registry: Registry) {
registry.register('service:-glimmer-environment', Environment);

registry.register(P`template-compiler:main`, TemplateCompiler);
registry.injection(P`template-compiler:main`, 'environment', '-environment:main');

registry.injection('template', 'compiler', P`template-compiler:main`);

Expand Down
10 changes: 8 additions & 2 deletions packages/@ember/-internals/glimmer/lib/template-compiler.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import { Compiler } from '@glimmer/interfaces';
import RuntimeResolver from './resolver';

export interface ICompilerOptions {
environment: {
isInteractive: boolean;
};
}

// factory for DI
export default {
create(): Compiler {
return new RuntimeResolver().compiler;
create({ environment }: ICompilerOptions): Compiler {
return new RuntimeResolver(environment.isInteractive).compiler;
},
};

0 comments on commit 9261888

Please sign in to comment.