From 11eadcbac7d73dfb2bc5d7ea93490ecaf35e0db0 Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Tue, 11 Apr 2023 17:21:45 -0400 Subject: [PATCH] perf(@angular-devkit/build-angular): enhance Sass package resolution in esbuild builder The package module resolution logic for Sass stylesheets within the esbuild-based browser application builder has been restructured to limit the need to perform fallback resolution unless fully required. This allows common cases to avoid unnecessary and expensive resolution attempts. This provided a roughly 40% improvement in build times for the Angular Material documentation site. --- .../builders/browser-esbuild/sass-plugin.ts | 62 +++++++++++++------ 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/packages/angular_devkit/build_angular/src/builders/browser-esbuild/sass-plugin.ts b/packages/angular_devkit/build_angular/src/builders/browser-esbuild/sass-plugin.ts index 6d96d3e071ab..a9c5dc5bd551 100644 --- a/packages/angular_devkit/build_angular/src/builders/browser-esbuild/sass-plugin.ts +++ b/packages/angular_devkit/build_angular/src/builders/browser-esbuild/sass-plugin.ts @@ -114,32 +114,54 @@ async function compileString( url, { previousResolvedModules }: FileImporterWithRequestContextOptions, ): Promise => { - const result = await resolveUrl(url, previousResolvedModules); + let result = await resolveUrl(url); + if (result.path) { + return pathToFileURL(result.path); + } // Check for package deep imports - if (!result.path) { - const parts = url.split('/'); - const hasScope = parts.length >= 2 && parts[0].startsWith('@'); - const [nameOrScope, nameOrFirstPath, ...pathPart] = parts; - const packageName = hasScope ? `${nameOrScope}/${nameOrFirstPath}` : nameOrScope; - - const packageResult = await resolveUrl( - packageName + '/package.json', - previousResolvedModules, + const parts = url.split('/'); + const hasScope = parts.length >= 2 && parts[0].startsWith('@'); + const [nameOrScope, nameOrFirstPath, ...pathPart] = parts; + const packageName = hasScope ? `${nameOrScope}/${nameOrFirstPath}` : nameOrScope; + + let packageResult = await resolveUrl(packageName + '/package.json'); + + if (packageResult.path) { + return pathToFileURL( + join( + dirname(packageResult.path), + !hasScope && nameOrFirstPath ? nameOrFirstPath : '', + ...pathPart, + ), ); + } + + // Check with Yarn PnP workaround using previous resolved modules. + // This is done last to avoid a performance penalty for common cases. - if (packageResult.path) { - return pathToFileURL( - join( - dirname(packageResult.path), - !hasScope && nameOrFirstPath ? nameOrFirstPath : '', - ...pathPart, - ), - ); - } + result = await resolveUrl(url, previousResolvedModules); + if (result.path) { + return pathToFileURL(result.path); + } + + packageResult = await resolveUrl( + packageName + '/package.json', + previousResolvedModules, + ); + + if (packageResult.path) { + return pathToFileURL( + join( + dirname(packageResult.path), + !hasScope && nameOrFirstPath ? nameOrFirstPath : '', + ...pathPart, + ), + ); } - return result.path ? pathToFileURL(result.path) : null; + // Not found + return null; }, }, ],