Browserify Cheatsheet¶
Browserify - Browser-side require()
Browserify lets you require('modules') in the browser by bundling up all of your dependencies. It uses the same module system as Node.js, allowing you to use npm modules in the browser and organize your code with CommonJS modules.
Table of Contents¶
- Installation
- Getting Started
- Basic Usage
- Command Line Interface
- Programmatic API
- Transforms
- Plugins
- Source Maps
- External Dependencies
- Multiple Bundles
- Development Workflow
- Production Builds
- Testing
- Advanced Features
- Performance Optimization
- Debugging
- Migration
- Best Practices
Installation¶
Global Installation¶
Local Installation (Recommended)¶
# Initialize npm project
npm init -y
# Install Browserify locally
npm install --save-dev browserify
# Install common transforms
npm install --save-dev babelify uglifyify envify
Project Setup¶
# Create project structure
mkdir my-browserify-project
cd my-browserify-project
# Initialize package.json
npm init -y
# Install Browserify and dependencies
npm install --save-dev browserify babelify @babel/core @babel/preset-env
# Create source directories
mkdir -p src/{js,css}
mkdir dist
# Create entry point
touch src/js/main.js
Package.json Scripts¶
{
"name": "my-browserify-project",
"version": "1.0.0",
"scripts": {
"build": "browserify src/js/main.js -o dist/bundle.js",
"build:watch": "watchify src/js/main.js -o dist/bundle.js -v",
"build:prod": "browserify src/js/main.js -t [ babelify --presets [ @babel/preset-env ] ] -t uglifyify -o dist/bundle.min.js",
"dev": "budo src/js/main.js:bundle.js --live --open",
"test": "tape test/*.js | tap-spec"
},
"browserify": {
"transform": [
["babelify", {
"presets": ["@babel/preset-env"]
}]
]
}
}
Getting Started¶
Basic Module Structure¶
// src/js/math.js - A simple module
function add(a, b) {
return a + b;
}
function multiply(a, b) {
return a * b;
}
function subtract(a, b) {
return a - b;
}
// Export functions
module.exports = {
add: add,
multiply: multiply,
subtract: subtract
};
// Or using shorthand
module.exports = { add, multiply, subtract };
// src/js/utils.js - Utility functions
const capitalize = (str) => {
return str.charAt(0).toUpperCase() + str.slice(1);
};
const formatDate = (date) => {
return date.toLocaleDateString();
};
const debounce = (func, wait) => {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
};
module.exports = {
capitalize,
formatDate,
debounce
};
Main Entry Point¶
// src/js/main.js - Application entry point
const math = require('./math');
const utils = require('./utils');
const $ = require('jquery'); // npm module
// Use local modules
console.log('2 + 3 =', math.add(2, 3));
console.log('4 * 5 =', math.multiply(4, 5));
// Use utility functions
const title = utils.capitalize('hello world');
console.log('Capitalized:', title);
// Use npm modules
$(document).ready(function() {
$('body').append('<h1>' + title + '</h1>');
// Add some interactivity
$('h1').click(function() {
$(this).css('color', 'blue');
});
});
// Export for testing
if (typeof module !== 'undefined' && module.exports) {
module.exports = { math, utils };
}
HTML Integration¶
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Browserify Demo</title>
</head>
<body>
<div id="app">
<h2>Browserify Application</h2>
<button id="calculate">Calculate</button>
<div id="result"></div>
</div>
<!-- Include the bundled JavaScript -->
<script src="dist/bundle.js"></script>
</body>
</html>
Basic Usage¶
Simple Bundle Creation¶
# Basic bundling
browserify src/js/main.js -o dist/bundle.js
# Bundle with verbose output
browserify src/js/main.js -o dist/bundle.js -v
# Bundle to stdout
browserify src/js/main.js
# Bundle multiple entry points
browserify src/js/main.js src/js/admin.js -o dist/bundle.js
Using Transforms¶
# Bundle with Babel transform
browserify src/js/main.js -t babelify -o dist/bundle.js
# Bundle with multiple transforms
browserify src/js/main.js -t babelify -t uglifyify -o dist/bundle.js
# Transform with options
browserify src/js/main.js -t [ babelify --presets [ @babel/preset-env ] ] -o dist/bundle.js
Watch Mode¶
# Install watchify
npm install --save-dev watchify
# Watch for changes
watchify src/js/main.js -o dist/bundle.js -v
# Watch with transforms
watchify src/js/main.js -t babelify -o dist/bundle.js -v
# Watch with polling (for network drives)
watchify src/js/main.js -o dist/bundle.js -v --poll
Command Line Interface¶
Basic Commands¶
# Bundle a file
browserify input.js -o output.js
# Bundle to stdout
browserify input.js > output.js
# Bundle with debug info
browserify input.js -d -o output.js
# Bundle with standalone UMD
browserify input.js -s MyModule -o output.js
Advanced Options¶
# Exclude modules
browserify input.js -x jquery -o output.js
# External dependencies
browserify input.js --external jquery -o output.js
# Ignore modules
browserify input.js --ignore fs -o output.js
# Insert global variables
browserify input.js --insert-globals -o output.js
# Detect globals
browserify input.js --detect-globals -o output.js
Transform Options¶
# Apply transforms
browserify input.js -t babelify -o output.js
# Transform with configuration
browserify input.js -t [ babelify --presets [ @babel/preset-env ] ] -o output.js
# Global transforms (apply to node_modules)
browserify input.js -g uglifyify -o output.js
# List available transforms
npm search browserify-transform
Plugin Options¶
# Use plugins
browserify input.js -p [ factor-bundle -o bundle1.js -o bundle2.js ] -o common.js
# Plugin with options
browserify input.js -p [ browserify-shim ] -o output.js
# Multiple plugins
browserify input.js -p plugin1 -p plugin2 -o output.js
Programmatic API¶
Basic API Usage¶
// build.js - Build script using Browserify API
const browserify = require('browserify');
const fs = require('fs');
// Create browserify instance
const b = browserify({
entries: ['src/js/main.js'],
debug: true // Enable source maps
});
// Add transforms
b.transform('babelify', {
presets: ['@babel/preset-env']
});
// Bundle and write to file
b.bundle()
.pipe(fs.createWriteStream('dist/bundle.js'))
.on('finish', () => {
console.log('Bundle created successfully!');
})
.on('error', (err) => {
console.error('Bundle error:', err);
});
Advanced API Configuration¶
const browserify = require('browserify');
const fs = require('fs');
const path = require('path');
// Advanced configuration
const b = browserify({
entries: ['src/js/main.js'],
debug: process.env.NODE_ENV !== 'production',
cache: {},
packageCache: {},
fullPaths: false,
// Transform options
transform: [
['babelify', {
presets: ['@babel/preset-env'],
sourceMaps: true
}]
],
// Plugin options
plugin: [
['factor-bundle', {
outputs: ['dist/page1.js', 'dist/page2.js']
}]
]
});
// Add external dependencies
b.external(['jquery', 'lodash']);
// Add ignore patterns
b.ignore('fs');
b.ignore('path');
// Bundle with error handling
function bundle() {
return b.bundle()
.on('error', function(err) {
console.error('Browserify error:', err.message);
this.emit('end');
})
.pipe(fs.createWriteStream('dist/bundle.js'));
}
// Initial bundle
bundle();
// Watch for changes (if using watchify)
if (process.env.NODE_ENV === 'development') {
const watchify = require('watchify');
const w = watchify(b);
w.on('update', () => {
console.log('Rebuilding...');
bundle();
});
w.on('log', (msg) => {
console.log(msg);
});
}
Stream Processing¶
const browserify = require('browserify');
const through2 = require('through2');
const uglify = require('uglify-js');
// Custom stream processing
function createBundle() {
const b = browserify('src/js/main.js');
return b.bundle()
.pipe(through2(function(chunk, enc, callback) {
// Custom processing
let code = chunk.toString();
// Minify in production
if (process.env.NODE_ENV === 'production') {
const result = uglify.minify(code);
code = result.code;
}
this.push(code);
callback();
}))
.pipe(fs.createWriteStream('dist/bundle.js'));
}
createBundle();
Transforms¶
Babel Transform¶
// .babelrc
{
"presets": ["@babel/preset-env"],
"plugins": [
"@babel/plugin-transform-arrow-functions",
"@babel/plugin-transform-classes"
]
}
CoffeeScript Transform¶
# src/js/app.coffee
class Calculator
constructor: ->
@result = 0
add: (num) ->
@result += num
@
multiply: (num) ->
@result *= num
@
getResult: ->
@result
module.exports = Calculator
TypeScript Transform¶
// src/js/app.ts
interface Calculator {
add(a: number, b: number): number;
multiply(a: number, b: number): number;
}
class BasicCalculator implements Calculator {
add(a: number, b: number): number {
return a + b;
}
multiply(a: number, b: number): number {
return a * b;
}
}
export default BasicCalculator;
CSS Transforms¶
Environment Variables¶
// src/js/config.js
const config = {
apiUrl: process.env.API_URL || 'http://localhost:3000',
debug: process.env.NODE_ENV === 'development',
version: process.env.npm_package_version
};
module.exports = config;
# Bundle with environment variables
API_URL=https://api.example.com browserify src/js/main.js -t envify -o dist/bundle.js
Plugins¶
Factor Bundle Plugin¶
// Multiple entry points with shared dependencies
const browserify = require('browserify');
const b = browserify({
entries: ['src/js/page1.js', 'src/js/page2.js']
});
b.plugin('factor-bundle', {
outputs: ['dist/page1.js', 'dist/page2.js']
});
b.bundle().pipe(fs.createWriteStream('dist/common.js'));
Bundle Collapser¶
// Reduce bundle size by collapsing modules
const b = browserify('src/js/main.js');
b.plugin('bundle-collapser/plugin');
b.bundle().pipe(fs.createWriteStream('dist/bundle.js'));
Browserify Shim¶
// package.json
{
"browserify": {
"transform": ["browserify-shim"]
},
"browserify-shim": {
"jquery": "global:jQuery",
"bootstrap": {
"depends": ["jquery"],
"exports": "bootstrap"
}
}
}
Disc Plugin (Bundle Analysis)¶
// Analyze bundle size
const browserify = require('browserify');
const disc = require('disc');
const b = browserify('src/js/main.js');
b.plugin(disc, {
output: 'bundle-analysis.html',
open: true
});
b.bundle().pipe(process.stdout);
Source Maps¶
Enabling Source Maps¶
# Enable debug mode for source maps
browserify src/js/main.js -d -o dist/bundle.js
# Source maps with transforms
browserify src/js/main.js -t babelify -d -o dist/bundle.js
Programmatic Source Maps¶
const browserify = require('browserify');
const exorcist = require('exorcist');
// External source maps
browserify('src/js/main.js', { debug: true })
.bundle()
.pipe(exorcist('dist/bundle.js.map'))
.pipe(fs.createWriteStream('dist/bundle.js'));
Source Map Options¶
const b = browserify({
entries: ['src/js/main.js'],
debug: true,
// Source map options
sourceMaps: true,
sourceMapPrefix: '/src',
sourceRoot: '/src'
});
Inline Source Maps¶
// Inline source maps for development
const b = browserify({
entries: ['src/js/main.js'],
debug: true
});
// Transform with source maps
b.transform('babelify', {
sourceMaps: 'inline'
});
External Dependencies¶
Creating Vendor Bundle¶
# Create vendor bundle with common libraries
browserify -r jquery -r lodash -r moment -o dist/vendor.js
# Create app bundle excluding vendor libraries
browserify src/js/main.js -x jquery -x lodash -x moment -o dist/app.js
Programmatic External Dependencies¶
// vendor.js - Create vendor bundle
const browserify = require('browserify');
const vendor = browserify();
vendor.require('jquery');
vendor.require('lodash');
vendor.require('moment');
vendor.bundle().pipe(fs.createWriteStream('dist/vendor.js'));
// app.js - Create app bundle
const app = browserify('src/js/main.js');
app.external('jquery');
app.external('lodash');
app.external('moment');
app.bundle().pipe(fs.createWriteStream('dist/app.js'));
HTML Integration¶
<!DOCTYPE html>
<html>
<head>
<title>Multi-bundle App</title>
</head>
<body>
<!-- Load vendor bundle first -->
<script src="dist/vendor.js"></script>
<!-- Then load app bundle -->
<script src="dist/app.js"></script>
</body>
</html>
Dynamic Externals¶
// Dynamic external configuration
const externals = ['jquery', 'lodash', 'react', 'react-dom'];
const b = browserify('src/js/main.js');
externals.forEach(lib => {
b.external(lib);
});
b.bundle().pipe(fs.createWriteStream('dist/app.js'));
Multiple Bundles¶
Factor Bundle Setup¶
// build-multiple.js
const browserify = require('browserify');
const factor = require('factor-bundle');
const b = browserify({
entries: [
'src/js/pages/home.js',
'src/js/pages/about.js',
'src/js/pages/contact.js'
]
});
b.plugin(factor, {
outputs: [
'dist/home.js',
'dist/about.js',
'dist/contact.js'
]
});
// Common bundle
b.bundle().pipe(fs.createWriteStream('dist/common.js'));
Page-specific Bundles¶
// src/js/pages/home.js
const common = require('../common');
const analytics = require('../analytics');
// Home page specific code
const homeController = {
init() {
console.log('Home page initialized');
analytics.track('page_view', 'home');
},
setupCarousel() {
// Home page carousel logic
}
};
homeController.init();
module.exports = homeController;
// src/js/pages/about.js
const common = require('../common');
// About page specific code
const aboutController = {
init() {
console.log('About page initialized');
},
setupTeamGrid() {
// About page team grid logic
}
};
aboutController.init();
module.exports = aboutController;
Build Script for Multiple Bundles¶
// build-all.js
const browserify = require('browserify');
const fs = require('fs');
const path = require('path');
const pages = ['home', 'about', 'contact', 'products'];
// Build individual page bundles
pages.forEach(page => {
const b = browserify(`src/js/pages/${page}.js`);
// Add common externals
b.external('jquery');
b.external('lodash');
b.bundle()
.pipe(fs.createWriteStream(`dist/${page}.js`))
.on('finish', () => {
console.log(`${page}.js bundle created`);
});
});
// Build vendor bundle
const vendor = browserify();
vendor.require('jquery');
vendor.require('lodash');
vendor.bundle()
.pipe(fs.createWriteStream('dist/vendor.js'))
.on('finish', () => {
console.log('vendor.js bundle created');
});
Development Workflow¶
Development Server¶
// package.json scripts
{
"scripts": {
"dev": "budo src/js/main.js:bundle.js --live --open --port 3000",
"dev:https": "budo src/js/main.js:bundle.js --live --open --ssl",
"dev:host": "budo src/js/main.js:bundle.js --live --host 0.0.0.0"
}
}
Live Reload Setup¶
// dev-server.js
const budo = require('budo');
const babelify = require('babelify');
budo('src/js/main.js:bundle.js', {
live: true,
open: true,
port: 3000,
stream: process.stdout,
// Browserify options
browserify: {
transform: [
babelify.configure({
presets: ['@babel/preset-env']
})
],
debug: true
}
}).on('connect', (ev) => {
console.log('Server running on %s', ev.uri);
});
Hot Module Replacement¶
// src/js/main.js with HMR
const app = require('./app');
// Initialize app
app.init();
// Hot module replacement
if (module.hot) {
module.hot.accept('./app', () => {
const newApp = require('./app');
newApp.init();
});
}
Development Build Script¶
// dev-build.js
const browserify = require('browserify');
const watchify = require('watchify');
const babelify = require('babelify');
// Create watchify instance
const b = watchify(browserify({
entries: ['src/js/main.js'],
cache: {},
packageCache: {},
debug: true
}));
// Add transforms
b.transform(babelify, {
presets: ['@babel/preset-env']
});
// Bundle function
function bundle() {
return b.bundle()
.on('error', (err) => {
console.error('Bundle error:', err.message);
})
.pipe(fs.createWriteStream('dist/bundle.js'))
.on('finish', () => {
console.log('Bundle updated');
});
}
// Watch for changes
b.on('update', bundle);
b.on('log', console.log);
// Initial bundle
bundle();
Production Builds¶
Minification¶
# Production build with minification
NODE_ENV=production browserify src/js/main.js -t babelify -g uglifyify -o dist/bundle.min.js
Production Build Script¶
// build-prod.js
const browserify = require('browserify');
const uglifyify = require('uglifyify');
const envify = require('envify');
// Set production environment
process.env.NODE_ENV = 'production';
const b = browserify({
entries: ['src/js/main.js'],
debug: false // Disable source maps for production
});
// Add transforms
b.transform('babelify', {
presets: ['@babel/preset-env']
});
b.transform('envify', {
NODE_ENV: 'production'
});
// Global transforms (apply to node_modules)
b.transform('uglifyify', {
global: true,
compress: {
drop_console: true,
drop_debugger: true
}
});
// Bundle
b.bundle()
.pipe(fs.createWriteStream('dist/bundle.min.js'))
.on('finish', () => {
console.log('Production bundle created');
});
Bundle Analysis¶
// analyze-bundle.js
const browserify = require('browserify');
const disc = require('disc');
const b = browserify('src/js/main.js');
b.plugin(disc, {
output: 'bundle-analysis.html',
open: true
});
b.bundle((err, buf) => {
if (err) {
console.error('Bundle error:', err);
} else {
console.log('Bundle size:', (buf.length / 1024).toFixed(2) + 'KB');
}
});
Gzip Analysis¶
// gzip-analysis.js
const browserify = require('browserify');
const zlib = require('zlib');
browserify('src/js/main.js')
.bundle((err, buf) => {
if (err) throw err;
const size = buf.length;
zlib.gzip(buf, (err, gzipped) => {
if (err) throw err;
const gzipSize = gzipped.length;
console.log('Bundle size:', (size / 1024).toFixed(2) + 'KB');
console.log('Gzipped size:', (gzipSize / 1024).toFixed(2) + 'KB');
console.log('Compression ratio:', ((1 - gzipSize / size) * 100).toFixed(1) + '%');
});
});
Testing¶
Unit Testing with Tape¶
// test/math.test.js
const test = require('tape');
const math = require('../src/js/math');
test('Math module tests', (t) => {
t.equal(math.add(2, 3), 5, 'Addition works correctly');
t.equal(math.multiply(4, 5), 20, 'Multiplication works correctly');
t.equal(math.subtract(10, 3), 7, 'Subtraction works correctly');
t.end();
});
Browser Testing¶
// package.json
{
"testling": {
"files": "test/*.js",
"browsers": [
"ie/9..latest",
"chrome/latest",
"firefox/latest",
"safari/latest"
]
}
}
Karma Integration¶
# Install karma and browserify
npm install --save-dev karma karma-browserify karma-chrome-launcher karma-jasmine
// karma.conf.js
module.exports = function(config) {
config.set({
frameworks: ['jasmine', 'browserify'],
files: [
'test/**/*.js'
],
preprocessors: {
'test/**/*.js': ['browserify']
},
browserify: {
debug: true,
transform: ['babelify']
},
browsers: ['Chrome'],
singleRun: true
});
};
Mocking and Stubbing¶
// test/api.test.js
const test = require('tape');
const proxyquire = require('proxyquire');
// Mock HTTP requests
const apiModule = proxyquire('../src/js/api', {
'http': {
get: (url, callback) => {
// Mock response
callback({
statusCode: 200,
body: JSON.stringify({ success: true })
});
}
}
});
test('API module tests', (t) => {
apiModule.fetchData((err, data) => {
t.error(err, 'No error occurred');
t.ok(data.success, 'API returned success');
t.end();
});
});
Advanced Features¶
Custom Transforms¶
// transforms/custom-transform.js
const through = require('through2');
const path = require('path');
module.exports = function(file, opts) {
// Only process .custom files
if (path.extname(file) !== '.custom') {
return through();
}
let content = '';
return through(
function(chunk, enc, callback) {
content += chunk.toString();
callback();
},
function(callback) {
// Transform the content
const transformed = content
.replace(/CUSTOM_SYNTAX/g, 'JavaScript equivalent')
.replace(/\$\{([^}]+)\}/g, '" + $1 + "');
this.push('module.exports = ' + JSON.stringify(transformed));
callback();
}
);
};
Plugin Development¶
// plugins/custom-plugin.js
module.exports = function(b, opts) {
opts = opts || {};
b.on('bundle', function(bundle) {
console.log('Bundle started');
});
b.pipeline.get('record').push(through.obj(function(row, enc, next) {
// Modify module records
if (row.file.endsWith('.special.js')) {
row.source = '// Special processing\n' + row.source;
}
this.push(row);
next();
}));
};
Conditional Bundling¶
// conditional-build.js
const browserify = require('browserify');
const isProduction = process.env.NODE_ENV === 'production';
const isDevelopment = !isProduction;
const b = browserify({
entries: ['src/js/main.js'],
debug: isDevelopment
});
// Conditional transforms
if (isDevelopment) {
b.transform('browserify-hmr');
} else {
b.transform('uglifyify', { global: true });
}
// Conditional plugins
if (isProduction) {
b.plugin('bundle-collapser/plugin');
}
b.bundle().pipe(fs.createWriteStream(
isProduction ? 'dist/bundle.min.js' : 'dist/bundle.js'
));
Dynamic Imports¶
// src/js/dynamic-loader.js
const loadModule = (moduleName) => {
return new Promise((resolve, reject) => {
// Dynamic require (note: this needs special handling in browserify)
try {
const module = require(`./modules/${moduleName}`);
resolve(module);
} catch (err) {
reject(err);
}
});
};
// Usage
loadModule('feature-a').then(module => {
module.init();
});
Performance Optimization¶
Bundle Splitting¶
// Split bundles by feature
const features = ['auth', 'dashboard', 'settings'];
features.forEach(feature => {
const b = browserify(`src/js/features/${feature}/index.js`);
// External common dependencies
b.external('jquery');
b.external('lodash');
b.bundle()
.pipe(fs.createWriteStream(`dist/${feature}.js`));
});
Lazy Loading¶
// src/js/lazy-loader.js
const lazyLoad = (modulePath) => {
return new Promise((resolve) => {
// Simulate dynamic loading
setTimeout(() => {
const module = require(modulePath);
resolve(module);
}, 100);
});
};
// Usage in main app
document.getElementById('load-feature').addEventListener('click', () => {
lazyLoad('./features/advanced-feature').then(feature => {
feature.initialize();
});
});
Code Splitting with Factor Bundle¶
// advanced-splitting.js
const browserify = require('browserify');
const factor = require('factor-bundle');
// Define entry points
const entries = [
'src/js/pages/home.js',
'src/js/pages/products.js',
'src/js/pages/checkout.js'
];
const b = browserify({
entries: entries,
debug: false
});
// Configure factor bundle
b.plugin(factor, {
outputs: [
'dist/home.js',
'dist/products.js',
'dist/checkout.js'
],
threshold: 1 // Minimum number of bundles a module must be in to be factored out
});
// Common bundle
b.bundle()
.pipe(fs.createWriteStream('dist/common.js'))
.on('finish', () => {
console.log('Code splitting completed');
});
Bundle Size Optimization¶
// optimize-bundle.js
const browserify = require('browserify');
const uglifyify = require('uglifyify');
const bundleCollapser = require('bundle-collapser/plugin');
const b = browserify('src/js/main.js');
// Optimization transforms and plugins
b.transform('uglifyify', {
global: true,
compress: {
drop_console: true,
drop_debugger: true,
pure_funcs: ['console.log', 'console.info']
},
mangle: {
reserved: ['$', 'jQuery']
}
});
b.plugin(bundleCollapser);
// Ignore unnecessary modules
b.ignore('fs');
b.ignore('path');
b.ignore('crypto');
b.bundle()
.pipe(fs.createWriteStream('dist/bundle.optimized.js'));
Debugging¶
Debug Mode¶
# Enable debug mode for detailed output
browserify src/js/main.js -d -o dist/bundle.js
# Verbose output
browserify src/js/main.js -v -o dist/bundle.js
Source Map Debugging¶
// Enable source maps in development
const b = browserify({
entries: ['src/js/main.js'],
debug: true, // Enables inline source maps
fullPaths: true // Keep full paths for better debugging
});
Bundle Analysis¶
// debug-bundle.js
const browserify = require('browserify');
const deps = require('browserify-deps');
// Analyze dependencies
browserify('src/js/main.js')
.pipeline.get('deps')
.pipe(deps())
.pipe(through.obj(function(row, enc, next) {
console.log('Module:', row.file);
console.log('Dependencies:', row.deps);
console.log('---');
next();
}));
Error Handling¶
// error-handling.js
const browserify = require('browserify');
const b = browserify('src/js/main.js');
b.bundle()
.on('error', function(err) {
console.error('Browserify error:');
console.error('Message:', err.message);
console.error('File:', err.filename);
console.error('Line:', err.line);
console.error('Column:', err.column);
// Don't exit process in watch mode
this.emit('end');
})
.pipe(fs.createWriteStream('dist/bundle.js'));
Profiling¶
// profile-build.js
const browserify = require('browserify');
console.time('Bundle time');
browserify('src/js/main.js')
.bundle()
.pipe(fs.createWriteStream('dist/bundle.js'))
.on('finish', () => {
console.timeEnd('Bundle time');
// Memory usage
const used = process.memoryUsage();
console.log('Memory usage:');
for (let key in used) {
console.log(`${key}: ${Math.round(used[key] / 1024 / 1024 * 100) / 100} MB`);
}
});
Migration¶
From Webpack¶
// webpack.config.js equivalent in Browserify
// Webpack:
// module.exports = {
// entry: './src/index.js',
// output: {
// filename: 'bundle.js',
// path: path.resolve(__dirname, 'dist')
// },
// module: {
// rules: [{
// test: /\.js$/,
// use: 'babel-loader'
// }]
// }
// };
// Browserify equivalent:
const browserify = require('browserify');
browserify('./src/index.js')
.transform('babelify')
.bundle()
.pipe(fs.createWriteStream('dist/bundle.js'));
From RequireJS¶
// RequireJS config equivalent
// requirejs.config({
// baseUrl: 'src/js',
// paths: {
// 'jquery': 'vendor/jquery',
// 'lodash': 'vendor/lodash'
// }
// });
// Browserify approach - use npm modules
// npm install jquery lodash
// src/js/main.js
const $ = require('jquery');
const _ = require('lodash');
// Use modules normally
$('#app').text('Hello from Browserify');
Migration Checklist¶
- Convert AMD/RequireJS modules to CommonJS
- Install npm equivalents of vendor libraries
- Update build scripts to use Browserify
- Configure transforms for preprocessing
- Set up development workflow with watchify
- Update HTML to use bundled scripts
- Test all functionality after migration
Best Practices¶
Module Organization¶
// Good: Clear module structure
// src/js/modules/user.js
const api = require('../api');
const utils = require('../utils');
class User {
constructor(data) {
this.data = data;
}
save() {
return api.post('/users', this.data);
}
format() {
return utils.formatUser(this.data);
}
}
module.exports = User;
Dependency Management¶
// package.json - Clear separation of dependencies
{
"dependencies": {
"jquery": "^3.6.0",
"lodash": "^4.17.21"
},
"devDependencies": {
"browserify": "^17.0.0",
"babelify": "^10.0.0",
"watchify": "^4.0.0"
}
}
Build Configuration¶
// build-config.js - Centralized configuration
const config = {
entry: 'src/js/main.js',
output: 'dist/bundle.js',
transforms: [
['babelify', { presets: ['@babel/preset-env'] }]
],
plugins: process.env.NODE_ENV === 'production' ? [
'bundle-collapser/plugin'
] : [],
external: ['jquery', 'lodash'],
debug: process.env.NODE_ENV !== 'production'
};
module.exports = config;
Performance Best Practices¶
- Use external bundles for large libraries
- Implement code splitting for large applications
- Enable source maps only in development
- Use transforms judiciously - they add build time
- Profile your builds to identify bottlenecks
Development Best Practices¶
- Use watchify for fast rebuilds during development
- Set up live reload with budo or similar tools
- Implement proper error handling in build scripts
- Use debug mode for better debugging experience
- Keep transforms in package.json for consistency
Production Best Practices¶
- Minify bundles with uglifyify
- Remove debug code with envify
- Analyze bundle size regularly
- Use gzip compression on the server
- Implement proper caching headers
Summary¶
Browserify is a powerful tool that brings Node.js-style module system to the browser. Key features include:
- CommonJS Modules: Use require() and module.exports in the browser
- NPM Integration: Leverage the entire npm ecosystem
- Transform System: Preprocess files with Babel, TypeScript, CoffeeScript, etc.
- Plugin Architecture: Extend functionality with plugins
- Source Maps: Debug original source code in the browser
- Code Splitting: Create multiple bundles for better performance
- Development Tools: Watch mode, live reload, and debugging support
- Production Ready: Minification, optimization, and bundle analysis
By using Browserify, you can organize your frontend code with the same module patterns used in Node.js, making your codebase more maintainable and allowing you to share code between frontend and backend.