55 * @typedef {Pick<CompileOptions, 'SourceMapGenerator'> } Defaults
66 * @typedef {Omit<CompileOptions, 'SourceMapGenerator'> } Options
77 * @typedef {import('webpack').LoaderContext<unknown> } LoaderContext
8+ * @typedef {import('webpack').Compiler } WebpackCompiler
89 * @typedef {(vfileCompatible: VFileCompatible) => Promise<VFile> } Process
910 */
1011
12+ import { createHash } from 'node:crypto'
1113import { SourceMapGenerator } from 'source-map'
1214import { createFormatAwareProcessors } from '@mdx-js/mdx/lib/util/create-format-aware-processors.js'
1315
14- /** @type {WeakMap<CompileOptions, Process> } */
16+ const own = { } . hasOwnProperty
17+
18+ // Note: the cache is heavily inspired by:
19+ // <https://github.com/TypeStrong/ts-loader/blob/5c030bf/src/instance-cache.ts>
20+ const marker = /** @type {WebpackCompiler } */ ( { } )
21+ /** @type {WeakMap<WebpackCompiler, Map<string, Process>> } */
1522const cache = new WeakMap ( )
1623
1724/**
@@ -28,6 +35,10 @@ export function loader(value, callback) {
2835 const defaults = this . sourceMap ? { SourceMapGenerator} : { }
2936 const options = /** @type {CompileOptions } */ ( this . getOptions ( ) )
3037 const config = { ...defaults , ...options }
38+ const hash = getOptionsHash ( options )
39+ // Some loaders set `undefined` (see `TypeStrong/ts-loader`).
40+ /* c8 ignore next */
41+ const compiler = this . _compiler || marker
3142
3243 /* Removed option. */
3344 /* c8 ignore next 5 */
@@ -37,15 +48,44 @@ export function loader(value, callback) {
3748 )
3849 }
3950
40- let process = cache . get ( config )
51+ let map = cache . get ( compiler )
52+
53+ if ( ! map ) {
54+ map = new Map ( )
55+ cache . set ( compiler , map )
56+ }
57+
58+ let process = map . get ( hash )
4159
4260 if ( ! process ) {
4361 process = createFormatAwareProcessors ( config ) . process
44- cache . set ( config , process )
62+ map . set ( hash , process )
4563 }
4664
4765 process ( { value, path : this . resourcePath } ) . then ( ( file ) => {
4866 callback ( null , file . value , file . map )
4967 return file
5068 } , callback )
5169}
70+
71+ /**
72+ * @param {Options } options
73+ */
74+ function getOptionsHash ( options ) {
75+ const hash = createHash ( 'sha256' )
76+ /** @type {keyof Options } */
77+ let key
78+
79+ for ( key in options ) {
80+ if ( own . call ( options , key ) ) {
81+ const value = options [ key ]
82+
83+ if ( value !== undefined ) {
84+ const valueString = JSON . stringify ( value )
85+ hash . update ( key + valueString )
86+ }
87+ }
88+ }
89+
90+ return hash . digest ( 'hex' ) . slice ( 0 , 16 )
91+ }
0 commit comments