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

Handle less dependencies [question] #108

Closed
guillaume86 opened this issue Oct 11, 2016 · 6 comments
Closed

Handle less dependencies [question] #108

guillaume86 opened this issue Oct 11, 2016 · 6 comments

Comments

@guillaume86
Copy link

Hi,

I currently use https://github.com/diagramatics/plugin-less to load a less file in my project.
If I make changes to this file, the CSS do reload properly, but if I edit an imported file (by @import),
the hot reloading is not working. The server do send the files changes events.

I'm willing to take a look into it but I'm not sure where to start.
What would be the best approach to implement this?
Is there a way to tell the hot reloader that a module has external dependencies?
Maybe I should generate "noop" imports for all dependent files when generating the JS module?
Is there another loader that solves a similar problem?

@alexisvincent
Copy link
Owner

At the moment the only approach is pretty hacky. But works well. Essentially, when you import a less file, the less plugin resolves and compiles that file (and all its imports), then hands it back to SystemJS. SystemJS then stores this in an internal registry (System.loads). Then when you edit the root less file on your computer, a change event is sent to systems-hot-reloader and it checks to see if its in System.loads. Since it is, it deletes is and asks the less compiler for the new version.

The problem now comes in when you edit one of the imported files. The change event gets sent to the browser. But SystemJS is only tracking the root file. So the event gets dropped.

The way i get around this is by storing (serverside) a list of all the less files (in my case postcss), then when any less file changes on the system, i send a change event for each root less file to the browser. This results in all root less file getting reloaded, including our change.

If you want an example of how I do this check out https://github.com/alexisvincent/jspm-devtools/blob/master/lib/index.js#L20.

I'm in the process of working on an extension to SystemJS to support these kinds of workflows.
https://github.com/alexisvincent/systemjs-hmr

Good luck. Let me know if you need anymore help.

@alexisvincent
Copy link
Owner

On another note. The whole situation regarding devtools for SystemJS is going to be getting a whole lot better in a little bit. I'm working on something, and I know others in the community are as well.

@guillaume86
Copy link
Author

Thanks I'll give your package a shot!
Can't wait to see how it will evolve, the jspm tooling is already pretty impressive as it is :).

@guillaume86
Copy link
Author

guillaume86 commented Oct 12, 2016

I managed to include a similar function into my setup (was using https://github.com/piotrwitek/jspm-hmr).

I just created a little script that subscribe to the reloader events and I include it as a script tag in my dev index.html:

(function (exports) {
  function onChange(moduleName) {
    // only continue if a less file changed
    if (!/\.less$/.test(moduleName)) return;

    // get list of SystemJS imported .less files
    var lessModules = Object.keys(SystemJS.loads)
      .map(function(key) { return SystemJS.loads[key]; })
      .filter(function(load) { return load.metadata.loader == "less"; })
      .map(function(load) { return new URL(load.address).pathname.slice(1); });

    // main module, don't need to reload
    if (lessModules.indexOf(moduleName) !== -1) return;

    // trigger reload on less modules
    lessModules.forEach(function(moduleName) {
      this.onFileChanged({ path: moduleName });
    }, this);
  }

  exports.setupLessHotReloader = function (reloader) {
    reloader.on('change', onChange.bind(reloader));
  }
})(window);

Then in the dev init script, I call it after creating the reloader:

// hot-reload config
SystemJS.import('systemjs-hot-reloader').then(function(HotReloader) {
  // if you're running server on custom port please remember to update below
  var reloader = new HotReloader.default('http://localhost:3000');
  setupLessHotReloader(reloader);
});
// load main module of your app with SystemJS
SystemJS.trace = true;
SystemJS.import('src/app');

Thanks for the help.

@alexisvincent
Copy link
Owner

Awesome! Glad you got sorted. I wouldn't recommend jspm-devtools just yet. I'm actively developing it. But you might find it useful in the future. It traces the dependency tree server side and does all compilation server side, with cached results. Then when you load a page for the first time it takes 1-3seconds instead of the ridiculously long time it usually does. It achieves this by pushing the dependencies of a file either in a bundle or via HTTP2 server push. Then for hot reloading it only sends the change

@guillaume86
Copy link
Author

No problem, yeah I took a look, it looks very promising to speed things up :).
I'll keep track of your progress and try it when it's stabilized.

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