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

Live-reload #2

Open
geelen opened this issue Jun 7, 2015 · 10 comments
Open

Live-reload #2

geelen opened this issue Jun 7, 2015 · 10 comments

Comments

@geelen
Copy link
Owner

geelen commented Jun 7, 2015

CSS files can be live-reloaded no problem, need to make sure jspm-server is up to date with them

@geelen
Copy link
Owner Author

geelen commented Jun 7, 2015

Hey @guybedford: So I've done a bunch of investigation into the way Webpack's Hot Module replacement works. It's complicated, but it convinced me that I've undercooked the work I've done so far. I've had a bunch of things rattling around in my head for a while but I think it's time to put them down into something coherent. So, let's begin!

Live-reloading CSS

Considering this as an example. If a CSS file has no exports (your bog-standard, old school CSS), then loading it involves simply creating a <link> or <style> tag in the DOM. Reloading it, then, involves removing the old one and adding the new one. It doesn't matter where the CSS is being used, it just gets reloaded. Easy.

If the CSS file exports some variables (CSS Modules style), you need to propagate the change up the dependency tree. So if component.js depends on symbols exported from component.css, the JS needs to be reloaded as well.

Live-reloading JS

There's no telling what a JS file might do, so we can't just arbitrarily reload a file. But we do need a way to say that some files are idempotent and totally ok to be reloaded. There's a couple of ways I can see this going:

  • A live-JS loader: `import X from './file.js!live'
  • Something in the file itself: e.g. "pragma idempotent;" or __module.reloadable = true

The second is what Webpack does, with module.hot.accept().

We should solve once for all file types

It's quite easy for a CSS or JSX loader to add a chunk of JS at the end of a file, that's what plugin-live-jsx does, and what a few of the Webpack loaders do. The current jspm-server needs the plugin to identify itself as being hot-reload compatible, but that means that normal JS files can't be included.

I think we should come up with a simple mechanism to pass metadata from a file to the loader, something like:

/* component.js */
__reload = { self: true, parents: false }
/* alternatively */
module.exports.__reload = { self: true, parents: false }

That later can be looked up, so if a new version of component.js appears, we know straight away whether it and all its dependencies are going to handle it ok, and reload the browser or swap the files in.

Not sure on the internals to support this, but thought I'd kick off the discussion.

@guybedford
Copy link

I like the idea of a meta export export let __hotReload = true. Then CSS could equally export this property and be hot-reloaded. Would it make sense to offer a __hotUnload method? How would parents: false work to propagate the binding?

@geelen
Copy link
Owner Author

geelen commented Jun 9, 2015

How about something like this:

export let __hotReload = RELOAD_CONFIG
// where RELOAD CONFIG can be one of
true // I'm safe to be reloaded, but I can't do it myself. Tell my parents to see if they can reload me
false // if anything happens, reload the whole browser (default)
function() // called before a reload (to do any cleanup), returns maybe true/false whether to pass the reload up the chain

Not sure what arguments to the function would be. Maybe pass in the loader instance? Dunno if it's needed. But, this would allow arbitrary unloading (the idea of a __hotUnload), which is good. Maybe it should be called with a newVersion, so for CSS it could be something like:

export let __hotReload = (plugin, newModule) => {
  plugin.removeElement(this)
  plugin.createElement(newModule)
  return this.default.values != newModule.default.values
}

Something like that could work...

@geelen
Copy link
Owner Author

geelen commented Jun 9, 2015

Got a couple working today:

@geelen
Copy link
Owner Author

geelen commented Jun 10, 2015

Made a bunch more progress. Wondering, for those not using ES6, should we allow

module.exports.__hotReload = true

as well? There's no way for an CJS file to export a named ES6 export is there?

@guybedford
Copy link

In SystemJS 0.17, named exports are copied down as the enumerable properties of the default to the Module exports themselves, so this would be allowed.

@geelen
Copy link
Owner Author

geelen commented Jun 10, 2015

Wait, really? So setting module.exports.a = 5 then you can do

import { a } from "./cjs.js"
a // 5

but you can also do

import x from "./cjs.js"
x.a // 5

@guybedford
Copy link

Yes exactly.

@geelen
Copy link
Owner Author

geelen commented Jun 10, 2015

That's cool! Can't wait for 0.17 😄

@geelen
Copy link
Owner Author

geelen commented Jun 20, 2015

This is now built in, but needs to be documented.

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

2 participants