Skip to content

Commit 1b84fed

Browse files
authored
Ensure a separate webpack instance is created for different loader options (#1104)
* Ensure a separate webpack instance is created if different loader options are used Add execution test for this behaviour * Fix import order (lint error) * Update version to 7.04 and include in changelog * Tweak to Changelog
1 parent 227d99a commit 1b84fed

18 files changed

+183
-3
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+
## v7.0.4
4+
* [Ensure a separate webpack instance is created for different loader options](https://github.com/TypeStrong/ts-loader/pull/1104) - thanks @appzuka
5+
36
## v7.0.3
47
* [Ensure that JSON files are included in build module resolution](https://github.com/TypeStrong/ts-loader/pull/1101) - thanks @berickson1
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": "7.0.3",
3+
"version": "7.0.4",
44
"description": "TypeScript loader for webpack",
55
"main": "index.js",
66
"types": "dist",

src/index.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import * as crypto from 'crypto';
12
import * as loaderUtils from 'loader-utils';
23
import * as path from 'path';
34
import * as typescript from 'typescript';
@@ -220,6 +221,22 @@ function setModuleMeta(
220221
}
221222
}
222223

224+
/**
225+
* Get a unique hash based on the contents of the options
226+
* Hash is created from the values converted to strings
227+
* Values which are functions (such as getCustomTransformers) are
228+
* converted to strings by this code, which JSON.stringify would not do.
229+
*/
230+
function getOptionsHash(loaderOptions: LoaderOptions) {
231+
const hash = crypto.createHash('sha256');
232+
Object.values(loaderOptions).map((v: any) => {
233+
if (v) {
234+
hash.update(v.toString());
235+
}
236+
});
237+
return hash.digest('hex').substring(0, 16);
238+
}
239+
223240
/**
224241
* either retrieves loader options from the cache
225242
* or creates them, adds them to the cache and returns
@@ -235,8 +252,12 @@ function getLoaderOptions(loaderContext: webpack.loader.LoaderContext) {
235252
loaderUtils.getOptions<LoaderOptions>(loaderContext) ||
236253
({} as LoaderOptions);
237254

255+
// If no instance name is given in the options, use the hash of the loader options
256+
// In this way, if different options are given the instances will be different
238257
const instanceName =
239-
webpackIndex + '_' + (loaderOptions.instance || 'default');
258+
webpackIndex +
259+
'_' +
260+
(loaderOptions.instance || 'default_' + getOptionsHash(loaderOptions));
240261

241262
if (!loaderOptionsCache.hasOwnProperty(instanceName)) {
242263
loaderOptionsCache[instanceName] = new WeakMap();
@@ -528,7 +549,7 @@ function getEmit(
528549

529550
loaderContext._module.buildMeta.tsLoaderDefinitionFileVersions = dependencies.map(
530551
defFilePath =>
531-
path.relative(loaderContext.rootContext,defFilePath) +
552+
path.relative(loaderContext.rootContext, defFilePath) +
532553
'@' +
533554
(
534555
instance.files.get(defFilePath) ||
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
## Loader Options Test
2+
3+
This test includes 3 submodules, only 1 of which should have the transformer applied via the options. This tests that separate webpack instances are created when module options are different.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/* eslint-disable no-var, strict */
2+
'use strict';
3+
var webpackConfig = require('./webpack.config.js');
4+
var makeKarmaConfig = require('../../karmaConfig');
5+
6+
module.exports = function(config) {
7+
config.set(
8+
makeKarmaConfig({
9+
config,
10+
webpackConfig,
11+
files: [
12+
// This ensures we have the es6 shims in place from babel and then loads all the tests
13+
'main.js'
14+
]
15+
})
16+
);
17+
};
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
declare module externalLib {
2+
export function doSomething(arg: any): void;
3+
}
4+
5+
declare module 'externalLib' {
6+
export = externalLib
7+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = {
2+
doSomething: function() { }
3+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
const testsContext = require.context('./', true, /\.tests\.ts(x?)$/);
2+
testsContext.keys().forEach(testsContext);
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"name": "basic",
3+
"license": "MIT",
4+
"version": "1.0.0",
5+
"main": "index.js",
6+
"devDependencies": {
7+
"@types/jasmine": "^2.5.35",
8+
"jasmine-core": "^2.3.4"
9+
}
10+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import submodule = require('./submodule/submodule');
2+
import externalLib = require('externalLib');
3+
externalLib.doSomething(submodule);
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import externalLib = require('externalLib');
2+
3+
externalLib.doSomething("");
4+
var message = "Hello from submodule"
5+
export = message
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import externalLib = require('externalLib');
2+
3+
externalLib.doSomething("");
4+
var message = "Hello from submodule2"
5+
export = message
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import externalLib = require('externalLib');
2+
3+
externalLib.doSomething("");
4+
var message = "Hello from submodule3"
5+
export = message
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import submodule = require('../src/submodule/submodule');
2+
import submodule2 = require('../src/submodule/submodule2');
3+
import submodule3 = require('../src/submodule/submodule3');
4+
import externalLib = require('externalLib');
5+
6+
describe("app", () => {
7+
it("externalLib can be called", () => {
8+
expect(externalLib.doSomething(submodule)).toBeUndefined();
9+
});
10+
11+
it("submodule return value should not be transformed", () => {
12+
expect(submodule).toBe("Hello "+"from submodule");
13+
});
14+
15+
it("submodule2 return value should be transformed", () => {
16+
expect(submodule2).toBe("HELLO "+"FROM SUBMODULE2");
17+
});
18+
19+
it("submodule3 return value should not be transformed", () => {
20+
expect(submodule3).toBe("Hello "+"from submodule3");
21+
});
22+
});
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"compilerOptions": {
3+
"noEmitOnError": true
4+
}
5+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
"use strict";
2+
exports.__esModule = true;
3+
var ts = require("typescript");
4+
var transformer = function (context) {
5+
var visitor = function (node) {
6+
if (node.kind === ts.SyntaxKind.StringLiteral) {
7+
var text = node.text;
8+
if (text.match(/^Hello from submodule/) !== null) {
9+
if (text !== text.toUpperCase()) {
10+
return ts.createLiteral(text.toUpperCase());
11+
}
12+
}
13+
}
14+
return ts.visitEachChild(node, visitor, context);
15+
};
16+
return function (node) { return ts.visitNode(node, visitor); };
17+
};
18+
exports["default"] = transformer;
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
var path = require('path')
2+
3+
var uppercaseStringLiteralTransformer = require('./uppercaseStringLiteralTransformer').default;
4+
5+
module.exports = {
6+
mode: 'development',
7+
entry: './src/app.ts',
8+
output: {
9+
filename: 'bundle.js'
10+
},
11+
resolve: {
12+
alias: { externalLib: path.join(__dirname, "./lib/externalLib.js") },
13+
extensions: ['.ts', '.js']
14+
},
15+
module: {
16+
rules: [
17+
{
18+
test: /submodule3\.ts$/,
19+
loader: 'ts-loader',
20+
},
21+
{
22+
test: /submodule2\.ts$/,
23+
loader: 'ts-loader',
24+
options: {
25+
getCustomTransformers: (program) => ({
26+
before: [uppercaseStringLiteralTransformer]
27+
})
28+
},
29+
},
30+
{
31+
test: /\.ts$/,
32+
exclude: /submodule\d\.ts$/,
33+
loader: 'ts-loader',
34+
}
35+
]
36+
}
37+
}
38+
39+
// for test harness purposes only, you would not need this in a normal project
40+
module.exports.resolveLoader = { alias: { 'ts-loader': require('path').join(__dirname, "../../../index.js") } }
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2+
# yarn lockfile v1
3+
4+
5+
"@types/jasmine@^2.5.35":
6+
version "2.8.5"
7+
resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-2.8.5.tgz#96e58872583fa80c7ea0dd29024b180d5e133678"
8+
9+
jasmine-core@^2.3.4:
10+
version "2.9.1"
11+
resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.9.1.tgz#b6bbc1d8e65250d56f5888461705ebeeeb88f22f"

0 commit comments

Comments
 (0)