Ts-node: `npx`-invoked application that utilizes `ts-node` fails with `SyntaxError: Unexpected identifier`.

Created on 14 Jul 2019  ยท  14Comments  ยท  Source: TypeStrong/ts-node

I've got a tricky one.

I'm trying to make a npx-invokable TypeScript application that launches a web server.

At first I tried to see if there was a way to have npx provide a way to invoke a package script, but the jury's still out on whether that's doable.

So instead I made a bin script that just contains:

#!/usr/bin/env node

require("ts-node").register();

require("../server");

With the following tsconfig.json:

{
    "compilerOptions": {
        "allowJs": true,
        "allowSyntheticDefaultImports": true,
        "alwaysStrict": true,
        "esModuleInterop": true,
        "experimentalDecorators": true,
        "moduleResolution": "Node",
        "target": "ES2015"
    }
}

and if I run my script:

$ ./script

It works just fine.

But if I npx git+https://my-module.git, I get:

$ npx git+https://my-module.git
~/.npm/_npx/12274/lib/node_modules/my-module/server.ts:1
import express from "express";
       ^^^^^^^

SyntaxError: Unexpected identifier

(Same result with --node-arg=--experimental-modules, which was my leading suspicion.)

And if I peek in ~/.npm/_npx/:

~/.npm/_npx/
โ”œโ”€โ”€ 19646
โ”œโ”€โ”€ 35009
โ””โ”€โ”€ 41526
    โ”œโ”€โ”€ bin
    โ”‚ย ย  โ””โ”€โ”€ my-module -> ../lib/node_modules/my-module/bin/my-module
    โ””โ”€โ”€ lib
        โ””โ”€โ”€ node_modules
            โ””โ”€โ”€ my-module
                โ”œโ”€โ”€ README.md
                โ”œโ”€โ”€ bin
                โ”‚ย ย  โ””โ”€โ”€ my-module
                โ”œโ”€โ”€ config.ts
                โ”œโ”€โ”€ node_modules
                โ”‚ย ย  โ””โ”€โ”€ ...
                โ”œโ”€โ”€ package.json
                โ”œโ”€โ”€ public
                โ”œโ”€โ”€ router
                โ”œโ”€โ”€ server.ts
                โ”œโ”€โ”€ tsconfig.json
                โ”œโ”€โ”€ utilities.ts
                โ””โ”€โ”€ views

Everything looks pretty standard.

I know this seems mostly like an npx problem, but I was hoping to get some input from people who are more familiar with the quirks of TypeScript project configuration.

Any ideas?

Most helpful comment

This looks to be all that's necessary with the latest version:

require("ts-node").register({
    "dir": __dirname,
});

require("../process");

All 14 comments

I'm going to guess that it's related to the .register() call. I suspect it's using the either the symlinked path or cwd so it doesn't actually find your tsconfig.json file (and maybe finds another one?). Can you try with console.log(process.cwd())? Specifically the issue is in https://github.com/TypeStrong/ts-node/blob/629525474fb548fddb7a90a48ab795a9199b1997/src/index.ts#L212. While you're at it, can you check __dirname? If that's correct, but cwd isn't, we should be able to enable .register({ cwd: __dirname }) for it to work.

When run from the bin directory:

process.cwd(): /Users/user/Developer/my-module/bin
__dirname: /Users/user/Developer/my-module/bin

When run from npx:

process.cwd(): /Users/user/Desktop/temp
__dirname: /Users/user/.npm/_npx/4630/lib/node_modules/my-module/bin

Setting:

require("ts-node").register({ "cwd": __dirname });

Seems like the correct solution to this problem. Want me to submit an MR?

Hmm, those two changes don't appear to have fixed it.

import express from "express";
       ^^^^^^^

SyntaxError: Unexpected identifier
    at Module._compile (internal/modules/cjs/loader.js:760:23)
    at Module._extensions..js (internal/modules/cjs/loader.js:827:10)
    ...

@brianjenkins94 I see, I wonder if that's because your tsconfig.json is still within the ../lib structure and __dirname is actually a symlink to the other location so tsconfig.json can't be found. I'm surprised it works normally - are you having the same issue if you run it from ./bin/my-module normally (without NPX)? I might have to reconstruct this and play around with the solution - it'll probably end up either specifying the execution directory or location of tsconfig.json since it currently only searches from wherever you're running.

$ node ~/.npm/_npx/12274/bin/my-module

and

cd ~/.npm/_npx/12274/lib/node_modules/my_module/
node ./bin/my-module

Yield the same error as above. So it doesn't actually work at all from under the ~/.npm/_npx/ folder.

I'll see if I can help you with a minimal reproducible sample.

Update: This should help: https://gist.github.com/brianjenkins94/8ca182b682610242ab35df36d4238e99

https://github.com/TypeStrong/ts-node/issues/617#issuecomment-401406834
npx installs your package in .../node_modules/, and TS Node does not compile files in node_modules by default.
So, try to change your code from

require("ts-node").register();

to

require('ts-node').register(
  Object.assign(
    {
      ignore: [/\.js/],
    },
    require('./tsconfig.json'),
  ),
);

Interesting. I won't have a chance to look into this for a bit but a new error message is definitely progress.

$ npx https://gist.github.com/brianjenkins94/8ca182b682610242ab35df36d4238e99

npx: installed 60 in 4.756s

process.cwd(): /Users/user
__dirname: /Users/user/.npm/_npx/51989/lib/node_modules/sampleThatReproducesTheIssue

โจฏ Unable to compile TypeScript:
.npm/_npx/51989/lib/node_modules/sampleThatReproducesTheIssue/server.ts:2:23 - error TS2307: Cannot find module 'path'.

2 import * as path from "path";
                        ~~~~~~
.npm/_npx/51989/lib/node_modules/sampleThatReproducesTheIssue/server.ts:6:34 - error TS2304: Cannot find name '__dirname'.

6 app.use(express.static(path.join(__dirname, "public")));
                                   ~~~~~~~~~

Try to add

/// <reference types="node" />

to the top of server.ts.

Weird. I wonder why it needs an explicit triple-slash reference. But that does make it work.

I'm going to do a little more research on if there's a way to do it without the triple-slash reference and then probably close this later today.

Removing types from the tsconfig.json fixed it. No triple-slash reference necessary.

Thanks a bunch guys!

@Broltes there's $10 for you at that BountySource link. Let me know if you run into any issues.

Weirdly this issue has come back up for me again. Investigating...

This works fine:

npx https://gist.github.com/brianjenkins94/8ca182b682610242ab35df36d4238e99

Screen Shot 2020-06-19 at 10 34 04 PM

This does not:

npx cireneirbo/airwinfi

Screen Shot 2020-06-19 at 10 34 06 PM

Code looks identical...

This works again. No idea why.

This looks to be all that's necessary with the latest version:

require("ts-node").register({
    "dir": __dirname,
});

require("../process");
Was this page helpful?
0 / 5 - 0 ratings

Related issues

Borewit picture Borewit  ยท  3Comments

grissius picture grissius  ยท  3Comments

motss picture motss  ยท  4Comments

watzon picture watzon  ยท  3Comments

cibergarri picture cibergarri  ยท  3Comments