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

Add hot reloading #2095

Closed
wants to merge 1 commit into from
Closed

Add hot reloading #2095

wants to merge 1 commit into from

Conversation

rogueg
Copy link
Contributor

@rogueg rogueg commented Nov 26, 2016

When a tag gets re-defined (eg riot.tag2), the hot reloader looks through DOM, finds every instance of that tag, and replaces it.

Replacing tags goes through the full lifecycle: the old instance is un-mounted, and the new instance calls the constructor and mount callbacks. Hot reloading will preserve the tag's original attributes, yields, and state.

If you need to do anything custom before or after the reload, you can use the callbacks:

riot.util.hotReloader.on('before-unmount', () => /* some cleanup */)
riot.util.hotReloader.on('after-mount', () => /* some setup */)

This is useful when you have 3rd party libraries that do DOM manipulation.

Here's a gist on using it with Gulp:
https://gist.github.com/rogueg/4d48d32bd678aba784455ef8685c4494

When a tag gets re-defined (eg `riot.tag2`), the hot reloader looks through DOM, finds every instance of that tag, and replaces it.

Replacing tags goes through the full lifecycle: the old instance is un-mounted, and the new instance calls the constructor and mount callbacks. Hot reloading will preserve the tag's original attributes, yields, and state.

If you need to do anything custom before or after the reload, you can use the callbacks:
```
riot.util.hotReloader.on('before-unmount', () => /* some cleanup */)
riot.util.hotReloader.on('after-mount', () => /* some setup */)
```
This is useful when you have 3rd party libraries that do DOM manipulation.

Here's a gist on using it with Gulp:
https://gist.github.com/rogueg/4d48d32bd678aba784455ef8685c4494
@GianlucaGuarini
Copy link
Member

@rogueg thanks for your pull request but I would like to create another repo called riot-hot-reload instead of adding a new riot bundle in the main repo only for this feature, what do you think?

@rogueg
Copy link
Contributor Author

rogueg commented Nov 26, 2016

I considered that, but the hot-reload code is tightly coupled to riot. Putting them in the same repo makes it easy to ensure that you always have the right version.

Setting up a new repo is a hassle, making a build, test setup, npm package, etc. Could you elaborate on the advantages of a separate repo?

@GianlucaGuarini
Copy link
Member

I consider hmr an additional feature to riot but not part of the core. I have never seen other libs adding new bundles just to handle this feature see also:

https://github.com/vuejs/vue-hot-reload-api
https://github.com/gaearon/react-hot-loader
https://github.com/AngularClass/angular2-hmr

I am just afraid to have too many riot bundles to maintain in the same repo, now we have: riot, riot+compiler, riot.csp and riot.es6.

I would rather prefer to give the access to internal riot APIs to handle this feature in an external script in another repo that our users could eventually install via npm.

I would like to hear also the opinion of the other @riot/core-maintainers on this

@rogueg
Copy link
Contributor Author

rogueg commented Nov 26, 2016

React native is an example of a lib that includes hot reloading. Most projects you reference are Webpack-specific, but thats not what this PR is.

I feel like the goal is to make hot reloading just work for our users, and this does that. I still don't see any advantage to a separate repo.

@cognitom
Copy link
Member

I'm waiting the team of Rollup supports hmr... rollup/rollup#50

BTW, I have no preference to include it or not. Could it be a option to include it in the loader module together? riot/loader or something for webpack basically.

@aMarCruz
Copy link
Contributor

Brunch handles HMR with

if (module.hot) {
  module.hot.accept(module, callback);
}

https://github.com/brunch/hmr-brunch

@GianlucaGuarini
Copy link
Member

@rogueg I would like to move your code here https://github.com/riot/hmr providing a simple api that anyone could use independently form the bundler they are using.

@ptb ptb mentioned this pull request Dec 20, 2016
@rogueg
Copy link
Contributor Author

rogueg commented Dec 21, 2016

All this code does is expose a small, optional API that allows for replacing tags at runtime. It doesn't do HMR (there aren't even modules!), and it isn't specific to any particular build tool.

Most users will never interact with this API directly. @GianlucaGuarini you mention that users could "install it via npm", but that shouldn't ever happen. Instead, the API will be used by the various build tools: gulp-riot, riotjs-loader, riotify, etc. When the user sets up one of those, they get hot-reloading for free, without any additional configuration.

Once this PR gets merged, we need to make PRs against all those build tools to use this API. Only after that happens will our users actually be able to benefit from hot reloading.

Hot reloading is tightly coupled with the internals of riot. This hot-reload code (for riot@3.0) won't work with riot@3.1. Putting them in the same repo ensures that you'll always have matching versions.

@GianlucaGuarini
Copy link
Member

GianlucaGuarini commented Dec 21, 2016

@rogueg I have tried your patch with a simple example here and I've got some issues. That's exactly the reason I would like to have it into its own separate repo to create a solid and specific unit test only for this feature and to avoid to overlap its issues with the ones riot specific. @ptb seems to have made already a pull request on riot-hmr that could be also renamed riot-hot-reload. I am not concerned about the versioning because riot uses already semver for all its own submodules observable compiler...

Side note: I really like the @rogueg approach because it magically works, but I guess that a more explicit api could be better suitable to the current increasing complexity of the frontend stacks allowing our users deciding by themselves when a tag an which one should be reloaded

@rogueg
Copy link
Contributor Author

rogueg commented Dec 21, 2016

Seems like your example code itself is causing the issue. If you change each={ item in to each={item in (that space matters) it works fine.

FWIW, this commit does add tests for hot reloading.

@GianlucaGuarini
Copy link
Member

@rogueg ok sorry I made a mistake here you can check the updated example http://plnkr.co/edit/5jx5T1iK0LeS2EiQbPBI?p=preview and as you can see the { message } seems to be not properly updated.

@rogueg
Copy link
Contributor Author

rogueg commented Dec 22, 2016

It's working as intended. this.message is state, and we preserve it across a hot-reload. If you imagine that message was something we entered in a text field, it makes sense why we'd want to keep it.

My understanding is that React and Vue do the same thing.

@GianlucaGuarini
Copy link
Member

Ah ok nevermind I guess the message should be the same because the tag is inheriting it by the previous old tag so think that's fine. I will bring this patch into a separate repo providing it as riot optional dependency. @rogueg what kind of name do you prefer? riot-hot-reload ?

@rogueg
Copy link
Contributor Author

rogueg commented Dec 22, 2016

Sounds fine to me.

@GianlucaGuarini
Copy link
Member

@rogueg thank you so much for this patch I really like it

@GianlucaGuarini
Copy link
Member

the @rogueg patch was published as separate riot module and it's already being used in our official webpack loader I am closing this pull request

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

Successfully merging this pull request may close these issues.

None yet

4 participants