diff --git a/packages/vite-plugin-angular/src/lib/component-resolvers.spec.ts b/packages/vite-plugin-angular/src/lib/component-resolvers.spec.ts index f285424d4..77bb3d963 100644 --- a/packages/vite-plugin-angular/src/lib/component-resolvers.spec.ts +++ b/packages/vite-plugin-angular/src/lib/component-resolvers.spec.ts @@ -136,7 +136,24 @@ describe('component-resolvers', () => { const resolvedTemplateUrls = templateUrlsResolver.resolve(code, id); expect(hasTemplateUrl(code)).toBeTruthy(); - expect(thePathsAreEqual(resolvedTemplateUrls, [actualUrl])); + expect(thePathsAreEqual(resolvedTemplateUrls, [actualUrl])).toBe(true); + }); + + it('should handle templateUrls with single quotes and route params', () => { + const code = ` + @Component({ + templateUrl: './[param].component.html' + }) + export class MyComponent {} + `; + + const actualUrl = + './[param].component.html|/path/to/src/[param].component.html'; + const templateUrlsResolver = new TemplateUrlsResolver(); + const resolvedTemplateUrls = templateUrlsResolver.resolve(code, id); + + expect(hasTemplateUrl(code)).toBeTruthy(); + expect(thePathsAreEqual(resolvedTemplateUrls, [actualUrl])).toBe(true); }); it('should handle templateUrls with double quotes', () => { @@ -153,7 +170,24 @@ describe('component-resolvers', () => { const resolvedTemplateUrls = templateUrlsResolver.resolve(code, id); expect(hasTemplateUrl(code)).toBeTruthy(); - expect(thePathsAreEqual(resolvedTemplateUrls, [actualUrl])); + expect(thePathsAreEqual(resolvedTemplateUrls, [actualUrl])).toBe(true); + }); + + it('should handle templateUrls with double quotes and route params', () => { + const code = ` + @Component({ + templateUrl: "./[param].component.html" + }) + export class MyComponent {} + `; + + const actualUrl = + './[param].component.html|/path/to/src/[param].component.html'; + const templateUrlsResolver = new TemplateUrlsResolver(); + const resolvedTemplateUrls = templateUrlsResolver.resolve(code, id); + + expect(hasTemplateUrl(code)).toBeTruthy(); + expect(thePathsAreEqual(resolvedTemplateUrls, [actualUrl])).toBe(true); }); it('should handle multiple templateUrls in a single file', () => { @@ -166,7 +200,7 @@ describe('component-resolvers', () => { @Component({ templateUrl: "./app1.component.html" }) - export class MyComponentTwo {} + export class MyComponentTwo {} `; const actualUrl1 = @@ -179,7 +213,21 @@ describe('component-resolvers', () => { expect(hasTemplateUrl(code)).toBeTruthy(); expect( thePathsAreEqual(resolvedTemplateUrls, [actualUrl1, actualUrl2]) - ); + ).toBe(true); + }); + + it('should ignore commented out templateUrls', () => { + const code = ` + @Component({ + //templateUrl: './app.component.html' + }) + export class MyComponent {} + `; + + const templateUrlsResolver = new TemplateUrlsResolver(); + const resolvedTemplateUrls = templateUrlsResolver.resolve(code, id); + + expect(resolvedTemplateUrls).toHaveLength(0); }); }); }); diff --git a/packages/vite-plugin-angular/src/lib/component-resolvers.ts b/packages/vite-plugin-angular/src/lib/component-resolvers.ts index c63d38e28..6c3416122 100644 --- a/packages/vite-plugin-angular/src/lib/component-resolvers.ts +++ b/packages/vite-plugin-angular/src/lib/component-resolvers.ts @@ -1,8 +1,8 @@ import { dirname, resolve } from 'path'; +import { Project, SyntaxKind } from 'ts-morph'; import { normalizePath } from 'vite'; const styleUrlsRE = /styleUrls\s*:\s*\[([^\[]*?)\]|styleUrl:\s*["'](.*?)["']/; -const templateUrlRE = /templateUrl:\s*["'](.*?)["']/g; export function hasStyleUrls(code: string) { return styleUrlsRE.test(code); @@ -71,6 +71,18 @@ export function hasTemplateUrl(code: string) { return code.includes('templateUrl:'); } +export function getTemplateUrls(code: string) { + const project = new Project({ useInMemoryFileSystem: true }); + const sourceFile = project.createSourceFile('cmp.ts', code); + return sourceFile + .getDescendantsOfKind(SyntaxKind.PropertyAssignment) + .filter((property) => property.getName() === 'templateUrl') + .map((property) => + property.getInitializer()?.getText().replace(/['"]/g, '') + ) + .filter((url): url is string => url !== undefined); +} + interface TemplateUrlsCacheEntry { code: string; templateUrlPaths: string[]; @@ -88,21 +100,10 @@ export class TemplateUrlsResolver { return entry.templateUrlPaths; } - const templateUrlGroup = Array.from(code.matchAll(templateUrlRE)); - const templateUrlPaths: string[] = []; - - if (Array.isArray(templateUrlGroup)) { - templateUrlGroup.forEach((trg) => { - const resolvedTemplatePath = trg[1].replace( - /templateUrl|\s|'|"|\:|,/g, - '' - ); - const templateUrlPath = normalizePath( - resolve(dirname(id), resolvedTemplatePath).replace(/\\/g, '/') - ); - templateUrlPaths.push(`${resolvedTemplatePath}|${templateUrlPath}`); - }); - } + const templateUrlPaths = getTemplateUrls(code).map( + (url) => + `${url}|${normalizePath(resolve(dirname(id), url).replace(/\\/g, '/'))}` + ); this.templateUrlsCache.set(id, { code, templateUrlPaths }); return templateUrlPaths;