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

JSPM/SystemJS live-reloading hot-swapping dev server? #1

Closed
geelen opened this issue Apr 8, 2015 · 17 comments
Closed

JSPM/SystemJS live-reloading hot-swapping dev server? #1

geelen opened this issue Apr 8, 2015 · 17 comments

Comments

@geelen
Copy link
Owner

geelen commented Apr 8, 2015

Ok, this is me just starting an issue to discuss with @guybedford about where this might fit in to the JSPM landscape. It didn't seem ready to add something against jspm-cli or systemjs yet because it's really early days, but I do have something working and I'd like to get feedback.

This project is a fork of live-server which I've been using for all my dev with JSPM. It has the best collection of defaults I've seen for any 0-configuration server, and doesn't build upon tiny-lr or anything, so I found the code really easy to get going with (thanks @tapio!)

Anyway, on to the proof-of-concept!

The main change from live-server is the behaviour here, where now I'm actually passing through the paths of the files that change, rather than deciding whether to 'reload css' or 'reload the whole page' on the server.

That logic has now moved into ChangeHandler, which uses System._loader.modules to figure out what's been loaded, and what plugin it used. It then loads the plugin and sees if a flag reloadable is set. Since my CSS plugin uses a side-effect to insert the CSS into <head>, I can simply call System.load (with a cache-busted URL) and cause the CSS to be reloaded.

Of course, I had to actually set my plugin up to work that way: post-css.js. I've changed this now to only ever add one <link> tag to the HEAD, but use a Map (which is ordered) to keep track of the source files so far loaded. When any new ones are translated, add them to the map (if they haven't been seen before they'll go at the end, if they have they'll take their older version's place) and regenerate the one <link> tag with a new URL. This means you can define variables in one file and use them in another, since postcss is being called on the full concatenated source each time.

In the end, I got a lot further than I thought I would have, because live-server had done so much already. Designing my CSS plugin to handle updates wasn't too bad, and actually bought me that variable support between two imports: defined with this import then used with this one

All in all, this server + plugin combo gives me super freaking fast CSS feedback, which was the whole goal. I'd love to extend this to support React hot-reloading too, but I understand that a lot less at the moment.

What do you think? Is there a better way to figure out what's loaded than System._loader.modules? And a better way to force a reload than using a cache busting query-string?

@geelen
Copy link
Owner Author

geelen commented Apr 9, 2015

Just changed post-css.js to use the fetch function instead of translate. Passing through the original fetch method as an argument is seriously helpful, thanks!

Needed this because I need to guarantee the order in which CSS is requested is preserved (previously it was the order of responses). It's all working though!

@geelen
Copy link
Owner Author

geelen commented Apr 9, 2015

GOT REACT HOT LOADING WORKING

live-reloading-jspm

It's a pretty rough hack right now (it assumes you're using ES6, only exporting a default class, named a certain way, etc) but it ACTUALLY WORKS :)

I ended up just copying the current plugin-jsx file into my own project to hack on it, you can see what my version looks like now. Using the documentation on react-hot-api I was able to figure out a minimal snippet that would work, as long as everything was named correctly in the file ¯_(ツ)_/¯

The complication comes from the fact that react-hot-loader needs to wrap itself around every definition of a React class, even the first one (not just after the first new version appears). But I couldn't figure out how the plugin might be able to inject something in between the instantiate call and the execute call. I tried overloading instantiate but unlike fetch you aren't passing the default instantiate method at all. Maybe if you were, I could call instantiate on the file that I have, then wrap its execute method in something that attached the hot-reloading behaviour.

Anyway, I think this is a big win, I'm very excited about where this leads. Zero-configuration virtually instantaneous reloading with JSPM is a pretty awesome concept. Particularly if we can standardise on a way that plugins can be live-reload friendly 😀

@guybedford
Copy link

@geelen, really nice work here! what APIs would help make this easier? It seems like:

  • Iterator API for module registry
  • The ability to unload CSS files in the CSS plugin. Perhaps the module value returned by the CSS plugin should have a "detach" function on it that can be used to unload a CSS file.
  • Did you consider looking at the System.has / System.delete API for refreshing scripts? This should work for hot reloading, except for one small bug which may be hit at Support System.delete for register pipeline systemjs/systemjs#375, but probably won't happen for the separate file case I don't think.

Glad to hear the plugin hook chaining works well. Is there anything I can do to help further?

@gersongoulart
Copy link

@guybedford: +1 for this feature. @geelen what can be done at this point to help out with the implementation of live-reloading hot-swapping?

@geelen
Copy link
Owner Author

geelen commented Apr 22, 2015

Let me publish where i'm at. I have my postcss plugin and my jsx plugin.
The jsx one needs a lot of work, with a much greater understanding of
SystemJS internals.
On Tue, 21 Apr 2015 at 11:57 pm Gerson Goulart notifications@github.com
wrote:

@guybedford https://github.com/guybedford: +1 for this feature. @geelen
https://github.com/geelen what can be done at this point to help out
with the implementation of live-reloading hot-swapping?


Reply to this email directly or view it on GitHub
#1 (comment).

@geelen
Copy link
Owner Author

geelen commented Apr 22, 2015

Published! Check out instructions on https://github.com/geelen/typeslab and see jspm-server in action!

@geelen
Copy link
Owner Author

geelen commented Apr 22, 2015

Oh and yeah you can do npm install -g jspm-server now :D

@geelen geelen closed this as completed Jun 10, 2015
@johnraz
Copy link
Contributor

johnraz commented Jun 12, 2015

Hi everyone,

I did try the typelabs project as is, I also tried integrating the all stuff in my own projet but I can't get the jsx files to hot reload... It does a full reload whenever I change a jsx file. Standard javascript files are correctly hot reloaded though.

any idea ?

@johnraz
Copy link
Contributor

johnraz commented Jun 12, 2015

ok nevermind I forgot to add the export let __hotReload = true ... :-)

@geelen
Copy link
Owner Author

geelen commented Jun 12, 2015

Hey @johnraz, I'm actually in the middle of changing how the live-reloading works, so the current version jspm-server doesn't automatically work with TypeSlab any more. It should be fixed in the next couple of days, but adding that snippet should get you some of the way in the mean time.

@johnraz
Copy link
Contributor

johnraz commented Jun 13, 2015

Ha ! Automatic hot reloading is possible then ?! That would be super awesome!

@asaf
Copy link

asaf commented Jun 20, 2015

@geelen I wonder, can you explain how hot-reload works without any plugin ? I just hit jspm-server in my folder and react components are being hot re-loaded, I see in your typeslab project you have jsx.js and a dependency on hot-reload-api so I wonder how it works without these pieces of code.

btw is there any better solution than pushing code per component? __hotReload export is kinda dirty,

Many thanks!

@johnraz
Copy link
Contributor

johnraz commented Jun 20, 2015

@asaf : you do need a custom plugin for the export let __hotReload = true to be automagically added to you .jsx files. That custom plugin can be installed with jspm install jsx=npm:jspm-loader-jsx

So this is solving the "pushing code per component" for the react components. Its not the case for the regular es6 modules though, and it would be nice to have a way to make them automatic too.

Regarding all the dependencies related to hot reloading, those are installed in the target project itself not in jspm-server, there is no way afaik that it would work if not installed in your target project.

@guybedford
Copy link

It could be worth allowing load metadata as an alternative way to indicate hot reloading as well (and that would also avoid the export * issue for hot reloadable modules as well if that causes problems down the line).

That would allow something like:

System.config({
  meta: {
    '*.js': { hotReload: true }
  }
});

@geelen
Copy link
Owner Author

geelen commented Jun 20, 2015

That could be a great solution @guybedford. I think hot-reloading should be opt-in, but yeah, it would be good to not to have to specify it on each and every file...

@johnraz
Copy link
Contributor

johnraz commented Jun 21, 2015

I created a new issue to keep talking about this - will make the discussion stands out for newcomers and we will be able to reference it once fixed ;-)

@ryancampbell
Copy link

Any update on this?

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

6 participants