← Back to marionettejs/backbone.marionette

How to Deploy & Use marionettejs/backbone.marionette

MarionetteJS Deployment and Usage Guide

MarionetteJS (Backbone.Marionette) is a JavaScript framework that simplifies the development of Backbone.js applications. It provides a set of conventions and abstractions to build scalable and maintainable client-side applications.

1. Prerequisites

To use MarionetteJS, you need the following:

  • Node.js: A JavaScript runtime environment. It is recommended to use an LTS (Long Term Support) version. You can download it from nodejs.org.
  • npm (Node Package Manager) or Yarn: Used for installing project dependencies. npm is included with Node.js.
  • Backbone.js: MarionetteJS is built on top of Backbone.js.
  • Underscore.js (or Lodash): A utility belt library for JavaScript, a dependency of Backbone.js.
  • Backbone.Radio: A messaging system for Backbone applications, used by MarionetteJS.

2. Installation

MarionetteJS can be installed via npm or included directly in your project.

Via npm

This is the recommended method for modern web development workflows.

  1. Initialize your project (if you haven't already):
    npm init -y
    
  2. Install MarionetteJS and its dependencies:
    npm install backbone.marionette backbone underscore backbone.radio
    

Direct Inclusion (CDN or Download)

For simpler setups or when not using a module bundler, you can include the minified JavaScript file directly.

  1. Download the minified file: You can download lib/backbone.marionette.min.js from the official MarionetteJS GitHub repository or use a CDN.

  2. Include in your HTML: Ensure Backbone, Underscore, and Backbone.Radio are included before MarionetteJS.

    <script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.13.1/underscore-min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.4.0/backbone-min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.radio/2.0.0/backbone.radio.min.js"></script>
    <script src="path/to/backbone.marionette.min.js"></script>
    

    (Note: Replace CDN links with the latest versions or local paths as needed.)

3. Configuration

MarionetteJS itself does not typically require environment variables or external configuration files in the way a backend application might. Configuration primarily involves setting up its internal DOM API or renderer if you're using a custom one.

Custom DOM API or Renderer

MarionetteJS allows you to swap out its internal DOM manipulation library (defaulting to Backbone's jQuery dependency) and its renderer. This is useful for integrating with different frontend libraries or custom rendering solutions.

  • Setting a custom DOM API: You can set a custom DOM API globally using Marionette.setDomApi(). This is done by providing an object that conforms to Marionette's expected DOM interface.

    import { setDomApi } from 'backbone.marionette';
    
    // Example with a hypothetical custom DOM library
    const MyCustomDomApi = {
      // Implement methods like `hasEl`, `getEl`, `append`, `remove`, etc.
      // Refer to `src/config/dom.js` for the full interface.
      hasEl: (parent, child) => parent.contains(child),
      getEl: (selectorOrEl) => {
        if (typeof selectorOrEl === 'string') {
          return document.querySelector(selectorOrEl);
        }
        return selectorOrEl;
      },
      // ... other required methods
    };
    
    setDomApi(MyCustomDomApi);
    
  • Setting a custom Renderer: Similarly, you can set a custom renderer globally using Marionette.setRenderer().

    import { setRenderer } from 'backbone.marionette';
    
    // Example custom renderer
    const MyCustomRenderer = (template, data) => {
      // Your custom rendering logic, e.g., using a templating engine like Handlebars
      // return Handlebars.compile(template)(data);
      return `<div>${template} - ${data.message}</div>`;
    };
    
    setRenderer(MyCustomRenderer);
    

4. Build & Run

MarionetteJS is a client-side library. There isn't a "build" process for MarionetteJS itself that you typically run; rather, it's integrated into your application's build process.

Development Setup

To use MarionetteJS in a development environment, you'll typically:

  1. Write your application code: Create Backbone.Marionette Views, Regions, Applications, etc.
  2. Bundle your code: Use a module bundler like Webpack, Rollup, or Parcel to combine your application's JavaScript files, including MarionetteJS, into a single bundle.
  3. Serve your application: Use a local development server to serve your HTML, CSS, and bundled JavaScript.

Example using Webpack (conceptual steps):

  1. Install Webpack and a development server:
    npm install --save-dev webpack webpack-cli webpack-dev-server html-webpack-plugin
    
  2. Create a webpack.config.js:
    const path = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    
    module.exports = {
      mode: 'development',
      entry: './src/index.js', // Your main application entry point
      output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist'),
      },
      plugins: [
        new HtmlWebpackPlugin({
          template: './src/index.html' // Your main HTML file
        })
      ],
      devServer: {
        static: {
          directory: path.join(__dirname, 'dist'),
        },
        compress: true,
        port: 9000,
      },
    };
    
  3. Create src/index.html:
    <!DOCTYPE html>
    <html>
    <head>
        <title>Marionette App</title>
    </head>
    <body>
        <div id="app-root"></div>
        <!-- Webpack will inject bundle.js here -->
    </body>
    </html>
    
  4. Create src/index.js:
    import { Application, Region, View } from 'backbone.marionette';
    import Backbone from 'backbone';
    import _ from 'underscore';
    
    const App = new Application({
      region: '#app-root'
    });
    
    const MyView = View.extend({
      template: _.template('<h1>Hello, <%= name %>!</h1>'),
      initialize() {
        this.model = new Backbone.Model({ name: 'Marionette' });
      }
    });
    
    App.on('start', () => {
      App.showView(new MyView());
    });
    
    App.start();
    
  5. Add scripts to package.json:
    {
      "name": "my-marionette-app",
      "version": "1.0.0",
      "scripts": {
        "start": "webpack serve --open",
        "build": "webpack --mode production"
      },
      // ... other dependencies
    }
    
  6. Run the development server:
    npm start
    
    This will open your application in a browser, typically at http://localhost:9000.

Production Build

For a production build, you'll use your bundler to create optimized, minified assets.

  1. Run the build command:
    npm run build
    
    This will create optimized JavaScript and other assets in your dist folder (or whatever output directory you configured).

5. Deployment

MarionetteJS applications are client-side JavaScript applications. Deployment involves serving the static assets (HTML, CSS, JavaScript bundle) generated by your build process.

Suitable platforms for deploying MarionetteJS applications include:

  • Static Site Hosting:
    • Netlify: Connects directly to your Git repository, automatically builds and deploys on push.
    • Vercel: Similar to Netlify, offers seamless Git integration and global CDN.
    • GitHub Pages: Free hosting directly from a GitHub repository.
    • GitLab Pages: Similar to GitHub Pages for GitLab users.
    • AWS S3 + CloudFront: For highly scalable and performant static asset hosting.
    • Google Cloud Storage + CDN: Google's equivalent for static hosting.
    • Firebase Hosting: Offers fast and secure static hosting with a global CDN.

General Deployment Steps:

  1. Build your application for production:

    npm run build
    

    This will generate your deployable static files (e.g., in the dist directory).

  2. Upload the dist directory contents:

    • For Git-integrated platforms (Netlify, Vercel, GitHub Pages):
      • Push your code to your Git repository.
      • Configure the platform to build from your package.json scripts (e.g., npm run build) and deploy the output directory (e.g., dist).
    • For cloud storage (S3, GCS):
      • Use the respective cloud provider's CLI or web console to upload the contents of your dist folder to a bucket configured for static website hosting.
      • Optionally, configure a CDN (CloudFront, Google CDN) in front of your bucket for better performance.
    • For traditional web servers (Apache, Nginx):
      • Copy the contents of your dist folder to the web server's document root (e.g., /var/www/html).

6. Troubleshooting

  • MarionetteError: View is already shown in a Region or CollectionView: This error typically occurs when you try to call show() on a view that is already being displayed in a Region or CollectionView.

    • Solution: Ensure you are not attempting to show the same view instance multiple times without first destroying or replacing it. If you intend to update the view, you might need to re-render it or show a new instance. Check the Region.show() method's logic, which explicitly throws this error.
  • MarionetteError: Bindings must be an object.: This error comes from internal Marionette functions like bindEvents or bindRequests (see lib/backbone.marionette.min.js). It means you've passed a non-object value where an object of event/request bindings was expected.

    • Solution: Review your events, modelEvents, collectionEvents, triggers, or requests definitions in your Marionette views or entities. Ensure they are always defined as plain JavaScript objects.
  • View events (e.g., events, triggers) not firing:

    • Cause 1: The view might not be rendered or attached to the DOM.
      • Solution: Ensure your view is properly rendered and then shown in a Region or manually appended to the DOM. Check view.isRendered() and view.isAttached().
    • Cause 2: Incorrect selector in event definition.
      • Solution: Double-check your event selectors (e.g., "click .my-button"). Use your browser's developer tools to verify the element exists and matches the selector.
    • Cause 3: delegateEvents was not called or was called incorrectly.
      • Solution: In most cases, Marionette handles delegateEvents automatically. If you're overriding delegateEvents in your view, ensure you call Backbone.View.prototype.delegateEvents.call(this, combinedEvents); as shown in src/mixins/view.js.
    • Cause 4: Using @ui. selectors without defining ui.
      • Solution: If you use @ui.myElement in your events, ensure you have a ui hash defined in your view: ui: { myElement: '.my-element-selector' }.
  • Child views not rendering in CollectionView:

    • Cause 1: childView property is not defined or is incorrect.
      • Solution: Ensure your CollectionView has a childView property pointing to a valid Marionette View constructor.
    • Cause 2: The collection is empty or not set.
      • Solution: Verify that the CollectionView has a collection instance and that the collection contains models.
    • Cause 3: viewFilter is preventing children from being shown.
      • Solution: If you're using viewFilter, ensure its logic correctly returns true for models you want to display.
  • Marionette not found or undefined:

    • Cause: Dependencies (Backbone, Underscore, Backbone.Radio) are not loaded or are loaded in the wrong order, or MarionetteJS itself isn't loaded.
    • Solution: If using direct <script> tags, ensure underscore.js, backbone.js, backbone.radio.js are loaded before backbone.marionette.min.js. If using a module bundler, ensure all dependencies are correctly imported.