| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 482f6d8 commit 0a137f9
4 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -15,7 +15,10 @@ import { | |||
| 15 | 15 | RebuildState, | |
| 16 | 16 | } from '../../tools/esbuild/bundler-execution-result'; | |
| 17 | 17 | import { BuildOutputFile, BuildOutputFileType } from '../../tools/esbuild/bundler-files'; | |
| 18 | - import { shutdownSassWorkerPool } from '../../tools/esbuild/stylesheets/sass-language'; | ||
| 18 | + import { | ||
| 19 | + resetSassWorkerPoolCaches, | ||
| 20 | + shutdownSassWorkerPool, | ||
| 21 | + } from '../../tools/esbuild/stylesheets/sass-language'; | ||
| 19 | 22 | import { logMessages, withNoProgress, withSpinner } from '../../tools/esbuild/utils'; | |
| 20 | 23 | import { ChangedFiles } from '../../tools/esbuild/watcher'; | |
| 21 | 24 | import { shouldWatchRoot } from '../../utils/environment-options'; | |
@@ -210,6 +213,8 @@ export async function* runEsBuildBuildAction( | |||
| 210 | 213 | // Clear removed files from current watch files | |
| 211 | 214 | changes.removed.forEach((removedPath) => currentWatchFiles.delete(removedPath)); | |
| 212 | 215 | ||
| 216 | + resetSassWorkerPoolCaches(); | ||
| 217 | + | ||
| 213 | 218 | const rebuildState = result.createRebuildState(changes); | |
| 214 | 219 | result = await withProgress('Changes detected. Rebuilding...', () => action(rebuildState)); | |
| 215 | 220 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -16,12 +16,25 @@ import { StylesheetLanguage, StylesheetPluginOptions } from './stylesheet-plugin | |||
| 16 | 16 | ||
| 17 | 17 | let sassService: SassCompiler | undefined; | |
| 18 | 18 | let sassServicePromise: Promise<SassCompiler> | undefined; | |
| 19 | + let resolutionCache: MemoryCache<URL | null> | undefined; | ||
| 20 | + let packageRootCache: MemoryCache<string | null> | undefined; | ||
| 19 | 21 | ||
| 20 | 22 | function isSassException(error: unknown): error is Exception { | |
| 21 | 23 | return !!error && typeof error === 'object' && 'sassMessage' in error; | |
| 22 | 24 | } | |
| 23 | 25 | ||
| 26 | + export function resetSassWorkerPoolCaches(): void { | ||
| 27 | + resolutionCache?.clear(); | ||
| 28 | + packageRootCache?.clear(); | ||
| 29 | + if (sassService) { | ||
| 30 | + sassService.clearCache(); | ||
| 31 | + } else if (sassServicePromise) { | ||
| 32 | + void sassServicePromise.then((service) => service.clearCache()); | ||
| 33 | + } | ||
| 34 | + } | ||
| 35 | + | ||
| 24 | 36 | export function shutdownSassWorkerPool(): void { | |
| 37 | + resetSassWorkerPoolCaches(); | ||
| 25 | 38 | if (sassService) { | |
| 26 | 39 | void sassService.close(); | |
| 27 | 40 | sassService = undefined; | |
@@ -91,14 +104,15 @@ async function compileString( | |||
| 91 | 104 | } | |
| 92 | 105 | } | |
| 93 | 106 | ||
| 94 | - // Cache is currently local to individual compile requests. | ||
| 95 | - // Caching follows Sass behavior where a given url will always resolve to the same value | ||
| 96 | - // regardless of its importer's path. | ||
| 107 | + // Caching follows Sass behavior where a given package url will always resolve to the same value | ||
| 108 | + // regardless of its importer's path. Relative paths are qualified with the containing URL. | ||
| 97 | 109 | // A null value indicates that the cached resolution attempt failed to find a location and | |
| 98 | 110 | // later stage resolution should be attempted. This avoids potentially expensive repeat | |
| 99 | 111 | // failing resolution attempts. | |
| 100 | - const resolutionCache = new MemoryCache<URL | null>(); | ||
| 101 | - const packageRootCache = new MemoryCache<string | null>(); | ||
| 112 | + resolutionCache ??= new MemoryCache<URL | null>(); | ||
| 113 | + packageRootCache ??= new MemoryCache<string | null>(); | ||
| 114 | + const currentResolutionCache = resolutionCache; | ||
| 115 | + const currentPackageRootCache = packageRootCache; | ||
| 102 | 116 | const warnings: PartialMessage[] = []; | |
| 103 | 117 | const { silenceDeprecations, futureDeprecations, fatalDeprecations } = options.sass ?? {}; | |
| 104 | 118 | ||
@@ -116,8 +130,12 @@ async function compileString( | |||
| 116 | 130 | quietDeps: true, | |
| 117 | 131 | importers: [ | |
| 118 | 132 | { | |
| 119 | - findFileUrl: (url, options) => | ||
| 120 | - resolutionCache.getOrCreate(url, async () => { | ||
| 133 | + findFileUrl: (url, options) => { | ||
| 134 | + const cacheKey = url.startsWith('pkg:') | ||
| 135 | + ? url | ||
| 136 | + : `${options.containingUrl?.href ?? ''}:${url}`; | ||
| 137 | + | ||
| 138 | + return currentResolutionCache.getOrCreate(cacheKey, async () => { | ||
| 121 | 139 | const result = await resolveUrl(url, options); | |
| 122 | 140 | if (result.path) { | |
| 123 | 141 | return pathToFileURL(result.path); | |
@@ -128,12 +146,16 @@ async function compileString( | |||
| 128 | 146 | ||
| 129 | 147 | // Caching package root locations is particularly beneficial for `@material/*` packages | |
| 130 | 148 | // which extensively use deep imports. | |
| 131 | - const packageRoot = await packageRootCache.getOrCreate(packageName, async () => { | ||
| 132 | - // Use the required presence of a package root `package.json` file to resolve the location | ||
| 133 | - const packageResult = await resolveUrl(packageName + '/package.json', options); | ||
| 149 | + const packageRootKey = `${options.containingUrl?.href ?? ''}:${packageName}`; | ||
| 150 | + const packageRoot = await currentPackageRootCache.getOrCreate( | ||
| 151 | + packageRootKey, | ||
| 152 | + async () => { | ||
| 153 | + // Use the required presence of a package root `package.json` file to resolve the location | ||
| 154 | + const packageResult = await resolveUrl(packageName + '/package.json', options); | ||
| 134 | 155 | ||
| 135 | - return packageResult.path ? dirname(packageResult.path) : null; | ||
| 136 | - }); | ||
| 156 | + return packageResult.path ? dirname(packageResult.path) : null; | ||
| 157 | + }, | ||
| 158 | + ); | ||
| 137 | 159 | ||
| 138 | 160 | // Package not found could be because of an error or the specifier is intended to be found | |
| 139 | 161 | // via a later stage of the resolution process (`loadPaths`, etc.). | |
@@ -145,7 +167,8 @@ async function compileString( | |||
| 145 | 167 | ||
| 146 | 168 | // Not found | |
| 147 | 169 | return null; | |
| 148 | - }), | ||
| 170 | + }); | ||
| 171 | + }, | ||
| 149 | 172 | }, | |
| 150 | 173 | ], | |
| 151 | 174 | logger: { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -45,6 +45,7 @@ function isFileImporter(value: Importers): value is FileImporter { | |||
| 45 | 45 | export class SassCompiler { | |
| 46 | 46 | #asyncCompiler: AsyncCompiler | undefined; | |
| 47 | 47 | #asyncCompilerPromise: Promise<AsyncCompiler> | undefined; | |
| 48 | + readonly #directoryCache = new Map<string, DirectoryEntry>(); | ||
| 48 | 49 | ||
| 49 | 50 | constructor(private readonly rebase = false) {} | |
| 50 | 51 | ||
@@ -119,7 +120,7 @@ export class SassCompiler { | |||
| 119 | 120 | (Importer<'async'> | FileImporter<'async'> | NodePackageImporter)[] | undefined; | |
| 120 | 121 | let loadPaths = options.loadPaths; | |
| 121 | 122 | const entryDirectory = url ? dirname(fileURLToPath(url)) : process.cwd(); | |
| 122 | - const directoryCache = new Map<string, DirectoryEntry>(); | ||
| 123 | + const directoryCache = this.#directoryCache; | ||
| 123 | 124 | const rebaseSourceMaps = options.sourceMap ? new Map<string, DecodedSourceMap>() : undefined; | |
| 124 | 125 | ||
| 125 | 126 | if (importers?.length) { | |
@@ -187,11 +188,20 @@ export class SassCompiler { | |||
| 187 | 188 | return result; | |
| 188 | 189 | } | |
| 189 | 190 | ||
| 191 | + /** | ||
| 192 | + * Clear the directory cache. | ||
| 193 | + */ | ||
| 194 | + clearCache(): void { | ||
| 195 | + this.#directoryCache.clear(); | ||
| 196 | + } | ||
| 197 | + | ||
| 190 | 198 | /** | |
| 191 | 199 | * Shutdown the Sass compiler. | |
| 192 | 200 | * @returns A void promise that resolves when closing is complete. | |
| 193 | 201 | */ | |
| 194 | 202 | async close(): Promise<void> { | |
| 203 | + this.clearCache(); | ||
| 204 | + | ||
| 195 | 205 | if (this.#asyncCompilerPromise) { | |
| 196 | 206 | try { | |
| 197 | 207 | await this.#ensureAsyncCompiler(); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -70,6 +70,9 @@ export async function getStylesConfig(wco: WebpackConfigOptions): Promise<Config | |||
| 70 | 70 | ||
| 71 | 71 | extraPlugins.push({ | |
| 72 | 72 | apply(compiler) { | |
| 73 | + compiler.hooks.thisCompilation.tap('sass-service', () => { | ||
| 74 | + sassImplementation.clearCache(); | ||
| 75 | + }); | ||
| 73 | 76 | compiler.hooks.shutdown.tap('sass-service', () => { | |
| 74 | 77 | void sassImplementation.close(); | |
| 75 | 78 | }); | |
| Back | FazBrowse Home | New Git URL |
0 commit comments