Upgrade from Monster 4 to 5
Monster 5 makes the CustomElement option lifecycle explicit. Code that reads or writes options while those options are still being defined now fails immediately instead of silently using a fallback or losing a write.
Who needs to migrate?
Migrate subclasses that call getOption(), setOption() or setOptions() while evaluating defaults or customization, including calls hidden in helpers. Applications that only configure existing components after construction are not affected by this breaking change.
The breaking contract
- The option API is unavailable while
defaultsandcustomizationare evaluated. - Early access throws the exported
OptionsNotInitializedError. Itsmethodandcomponentproperties identify the operation and class. - Monster 5 has no compatibility flag, injected legacy strategy, early-read fallback or queue for early writes.
- Normal fallbacks still work after initialization. Valid values such as
false,0, an empty string andnullremain valid.
Choose the phase that owns the data
| Phase | Available configuration | Use it for |
|---|---|---|
defaults / customization | Static declarations only; the option API is unavailable. | Default values, templates, mappings and callbacks that run later. |
initMethodSymbol | Initialized defaults, customization and attributes already present during construction. | One-time non-DOM state derived from constructor-time options. |
assembleMethodSymbol, after super | Connection-time attributes, data-monster-options, selected script configuration and rendered DOM. | DOM work and values that may arrive after construction. |
| Runtime | The complete option tree. | Reactive changes through setOption() and setOptions(). |
One constructor caveat
initMethodSymbol runs from the base constructor. Derived class fields have not been initialized yet. Do not make the hook depend on those fields.
Replace circular defaults
This Monster 4 pattern asks the option tree for a value while that same tree is being built. It always depended on fallback behavior and throws in Monster 5.
// Before: unsupported in Monster 5
get defaults() {
return {
...super.defaults,
title: this.getOption("labels.title", "Details"),
};
}Declare the state directly and let updater-bound markup read it after assembly.
// After: declarative defaults
get defaults() {
return {
...super.defaults,
labels: {
title: "Details",
},
templates: {
main: "<h2 data-monster-replace='path:labels.title'></h2>",
},
};
}Move derived work to the right hook
Use initMethodSymbol only when constructor-time configuration is sufficient. Always keep the parent call.
import {
CustomElement,
initMethodSymbol,
} from "@schukai/monster/source/dom/customelement.mjs";
class ReportPanel extends CustomElement {
[initMethodSymbol]() {
super[initMethodSymbol]();
this.initialReportType = this.getOption("report.type", "summary");
return this;
}
}Use assembleMethodSymbol when values may come from late attributes or script configuration, or when the work needs rendered DOM. Call super first.
import {
CustomElement,
assembleMethodSymbol,
} from "@schukai/monster/source/dom/customelement.mjs";
class ReportPanel extends CustomElement {
[assembleMethodSymbol]() {
super[assembleMethodSymbol]();
this.configureResource(this.getOption("resourceConfig"));
return this;
}
}Assembly does not rebuild an earlier template decision
The base template has rendered after the parent assembly call. Prefer static templates with updater bindings, or update the rendered component through its documented API. Do not cache IDs or context keys from constructor-time fallback values.
document.createElement() and late configuration
document.createElement() completes construction synchronously. The returned upgraded element can use the option API immediately, but attributes the caller adds later could not have influenced initMethodSymbol.
await customElements.whenDefined("report-panel");
const panel = document.createElement("report-panel");
// Safe: construction and option initialization have completed.
panel.setOption("report.type", "detailed");
// Also applied during connection, but it was not visible to initMethodSymbol.
panel.setAttribute("data-monster-option-report-scope", "quarter");
document.body.append(panel);On first connection, Monster reads option attributes again, merges data-monster-options and selected script configuration, then renders and binds updaters. Reconnection reuses the assembled state; it does not reload those configuration sources.
Migration checklist
- Search both getters and every helper they call for all three option methods.
- Replace option-derived defaults with literal, static or class-level declarations.
- Move constructor-only derived state to
initMethodSymbol. - Move DOM and connection-time configuration work to
assembleMethodSymbol. - Call the matching parent hook before relying on Monster state.
- Test parsed HTML,
document.createElement(), first connection and reconnection. - Remove compatibility guards that catch
OptionsNotInitializedError.