Skip to content

Commit 3f73e98

Browse files
author
Valerio Pipolo
authored
Fix failed builds when using thread-loader (#1207)
* Use a dummy compiler reference when the calling webpack compiler is undefined or null * Use a module instead of a class for caching instances * Bump version and update changelog
1 parent e90f8ad commit 3f73e98

File tree

4 files changed

+51
-25
lines changed

4 files changed

+51
-25
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# Changelog
22

3+
## v8.0.9
4+
* [Fixed build failing when using thread-loader](https://github.com/TypeStrong/ts-loader/pull/1207) - thanks @valerio
5+
36
## v8.0.8
47
* [Fixed memory leak when using multiple webpack instances](https://github.com/TypeStrong/ts-loader/pull/1205) - thanks @valerio
58

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ts-loader",
3-
"version": "8.0.8",
3+
"version": "8.0.9",
44
"description": "TypeScript loader for webpack",
55
"main": "index.js",
66
"types": "dist",

src/instance-cache.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import * as webpack from 'webpack';
2+
import { TSInstance } from './interfaces';
3+
4+
// Some loaders (e.g. thread-loader) will set the _compiler property to undefined.
5+
// We can't use undefined as a WeakMap key as it will throw an error at runtime,
6+
// thus we keep a dummy "marker" object to use as key in those situations.
7+
const marker: webpack.Compiler = {} as webpack.Compiler;
8+
9+
// Each TypeScript instance is cached based on the webpack instance (key of the WeakMap)
10+
// and also the name that was generated or passed via the options (string key of the
11+
// internal Map)
12+
const cache: WeakMap<webpack.Compiler, Map<string, TSInstance>> = new WeakMap();
13+
14+
export function getTSInstanceFromCache(
15+
key: webpack.Compiler,
16+
name: string
17+
): TSInstance | undefined {
18+
const compiler = key ?? marker;
19+
20+
let instances = cache.get(compiler);
21+
if (!instances) {
22+
instances = new Map();
23+
cache.set(compiler, instances);
24+
}
25+
26+
return instances.get(name);
27+
}
28+
29+
export function setTSInstanceInCache(
30+
key: webpack.Compiler,
31+
name: string,
32+
instance: TSInstance
33+
) {
34+
const compiler = key ?? marker;
35+
36+
const instances = cache.get(compiler) ?? new Map<string, TSInstance>();
37+
instances.set(name, instance);
38+
cache.set(compiler, instances);
39+
}

src/instances.ts

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { makeAfterCompile } from './after-compile';
88
import { getCompiler, getCompilerOptions } from './compilerSetup';
99
import { getConfigFile, getConfigParseResult } from './config';
1010
import { dtsDtsxOrDtsDtsxMapRegex, EOL, tsTsxRegex } from './constants';
11+
import { getTSInstanceFromCache, setTSInstanceInCache } from './instance-cache';
1112
import {
1213
FilePathKey,
1314
LoaderOptions,
@@ -33,22 +34,8 @@ import {
3334
} from './utils';
3435
import { makeWatchRun } from './watch-run';
3536

36-
// Each TypeScript instance is based on the webpack instance (key of the WeakMap)
37-
// and also the name that was generated or passed via the options (string key of the
38-
// internal Map)
39-
const instanceCache = new WeakMap<webpack.Compiler, Map<string, TSInstance>>();
4037
const instancesBySolutionBuilderConfigs = new Map<FilePathKey, TSInstance>();
4138

42-
function addTSInstanceToCache(
43-
key: webpack.Compiler,
44-
instanceName: string,
45-
instance: TSInstance
46-
) {
47-
const instances = instanceCache.get(key) ?? new Map<string, TSInstance>();
48-
instances.set(instanceName, instance);
49-
instanceCache.set(key, instances);
50-
}
51-
5239
/**
5340
* The loader is executed once for each file seen by webpack. However, we need to keep
5441
* a persistent instance of TypeScript that contains all of the files in the program
@@ -60,13 +47,10 @@ export function getTypeScriptInstance(
6047
loaderOptions: LoaderOptions,
6148
loader: webpack.loader.LoaderContext
6249
): { instance?: TSInstance; error?: WebpackError } {
63-
let instances = instanceCache.get(loader._compiler);
64-
if (!instances) {
65-
instances = new Map();
66-
instanceCache.set(loader._compiler, instances);
67-
}
68-
69-
const existing = instances.get(loaderOptions.instance);
50+
const existing = getTSInstanceFromCache(
51+
loader._compiler,
52+
loaderOptions.instance
53+
);
7054
if (existing) {
7155
if (!existing.initialSetupPending) {
7256
ensureProgram(existing);
@@ -160,7 +144,7 @@ function successfulTypeScriptInstance(
160144
const existing = getExistingSolutionBuilderHost(configFileKey);
161145
if (existing) {
162146
// Reuse the instance if config file for project references is shared.
163-
addTSInstanceToCache(loader._compiler, loaderOptions.instance, existing);
147+
setTSInstanceInCache(loader._compiler, loaderOptions.instance, existing);
164148
return { instance: existing };
165149
}
166150
}
@@ -246,7 +230,7 @@ function successfulTypeScriptInstance(
246230
filePathKeyMapper,
247231
};
248232

249-
addTSInstanceToCache(
233+
setTSInstanceInCache(
250234
loader._compiler,
251235
loaderOptions.instance,
252236
transpileInstance
@@ -303,7 +287,7 @@ function successfulTypeScriptInstance(
303287
filePathKeyMapper,
304288
};
305289

306-
addTSInstanceToCache(loader._compiler, loaderOptions.instance, instance);
290+
setTSInstanceInCache(loader._compiler, loaderOptions.instance, instance);
307291
return { instance };
308292
}
309293

0 commit comments

Comments
 (0)