Skip to content

[APPS] Inject transport at build time instead of forking at runtime#323

Draft
sdkennedy2 wants to merge 1 commit intomasterfrom
sdkennedy2/apps-runtime-split-transports
Draft

[APPS] Inject transport at build time instead of forking at runtime#323
sdkennedy2 wants to merge 1 commit intomasterfrom
sdkennedy2/apps-runtime-split-transports

Conversation

@sdkennedy2
Copy link
Copy Markdown
Collaborator

@sdkennedy2 sdkennedy2 commented Apr 18, 2026

Motivation

The injected browser runtime (apps-runtime.mjs) currently forks between two transports at runtime in executeBackendFunction:

  • devServerTransportPOST /__dd/executeAction against the Vite dev server middleware
  • postMessageTransport — iframe bridge to the parent Datadog app

Whether we're in a dev-server context or an iframe sandbox is actually known at build time (vite vs vite build), so shipping both transports to every bundle is dead weight — production apps always run in an iframe and will never hit /__dd/executeAction.

This PR makes the decision at build time: each bundle now ships only the transport it needs.

Changes

Split the single src/built/apps-runtime.ts into two single-transport entries and emit both from the plugin's toBuild pipeline:

  • src/built/apps-runtime-dev.tsapps-runtime-dev.mjs (fetch to /__dd/executeAction)
  • src/built/apps-runtime-prod.tsapps-runtime-prod.mjs (window.parent.postMessage)

Each runtime is a trivial side-effect module that assigns globalThis.DD_APPS_RUNTIME.executeBackendFunction directly from its one transport — the executeBackendFunction dispatcher (src/backend/client/execute-backend-function.ts) and its runtime isInIframe() fork are removed.

The top-level context.inject(...) in getPlugins() is moved into a new Vite config(_, { command }) hook on the apps plugin's Vite sub-plugin. The injection plugin queues inject() items to a Map that's only consumed inside plugin.buildStart (see packages/plugins/injection/src/index.ts), so deferring to Vite's config() hook still lands in time. InjectPosition.MIDDLE is preserved — same reasoning as before: Vite's dev server only injects MIDDLE content via transformIndexHtml.

// src/vite/index.ts
config(_userConfig, { command }) {
    const runtime = command === 'serve' ? 'apps-runtime-dev.mjs' : 'apps-runtime-prod.mjs';
    inject({
        type: 'file',
        position: InjectPosition.MIDDLE,
        value: path.join(pluginDir, runtime),
    });
},

The apps plugin is Vite-only in practice (build/upload and dev-server middleware both live under src/vite/), so non-Vite bundlers simply stop getting an injection. No fallback is added — without Vite's closeBundle/configureServer the runtime global would dangle with nothing to call.

The existing execute-backend-function.test.ts was ported to src/backend/client/transports/dev-server-transport.test.ts (same 6 cases, now targeting the transport directly). src/index.test.ts now runs a test.each over both serve and build commands to assert the correct runtime file is injected for each.

QA Instructions

Stacked on #320.

Local dev:

  1. cd ~/dd/build-plugins && ~/.yarn/switch/bin/yarn dev (runs prepare-link + auto-rebuild watcher).
  2. In a scaffolded high-code app:
    • Dev: NODE_TLS_REJECT_UNAUTHORIZED=0 dd-auth --domain="dd.datad0g.com" --actions-api -- npx vite. Fetch /@id/__datadog-helper-file and confirm the response contains fetch("/__dd/executeAction"...) and has no postMessage / app-builder:run-query references.
    • Prod: NODE_TLS_REJECT_UNAUTHORIZED=0 dd-auth --domain="dd.datad0g.com" --actions-api -- npx vite build. Grep the built dist/assets/index-*.jspostMessage should appear, /__dd/executeAction should not.
  3. Confirm window.DD_APPS_RUNTIME.executeBackendFunction resolves in both modes and backend function calls succeed.

Verified locally against test-action-catalog-app:

  • Dev /@id/__datadog-helper-file contained only fetch-based transport.
  • Prod dist/assets/index-Bo1i35ss.js contained postMessage (1) and app-builder:run-query (1) with 0 occurrences of /__dd/executeAction.

Unit:

  • yarn test:unit packages/plugins/apps — 13 suites / 137 tests pass.

Blast Radius

  • Scope: @dd/apps-plugin and the published @datadog/vite-plugin.
  • No breaking change for consumers — globalThis.DD_APPS_RUNTIME.executeBackendFunction contract is unchanged.
  • Non-Vite bundlers stop receiving the runtime injection, but the apps plugin was Vite-only in practice and had no working upload/dev-server pipeline for other bundlers anyway.
  • Published vite-plugin now ships two apps-runtime-{dev,prod}.mjs files in place of apps-runtime.mjs. Consumers never referenced the file path directly; the build tooling emits it.

Documentation

Copy link
Copy Markdown
Collaborator Author

sdkennedy2 commented Apr 18, 2026

@sdkennedy2 sdkennedy2 changed the title Split apps runtime into dev and prod and inject based on Vite command [APPS] Inject transport at build time instead of forking at runtime Apr 18, 2026
@sdkennedy2
Copy link
Copy Markdown
Collaborator Author

@codex review
@cursor review

@datadog-prod-us1-6
Copy link
Copy Markdown

datadog-prod-us1-6 Bot commented Apr 18, 2026

Tests

🎉 All green!

❄️ No new flaky tests detected
🧪 All tests passed

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 8a8ebf4 | Docs | Datadog PR Page | Give us feedback!

@sdkennedy2 sdkennedy2 force-pushed the sdkennedy2/apps-runtime-split-transports branch from 80f3364 to 22efe5c Compare April 18, 2026 18:46
@chatgpt-codex-connector
Copy link
Copy Markdown

Summary

  • Reviewed the PR context and made a follow-up cleanup commit to keep docs aligned with the runtime split: updated the proxy-codegen comment to reference apps-runtime-{dev,prod}.ts (instead of the removed single apps-runtime.ts).
  • Committed on the current branch: 7223f48.
  • Created a follow-up PR via make_pr with title: [APPS] Fix proxy-codegen runtime reference for split dev/prod runtimes.

Testing

  • yarn test:unit packages/plugins/apps/src/backend/proxy-codegen.test.ts
  • ⚠️ yarn test:unit packages/plugins/apps (suite passes, but environment emits intermittent Corepack/Yarn network setup warnings due proxy/tunneling restrictions)

View task →

@sdkennedy2 sdkennedy2 force-pushed the sdkennedy2/apps-runtime-split-transports branch from 22efe5c to e072fb6 Compare April 20, 2026 11:54
@sdkennedy2 sdkennedy2 force-pushed the sdkennedy2/replace-esbuild-acorn-with-transform-hook branch from ed163fe to 203664f Compare April 20, 2026 11:54
@sdkennedy2 sdkennedy2 changed the base branch from sdkennedy2/replace-esbuild-acorn-with-transform-hook to graphite-base/323 April 21, 2026 17:17
@sdkennedy2 sdkennedy2 force-pushed the sdkennedy2/apps-runtime-split-transports branch from e072fb6 to 8a8ebf4 Compare April 22, 2026 18:40
@sdkennedy2 sdkennedy2 changed the base branch from graphite-base/323 to master April 22, 2026 18:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant