Macil / browserify-hmr

Hot Module Replacement plugin for Browserify
MIT License
373 stars 26 forks source link

Does not inject new code #18

Open aegyed91 opened 8 years ago

aegyed91 commented 8 years ago

Hello @AgentME could you please help me out a bit? I having hard times getting this thing to work.

It seems like updates being emitted early, but i don't think so this is the problem because it never inject the code changed in the previous save.

Browser console:

[HMR] Websocket connection successful.
index.js:514 [HMR] Updated modules ["src/javascripts/main.js"]
index.js:514 [HMR] Updated modules ["src/javascripts/main.js"]

This is how my gulpfile looks:

let options = { debug: true };

if (config.isDev) _.extend(options, watchify.args);

let bundler = browserify(paths.src, options).plugin(hmr);

bundler.transform(babelify);
bundler.transform(hbsfy);
bundler.transform(envify);

if (config.isDev) {
  bundler = watchify(bundler);
  bundler.on('update', () => gulp.start('js'));
}

function bundle() {
  return bundler.bundle()
    .on('error', onError)
    .pipe(source(config.js.bundleName))
    .pipe(buffer())
    .pipe(sourcemaps.init({ loadMaps: true }))
    .pipe(sourcemaps.write('.'))
    .pipe(gulp.dest(paths.dest))
    // .pipe(bs.stream({ once: true }));
}

gulp.task('js', preTasks, () => bundle());

Terminal:

[BS] Serving files from: public
GET / 200 10.957 ms - 486
GET /stylesheets/main.css 200 4.258 ms - 560724
GET /javascripts/main.js 200 1.663 ms - 1816775
GET /javascripts/main.js.map 200 3.722 ms - 2103596
19:34:59 GMT+0100 (CET) [HMR] User connected, syncing
[19:35:05] Starting 'js'...
19:35:06 GMT+0100 (CET) [HMR] Emitting updates
[19:35:07] Finished 'js' after 1.67 s
[19:35:12] Starting 'js'...
19:35:13 GMT+0100 (CET) [HMR] Emitting updates
[19:35:13] Finished 'js' after 1.22 s

I also use browsersync for server can that be a problem?

gulp.task('browser-sync', () => {
  bs.init({

    // A, if you don't have a backend api use the built in server
    server: {
      baseDir: 'public'
    },

    // B, if you got a backend api proxy the request to it
    // proxy: 'some-vhost-of-existing-backend.api',

    // custom middleware for mock api
    middleware(req, res, next) {
      require('../../api/api')(req, res, next);
    },

    // default port
    port: config.isProd ? 8080 : 3000,

    // disable notify popup
    notify: false,

    // do not open browser on start
    open: false,

    // disable UI completely
    ui: false
  });
Macil commented 8 years ago

If you're seeing the "Emitting updates" and "Updated modules" messages, then your build process is likely correct. The issue is probably that you don't have any code calling module.hot. See #16.

tj commented 8 years ago

I'm getting this as well, is there a way to get more verbose logging?

nicolas-zozol commented 8 years ago

I have also the same problem. As I use websocket, I should not have to add js code, no ?

From the node console :

22:48:11 GMT+0200 (CEST) [HMR] User connected, syncing
updated source
22:48:29 GMT+0200 (CEST) [HMR] Emitting updates
864035 bytes written (0.78 seconds)

From the Dev tool console :


[HMR] Attempting websocket connection to http://localhost:3123
admin.ts:13creating an admin
index.js:425 [HMR] Websocket connection successful.
index.js:514 [HMR] Updated modules ["modules/template.html", "modules/admin.ts", "index.ts"]
Macil commented 8 years ago

Are you using module.hot.accept (or a transform that uses it for you, like react-transform-hmr) anywhere in your code? You need to, or else Browserify-HMR won't know how to update your code and you'll run into this issue.

nicolas-zozol commented 8 years ago

Not at all. Where do we find it ?

Macil commented 8 years ago

Browserify-HMR and Webpack HMR update files by executing them again, but you have to first mark which files can accept updates by using module.hot.accept.

A file can accept updates of itself like this:

console.log("foo");
if (module.hot) {
  module.hot.accept();
}

Each time you edit that file, it will execute (and log something again, unless you've removed that statement). Now that's not terribly useful. Usually you want to update functions or classes in-place that are required by other files. Or maybe you want to update already instantiated instances of a class. This takes more effort to set up. I plan to write a bit about this, but I've been delaying that until I polish up and fix a few bugs in Browserify-HMR (like these misleading log statements).

If your project uses React, then go use react-transform-hmr, and all of your files that define React components will automatically be hot-replaceable and you can stop reading here if you want!

If you use the ud library, then it handles using the module.hot APIs to accomplish common tasks for you, and you can make a file with a hot-replaceable function like this:

var ud = require('ud');

// You can edit this function in a live application!
function greeting(name) {
  return "Hello, "+name;
}

module.exports = ud.defn(module, greeting);

or you can make a hot-updateable class like this in ES6:

import {defn} from 'ud';

class Greeter {
  // Changes to this constructor will only affect future instances of Greeter. Changes 
  // to it can't affect instances that have already been constructed!
  constructor(ownName) {
    this._ownName = ownName;
  }
  // Changes to this method will affect all current and future instances of Greeter
  // immediately!
  greet(name) {
    return `Hello ${name}, this is ${this._ownName}`;
  }
}

// defn works on both functions and classes, because they're the same in Javascript
// anyway.
export default defn(module, Greeter);

It's a bit of boilerplate, but the control it gives you is necessary when you have file-scoped state that needs to be persisted between updates (ud's defonce function helps here). I've been brainstorming about automatic code transform tools to make this not necessary, but I haven't yet figured out a technique that would fit all of the needs I've seen in real codebases that ud is able to handle now.

nicolas-zozol commented 8 years ago

Thanks for your reply. It makes thing much more clear.

linus-amg commented 8 years ago

Hi @AgentME, did you yet came to write a little more about how to update already instantiated instances? I'm referring to your comment: "Or maybe you want to update already instantiated instances of a class. I plan to write a bit about this, but I've been delaying that until I polish up and fix a few bugs in Browserify-HMR"

mykone commented 7 years ago

Hello @AgentME, I am having this issue too. Also, I am using Browserify+Watchify+BrowserSync. I did use the module.hot.accept() in my custom HMR-like class. I am not using ud or React so I am just adding the following code at the end of my ES6 class.

if(module.hot){
   module.hot.accept();
}

I am also getting these outputs in the browser console:

[HMR] Updated modules ["./moduleName.js"]

However, it seems the JS code isn't being re-inject in the tag just like WebPack does.

Any ideas on what's causing this?