javascripthtmlwebpackes6-modules

import.meta.url emits file:/// rather than http://?


I've read the docs of import.meta.url saying :

The full URL to the module, includes query parameters and/or hash (following the ? or #). In browsers, this is either the URL from which the script was obtained (for external scripts), or the URL of the containing document (for inline scripts). In Node.js, this is the file path (including the file:// protocol).

I created a simple React app with this code:

console.log(import.meta.url); //here
export function App() {
  ...
  ...
  console.log(import.meta.url); //also here
  ...

Then I created assets (js, css, html) via npm run build (webpack etc.) and deployed them in an Nginx Docker container.

However, when I run the code, I get this:

enter image description here

Question:
Why do I see file:// instead of http://? It's not in node mode, and it is a module (App.tsx) is a module .


Solution

  • By default Webpack will replace the value of import.meta.url with the module's file: URL at build time. You haven't stated what version of Webpack you are using, but support for allowing dynamic import.meta.url values was added in versions >= 5.68.0 via PR 15246 as a result of issue 14445.

    To disable Webpack replacing import.meta.url at build time with the module's associated file: URL update your configuration:

    module: {
      parser: {
        javascript: {
          importMeta: false,
        },
      },
    },
    

    Here is the documentation for enabling or disabling evaluation of import.meta at build time.

    You can see an example of a build configuration that uses this and returns the value of import.meta.url you want: https://github.com/morganney/import-meta. This is also hosted on GitHub pages at https://morganney.github.io/import-meta/

    Why?

    This is a design question, and as such you're better off asking the designers, however, I'll offer a possible reason.

    Webpack supports different targets. One of those is node and Node.js supports CommonJS and ES Modules. There is no equivalent of import.meta.url in CommonJS which was supported before ES modules and that may be why it is rewritten during the build by default, because you may be targeting a CJS environment. Moreover, you may be targeting web where some browsers do not support native ES modules.

    Other bundlers like rollup and swc have had to go through a similar process of how to deal with import.meta.url in various contexts. Thus, there are configuration options to tell Webpack how to handle import.meta.url during a build. Having an explicit option for this, rather than trying to infer it all from your target and/or browserslist file was probably a more reliable way to proceed with easier to maintain code, but you should ask the maintainers for a more definitive reason "why" they chose this design.

    What does webpack do that it still fetches chunks of js and still those chunks show file:/// when they are lazy fetched?

    It is the Webpack source code on GitHub. Referenced from the issue I mentioned above. Within lib/dependencies/importMetaPlugin.js: https://github.com/webpack/webpack/blob/main/lib/dependencies/ImportMetaPlugin.js#L99