Skip to content

Commit fc5a2ec

Browse files
committed
refactor(@angular/build): remove sass worker and fallback to pure-JS sass
Removes the legacy Piscina-based Sass worker thread pool implementation (`sass-worker-implementation.ts` and `worker.ts`). When the native `sass-embedded` compiler cannot be used (such as inside WebContainers or when disabled), the build system now directly falls back to the in-process pure-JS Dart Sass asynchronous compiler (`sass.initAsyncCompiler()`). Consolidates the Sass compilation logic in `packages/angular/build/src/tools/sass` into a simplified `SassCompiler` class in `sass-service.ts` supporting both rebasing (esbuild) and non-rebasing (Webpack) usage. Environment Variable: - Replaces `NG_BUILD_SASS_WORKER` with `NG_BUILD_SASS_EMBEDDED`. - When `NG_BUILD_SASS_EMBEDDED` is set to `0` or `false`, or when running within a WebContainer environment, the native embedded Sass compiler is disabled and the pure-JS Sass compiler is used instead.
1 parent 9cebe22 commit fc5a2ec

9 files changed

Lines changed: 207 additions & 807 deletions

File tree

packages/angular/build/src/private.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export {
3535
export type { ExternalResultMetadata } from './tools/esbuild/bundler-execution-result';
3636
export { emitFilesToDisk } from './tools/esbuild/utils';
3737
export { transformSupportedBrowsersToTargets } from './tools/esbuild/target';
38-
export { SassWorkerImplementation } from './tools/sass/sass-worker-implementation';
38+
export { SassCompiler } from './tools/sass/sass-service';
3939

4040
export { SourceFileCache } from './tools/esbuild/angular/source-file-cache';
4141
export { Cache } from './tools/esbuild/cache';

packages/angular/build/src/tools/esbuild/stylesheets/sass-language.ts

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,12 @@ import type { OnLoadResult, PartialMessage, PartialNote, ResolveResult } from 'e
1010
import { dirname, join } from 'node:path';
1111
import { fileURLToPath, pathToFileURL } from 'node:url';
1212
import type { CanonicalizeContext, CompileResult, Exception, Syntax } from 'sass-embedded';
13-
import { useSassWorker } from '../../../utils/environment-options';
14-
import type { SassServiceImplementation } from '../../sass/sass-service';
13+
import type { SassCompiler } from '../../sass/sass-service';
1514
import { MemoryCache } from '../cache';
1615
import { StylesheetLanguage, StylesheetPluginOptions } from './stylesheet-plugin-factory';
1716

18-
let sassService: SassServiceImplementation | undefined;
19-
let sassServicePromise: Promise<SassServiceImplementation> | undefined;
17+
let sassService: SassCompiler | undefined;
18+
let sassServicePromise: Promise<SassCompiler> | undefined;
2019

2120
function isSassException(error: unknown): error is Exception {
2221
return !!error && typeof error === 'object' && 'sassMessage' in error;
@@ -81,13 +80,9 @@ async function compileString(
8180
// Lazily load Sass when a Sass file is found
8281
if (sassService === undefined) {
8382
if (sassServicePromise === undefined) {
84-
sassServicePromise = useSassWorker
85-
? import('../../sass/sass-worker-implementation').then(
86-
(sassService) => new sassService.SassWorkerImplementation(true),
87-
)
88-
: import('../../sass/sass-async-compiler-implementation').then(
89-
(sassService) => new sassService.SassAsyncCompilerImplementation(),
90-
);
83+
sassServicePromise = import('../../sass/sass-service').then(
84+
(sassService) => new sassService.SassCompiler(true),
85+
);
9186
}
9287
try {
9388
sassService = await sassServicePromise;

packages/angular/build/src/tools/sass/rebasing-importer.ts

Lines changed: 6 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ abstract class UrlRebasingImporter implements Importer<'sync'> {
4545
constructor(
4646
private entryDirectory: string,
4747
private rebaseSourceMaps?: Map<string, DecodedSourceMap>,
48-
) {}
48+
) {
49+
this.load = this.load.bind(this);
50+
}
4951

5052
abstract canonicalize(url: string, options: { fromImport: boolean }): URL | null;
5153

@@ -140,6 +142,7 @@ export class RelativeUrlRebasingImporter extends UrlRebasingImporter {
140142
rebaseSourceMaps?: Map<string, DecodedSourceMap>,
141143
) {
142144
super(entryDirectory, rebaseSourceMaps);
145+
this.canonicalize = this.canonicalize.bind(this);
143146
}
144147

145148
canonicalize(url: string, options: { fromImport: boolean }): URL | null {
@@ -316,33 +319,6 @@ export class RelativeUrlRebasingImporter extends UrlRebasingImporter {
316319
}
317320
}
318321

319-
/**
320-
* Provides the Sass importer logic to resolve module (npm package) stylesheet imports via both import and
321-
* use rules and also rebase any `url()` function usage within those stylesheets. The rebasing will ensure that
322-
* the URLs in the output of the Sass compiler reflect the final filesystem location of the output CSS file.
323-
*/
324-
export class ModuleUrlRebasingImporter extends RelativeUrlRebasingImporter {
325-
constructor(
326-
entryDirectory: string,
327-
directoryCache: Map<string, DirectoryEntry>,
328-
rebaseSourceMaps: Map<string, DecodedSourceMap> | undefined,
329-
private finder: (specifier: string, options: CanonicalizeContext) => URL | null,
330-
) {
331-
super(entryDirectory, directoryCache, rebaseSourceMaps);
332-
}
333-
334-
override canonicalize(url: string, options: CanonicalizeContext): URL | null {
335-
if (url.startsWith('file://')) {
336-
return super.canonicalize(url, options);
337-
}
338-
339-
let result = this.finder(url, options);
340-
result &&= super.canonicalize(result.href, options);
341-
342-
return result;
343-
}
344-
}
345-
346322
/**
347323
* Provides the Sass importer logic to resolve module (npm package) stylesheet imports asynchronously
348324
* and also rebase any `url()` function usage within those stylesheets.
@@ -364,6 +340,8 @@ export class AsyncModuleUrlRebasingImporter implements Importer<'async'> {
364340
directoryCache,
365341
rebaseSourceMaps,
366342
);
343+
this.canonicalize = this.canonicalize.bind(this);
344+
this.load = this.load.bind(this);
367345
}
368346

369347
async canonicalize(url: string, options: CanonicalizeContext): Promise<URL | null> {
@@ -412,16 +390,3 @@ export class LoadPathsUrlRebasingImporter extends RelativeUrlRebasingImporter {
412390
return result;
413391
}
414392
}
415-
416-
/**
417-
* Workaround for Sass not calling instance methods with `this`.
418-
* The `canonicalize` and `load` methods will be bound to the class instance.
419-
* @param importer A Sass importer to bind.
420-
* @returns The bound Sass importer.
421-
*/
422-
export function sassBindWorkaround<T extends Importer>(importer: T): T {
423-
importer.canonicalize = importer.canonicalize.bind(importer);
424-
importer.load = importer.load.bind(importer);
425-
426-
return importer;
427-
}

packages/angular/build/src/tools/sass/sass-async-compiler-implementation.ts

Lines changed: 0 additions & 182 deletions
This file was deleted.

0 commit comments

Comments
 (0)