Ts-loader: transpileOnly: true, didnt compile ts files imported with triple-slash references tag(///<reference path="xxx">)?

Created on 10 Jun 2020  路  4Comments  路  Source: TypeStrong/ts-loader

Expected Behaviour

transpileOnly: true, the output js file contains the codes about Test.ts

Actual Behaviour

when transpileOnly: true, the output js file didnt contains any thing of Test.ts (imported in main.ts).
but transpileOnly: false did.

Steps to Reproduce the Problem

my env:
node version: v12.16.1
os: win10

1.git clone my repos below.
2.npm install
3.npm run webpack

and set transpileOnly: false in webpack.config.ts, npm run webpack again, pls check the difference of output js file(bin\js\main_webpack.js)

Location of a Minimal Repository that Demonstrates the Issue.

https://github.com/hslin2020/client_wp.git

is there any thing im doing wrong? any hints would be very appreciated!!!

so sorry about my broken english, i hope you guys still know.

best regards!
sheng

Most helpful comment

If you delete tsconfig.json and process the input with the command

npx tsc src/main.ts --outFile out.js --module amd

then out.js will include the code in test/Test.ts. You need the outFile option for this to work. Without the outFile option the output will be main.js which will only include the triple slash reference, not the actual code.

When you enable transpileOnly ts-loader will use typescript.transpileModule
to process the file. This is similar to using the isolatedModules option which is not compatible with outFile. So I suspect the behaviour is expected.

You may not need to use a namespace. See the following link for a discussion on namespaces and modules and when namespacing may be needless:

https://www.typescriptlang.org/docs/handbook/namespaces-and-modules.html#needless-namespacing

You could remove your namespace from Test.ts and then use it in main.ts as follows:

import * as test from './test/Test'

export default class main {
    private _test: test.Test;
    constructor() {
        this._test = new test.Test();
        this._test.sayHello();
    }
}

Here you group all exported items from Test.ts under the name 'test', which is the same as creating the namespace in the first place. As stated at the link above:

Because the module file itself is already a logical grouping, and its top-level name is defined by the code that imports it, it鈥檚 unnecessary to use an additional module layer for exported objects.

You could also export the namespace in Test.ts:

export namespace test {

And then import it in main.ts:

import { test } from "./test/Test";

I don't see any benefit and it still creates a needless namespace.

I appreciate your repo is only a minimal example so perhaps there is a reason in your application to use namespaces this way. From what I can see the triple slash references will not work with transpileOnly so I recommend checking whether you really need a namespace and if so, use exports or switch off transpileOnly.

All 4 comments

If you delete tsconfig.json and process the input with the command

npx tsc src/main.ts --outFile out.js --module amd

then out.js will include the code in test/Test.ts. You need the outFile option for this to work. Without the outFile option the output will be main.js which will only include the triple slash reference, not the actual code.

When you enable transpileOnly ts-loader will use typescript.transpileModule
to process the file. This is similar to using the isolatedModules option which is not compatible with outFile. So I suspect the behaviour is expected.

You may not need to use a namespace. See the following link for a discussion on namespaces and modules and when namespacing may be needless:

https://www.typescriptlang.org/docs/handbook/namespaces-and-modules.html#needless-namespacing

You could remove your namespace from Test.ts and then use it in main.ts as follows:

import * as test from './test/Test'

export default class main {
    private _test: test.Test;
    constructor() {
        this._test = new test.Test();
        this._test.sayHello();
    }
}

Here you group all exported items from Test.ts under the name 'test', which is the same as creating the namespace in the first place. As stated at the link above:

Because the module file itself is already a logical grouping, and its top-level name is defined by the code that imports it, it鈥檚 unnecessary to use an additional module layer for exported objects.

You could also export the namespace in Test.ts:

export namespace test {

And then import it in main.ts:

import { test } from "./test/Test";

I don't see any benefit and it still creates a needless namespace.

I appreciate your repo is only a minimal example so perhaps there is a reason in your application to use namespaces this way. From what I can see the triple slash references will not work with transpileOnly so I recommend checking whether you really need a namespace and if so, use exports or switch off transpileOnly.

Many thanks about your detail reply.
But there are tons of namespaces everywhere in my project, its impossible to remove them. At the meanwhile if i disable transpileOnly , it cost a huge time compiling the proj. So far what we can do is to run tsc in the command line. Im just looking forward to using webpack & ts-loader to instead of it.
Anyway, thanks again for your reply and what youre working on this plugin. Its a really nice work for the public!!!
best regards.

If your project is so big that build time is an issue you might want to consider using project references:

https://www.typescriptlang.org/docs/handbook/project-references.html

You can split your codebase into projects which will be separately built using tsc. Webpack will then build the whole project using the pre-built subprojects. If the bulk of your codebase is not changing you can put it in one subproject and just build it once. The build uses tsc so you should be able to use the triple slash reference.

Another solution could be to use a custom transformer (https://github.com/TypeStrong/ts-loader#getcustomtransformers), or a separate webpack loader that runs before ts-loader, to search for the triple slash references and include the files directly, or change the triple slash references into import statements. This feels like a less elegant solution than project references.

I did notice that in your file tsconfig-for-webpack-config.json you use the module type commonjs, which is not compatible with the outFile option, (that is required to get tsc to include the referenced file). Webpack does not understand the triple slash reference, which is why it does not include the Test.ts file in the bundle. The only way to get it included with webpack is to export the namespace from Test.ts and import it normally.

Maybe someone with more experience can weigh in here, but my take is that triple slash references are a tsc only construct, which has been replaced by tsconfig.json and normal module export/import. I don't believe ts-loader can or should be patched to make this work with transpileOnly. ts-loader does support project references so that is probably the best solution.

project reference sounds a good suggestion so that i will be trying to working on that. thanks bro. you really help me alot!!!

regards
sheng

Was this page helpful?
0 / 5 - 0 ratings