|
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