JavaScript 热重载在 1.3.0 中的应用

David Peicho

Wonderland Engine 1.3.0 的发布引入了一种在编辑器中打包 JavaScript/TypeScript 应用的新方法。

新的设置允许编辑器重新支持热重载功能,即无需重启引擎和 VR 会话就能在浏览器中重新加载您的 JavaScript。

1.3.0 之前 

此前,编辑器从一个单一入口点(index.js)生成一个 JavaScript 包:

js/index.js

import {loadRuntime} from '@wonderlandengine/api';

/* wle:auto-imports:start */
import {MyComponent} from './js/my-component.js';
/* wle:auto-imports:end */

const engine = await loadRuntime(...);

/* wle:auto-register:start */
engine.registerComponent(MyComponent);
/* wle:auto-register:end */

生成的包因此包含了导入的依赖引擎实例化代码,以及全局变量。

新架构 

新的架构将应用入口和组件注册分开:

  • js/index.js:包含组件注册
  • app.js:包含引擎创建、全局变量等…

js/index.js

// 组件入口点

/* wle:auto-imports:start */
import {MyComponent} from './js/my-component.js';
/* wle:auto-imports:end */

export default function(engine) {
  /* wle:auto-register:start */
  engine.registerComponent(MyComponent);
  /* wle:auto-register:end */
}

app.js

// 应用入口点

import {loadRuntime} from '@wonderlandengine/api';

const engine = await loadRuntime(...);
engine.loadMainScene('MyScene.bin');

此外,组件包将由 engine.loadMainScene() 调用自动下载并注册。

您可以手动导入组件并在应用中注册它们,但请先参考 Gotchas 部分以避免常见问题。

设置 

编辑器过去只在 JavaScript 设置中有一个入口:

如何选择 npm 脚本

现在分为了应用和组件入口:

如何选择 npm 脚本

output 设置用于指代部署文件夹中的包文件名。

当使用自定义 npm 命令时,此值必须设置为生成文件的文件名。

迁移 

打开 1.3 版本之前的项目时,迁移过程将禁用组件包,并保留在原始索引中的导入列表。

迁移包括以下几个步骤:

  • Project Settings 中启用组件打包
  • 将组件的导入/注册移至新索引文件

启用组件包 

Project Settings 中:

  • 如果未选中,勾选 Show Advanced Settings 复选框
  • 设置 bundling 选项。我们推荐使用 esbuild
  • entryPoint 设置为 js/component-index.js
  • output 设置为 MyWonderland-components.js
如何选择 npm 脚本

打包将自动生成 js/component-index.js

/* wle:auto-imports:start */
/* wle:auto-imports:end */

export default function(engine) {
/* wle:auto-register:start */
/* wle:auto-register:end */
}

移动组件 

如果您的项目在旧的 js/index.js 文件中手动导入/注册了组件,这些需要移至 js/component-index.js 入口点:

js/index.js

import {loadRuntime} from '@wonderlandengine/api';

/* wle:auto-imports:start */
/* wle:auto-imports:end */

// 这一行必须移至组件包
import {ManualComponent} from './js/manual-component.js';

const engine = await loadRuntime(...);

/* wle:auto-register:start */
/* wle:auto-register:end */

// 这一行必须移至组件包
engine.registerComponent(ManualComponent);

js/component-index.js

/* wle:auto-imports:start */
/* wle:auto-imports:end */

import {ManualComponent} from './manual-component.js';

export default function(engine) {
    /* wle:auto-register:start */
    /* wle:auto-register:end */
    engine.registerComponent(ManualComponent);
}

恭喜,您现在已使用新架构!

注意事项(Gotchas) 

具有全局变量的应用程序可能会遇到以下情况:

js/manager.js

export class Manager {
    static isReady = false;
}

app.js

import {loadRuntime} from '@wonderlandengine/api';
import {Manager} from './js/manager.js';

const engine = await loadRuntime(...);
Manager.isReady = true;
engine.loadMainScene('MyScene.bin');

js/my-component.js

import {Manager} from './manager.js';

export class MyComponent extends Component {
    start() {
        console.log(Manager.isReady); // `false`
    }
}

在此示例中,Manager 类将在每个文件中声明一次。

关于如何架构应用程序的决策将因用例而异。以下是一些潜在的迁移步骤:

  • 管理器可以完全移至组件包一侧
  • 全局变量可以延迟初始化
  • 可以使用 window 共享数据(不太推荐)
  • 对于高级用户:可以使用单独的 js 包并在 html 中导入
Last Update: February 5, 2025

保持更新。