quarkusio / quarkus

Quarkus: Supersonic Subatomic Java.
https://quarkus.io
Apache License 2.0
13.53k stars 2.61k forks source link

Automatic browser LiveReload support on non-class changes (html, js, css..) #1418

Open fbricon opened 5 years ago

fbricon commented 5 years ago

I already mentioned it in zulip some time ago, but apparently forgot to open an issue so here goes: in spring boot, if the spring dev tools dependency is available, a livereload server instance is started. changes to files trigger a livereload event that makes all clients (i.e browsers) to refresh automagically.

Now, in quarkus, if you could listen to a "classloader was reloaded" event, you could tell a livereload server to propagate the reload event to all clients, when java files are changed, so you wouldn't need to manually refresh the browser (it's way much cooler to perform a demo when multiple screens are connected to the same server). Listening to non-class changes could also trigger the reload (i.e html, js, css...)

danielpetisme commented 5 years ago

Same idea #1410

gsmet commented 5 years ago

So, I'm not sure it's a good thing for Java files (some people were concerned about reloading partial changes that wouldn't compile and generate a lot of noise in the log...).

But I think we should do it for static resources as you could at least do the CSS changes in live.

fbricon commented 5 years ago

That's why I mentioned the "classloader was reloaded" event

Sanne commented 5 years ago

I love it conceptually, but we'll need to address another design aspect too:

the "reload" operation today is waiting for some kind of trigger. We don't want to "reload" the whole app just because a single file changed, especially as a change might be in progress - and not ready to be compiled yet.

So today the browser refresh is actually the event that triggers re-compile, process it all, reload the app ..

If it's not the browser, what should it be? A git commit hook maybe? a button in your IDE? I'm thinking it could be the "touching" of a specific file, so that people can hook in anything they like.

Another alternative would be to have Quarkus watch the file changes, and simply keep trying - to only reload when there are no compilation errors. But would people like this? You'd have no feedback at all on mistakes.

N.B. I usually don't use the browser so I'm not at all defending the current design as I'd love to use it without necessarily having a browser open ;)

@stuartwdouglas is the master of puppets here.

fbricon commented 5 years ago

One would have to check how springboot handles it, but I imagine one solution could be:

It might not be perfect, but will prolly handle more than 80% of the use cases. And you could still add a flag to disable the behavior

geoand commented 5 years ago

Honestly I find the Quarkus approach to live reload much more intuitive for developing APIs that what Spring Boot does. It just seems to fit the API developer workflow like a glove!

Personally the only thing I would like would be to have reload work for event based applications as well.

Reloading the web assets can certainly be done using the current approach as Stuart has demonstrated in an old PR.

stuartwdouglas commented 5 years ago

We could certainly offer it as an option and see how it actually works in practice, however I would also want to keep the current behaviour.

The issue is picking a value of X that makes sense for the poll time and the 'wait X ms logic'. If you make this a small value then the FS is being hit constantly, which can impact IDE performance. If you make this a large value then when you refresh there is a good chance you will see out of date content.

I also think that livereload makes way more sense than CSS + HTML than it does for java. When modifying these assets the changes are likely visual, so when the browser updates you can see the effects immediately. With Java backend code you often need to hit a button or perform some other action to see the result. Depending on how stateful your app is auto reloading could actually be a drain on productivity.

vorburger commented 5 years ago

Personally the only thing I would like would be to have reload work for event based applications as well.

641

geoand commented 5 years ago

Personally the only thing I would like would be to have reload work for event based applications as well.

641

True, but I also had Kafka messages in mind :)

emmanuelbernard commented 5 years ago

A couple of ideas:

  1. adding other input as the trigger for live reload (like websocket) is likely our main way forward
  2. as part of the discussion around front end development support (with resources hosted by quarkus), then indeed the hook to livereload makes sense but indeed we need to filter which resource trigger that vs which does not (like java files)

It's a bit unclear to how to best address 2.

dector commented 2 years ago

Is it possible to re-use some existing Quarkus file watching mechanism in a reactive way to detect if source files or resources were changed? Or it's not yet possible and we need to implement our own file-watcher for now?

Sanne commented 2 years ago

@dector probably best to ask on zulip [https://quarkusio.zulipchat.com/#narrow/stream/187038-dev].

I think you could use WatchServiceFileSystemWatcher but it's not meant as public API - @stuartwdouglas might know about something better.

I'd also question why you need it? In general Quarkus just rebuilds it all, as we can do it quickly.

dector commented 2 years ago

@Sanne thanks for your reply!

Currently I'm evaluating quarkus as my next main BE development stack for small/medium project. I'm quite impressed with it's functionality and simplicity ("hardcore enterprise" nature is still very obvious here and there but in acceptable amounts for now).

At the current point one thing I'm missing - proper live reload. Classes hot reload works awesome BTW but development UX is much more pleasant in my case if I don't need to refresh browser manually. So I've implemented live reload using web socket on BE + Violentmonkey script in browser. But I'm using additional dependency for recursive file-watching. Would be nice to be able to remove this dependency if quarkus has some native functionaly for file-watching.

Demo

Sanne commented 2 years ago

I must say it looks awesome.

There's a conceptual problem with such an approach though: often one single consistent "patch" requires changes in multiple files to compile successfully - if you trigger a live reload just after a single file has changed, you might not have all the changes yet - this would most likely result in a sequence of reload events, some of the intermediary ones failing as the project won't necessarily compile.

Please see https://quarkusio.zulipchat.com/#narrow/stream/187038-dev/topic/.22real.22.20live.20reload

geoand commented 2 years ago

As @Sanne mentioned, the Zulip Thread contains a lot of details about why we would not want to change the live reload feature, so I'll close this broad scoped issue as won't fix. We can of course consider improvements (@Ladicek has something in mind in the Zulip thread) but it would be best to have topical issues for those.

Sanne commented 2 years ago

Actually we'll re-open as @fbricon also suggested the browser could trigger live-reload on web resources.

That's still an applicable improvement which sound very useful - I'll change the title to reflect.

dector commented 2 years ago

There's a conceptual problem with such an approach though: often one single consistent "patch" requires changes in multiple files to compile successfully

@Sanne that's true. My solution was intended to create short feedback loop for changing templates (BTW Qute seems like the best template engine I've ever worked!) - I'm using Tailwind and such primitive live-reload helps me to experiment/iterate on design very quick. It was quite easy to implement and is very helpful in my case. Most probably I'll need to extract file watcher into separate utility because now live-reload doesn't work if website can't be compiled.

@Sanne @geoand thanks, I'll check the thread

blazmrak commented 10 months ago

I use gulp + browser-sync for this. I know that this isn't a Quarkus solution, but it works quite nice for me, because I have to have tailwind installed anyways. It basically just starts a proxy to your server and listen to file changes. Each time the change is detected, the browser will reload the page after some delay.

  1. install the dependencies:

    npm i -D gulp gulp-cli browser-sync
  2. confirm that gulp cli works

    npx gulp --version
  3. Create gulp script (edit the glob pattern in gulp.watch to match your project)

    
    // gulpfile.js

const gulp = require('gulp'); const browserSync = require('browser-sync').create();

exports.build = gulp.task('sync', function() { browserSync.init({ proxy: { target: 'http://127.0.0.1:8080', // this is the server, localhost didn't work for me for some reason }, ui: { port: 3003 }, // UI, can be any port reloadDelay: 200 // Important, otherwise syncing will not work }); gulp.watch([ '../public//*.js', '../public/*/.html', '../public//*.css', '../src/main/**', ]).on("change", browserSync.reload); });



4.  Run `npx gulp sync`.
vorburger commented 10 months ago

Regarding:

Most probably I'll need to extract file watcher into separate utilit

and:

I think you could use WatchServiceFileSystemWatcher but it's not meant as public API - @stuartwdouglas might know about something better.

Just FYI https://github.com/vorburger/ch.vorburger.fswatch in case that could ever be of any interest to anyone in this context? (Not https://github.com/vorburger/ch.vorburger.exec as originally posted, that's unrelated; I got mixed up.)

stuartwdouglas commented 10 months ago

WatchServiceFileSystemWatcher was copied directly from XNIO, it should be fine to use, but it certainly not something we ever claimed was a stable API. It's only one class though so if anything ever did change you could just copy it.

simasch commented 5 months ago

I did some experiments with JSF (Primefaces) and Quarkus and the browser reload is really missing when working on the xthml and CSS files.

maxandersen commented 5 months ago

context: https://twitter.com/maxandersen/status/1767655187819225330

@ia3andy didn't you do something in the area of handling updates to js/css/html ? feels like we at least should be able to offer trigger browse livereload for some resources...possibly adopt https://github.com/38leinaD/quarkus-livereload-extension to more recent version ?

mstahv commented 5 months ago

Remingind you @maxandersen that we discussed this a while ago when we were finishing the Vaadin integration. The dev mode in Vaadin does exactly that, automatically reloads the browser that web developers usually have on a second screen on "hot reload"/save/compile (in Spring Boot with Dev Tools or with basic servlet/CDI apps using JRebel/HotSwapAgent). Excellent for productivity as one don't need to leave the IDE to see changes in the UI (potentially on multiple screens/windows/devices). This is proably why @simasch has this level as gold standard, although he right now seems to be on the "dark side" with JSF 🤓

IIRC there was nothing in place where the Vaadin devmode could have connected as all checks for new changes are done lazily when a request starts in Quarkus dev mode. But if this has changed/will change, there we have a project with requirements 🙋‍♂️

simasch commented 5 months ago

@mstahv it is not the dark side. It makes me reminisce 😅

But you are right I use Vaadin with JRebel and that sets the bar high.

maxandersen commented 5 months ago

@mstahv yes, I fully get the value on it. having participated in implementing reload and livereload support for JBoss in Eclipse eons ago I get the value - just that quarkus default focus (good UX for backend dev where we only spend cycles on actual request) the "refresh browser pro-actively" have not been done. @simasch tweets made me realize we could do it without changing the default ux by doing something akin to how browser-sync does it. might not be 100% incremental as some state might be lost - but at least the browser does refresh and reloads on updates.