Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add appendTsxSuffixTo option #581

Merged
merged 16 commits into from
Jul 15, 2017
61 changes: 60 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.)

Expand Down Expand Up @@ -287,6 +288,64 @@ export default {
</script>
```

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
<script lang="tsx">
export default {
functional: true,
render(h, c) {
return (<div>Content</div>);
}
}
</script>
```

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!)
Expand Down
18 changes: 13 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);
Expand Down Expand Up @@ -83,6 +90,7 @@ function getLoaderOptions(loader: interfaces.Webpack) {
visualStudioErrorFormat: false,
compilerOptions: {},
appendTsSuffixTo: [],
appendTsxSuffixTo: [],
transformers: {},
entryFileIsJs: false,
happyPackMode: false,
Expand Down
2 changes: 1 addition & 1 deletion src/instances.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
1 change: 1 addition & 0 deletions src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ export interface LoaderOptions {
visualStudioErrorFormat: boolean;
compilerOptions: typescript.CompilerOptions;
appendTsSuffixTo: RegExp[];
appendTsxSuffixTo: RegExp[];
entryFileIsJs: boolean;
happyPackMode: boolean;
getCustomTransformers?(): typescript.CustomTransformers | undefined;
Expand Down
21 changes: 15 additions & 6 deletions src/servicesHost.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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
};
Expand All @@ -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)
);

Expand All @@ -106,6 +108,7 @@ function resolveModuleName(
resolveSync: interfaces.ResolveSync,
moduleResolutionHost: interfaces.ModuleResolutionHost,
appendTsSuffixTo: RegExp[],
appendTsxSuffixTo: RegExp[],
scriptRegex: RegExp,
instance: interfaces.TSInstance,

Expand All @@ -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 };
Expand Down
11 changes: 9 additions & 2 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,17 +77,24 @@ export function makeError({ rawMessage, message, location, file }: MakeError): i
return <interfaces.WebpackError>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
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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