require() in Browserify and Gulp - javascript

My understanding the purpose of using Browserify is allow you to use require('modules') in the browser by bundling up all of your dependencies.
In Gulp, you can also use require('modules') - so how is that different from Browserify? for example:
var browserify = require('browserify');
var gulp = require('gulp');

require() is Node's way of loading/importing modules. When you run a Gulp task, it is being run by the Node runtime on your computer, so require() is "natively" supported.
Browserify came later, and was inspired by this behaviour. As it says on Browserify's website:
Browsers don't have the require method defined, but Node.js does. With Browserify you can write code that uses require in the same way that you would use it in Node.
In other words, when your JavaScript runs in a browser, there's no Node to be found, so you can't use require(). Browsers will complain that there's no such method. Browserify's solution is to let you write code with modules and require(), but with an extra compilation step before it ever gets to the browser so that require() works like it does in Node.
The "extra compilation step" involves working out what modules depend on others, and bundling your code in a way that facilitates certain modules to load other modules (with require()) when they need to. Browserify then has its own require() method that it makes available to browsers within your bundle, providing essentially the same functionality as Node's require().
This is a good article that explains how Browserify works.
So in some ways, to answer your question, there isn't that much difference that you need to worry about. The main practical difference is that Browserify needs an explicit compilation/build step to generate your output bundle whereas you don't need to think about that when running code with Node (and therefore Gulp).

Related

Modularity in Javascript

I know that if there are multiple JS files to be rendered by the browser, which apparently have identifiers inside, the global scope is polluted by this identifiers. I also know that one way to avoid this is using modules which(in my understanding) are just objects which have the aformentioned identifiers as members, thus sort of imitating C++ namespaces. I am also learning Node.js and there is a built in module system which eases this task so my question is: how to use modules in js files that are sent to the browser to be rendered?
Thanks.
Tools like browserify and WebPack are exactly what you are looking for (I personally prefer browserify over WebPack). Have a look at this answer, it explains a lot of your concerns.
In Node.JS, you can export a module using module.exports keyword, but you cannot just import those modules in your browser by just requiring them in a <script> tag. That's because, the browser doesn't understand the module system and everything works in the context of a global window object there, so module.exports simply becomes window.module.exports which I'm sure you'll not want. Hence you use tools like browserify that process the Node.JS scripts into something that your browser will understand.
This problem is usually solved by module bundlers or module loaders (e.g Webpack, Browserify, RequireJS). They are able to understand relations between your JS modules, skip unused modules and produce output that just works in your browser. All of that without the need to worry too much about global scope if you follow some conventions.
Some time ago, before ES6, two different approaches to this problem were widely used:
CommonJS:
var module = require('my-module');
widely known from Node.js
AMD:
define(['jquery'] , function ($) {
return function () {};
});
Which was suited for browser usage since it by design supported asynchronous loading of modules.
Then ES6 was introduced with native support for modules:
import * as lib from 'lib';
Main problem with new technology in web is that you often have variety of browsers to support which for a long time prevented developers from using new features. Nowadays, we have code transpilers and sophisticated code bundlers (e.g. Webpack). With their help you can use latest version of language, compile and bundle your code and at the end single "bundle.js" file is emitted which supports older browsers at the cost of slower execution times.

Babel and Browserify / Webpack confusion

Quick question. I am a bit confused about ES2015(ES6).
Let's say I use Babel to compile to ES6 Javascript to compliant ES5 for current browsers.
The import/export functions are already available in ES6 by using Babel. So why would I need something like Browserify or Webpack if I were to simply use these just to bundle my modules, when ES6 could do it for me?
Everywhere I go I see people using Babel in combination with Browserify or Webpack. Although I know something like Webpack can be used for more, but I wonder if it is also possible to bundle files using the ES6 syntax.
I might be totally in the wrong here and I might have gotten lost in the Javascript Jungle of 2016, so I hope someone can clarifty this for me.
Edit
Am I right to assume that the native ES6 import / export functionality simply does not bundle files? From what I have read so far I think you still need to include all the separate Javascript files but you simply import modules into each-others namespace by using the native import functionality?
Yes, using babel to transpile your ES6 imports into ES5 will work.
However, one advantage of using webpack is that creates one static file to be served up in your production environment.
Pre-ES6 has no native module system, so there are multiple systems constructed in userland code (e.g. CommonJS / Node modules and AMD). Those are what Babel converts ES6 module syntax to (and yes, you're correct that ES6 module syntax has no native bundling story anyway). Browsers have no knowledge of those userland APIs. Node implements its module system by wrapping a "module" in a function that injects require() etc. In a browser require() would just be a reference error. Browserify (or another bundler) makes it work in the browser, and bundles a whole dependency graph into a single script. So if the code is for the browser you're likely going to want to bundle it. If it's for Node you may not need to.
The import/export functions
Not functions, declarations.
if I were to simply use these just to bundle my modules, when ES6 could do it for me?
I wonder if it is also possible to bundle files using the ES6 syntax.
Am I right to assume that the native ES6 import / export functionality simply does not bundle files?
Yes. There's no native way to bundle ES6 modules. You can transpile ES6 module syntax to something like Node modules and bundle those.
From what I have read so far I think you still need to include all the separate Javascript files but you simply import modules into each-others namespace by using the native import functionality?
It's important to realize that while the syntax is standardized, a lot of the behavior isn't. There's a Loader spec under development to specify how modules will actually be located and loaded.
See also https://stackoverflow.com/a/33044085/1034448.

How to easily modularize Javascript like C/C++

I have a large project entirely built in JavaScript, I have an ordered and "inside modularized" 5k lines .js file that's the engine of whole site.
Now I have to make other site (extension of this one) in which I'll have to repeat a lot of code, my question is, I've seen lot of possibilities using Browserify, CommonJS, etc. But that's not what I'm searching, I'm searching modularize JavaScript just like C/C++, making #includes with the files of the functions or functionalities and reuse code like that. I'm already doing this including other JS files in HTML, but that JS files are only variables and some arrays, not functionality of the site.
I use jQuery too, in that large 5k lines .js file I have almost all inside the jQuery document.ready event, that's bringing trouble too, because I'll have to make a document.ready event for every file?
I need some orientation please
CommonJS will let you require() modules, this is the foundation for the NodeJS module system. Browserify simplifies this implementation for use in browsers and even allows you to require Node modules (as long as they don't depend on binaries, the file system and other features a browser doesn't support).
var lib = require('someLibrary');
ECMAScript6 (aka: ES6) brings imports to javascript. While browsers don't fully support ES6 yet, you can use Babel to "transpile" ES6 to ES5. This ES5 will take advantage of CommonJS to replicate the importing behaviour.
import { SomeClass, someFunction, someValue } from 'some/library';
In all cases, your javascript will require some kind of pre-processing to transpile it into javscript a browser can understand. This usually means taking all your separate source files and bundling them into a single minified bundle file. This reduces the number of requests the browser has to make.
To handle all this transpiling and bundling, several popular build systems exist including Grunt, Gulp and Webpack. Grunt is older and typically slower because of it's configuration-based design. Gulp is simpler and faster because it relies on NodeJS streams. Webpack is the newest and most powerful, but at the cost of complexity. For what you're hoping to do, I'd recommend looking at Webpack since it can modularize not only your javascript but your stylesheets and other web assets.
http://webpack.github.io/docs/tutorials/getting-started/
Use webpack to bundle your code http://webpack.github.io/docs/tutorials/getting-started/

How to bundle CommonJS modules into a single UMD library file?

I'm writing a JS library and organizing the code in a hierarchy of CommonJS modules connected with require calls. Then in addition there are also external dependencies (like Underscore).
How can I bundle all my library modules into a single file (CommonJS+AMD) excluding the external dependencies which should remain as require calls?
I've experimented with Browserify and came close with --standalone and --external but when using Browserify again on the application that is using this bundled library it gets confused with the remaining require calls inside the bundled lib. And when I get rid of them with something like Derequire it will also strip out the require calls to external dependencies.
I tried to figure out how other libraries approach this but they mostly seem to have some custom concatenation scripts. Is there a simpler solution? Seems like it should be a common enough use case.
Try what you're already doing with standalone and external, then when you bundle the second time pass the noParse option to browserify (e.g. browserify({noParse: ['/abs/path/to/first/bundle']})). Or you could try minifying the first bundle. See also this answer.

Run script using Browserify without build process first

I read through many articles on Browserify like http://javascriptplayground.com/blog/2013/11/backbone-browserify/ and there is always a step such as below:
$ browserify app/app.js | uglifyjs > app/bundle.js
This seems to be done before you run the script in the browser to see how it works. Is there a way NOT having to do build each time I change code? Something similar to define() function in requirejs...
It's 2015 now and there's a library for this, it's called drq. It uses internally sync xhr requests, so it's only well suited for development purposes. You just have to include it:
<script src="drq.js"></script>
And then, you can do your require calls in any script of the page:
<script>
var myModule = require('my-module'),
myClass = require('./classes/my-class.js');
// etc.
</script>
It will look for node modules up to your web root, so be sure to npm install them at a directory not upper than it. Also, please take a look at the GitHub page where you can find some tips to increase performance.
Again, please remember that bundles are the optimal solution for production.
I originally said you can't do this for the reasons below, but I want to add that where there is a will there is a way. I'm sure given enough time and effort, you (or someone) could (and probably will) come up with a way to accomplish this task - but as of right now (12/12/13), I don't know if there's any out of the box tools that will facilitate it.
browserify "modules" are written using the same concept as node.js modules. You write your code, and export any public methods/properties/etc via a module.exports object. Javascript in the browser doesn't support this sort of thing natively. There are some boilerplate templates (some info here) to help facilitate this in the browser, and they can be compatible with browserify, but...
When you browserify your code, the browserify script analyzes your syntax and finds the modules that it has to make available via the require method. This require method gets defined right in your bundle.js that you export, along with all the code for all the dependencies that your module needs. This allows the require method that browserify defines to work synchronously, returning a reference to the module that you requested immediately without waiting for any kind of web response (like, loading a js script).
Require.js works fundamentally differently than browserify. Require.js defines your packages using the define syntax you referenced, and exposes a require method which you use to tell Require.js which modules your code depends on. Require.js then, in turn, looks up the dependencies you require and if it hasn't loaded them for another module yet, generates a new script tag and forces your browser to load that module, waiting to execute your code until that is complete. This is an asynchronous process, which means, the javascript engine continues to process instructions while it waits for the new script to download, parse, and execute. Require.js wraps all of this up in some callbacks, so it can wait until all your dependencies are satisfied, before allowing your defined code to execute (which is why you pass functions to require and define, so require.js can execute them when it's ready).
The biggest reason to not want to bundle every time you make a change in development, is just for speed of iteration. Some things you can do (with browserify) to improve performance (that is, speed of bundling) are:
Don't uglify your code during development. You can just bundle it using browserify (make sure you use -d, for sourcemaps) without uglifying/minifying it, that should speed up the bundle performance a bit (for larger projects, anyway).
Split up your modules a little bit. Modules that don't have direct dependencies with one another don't have to be built at the same time. You can include different modules in your application using multiple script tags, or you can concatenate browserify bundles files together. You could absolutely set up some grunt tasks to watch your code for changes, and only compile the modules which contained the code change. This will cut out a lot of wasted cpu cycles, since browserify won't have to parse and transform multiple modules, just the ones that changed. From there you can re-concatenate into one big bundle, or just stick with the multiple bundle includes on the page.

Categories

Resources