fable-compiler / Fable

F# to JavaScript, TypeScript, Python, Rust and Dart Compiler
http://fable.io/
MIT License
2.92k stars 300 forks source link

JS import helpers don't respect absolute paths #3146

Open AngelMunoz opened 2 years ago

AngelMunoz commented 2 years ago

Description

Fable seems to resolve some paths when importing javascript files that have an extension

e.g. import "FOO" "./env.js" will output something like the following

import { FOO as FOO_1 } from "./env.js";

Which is completely fine, the problem arises when one wants to import from the root of a server

e.g. import "FOO /env.js will output something like the following

import { FOO as FOO_1 } from "../../../../../env.js";

which in most cases it won't break anything but it doesn't respect how ESModule imports work in the browser.

As an Extra point if you use a dynamic import, fable doesn't follow this behavior

let fooP: JS.Promise<unit> =
    importDynamic "/env.js"
    |> fun p -> p.``then`` (fun (f: obj) -> printfn "%A" f?FOO)

will output something like

export const fooP = (() => {
  const p = import("/env.js");
  return p.then((f) => {
    const arg = f.FOO;
    toConsole(printf("%A"))(arg);
  });
})();

As you can see, /env.js is preserved in the dynamic import output which respects ESModules imports in the browser as well.

Repro code

here's a reproduction repository https://github.com/AngelMunoz/fable-repro

Expected and actual results

I expect fable JS import helpers to respect "absolute" paths because that's how ESModule import works (just like with dynamic import), relative paths can still be resolved as usual and make sense in various cases

Related information

alfonsogarciacaro commented 2 years ago

Ah ok. So far we've always been bundling the apps but I guess when using imports directly on the web it make sense to use absolute paths for the web root. Probably the fact that importDynamic doesn't change the absolute paths is actually a bug 😅 Right now Fable behaves like this:

  1. When encountering an import, if it's relative we turn it into an absolute path depending on the file doing the import (which may be different to the source file if the function is inlined)
  2. Then when putting the files in the output directory we turned the absolute imports into relative paths again based on the location of the generated file.

I guess what we need to do is "mark" absolute imports internally somehow so step 2 doesn't turn them into relative.

AngelMunoz commented 2 years ago

Given that's how it works yeah I might be reporting a different feature 😆

I guess what we need to do is "mark" absolute imports internally somehow so step 2 doesn't turn them into relative.

I agree, the web server may choose to serve something different when using absolute paths like it was our case in Perla, at my job we also have code angular/typescript code that uses this feature, so it can happen in the wild as well