Skip to content
This repository was archived by the owner on Jan 6, 2025. It is now read-only.

Commit edec14d

Browse files
committed
fix: add correct ssr styles
* Add virtual stylesheet to store server styles, which applies default styles when breakpoint overrides are not present * Intercept all style calls and reroute them to the virtual stylesheet while not in the browser * Add a new type of MediaQueryList similar to the MockMediaQueryList for the server that allows for manual activation/deactivation of breakpoints * Update deps to Angular v5.2.x and TypeScript v2.6.x
1 parent 2d17a48 commit edec14d

33 files changed

+9712
-8517
lines changed

package-lock.json

Lines changed: 9257 additions & 8369 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -26,58 +26,58 @@
2626
"node": ">= 5.4.1"
2727
},
2828
"dependencies": {
29-
"@angular/core": "~5.1.0",
30-
"@angular/common": "~5.1.0",
31-
"@angular/compiler": "~5.1.0",
32-
"@angular/platform-browser": "~5.1.0",
33-
"core-js": "^2.4.1",
34-
"rxjs": "^5.5.5",
29+
"@angular/common": "^5.2.0",
30+
"@angular/compiler": "^5.2.0",
31+
"@angular/core": "^5.2.0",
32+
"@angular/platform-browser": "^5.2.0",
33+
"core-js": "^2.5.3",
34+
"rxjs": "^5.5.6",
3535
"systemjs": "0.19.43",
3636
"tsickle": "^0.24.x",
37-
"tslib": "^1.8.0",
38-
"zone.js": "^0.8.18"
37+
"tslib": "^1.8.1",
38+
"zone.js": "^0.8.20"
3939
},
4040
"devDependencies": {
41-
"@angular/animations": "~5.1.0",
42-
"@angular/cdk": "^5.0.1",
43-
"@angular/compiler-cli": "~5.1.0",
44-
"@angular/forms": "~5.1.0",
45-
"@angular/http": "~5.1.0",
46-
"@angular/material": "^5.0.1",
47-
"@angular/platform-browser-dynamic": "~5.1.0",
48-
"@angular/platform-server": "~5.1.0",
49-
"@angular/router": "~5.1.0",
41+
"@angular/animations": "^5.2.0",
42+
"@angular/cdk": "^5.0.4",
43+
"@angular/compiler-cli": "^5.2.0",
44+
"@angular/forms": "^5.2.0",
45+
"@angular/http": "^5.2.0",
46+
"@angular/material": "^5.0.4",
47+
"@angular/platform-browser-dynamic": "^5.2.0",
48+
"@angular/platform-server": "^5.2.0",
49+
"@angular/router": "^5.2.0",
5050
"@angular/tsc-wrapped": "^4.4.6",
51-
"@google-cloud/storage": "^1.4.0",
51+
"@google-cloud/storage": "^1.5.2",
5252
"@types/chalk": "^0.4.31",
5353
"@types/fs-extra": "^4.0.5",
54-
"@types/glob": "^5.0.33",
54+
"@types/glob": "^5.0.34",
5555
"@types/gulp": "3.8.32",
5656
"@types/hammerjs": "^2.0.34",
57-
"@types/jasmine": "^2.6.3",
57+
"@types/jasmine": "^2.8.3",
5858
"@types/merge2": "^0.3.30",
5959
"@types/minimist": "^1.2.0",
60-
"@types/node": "^7.0.46",
60+
"@types/node": "^7.0.52",
6161
"@types/run-sequence": "^0.0.29",
6262
"@types/rx": "2.5.33",
63-
"axe-core": "^2.4.2",
64-
"axe-webdriverjs": "^1.1.5",
63+
"axe-core": "^2.6.1",
64+
"axe-webdriverjs": "^1.2.1",
6565
"chalk": "^1.1.3",
6666
"cli-color": "^1.2.0",
6767
"dgeni": "^0.4.7",
6868
"dgeni-packages": "^0.22.0",
69-
"firebase": "^4.6.0",
70-
"firebase-admin": "^5.4.2",
71-
"firebase-tools": "^3.13.1",
69+
"firebase": "^4.8.1",
70+
"firebase-admin": "^5.7.0",
71+
"firebase-tools": "^3.16.0",
7272
"fs-extra": "^3.0.1",
7373
"glob": "^7.1.2",
7474
"google-closure-compiler": "20170409.0.0",
7575
"gulp": "^3.9.1",
7676
"gulp-clean": "^0.3.2",
77-
"gulp-clean-css": "^3.9.0",
77+
"gulp-clean-css": "^3.9.2",
7878
"gulp-cli": "^1.3.0",
79-
"gulp-connect": "^5.0.0",
80-
"gulp-conventional-changelog": "^1.1.6",
79+
"gulp-connect": "^5.2.0",
80+
"gulp-conventional-changelog": "^1.1.7",
8181
"gulp-dom": "^0.9.17",
8282
"gulp-flatten": "^0.3.1",
8383
"gulp-highlight-files": "^0.0.5",
@@ -97,32 +97,32 @@
9797
"karma-browserstack-launcher": "^1.3.0",
9898
"karma-chrome-launcher": "^2.2.0",
9999
"karma-coverage": "^1.1.1",
100-
"karma-firefox-launcher": "^1.0.1",
100+
"karma-firefox-launcher": "^1.1.0",
101101
"karma-jasmine": "^1.1.1",
102102
"karma-sauce-launcher": "^1.2.0",
103103
"karma-sourcemap-loader": "^0.3.7",
104104
"madge": "^2.2.0",
105105
"magic-string": "^0.22.4",
106-
"merge2": "^1.2.0",
106+
"merge2": "^1.2.1",
107107
"minimatch": "^3.0.4",
108108
"minimist": "^1.2.0",
109109
"prompt-sync": "^4.1.5",
110-
"protractor": "^5.2.0",
110+
"protractor": "^5.2.2",
111111
"request": "^2.83.0",
112112
"resolve-bin": "^0.4.0",
113113
"rollup": "^0.41.6",
114114
"rollup-plugin-alias": "^1.4.0",
115-
"rollup-plugin-node-resolve": "^3.0.0",
115+
"rollup-plugin-node-resolve": "^3.0.2",
116116
"run-sequence": "^1.2.2",
117-
"scss-bundle": "^2.0.1-beta.7",
117+
"scss-bundle": "^2.1.1",
118118
"selenium-webdriver": "^3.6.0",
119119
"sorcery": "^0.10.0",
120-
"stylelint": "^7.12.0",
120+
"stylelint": "^8.4.0",
121121
"ts-node": "^3.0.4",
122-
"tsconfig-paths": "^2.3.0",
123-
"tslint": "^5.8.0",
124-
"tsutils": "^2.13.0",
125-
"typescript": "^2.4.2",
122+
"tsconfig-paths": "^2.7.3",
123+
"tslint": "^5.9.1",
124+
"tsutils": "^2.16.0",
125+
"typescript": "^2.6.2",
126126
"uglify-js": "^2.8.14"
127127
}
128-
}
128+
}

src/lib/api/core/base-adapter.spec.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
import {ElementRef, Renderer2} from '@angular/core';
99
import {BaseFxDirectiveAdapter} from './base-adapter';
1010
import {expect} from '../../utils/testing/custom-matchers';
11-
import {MediaMonitor} from '@angular/flex-layout/media-query';
11+
import {MediaMonitor} from '../../media-query/media-monitor';
12+
import {ServerStylesheet} from '../../utils/server-stylesheet';
1213

1314
export class MockElementRef extends ElementRef {
1415
constructor() {
@@ -21,7 +22,7 @@ export class MockElementRef extends ElementRef {
2122
describe('BaseFxDirectiveAdapter class', () => {
2223
let component;
2324
beforeEach(() => {
24-
component = new BaseFxDirectiveAdapter('', {} as MediaMonitor, new MockElementRef(), {} as Renderer2, {}); // tslint:disable-line:max-line-length
25+
component = new BaseFxDirectiveAdapter('', {} as MediaMonitor, new MockElementRef(), {} as Renderer2, {}, {} as ServerStylesheet); // tslint:disable-line:max-line-length
2526
});
2627
describe('cacheInput', () => {
2728
it('should call _cacheInputArray when source is an array', () => {

src/lib/api/core/base-adapter.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {BaseFxDirective} from './base';
1111
import {ResponsiveActivation} from './responsive-activation';
1212
import {MediaQuerySubscriber} from '../../media-query/media-change';
1313
import {MediaMonitor} from '../../media-query/media-monitor';
14+
import {ServerStylesheet} from '../../utils/server-stylesheet';
1415

1516

1617
/**
@@ -49,8 +50,9 @@ export class BaseFxDirectiveAdapter extends BaseFxDirective {
4950
protected _mediaMonitor: MediaMonitor,
5051
protected _elementRef: ElementRef,
5152
protected _renderer: Renderer2,
52-
@Inject(PLATFORM_ID) protected _platformId: Object) {
53-
super(_mediaMonitor, _elementRef, _renderer, _platformId);
53+
@Inject(PLATFORM_ID) protected _platformId: Object,
54+
protected _serverStylesheet: ServerStylesheet) {
55+
super(_mediaMonitor, _elementRef, _renderer, _platformId, _serverStylesheet);
5456
}
5557

5658
/**

src/lib/api/core/base.ts

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ import {
2929
import {ResponsiveActivation, KeyOptions} from '../core/responsive-activation';
3030
import {MediaMonitor} from '../../media-query/media-monitor';
3131
import {MediaQuerySubscriber} from '../../media-query/media-change';
32+
import {ServerStylesheet} from '../../utils/server-stylesheet';
33+
import {isPlatformBrowser} from '@angular/common';
3234

3335
/** Abstract base class for the Layout API styling directives. */
3436
export abstract class BaseFxDirective implements OnDestroy, OnChanges {
@@ -71,7 +73,8 @@ export abstract class BaseFxDirective implements OnDestroy, OnChanges {
7173
constructor(protected _mediaMonitor: MediaMonitor,
7274
protected _elementRef: ElementRef,
7375
protected _renderer: Renderer2,
74-
@Inject(PLATFORM_ID) protected _platformId: Object) {
76+
@Inject(PLATFORM_ID) protected _platformId: Object,
77+
protected _serverStylesheet: ServerStylesheet) {
7578
}
7679

7780
// *********************************************
@@ -137,11 +140,16 @@ export abstract class BaseFxDirective implements OnDestroy, OnChanges {
137140

138141
/**
139142
* Quick accessor to the current HTMLElement's `display` style
140-
* Note: this allows use to preserve the original style
143+
* Note: this allows us to preserve the original style
141144
* and optional restore it when the mediaQueries deactivate
142145
*/
143146
protected _getDisplayStyle(source: HTMLElement = this.nativeElement): string {
144-
return lookupStyle(this._platformId, source || this.nativeElement, 'display');
147+
const query = 'display';
148+
if (isPlatformBrowser(this._platformId)) {
149+
return lookupStyle(this._platformId, source || this.nativeElement, query);
150+
} else {
151+
return this._serverStylesheet.getStyleForElement(source, query);
152+
}
145153
}
146154

147155
/**
@@ -160,13 +168,26 @@ export abstract class BaseFxDirective implements OnDestroy, OnChanges {
160168
*/
161169
protected _getFlowDirection(target: any, addIfMissing = false): string {
162170
let value = 'row';
171+
let hasInlineValue = '';
172+
const query = 'flex-direction';
163173

164174
if (target) {
165-
value = lookupStyle(this._platformId, target, 'flex-direction') || 'row';
166-
let hasInlineValue = lookupInlineStyle(target, 'flex-direction');
175+
if (isPlatformBrowser(this._platformId)) {
176+
value = lookupStyle(this._platformId, target, query) || 'row';
177+
hasInlineValue = lookupInlineStyle(target, query);
178+
} else {
179+
// TODO(CaerusKaru): platform-server has no implementation for getComputedStyle
180+
value = this._serverStylesheet.getStyleForElement(target, query) || 'row';
181+
}
167182

168183
if (!hasInlineValue && addIfMissing) {
169-
applyStyleToElements(this._renderer, buildLayoutCSS(value), [target]);
184+
const style = buildLayoutCSS(value);
185+
const elements = [target];
186+
if (isPlatformBrowser(this._platformId)) {
187+
applyStyleToElements(this._renderer, style, elements);
188+
} else {
189+
this._serverStylesheet.addStyleToElements(style, elements);
190+
}
170191
}
171192
}
172193

@@ -180,14 +201,22 @@ export abstract class BaseFxDirective implements OnDestroy, OnChanges {
180201
value?: string | number,
181202
nativeElement: any = this.nativeElement) {
182203
let element = nativeElement || this.nativeElement;
183-
applyStyleToElement(this._renderer, element, style, value);
204+
if (isPlatformBrowser(this._platformId)) {
205+
applyStyleToElement(this._renderer, element, style, value);
206+
} else {
207+
this._serverStylesheet.addStyleToElement(element, style, value);
208+
}
184209
}
185210

186211
/**
187212
* Applies styles given via string pair or object map to the directive's element.
188213
*/
189214
protected _applyStyleToElements(style: StyleDefinition, elements: HTMLElement[ ]) {
190-
applyStyleToElements(this._renderer, style, elements || []);
215+
if (isPlatformBrowser(this._platformId)) {
216+
applyStyleToElements(this._renderer, style, elements || []);
217+
} else {
218+
this._serverStylesheet.addStyleToElements(style, elements || []);
219+
}
191220
}
192221

193222
/**

src/lib/api/core/responsive-activation.spec.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import {MediaQuerySubscriber, MediaChange} from '../../media-query/media-change'
2222
describe('responsive-activation', () => {
2323
let monitor: MediaMonitor;
2424
let matchMedia: MockMatchMedia;
25-
let breakPoints: BreakPointRegistry;
2625

2726
/**
2827
* MediaQuery Change responder used to determine the activated input
@@ -52,9 +51,8 @@ describe('responsive-activation', () => {
5251

5352
// Single async inject to save references; which are used in all tests below
5453
beforeEach(inject(
55-
[BreakPointRegistry, MatchMedia, MediaMonitor],
56-
(_breakPoints, _matchMedia, _mediaMonitor) => {
57-
breakPoints = _breakPoints; // Only used to look up mediaQuery by aliases
54+
[MatchMedia, MediaMonitor],
55+
(_matchMedia, _mediaMonitor) => {
5856
matchMedia = _matchMedia; // Only used to manual/simulate activate a mediaQuery
5957
monitor = _mediaMonitor;
6058
}

src/lib/api/ext/class.spec.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {BreakPointRegistry} from '../../media-query/breakpoints/break-point-regi
2222

2323
import {ClassDirective} from './class';
2424
import {MediaQueriesModule} from '../../media-query/_module';
25+
import {ServerStylesheet} from '../../utils/server-stylesheet';
2526

2627
describe('class directive', () => {
2728
let fixture: ComponentFixture<any>;
@@ -47,7 +48,8 @@ describe('class directive', () => {
4748
declarations: [TestClassComponent, ClassDirective],
4849
providers: [
4950
BreakPointRegistry, DEFAULT_BREAKPOINTS_PROVIDER,
50-
{provide: MatchMedia, useClass: MockMatchMedia}
51+
{provide: MatchMedia, useClass: MockMatchMedia},
52+
ServerStylesheet
5153
]
5254
});
5355
});

src/lib/api/ext/class.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import {BaseFxDirectiveAdapter} from '../core/base-adapter';
2929
import {MediaChange} from '../../media-query/media-change';
3030
import {MediaMonitor} from '../../media-query/media-monitor';
3131
import {RendererAdapter} from '../core/renderer-adapter';
32+
import {ServerStylesheet} from '../../utils/server-stylesheet';
3233

3334
/** NgClass allowed inputs **/
3435
export type NgClassType = string | string[] | Set<string> | {[klass: string]: any};
@@ -95,8 +96,9 @@ export class ClassDirective extends BaseFxDirective
9596
protected _ngEl: ElementRef,
9697
protected _renderer: Renderer2,
9798
@Optional() @Self() private _ngClassInstance: NgClass,
98-
@Inject(PLATFORM_ID) protected _platformId: Object) {
99-
super(monitor, _ngEl, _renderer, _platformId);
99+
@Inject(PLATFORM_ID) protected _platformId: Object,
100+
protected _serverStylesheet: ServerStylesheet) {
101+
super(monitor, _ngEl, _renderer, _platformId, _serverStylesheet);
100102
this._configureAdapters();
101103
}
102104

@@ -139,7 +141,12 @@ export class ClassDirective extends BaseFxDirective
139141
*/
140142
protected _configureAdapters() {
141143
this._base = new BaseFxDirectiveAdapter(
142-
'ngClass', this.monitor, this._ngEl, this._renderer, this._platformId
144+
'ngClass',
145+
this.monitor,
146+
this._ngEl,
147+
this._renderer,
148+
this._platformId,
149+
this._serverStylesheet,
143150
);
144151
if (!this._ngClassInstance) {
145152
// Create an instance NgClass Directive instance only if `ngClass=""` has NOT been defined on

src/lib/api/ext/hide.spec.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
} from '../../utils/testing/helpers';
2424
import {ShowHideDirective} from './show-hide';
2525
import {MediaQueriesModule} from '../../media-query/_module';
26+
import {ServerStylesheet} from '../../utils/server-stylesheet';
2627

2728
describe('hide directive', () => {
2829
let fixture: ComponentFixture<any>;
@@ -60,7 +61,8 @@ describe('hide directive', () => {
6061
declarations: [TestHideComponent, ShowHideDirective],
6162
providers: [
6263
BreakPointRegistry, DEFAULT_BREAKPOINTS_PROVIDER,
63-
{provide: MatchMedia, useClass: MockMatchMedia}
64+
{provide: MatchMedia, useClass: MockMatchMedia},
65+
ServerStylesheet
6466
]
6567
});
6668
});

src/lib/api/ext/img-src.spec.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,15 +51,13 @@ const DEFAULT_SRC = 'https://dummyimage.com/300x300/c72538/ffffff.png';
5151
describe('img-src directive', () => {
5252
let fixture: ComponentFixture<any>;
5353
let matchMedia: MockMatchMedia;
54-
let breakpoints: BreakPointRegistry;
5554

5655
let componentWithTemplate = (template: string) => {
5756
fixture = makeCreateTestComponent(() => TestSrcComponent)(template);
5857

59-
inject([MatchMedia, BreakPointRegistry],
60-
(_matchMedia: MockMatchMedia, _breakpoints: BreakPointRegistry) => {
58+
inject([MatchMedia],
59+
(_matchMedia: MockMatchMedia) => {
6160
matchMedia = _matchMedia;
62-
breakpoints = _breakpoints;
6361
})();
6462
};
6563

src/lib/api/ext/img-src.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818

1919
import {BaseFxDirective} from '../core/base';
2020
import {MediaMonitor} from '../../media-query/media-monitor';
21+
import {ServerStylesheet} from '../../utils/server-stylesheet';
2122

2223
/**
2324
* This directive provides a responsive API for the HTML <img> 'src' attribute
@@ -60,8 +61,9 @@ export class ImgSrcDirective extends BaseFxDirective implements OnInit, OnChange
6061
constructor(elRef: ElementRef,
6162
renderer: Renderer2,
6263
monitor: MediaMonitor,
63-
@Inject(PLATFORM_ID) platformId: Object) {
64-
super(monitor, elRef, renderer, platformId);
64+
@Inject(PLATFORM_ID) platformId: Object,
65+
serverStylesheet: ServerStylesheet) {
66+
super(monitor, elRef, renderer, platformId, serverStylesheet);
6567
this._cacheInput('src', elRef.nativeElement.getAttribute('src') || '');
6668
}
6769

0 commit comments

Comments
 (0)