tsify
tsify copied to clipboard
Cannot find ambient module declaration in .d.ts
When trying to transpile and bundle .ts
file via Gulp/Browserify/Tsify the task fails with "Cannot find module" although standard tsc
transpilation works.
I created an ambient module declaration based on TypeScript handbook:
// File: ./src/node_modules/mymodule.d.ts
declare module "mymodule"
{
export class MyModule
{
public static Report(message:string):any;
}
}
And I'm trying to import it in another file:
// File: ./src/consumer.ts
import {MyModule} from "mymodule";
MyModule.Report("MyModule was found by consumer");
The standard transpilation by TSC works ok: tsc ./src/consumer.ts
But when trying to transpile with the use of Browserify/Tsify/Gulp the gulp task fails:
// File: gulpfile.js
var gulp = require('gulp');
var browserify = require('browserify');
var source = require('vinyl-source-stream');
var tsify = require('tsify');
gulp.task('default', function () {
return browserify({
basedir: '.',
debug: true,
entries: ['src/consumer.ts'],
cache: {},
packageCache: {}
})
.plugin(tsify)
.bundle()
.pipe(source('consumer.js'))
.pipe(gulp.dest('dist'));
});
The error is: Error: Cannot find module 'mymodule' from 'D:\Projects\Playground\TSTest\src'
I've put together a minimal repository which replicates the issue: https://github.com/mnovotny/tsify-issue-250
Thanks for opening such a thorough issue. Unfortunately, I don't have the time, at the moment, to figure out why this isn't working for you, but I do have some suggestions:
- When
tsc
is run with file specified on the command line, it ignores anytsconfig.json
file, so it might not be doing what you expect it do be doing. - Browserify needs to be able to resolve the modules and, AFAICT,
./src/node_modules/mymodule.d.ts
is not a valid location for module resolution using Node'sresolve
algorithm. I would have though that it would have to be in a directory undernode_modules
. I guess it's possible that this is working - for some reason - withtsc
but not for Browserify. - To obtain more diagnostic information, you can switch on the logging that's built into
tsify
- see the Debugging section inCONTRIBUTING.md
. It might give you some hints as to what is going on.
Good luck.
Thanks for the reply. Here are my findings:
-
tsc
compilation withtsconfig.json
also works OK. I've tried puttingconsumer.ts
tofiles[ ]
and rantsc
with the-p
option. It does produce a slightly different.js
file but no error is thrown. - According to https://www.typescriptlang.org/docs/handbook/module-resolution.html#how-typescript-resolves-modules the location
./src/node_modules/mymodule.d.ts
is a valid location. Anyway, I've tried copying the ambient declaration to./node_modules/@types/mymodule/index.d.ts
and Browserify/Tsify threw an errorDuplicate identifier 'MyModule'
which IMO means the declaration was being processed from both the original location and the new location. I believe this implies the original location was valid as well. - I've tried turning the logging on but the instructions in CONTRIBUTING.md are not clear to me, my apologies. I've put the
NODE_DEBUG
variable to system variables (I'm on Windows) with valuetsify browserify
and I've putvar log = require('util').debuglog(require('./package').name);
to myguplfile.js
but I'm not sure what to do next.
How TypeScript resolves modules - and what it considers to be valid - does not matter. What might matter is how Browserify does it. And what Browserify considers to be valid.
The algorithm used by Browserify - and Node - is explained here.
I'm also a Windows developer. I would not recommend putting the environment variable into the system variables. Specify it on the command line and use Git Bash or a similar shell.
The following locations for the ambient declaration were tried and with no success
- ./node_modules/@types/mymodule/index.d.ts
- ./node_modules/@types/mymodule.d.ts
Again, when I tried to keep the file in both of these locations the Gulp task complained about a duplicate identifier. I believe this means the file was, in fact, found. Therefore I believe the error is not in the location.
Another reason to believe the locations are correct is that when I completely remove the file there is not 1 error but 2 errors in the Gulp task execution:
TypeScript error: src/consumer.ts(1,24): Error TS2307: Cannot find module 'mymodule'. Error: Cannot find module 'mymodule' from 'D:\Projects\Playground\TSTest\src'
And I'm sorry, I'm having no luck with setting up the logging. I've put NODE_DEBUG into my .bashrc and I'm running Gulp from within Git Bash. But I have no idea what to do next in order to actually see some more info about my error from within Browserify/Tsify.
The environment variable doesn't go into a configuration file; it's specified on the command line, immediately before the command you want to run - as in the doc to which I referred you.
The duplicate error you are.getting is a TS error. The initial error you mentioned in the issue is - IMO - most likely a Browserify error. Have a looks at what tsc
generates when it 'works'. Is there a require
for this ambient module? If there is, that is likely the problem.
Unfortunately, I no longer use tsify
have never authored my own ambient modules and don't have the time to diagnose this problem for you.
Well, thanks for your effort anyway.
@mnovotny I encountered the same situation as you, and found the answer. Maybe the same method can help you too.
I got the initial answer from here
For you, I first suppose the final calling of MyModule.Report
could be rewritten to window.MyModule.Report
. If it is not right, you may need to modify the config option.
In package.json
at the root directory of the project, adding module browserify-shim
(or just npm install browserify-shim
) and config options for it. At last, it would be like:
{
"devDependencies": {
"browserify-shim": "*"
},
"browserify-shim": {
"mymodule": "global:window"
},
"browserify": {
"transform": [
"browserify-shim"
]
}
}
That's all :)
In consumer.js
, the compiled code is like this:
var mymodule_1 = (typeof window !== "undefined" ? window['window'] : typeof global !== "undefined" ? global['window'] : null);
mymodule_1.MyModule.Report("MyModule was found by consumer");
The browserify-shim plugin treats mymodule
as a external module and use another variable name to replace it, just like using external
and output.global
with rollup
Hope it will help you.