From 7cdf56ba02561dfe3f61c5a67f6bdd4f2e00992a Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Fri, 17 Mar 2017 15:57:26 -0700 Subject: [PATCH] fix(@ngtools/webpack): add template/styles as dependencies So they are rebuilt when the resource changes. This PR refactor _replaceResources into _getResourceNodes which returns the AST nodes for templateUrl or styleUrls, then use that to get the URLs (values). For values that are not computable, we simply ignores. --- packages/@ngtools/webpack/src/loader.ts | 68 +++++++++++++++++++----- packages/@ngtools/webpack/src/webpack.ts | 1 + 2 files changed, 57 insertions(+), 12 deletions(-) diff --git a/packages/@ngtools/webpack/src/loader.ts b/packages/@ngtools/webpack/src/loader.ts index b297c8b18f38..97bd6b1feda4 100644 --- a/packages/@ngtools/webpack/src/loader.ts +++ b/packages/@ngtools/webpack/src/loader.ts @@ -278,9 +278,36 @@ function _getResourceRequest(element: ts.Expression, sourceFile: ts.SourceFile) function _replaceResources(refactor: TypeScriptFileRefactor): void { const sourceFile = refactor.sourceFile; + _getResourceNodes(refactor) + // Get the full text of the initializer. + .forEach((node: ts.PropertyAssignment) => { + const key = _getContentOfKeyLiteral(sourceFile, node.name); + + if (key == 'templateUrl') { + refactor.replaceNode(node, + `template: require(${_getResourceRequest(node.initializer, sourceFile)})`); + } else if (key == 'styleUrls') { + const arr = ( + refactor.findAstNodes(node, ts.SyntaxKind.ArrayLiteralExpression, false)); + if (!arr || arr.length == 0 || arr[0].elements.length == 0) { + return; + } + + const initializer = arr[0].elements.map((element: ts.Expression) => { + return _getResourceRequest(element, sourceFile); + }); + refactor.replaceNode(node, `styles: [require(${initializer.join('), require(')})]`); + } + }); +} + + +function _getResourceNodes(refactor: TypeScriptFileRefactor) { + const { sourceFile } = refactor; + // Find all object literals. - refactor.findAstNodes(sourceFile, ts.SyntaxKind.ObjectLiteralExpression, true) - // Get all their property assignments. + return refactor.findAstNodes(sourceFile, ts.SyntaxKind.ObjectLiteralExpression, true) + // Get all their property assignments. .map(node => refactor.findAstNodes(node, ts.SyntaxKind.PropertyAssignment)) // Flatten into a single array (from an array of array). .reduce((prev, curr) => curr ? prev.concat(curr) : prev, []) @@ -292,14 +319,20 @@ function _replaceResources(refactor: TypeScriptFileRefactor): void { return false; } return key == 'templateUrl' || key == 'styleUrls'; - }) - // Get the full text of the initializer. - .forEach((node: ts.PropertyAssignment) => { - const key = _getContentOfKeyLiteral(sourceFile, node.name); + }); +} + + +function _getResourcesUrls(refactor: TypeScriptFileRefactor): string[] { + return _getResourceNodes(refactor) + .reduce((acc: string[], node: ts.PropertyAssignment) => { + const key = _getContentOfKeyLiteral(refactor.sourceFile, node.name); if (key == 'templateUrl') { - refactor.replaceNode(node, - `template: require(${_getResourceRequest(node.initializer, sourceFile)})`); + const url = (node.initializer as ts.StringLiteral).text; + if (url) { + acc.push(url); + } } else if (key == 'styleUrls') { const arr = ( refactor.findAstNodes(node, ts.SyntaxKind.ArrayLiteralExpression, false)); @@ -307,12 +340,17 @@ function _replaceResources(refactor: TypeScriptFileRefactor): void { return; } - const initializer = arr[0].elements.map((element: ts.Expression) => { - return _getResourceRequest(element, sourceFile); + arr[0].elements.forEach((element: ts.Expression) => { + if (element.kind == ts.SyntaxKind.StringLiteral) { + const url = (element as ts.StringLiteral).text; + if (url) { + acc.push(url); + } + } }); - refactor.replaceNode(node, `styles: [require(${initializer.join('), require(')})]`); } - }); + return acc; + }, []); } @@ -366,6 +404,12 @@ export function ngcLoader(this: LoaderContext & { _compilation: any }) { plugin.diagnose(sourceFileName); } }) + .then(() => { + // Add resources as dependencies. + _getResourcesUrls(refactor).forEach((url: string) => { + this.addDependency(path.resolve(path.dirname(sourceFileName), url)); + }); + }) .then(() => { // Force a few compiler options to make sure we get the result we want. const compilerOptions: ts.CompilerOptions = Object.assign({}, plugin.compilerOptions, { diff --git a/packages/@ngtools/webpack/src/webpack.ts b/packages/@ngtools/webpack/src/webpack.ts index 66ee79f7428f..f04b5d7dc765 100644 --- a/packages/@ngtools/webpack/src/webpack.ts +++ b/packages/@ngtools/webpack/src/webpack.ts @@ -42,6 +42,7 @@ export interface NormalModule { export interface LoaderContext { _module: NormalModule; + addDependency(path: string): void; async(): LoaderCallback; cacheable(): void;