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

file changed event socket api #147

Open
dazinator opened this issue Sep 20, 2018 · 3 comments
Open

file changed event socket api #147

dazinator opened this issue Sep 20, 2018 · 3 comments

Comments

@dazinator
Copy link

dazinator commented Sep 20, 2018

Hello,
Suppose I am writing my own file watcher, and its listening on a socket. When the client connects, what are the format of the messages I need to trigger a reload?

  1. Suppose I detect /wwwroot/bundle.js changed which has moduleA, moduleB in.
  2. Suppose I detect /wwwroot/moduleC.js changed (not bundled)

In both cases system.js config knows the modules / bundle mapping.

Does this mean all I need to send over the socket is the changed file path and the hmr system will know in the case of bundle.js that it needs to reload all bundled modules? Or do I need to work out which modules have changed when bundle.js is modified and send accross just the module names?

Do I also need to push the new file contents itself to save a roundtrip?

Many Thanks

@alexisvincent
Copy link
Owner

Hi there,

Take all answers lightly. It's been a little while since I worked on this project and my working memory is pretty poor anyway.

In terms of message format, there's really two "formats" that it currently supports. The new one I was playing with and the original one that @capaj had. Ultimately they both are just given to fileChanged which expects {url: String, entries: [<roots>]}, this then is passed into the System.reload function provided by systemjs-hmr which resolves this to an individual module using either System.normalize or System.resolve, depending on the version of SystemJS you're using.

Once we know the specific module that changed, we search the SystemJS module registry (loaded modules) to find any files that depend on the changed one in any way and delete them. We then run a simple System.import on the root files. Which we try detect, but otherwise are provided with the entries key mentioned earlier.

To answer your specific questions. Currently systemjs-hmr doesn't know how to handle your bundle change case... However this shouldn't be difficult to add if you would like to give it a go. A dumb version could just System.delete all modules that were in the previous bundle. But to handle it better we would need to actually check all sources in the bundle and compare them to all the previous sources to determine if there has been a change.

systemjs-hmr was really designed with the understanding that in almost all cases we can rather set file watchers on the sources, rather then the compiled bundle which would mean we have a lot more work to do.

Ultimately I decided that the best place for more complicated computation and scenarios was in the file watcher lib itself. That's what I was trying to achieve with systemjs-tools. Not only would it be able to calculate this, but also handle caching of these modules, precompile them so that the browser didn't have to, sending over file contents (as you suggested), to save on latency, compile error messages and all that good stuff. If you're working on a file watcher, you might have luck with that project. And perhaps if it takes your fancy might be able to continue with some of the features I haven't gotten to. Fair warning though, I'm probably not going to be working on these projects in the future. My professional life as taken be to other places and I don't have time to work on these as I would have liked.

@alexisvincent
Copy link
Owner

On another note, I noticed your bio mentioned you were based in Surrey. I've recently moved to Guildford. If you ever decide you want to push any of these projects further, I'd be happy to explain things in person.

@dazinator
Copy link
Author

dazinator commented Sep 22, 2018

Thanks for the explanation.
I used to live in Guildford, I'm now about 20 mins away! I might take you up on that offer but I am not sure I can fit in any other projects on at the moment! I will certainly try to contribute once I get some more exposure to the projects.
Just to make sure I have the right conceptual model, could I run this scenario past you - sorry to be a burden. This is my current understanding;

  1. The browser is currently navigated to /page.html.
  2. Page.html has two seperate SPA applications on the same page - it imports calculator as application one, and newsfeed as application two.
  3. calculator.js defines / exports the module calculator. newsfeed.js defines / exports the module newsfeed. These are configured as expected in system.js config.
  4. calculator app is rendered inside the calculator div / section of the page, newsfeed is rendered in another. They are considered isolated from eachother / standalone on the page.
  5. calculator module depends on module foo.
  6. foo module is mapped to the file /foo.js.
    6 newsfeed module has no dependencies.

Side Note: I am thinking very much long the lines of a modular CMS here, where different modules can be configured on different pages.

So in the above scenario, when the file watcher detects a change to the file foo.js the watcher would need to send a message to the client with

  • URL = /foo.js (i.e this is the request path that the changed file foo.js can be served up to the browser on?
  • Entries = [calculator] = the array of entry / root / top level modules that are imported at page level that will be effected by this dependency change.

Lastly, if Entries is not provided, then your client side HMR system will do some clever work to trace the dependencies to work out the effected roots itself (but this obviously means more work for the client).

I am making a complete guess about what Entries refers to by the way. If my guess is correct, then I am also a little bit confused abotu the followijng: suppose this dependency tree:

Foo --> Bar --> Baz

Foo is the entry for Baz when Baz changes, Foo must be reloaded - but only if Foo is imported on a page. If on the page you were importing Bar, then when Baz is changed, Bar would surely be the entry point, not Foo. ?

So.. thinking about it, the entry point cannot be determined by static analysis of the entire dependency graph alone, you also need to know which modules are actually "in use" to know how much of the dependency graph is actually impacted? Does this sound right? If so, when /Baz is changes, how does my file watcher know what to poulate Entries with - it would have to know what Imports are on the current page at the time - but the client does't submit that info?

My last thoughts are that I think I could interop with System.JS builder on the server to compute the Entries for a changed file, and I could probably cache that information with the file so that when it changes in future, I don't need to re-run the trace. However if caching, I'd have to invalidate the cache whenever the dependency tree changed and I am not sure how I could detect that event off the back of a file edit on the server side.. Sorry - I digress!

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