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-properties
should 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-properties
as a plugin. Plugins are run before presets which leads to the error you’re seeing.Switching to the
@babel/plugin-transform-typescript
which is also included in@babel/preset-typescript
means it is run first, removing thedeclare
keyword (and probably stripping the class field) allowing@babel/plugin-proposal-class-properties
to work correctly.if webpacker is using
@babel/preset-typescript
then it’s likely that@babel/plugin-transform-typescript
is 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-properties
plugin is not required if you’re using Babel 7.14 or greater and@babel/preset-env
I 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: