Dynamic module import with Stimulus JS

adrienpoly profile image Adrien Poly ・1 min read

Scoped behavior by default

Being built on top of the mutation observer, Stimulus Controllers are only loaded once a data-controller="my-controller" is visible within the DOM.

This is a great way to scope JS behavior to an element within a page.

With the typical Webpack loader, all the Controllers are bundled within the pack.

// src/application.js
import { Application } from "stimulus"
import { definitionsFromContext } from "stimulus/webpack-helpers"

const application = Application.start()
const context = require.context("./controllers", true, /\.js$/)

Importing large ES modules

When importing very large JS library you might want to only load them only on pages where the controller is used to avoid loading too much JS on other pages.

One nice feature of Webpack is the ability to dynamically load modules.

Using the lifecycle of Stimulus Controllers you can stick you dynamic import right into the initialize() or connect() function.

Here is and example to dynamically load moment

import { Controller } from "stimulus";

export default class extends Controller {

  connect() {
    import("moment").then(moment => {
      this.moment = moment.default;

  doSomething() {
    const formatedTime = this.moment().format("dddd, MMMM Do YYYY, h:mm:ss a");

and a working demo

Posted on May 11 by:

adrienpoly profile

Adrien Poly


Freelance Fullstack developer Rails React Javascript


markdown guide

Woah, what!?

How does this actually work? Is it generating a second pack and downloading it somehow? Are we talking about a second HTTP request?

Is the dynamically imported module cached? That is, if my controller mounts twice (or I have many objects with a given controller) does it move any additional data over the wire?

Big picture... doesn't this make the larger discussion around complicated code-splitting techniques discussed by React developers entirely moot?

As usual, thanks for the brilliant tip.


Yes it will make a second http call. Lots of magic to me on how this actually works...

Cache works in the same way as your main cache


I'm trying to get my head around why this isn't a bigger deal. Again, it would seem to make the masochistic steps React devs take to split code seem ridiculous and moot.

Surely it can't actually be this simple?


Actually you can do it anywhere with webpack, not only Stimulus.

Thanks for quick tip!


Yes I didn't emphasize on it. You are right, this is a Webpack feature (probably also supported by other bundlers as it is a JS feature developer.mozilla.org/en-US/docs/W...).

The nice thing with Stimulus is that it pairs very well with the lifecycle events.


Indeed, forgot that browser modules have native support for dynamic imports.