evanw / esbuild

An extremely fast bundler for the web
https://esbuild.github.io/
MIT License
38.19k stars 1.15k forks source link

🐞 `import.meta.url` transpile. #2441

Open caoxiemeihao opened 2 years ago

caoxiemeihao commented 2 years ago

When i use esbuild to transpile import.meat.url in cjs format, I always don't get the correct result.

Reproduce

const result = require('esbuild')
  .transformSync('import.meta.url', { format: 'cjs' });

console.log(result.code);
// const import_meta = {};
// import_meta.url;

Expected

const import_meta = {
+ url: 'file:' + __filename
};
import_meta.url;
wdanilo commented 2 years ago

@evanw is there a solution planned for this? This prevents us from bumping versions of several dependencies, including some critical ones :(

privatenumber commented 2 years ago

You can inject it yourself:

https://hyrious.me/esbuild-repl/?version=0.15.5&mode=transform&input=import.meta.url&options=--format%3Dcjs+--define%3Aimport.meta.url%3D%27_importMetaUrl%27+--banner%3D%22const+_importMetaUrl%3Drequire%28%27url%27%29.pathToFileURL%28__filename%29%22

vnues commented 1 year ago

Is it still not resolved?

Valexr commented 1 year ago

Why this need?

SPWizard01 commented 8 months ago

We use this to dynamically determine path for import outside of javascript.

esbuild options:

...
    platform: "browser",
    format: "esm",
    bundle: true,
    treeShaking: true,
    splitting: true,
    sourcemap: true,
...

Consider this example:

function inject_style(text: string) {
  let newText = text;
  const pathSearch = new RegExp(/(\\[START_RESOLVE_PATH\\])(?<RelativePath>.*)(\\[END_RESOLVE_PATH\\])/g);
  const foundResources = text.matchAll(pathSearch);
  for (const iterator of foundResources) {
    const relPath = iterator["groups"].RelativePath;
    const replaceRegexp = new RegExp(`(\\\\[START_RESOLVE_PATH\\\\])($\{relPath})(\\\\[END_RESOLVE_PATH\\\\])`);
    const resolvedPath = import.meta.resolve(relPath);
    newText = newText.replace(replaceRegexp, resolvedPath);
  }

  const style = window.document.createElement("style");
  const node = window.document.createTextNode(newText);
  style.appendChild(node);
  window.document.head.appendChild(style);
}

in a custom plugin:

[custom esbuild plugin setup]....
      onResolve({ filter: /^__style_helper__$/ }, () => {
        return { path: "styleImporter.js", namespace: "style-helper" };
      });
      //if you pass he function as a string it will be correct, however if you pass the "function".toString() it will be "import_meta"
      onLoad({ filter: /.*/, namespace: "style-helper" }, () => ({
        contents: `export ${inject_style.toString().replace("import_meta","import.meta")}`,
      }));