Fable: Recompile dependent modules in Fable 3 during watch mode

Created on 26 Oct 2020  路  11Comments  路  Source: fable-compiler/Fable

Description

I am not sure whether this is a regression to the way Fable 3 handled watching compilation but it seems that when editing file ModuleA.fs which in used in ModuleB.fs, that ModuleB is not recompiled and the changes do not propagate to the used bundler.

Currently I have to manually go to ModuleB.fs, add a space somewhere and save the file in order to see changes.

acties

Related information

  • Fable version: 3.0.0-nagareyama-beta-003
  • Operating system: Windows 10

All 11 comments

Actually, Fable 2 didn't have a watcher (only fable-splitter had one) we just relied on Webpack one. We did build a dependency tree for the dependencies that Webpack "couldn't see": inlined functions and overload suffixes. In the new watcher we are using the same dependency tree, which means changes in one file don't necessarily trigger the recompilation of all the dependent ones, as most of the times the imports don't change.

Which bundler are you using? I got a bit excited about the possibility of using Parcel, but I'm testing now Webpack 5 and it actually seems to be faster. If I have the following dependencies: Main.fs < ModuleB.fs < ModuleA.fs, when I touch ModuleA and ModuleA.fs.js gets recompiled, the Webpack serves catches it and correctly refreshes the bundle even if Main.fs.js and ModuleB.fs.js haven't changed.

I am doing all my testing right now with parcel because this "no config" thing is really addictive so many things already built-in and taken care of, but of course only when it actually works 馃榿 I will need to test why parcel isn't recompling Main.fs.js and whether it is a Fable problem.

Ideally, parcel support would be really awesome!

Hmm, with Parcel I get similar results in my simple example: there's no need to recompile all the files for the bundler to be refreshed. Would it be possible to set a repository to reproduce the issue? I wrote an issue in the Parcel repo about the watcher, but probably it's not related.

Would it be possible to set a repository to reproduce the issue?

I can make one

@Zaid-Ajaj did you made any progress with parcel?
While most of it works fine for me, including fast refresh without reloading the page, it's not preserving the state of the components during refresh.

@marcpiechura What version of parcel are you using? latest beta doesn't work properly, but the nightly does (maybe nightly 443?) I have managed to make it work but there are some edge cases that break react-refresh such as defining record types in a module that uses them (especially when used as props for []) they have to defined in another module in a _different_ file or you can use anonymous records instead.

Right now tracking this issue down in Using extended classes for props doesn't get picked up by react-refresh but the solution is not clear yet.

You can try webpack using configuration specified in this template SAFE.React, however the record type limitations still persist :/

@Zaid-Ajaj thanks a lot for the version hint. Turned out I had a global parcel version 1.x installed and it used this one instead of the local one. Now everything works fine with the local nightly build 馃憤

I believe this is no longer an issue, at least I don't see it anymore in latest :smile: will close the issue

It's worth noting that I fixed another issue reported to me directly to recompile dependent files when the order of union cases changes. Maybe your problem was related. In any case, there are probably still situations where there are no imports but we still need to recompile some files because of changes, if you find one of these please let me know!

Hey @alfonsogarciacaro

I have the exact same issue in fable 3.1.1 and 3.1.7 (the ones I tested) not picking up [

To reproduce, in my case:

// bindings.fs
  ... axios bindings ... 

    [<AllowNullLiteral>]
    type AxiosInstance =
        [<Emit "$0($1...)">]
        abstract Invoke : config: AxiosRequestConfig -> AxiosPromise

        [<Emit "$0($1...)">]
        abstract Invoke : url: string * ?config: AxiosRequestConfig -> AxiosPromise

       .... 
        abstract get : url: string -> Promise<'R>

        [<Emit("$0.loadsaf($1, $2)")>]
        abstract getc : url: string * config: obj -> Promise<'R>

        abstract delete : url: string * ?config: AxiosRequestConfig -> Promise<'R>
        abstract head : url: string * ?config: AxiosRequestConfig -> Promise<'R>
        abstract options : url: string * ?config: AxiosRequestConfig -> Promise<'R>
        abstract post : url: string * ?data: obj * ?config: AxiosRequestConfig -> Promise<'R>
        abstract put : url: string * ?data: obj * ?config: AxiosRequestConfig -> Promise<'R>
        abstract patch : url: string * ?data: obj * ?config: AxiosRequestConfig -> Promise<'R>

  .... more axios bindings
// App.fs, the consumer file

let main () =
    // ()

    promise {
        printfn "Comen莽ant request..."

        let! res1 = Axios.axios.get ("some api")

        console.log (res1?data)

        let! res2 = Axios.axios.getc ("some other api", {| ``params`` = {| attributes= "id"|} |})

        console.log (res2?data)

    }

As you can see I'm trying to provide an alternative method to axios.get. All I know is that it doesn't recompile only when changing the Emit attribute.

If, for example, I add a let add x y = x + y function it will recompile, the same happening whenever changin the App.fs. But sadly not whenever changing the emit attribute.

Shall I add another issue?

Thanks for reporting @not-rusty! I've added a fix to add files with Emit (and also Import) attribute to the watch dependency tree, and I will include it in the next release. There may be more similar cases when code from one file is inlined into another but it's not recompiled during watch compilations, but I hope we're narrowing down most of them. Unfortunately for literals I couldn't fix it, because F# embeds directly the value into the AST and doesn't give you a reference to the source, so if you've something like let [<Literal>] foo = 5, changing the value won't trigger recompilation of dependent files (unless there's something else that causes the file to be included in the dependency tree).

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ncave picture ncave  路  3Comments

alfonsogarciacaro picture alfonsogarciacaro  路  3Comments

rommsen picture rommsen  路  3Comments

alfonsogarciacaro picture alfonsogarciacaro  路  3Comments

jwosty picture jwosty  路  3Comments