Skip to content

[break] refactor(scene): lib service interface — per-service access, drop browser globals#745

Open
bofeng-song wants to merge 10 commits into
cocos:mainfrom
bofeng-song:feat-lib-service-aggregate
Open

[break] refactor(scene): lib service interface — per-service access, drop browser globals#745
bofeng-song wants to merge 10 commits into
cocos:mainfrom
bofeng-song:feat-lib-service-aggregate

Conversation

@bofeng-song

@bofeng-song bofeng-song commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Consolidates the scene-service interface work (supersedes and replaces #743).

Goals

  • External IDEs and cli's own pages reach scene services through one interface.
  • Callers import only the services they use (Service.Node / import { Node } from '<cli>/lib/service/node').
  • Drop ad-hoc browser globals (window.cli, window.WebEnv); pass the server address (ip/port) through the boot interface.

Changes

Per-service lib entry modules (incremental access)

  • src/lib/service/<name>.ts (16 services): each registers its scene service via its @register(...) decorator on import and exports the ready, precisely-typed instance:
    import { Node } from '<cli>/lib/service/node';
    await Node.createByType(...);
  • src/lib/service/index.ts: exposes the aggregate Service proxy + Services / IPublicServiceManager types; src/lib/index.ts re-exports them.

Single typed entry on ServiceManager

  • service-manager.ts: add init(serverURL), getServices(): IServiceManager, getServiceEvents(): GlobalEventManager (returns ServiceEvents, where service events like editor:open are actually emitted). main.ts uses init.

Drop src/lib/cli.ts

  • Deleted (dead, only re-exported types). Types now come from lib/scene/scene.ts (Services, GlobalEventManager) and lib/service.

Drop browser globals; pass ip/port via boot

  • engine-bootstrap.ts: removes the globalThis.cli assignment; startup() calls serviceManager.init(serverURL).
  • scene-editor-boot.js / game-boot.js: boot({ ip, port, https }) composes the server URL (falls back to location.origin) and returns { services, events, serverURL } from serviceManager.getServices() / getServiceEvents().
  • engine-loader.js: takes serverURL (new composeServerURL) instead of window.WebEnv; editor-stub-preload.jsinitEditorStub(serverURL).
  • load-scene.js / preview-app.js: use the boot context instead of window.cli.*.
  • scene-editor.ejs / preview.ejs / game.ejs: call boot({ ip, port, https }); removed window.WebEnv.
  • scene.scripting.middleware.ts / game-preview.middleware.ts: inject ip / port / https into the templates.

Engine-required window.CC_EDITOR / window.CC_PREVIEW and globalThis.cce.Script are intentionally kept.

Test

  • npx tsc -b passes.
  • npm run build:static-web rebuilds the scene bundle (no globalThis.cli; getServices / getServiceEvents present).
  • Scene editor (/scene-editor/), resource preview (/preview) and game preview (/) load; editor:open fires; no window.cli / window.WebEnv in the served assets.

…cess

Each src/lib/service/<name>.ts registers its scene service (via its @register
decorator on import) and exports the ready, precisely-typed instance, so callers
import only the services they use:

    import { Node } from '<cli>/lib/service/node';
    await Node.createByType(...);

Exporting the specific instance (instead of the generic Service proxy) keeps the
type accurate to what's registered and makes each module's intent clear.

src/lib/service/index.ts still exposes the aggregate Service proxy and the
Services / IPublicServiceManager types; src/lib/index.ts re-exports them.
@bofeng-song bofeng-song force-pushed the feat-lib-service-aggregate branch from a3975b3 to 67e50a7 Compare July 13, 2026 08:19
…owser globals

Scene editor and preview pages reached the scene services through ad-hoc browser
globals (window.cli.Scene / window.cli.SceneEvents) and read the server address
from another global (window.WebEnv). That is not a real interface, leaks globals,
and cannot be shared with external IDEs that consume the src/lib layer.
src/lib/cli.ts only re-exported types and had no importers.

window.cli.SceneEvents was also wired to messageManager (an isolated emitter),
while service events such as editor:open are emitted on ServiceEvents
(a GlobalEventManager); listeners on the former never fired.

ServiceManager (single typed entry):
- Add init(serverURL), getServices(): IServiceManager and
  getServiceEvents(): GlobalEventManager. getServiceEvents() returns ServiceEvents,
  where service events are actually emitted (fixes the dead editor:open listener).

Public lib interface:
- Delete the unused src/lib/cli.ts.
- Re-export Services (IServiceManager), IPublicServiceManager and
  GlobalEventManager from src/lib/scene/scene.ts.

Drop browser globals, pass the address through the boot interface:
- engine-bootstrap.ts: remove the globalThis.cli assignment; startup() calls
  serviceManager.init(serverURL).
- scene-editor-boot.js / game-boot.js: boot({ ip, port, https }) composes the
  server URL (falls back to location.origin) and returns { services, events,
  serverURL } from serviceManager.getServices() / getServiceEvents().
- engine-loader.js: takes serverURL as an argument (new composeServerURL) instead
  of reading window.WebEnv; editor-stub-preload.js becomes initEditorStub(serverURL).
- load-scene.js / preview-app.js: consume the boot context instead of window.cli.
- scene-editor.ejs / preview.ejs / game.ejs: call boot({ ip, port, https });
  the scene editor page uses the returned context via window.SceneCtx. Removed
  window.WebEnv.
- scene.scripting.middleware.ts / game-preview.middleware.ts: inject ip / port /
  https into the templates instead of a combined serverURL.
- main.ts (native scene worker): use serviceManager.init(...); the server URL still
  arrives via the --serverURL fork argument.

The engine-required window.CC_EDITOR / window.CC_PREVIEW flags and
globalThis.cce.Script are intentionally kept.
@bofeng-song bofeng-song changed the title feat(lib): per-service entry modules for incremental scene service access refactor(scene): lib service interface — per-service access, drop browser globals Jul 13, 2026
…ce-aggregate

# Conflicts:
#	static/web/scene-editor-boot.js
#	static/web/scene-editor.ejs
…eCtx

The scene-editor page used inline <script> blocks + on* attributes that reached
services through a window.SceneCtx global. Extract all of it into an ES module
(static/web/scene-editor-page.js): boot the scene context, keep it in module
closure, destructure the specific services used, and bind the UI via
addEventListener instead of inline onclick/onchange. No window.SceneCtx and no
global handler functions remain.

Also make boot()'s context key consistent: return { services, events, serverURL }
(services = the Service proxy) so all consumers (scene-editor-page, load-scene,
preview-app) read ctx.services; and have load-scene use the specific Editor
service.
The HTTP server hardcoded `localhost` in its base URL and only accepted a port.
Add an optional host/ip so callers can bind and advertise a specific address:

- ServerService.start(port?, host?) stores the host; `get url` now returns
  `http[s]://<host>:<port>` using the actual bound port (host defaults to
  localhost). createServer binds to the host when given (omitted = all
  interfaces, preserving previous behavior); port-conflict retry is preserved.
- startServer(port?, host?) forwards the host.
- lib/server start({ ip?, port? }) forwards to the service and returns the real
  base URL. serverService.url stays the single source of truth (serviceManager
  keeps receiving it via init).
…blic)

- lib/index.ts re-exports the service aggregate once via `export * from './service'`
  instead of re-listing each name (removes duplication with lib/service/index.ts).
- Expose `IServiceManager` (the service map type); drop `IPublicServiceManager`,
  which is the MCP-facing type and doesn't belong in this lib interface.
- lib/scene/scene.ts keeps only `GlobalEventManager` (+ init/startupWorker); the
  service map type now lives solely in lib/service.
src/lib/cli.ts was removed, so drop its entry from the dts generator; refresh the
cocos-cli-types dts snapshot to match the current lib surface (per-service
service modules, IServiceManager, no IPublicServiceManager/cli).
…entry

- Move all service-interface types into src/lib/service/index.ts: Service
  (DecoratorService proxy), IServiceManager, and GlobalEventManager (returned by
  serviceManager.getServiceEvents()).
- Drop the service re-export from src/lib/index.ts so the barrel stays one
  namespace per module; callers use `<cli>/lib/service` (or the per-service
  entry modules `<cli>/lib/service/<name>`).
- lib/scene/scene.ts keeps only the scene lifecycle (init / startupWorker).
- generate-dts.ts: add a `service` entry so cocos-cli-types emits service.d.ts;
  refresh the dts snapshot.
@bofeng-song bofeng-song changed the title refactor(scene): lib service interface — per-service access, drop browser globals [break] refactor(scene): lib service interface — per-service access, drop browser globals Jul 13, 2026
@bofeng-song bofeng-song requested a review from knoxHuang July 14, 2026 02:49
@bofeng-song bofeng-song added the pending Not ready yet label Jul 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pending Not ready yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant