How to enable JavaScript Hot-Reload on pre-1.3.0 Wonderland Engine projects.

JavaScript Hot-Reload in 1.3.0

The Wonderland Engine 1.3.0 release introduces a new way to bundle JavaScript/TypeScript application in the editor.

The new setup allows the editor to bring back Hot Reload support, i.e. reloading your JavaScript in the browser without restarting the engine and VR sessions.

Pre-1.3.0 

Previously, the editor produced a single JavaScript bundle, from a single entry point (index.js):

js/index.js

 1import {loadRuntime} from '@wonderlandengine/api';
 2
 3/* wle:auto-imports:start */
 4import {MyComponent} from './js/my-component.js';
 5/* wle:auto-imports:end */
 6
 7const engine = await loadRuntime(...);
 8
 9/* wle:auto-register:start */
10engine.registerComponent(MyComponent);
11/* wle:auto-register:end */

The generated bundle thus contained imported dependencies, the engine instantiation code, as well as globals.

New Architecture 

The new architecture splits the application entry from the components registration one:

  • js/index.js: Contains components registration
  • app.js: Contains the engine creation, globals, etc…

js/index.js

 1// Components entry point
 2
 3/* wle:auto-imports:start */
 4import {MyComponent} from './js/my-component.js';
 5/* wle:auto-imports:end */
 6
 7export default function(engine) {
 8  /* wle:auto-register:start */
 9  engine.registerComponent(MyComponent);
10  /* wle:auto-register:end */
11}

app.js

1// Application entry point
2
3import {loadRuntime} from '@wonderlandengine/api';
4
5const engine = await loadRuntime(...);
6engine.loadMainScene('MyScene.bin');

In addition, the components bundle will be automatically downloaded and registered by the engine.loadMainScene() call.

You are free to manually import components and register them in the application, but refer to the Gotchas section first to avoid running into common pitfalls.

Settings 

The editor used to have a single entry for JavaScript settings:

It’s now duplicated for the application and components entry:

JavaScript Hot-Reload in 1.3.0

The output setting is used to refer to the bundle filename in the deploy folder.

When using a custom npm command, this value must be set to the generated file’s filename.

Migration 

When opening a pre-1.3 project, the migration process will disable the components bundle, and leave the imports list in the original index.

Migrating consists in following a few steps:

  • Enable components bundling in the Project Settings
  • Move components import/registration to a new index file

Enable Components Bundle 

In the Project Settings:

  • Tick the Show Advanced Settings checkbox if unticked
  • Set the bundling option. We recommend using esbuild
  • Set the entryPoint to js/component-index.js
  • Set the output to MyWonderland-components.js
JavaScript Hot-Reload in 1.3.0

Packaging will generate the js/component-index.js automatically:

1/* wle:auto-imports:start */
2/* wle:auto-imports:end */
3
4export default function(engine) {
5/* wle:auto-register:start */
6/* wle:auto-register:end */
7}

Move Components 

If your project had manually imported/registered components in the old js/index.js file, those will need to be moved over to the js/component-index.js entry point:

js/index.js

 1import {loadRuntime} from '@wonderlandengine/api';
 2
 3/* wle:auto-imports:start */
 4/* wle:auto-imports:end */
 5
 6// This line must be caried over to the components bundle
 7import {ManualComponent} from './js/manual-component.js';
 8
 9const engine = await loadRuntime(...);
10
11/* wle:auto-register:start */
12/* wle:auto-register:end */
13
14// This line must be caried over to the components bundle
15engine.registerComponent(ManualComponent);

js/component-index.js

 1/* wle:auto-imports:start */
 2/* wle:auto-imports:end */
 3
 4import {ManualComponent} from './manual-component.js';
 5
 6export default function(engine) {
 7    /* wle:auto-register:start */
 8    /* wle:auto-register:end */
 9    engine.registerComponent(ManualComponent);
10}

Congratulations, you are now using the new architecture!

Gotchas 

Applications that have globals can end up in the following case:

js/manager.js

1export class Manager {
2    static isReady = false;
3}

app.js

1import {loadRuntime} from '@wonderlandengine/api';
2import {Manager} from './js/manager.js';
3
4const engine = await loadRuntime(...);
5Manager.isReady = true;
6engine.loadMainScene('MyScene.bin');

js/my-component.js

1import {Manager} from './manager.js';
2
3export class MyComponent extends Component {
4    start() {
5        console.log(Manager.isReady); // `false`
6    }
7}

In this example, the Manager class would be declared once in each file.

The decision about how to architecture the application will be different for each use case. Here is a list of potential migration step(s):

  • Managers could be moved entirely to the components bundle side
  • Globals could be lazy initialized
  • Data could be shared using window (less recommended)
  • For advanced users: Make use of a separate js bundle imported in the html
Last Update: February 5, 2025

Stay up to date.