fable-compiler / repl

Fable online REPL
http://fable.io/repl
MIT License
64 stars 37 forks source link

Feature/update dependencies #110

Closed MangelMaxime closed 9 months ago

MangelMaxime commented 4 years ago

@ncave I could need your help 🙏

I am trying to upgrade the dependencies used in the REPL and I am facing a problem.

I re-added a target which is generated the METADATA for the libraries specific to the REPL. I am still using 95% of the metadata coming from fable-metadata but because I am planning to add more I think it better to keep the specific one in the REPL directory for now. Especially, because we need to know which version of the library has been used in order to use the precompiled JavaScript etc.

You can see it here

It is running your fork of fsharp located next to the repl folder. |Here are the instructions](https://github.com/fable-compiler/repl/pull/110/files#diff-d300a8c093f5d0ef8a62d44baf18ec2c) I followed to configure your repository.

I would say this is working because the code generated between my local version of the REPL and the online version is not the same.

F# code

// More info about Fulma at https://mangelmaxime.github.io/Fulma/
module Fulma.Button

open Fable.React
open Fable.React.Props
open Fulma

type Props =
    {
        InitCount : int
    }

let counter = 
    FunctionComponent.Of(fun (props : Props) ->
        let state = Hooks.useState(props.InitCount)
        button 
            [
                OnClick (fun ev -> 
                    state.update(fun s -> s + 1)
                )
            ]
            [ 
                str "Times clicked: "
                ofInt state.current
            ]
    )

div [] [
    counter { InitCount = 10 }
] |> mountById "elmish-app"

Generated code from my local version

import { declare, Record } from "fable-library/Types.js";
import { record, int32 } from "fable-library/Reflection.js";
import { DOMAttr } from "fable-repl-lib/src/Fable.React.Props";
import { Helpers$$$mountById as Helpers$0024$0024$0024mountById, Helpers$$$ofInt as Helpers$0024$0024$0024ofInt, Helpers$$$str as Helpers$0024$0024$0024str } from "fable-repl-lib/src/Fable.React.Helpers";
import { div, button } from "fable-repl-lib/src/Fable.React.Standard";
import { uncurry } from "fable-library/Util.js";
import { FunctionComponent$$$Of$$Z5A158BBF as FunctionComponent$0024$0024$0024Of$0024$0024Z5A158BBF } from "fable-repl-lib/src/Fable.React.FunctionComponent";
export const Props = declare(function Fulma_Button_Props(arg1) {
  this.InitCount = arg1 | 0;
}, Record);
export function Props$reflection() {
  return record("Fulma.Button.Props", [], Props, () => [["InitCount", int32]]);
}
export const counter = FunctionComponent$0024$0024$0024Of$0024$0024Z5A158BBF(function (props) {
  const state = React.useState(props.InitCount);
  return button([new DOMAttr(40, "OnClick", function (ev) {
    state[1](function (s) {
      return s + 1;
    });
  })], [Helpers$0024$0024$0024str("Times clicked: "), Helpers$0024$0024$0024ofInt(state[0])]);
}, null, uncurry(2, null), null, "counter", "test.fs", 14);

(function () {
  const reactEl = div([], [counter(new Props(10))]);
  Helpers$0024$0024$0024mountById("elmish-app", reactEl);
})();

Generated code from my online version

import { declare, Record } from "fable-library/Types.js";
import { record, int32 } from "fable-library/Reflection.js";
import { DOMAttr } from "fable-repl-lib/src/Fable.React.Props";
import { Helpers$$$mountById as Helpers$0024$0024$0024mountById, Helpers$$$ofInt as Helpers$0024$0024$0024ofInt, Helpers$$$str as Helpers$0024$0024$0024str } from "fable-repl-lib/src/Fable.React.Helpers";
import { div, button } from "fable-repl-lib/src/Fable.React.Standard";
import { FunctionComponent$$$Of$$2F363EB5 as FunctionComponent$0024$0024$0024Of$0024$00242F363EB5 } from "fable-repl-lib/src/Fable.React.FunctionComponent";
export const Props = declare(function Fulma_Button_Props(arg1) {
  this.InitCount = arg1 | 0;
}, Record);
export function Props$reflection() {
  return record("Fulma.Button.Props", [], Props, () => [["InitCount", int32]]);
}
export const counter = FunctionComponent$0024$0024$0024Of$0024$00242F363EB5(function (props) {
  const state = React.useState(props.InitCount);
  return button([new DOMAttr(40, "OnClick", function (ev) {
    state[1](function (s) {
      return s + 1;
    });
  })], [Helpers$0024$0024$0024str("Times clicked: "), Helpers$0024$0024$0024ofInt(state[0])]);
});

(function () {
  const reactEl = div([], [counter(new Props(10))]);
  Helpers$0024$0024$0024mountById("elmish-app", reactEl);
})();

For example, the local version is generating import { FunctionComponent$$$Of$$Z5A158BBF while online version generate import { FunctionComponent$$$Of$$2F363EB5.

However, I am facing a problem when trying to use some code from Thoth.Json.

F# code

open Thoth.Json

type Enum_UInt8 =
    | Zero = 0uy
    | NinetyNine = 99uy

let x = Decode.Auto.unsafeFromString<string> "\"Maxime\""
Fable.Core.JS.console.log(x)

I get this error:

The requested module 'http://localhost:8080/js/repl/lib/src/Decode.js' does not provide an export named 'Auto$$$unsafeFromString$$Z33228D48'

Indeed if I look at the generated code in public\js\repl\lib\src\Decode.js I see export function Auto$$$unsafeFromString$$Z5CB6BD which is not the same name.

Do you have an idea why this is happening? What can I do to explore the problem?

gitpod-io[bot] commented 4 years ago

MangelMaxime commented 4 years ago

I don't know if this could be related but I added compiler directives in Thoth.Json to remove the code not supported by fable-standalone

https://github.com/thoth-org/Thoth.Json/commit/32c3fde07364ae6bb5a02853a1f4b1ef8468d639

ncave commented 4 years ago

@MangelMaxime Not sure exactly, could it be two different compiler versions being used? If not, have you tried using interfaces to eliminate name mangling of the exported APIs?

Also, just FYI, there is probably no need to pass the additional DLLs dependencies through the export metadata process, since they're most likely just bindings with little code. All the export does is to remove the code part in the DLL, which is probably very small anyway, so there may not be a lot of size savings there, so just use the original DLL as is (in addition to the binaries from fable-metadata).

MangelMaxime commented 4 years ago

Hum 🤔

After several days I came back to this PR and it is now working.

If I remember correctly I had the same thing happen when upgrading Fable.React library.

- Day 1: Not working - Day 2: Recompiling and working again

I suspect that there is a cache happening somewhere which either import the wrong version of the precompiled library or of the compiler. The good news is I can upgrade the libraries if I wait 1 day between the compilation and the test 😂

Will explore more ^^

alfonsogarciacaro commented 4 years ago

Not sure if it's related, but my project only showed a blank screen (without errors) after updating Fable from v2.4.11. At the end updating Paket dependencies made it work, I suspect it was Fable.Elmish.Browser.

MangelMaxime commented 4 years ago

I just remember we indeed use a service-worker.js file which controls the cache.

We don't include in when in DEBUG mode but I suspect it is still active because nonetheless.

Hum, for your error @alfonsogarciacaro it happens to me to have the black loader screen infinite and reloading the page again fixed it. I don't have yet updated Elmish dependencies in this branch was stuck with Thoth.Json but I will update the rest of the dependencies later today as it seems I am unstuck for now.

MangelMaxime commented 4 years ago

Forget all I said I was on master branch locally... 🤦‍♂️

I need to re-check everything

MangelMaxime commented 4 years ago

Ooh, maybe I say well maybe I forgot to regenerate the metadata/update the Fable.Repl.Lib.dll since updating the dependencies version.

Which would explain why it was generating an "incorrect" JavaScript code.

Going back to upgrading more library and see if I am right ^^