Skip to content

Commit 40315be

Browse files
alexeaglekara
authored andcommitted
fix(compiler-cli): enableResourceInlining handles both styles and styleUrls (angular#22688)
When both are present, the inlined styles are appended to the end of the styles PR Close angular#22688
1 parent 123efba commit 40315be

File tree

3 files changed

+87
-57
lines changed

3 files changed

+87
-57
lines changed

packages/bazel/src/ng_module.bzl

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,7 @@ def _ngc_tsconfig(ctx, files, srcs, **kwargs):
8888

8989
return dict(tsc_wrapped_tsconfig(ctx, files, srcs, **kwargs), **{
9090
"angularCompilerOptions": {
91-
# Always assume that resources can be loaded statically at build time
92-
# TODO(alexeagle): if someone has a legitimate use case for dynamic
93-
# template loading, maybe we need to make this configurable.
94-
"enableResourceInlining": True,
91+
"enableResourceInlining": ctx.attr.inline_resources,
9592
"generateCodeForLibraries": False,
9693
"allowEmptyCodegenFiles": True,
9794
"enableSummariesForJit": True,
@@ -346,6 +343,8 @@ NG_MODULE_ATTRIBUTES = {
346343

347344
"type_check": attr.bool(default = True),
348345

346+
"inline_resources": attr.bool(default = True),
347+
349348
"no_i18n": attr.bool(default = False),
350349

351350
"compiler": attr.label(

packages/compiler-cli/src/transformers/inline_resources.ts

Lines changed: 61 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,16 @@ export class InlineResourcesMetadataTransformer implements MetadataTransformer {
6767
arg['template'] = loader.get(arg['templateUrl']);
6868
delete arg.templateUrl;
6969
}
70-
if (arg['styleUrls']) {
71-
const styleUrls = arg['styleUrls'];
72-
if (Array.isArray(styleUrls)) {
73-
arg['styles'] = styleUrls.map(styleUrl => loader.get(styleUrl));
74-
delete arg.styleUrls;
75-
}
70+
71+
const styles = arg['styles'] || [];
72+
const styleUrls = arg['styleUrls'] || [];
73+
if (!Array.isArray(styles)) throw new Error('styles should be an array');
74+
if (!Array.isArray(styleUrls)) throw new Error('styleUrls should be an array');
75+
76+
styles.push(...styleUrls.map(styleUrl => loader.get(styleUrl)));
77+
if (styles.length > 0) {
78+
arg['styles'] = styles;
79+
delete arg.styleUrls;
7680
}
7781

7882
return arg;
@@ -262,49 +266,59 @@ function updateComponentProperties(
262266
// argument
263267
return args;
264268
}
265-
const newArgument = ts.updateObjectLiteral(
266-
componentArg, ts.visitNodes(componentArg.properties, (node: ts.ObjectLiteralElementLike) => {
267-
if (!ts.isPropertyAssignment(node)) {
268-
// Error: unsupported
269-
return node;
270-
}
271269

272-
if (ts.isComputedPropertyName(node.name)) {
273-
// computed names are not supported
274-
return node;
270+
const newProperties: ts.ObjectLiteralElementLike[] = [];
271+
const newStyleExprs: ts.Expression[] = [];
272+
componentArg.properties.forEach(prop => {
273+
if (!ts.isPropertyAssignment(prop) || ts.isComputedPropertyName(prop.name)) {
274+
newProperties.push(prop);
275+
return;
276+
}
277+
278+
switch (prop.name.text) {
279+
case 'styles':
280+
if (!ts.isArrayLiteralExpression(prop.initializer)) {
281+
throw new Error('styles takes an array argument');
275282
}
283+
newStyleExprs.push(...prop.initializer.elements);
284+
break;
276285

277-
const name = node.name.text;
278-
switch (name) {
279-
case 'styleUrls':
280-
if (!ts.isArrayLiteralExpression(node.initializer)) {
281-
// Error: unsupported
282-
return node;
283-
}
284-
const styleUrls = node.initializer.elements;
285-
286-
return ts.updatePropertyAssignment(
287-
node, ts.createIdentifier('styles'),
288-
ts.createArrayLiteral(ts.visitNodes(styleUrls, (expr: ts.Expression) => {
289-
if (ts.isStringLiteral(expr)) {
290-
const styles = loader.get(expr.text);
291-
return ts.createLiteral(styles);
292-
}
293-
return expr;
294-
})));
295-
296-
297-
case 'templateUrl':
298-
if (ts.isStringLiteral(node.initializer)) {
299-
const template = loader.get(node.initializer.text);
300-
return ts.updatePropertyAssignment(
301-
node, ts.createIdentifier('template'), ts.createLiteral(template));
302-
}
303-
return node;
304-
305-
default:
306-
return node;
286+
case 'styleUrls':
287+
if (!ts.isArrayLiteralExpression(prop.initializer)) {
288+
throw new Error('styleUrls takes an array argument');
289+
}
290+
newStyleExprs.push(...prop.initializer.elements.map((expr: ts.Expression) => {
291+
if (!ts.isStringLiteral(expr) && !ts.isNoSubstitutionTemplateLiteral(expr)) {
292+
throw new Error(
293+
'Can only accept string literal arguments to styleUrls. ' + PRECONDITIONS_TEXT);
294+
}
295+
const styles = loader.get(expr.text);
296+
return ts.createLiteral(styles);
297+
}));
298+
break;
299+
300+
case 'templateUrl':
301+
if (!ts.isStringLiteral(prop.initializer) &&
302+
!ts.isNoSubstitutionTemplateLiteral(prop.initializer)) {
303+
throw new Error(
304+
'Can only accept a string literal argument to templateUrl. ' + PRECONDITIONS_TEXT);
307305
}
308-
}));
309-
return ts.createNodeArray<ts.Expression>([newArgument]);
306+
const template = loader.get(prop.initializer.text);
307+
newProperties.push(ts.updatePropertyAssignment(
308+
prop, ts.createIdentifier('template'), ts.createLiteral(template)));
309+
break;
310+
311+
default:
312+
newProperties.push(prop);
313+
}
314+
});
315+
316+
// Add the non-inline styles
317+
if (newStyleExprs.length > 0) {
318+
const newStyles = ts.createPropertyAssignment(
319+
ts.createIdentifier('styles'), ts.createArrayLiteral(newStyleExprs));
320+
newProperties.push(newStyles);
321+
}
322+
323+
return ts.createNodeArray([ts.updateObjectLiteral(componentArg, newProperties)]);
310324
}

packages/compiler-cli/test/transformers/inline_resources_spec.ts

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,18 @@ describe('inline resources transformer', () => {
4242
const actual = convert(`import {Component} from '@angular/core';
4343
@Component({
4444
templateUrl: './thing.html',
45-
otherProp: 3,
46-
}) export class Foo {}`);
45+
otherProp: 3,
46+
}) export class Foo {}`);
4747
expect(actual).not.toContain('templateUrl:');
4848
expect(actual.replace(/\s+/g, ' '))
4949
.toContain(
50-
'Foo = __decorate([ core_1.Component({ template: "Some template", otherProp: 3, }) ], Foo)');
50+
'Foo = __decorate([ core_1.Component({ template: "Some template", otherProp: 3 }) ], Foo)');
51+
});
52+
it('should allow different quotes', () => {
53+
const actual = convert(`import {Component} from '@angular/core';
54+
@Component({"templateUrl": \`./thing.html\`}) export class Foo {}`);
55+
expect(actual).not.toContain('templateUrl:');
56+
expect(actual).toContain('{ template: "Some template" }');
5157
});
5258
it('should replace styleUrls', () => {
5359
const actual = convert(`import {Component} from '@angular/core';
@@ -58,11 +64,21 @@ describe('inline resources transformer', () => {
5864
expect(actual).not.toContain('styleUrls:');
5965
expect(actual).toContain('styles: [".some_style {}", ".some_other_style {}"]');
6066
});
67+
it('should preserve existing styles', () => {
68+
const actual = convert(`import {Component} from '@angular/core';
69+
@Component({
70+
styles: ['h1 { color: blue }'],
71+
styleUrls: ['./thing1.css'],
72+
})
73+
export class Foo {}`);
74+
expect(actual).not.toContain('styleUrls:');
75+
expect(actual).toContain(`styles: ['h1 { color: blue }', ".some_style {}"]`);
76+
});
6177
it('should handle empty styleUrls', () => {
6278
const actual = convert(`import {Component} from '@angular/core';
63-
@Component({styleUrls: []}) export class Foo {}`);
79+
@Component({styleUrls: [], styles: []}) export class Foo {}`);
6480
expect(actual).not.toContain('styleUrls:');
65-
expect(actual).toContain('styles: []');
81+
expect(actual).not.toContain('styles:');
6682
});
6783
});
6884
describe('annotation input', () => {
@@ -115,6 +131,7 @@ describe('metadata transformer', () => {
115131
@Component({
116132
templateUrl: './thing.html',
117133
styleUrls: ['./thing1.css', './thing2.css'],
134+
styles: ['h1 { color: red }'],
118135
})
119136
export class Foo {}
120137
`;
@@ -135,7 +152,7 @@ describe('metadata transformer', () => {
135152
expect(JSON.stringify(classData)).toContain('"template":"Some template"');
136153
expect(JSON.stringify(classData)).not.toContain('styleUrls');
137154
expect(JSON.stringify(classData))
138-
.toContain('"styles":[".some_style {}",".some_other_style {}"]');
155+
.toContain('"styles":["h1 { color: red }",".some_style {}",".some_other_style {}"]');
139156
}
140157
}
141158
});

0 commit comments

Comments
 (0)