When running an application using in ts-node with --transpile-only flag (or ts-node-dev) and ttypescript with ts-transform-paths plugin, the plugin doesn't seem to work.
I did some research and the reason is transpile-only of ts-node mode and ts-node-dev compile the code using transpileModule function of the main typescript library.
https://github.com/microsoft/TypeScript/blob/468ca9f87076db70aa7d0b037a73f5232b6834e6/src/services/transpile.ts#L26-L102
Now, ts-transform-paths gets info about paths from an object implementing the interface Program
transformationContext.getCompilerOptions()
Here is the interface:
https://github.com/microsoft/TypeScript/blob/167f954ec7cf456238cad4f2006fb330c53bba8e/src/compiler/types.ts#L3195-L3300
The transformationContext is created by TS itself, but when it's created inside transpileModule function, things get a bit weird...
(Here's the line where the Program instance is created).
https://github.com/microsoft/TypeScript/blob/167f954ec7cf456238cad4f2006fb330c53bba8e/src/services/transpile.ts#L90
const program = createProgram([inputFileName], options, compilerHost);
Because the options that are passed to the factory are not exactly what's in tsconfig.json.
And here are the lines that are responsible for that:
https://github.com/microsoft/TypeScript/blob/167f954ec7cf456238cad4f2006fb330c53bba8e/src/services/transpile.ts#L32-L41
const defaultOptions = getDefaultCompilerOptions();
for (const key in defaultOptions) {
if (hasProperty(defaultOptions, key) && options[key] === undefined) {
options[key] = defaultOptions[key];
}
}
for (const option of transpileOptionValueCompilerOptions) {
options[option.name] = option.transpileOptionValue;
}
What this fragment does is it takes this array:
https://github.com/microsoft/TypeScript/blob/167f954ec7cf456238cad4f2006fb330c53bba8e/src/compiler/commandLineParser.ts#L224-L1000
And replaces each property of tsconfig.json with the value of matching transpileOptionValue property, and in case of paths it's:
{
// this option can only be specified in tsconfig.json
// use type = object to copy the value as-is
name: "paths",
type: "object",
affectsModuleResolution: true,
isTSConfigOnly: true,
category: Diagnostics.Module_Resolution_Options,
description: Diagnostics.A_series_of_entries_which_re_map_imports_to_lookup_locations_relative_to_the_baseUrl,
transpileOptionValue: undefined
},
undefined
So when ts-transform-paths tries to resolve paths in a transpileOnly mode, it cannot do so, because the config it gets in this mode using this
transformationContext.getCompilerOptions();
has paths set to undefined.
The summary is: getCompilerOptions() of a Program instance is not a reliable way of accessing info about paths, because the data is lost in transpileOnly mode. There should be another way to access such data, because they probably won't change the behaviour in typescript library, because they always consider such things intentional.
You can see the library failing in this repo:
https://github.com/IgorSzymanski/ts-transform-paths-bug-repro
Either run
or
yarn
yarn start:transpile
on the contrary:
Will work just fine, because it's not using transpileOnly mode.
When running an application using in
ts-nodewith--transpile-onlyflag (orts-node-dev) andttypescriptwithts-transform-pathsplugin, the plugin doesn't seem to work.I did some research and the reason is
transpile-onlyofts-nodemode andts-node-devcompile the code usingtranspileModulefunction of the maintypescriptlibrary.https://github.com/microsoft/TypeScript/blob/468ca9f87076db70aa7d0b037a73f5232b6834e6/src/services/transpile.ts#L26-L102
Now,
ts-transform-pathsgets info about paths from an object implementing the interfaceProgramHere is the interface:
https://github.com/microsoft/TypeScript/blob/167f954ec7cf456238cad4f2006fb330c53bba8e/src/compiler/types.ts#L3195-L3300
The
transformationContextis created by TS itself, but when it's created insidetranspileModulefunction, things get a bit weird...(Here's the line where the
Programinstance is created).https://github.com/microsoft/TypeScript/blob/167f954ec7cf456238cad4f2006fb330c53bba8e/src/services/transpile.ts#L90
Because the options that are passed to the factory are not exactly what's in
tsconfig.json.And here are the lines that are responsible for that:
https://github.com/microsoft/TypeScript/blob/167f954ec7cf456238cad4f2006fb330c53bba8e/src/services/transpile.ts#L32-L41
What this fragment does is it takes this array:
https://github.com/microsoft/TypeScript/blob/167f954ec7cf456238cad4f2006fb330c53bba8e/src/compiler/commandLineParser.ts#L224-L1000
And replaces each property of
tsconfig.jsonwith the value of matchingtranspileOptionValueproperty, and in case ofpathsit's:undefinedSo when
ts-transform-pathstries to resolve paths in atranspileOnlymode, it cannot do so, because the config it gets in this mode using thishas
pathsset toundefined.The summary is:
getCompilerOptions()of aPrograminstance is not a reliable way of accessing info aboutpaths, because the data is lost intranspileOnlymode. There should be another way to access such data, because they probably won't change the behaviour intypescriptlibrary, because they always consider such things intentional.You can see the library failing in this repo:
https://github.com/IgorSzymanski/ts-transform-paths-bug-repro
Either run
or
on the contrary:
Will work just fine, because it's not using
transpileOnlymode.