hot-module-reload icon indicating copy to clipboard operation
hot-module-reload copied to clipboard

HMR for SystemJS

Open alexisvincent opened this issue 8 years ago • 12 comments

Hi Guys,

I'm trying to work out how to get Aurelia HMR support into systemjs-hmr, and by extension systemjs-hot-reloader.

But I'm unsure of what it would take other then standard hmr. This project seems to reimplement a module registry?

alexisvincent avatar Jan 30 '17 06:01 alexisvincent

No such reimplementation here. It should be pretty simple to add the required hooks via the SystemJS interface. I don't have capacity to do this, however any PRs are welcome. All that's most probably needed is a PR to aurelia/loader, adding similar capabilities as outlined here in the loader-webpack: https://github.com/aurelia/loader-webpack/blob/1e318399ad40290185296197839149aa85148bd9/src/aurelia-loader-webpack.ts#L113-L132.

niieani avatar Jan 30 '17 20:01 niieani

I'm trying to implement aurelia-systemjs-loader based on (https://github.com/aurelia/loader-default) for HMR module, but as for me it's not so clear what the aurelia-webpack loader do (https://github.com/aurelia/loader-webpack).

The stack I use: https://github.com/alexisvincent/systemjs-hot-reloader - it provide two points of trues:

  1. As I suppose the place where I have to run HMR methods to force the Aurelia to reload the module
export const __unload = () => {
    console.log('Unload something (unsubscribe from listeners, disconnect from socket, etc...)')
    // your container node
}
  1. Check the module was loaded, and force Aurelia to reload the module.
/**
 * You can import the previous instance of your module as you would any other module.
 * On first load, module == false.
 */
import { module } from '@hot'

/**
 * Since all exports of the previous instance are available, you can simply export any state you might want to persist.
 *
 * Here we set and export the state of the file. If 'module == false' (first load),
 * then initialise the state to {}, otherwise set the state to the previously exported
 * state.
 */
export const _state = module ? module._state : {}

https://github.com/capaj/chokidar-socket-emitter - to connect to the browser-sync https://github.com/aurelia/hot-module-reload - try current module, to reload the modules,

The aurelia/hot-module-reload still a black box for me, would be glad for any information about API needs to be used in the aurelia loader.

I'm not so familiar with webpack, so I start to compare line by line with default-loader, to find the places I have to reimplement:

  1. https://github.com/aurelia/loader-webpack/blob/1e318399ad40290185296197839149aa85148bd9/src/aurelia-loader-webpack.ts#L65-L88
  2. https://github.com/aurelia/loader-webpack/blob/master/src/aurelia-loader-webpack.ts#L91-L100
  3. https://github.com/aurelia/loader-webpack/blob/master/src/aurelia-loader-webpack.ts#L104-L137

And I stuck for now with system js alias for:

  • I suppose
__webpack_require__.m[moduleId] => SystemJS.has(moduleId)
  • for the https://github.com/aurelia/loader-webpack/blob/master/src/aurelia-loader-webpack.ts#L91-L100
__webpack_require__.c ~  System.registry.get
          // but for webpack 
           const moduleExports = registry[moduleId].exports;
           if (typeof moduleExports === 'object') {
                callback(moduleId, moduleExports);  // <= not clear what the module Exports is, and why we push it to the callback.
           }

           // for systemjs
           const moduleExports = registry(moduleId) >????<;
           if (typeof moduleExports === 'object') {
                callback(moduleId, moduleExports); 
           }
  • for the https://github.com/aurelia/loader-webpack/blob/master/src/aurelia-loader-webpack.ts#L104-L137
__webpack_require__(moduleId)  => SystemJS.reload(moduleId) 

@niieani, could you please explain the scenario we have to implement in aurelia/loader to be able use aurelia-hmr modue with any custom loader, let's skip systemjs for a while. Any information even in general would be helpfull

wegorich avatar Jul 06 '17 10:07 wegorich

For now I have aurelia-systemjs-loader that didn't launch any methods after systemjs reload module, have no idea what to do next :(

Updates:

Found the way how to receive SystemJS new module object, and how to trigger the methods in the aurelia-loader. But two questions:

  1. How can I update templates runtime
  2. How can I update JS runtime

Using the aurelia/hot-module-reload?

wegorich avatar Jul 06 '17 16:07 wegorich

@wegorich see this main class: https://github.com/aurelia/hot-module-reload/blob/master/src/aurelia-hot-module-reload.ts#L41

It contains 3 methods: handleModuleChange, handleViewChange and reloadCss. Each can be used to hot reload a module of given type, once it is removed from the cache of the AureliaLoader instance, and a new instance is available for loading.

You'll need to fork and edit aurelia-loader to add functionality that removes stale modules from its cache. You can see how this is done in aurelia-loader-webpack, since both have a relatively similar structure.

niieani avatar Jul 06 '17 20:07 niieani

@niieani thanks. Will dive in this methods.

if(window.__reloaded) {
                    if (!this.hmrContext) {
                        // Note: Please do NOT import aurelia-hot-module-reload statically at the top of file.
                        //       We don't want to bundle it when not using --hot, in particular in production builds.
                        //       Webpack will evaluate the `if (module.hot)` above at build time 
                        //       and will include (or not) aurelia-hot-module-reload accordingly.
                        const { HmrContext } = require('aurelia-hot-module-reload');
                        this.hmrContext = new HmrContext(this);
                    }

                    await this.hmrContext.handleViewChange(address);
                }

I did pretty similar as at the aurelia-loader-webpack, but receive aurelia-hot-module-reload.js:278 Something's gone wrong, no original ViewFactory?!

error.

wegorich avatar Jul 06 '17 20:07 wegorich

@niieani Still a bit confusing.

So I reload js && html client side module then I trigger:

if (defaultHMR && this.hmrContext) {
    this.hmrContext.handleModuleChange(address);
}

Nothing happened.

wegorich avatar Jul 06 '17 21:07 wegorich

@wegorich did you implement logic for cleaning the cache of modules in your fork of aurelia-loader? If you send me a link to your fork, I can have a look if I see any problems.

niieani avatar Jul 08 '17 13:07 niieani

@niieani yep, aurelia-loader-systemjs, I made it works in the sandbox. Test only HTML and JS reloads.

I'll make the beautiful fork of aurelia-loader in Monday 👍

wegorich avatar Jul 08 '17 17:07 wegorich

Please share a bit about the changes you needed to make, maybe they can be officially incorporated somehow or built into a plugin.

EisenbergEffect avatar Jul 08 '17 18:07 EisenbergEffect

Yeah, I spend the day and create simple modules we can use. No need to change the aurelia-hot-module-reload it works fine. Not sure about ViewSlots...

So I did

  • the plugin aurelia-systemjs-hot-plugin for systemjs-hot-reloader, sends events about changes directly to HmrContext of Aurelia Loader.
  • the fork of aurelia-loader - aurelia-loader fork. Just port the code from aurelia-loader-webpack to systemjs.
  • the PR for systemjs-hot-reloader - PR - to be able to subscribe for the file changes events, especially for the aurelia-systemjs-hot-plugin.

Not sure what to do with aurelia-loader next. So publish it as aurelia-loader-systemjs to the npm.

wegorich avatar Jul 10 '17 17:07 wegorich

Ah my mistake, play with aurelia-systemjs-hot-plugin and found that I have to reimplement the aurelia-webpack-plugin. Hope aurelia-hot-module-reload handle all this cases, but it should be done manually... Heh.

wegorich avatar Jul 11 '17 14:07 wegorich

Does this mean that the description of this package that says HMR works across all loaders is incorrect ? or are these comments dated and there's no need for aurelia-systemjs-hot-plugin now ?

I don't have HMR confgured with SystemJS now but I'm using aurelia + systemjs + ts... would like to setup HRM in the easiest/simplest way possible ..

diegohb avatar Nov 16 '17 04:11 diegohb