Ts-node: Could not find file .png

Created on 15 Oct 2016  Â·  11Comments  Â·  Source: TypeStrong/ts-node

Getting the following error when running ts-node. I haven't been able to resolve an issue surrounding asset requires with ts-node. However, it seems to be working properly with tsc and the proper definition types.

Error: Could not find file: '/valid/path/to/actual/file/image.png'. at getValidSourceFile (~/node_modules/typescript/lib/typescript.js:73826:23)

I thought it might be a typescript version issue at first, but I've confirmed that 2.1.0-dev is being used.

When enabling the fast prop for the register config, I then get hundreds of the following errors:

/valid/path/to/actual/file/image.png (38,64): Invalid character. (1127)
/valid/path/to/actual/file/image.png (38,64): Argument expression expected. (1135)
/valid/path/to/actual/file/image.png (38,64): Unterminated string literal. (1002)

Basically it seems it's trying to interpret the file as .js. I've tried defining the gif module as well like the following to no avail.

src/@types/images/index.d.ts

declare module '*.png' {
  const png: any;
  export default png;
}

The only thing I can do to get it working is override the require.extensions assignment for each extension and silence it. Unfortunately, this is a pretty big hack IMO.

I'm not really sure what else to dig into here. Any thoughts?

question

Most helpful comment

Also, TypeScript is not trying to compile the asset. Node.js is trying to compile the asset. When in doubt, please run your code without TypeScript and you'll see the same result. Node.js doesn't typically enable arbitrary requires like that unless you add a "loader" (assuming you're coming from Webpack, no one else requires images except Webpack users 😛) like ts-node (which is how you can require .ts files without it blowing up).

All 11 comments

This can't be ts-node, as ts-node never attaches to any extensions other than .js (with allowJs), .ts and .tsx. Can you share an example?

The only thing I can do to get it working is override the require.extensions assignment for each extension and silence it.

Wait, are you saying that this fixes it? Because the issue is obvious then. You've got allowJs enabled and misunderstand how node.js works. Node will always fallback to treating a file as JavaScript when it can't handle the extension.

I disabled the allowJs prop in the tsconfig, but now I get the following error:

(function (exports, require, module, __filename, __dirname) { �PNG
                                                              ^
SyntaxError: Invalid or unexpected token

This isn't the actual files, it's the require statements. But yes, overriding the require.extensions['.png'] = function(){} will stop the error and allow everything to continue running as expected, without any issues. So, it seems fairly evident to me that TS is trying to compile the png require asset.

There is a registerExtension function within the ts-node/dist/index.js. I haven't been able to really dig into that to see what it's doing, but looked potentially related.

@oojacoboo Again, this is how node works. What you're seeing is either one runtime error or the other, and 100% expected.

Also, TypeScript is not trying to compile the asset. Node.js is trying to compile the asset. When in doubt, please run your code without TypeScript and you'll see the same result. Node.js doesn't typically enable arbitrary requires like that unless you add a "loader" (assuming you're coming from Webpack, no one else requires images except Webpack users 😛) like ts-node (which is how you can require .ts files without it blowing up).

Sorry, that's doesn't seem to be accurate or correct. It seems pretty clear based on this error that TS is trying to compile the asset and throwing the errors as a result.

~/node_modules/ts-node/src/index.ts:233
        throw new TSError(diagnosticList)
              ^
TSError: ⨯ Unable to compile TypeScript
/valid/path/to/actual/file/image.png (1,1): Invalid character. (1127)
/valid/path/to/actual/file/image.png (2,1): Invalid character. (1127)
/valid/path/to/actual/file/image.png (3,1): Invalid character. (1127)
/valid/path/to/actual/file/image.png (3,2): Invalid character. (1127)
/valid/path/to/actual/file/image.png (3,3): Invalid character. (1127)
/valid/path/to/actual/file/image.png (4,5): Invalid character. (1127)
/valid/path/to/actual/file/image.png (4,6): Invalid character. (1127)
/valid/path/to/actual/file/image.png (4,7): Invalid character. (1127)
...

I tried my best to explain the issue to you. I've given you multiple steps and explained how you can re-produce it in node.js only. This is not a TypeScript or ts-node issue. Like I said in https://github.com/TypeStrong/ts-node/issues/223#issuecomment-253954359 and https://github.com/TypeStrong/ts-node/issues/223#issuecomment-253953305, TypeScript is not compiling the asset. When allowJs is enable, TypeScript is used to compile JavaScript assets. By default, node.js falls back to .js compilation when it can't understand an extension. That's exactly what happened here, the result is that TypeScript is the fallback because you're using allowJs. I've released a breaking change to try and appease you so TypeScript won't touch it anymore - https://github.com/TypeStrong/ts-node/commit/380ab99d6577a07cf8d45a5811233bf27f6362f5 - but I just remembered breaks backward compatibility too because some people are actually using ts-node like this (E.g. for bin/ scripts).

Now, if you update to the latest ts-node, you won't see any more TypeScript errors. Only the node.js error you got above. Hopefully that makes it better for you, but it doesn't change anything about the issue as node.js operates how I stated above. Just because you said something in the type system, it doesn't make the runtime true.

I'm actually really disappointed I merged this hack so the TypeScript compiler is skipped and will likely revert it at later date. I think the previous behaviour was the expected behaviour, you just didn't understand how node.js worked and wouldn't accept the explanation. If you're using allowJs, and the behaviour of node.js is to fallback to .js for compiling, why wouldn't you expect TypeScript (with allowJs) to be compiling it then? I'm going to unlock the conversation in case someone else runs into this behaviour and finds it confusing that TypeScript isn't running when it should.

@blakeembrey sorry for the frustration - not my intent. I do find this behavior quite frustrating. That said, I completely see what you're saying here. Thanks for explaining that in further detail. I wasn't aware of the Node.js fallback, although that makes perfect sense.

I was under the impression that TS, through the declare module construct, could assign a type to a particular require/module even being an image/scss file, etc. Granted, that may not prevent TS from trying to compile that as js - unsure there.

This was discussed here:
https://github.com/Microsoft/TypeScript/issues/6615

I do know I was able to compile with tsc without any errors.

@oojacoboo Right. The behaviour works like this - TypeScript is the compiler and node is the runtime. Technically you're seeing the same behaviour in ts-node, it's just two steps have been merged into one big step and it's harder to see the details.

The declare module works, because the .ts files importing the .png file is successfully compiled. However, then the node.js kicks in and it actually does the _require_ of the .png file. This is where the error you're seeing comes in - at runtime. It's why I suggested trying it with plain node and also without allowJs - so you could see how node.js treats files, and you saw it tried to execute them. Compilation is definitely successful, but the runtime is failing - these things aren't intrinsically tied together in TypeScript as you can tell the compiler one thing, when the runtime is really something else. That's what happened - you told the compile declare module "*.png" (these files are handled like this) but you never implemented the runtime side for it (until you added require.extensions, which is the node.js runtime for it - the Webpack runtime for it looks like a loader, etc).

In summary, the compilation and TypeScript is 100% correct based on what you told it. However, the runtime doesn't match up with what you told the compiler is true. I've reverted the PR I did above and tried an initial write-up in the README instead - see https://github.com/TypeStrong/ts-node#how-it-works.

(Note that this sort of runtime/compiler mismatch is quite common - the most common example is adding .d.ts files).

Was this page helpful?
0 / 5 - 0 ratings

Related issues

remojansen picture remojansen  Â·  4Comments

Borewit picture Borewit  Â·  3Comments

sanex3339 picture sanex3339  Â·  4Comments

JoseLion picture JoseLion  Â·  3Comments

dakom picture dakom  Â·  3Comments