diff --git a/README.md b/README.md index 07a6d7bca..3d983438b 100644 --- a/README.md +++ b/README.md @@ -248,7 +248,8 @@ of your code. 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`. #### appendTsSuffixTo *(RegExp[]) (default=[])* -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. +#### appendTsxSuffixTo *(RegExp[]) (default=[])* +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. 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.) @@ -287,6 +288,64 @@ export default { ``` +We can handle `.tsx` by quite similar way: + +webpack.config.js: + +```javascript +module.exports = { + entry: './index.vue', + output: { filename: 'bundle.js' }, + resolve: { + extensions: ['.ts', '.tsx', '.vue', '.vuex'] + }, + module: { + rules: [ + { test: /\.vue$/, loader: 'vue-loader', + options: { + loaders: { + ts: 'ts-loader', + tsx: 'babel-loader!ts-loader', + } + } + }, + { test: /\.ts$/, loader: 'ts-loader', options: { appendTsSuffixTo: [/TS\.vue$/] } } + { test: /\.tsx$/, loader: 'babel-loader!ts-loader', options: { appendTsxSuffixTo: [/TSX\.vue$/] } } + ] + } +} +``` + +tsconfig.json (set `jsx` option to `preserve` to let babel handle jsx) + +```json +{ + "compilerOptions": { + "jsx": "preserve" + } +} +``` + +index.vue + +```vue + +``` + +Or if you want to use only tsx, just use the `appendTsxSuffixTo` option only: + +```javascript + { test: /\.ts$/, loader: 'ts-loader' } + { test: /\.tsx$/, loader: 'babel-loader!ts-loader', options: { appendTsxSuffixTo: [/\.vue$/] } } +``` + ### `LoaderOptionsPlugin` [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!) diff --git a/src/index.ts b/src/index.ts index 3f035d2b8..4acddfa94 100644 --- a/src/index.ts +++ b/src/index.ts @@ -26,7 +26,14 @@ function loader(this: interfaces.Webpack, contents: string) { } const rawFilePath = path.normalize(this.resourcePath); - const filePath = utils.appendTsSuffixIfMatch(options.appendTsSuffixTo, rawFilePath); + + const filePath = options.appendTsSuffixTo.length > 0 || options.appendTsxSuffixTo.length > 0 + ? utils.appendSuffixesIfMatch({ + '.ts': options.appendTsSuffixTo, + '.tsx': options.appendTsxSuffixTo, + }, rawFilePath) + : rawFilePath; + const fileVersion = updateFileInCache(filePath, contents, instance); const { outputText, sourceMapText } = options.transpileOnly @@ -44,10 +51,10 @@ function loader(this: interfaces.Webpack, contents: string) { // _module.meta is not available inside happypack if (!options.happyPackMode) { - // Make sure webpack is aware that even though the emitted JavaScript may be the same as - // a previously cached version the TypeScript may be different and therefore should be - // treated as new - this._module.meta.tsLoaderFileVersion = fileVersion; + // Make sure webpack is aware that even though the emitted JavaScript may be the same as + // a previously cached version the TypeScript may be different and therefore should be + // treated as new + this._module.meta.tsLoaderFileVersion = fileVersion; } callback(null, output, sourceMap); @@ -83,6 +90,7 @@ function getLoaderOptions(loader: interfaces.Webpack) { visualStudioErrorFormat: false, compilerOptions: {}, appendTsSuffixTo: [], + appendTsxSuffixTo: [], transformers: {}, entryFileIsJs: false, happyPackMode: false, diff --git a/src/instances.ts b/src/instances.ts index dabac8721..be13a9c75 100644 --- a/src/instances.ts +++ b/src/instances.ts @@ -110,7 +110,7 @@ export function getTypeScriptInstance( modifiedFiles: null, }; - const servicesHost = makeServicesHost(scriptRegex, log, loader, instance, loaderOptions.appendTsSuffixTo); + const servicesHost = makeServicesHost(scriptRegex, log, loader, instance, loaderOptions.appendTsSuffixTo, loaderOptions.appendTsxSuffixTo); instance.languageService = compiler.createLanguageService(servicesHost, compiler.createDocumentRegistry()); loader._compiler.plugin("after-compile", afterCompile(instance, configFilePath)); diff --git a/src/interfaces.ts b/src/interfaces.ts index 4b4ec8758..1f0a19c06 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -254,6 +254,7 @@ export interface LoaderOptions { visualStudioErrorFormat: boolean; compilerOptions: typescript.CompilerOptions; appendTsSuffixTo: RegExp[]; + appendTsxSuffixTo: RegExp[]; entryFileIsJs: boolean; happyPackMode: boolean; getCustomTransformers?(): typescript.CustomTransformers | undefined; diff --git a/src/servicesHost.ts b/src/servicesHost.ts index ddc0c201e..d3e02f623 100644 --- a/src/servicesHost.ts +++ b/src/servicesHost.ts @@ -14,14 +14,15 @@ function makeServicesHost( log: logger.Logger, loader: interfaces.Webpack, instance: interfaces.TSInstance, - appendTsSuffixTo: RegExp[] + appendTsSuffixTo: RegExp[], + appendTsxSuffixTo: RegExp[] ) { const { compiler, compilerOptions, files } = instance; const newLine = compilerOptions.newLine === constants.CarriageReturnLineFeedCode ? constants.CarriageReturnLineFeed : - compilerOptions.newLine === constants.LineFeedCode ? constants.LineFeed : - constants.EOL; + compilerOptions.newLine === constants.LineFeedCode ? constants.LineFeed : + constants.EOL; // make a (sync) resolver that follows webpack's rules const resolveSync = makeResolver(loader.options); @@ -77,7 +78,7 @@ function makeServicesHost( log: log.log, resolveModuleNames: (moduleNames: string[], containingFile: string) => resolveModuleNames( - resolveSync, moduleResolutionHost, appendTsSuffixTo, scriptRegex, instance, + resolveSync, moduleResolutionHost, appendTsSuffixTo, appendTsxSuffixTo, scriptRegex, instance, moduleNames, containingFile), getCustomTransformers: () => instance.transformers }; @@ -87,13 +88,14 @@ function resolveModuleNames( resolveSync: interfaces.ResolveSync, moduleResolutionHost: interfaces.ModuleResolutionHost, appendTsSuffixTo: RegExp[], + appendTsxSuffixTo: RegExp[], scriptRegex: RegExp, instance: interfaces.TSInstance, moduleNames: string[], containingFile: string ) { const resolvedModules = moduleNames.map(moduleName => - resolveModuleName(resolveSync, moduleResolutionHost, appendTsSuffixTo, scriptRegex, instance, + resolveModuleName(resolveSync, moduleResolutionHost, appendTsSuffixTo, appendTsxSuffixTo, scriptRegex, instance, moduleName, containingFile) ); @@ -106,6 +108,7 @@ function resolveModuleName( resolveSync: interfaces.ResolveSync, moduleResolutionHost: interfaces.ModuleResolutionHost, appendTsSuffixTo: RegExp[], + appendTsxSuffixTo: RegExp[], scriptRegex: RegExp, instance: interfaces.TSInstance, @@ -118,7 +121,13 @@ function resolveModuleName( try { const originalFileName = resolveSync(undefined, path.normalize(path.dirname(containingFile)), moduleName); - const resolvedFileName = utils.appendTsSuffixIfMatch(appendTsSuffixTo, originalFileName); + + const resolvedFileName = appendTsSuffixTo.length > 0 || appendTsxSuffixTo.length > 0 + ? utils.appendSuffixesIfMatch({ + '.ts': appendTsSuffixTo, + '.tsx': appendTsxSuffixTo, + }, originalFileName) + : originalFileName; if (resolvedFileName.match(scriptRegex)) { resolutionResult = { resolvedFileName, originalFileName }; diff --git a/src/utils.ts b/src/utils.ts index d74d95398..e4ad77240 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -77,17 +77,24 @@ export function makeError({ rawMessage, message, location, file }: MakeError): i return Object.assign(error, { location, file }); } -export function appendTsSuffixIfMatch(patterns: RegExp[], path: string): string { +export function appendSuffixIfMatch(patterns: RegExp[], path: string, suffix: string): string { if (patterns.length > 0) { for (let regexp of patterns) { if (path.match(regexp)) { - return path + '.ts'; + return path + suffix; } } } return path; } +export function appendSuffixesIfMatch(suffixDict: {[suffix: string]: RegExp[]}, path: string): string { + for(let suffix in suffixDict) { + path = appendSuffixIfMatch(suffixDict[suffix], path, suffix); + } + return path; +} + /** * Recursively collect all possible dependants of passed file */ diff --git a/test/comparison-tests/nodeModulesMeaningfulErrorWhenImportingTs/expectedOutput-2.0/output.txt b/test/comparison-tests/nodeModulesMeaningfulErrorWhenImportingTs/expectedOutput-2.0/output.txt index e66ec8175..dac52d06d 100644 --- a/test/comparison-tests/nodeModulesMeaningfulErrorWhenImportingTs/expectedOutput-2.0/output.txt +++ b/test/comparison-tests/nodeModulesMeaningfulErrorWhenImportingTs/expectedOutput-2.0/output.txt @@ -8,5 +8,5 @@ Module build failed: Error: Typescript emitted no output for node_modules/a/inde You should not need to recompile .ts files in node_modules. Please contact the package author to advise them to use --declaration --outDir. More https://github.com/Microsoft/TypeScript/issues/12358 - at Object.loader (dist/index.js:31:15) + at Object.loader (dist/index.js:33:15) @ ./.test/nodeModulesMeaningfulErrorWhenImportingTs/app.ts 2:8-20 \ No newline at end of file diff --git a/test/comparison-tests/nodeModulesMeaningfulErrorWhenImportingTs/expectedOutput-2.1/output.txt b/test/comparison-tests/nodeModulesMeaningfulErrorWhenImportingTs/expectedOutput-2.1/output.txt index cced2fa78..c26740130 100644 --- a/test/comparison-tests/nodeModulesMeaningfulErrorWhenImportingTs/expectedOutput-2.1/output.txt +++ b/test/comparison-tests/nodeModulesMeaningfulErrorWhenImportingTs/expectedOutput-2.1/output.txt @@ -9,5 +9,5 @@ Module build failed: Error: Typescript emitted no output for node_modules/a/inde You should not need to recompile .ts files in node_modules. Please contact the package author to advise them to use --declaration --outDir. More https://github.com/Microsoft/TypeScript/issues/12358 - at Object.loader (dist/index.js:31:15) + at Object.loader (dist/index.js:33:15) @ ./.test/nodeModulesMeaningfulErrorWhenImportingTs/app.ts 2:8-20 \ No newline at end of file diff --git a/test/comparison-tests/nodeModulesMeaningfulErrorWhenImportingTs/expectedOutput-2.2/output.txt b/test/comparison-tests/nodeModulesMeaningfulErrorWhenImportingTs/expectedOutput-2.2/output.txt index ed8b4e1a4..9709eca0f 100644 --- a/test/comparison-tests/nodeModulesMeaningfulErrorWhenImportingTs/expectedOutput-2.2/output.txt +++ b/test/comparison-tests/nodeModulesMeaningfulErrorWhenImportingTs/expectedOutput-2.2/output.txt @@ -9,5 +9,5 @@ Module build failed: Error: Typescript emitted no output for node_modules\a\inde You should not need to recompile .ts files in node_modules. Please contact the package author to advise them to use --declaration --outDir. More https://github.com/Microsoft/TypeScript/issues/12358 - at Object.loader (dist\index.js:32:15) + at Object.loader (dist\index.js:33:15) @ ./.test/nodeModulesMeaningfulErrorWhenImportingTs/app.ts 3:8-20 \ No newline at end of file diff --git a/test/comparison-tests/nodeModulesMeaningfulErrorWhenImportingTs/expectedOutput-2.3/output.txt b/test/comparison-tests/nodeModulesMeaningfulErrorWhenImportingTs/expectedOutput-2.3/output.txt index 28b6a3ae1..63d7c4b4b 100644 --- a/test/comparison-tests/nodeModulesMeaningfulErrorWhenImportingTs/expectedOutput-2.3/output.txt +++ b/test/comparison-tests/nodeModulesMeaningfulErrorWhenImportingTs/expectedOutput-2.3/output.txt @@ -9,5 +9,5 @@ Module build failed: Error: Typescript emitted no output for node_modules\a\inde You should not need to recompile .ts files in node_modules. Please contact the package author to advise them to use --declaration --outDir. More https://github.com/Microsoft/TypeScript/issues/12358 - at Object.loader (dist\index.js:32:15) + at Object.loader (dist\index.js:33:15) @ ./.test/nodeModulesMeaningfulErrorWhenImportingTs/app.ts 3:8-20 \ No newline at end of file diff --git a/test/comparison-tests/nodeModulesMeaningfulErrorWhenImportingTs/expectedOutput-2.4/output.txt b/test/comparison-tests/nodeModulesMeaningfulErrorWhenImportingTs/expectedOutput-2.4/output.txt index 7aaa74e35..ed8b4e1a4 100644 --- a/test/comparison-tests/nodeModulesMeaningfulErrorWhenImportingTs/expectedOutput-2.4/output.txt +++ b/test/comparison-tests/nodeModulesMeaningfulErrorWhenImportingTs/expectedOutput-2.4/output.txt @@ -9,5 +9,5 @@ Module build failed: Error: Typescript emitted no output for node_modules\a\inde You should not need to recompile .ts files in node_modules. Please contact the package author to advise them to use --declaration --outDir. More https://github.com/Microsoft/TypeScript/issues/12358 - at Object.loader (dist\index.js:31:15) + at Object.loader (dist\index.js:32:15) @ ./.test/nodeModulesMeaningfulErrorWhenImportingTs/app.ts 3:8-20 \ No newline at end of file