ts-node: Fail to load module from node_moules
The main ts file app.ts
:
import m from "mod"
console.log('imported module', m)
The module file node_modules/mod.ts
:
export default "TS module in node_modules";
app.ts
and node_modules
are in the same directory. When I run ts-node app.ts
, reports following error:
SyntaxError: Unexpected token export at exports.runInThisContext (vm.js:53:16) at Module._compile (module.js:387:25) at Module._extensions…js (module.js:422:10) at Object.require.extensions.(anonymous function) as .ts at Module.load (module.js:357:32) at Function.Module._load (module.js:314:12) at Module.require (module.js:367:17) at require (internal/module.js:20:19) at Object.<anonymous> (/Users/kevin.zeng/Projects/ringcentral-js-client/codegen/ts-sample/app.ts:1:1) at Module._compile (module.js:413:34)
The code runs normally when compiled to js using tsc
. Version info:
ts-node v1.0.0
node v5.11.1
tsc 1.8.10
About this issue
- Original URL
- State: closed
- Created 8 years ago
- Reactions: 1
- Comments: 38 (9 by maintainers)
Commits related to this issue
- Bundle files node & ts-node are not quite ready to run the imported TypeScript files directly. See https://github.com/TypeStrong/ts-node/issues/155. — committed to renehamburger/blinx-cli by renehamburger 4 years ago
Since I’m using Typescript for my project, I also prefer Typescript modules as the dependencies. So I think it’s necessary to compile dependencies or project won’t work using
ts-node
.Node.js v13 adds new complications. For anyone stumbling here, this is what you may face if you’re using Node.js v13+, but I have not found a solution yet.
It seems the
ignore
trick no longer works if both usingmodule: 'commonjs'
and having dependencies that are published as ES Modules.So although my
ignore
options is set correctly like I had it before Node 13 while I havemodule
set tocommonjs
, I get an error like the following error when Node tries to import an ES Module from the CommonJS module output of ts-node:Now you may think “just change
module
toesnext
”. Well, it ain’t that easy!Here’s the problem: the entry point that loads
ts-node
is still a CommonJS module, so as soon as ts-node supplies ES Module output, then you’ll get an error when you import your first.ts
file, like:Next, you might think “well, now just convert the
.js
file that loadsts-node
into an ES Module instead of CommonJS and give it the.mjs
extension or use--input-type=module
, and nowimport
your.ts
file instead ofrequire
ing it”. For example:Unfortunately, now this won’t work, because
.ts
extensions are not something that ES Modules understand by default, so now errors like the following happen:TLDR:
ts-node
is not yet in good shape to deal with the new ES Modules (unless I missed something).Same situation
The hard coded
node_modules
is actually a problem for repositories relying on how require works to load sub-projects in the same monorepo (like Pouchdb, Cerebraljs). If you store your projects like this:This setup works fine until testing cannot happen because ts-node does not compile in
node_modules
(which is in the test path).Please give us a way to fix this.
To allow monorepo packages to be transpiled, something like this works:
In case it helps anyone, here’s how to do it using the API (instead of CLI) with regex(es):
Since
ignore
wants a pattern. We can use a regex to whitelist package.Here is an example for
my_package
=>--ignore='node_modules\/(?!my_package)'
@blakeembrey This is really a confused discussion. I will never publish a typescript module and this is not the issue.
The issue is that people work inside a repository that happens to be
packages/node_modules
. Look at PouchDB source or Cerebral.js.The issue is that we cannot use
ts-node
to test this working directory. It has nothing to do with publishing.For example, these are not installed modules, but the actual packages developed by Cerebral.js: https://github.com/cerebral/cerebral/tree/master/packages/node_modules
@blakeembrey Can you please explain in what sense using a public API is
bad practice
?Using
node_modules
to load modules is totally part of node.js API. There is no hack whatsoever here. Reasons to use such a folder architecture are absolutely valid. Here is a discussion related to PouchDB: alle monorepo, we don’t have a public summary of our discussion at Cerebral.js but the reasons are similar and I have also good reasons with Lucidity to move away from lerna.I think there are simple ways to avoid compiling vendor modules and still allow complex open source projects to use
ts-node
for testing. One such way would be to be able to specify, like.gitignore
does for example:@cleavera No, they don’t. You should probably do some research into the topic yourself to get familiar. TypeScript libraries should be distributed in JavaScript with declarations enabled. Please don’t publish raw TypeScript libraries and fragment the ecosystem for no reason. Internally, you can do whatever you want of course.
Realistically, the setup you’re building is kind of awkward. You’re relying on a global mutation that’ll be done by a dependent. Why not just compile the files to JavaScript? What about having both projects register with
ts-node
? What if one project uses different compilation settings to the other? Or they have different dependencies on.d.ts
files that happen to conflict when you put them together?No problem 😄 Let me know if there’s any way to improve the docs to avoid issues in the future.
It’s exactly the same and nothing is confused here. If you check the README you can see how to get around it (
--ignore=false
should work, see https://github.com/TypeStrong/ts-node#configuration-options). I won’t be changing it by default, which is what I already said. Unless you have some magic solution that detects just node modules of your package vs node modules installed, I don’t see a better solution.I am really sorry. I don’t know how I missed this
--ignore
flag. I never intended for this to be the default.I had a similar problem to what @zixia had (sharing internal code between Typescript projects) which led me to this issue. Since it appears to be a design decision not to support .ts files in the
node_modules
folder, the solution I went with was to use a postinstall script in the library’s package.json.Example:
I also added a tsconfig.json file to the root folder of the library with all the compiler settings.
Thanks @romainPrignon. It seems that the same type of thing is necessary when dealing with
esnext
tsc-produced libraries as well. We were gettingSyntaxError: Unexpected identifier
on ouresnext
ores2015
modules, but the following solved it.I whitelisted our npm org and things started working:
As my perspective, I agree with @gaspard before, but I have to say, today I’ll agree with @blakeembrey.
Last year, I want to publish pure TypeScript module to NPM, and actually, I did. I also have a workaround about this, you could have a look at this thread at https://github.com/TypeStrong/ts-node/issues/155#issuecomment-235243048 .
The reason I want to do this is that at first:
Today, I learned from Angular how to publish NPM in UMD format with TypeDefination, it’s very easy to do this with an npm script, just as @blakeembrey said, really is a two seconds work. So I have no reason to keep my module in ts only.
At last, if there’s no dark side of using pure TypeScript NPM module, I believe it is possible to support it by ts-node. However, the dark side I could image is: when a javascript developer found your module from NPM and
npm -i
it, but it could not be able to run.. This will do hurt the npm eco-system.So today I vote NO for publishing pure TypeScript module to NPM. Hope this could help others like me to make the right decision today. 😃
I’m also running into similar issues. I have a dependency that distributes itself compiled to ES2015 I believe, with ES modules. I’m having a difficult time messing with all of the possible Node.js and ts-node settings to try and get it to work. Fortunately for me, I control the dependency so I might just go add a commonjs compilation to it.
Until this point, ts-node has generally worked wonderfully for me. The dream for me would be for ts-node to simply handle any files or dependencies that you point at it, be they JavaScript, TypeScript, CommonJS, or ES Modules. IMO ts-node should simply take an initial file as input and just make it work
I believe I’ve hit this issue with a project using Node.js v14. Basically, I’m trying to use a dependency with ES Modules and
"type": "module"
in itspackage.json
, and getting the error below:It seems to be the same issue described here (or have I got that wrong?) so I’m a bit surprised to see it marked as a “won’t fix”. Are ES Modules simply not supported, and there’s no interest in supporting them? Support for ES Modules in Node.js itself has been improving in recent versions, and I’d be glad to see
ts-node
take advantage of that. 😃@gaspard
How does your final
--ignore
configuration look like? I also have a mono repo setup and find that simply specifying--ignore=false
does not work for me, asts-node
would try to compile various files from the vendor’snode_module
directory which leads to errors.On the other hand, I’ve not found a good regex to specify a robust ignore pattern:
(?<!\/packages)\/node_modules\/
does not work due to JavaScript’s lack of look behind\/project_name\/node_modules\/
works, but it hardcodes the root folder name of the repo and would fail if some developer renames the directoryAny suggestions?
PS: @blakeembrey: Please fix the typo in the ticket’s title (“node_moules”) – it’s impossible to find when searching for ‘node_modules’.
@blakeembrey thanks for point me from #158 to here, sorry for not notice this issue before I post.
I do suggest ts-node to compiling dependencies. because is a good way to modulize pure typescript code if we do not want to compile .ts file any more. (it’s why ts-node here, right?)
@zengfenfei I ran into the same issue as you today. I have to make this work by soft link this:
more detail you can find in my dup issue #158