ForbesLindesay / browserify-middleware

express middleware for browserify, done right
http://browserify.org
MIT License
381 stars 66 forks source link

How to use non-commonjs library with browserify? #20

Closed gagan-bansal closed 11 years ago

gagan-bansal commented 11 years ago

I want to use OpenLayers with borowserify-middleware, here are my code files app.js, main.js and index.html

I am able to display map properly, but there are few issues regarding the proper usage of browserify-middleware

ForbesLindesay commented 11 years ago

Source Maps

To answer the first point. The extra text at the end of the file is a source map. It makes debugging easier by showing all the source files as separate files. By default, it is enabled in development and disabled in production (i.e. when the NODE_ENV environment variable is set to production).

You can enable production mode manually by adding the following code before you call app.get('/foo.js', browserify('./foo.js')):

browserify.settings.mode = 'production';

You can optionally just disable source maps, which will remove that extra text, but make debugging more difficult, by adding:

browserify.settings.development('debug', false);

or on an individual route:

app.get('/index.js', browserify('./index.js', {debug: false}));

Even with debugging (i.e. source maps) enabled, they will be removed if you are minifying your files.

non CommonJS modules

To answer your second point, if OpenLayers is not a CommonJS module, it won't have any exports, and will instead assign to a global.

The reason that what you've been trying has become confusing is that you added:

app.use('/js',browserify('./client'));

So all the serving of individual js files was ignored. To do it the way you were originally trying to do it (not recommended by the way) you should simply do:

var browserify = require('browserify-middleware');
var express = require('express');
var app = express();

browserify.settings.development('basedir', __dirname);
app.get('/js/main.js', browserify('./client/main.js',{
  external: './client/OpenLayers.js',
  debug: false
}));
app.get('/js/OpenLayers.js',browserify(['./client/OpenLayers.js'], {
  noParse: './client/OpenLayers.js',
  cache: true,
  debug: false
}));

app.use(express.static(__dirname + '/public'));

app.listen(3000);
console.log("server listening at: 3000");

That code should be close, but may need some adjustment before it works properly. There are two nice sensible options though:

Option 1

If you want to have two separate files served to the client, you don't need to require open layers at all. Note that for source files you should use all lower case names, it makes caching simpler.

app.js

var browserify = require('browserify-middleware');
var express = require('express');
var app = express();

browserify.settings.development('basedir', __dirname);
app.get('/js/main.js', browserify('./client/main.js'));
app.get('/js/openlayers.js', function (req, res, next) {
  res.sendfile(__dirname + '/OpenLayers.js')
});

app.use(express.static(__dirname + '/public'));

app.listen(3000);
console.log("server listening at: 3000");

main.js

var osm = new OpenLayers.Layer.OSM();
osm.wrapDateLine = false;
var map = new OpenLayers.Map("map",{projection:'EPSG:900913',numZoomLevels:18});
map.addLayers([osm]);
map.setCenter(new OpenLayers.LonLat(8126483.8753499,2162623.286343),15);
console.log('init function called');

index.html

<html>
<head>
  <style>
    #map {
      width:600px;
      height:400px;
    }
  </style>
</head>
<body>
  Sample map with OpenLayers
  <div id="map"></div>
  <script type="text/javascript" src="/js/openlayers.js"></script>
  <script type="text/javascript" src="/js/main.js"></script>
</body>
</html>

Option 2

If you're fine with having just a single file (this is almost certainly a better approach in pretty much every respect) you can use require, just don't assign it to anything.

app.js

var browserify = require('browserify-middleware');
var express = require('express');
var app = express();

browserify.settings.development('basedir', __dirname);
app.get('/js/main.js', browserify('./client/main.js'));

app.use(express.static(__dirname + '/public'));

app.listen(3000);
console.log("server listening at: 3000");

main.js

require('./OpenLayers.js');
var osm = new OpenLayers.Layer.OSM();
osm.wrapDateLine = false;
var map = new OpenLayers.Map("map",{projection:'EPSG:900913',numZoomLevels:18});
map.addLayers([osm]);
map.setCenter(new OpenLayers.LonLat(8126483.8753499,2162623.286343),15);
console.log('init function called');

index.html

<html>
<head>
  <style>
    #map {
      width:600px;
      height:400px;
    }
  </style>
</head>
<body>
  Sample map with OpenLayers
  <div id="map"></div>
  <script type="text/javascript" src="/js/main.js"></script>
</body>
</html>

N.B. By putting the script tag at the end, we don't need the wacky onload stuff. The DOM will already be fully loaded when the script executes.

gagan-bansal commented 11 years ago

Thanks for the detailed explanations and for editing my code to remove the legacy style (onload). Your code gave me a good understanding to write code with browserify. As I am transferring my code from AMD (RequireJS) I need to study more about the browserify. Browserify-v2 seems very promising.
As you mentioned that option 2 is better approach, is it better in production or even in development ?

ForbesLindesay commented 10 years ago

It's definitely a simpler approach. It will be more performant in most situations. There is one situation in which you might want to use option 1, if all the following are true:

That last one is the killer. It's very unlikely that you gain any significant performance benefit by using Option 1, and Option 2 will always be faster for the first page load, since it only makes one request instead of 2. Option 1 is only faster if OpenLayers.js is already in the cache, and main.js must be re-loaded from the server. If the whole thing is cached, Option 2 will be faster, if nothing is cached, Option 2 will be faster.

If you have performance problems, run benchmarks. If you don't know whether you have performance problems, carry on building awesome features and fixing bugs until someone says "I don't like this website because it's too slow".

gagan-bansal commented 10 years ago

Thanks again for such a detailed explanation.

ForbesLindesay commented 10 years ago

No problem, I hope you manage to use this library to build something awesome :smile:

maraoz commented 10 years ago

Thanks for the explanation on the best practices to include non-commonjs modules into a browserify bundle @ForbesLindesay ! I'll try it out now and report if any problem arises.

benjamingr commented 8 years ago

@ForbesLindesay hey, any chance you could copy-paste your answer here: http://stackoverflow.com/questions/34962506/how-to-include-my-ownnon-moduled-scripts-using-browserify ? (Since you're an active SO user and all and you should get credit for it - excellent writeup btw)