|
6 | 6 | * found in the LICENSE file at https://angular.io/license
|
7 | 7 | */
|
8 | 8 |
|
9 |
| -import * as fs from 'fs'; |
10 | 9 | import MiniCssExtractPlugin from 'mini-css-extract-plugin';
|
11 |
| -import * as path from 'path'; |
| 10 | +import * as fs from 'node:fs'; |
| 11 | +import * as path from 'node:path'; |
| 12 | +import { pathToFileURL } from 'node:url'; |
12 | 13 | import type { FileImporter } from 'sass';
|
13 |
| -import { pathToFileURL } from 'url'; |
14 | 14 | import type { Configuration, LoaderContext, RuleSetUseItem } from 'webpack';
|
15 |
| -import { SassWorkerImplementation } from '../../sass/sass-service'; |
| 15 | +import { |
| 16 | + FileImporterWithRequestContextOptions, |
| 17 | + SassWorkerImplementation, |
| 18 | +} from '../../sass/sass-service'; |
16 | 19 | import { SassLegacyWorkerImplementation } from '../../sass/sass-service-legacy';
|
17 | 20 | import { WebpackConfigOptions } from '../../utils/build-options';
|
18 | 21 | import { useLegacySass } from '../../utils/environment-options';
|
@@ -413,30 +416,53 @@ function getSassResolutionImporter(
|
413 | 416 | });
|
414 | 417 |
|
415 | 418 | return {
|
416 |
| - findFileUrl: async (url, { fromImport }): Promise<URL | null> => { |
| 419 | + findFileUrl: async ( |
| 420 | + url, |
| 421 | + { fromImport, previousResolvedModules }: FileImporterWithRequestContextOptions, |
| 422 | + ): Promise<URL | null> => { |
417 | 423 | if (url.charAt(0) === '.') {
|
418 | 424 | // Let Sass handle relative imports.
|
419 | 425 | return null;
|
420 | 426 | }
|
421 | 427 |
|
422 |
| - let file: string | undefined; |
423 | 428 | const resolve = fromImport ? resolveImport : resolveModule;
|
424 |
| - |
425 |
| - try { |
426 |
| - file = await resolve(root, url); |
427 |
| - } catch { |
428 |
| - // Try to resolve a partial file |
429 |
| - // @use '@material/button/button' as mdc-button; |
430 |
| - // `@material/button/button` -> `@material/button/_button` |
431 |
| - const lastSlashIndex = url.lastIndexOf('/'); |
432 |
| - const underscoreIndex = lastSlashIndex + 1; |
433 |
| - if (underscoreIndex > 0 && url.charAt(underscoreIndex) !== '_') { |
434 |
| - const partialFileUrl = `${url.slice(0, underscoreIndex)}_${url.slice(underscoreIndex)}`; |
435 |
| - file = await resolve(root, partialFileUrl).catch(() => undefined); |
| 429 | + // Try to resolve from root of workspace |
| 430 | + let result = await tryResolve(resolve, root, url); |
| 431 | + |
| 432 | + // Try to resolve from previously resolved modules. |
| 433 | + if (!result && previousResolvedModules) { |
| 434 | + for (const path of previousResolvedModules) { |
| 435 | + result = await tryResolve(resolve, path, url); |
| 436 | + if (result) { |
| 437 | + break; |
| 438 | + } |
436 | 439 | }
|
437 | 440 | }
|
438 | 441 |
|
439 |
| - return file ? pathToFileURL(file) : null; |
| 442 | + return result ? pathToFileURL(result) : null; |
440 | 443 | },
|
441 | 444 | };
|
442 | 445 | }
|
| 446 | + |
| 447 | +async function tryResolve( |
| 448 | + resolve: ReturnType<LoaderContext<{}>['getResolve']>, |
| 449 | + root: string, |
| 450 | + url: string, |
| 451 | +): Promise<string | undefined> { |
| 452 | + try { |
| 453 | + return await resolve(root, url); |
| 454 | + } catch { |
| 455 | + // Try to resolve a partial file |
| 456 | + // @use '@material/button/button' as mdc-button; |
| 457 | + // `@material/button/button` -> `@material/button/_button` |
| 458 | + const lastSlashIndex = url.lastIndexOf('/'); |
| 459 | + const underscoreIndex = lastSlashIndex + 1; |
| 460 | + if (underscoreIndex > 0 && url.charAt(underscoreIndex) !== '_') { |
| 461 | + const partialFileUrl = `${url.slice(0, underscoreIndex)}_${url.slice(underscoreIndex)}`; |
| 462 | + |
| 463 | + return resolve(root, partialFileUrl).catch(() => undefined); |
| 464 | + } |
| 465 | + } |
| 466 | + |
| 467 | + return undefined; |
| 468 | +} |
0 commit comments