Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Has fable 3/elmish/react been made to work with webpack 5 or vitejs yet? Nagareyama build documentation #10

Open
tomcl opened this issue Jul 5, 2021 · 10 comments

Comments

@tomcl
Copy link

tomcl commented Jul 5, 2021

Fable 3

I'm thinking of changing my boilerplate for current fable 3/elmish/hmr/webpack 4/electron (using electron-webpack) to webpack 5. electron-webpack - currently used - does not work (and will not work) with later versions of electron so I will start with a well maintained electron-react-webpack 5 boilerplate https://github.com/alexdevero/electron-react-webpack-boilerplate/blob/master/package.json or https://github.com/electron-react-boilerplate/electron-react-boilerplate/blob/main/package.json (one of these is minimal - I could build up as needed, the other enormous) and then getting this to work with Fable/Elmish.

AFAIK Fable 3's main interaction with Webpack is the output js files which are all picked up from the top-level entry and should be trouble-free. I see more trouble getting HMR to work with Elmish but with any luck HMR working with React in an existing boilerplate would be a good start? So I'm wondering - what else will I need to consider (source maps are always an issue)?

Is this going to be a big mess? Who has working fable 3 / elmish/ webpack 5 boilerplate? I am also half-thinking I should try to use vite as bundler with vite/electron/react starting point https://github.com/twstyled/electron-vite-react but that looks riskier to me. It would be really helpful to have a complete description of fable 3 output - since I'm hoping this is pretty simple now?

On this topic - every time I try to debug fable 3 source maps (which work intermittently on my current electron build) my documentation for how to do this is a tangled set of googled posts. It might help to put this on the documentation somewhere? Unless this has been done and I'm missing something.

@alfonsogarciacaro
Copy link
Member

Updating to Webpack 5... unfortunately not as straightforward as it should be. For minimal/new Fable projects it's usually trivial. The main change is basically to use webpack serve instead of webpack-dev-server (god knows why they changed that, because you still need webpack-dev-server) but with existing projects I've got mixed results. In some, Webpack 5 works after some trial-and-error editing the Webpack config, but in others I kept getting issues and gave up. And I don't even remember what changes made Webpack 5 worked 😕 One problem is that some plugins that you need to update for Webpack 5 (like html-webpack-plugin) also have breakings changes so difficulties compound.

Same thing for HMR, in principle Elmish.HMR should work as is, but I do remember I had issues at the beginning when updating to Fable 5 and at some point it started working again but I'm not entirely sure why 😞

About source maps, since Fable 3.1 the only thing you need to do on the Fable side is to pass the -s option to the CLI command. On the Webpack side you also need to add the source-map-loader (this was not needed before because source-maps went through babel-loader). But again, it has worked for me in some projects and not in others without any obvious difference in the config...

Now that SAFE 3 is released, it'd be nice if someone could sit down, update a Fable 3 project to Webpack 5 and write down the steps in a recipe. BTW, for Electron I'm thinking that you may not even need Webpack as you don't need to bundle the JS as we do for the web (if I'm not mistaken), so it could be a good idea to try one of these non-bundle build tools like Vite or Snowpack. Or maybe you don't need anything, just a tag like the one below pointing to the generated JS main file and the Fable watcher. But I'm not sure if HMR works this way 🤔

<script type="module" src="build/App.js"></script>

@MangelMaxime
Copy link
Member

MangelMaxime commented Jul 6, 2021

One possible source of problem with Fable 3 and HMR is that Fable 3 write to the JavaScript files even if the complication of this file or another files fails.

At least, this is the impression I have but I need to make some tests one day (when I have the time).

Edit: HMR does work with Fable 3 and Elmish.HMR it is just that in case like that HMR is triggered with an invalid JavaScript / Project causing the app to crash so often you need to reload the app.

@tomcl
Copy link
Author

tomcl commented Jul 6, 2021

Thanks! I am looking at Vite, it seems a very good fit for electron and maybe will be a good deal faster than webpack. One thing I am not sure is what type of hot loading does Elmish.Hmr support. Vite supports (via plugin-react-refresh) react fast Refresh.

I have a 17K line F# app (not counting libraries) so faster dev loading would be useful.

If Vite proves too difficult I will work through Webpack 5.

But now the title of this issue is I guess wrong - I'll add to it.

I realise I also don't quite understand how source maps work - Vite uses them and maybe it is the same format as is used by source-map-loader, or maybe not. So that might not be compatible.

I will report back here when I have got some sample stuff working (or not)!

@tomcl tomcl changed the title Has fable 3/elmish/react been made to work with webpack 5 yet? Nagareyama build documentation Has fable 3/elmish/react been made to work with webpack 5 or vitejs yet? Nagareyama build documentation Jul 6, 2021
@MangelMaxime
Copy link
Member

One thing I am not sure is what type of hot loading does Elmish.Hmr support. Vite supports (via plugin-react-refresh) react fast Refresh.

Elmish.Hmr supports Hot Module Replacement and not React fast refresh. React fast refresh is an evolution of HMR considered to be "better" when IHMO it is actually worse. React fact refresh needs you to write your code in a specific way, expose only React component from your file, have your React component start with an upper case letter, etc. Basically, you need to write code even more specific for it to work which IHMO is stupid. I mean, you should not have to write a code in a that specific way for a tool to help you 🤷‍♂️

I made some experimentation and analysis in the past. My observation are noted inside of this issue: Zaid-Ajaj/Feliz#157 (comment) (I linked the main comment but the whole thread can be useful).

However, the good news is Vite does expose the standard HMR API: https://vitejs.dev/guide/api-hmr.html

The less good news, is that Vite seems to expose the HMR API at another point than Webpack and Parcel does import.meta.hot versus module.hot for Webpack / Parcel.

I already need to make a patch to support Parcel lack of support of status API. So I will add it to my To-do of updating Elmish.HMR to support Vite, WebPack, Parcel API.

So in summary, don't focus to much on HMR support for now as more work is needed upstream for your project to support it. Unless, you want to fork Elmish.HMR temporally for your project.

I realise I also don't quite understand how source maps work - Vite uses them and maybe it is the same format as is used by source-map-loader, or maybe not. So that might not be compatible.

Source maps is a standard format so, if you hook them up correctly into Vite they should work the same as in the browser, VSCode, etc.

@alfonsogarciacaro
Copy link
Member

Thanks a lot for the comments @MangelMaxime. Ah, you're right with Fable 2 the fable-loader would tell Webpack if there were errors in the compilation so the bundle was not updated, but Fable 3 updates the JS files anyways triggering a new bundle. Hmm, maybe we should add the option to prevent updating files if there are errors, or just do it by default? Actually it's a bit annoying for example with Rider which saves files automatically

@MangelMaxime
Copy link
Member

@alfonsogarciacaro IHMO the default should be to write the files only if the compilation succeeded. It would avoid HMR, watcher (like nodemon) or even bundler from triggering for "nothing".

Actually it's a bit annoying for example with Rider which saves files automatically

Yep, I discover that today. I am not sure why they save the files automatically like that.

But Rider is not the only case where this can happen, for example I often save the files even if it is not complete. Or when modifying several files at the same times, it often happen that the project is not compiling yet.

@alfonsogarciacaro
Copy link
Member

@MangelMaxime I've release Fable 3.2.9 which will skip Fable compilation (and thus reprinting JS files) in watch mode if there're F# errors, could you please give it a try?

Files will still be reprinted if there are Fable errors (e.g. unsupported dotnet methods) but this required more code changes and I preferred not to do it given that I always break something when I touch the watcher. F# errors should covert most of the cases anyways.

@MangelMaxime
Copy link
Member

Sure, I will give it a try.

Files will still be reprinted if there are Fable errors (e.g. unsupported dotnet methods) but this required more code changes and I preferred not to do it given that I always break something when I touch the watcher. F# errors should covert most of the cases anyways.

Well Fable errors should be less common indeed. I understand your worries, perhaps we can plan it for Fable 4 as this will have beta version etc helping us identify regression.

@MangelMaxime
Copy link
Member

@alfonsogarciacaro It seems to be working as expected when using nodemon.

I don't have time to test with an application with HMR right now but it should be the same result :). I will check it when working on updating Elmish.HMR to support other bundlers

Thank you very much.

@alfonsogarciacaro
Copy link
Member

Thanks for checking @MangelMaxime! I'm also checking it in another project and seems to work fine with Elmish HMR. Interestingly saving with errors still triggered new Webpack builds and I realized it was because I'm using source maps and the source map loader is adding the F# sources as dependencies to Webpack. But even with that, as long as there are no actual JS changes the bundle doesn't change and the web page doesn't break (it just stays the same).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants