ESM Hot Module Reloading
Support Hot reloading for ESM Scripts
Existing scripts support "Hot Reloading" by manually calling a 'swap()` on a ScriptType as it updates. ESM scripts however are modular and can contain complex dependancies...
./config.mjs
export const speed = 10.0;
./utils.mjs
import { speed } from './config.mjs';
export const addSpeed = n => n * 2;
./MyRotator.mjs
import { addSpeed } from './utils.mjs'
class MyRotator extends ScriptType {
update(){
this.prop = addSpeed(this.prop)
}
}
This works when MyRotator.mjs changes, but when config.mjs changes, the user needs to manually refresh the page to see the update. In an ideal world when config.mjs changes only it's dependants update.
This is non-trivial, as it requires maintaining a dependancy graph so that for each module update, we can walk the tree and find the relevant ScriptTypes that need to be reloaded.
ESM HMR requirements
- Support module dependancies - Allow updates in sub-dependancies to update only their dependants
- Should not require use input - It should work out the box
- Compatible with existing ScriptType
swap- Should not require any change to the api or semantics of theScriptType.swapand should work along side
Considerations
ScriptType.swapis currently opt-in, meaning that if not defined, hot reloading won't work. Whilst it may be beneficial to turn on/off, this can become complex for the userScriptType.swapis a class level hot reloading, modules can export multiple ScriptTypes, so this may need additional thought
I believe that ScriptType.swap - is very straight forward and simple feature, that is not related to actually hot-reloading every possible script.
Current logic is pretty specific: if the script has swap method, then when it is updated, attempt to reload it.
To clarify, this is "ScriptType Hot-Reload". The actual "ESM Hot-Reload" - is a different story.
For ScriptType hot-reload logic very straight forward:
- The script asset file has been updated (load event).
- Check if that script asset has script definitions.
- For every already loaded script that have a
swapmethod, update script registry with a new instance of a ScriptType class if it is defined in exports of a new file.
If I'm not wrong, it should already work based on the current code, as it calls registerScript for each ScriptType from a module, and it will trigger swap on its own based on the logic described above.
Yep swap works as is. This is just for HMR with sub dependancies etc. For end users, I worry it might be confusing if they have different behaviours.
Given a ScriptType with no swap method
- If the ScriptType is modified directly - No update ❌
- If one of its' dependancy is modified - Update occurs ✅
That seems like it might be confusing. I was initially thinking that the swap method could control both, so at least it's consistent, but that doesn't really work as ones a class and the other a module
The full and real hot-swap would be amazing of course. But might be challenging.
Current hot-swap is meant for development and really is a viable solution for small/medium complexity scripts. I think state management for big complex scripts would be challenging.
Yes exactly. There's lots to work out. However the developer experience when it does work is so good, I believe it's worth the effort.
Hi @marklundin, any status on swap support in Editor for ESM?
We've tried to use ESM scripts with engine v1 in Editor on small new (clean) projects, and we rely on swap a lot, especially as the project grows and refreshes become longer and more complex due to the complex states of an app. So we do need a swap a lot to ensure we can efficiently work.
Hi @marklundin, any status on
swapsupport in Editor for ESM? We've tried to use ESM scripts with engine v1 in Editor on small new (clean) projects, and we rely on swap a lot, especially as the project grows and refreshes become longer and more complex due to the complex states of an app. So we do need aswapa lot to ensure we can efficiently work.
The existing hot-swap for ESM Scripts without dependencies should work, however I've just tested and found a caching issue. Will submit a fix
Hi @marklundin, is there an ETA for hot-reloading support for ESM scripts?