Giter VIP home page Giter VIP logo

browserify-hmr's Introduction

Browserify-HMR

This an implementation of Webpack's Hot Module Replacement API as a plugin for Browserify. This project seems to work in many cases, but it is still early in development and likely has some bugs at the moment. Let me know how it works for you!

Quick Example

git clone https://github.com/Macil/browserify-hmr.git
cd browserify-hmr/example
yarn
yarn start

Open http://localhost:8080/ and try updating label.jsx and interval.js.

Hot Module Replacement Usage

Hot module replacement works by re-executing updated modules. The Hot Module Replacement API must be used to define which modules can accept updates, and what to do when a module is going to be updated.

However, using the HMR API directly in application code is not always the best route. Code transforms and libraries like react-transform-hmr and ud can help do common tasks or entirely automate making certain types of code be hot replaceable.

In addition to the module.hot.* functions from the Webpack Hot Module Replacement API, the following is also implemented:

module.hot.setUpdateMode(mode, options)

This allows the bundle update mode and options to be changed at runtime. mode should be a string and has the same meaning as mode in the Plugin Options section. options is an optional object which may have the properties url, cacheBust, and ignoreUnaccepted, also with the same meanings as the same options in the Plugin Options section. The HMR status must be "idle" when this is called.

Plugin Usage

Add the browserify-hmr plugin to your watchify call:

yarn add --dev browserify-hmr
watchify -p browserify-hmr index.js -o bundle.js

Browserify-HMR works with Node too! Use the m/mode option to tell it to use the "fs" method to update itself. See more information below in the Options section.

watchify --node -p [ browserify-hmr -m fs ] index.js -o bundle.js

Watchify is not required. Browserify can be run multiple times manually instead if more control over the timing of the reloads is desired.

browserify -p [ browserify-hmr -m ajax -u /bundle.js ] index.js -o bundle.js
nano foo.js # make some edits
nano bar.js # edit some more files
browserify -p [ browserify-hmr -m ajax -u /bundle.js ] index.js -o bundle.js

Plugin Options

Browserify-HMR options can be specified from the command line following the plugin name with braces in long or short form:

watchify -p [ browserify-hmr -m fs ] index.js -o bundle.js

Options can be specified using the Browserify API too:

var hmr = require('browserify-hmr');

browserify().plugin(hmr, {
  mode: "fs"
})

m, mode is a string which sets the update mode. "websocket" tells the bundle to open a connection to a websocket server hosted by the plugin to listen for changes. The websocket will be served over HTTP unless any of the tlskey, tlscert, or tlsoptions options are passed. "ajax" uses AJAX requests to download updates. "fs" uses the filesystem module and is suitable for Node use. "none" causes the bundle to not be configured to check for updates. module.hot.setUpdateMode may be called at runtime to reconfigure the bundle. Defaults to "websocket".

supportModes is an optional array of strings specifying other update modes to build support for into the bundle in addition to the given mode. This must be used if the bundle is going to change the update mode by using module.hot.setUpdateMode at runtime to a mode not given in the mode option. You can pass this option on the command like this:

watchify -p [ browserify-hmr -m none --supportModes [ ajax websocket ] ] index.js -o bundle.js

noServe is a boolean which allows Browserify-HMR's automatic websocket server to be disabled. Normally, the Browserify-HMR plugin automatically hosts a websocket server if mode or supportModes contains "websocket". If this is set to true, then the plugin will never host its own websocket server. You could use this if you're building a bundle in websocket mode with the url option set to point to a websocket server hosted by another instance of Browserify-HMR. Defaults to false.

ignoreUnaccepted is a boolean which controls the value of the ignoreUnaccepted parameter to module.hot.apply for the "websocket" mode. (When the "websocket" mode is used, Browserify-HMR automatically checks for updates and applies them, so the application never gets a chance to call module.hot.apply itself.) Defaults to true.

u, url is a string which sets the update URL that the websocket connection or Browserify bundle is accessible at. In "websocket" mode, this defaults to "http://localhost:3123". This is required for the "ajax" mode. This is not required for "fs" mode.

p, port is a number that sets the port to listen on if "websocket" mode is used. If you change this, you'll most likely want to change the url setting too. Defaults to 3123.

h, hostname is the hostname to listen on if "websocket" mode is used. This defaults to "localhost".

b, cacheBust is a boolean which controls whether cache busting should be used for AJAX requests. This only has an effect if the update mode is set to "ajax". If true, then a random parameter is appended to the URL on every request. This allows the cache to be bypassed when the server does not give a low Expires or Cache-Control header value. Note that this prevents E-Tag and Last-Modified headers from being used by the client, so keeping this disabled if it's not needed can be better for performance. You should consider tuning the HTTP headers your script is served with before tweaking this. Defaults to false.

k, key is the bundle key. If multiple bundles built using Browserify-HMR are run within the same javascript environment, then each must have a unique bundle key. The bundle key defaults to a value created by combining the update mode and update url, so you generally don't need to worry about this option.

K, tlskey is the path to the key file to use for HTTPS mode.

C, tlscert is the path to the certificate file to use for HTTPS mode.

tlsoptions is an object of options to pass to the call to https.createServer. Note that this object must be JSONifiable, so use strings instead of any buffers inside of it. This option may not be given by the command line.

disableHostCheck disables Origin and Host header checking when connecting to the server via WebSockets. By default it is set to false to 3rd party websites from connecting to a local websocket and leaking source code. For more information see (NPM Advisory 726)[https://www.npmjs.com/advisories/726].

If you don't use the default websocket update mode, then you'll need to manually tell browserify-hmr when it should check for and apply updates. You can use code like the following somewhere in your project to poll for updates:

if (module.hot) {
  var doCheck = function() {
    module.hot.check(function(err, outdated) {
      if (err) {
        console.error('Check error', err);
      }
      if (outdated) {
        module.hot.apply(function(err, updated) {
          if (err) {
            console.error('Update error', err);
          } else {
            console.log('Replaced modules', updated);
          }
          setTimeout(doCheck, 2000);
        });
      } else {
        setTimeout(doCheck, 2000);
      }
    });
  };
  doCheck();
}

See Also

  • react-hot-loader can be used to make React code live-update-able.
  • ud and ud-kefir are small simple utilities for declaring data and code as live-updatable.

Planned Work

  • There are known bugs currently where changes to modules without update accepters can cause the updates to bubble up to the entry and cause many modules to be reloaded incorrectly.
  • The client code is a bit of a mess. It should be refactored and have many smaller unit tests made.

browserify-hmr's People

Contributors

dependabot[bot] avatar jeremija avatar lokenmakwana avatar macil avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

browserify-hmr's Issues

Does not work with multiple bundles

In my use case my application code consists of multiple bundles, for simplicity let's say two one for code running in main thread and other for web-worker thread. Each is bundled with a separate browserify + watchify bundle and both use hmr plugin for hot reloading.

As far as I can understand from error messages below second bundle is attempting to start a second hmr server which errors:

[12:36:02] Requiring external module babel-core/register
[12:36:04] Using gulpfile ~/Projects/browser.html/gulpfile.babel.js
[12:36:04] Starting 'hotreload'...
[12:36:04] Finished 'hotreload' after 426 μs
[12:36:04] Starting 'develop'...
[12:36:04] Starting 'watcher'...
[12:36:04] Finished 'watcher' after 15 μs
[12:36:04] Starting 'browser/index'...
[12:36:04] Begin bundling: 'browser/index'
[12:36:04] Starting 'service/history-worker'...
[12:36:04] Begin bundling: 'service/history-worker'
[12:36:04] Starting 'about/settings/index'...
[12:36:04] Begin bundling: 'about/settings/index'
12:36:21 GMT-0700 (PDT) [HMR] Emitting updates
12:36:21 GMT-0700 (PDT) [HMR] Listening on localhost:3123
[12:36:23] Completed bundling: 'service/history-worker'
[12:36:23] Finished 'service/history-worker' after 19 s
12:36:24 GMT-0700 (PDT) [HMR] Emitting updates
events.js:141
      throw er; // Unhandled 'error' event
      ^

Error: listen EADDRINUSE 127.0.0.1:3123
    at Object.exports._errnoException (util.js:874:11)
    at exports._exceptionWithHostPort (util.js:897:20)
    at Server._listen2 (net.js:1234:14)
    at listen (net.js:1270:10)
    at net.js:1379:9
    at GetAddrInfoReqWrap.asyncCallback [as callback] (dns.js:63:16)
    at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:82:10)
events.js:141
      throw er; // Unhandled 'error' event
      ^

Error: Browserify-HMR lost connection to socket server
    at ChildProcess.<anonymous> (/Users/gozala/Projects/browser.html/node_modules/browserify-hmr/index.js:111:24)
    at emitNone (events.js:67:13)
    at ChildProcess.emit (events.js:166:7)
    at finish (internal/child_process.js:657:14)
    at doNTCallback0 (node.js:417:9)
    at process._tickCallback (node.js:346:13)

It would be nice if somehow multiple bundles could share same HMR instance. I also tried documented key parameter but that seems to fail due to #11 although not sure if that is what's it intended for.

Use of different port and url options per bundle works although I don't find it to be an ideal.

Error messages from react-hot-loader

The current example/ uses an old version of react-hot-loader which silently swallows require errors:

https://github.com/gaearon/react-hot-loader/blob/62f9ccdd076b26302dae077c23de3dd6812ebd97/src/hot.dev.js#L27-L31

The latest version of react-hot-loader always logs require errors:

https://github.com/gaearon/react-hot-loader/blob/3fadc05783f2aa534372dbe6846b1a379ed76ebd/src/hot.dev.js#L86-L93

Steps to reproduce:

https://github.com/Macil/browserify-hmr
cd browserify-hmr/example
npm install
npm install react-hot-loader@latest
npm start

After modifying Label.jsx, the component refreshes in the browser, but an error is present in browser console:

[HMR] Websocket connection successful. index.js:424
interval step 3 interval.js:8:10
[HMR] Updated modules 
Array [ "Label.jsx" ]
index.js:512
React-Hot-Loader: error detected while loading Label.jsx backend.js:6:2315
Error: "Cannot find module 'Label.jsx'"
    o _prelude.js:1
    o _prelude.js:1
    updateInstances react-hot-loader.development.js:3096
    runAll react-hot-loader.development.js:2998
    runAll react-hot-loader.development.js:2997
    runner react-hot-loader.development.js:2989
    promise react-hot-loader.development.js:3006
backend.js:6:2315
interval step 2 interval.js:8:10

It looks like the problem is the fact that browserify is converting module ids to numerical indexes, so the require('Label.jsx') call fails. I've also tried using --fullPaths, but that also fails because it would expect an absolute path to Label.jsx, not just Label.jsx.

The hot reload still seems to work, but I wonder if there's anything that could be done to fix this?

The problem of using numeric indexes in browserify

I ran into problems when running the example in this repo.

The original label.jsx:

import React from 'react';

export default class Label extends React.Component {
  render() {
    return (
      <div className="commentBox">
        Hello, world!
      </div>
    );
  }
}

If we add a dependency to it:

import React from 'react';
import str from './a.js';

export default class Label extends React.Component {
  render() {
    return (
      <div className="commentBox">
        Hello, world!
      </div>
    );
  }
}

we get an error in the browser:

bundle.js:366 TypeError: (0 , _index6.default) is not a function(…)(anonymous function) 
bundle.js:9386 [HMR] Updated modules ["label.jsx", "a.js"]

However, if we rename './a.js' to './z.js', it works.

I dived a little into the source code, and found that modules are updated only when their contents change.
However, when './a.js' inserted, all indexes (to modules in the final bundle) change.
The index to node_modules/babel-preset-react-hmre/node_modules/react-transform-hmr/lib/index.js changes from 6 to 7, as the new label.jsx knows.
So, when reloading, it tries to load the module with the index 7, which fails as react-transform-hmr keeps the old index 6 in the module definitions.

I've thought up two ways to fix it:

  • turn on the --full-paths flag, so absolute paths are used as indexes instead of numbers. The result will not be suitable for production.
  • use another plugin to change the indexes into some values which change and only change when contents or file paths change. Like index-hashify

How would you fix this problem, @agentme ?

Doesn't work with factor-bundle

const browserify = require('browserify')
const watchify = require('watchify')
const hmr = require('browserify-hmr')
const fs = require('fs')

const entries = [
  'src/dash.js',
  'src/home.js'
]

const outputs = [
  'dist/dash.js',
  'dist/home.js'
]

var b = browserify({ entries: entries, cache: {}, packageCache: {} })
  .transform('vueify')
  .plugin(watchify)
  .plugin(hmr)
  .plugin('factor-bundle', { outputs: outputs })

function bundle() {
  b.bundle().pipe(fs.createWriteStream('dist/common.js'))
}

b.on('update', bundle)
bundle()

There's a high chance I'm doing something wrong here, but i've spent a whole day trying different ways but the output is always _hmr_manager.js. I've also tried doing CLI commands and no luck there either.

Update broke my workflow

  "scripts": {
    "watch": "watchify source/index.js -p [ browserify-hmr -u http://$(my-local-ip):3123 ] -p ghostmodeify -t babelify -o public/browser/bundle.js -dv"
  },
  "devDependencies": {
    "babelify": "^6.3.0",
    "browserify": "^11.2.0",
    "browserify-hmr": "^0.2.2",
    "ecstatic": "^1.1.3",
    "ghostmodeify": "^0.1.1",
    "my-local-ip": "^1.0.0",
    "watchify": "^3.4.0"
  }

npm run watch worked, but after upgrading from 0.2.2 to 0.3.1

  "scripts": {
    "watch": "watchify source/index.js -p [ browserify-hmr -u http://$(my-local-ip):3123 ] -p ghostmodeify -t babelify -o public/browser/bundle.js -dv"
  },
  "devDependencies": {
    "babelify": "^6.3.0",
    "browserify": "^11.2.0",
    "browserify-hmr": "^0.3.1",
    "ecstatic": "^1.1.3",
    "ghostmodeify": "^0.1.1",
    "my-local-ip": "^1.0.0",
    "watchify": "^3.4.0"
  }

I get

polling-xhr.js:232 

GET http://192.168.2.109:3124/socket.io/?EIO=3&transport=polling&t=1444336564470-5 net::ERR_CONNECTION_REFUSED

@ polling-xhr.js:232Request 
@ polling-xhr.js:155XHR.request 
@ polling-xhr.js:86XHR.doPoll 
@ polling-xhr.js:116Polling.poll 
@ polling.js:118Polling.doOpen 
@ polling.js:62Transport.open 
@ transport.js:82Socket.open 
@ socket.js:220Socket 
@ socket.js:102Socket 
@ socket.js:37Manager.open.Manager.connect 
@ manager.js:205(anonymous function) 
@ manager.js:470setTimeout (async)Manager.reconnect 
@ manager.js:460(anonymous function) 
@ manager.js:474(anonymous function) 
@ manager.js:226Emitter.emit 
@ index.js:134Socket.onError 
@ socket.js:644(anonymous function) 
@ socket.js:251Emitter.emit 
@ index.js:134Transport.onError 
@ transport.js:69(anonymous function) 
@ polling-xhr.js:122Emitter.emit 
@ index.js:134Request.onError 
@ polling-xhr.js:278(anonymous function) 
@ polling-xhr.js:225setTimeout (async)Request.create.xhr.onreadystatechange 
@ polling-xhr.js:224XMLHttpRequest.send (async)Request.create 
@ polling-xhr.js:232Request 
@ polling-xhr.js:155XHR.request 
@ polling-xhr.js:86XHR.doPoll 
@ polling-xhr.js:116Polling.poll 
@ polling.js:118Polling.doOpen 
@ polling.js:62Transport.open 
@ transport.js:82Socket.open 
@ socket.js:220Socket 
@ socket.js:102Socket 
@ socket.js:37Manager.open.Manager.connect 
@ manager.js:205(anonymous function) 
@ manager.js:470setTimeout (async)Manager.reconnect 
@ manager.js:460(anonymous function) 
@ manager.js:474(anonymous function) 
@ manager.js:226Emitter.emit 
@ index.js:134Socket.onError 
@ socket.js:644(anonymous function) 
@ socket.js:251Emitter.emit 
@ index.js:134Transport.onError 
@ transport.js:69(anonymous function) 
@ polling-xhr.js:122Emitter.emit 
@ index.js:134Request.onError 
@ polling-xhr.js:278(anonymous function) 
@ polling-xhr.js:225

For now I just reverted back to 0.2.2, but what's wrong?

Doesn't handle $$ in filenames correctly

Ran into this error:

Uncaught TypeError: Cannot set property 'module' of undefined

Turns out there's a bug with the filenames?

screen shot 2016-04-28 at 1 57 23 am

screen shot 2016-04-28 at 1 57 28 am

screen shot 2016-04-28 at 1 57 32 am

Have you considered checksums?

how can i define a one accept method for all enabled modules?

i work with backbone/marionette and i want to try out what i can do to re-render a view on code/module change, or is that a bad idea?

also my setup includes gulp, browserify, rollupify, latest babel, not sure if thats of high importance. What i got so far is this:

import AppLayout from 'Views/AppLayout';
const appLayout = new AppLayout();
appLayout.render();

if (module.hot) {
  module.hot.accept('Views/AppLayout', deps => {
    console.log(deps);
  });
}

so now every time the AppLayout changes, the console log gets triggered, i guess i now can appLayout.render() again (forget the state right now..)

EDIT:
id like to define some kind of switch/case for all the different kind of modules which can enter the accept, could be a view, could be a model, etc. i dont want to define the accept for every module by hand, i want to define one accept per lets say instanceof (Backbone.View, Backbone.Model, etc.)

EDIT2:
also, if this is not the place to discuss that, where would the common hmr-api-discuccion-place be?

Modules get updated before bundle completes rebuild

I have a fairly large codebase that seems to produce a race condition between browserify-hmr and watchify. Sometimes the build takes about 8 seconds to rebuild when I file changes, but the module will hot (re)load after only a second.

I'm not sure if the race condition is caused me, or if it's actually a bug in browserify-hmr.

Script

{
  "scripts": {
    "watch:js": "NODE_ENV=development watchify -t babelify -t envify -p browserify-hmr --extension=.jsx -vd $npm_package_config_entry -o $npm_package_config_output"
  }
}

Video of Code Being Saved Running

browserify-hmr-bug

Live Reloading

First, great work on this module. It works well with budo.

In webpack, when a module without module.hot (like the app root) is changed, it triggers a full page refresh. I am not sure how to achieve this with browserify-hmr. I can include LiveReload but then any module changes will trigger a full page refresh.

Any ideas?

Problem with bufferutil and utf-8-validate

Using browserify-hmr now gives you these errors:

Error: Cannot find module 'bufferutil' from 'xxx/node_modules/ws/lib'
Error: Cannot find module 'utf-8-validate' from 'xxx/node_modules/ws/lib'

Because ws is now not compatible with browserify:

websockets/ws@e54d45f

This is a problem because browserify-hmr uses ws, which it assumes to be browserifyable (it was before!). As a workaround, you can install bufferutil and utf-8-validate, but it probably won't work completely (they rely on compiled extensions), and it will add 3.5MB of bloat on your package.

bundle fails when required a module from npm that uses its own browserify transform

Hi I just stumbled upon this issue:

When I try to use this module dtektor and at the same time I try to use browserify-hmr

I have made a small example repo for this issue: https://github.com/royriojas/browserify-hmr/tree/fail-source-map

npm start

> [email protected] start /Users/roy/royws/browserify-hmr/example
> ./scripts/run

Starting up http-server, serving ./
Available on:
  http:127.0.0.1:8080
  http:10.211.55.2:8080
  http:10.37.129.2:8080
  http:192.168.1.3:8080
Hit CTRL-C to stop the server
17:59:50 GMT-0500 (PET) [HMR] Emitting updates
17:59:50 GMT-0500 (PET) [HMR] Listening on localhost:3123
TypeError: Cannot read property 'substr' of undefined

This is what I get, the important part is this one:

TypeError: Cannot read property 'substr' of undefined

Apparently it fails when try to alter the source map of the previous run. I have done some investigation and it seems that fails here:

var node = new sm.SourceNode(null, null, null, [
   new sm.SourceNode(null, null, null, header),
   sm.SourceNode.fromStringWithSourceMap(row.source, new sm.SourceMapConsumer(inputMap)),
   new sm.SourceNode(null, null, null, footer)
]);

because the row.source does not correspond to the inputMap, because the transform altered the code.

Dynamic hostname of websocket connection?

Sometimes I need to test my app in a VM or remotely, so I access the js bundle using a different hostname than localhost. For hmr I specify -u http://0.0.0.0:3123 as the url of the websocket connection. The problem is the in the VM it will try to access http://0.0.0.0:3123 instead of using the IP/hostname of the server running the websocket server and fail. Is it possible to substitute 0.0.0.0 to the hostname that accessed the bundle at runtime?

npm install - vulnerability warning (0.3.7)

┌───────────────┬──────────────────────────────────────────────────────────────┐
│ High          │ Missing Origin Validation                                    │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ browserify-hmr                                               │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Patched in    │ No patch available                                           │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ browserify-hmr [dev]                                         │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ browserify-hmr                                               │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://npmjs.com/advisories/726                             │
└───────────────┴──────────────────────────────────────────────────────────────┘

Link to the issue: https://npmjs.com/advisories/726

I'm not sure what other hot-reloading libraries do to prevent this. Is there a fix/mitigation that can be implemented or can NPM be asked to change their warning?

I still find this library really useful and enjoy the stability and simplicity of the browserify toolchain!

Does not inject new code

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
  });

Browserify-hmr breaks the standalone option

I use browserify with the standalone option to avoid having to store initial state data on the window object in my universal apps.

I have found that adding the hmr plugin breaks the standalone option, though I have been unable to determine why. Reproduction:

package.json

{
  "name": "browserify-hmr-standalone",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "bundle": "browserify -p browserify-hmr index.js -o bundle.js -s Log",
    "bundle-no-hmr": "browserify index.js -o bundle.js -s Log"
  },
  "author": "James Hiscock <[email protected]> (http://jameshiscock.com/)",
  "license": "BSD-3-Clause",
  "devDependencies": {
    "browserify": "^13.0.0",
    "browserify-hmr": "^0.3.1"
  }
}

index.js

module.exports = function(message) {
    console.log(message)
}

index.html

<!DOCTYPE html>
<html>
    <head></head>
    <body>
        <script src="bundle.js"></script>
        <script>
            Log("Foo")
        </script>
    </body>
</html>

If you run npm run bundle-no-hmr and serve this folder up and visit index.html, you'll see Foo in the console.

If you run npm run bundle, close once the bundling is complete and serve this folder up and visit index.html, you'll see Log is not a function in the console. It's actually an empty object {}

Thanks for your time.

doesn't work well with nodemon

I haven't had a chance to dive in deeply but it appears hmr spawns it's own process to manage the websockets server. When nodemon detects a code change and restarts the main process, hmr tries to listen on 3123 again, which is still in use by the previous instance.

TypeError: Invalid attempt to destructure non-iterable instance

  1. Check out reactTransform branch
  2. Add a new file to the example (e.g. stuff.js)
  3. npm start the example
  4. Write require('./stuff'); in label.jsx

Expected: the file is normally imported.
Actual: TypeError: Invalid attempt to destructure non-iterable instance.

The error is being caught by the HMR code, but it seems thrown at the module evaluation time.

screen shot 2015-09-20 at 16 20 00

If you enable "pause on caught exceptions" in Chrome debugger, you'll see that the original exception happens during evaluation of the label.jsx code:

screen shot 2015-09-20 at 16 19 36

What strikes me as odd is that _interopRequireDefault Babel helper seems to actually point to sliced-to-array helper (note the filename in the popup). It explains the weird exception: _interopRequireDefault is a function that checks export for default, but slicedToArray is a completely different helper that expects an iterable.

It appears that something in the HMR machinery causes module IDs to get messed up, so require() made by Babel to one of its runtime utilities resolves to a different utility.

Updating source maps

It might be more of a question that an issue (or it might not be related to browserify-hmr) but it looks like source maps aren't updating with browserify-hmr, is there a way to have them updating somehow ?

support for websites running over https

Hi the current website I have is running over ssl, and I had tweak the socket-server to make it work on ssl (with self signed certs).

I was wondering if you might be interested in add the ssl option.

I know I can make it work on http as well, but it would be nice not having to add the http vhost for the app I'm currently developing

[PUG] how to use HMR template engine express

let router = require('./router.js');
app.set('views', path.resolve(__dirname, entryPath));
app.locals.basedir = path.resolve(__dirname, appConfig.folders.path);
app.set('view engine', 'pug');
app.use('/', router);

Not working with browserSync

Getting this error with Browserify-hmr when saving a js file:
[HMR] Error applying update TypeError: Failed to execute 'removeChild' on 'Node': parameter 1 is not of type 'Node'.
Is not hot reloading the browser

This is my gulpfile:

var elixir = require('laravel-elixir');
var gutils = require('gulp-util');
var  b = elixir.config.js.browserify;

if(gutils.env._.indexOf('watch') > -1){
    b.plugins.push({
          name: "browserify-hmr",
          options : {}
    });
}

b.transformers.push({
    name: "vueify",
    options : {}
});

elixir(function(mix) {
    // mix.sass('app.scss');
    mix.browserify('main.js');
    mix.browserSync({
        files: [
            elixir.config.appPath + '/**/*.php',
            elixir.config.get('public.css.outputFolder') + '/**/*.css',
            elixir.config.get('public.versioning.buildFolder') + '/rev-manifest.json',
            'resources/views/**/*.php'
        ],
         proxy: 'tasklap.app',
    }).version(["public/css/all.css", "public/js/main.js"]);
});

The Example doesn't work.

Just got this:

> [email protected] start ~/work/vue/browserify-hmr/example
> ./scripts/run

Starting up http-server, serving ./
Available on:
  http:127.0.0.1:8080
  http:192.168.0.232:8080
Hit CTRL-C to stop the server
events.js:160
      throw er; // Unhandled 'error' event
      ^

Error: watch ~/work/vue/browserify-hmr/example/node_modules/react/react.js ENOSPC
    at exports._errnoException (util.js:1012:11)
    at FSWatcher.start (fs.js:1429:19)
    at Object.fs.watch (fs.js:1456:11)
    at createFsWatchInstance (~/work/vue/browserify-hmr/example/node_modules/chokidar/lib/nodefs-handler.js:37:15)
    at setFsWatchListener (~/work/vue/browserify-hmr/example/node_modules/chokidar/lib/nodefs-handler.js:80:15)
    at FSWatcher.NodeFsHandler._watchWithNodeFs (~/work/vue/browserify-hmr/example/node_modules/chokidar/lib/nodefs-handler.js:228:14)
    at FSWatcher.NodeFsHandler._handleFile (~/work/vue/browserify-hmr/example/node_modules/chokidar/lib/nodefs-handler.js:255:21)
    at FSWatcher.<anonymous> (~/work/vue/browserify-hmr/example/node_modules/chokidar/lib/nodefs-handler.js:473:21)
    at FSReqWrap.oncomplete (fs.js:123:15)
[Fri, 19 Aug 2016 13:13:11 GMT] "GET /" "Mozilla/5.0 (X11; Linux x86_64; rv:48.0) Gecko/20100101 Firefox/48.0"
[Fri, 19 Aug 2016 13:13:12 GMT] "GET /bundle.js" "Mozilla/5.0 (X11; Linux x86_64; rv:48.0) Gecko/20100101 Firefox/48.0"
[Fri, 19 Aug 2016 13:13:12 GMT] "GET /bundle.js" Error (404): "Not found"

The version I used:

node: v6.3.1
npm:  v3.10.3

Access browserify-hmr across docker container.

Hello I am trying to put my existing web application into a docker container for dev purpose.

Everything is working except the hot module replacement. I suppose it's because browserify for security reason bind to localhost only and in a docker container the ip change.

My docker configuration is good because I got a connection reset and not a connection refused.

This is my package.json scripts (I add the -u http://0.0.0.0:3123 options for testing without results):

"watchify": "watchify -vd -p browserify-hmr -u http://0.0.0.0:3123 -e src/frontend/main.js -o dist/build.js",
"serve": "cross-env DEBUG=web:* nodemon --ignore dist -e js server.js",
"dev": "cross-env NODE_ENV=dev npm-run-all --parallel lint watchify serve",

By reading the doc it my be a combination of the noServe and the -u options but not sur how to use this inside a docker container with my apps files in a docker volume.

Broken with the latest version of browserify

This doesn't work with the latest version of browserify. Version 14.1.0

Uncaught TypeError: Cannot read property 'config' of undefined

Edit: after looking closer this could be an issue with Vueify and not this plugin. I apologize if that's the case.

[Feature-request] Dispatch custom DOM events when HMR updates modules

Hello,
I don't know if this project accepts feature requests, but anyway...

There are cases when dispatching a DOM event could be very useful. For example, I use Turbolinks in my project so I need to call window.location.reload() in order to get updated script.
I could subscribe to the HMR socket, but subscribing to an event seems like better solution, because in that case I don't need to check if my application uses development build or production version (hmr wouldn't get to prod build anyway and the event wouldn't be triggered).

Currently, I use a custom version from forked repository, but I think this feature would be useful for someone else.

Embeddable server

Hi. Firstly thanks so much for this project. I've been using it for a while and it's absolutely fantastic.

I am currently exploring the possibility of a browser based editing tool. I have an initial prototype working well with browserify-hmr, but it needs two ports - one for the main editor server and another for browserify-hmr. Is it possible to split up browserify hmr to allow it to run within an existing server?

Thanks.

Updating a module without update accepts bubbles up incorrectly

Noting this to myself to fix sometime.

If a module without any update accepters gets an update, then the update bubbles up as the system looks to see if its parents might have update accepters, but if we reach an entry script that isn't accepting updates of itself, we should decline the update. Instead, right now the update is incorrectly accepted, and the module and all of its parents all the way up to the entry module are re-executed. This can cause lots of issues (until the user refreshes). This appears as a console message "[HMR] Updated modules" followed by an array of a lot of modules all the way down to the entry script.

Tests for this exist in the "fail" branch.

Error in browser when using the plugin method in Gulp+Browserify+Browsersync

Using the plugin technique in my Gulp environment.

var watchify = require('watchify');
watcher = watchify(bundler);
watcher.plugin(hmr);

Builds ok, but when browser runs, I am getting:

Cannot find module './node_modules/browserify-hmr/inc/index.js'

Not sure what I am doing wrong, but, if I run "watchify -p browserify-hmr" from the command line , as in your example, it works fine. I am trying to integrate it in my current dev environment which is using Gulp+Browserify+BrowserSync.

Can't get it to work from remote server

hi,
i'm using:
watchify -vd -p browserify-hmr -e src/main.js -o dist/js/build.js
which works fine from localhost, but i cant get hmr to work when i develop from a remote server.
I tried things like:
watchify -vd -p [browserify-hmr -h remoteServer -u http://remoteServer:3123] -e src/main.js -o dist/js/build.js
but no luck.
I create a ssh tunnel with ssh -NL 3123:localhost:3123 user@serverName as a workaround, but that's less then ideal.

Any advice would be greatly appreciated
thanks
andrej

Capturing browserify errors

great tool, thank you for developing this

one feature i'd love to have is the injection of browserify errors (e.g. syntax errors) into my browser. figwheel has a little pop-up UI for syntax errors, but i would even do with something less fancy - just a console.log() statement like the others that browserify-HMR makes. this would prevent me from checking my terminal. (presently, code simply doesn't reload on a syntax error).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.