Skip to content

How does JavaScript import find the module without an extension?

I understand that we can use import {x} from "./file" and a variable x will be imported from file.js in the same directory. How is this handled if there are files of the same name with different extensions in the directory?

For example, if there were file.js and file.ts in the same directory, how would import {x} from "./file" behave? Would it depend on the version of JavaScript?

Answer

Would it depend on the version of javascript?

No, it depends on the behavior of JavaScript runtime, that is, the thing that executes your script.

In a browser with support for ES Modules (ESM), no extensions will be added to the URL that you import – if your file for example has .js extension, you have to write import {x} from "./file.js". Browsers have no useful way of looking up which files with which extensions are available on the server.

In browsers without native support for ESM, you have to transpile your modules to a bundled format which can run in browser. In this case, it depends on the behaviour of the specific bundler you choose to use (see below).

In Node.js versions which support ESM, the runtime will not search for extensions, but it will resolve modules from node_modules by name. For example import 'lodash' could resolve to ./node_modules/lodash/index.mjs, without you needing to know that the extension of index.mjs.

In Node.js versions which do not support ESM, you can’t use import – you have to transpile the module to CommonJS format first, which will end up using require. require has a list of extensions that it will search the filesystem for.

For example, if there were file.js and file.ts in the same directory, how would import {x} from "./file" behave?

It depends.

When you transpile or compile your script, which extensions are recognized depends on the compiler and the settings you provide for compilation.

In webpack, for example, there is predefined list of supported extensions – ‘.wasm’, ‘.mjs’, ‘.js’, ‘.json’, but it could be changed by using resolve.extension setting in your webpack.config.js file.

If you use webpack with ts-loader plugin, .ts file extension is also recognized, but the loader will try to make it so that .ts file is compiled into .js file, and will try to use that compiled .js file when bundling.

If you use plain typescript compiler to compile your scripts, the compiler will look for a file with ‘.ts’ extension to perform type checking, but it will generate code which will look for a file with ‘.js’ extension when you will run the script. Also, if the file with ‘.ts’ extension is compiled, the compiler will write generated code in the file with ‘.js’ extension and may overwrite your javascript file if you have one, depending on the setting which tells it where to output ‘.js’ files.