Skip to content

Commit 80e0349

Browse files
vhqtvnjohnnyreilly
authored andcommitted
add appendTsxSuffixTo option (#581)
* add tsx option * update readme * update * update test * update test for ts 2.4 * add jsx example * update README * update example * combine suffix append functions * combine function usage * update index.ts * update readme * appendSuffixesIfMatch is only invoked if appendTsSuffixTo and / or appendTsxSuffixTo has been passed
1 parent e07cb4e commit 80e0349

File tree

11 files changed

+104
-20
lines changed

11 files changed

+104
-20
lines changed

README.md

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,8 @@ of your code.
248248
To be used in concert with the `allowJs` compiler option. If your entry file is JS then you'll need to set this option to true. Please note that this is rather unusual and will generally not be necessary when using `allowJs`.
249249

250250
#### appendTsSuffixTo *(RegExp[]) (default=[])*
251-
A list of regular expressions to be matched against filename. If filename matches one of the regular expressions, a `.ts` suffix will be appended to that filename.
251+
#### appendTsxSuffixTo *(RegExp[]) (default=[])*
252+
A list of regular expressions to be matched against filename. If filename matches one of the regular expressions, a `.ts` or `.tsx` suffix will be appended to that filename.
252253

253254
This is useful for `*.vue` [file format](https://vuejs.org/v2/guide/single-file-components.html) for now. (Probably will benefit from the new single file format in the future.)
254255

@@ -287,6 +288,64 @@ export default {
287288
</script>
288289
```
289290

291+
We can handle `.tsx` by quite similar way:
292+
293+
webpack.config.js:
294+
295+
```javascript
296+
module.exports = {
297+
entry: './index.vue',
298+
output: { filename: 'bundle.js' },
299+
resolve: {
300+
extensions: ['.ts', '.tsx', '.vue', '.vuex']
301+
},
302+
module: {
303+
rules: [
304+
{ test: /\.vue$/, loader: 'vue-loader',
305+
options: {
306+
loaders: {
307+
ts: 'ts-loader',
308+
tsx: 'babel-loader!ts-loader',
309+
}
310+
}
311+
},
312+
{ test: /\.ts$/, loader: 'ts-loader', options: { appendTsSuffixTo: [/TS\.vue$/] } }
313+
{ test: /\.tsx$/, loader: 'babel-loader!ts-loader', options: { appendTsxSuffixTo: [/TSX\.vue$/] } }
314+
]
315+
}
316+
}
317+
```
318+
319+
tsconfig.json (set `jsx` option to `preserve` to let babel handle jsx)
320+
321+
```json
322+
{
323+
"compilerOptions": {
324+
"jsx": "preserve"
325+
}
326+
}
327+
```
328+
329+
index.vue
330+
331+
```vue
332+
<script lang="tsx">
333+
export default {
334+
functional: true,
335+
render(h, c) {
336+
return (<div>Content</div>);
337+
}
338+
}
339+
</script>
340+
```
341+
342+
Or if you want to use only tsx, just use the `appendTsxSuffixTo` option only:
343+
344+
```javascript
345+
{ test: /\.ts$/, loader: 'ts-loader' }
346+
{ test: /\.tsx$/, loader: 'babel-loader!ts-loader', options: { appendTsxSuffixTo: [/\.vue$/] } }
347+
```
348+
290349
### `LoaderOptionsPlugin`
291350

292351
[There's a known "gotcha"](https://github.com/TypeStrong/ts-loader/issues/283) if you are using webpack 2 with the `LoaderOptionsPlugin`. If you are faced with the `Cannot read property 'unsafeCache' of undefined` error then you probably need to supply a `resolve` object as below: (Thanks @jeffijoe!)

src/index.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,14 @@ function loader(this: interfaces.Webpack, contents: string) {
2626
}
2727

2828
const rawFilePath = path.normalize(this.resourcePath);
29-
const filePath = utils.appendTsSuffixIfMatch(options.appendTsSuffixTo, rawFilePath);
29+
30+
const filePath = options.appendTsSuffixTo.length > 0 || options.appendTsxSuffixTo.length > 0
31+
? utils.appendSuffixesIfMatch({
32+
'.ts': options.appendTsSuffixTo,
33+
'.tsx': options.appendTsxSuffixTo,
34+
}, rawFilePath)
35+
: rawFilePath;
36+
3037
const fileVersion = updateFileInCache(filePath, contents, instance);
3138

3239
const { outputText, sourceMapText } = options.transpileOnly
@@ -44,10 +51,10 @@ function loader(this: interfaces.Webpack, contents: string) {
4451

4552
// _module.meta is not available inside happypack
4653
if (!options.happyPackMode) {
47-
// Make sure webpack is aware that even though the emitted JavaScript may be the same as
48-
// a previously cached version the TypeScript may be different and therefore should be
49-
// treated as new
50-
this._module.meta.tsLoaderFileVersion = fileVersion;
54+
// Make sure webpack is aware that even though the emitted JavaScript may be the same as
55+
// a previously cached version the TypeScript may be different and therefore should be
56+
// treated as new
57+
this._module.meta.tsLoaderFileVersion = fileVersion;
5158
}
5259

5360
callback(null, output, sourceMap);
@@ -83,6 +90,7 @@ function getLoaderOptions(loader: interfaces.Webpack) {
8390
visualStudioErrorFormat: false,
8491
compilerOptions: {},
8592
appendTsSuffixTo: [],
93+
appendTsxSuffixTo: [],
8694
transformers: {},
8795
entryFileIsJs: false,
8896
happyPackMode: false,

src/instances.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ export function getTypeScriptInstance(
110110
modifiedFiles: null,
111111
};
112112

113-
const servicesHost = makeServicesHost(scriptRegex, log, loader, instance, loaderOptions.appendTsSuffixTo);
113+
const servicesHost = makeServicesHost(scriptRegex, log, loader, instance, loaderOptions.appendTsSuffixTo, loaderOptions.appendTsxSuffixTo);
114114
instance.languageService = compiler.createLanguageService(servicesHost, compiler.createDocumentRegistry());
115115

116116
loader._compiler.plugin("after-compile", afterCompile(instance, configFilePath));

src/interfaces.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ export interface LoaderOptions {
254254
visualStudioErrorFormat: boolean;
255255
compilerOptions: typescript.CompilerOptions;
256256
appendTsSuffixTo: RegExp[];
257+
appendTsxSuffixTo: RegExp[];
257258
entryFileIsJs: boolean;
258259
happyPackMode: boolean;
259260
getCustomTransformers?(): typescript.CustomTransformers | undefined;

src/servicesHost.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,15 @@ function makeServicesHost(
1414
log: logger.Logger,
1515
loader: interfaces.Webpack,
1616
instance: interfaces.TSInstance,
17-
appendTsSuffixTo: RegExp[]
17+
appendTsSuffixTo: RegExp[],
18+
appendTsxSuffixTo: RegExp[]
1819
) {
1920
const { compiler, compilerOptions, files } = instance;
2021

2122
const newLine =
2223
compilerOptions.newLine === constants.CarriageReturnLineFeedCode ? constants.CarriageReturnLineFeed :
23-
compilerOptions.newLine === constants.LineFeedCode ? constants.LineFeed :
24-
constants.EOL;
24+
compilerOptions.newLine === constants.LineFeedCode ? constants.LineFeed :
25+
constants.EOL;
2526

2627
// make a (sync) resolver that follows webpack's rules
2728
const resolveSync = makeResolver(loader.options);
@@ -77,7 +78,7 @@ function makeServicesHost(
7778
log: log.log,
7879
resolveModuleNames: (moduleNames: string[], containingFile: string) =>
7980
resolveModuleNames(
80-
resolveSync, moduleResolutionHost, appendTsSuffixTo, scriptRegex, instance,
81+
resolveSync, moduleResolutionHost, appendTsSuffixTo, appendTsxSuffixTo, scriptRegex, instance,
8182
moduleNames, containingFile),
8283
getCustomTransformers: () => instance.transformers
8384
};
@@ -87,13 +88,14 @@ function resolveModuleNames(
8788
resolveSync: interfaces.ResolveSync,
8889
moduleResolutionHost: interfaces.ModuleResolutionHost,
8990
appendTsSuffixTo: RegExp[],
91+
appendTsxSuffixTo: RegExp[],
9092
scriptRegex: RegExp,
9193
instance: interfaces.TSInstance,
9294
moduleNames: string[],
9395
containingFile: string
9496
) {
9597
const resolvedModules = moduleNames.map(moduleName =>
96-
resolveModuleName(resolveSync, moduleResolutionHost, appendTsSuffixTo, scriptRegex, instance,
98+
resolveModuleName(resolveSync, moduleResolutionHost, appendTsSuffixTo, appendTsxSuffixTo, scriptRegex, instance,
9799
moduleName, containingFile)
98100
);
99101

@@ -106,6 +108,7 @@ function resolveModuleName(
106108
resolveSync: interfaces.ResolveSync,
107109
moduleResolutionHost: interfaces.ModuleResolutionHost,
108110
appendTsSuffixTo: RegExp[],
111+
appendTsxSuffixTo: RegExp[],
109112
scriptRegex: RegExp,
110113
instance: interfaces.TSInstance,
111114

@@ -118,7 +121,13 @@ function resolveModuleName(
118121

119122
try {
120123
const originalFileName = resolveSync(undefined, path.normalize(path.dirname(containingFile)), moduleName);
121-
const resolvedFileName = utils.appendTsSuffixIfMatch(appendTsSuffixTo, originalFileName);
124+
125+
const resolvedFileName = appendTsSuffixTo.length > 0 || appendTsxSuffixTo.length > 0
126+
? utils.appendSuffixesIfMatch({
127+
'.ts': appendTsSuffixTo,
128+
'.tsx': appendTsxSuffixTo,
129+
}, originalFileName)
130+
: originalFileName;
122131

123132
if (resolvedFileName.match(scriptRegex)) {
124133
resolutionResult = { resolvedFileName, originalFileName };

src/utils.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,17 +77,24 @@ export function makeError({ rawMessage, message, location, file }: MakeError): i
7777
return <interfaces.WebpackError>Object.assign(error, { location, file });
7878
}
7979

80-
export function appendTsSuffixIfMatch(patterns: RegExp[], path: string): string {
80+
export function appendSuffixIfMatch(patterns: RegExp[], path: string, suffix: string): string {
8181
if (patterns.length > 0) {
8282
for (let regexp of patterns) {
8383
if (path.match(regexp)) {
84-
return path + '.ts';
84+
return path + suffix;
8585
}
8686
}
8787
}
8888
return path;
8989
}
9090

91+
export function appendSuffixesIfMatch(suffixDict: {[suffix: string]: RegExp[]}, path: string): string {
92+
for(let suffix in suffixDict) {
93+
path = appendSuffixIfMatch(suffixDict[suffix], path, suffix);
94+
}
95+
return path;
96+
}
97+
9198
/**
9299
* Recursively collect all possible dependants of passed file
93100
*/

test/comparison-tests/nodeModulesMeaningfulErrorWhenImportingTs/expectedOutput-2.0/output.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ Module build failed: Error: Typescript emitted no output for node_modules/a/inde
88
You should not need to recompile .ts files in node_modules.
99
Please contact the package author to advise them to use --declaration --outDir.
1010
More https://github.com/Microsoft/TypeScript/issues/12358
11-
at Object.loader (dist/index.js:31:15)
11+
at Object.loader (dist/index.js:33:15)
1212
@ ./.test/nodeModulesMeaningfulErrorWhenImportingTs/app.ts 2:8-20

test/comparison-tests/nodeModulesMeaningfulErrorWhenImportingTs/expectedOutput-2.1/output.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ Module build failed: Error: Typescript emitted no output for node_modules/a/inde
99
You should not need to recompile .ts files in node_modules.
1010
Please contact the package author to advise them to use --declaration --outDir.
1111
More https://github.com/Microsoft/TypeScript/issues/12358
12-
at Object.loader (dist/index.js:31:15)
12+
at Object.loader (dist/index.js:33:15)
1313
@ ./.test/nodeModulesMeaningfulErrorWhenImportingTs/app.ts 2:8-20

test/comparison-tests/nodeModulesMeaningfulErrorWhenImportingTs/expectedOutput-2.2/output.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ Module build failed: Error: Typescript emitted no output for node_modules\a\inde
99
You should not need to recompile .ts files in node_modules.
1010
Please contact the package author to advise them to use --declaration --outDir.
1111
More https://github.com/Microsoft/TypeScript/issues/12358
12-
at Object.loader (dist\index.js:32:15)
12+
at Object.loader (dist\index.js:33:15)
1313
@ ./.test/nodeModulesMeaningfulErrorWhenImportingTs/app.ts 3:8-20

test/comparison-tests/nodeModulesMeaningfulErrorWhenImportingTs/expectedOutput-2.3/output.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ Module build failed: Error: Typescript emitted no output for node_modules\a\inde
99
You should not need to recompile .ts files in node_modules.
1010
Please contact the package author to advise them to use --declaration --outDir.
1111
More https://github.com/Microsoft/TypeScript/issues/12358
12-
at Object.loader (dist\index.js:32:15)
12+
at Object.loader (dist\index.js:33:15)
1313
@ ./.test/nodeModulesMeaningfulErrorWhenImportingTs/app.ts 3:8-20

test/comparison-tests/nodeModulesMeaningfulErrorWhenImportingTs/expectedOutput-2.4/output.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ Module build failed: Error: Typescript emitted no output for node_modules\a\inde
99
You should not need to recompile .ts files in node_modules.
1010
Please contact the package author to advise them to use --declaration --outDir.
1111
More https://github.com/Microsoft/TypeScript/issues/12358
12-
at Object.loader (dist\index.js:31:15)
12+
at Object.loader (dist\index.js:32:15)
1313
@ ./.test/nodeModulesMeaningfulErrorWhenImportingTs/app.ts 3:8-20

0 commit comments

Comments
 (0)