How to circumvent importing Stimulus within every controller
posted by Ayush Newatia
2 July, 2021
If you’re familiar with Stimulus at all, the below bog standard controller should look very familiar. In fact I’ve nicked it from their homepage!
import { Controller } from "stimulus"
export default class extends Controller {
static targets = ["name", "output"]
greet() {
this.outputTarget.textContent =
`Hello, ${this.nameTarget.value}!`
}
}
I’m a Rubyist and unashamedly rather lazy; so having that import
statement at the top of every Stimulus controller always irked me. If you’re using Webpack, there’s a super simple way of circumventing this annoying import
statement.
First thing you need to do is create a file called application_controller.js
and place it in your controllers
directory. This is good practice nevertheless as you can put app specific utilities in there; such as getting some data out of meta
tags for example.
// application_controller.js
import { Controller } from 'stimulus'
export default class extends Controller {
}
And then change your controllers to inherit from ApplicationController
and remove the import
statement. So the above controller would become:
export default class extends ApplicationController {
static targets = ["name", "output"]
greet() {
this.outputTarget.textContent =
`Hello, ${this.nameTarget.value}!`
}
}
And finally we need to make a change to our Webpack configuration so the controllers know where to find ApplicationController
without the import
statement. We’ll use the Webpack Provide plugin to accomplish this.
Add the following lines to the plugins
array in your webpack.config.js
:
new webpack.ProvidePlugin({
ApplicationController: ['./application_controller', 'default']
})
If you’re using Webpacker 5 or older, add the following lines to your config/webpack/environment.js
:
const webpack = require('webpack')
environment.plugins.append('Provide', new webpack.ProvidePlugin({
ApplicationController: ['./application_controller', 'default']
}))
And if you’re using Webpacker 6, change your config/webpack/base.js
to:
const { webpackConfig, merge } = require('@rails/webpacker')
const webpack = require('webpack')
const customConfig = {
plugins: [
new webpack.ProvidePlugin({
ApplicationController: ['./application_controller', 'default']
})
]
}
module.exports = merge(webpackConfig, customConfig)
And that should do the trick! You no longer need to import Controller
manually within every Stimulus controller!
Shout out to Konnor Rogers for showing me how to do this :)