NodeJS import file with the same name as a folder

Viewed 683

I have the following file structure: ([] are folders)

[MySQL]
   ConnectionPool.ts
   Connection.ts
MySQL.ts

In my code, I am using typescript to develop the app, which will be built to javascript for the production version. The development version is tested directly from the uncompiled typescript files, using babel with the following configurations:

{
    "presets": [
        ["@babel/preset-env", {
            "targets": {
                "node": "current"
            }
        }], 
        "@babel/preset-typescript"
    ],
    "plugins": [
        "@babel/plugin-transform-runtime", 
        [
            "module-resolver",
            {
                "alias": {
                    ... list of some aliases
                }
            }
        ]
    ]
}

My problem is the following, I do most of my imports like this:

import ConnectionPool from 'MySQL/ConnectionPool`

which works for me, as when I run my dev code, the compiler correctly identifies the file extension to .ts, and it also correctly identifies the built versions file extension to .js.

But if I want to import my MySQL.ts file, I can't do it this way, as I will get the following error: Error: Cannot find module './'. If I specify in my import statement the file extension, everything works correctly, but then, when I build my code, there will be no more .ts files in there, so I will get errors there.

Strangely, on the frontend, where I use webpack, I get no complaints about importing files without extension whose name is the same as a folders name in the same directory. What solutions do I have for this issue, which does not revolve around renaming my files or folders in the structure?

5 Answers

Rename your file MySQL.ts to index.ts and move it into the folder MySQL

In the meantime, I resolved my problem by explicitly specifying .ts as the file extension, and when building the code, using the babel-plugin-transform-rename-import to replace the .ts extensions to .js extension.

I won't accept this as the correct answer, as this is too hacky for me, so if a better solution comes up, I am still open for it.

I don't believe what you want to do is possible, node will automatically include either the file or the directory but if both of them are called the same thing node will have no idea which one to import and it will always prefer one over the other.

Using import Example from 'example' will have node search either for any files called example.js or directories called example with an index.js and it will only load one of them.

The reason webpack does it correctly is because webpack will never bundle a "directory", it will take what you've specified as an import and try all of the resolves extensions until it finds one and then it will import that file, so you'll never have conflicting files with directories with webpack.

I thought maybe a solution is to use aliasing in your typescript config so that you can use import Example from '@example' and differentiate between your directories and files that way. Then you can also do import Example from 'example' if you just want to load the file itself. But even then I don't think that will even work because once it gets compiled to javascript you'll just have the same issue as before with conflicting paths.

That being said, while I understand being a little bit obsessed with naming conventions and small things, I really don't think you should be storing "mysql" outside of the "mysql" directory, for two reasons. The first reason is that it's part of that directory, that's what that directory is for, it contains the "mysql" stuff, so why would you want to store it outside. Secondly using a "index.ts" communicates something to other developers, when I open up a new project or directory I'm immediately looking for something called "index.ts" or similar, otherwise I have no idea where to even begin. Using "index.ts" is a good way to communicate to anyone that "this file right here is the one you're looking for, everything starts here". That being said, just call it index.ts and store it where it belongs.

You can try in your tsconfig.json to set moduleResolution to the classic strategy:

{
  "compilerOptions": {
    "moduleResolution": "classic"
  }
}
Related