From 5ca2e1de9c10e2e498eaf0c22e3b660371242363 Mon Sep 17 00:00:00 2001 From: Alan Agius Date: Mon, 23 May 2022 17:27:23 +0000 Subject: [PATCH] fix(@angular-devkit/build-angular): better handle Windows paths in esbuild experimental builder With this change we handle several esbuild path issues in Windows. Closes #23154 --- .../src/builders/browser-esbuild/esbuild.ts | 4 +++ .../src/builders/browser-esbuild/index.ts | 27 ++++++++++++------- .../builders/browser-esbuild/stylesheets.ts | 5 ++-- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/packages/angular_devkit/build_angular/src/builders/browser-esbuild/esbuild.ts b/packages/angular_devkit/build_angular/src/builders/browser-esbuild/esbuild.ts index 62f592cd6b54..d0363e2f95f5 100644 --- a/packages/angular_devkit/build_angular/src/builders/browser-esbuild/esbuild.ts +++ b/packages/angular_devkit/build_angular/src/builders/browser-esbuild/esbuild.ts @@ -16,6 +16,10 @@ import { build, formatMessages, } from 'esbuild'; +import { resolve } from 'path'; + +/** Default outdir setting for esbuild. */ +export const DEFAULT_OUTDIR = resolve('/virtual-output'); /** * Determines if an unknown value is an esbuild BuildFailure error object thrown by esbuild. diff --git a/packages/angular_devkit/build_angular/src/builders/browser-esbuild/index.ts b/packages/angular_devkit/build_angular/src/builders/browser-esbuild/index.ts index d4da21e528b9..fd0016311c09 100644 --- a/packages/angular_devkit/build_angular/src/builders/browser-esbuild/index.ts +++ b/packages/angular_devkit/build_angular/src/builders/browser-esbuild/index.ts @@ -20,7 +20,7 @@ import { getIndexInputFile, getIndexOutputFile } from '../../utils/webpack-brows import { resolveGlobalStyles } from '../../webpack/configs'; import { Schema as BrowserBuilderOptions, SourceMapClass } from '../browser/schema'; import { createCompilerPlugin } from './compiler-plugin'; -import { bundle, logMessages } from './esbuild'; +import { DEFAULT_OUTDIR, bundle, logMessages } from './esbuild'; import { logExperimentalWarnings } from './experimental-warnings'; import { normalizeOptions } from './options'; import { bundleStylesheetText } from './stylesheets'; @@ -116,11 +116,13 @@ export async function execute( // Entries in the metafile are relative to the `absWorkingDir` option which is set to the workspaceRoot const relativeFilePath = path.relative(workspaceRoot, outputFile.path); const entryPoint = result.metafile?.outputs[relativeFilePath]?.entryPoint; + + outputFile.path = path.relative(DEFAULT_OUTDIR, outputFile.path); + if (entryPoint) { // An entryPoint value indicates an initial file initialFiles.push({ - // Remove leading directory separator - file: outputFile.path.slice(1), + file: outputFile.path, name: entryPointNameLookup.get(entryPoint) ?? '', extension: path.extname(outputFile.path), }); @@ -147,7 +149,9 @@ export async function execute( !!options.preserveSymlinks, ); for (const [name, files] of Object.entries(stylesheetEntrypoints)) { - const virtualEntryData = files.map((file) => `@import '${file}';`).join('\n'); + const virtualEntryData = files + .map((file) => `@import '${file.replace(/\\/g, '/')}';`) + .join('\n'); const sheetResult = await bundleStylesheetText( virtualEntryData, { virtualName: `angular:style/global;${name}`, resolvePath: workspaceRoot }, @@ -172,7 +176,7 @@ export async function execute( // The virtual stylesheets will be named `stdin` by esbuild. This must be replaced // with the actual name of the global style and the leading directory separator must // also be removed to make the path relative. - const sheetPath = sheetResult.path.replace('stdin', name).slice(1); + const sheetPath = sheetResult.path.replace('stdin', name); outputFiles.push(createOutputFileFromText(sheetPath, sheetResult.contents)); if (sheetResult.map) { outputFiles.push(createOutputFileFromText(sheetPath + '.map', sheetResult.map)); @@ -203,10 +207,13 @@ export async function execute( optimization: optimizationOptions, crossOrigin: options.crossOrigin, }); - indexHtmlGenerator.readAsset = async function (path: string): Promise { + + /** Virtual output path to support reading in-memory files. */ + const virtualOutputPath = '/'; + indexHtmlGenerator.readAsset = async function (filePath: string): Promise { // Remove leading directory separator - path = path.slice(1); - const file = outputFiles.find((file) => file.path === path); + const relativefilePath = path.relative(virtualOutputPath, filePath); + const file = outputFiles.find((file) => file.path === relativefilePath); if (file) { return file.text; } @@ -217,7 +224,7 @@ export async function execute( const { content, warnings, errors } = await indexHtmlGenerator.process({ baseHref: options.baseHref, lang: undefined, - outputPath: '/', // Virtual output path to support reading in-memory files + outputPath: virtualOutputPath, files: initialFiles, }); @@ -280,7 +287,7 @@ async function bundleCode( metafile: true, minify: optimizationOptions.scripts, pure: ['forwardRef'], - outdir: '/', + outdir: DEFAULT_OUTDIR, sourcemap: sourcemapOptions.scripts && (sourcemapOptions.hidden ? 'external' : true), splitting: true, tsconfig, diff --git a/packages/angular_devkit/build_angular/src/builders/browser-esbuild/stylesheets.ts b/packages/angular_devkit/build_angular/src/builders/browser-esbuild/stylesheets.ts index 215eac7e8474..86c158598176 100644 --- a/packages/angular_devkit/build_angular/src/builders/browser-esbuild/stylesheets.ts +++ b/packages/angular_devkit/build_angular/src/builders/browser-esbuild/stylesheets.ts @@ -8,7 +8,7 @@ import type { BuildOptions, OutputFile } from 'esbuild'; import * as path from 'path'; -import { bundle } from './esbuild'; +import { DEFAULT_OUTDIR, bundle } from './esbuild'; export interface BundleStylesheetOptions { workspaceRoot?: string; @@ -32,7 +32,7 @@ async function bundleStylesheet( logLevel: 'silent', minify: options.optimization, sourcemap: options.sourcemap, - outdir: '/', + outdir: DEFAULT_OUTDIR, write: false, platform: 'browser', preserveSymlinks: options.preserveSymlinks, @@ -50,6 +50,7 @@ async function bundleStylesheet( const resourceFiles: OutputFile[] = []; if (result.outputFiles) { for (const outputFile of result.outputFiles) { + outputFile.path = path.relative(DEFAULT_OUTDIR, outputFile.path); const filename = path.basename(outputFile.path); if (filename.endsWith('.css')) { outputPath = outputFile.path;