Aller au contenu

Browserify Cheatsheet

Parcourir - Requirement côté navigateur

Browserify vous permet de requérir ('modules') dans le navigateur en regroupant toutes vos dépendances. Il utilise le même système de module que Node.js, vous permettant d'utiliser des modules npm dans le navigateur et d'organiser votre code avec des modules CommonJS.

Copier toutes les commandes Générer PDF

Sommaire

  • [Installation] (#installation)
  • [Pour commencer] (#getting-started)
  • [Utilisation de base] (#basic-usage)
  • [Interface de ligne de commande] (#command-line-interface)
  • [API programmatique] (#programmatic-api)
  • [Transformations] (#transforms)
  • [Plugins] (#plugins)
  • [Cartes des sources] (#source-maps)
  • [dépendances extérieures] (#external-dependencies)
  • [Ensembles multiples] (#multiple-bundles)
  • [Travaux de développement] (#development-workflow)
  • [Construits de production] (#production-builds)
  • [Essais] (#testing)
  • [Caractéristiques avancées] (#advanced-features)
  • [Optimisation du rendement] (#performance-optimization)
  • [Débogage] (#debugging)
  • [Migration] (#migration)
  • [Meilleures pratiques] (#best-practices)

Installation

Installation mondiale

# Install Browserify globally
npm install -g browserify

# Verify installation
browserify --version

Installation locale (recommandée)

# Initialize npm project
npm init -y

# Install Browserify locally
npm install --save-dev browserify

# Install common transforms
npm install --save-dev babelify uglifyify envify
```_

### Configuration du projet
```bash
# 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
```_

### Paquet.json Scripts
```json
{
  "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"]
      }]
    ]
  }
}

Commencer

Structure de base du module

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

Point d'entrée principal

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

Intégration HTML

<!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>

Utilisation de base

Création simple d'un ensemble

# 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

Utilisation de 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

Mode veille

# 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

Interface de ligne de commande

Commandes de base

# 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

Options avancées

# 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

Transformer les 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

Options de plugin

# 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

API programmatique

API de base Utilisation

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

Configuration avancée de l'API

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

Traitement des flux

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

Transformes

Babel Transforme

# Install babelify
npm install --save-dev babelify @babel/core @babel/preset-env
// .babelrc
{
  "presets": ["@babel/preset-env"],
  "plugins": [
    "@babel/plugin-transform-arrow-functions",
    "@babel/plugin-transform-classes"
  ]
}
# Use with browserify
browserify src/js/main.js -t babelify -o dist/bundle.js

Transformer le script de café

# Install coffeeify
npm install --save-dev coffeeify coffee-script
# src/js/app.coffee
class Calculator
  constructor: ->
    @result = 0

  add: (num) ->
    @result += num
    @

  multiply: (num) ->
    @result *= num
    @

  getResult: ->
    @result

module.exports = Calculator
# Bundle CoffeeScript
browserify src/js/app.coffee -t coffeeify -o dist/bundle.js

TypeScript Transformer

# Install tsify
npm install --save-dev tsify typescript
// 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;
# Bundle TypeScript
browserify src/js/app.ts -p tsify -o dist/bundle.js

CSS Transformes

# Install css transforms
npm install --save-dev browserify-css stringify
// Using browserify-css
const css = require('./styles.css');
document.head.appendChild(css);
# Bundle with CSS
browserify src/js/main.js -t browserify-css -o dist/bundle.js

Variables d'environnement

# Install envify
npm install --save-dev envify
// 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

Greffons

Plugin de groupe de facteurs

# Install factor-bundle
npm install --save-dev factor-bundle
// 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'));

Effacement du groupe

# Install bundle-collapser
npm install --save-dev 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'));
# Install browserify-shim
npm install --save-dev browserify-shim
// package.json
{
  "browserify": {
    "transform": ["browserify-shim"]
  },
  "browserify-shim": {
    "jquery": "global:jQuery",
    "bootstrap": {
      "depends": ["jquery"],
      "exports": "bootstrap"
    }
  }
}

Plugin de disque (analyse de bulle)

# Install disc
npm install --save-dev disc
// 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);

Cartes sources

Autoriser les cartes des sources

# 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

Cartes des sources programmatiques

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

Options de carte des sources

const b = browserify({
  entries: ['src/js/main.js'],
  debug: true,

  // Source map options
  sourceMaps: true,
  sourceMapPrefix: '/src',
  sourceRoot: '/src'
});

Cartes des sources en ligne

// Inline source maps for development
const b = browserify({
  entries: ['src/js/main.js'],
  debug: true
});

// Transform with source maps
b.transform('babelify', {
  sourceMaps: 'inline'
});

Dépendances extérieures

Création du fournisseur Ensemble

# 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

Dépendances externes programmatiques

// 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'));

Intégration HTML

<!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>

Externes dynamiques

// 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'));

Ensembles multiples

Configuration du bloc de facteurs

// 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 spécifique Ensembles

// 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;

Construire un script pour plusieurs ensembles

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

Développement Flux de travail

Serveur de développement

# Install budo (development server)
npm install --save-dev budo
// 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"
  }
}

Configuration de la recharge en direct

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

Remplacement du module à chaud

# Install browserify-hmr
npm install --save-dev browserify-hmr
// 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();
  });
}

Développement construire 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();

Constructions de production

Minification

# Install uglifyify
npm install --save-dev uglifyify
# Production build with minification
NODE_ENV=production browserify src/js/main.js -t babelify -g uglifyify -o dist/bundle.min.js

Scénario de construction de production

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

Analyse de l'ensemble

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

Analyse Gzip

// 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) + '%');
    });
  });

Essais

Essai d'unité avec bande

# Install tape
npm install --save-dev tape tap-spec
// 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();
});
// package.json
{
  "scripts": {
    "test": "tape test/*.js | tap-spec"
  }
}

Essai du navigateur

# Install testling
npm install --save-dev testling
// package.json
{
  "testling": {
    "files": "test/*.js",
    "browsers": [
      "ie/9..latest",
      "chrome/latest",
      "firefox/latest",
      "safari/latest"
    ]
  }
}

Intégration du Karma

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

Mèche et stabulation

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

Caractéristiques avancées

Transformations personnalisées

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

Développement de plugins

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

Bundling conditionnel

// 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'
));

Importations dynamiques

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

Optimisation des performances

Séparation des ensembles

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

Chargement paresseux

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

fractionnement du code avec le bloc de facteurs

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

Optimisation de la taille des ensembles

// 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'));

Déboguement

Mode de débogage

# 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

Déboguement de la carte source

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

Analyse de l'ensemble

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

Gestion des erreurs

// 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'));

Profilage

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

Migrations

À partir de 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'));

À partir de 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');

Liste de contrôle des migrations

  • Convertir les modules AMD/RequireJS en CommonJS
  • Installer des équivalents npm des bibliothèques fournisseurs
  • Mettre à jour les scripts de construction pour utiliser Browserify
  • Configurer les transformations pour le prétraitement
  • Configurer le workflow de développement avec watchify
  • Mettre à jour HTML pour utiliser les scripts groupés
  • Tester toutes les fonctionnalités après la migration

Meilleures pratiques

Organisation du module

// 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;

Gestion de la dépendance

// 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"
  }
}

Configuration de construction

// 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;

Meilleures pratiques en matière de rendement

  • Utilisez des paquets externes pour les grandes bibliothèques
  • Doublure du code d'exécution pour les grandes applications
  • Mappes sources utilisables uniquement en développement
  • Utilisez les transformations judicieusement - ils ajoutent du temps de construction
  • Profilez vos builds pour identifier les goulets d'étranglement

Meilleures pratiques de développement

  • Utilisez watchify pour les reconstructions rapides pendant le développement
  • Set up live reload avec budo ou outils similaires
  • Mettre en œuvre la bonne gestion des erreurs dans les scripts de construction
  • Utilisez le mode de débogage pour une meilleure expérience de débogage
  • Conserver les transformations dans package.json pour assurer la cohérence

Meilleures pratiques de production

  • ** Minimiser les paquets** avec uglify
  • Supprimer le code de débogage avec envie
  • Analyze taille du faisceau régulièrement
  • ** Utiliser la compression gzip** sur le serveur
  • Mise en œuvre des en-têtes appropriés

Résumé

Browserify est un outil puissant qui apporte Node.js-style module système au navigateur. Les principales caractéristiques sont les suivantes :

  • CommonJS Modules: Utiliser require() et module. exportations dans le navigateur
  • ** Intégration NPM**: Tirer parti de tout l'écosystème npm
  • Transform System: fichiers préprocédés avec Babel, TypeScript, CoffeeScript, etc.
  • Architecture des puces: Extension des fonctionnalités avec les plugins
  • Cartes d'origine : Déboguer le code source original dans le navigateur
  • Doublure du code: Créer plusieurs faisceaux pour une meilleure performance
  • ** Outils de développement** : Mode de veille, recharge en direct et support de débogage
  • Prêt à la production: minification, optimisation et analyse du faisceau

En utilisant Browserify, vous pouvez organiser votre code frontend avec les mêmes modèles de module utilisés dans Node.js, ce qui rend votre base de code plus durable et vous permet de partager le code entre frontend et backend.