How does javascript import find the module without an extension?

浪尽此生 提交于 2019-12-10 17:38:40

问题


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?


回答1:


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 node.js with ES modules enabled, there is pre-determined list of file extensions which are searched if URL in the import does not have an extension. Recognized extensions are ".mjs", ".js", ".json", ".node". Also, if the path refers to a directory, the "index" file is searched, also with various extentions.

In node.js without ES modules enabled, you can't have import in the script when it's being executed - you have to transpile it to CommonJS format first, and then the script has to use require which recognizes similar list of extensions, but without "mjs".

In browser, if it has native support for ES modules, the browser will not add any extensions to the URL you provided in the 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 ES modules, you again have to transpile any script which contains import statements, and then use some kind of bundler or module loader to run compiled scripts in the browser.

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.




回答2:


i encountered the same problem, and i SOLVED "easily", this way : URL REWRITING, what do i mean ? i'm gonna explain that from the beginning !

Here is the story, from compiled Typescript code, i wanted to obtain some ES6 code(target es2015 in tsconfig.json), in order to keep in the final code the original syntaxes: import/export that i've written in Typescript ( indeed at final, i did not want to use Module loaders for ES5 !! Because it's old school...).

The thing is that, when Typescript generates the ES6, it completely keeps intact the syntaxes : import .. from "./.../MyJSFile", so it keeps it without the ".js" extension !! And of course, in Typescript code, you can't mention the extension on an import syntax ! (it assumes it to be ".ts").

So now, i've got like you, the ES6 code generated, and containing import syntaxes that DOESN'T mention the ".js" extension of the imported files. So what is the problem ?

The problem is :

  • In order to execute such code in a browser, because it uses ES6 Modules you HAVE TO run it from a WEB SERVER (no matter which) !

  • BUT ! any Web Server won't find the files you want to import (import ... from "./.../MyJSFile"), because without extension, it says, well this resource doesn't exist ! and indeed it doesn't !! BUT what we know is that the resource "./.../MyJSFile.JS" EXISTS ! So ?? You see me coming ?

    YOU JUST HAVE TO WRITE : URL REWRITING RULES FOR THE WEB SERVER, and that's what i did to solve ! I did it with :

    • an APACHE WEB SERVER (that has a directive : AllowOverride All , in order to allow URL rewriting !!).
    • and then, i just created an .htaccess file at the root of my localhost site, in which i tell him: If the requested resource doesn't exist, then try to find (by URL Rewriting), the same resource name BUT, with a ".js" extension at the end of it ! AND IT WORKS FINE !! Here is my .htaccess in its simplest working form :

      RewriteEngine on
      
      RewriteCond %{REQUEST_FILENAME} !-f
      
      RewriteRule  ^(.*)(/[A-Za-z0-9_]+)$  $1$2.js   [L]
      

AND THAT's really all you have to do ! with an Apache Server. So keep in mind, whatever is the Web Server, the idea is : URL REWRITING !

I ALSO USED THE SAME PRINCIPLE WITH a NODE.JS WEB SERVER that i've created, here is its full tested code, it works absolutely fine (nodeJsAsWebServer.js) :

//In terminal, just run : node nodeJsAsWebServer  
//to launch this below Web Server. (CTRL+C to stop) .
//
//And then in the browser, just invoke your ES6 code 
//(via normal html call), 
//on this domain : localhost:555

//------- nodeJsAsWebServer.js ---------

const oHttpTool = require('http');
const oFilesTool = require('fs');
const oPathesTool = require('path');

const oMIMETypes = {
  'html': 'text/html',
  'css': 'text/css',
  'js': 'text/javascript',

 'json': 'application/json',

  'png': 'image/png',
  'jpg': 'image/jpeg',
  'ico': 'image/x-icon',

  'wav': 'audio/wav',
  'mp3': 'audio/mpeg',

  'pdf': 'application/pdf',
  'doc': 'application/msword'
};

let oMyWebServer = oHttpTool.createServer(function (req, res) {

  console.log("\n\n=========================================================");
  console.log("=========================================================\n");

  let sSubUrl = req.url;
  console.log("Client code asks for: "+sSubUrl);

  let sFileExtension = oPathesTool.parse(sSubUrl).ext.substr(1);    
  let sMIMEType = oMIMETypes[sFileExtension];
  console.log("Asked MIMEType="+sMIMEType);

  let sFileHDDPath = __dirname; //Real path on server hard disk
  let sFileToRead = sFileHDDPath+sSubUrl;
  console.log("FileToRead="+sFileToRead);
  oFilesTool.exists(sFileToRead, function (pbFileExists) {
    if(!pbFileExists) {
      console.log(`  - File NOT FOUND on the server!  -`);
      if (sFileExtension==="") { //If the requested URL doesn't have any extension !
        let sNewUrl = sSubUrl+".js"; //<<<<<<<<<<<< URL Rewriting
        console.log(" REDIRECTION ...(sNewUrl='"+sNewUrl+"'; ldUrl='"+sSubUrl+"')");
        res.writeHead(301, {Location:sNewUrl});//Redirect, we try to load this newURL
        res.end();

      } else { //if the URL already had an extension.
        res.statusCode = 404;
        res.end();
      }

    } else { //Normal case, when the requested resource exists.
      oFilesTool.readFile(sFileToRead, function(poError, poData){
        if(poError){
          res.statusCode = 500;
          console.log("ERROR getting file content !!", poError);
          res.end();

        } else { //We send the file whole content and with a header.
          res.setHeader('Content-type', sMIMEType );
          res.end(poData); //<<Also works for Binary files such as Image, PDF, etc..
        }
      });      
    }
  });

});


let iPort=555; //<<< choose your port on localhost.
console.clear();
console.log("Node Web Server listening on localhost:"+iPort+" ...    (CTRL+C to stop)");
oMyWebServer.listen(iPort);


来源:https://stackoverflow.com/questions/55251956/how-does-javascript-import-find-the-module-without-an-extension

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!