stimulus: Webpacker 5.1 breaks recommended TypeScript controller pattern
See: https://github.com/rails/webpacker/issues/2558
Webpacker 5.1 changed the loader for TypeScript, which changed code compilation behavior, which breaks class properties.
So the controller declaration:
I have a simple Stimulus controller, defined to start as follows:
import { Controller } from "stimulus"
export default class extends Controller {
static classes = ["hidden"]
static targets = ["filterInput", "concert"]
hiddenClass: string
concertTargets: HTMLElement[]
filterInputTarget: HTMLInputElement
// and so on
Now breaks with a TypeError: Cannot set property hiddenClass of #<extended> which has only a getter.
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Reactions: 1
- Comments: 15 (4 by maintainers)
To fix this I removed
['@babel/preset-typescript', { 'allExtensions': true, 'isTSX': true }]from babel.config.js and added["@babel/plugin-transform-typescript", { 'allExtensions': true, 'isTSX': true, 'allowDeclareFields': true }],to the top of my plugins entry (anywhere above@babel/plugin-proposal-class-propertiesshould work).This will also allow the use of declare
declare containerTarget: HTMLDialogElement;which will future proof your controllers should TS ever align more closely with the ECMA spec.Ran into this issue after upgrading to Stimulus 2.0, running a Rails app with Webpacker 5.2.1. It complains when you use targets in a Stimulus controller built in TypeScript. @fleck’s suggestion fixed it.
In babel.config.js:
In the TypeScript controller:
@noelrappin @fleck
I think I’ve nailed down the error you were getting here:
and why the plugin solution works:
It’s likely webpacker is adding
@babel/plugin-proposal-class-propertiesas a plugin. Plugins are run before presets which leads to the error you’re seeing.Switching to the
@babel/plugin-transform-typescriptwhich is also included in@babel/preset-typescriptmeans it is run first, removing thedeclarekeyword (and probably stripping the class field) allowing@babel/plugin-proposal-class-propertiesto work correctly.if webpacker is using
@babel/preset-typescriptthen it’s likely that@babel/plugin-transform-typescriptis being called twice which is potentially slowing down the build.Babel 7.14 enables class fields & private methods by default in @babel/preset-env so adding the
@babel/plugin-proposal-class-propertiesplugin is not required if you’re using Babel 7.14 or greater and@babel/preset-envI mean, if it works, I guess I’ll switch to it, but I’m not looking forward to explaining it in the book.
The Babel team seems unlikely to change this behavior, so unless TypeScript changes for some reason, I think we’re stuck with trying to make this work better on the Stimulus side.
@javan It seems like it would be. Unfortunately, it seems like that feature doesn’t change the runtime behaviour and still causes the error mentioned.
It seems to me like declare fields might be the right approach. I.e.
However, I don’t seem to be able to get the allowDeclareFields @babel/preset-typescript option to work. I get the following error in the browser console: