diff --git a/CHANGELOG.md b/CHANGELOG.md index b396a94e7..763cc44d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## v8.0.9 +* [Fixed build failing when using thread-loader](https://github.com/TypeStrong/ts-loader/pull/1207) - thanks @valerio + ## v8.0.8 * [Fixed memory leak when using multiple webpack instances](https://github.com/TypeStrong/ts-loader/pull/1205) - thanks @valerio diff --git a/package.json b/package.json index e5e48f498..9c12bc5cd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts-loader", - "version": "8.0.8", + "version": "8.0.9", "description": "TypeScript loader for webpack", "main": "index.js", "types": "dist", diff --git a/src/instance-cache.ts b/src/instance-cache.ts new file mode 100644 index 000000000..4ed44e9a5 --- /dev/null +++ b/src/instance-cache.ts @@ -0,0 +1,39 @@ +import * as webpack from 'webpack'; +import { TSInstance } from './interfaces'; + +// Some loaders (e.g. thread-loader) will set the _compiler property to undefined. +// We can't use undefined as a WeakMap key as it will throw an error at runtime, +// thus we keep a dummy "marker" object to use as key in those situations. +const marker: webpack.Compiler = {} as webpack.Compiler; + +// Each TypeScript instance is cached based on the webpack instance (key of the WeakMap) +// and also the name that was generated or passed via the options (string key of the +// internal Map) +const cache: WeakMap> = new WeakMap(); + +export function getTSInstanceFromCache( + key: webpack.Compiler, + name: string +): TSInstance | undefined { + const compiler = key ?? marker; + + let instances = cache.get(compiler); + if (!instances) { + instances = new Map(); + cache.set(compiler, instances); + } + + return instances.get(name); +} + +export function setTSInstanceInCache( + key: webpack.Compiler, + name: string, + instance: TSInstance +) { + const compiler = key ?? marker; + + const instances = cache.get(compiler) ?? new Map(); + instances.set(name, instance); + cache.set(compiler, instances); +} diff --git a/src/instances.ts b/src/instances.ts index 69008844e..f7496132a 100644 --- a/src/instances.ts +++ b/src/instances.ts @@ -8,6 +8,7 @@ import { makeAfterCompile } from './after-compile'; import { getCompiler, getCompilerOptions } from './compilerSetup'; import { getConfigFile, getConfigParseResult } from './config'; import { dtsDtsxOrDtsDtsxMapRegex, EOL, tsTsxRegex } from './constants'; +import { getTSInstanceFromCache, setTSInstanceInCache } from './instance-cache'; import { FilePathKey, LoaderOptions, @@ -33,22 +34,8 @@ import { } from './utils'; import { makeWatchRun } from './watch-run'; -// Each TypeScript instance is based on the webpack instance (key of the WeakMap) -// and also the name that was generated or passed via the options (string key of the -// internal Map) -const instanceCache = new WeakMap>(); const instancesBySolutionBuilderConfigs = new Map(); -function addTSInstanceToCache( - key: webpack.Compiler, - instanceName: string, - instance: TSInstance -) { - const instances = instanceCache.get(key) ?? new Map(); - instances.set(instanceName, instance); - instanceCache.set(key, instances); -} - /** * The loader is executed once for each file seen by webpack. However, we need to keep * a persistent instance of TypeScript that contains all of the files in the program @@ -60,13 +47,10 @@ export function getTypeScriptInstance( loaderOptions: LoaderOptions, loader: webpack.loader.LoaderContext ): { instance?: TSInstance; error?: WebpackError } { - let instances = instanceCache.get(loader._compiler); - if (!instances) { - instances = new Map(); - instanceCache.set(loader._compiler, instances); - } - - const existing = instances.get(loaderOptions.instance); + const existing = getTSInstanceFromCache( + loader._compiler, + loaderOptions.instance + ); if (existing) { if (!existing.initialSetupPending) { ensureProgram(existing); @@ -160,7 +144,7 @@ function successfulTypeScriptInstance( const existing = getExistingSolutionBuilderHost(configFileKey); if (existing) { // Reuse the instance if config file for project references is shared. - addTSInstanceToCache(loader._compiler, loaderOptions.instance, existing); + setTSInstanceInCache(loader._compiler, loaderOptions.instance, existing); return { instance: existing }; } } @@ -246,7 +230,7 @@ function successfulTypeScriptInstance( filePathKeyMapper, }; - addTSInstanceToCache( + setTSInstanceInCache( loader._compiler, loaderOptions.instance, transpileInstance @@ -303,7 +287,7 @@ function successfulTypeScriptInstance( filePathKeyMapper, }; - addTSInstanceToCache(loader._compiler, loaderOptions.instance, instance); + setTSInstanceInCache(loader._compiler, loaderOptions.instance, instance); return { instance }; }