From ad770f47b6c308103b06448f05410df2e12a7457 Mon Sep 17 00:00:00 2001 From: Scott Kennedy Date: Mon, 11 May 2026 11:45:06 -0400 Subject: [PATCH 1/3] Move apps Vite behavior into getVitePlugin --- packages/plugins/apps/src/index.test.ts | 2 +- packages/plugins/apps/src/index.ts | 282 +-------------- packages/plugins/apps/src/vite/index.test.ts | 75 +++- packages/plugins/apps/src/vite/index.ts | 340 +++++++++++++++++-- 4 files changed, 370 insertions(+), 329 deletions(-) diff --git a/packages/plugins/apps/src/index.test.ts b/packages/plugins/apps/src/index.test.ts index 4d126a46d..ee6230426 100644 --- a/packages/plugins/apps/src/index.test.ts +++ b/packages/plugins/apps/src/index.test.ts @@ -248,7 +248,7 @@ describe('Apps Plugin - getPlugins', () => { const args = getArgs(); args.bundler = { build: viteBuild }; const plugins = getPlugins(args); - const transform = plugins[0].transform as { + const transform = plugins[0].vite?.transform as { handler: (code: string, id: string) => unknown; }; transform.handler.call( diff --git a/packages/plugins/apps/src/index.ts b/packages/plugins/apps/src/index.ts index f23758b2c..86bdec673 100644 --- a/packages/plugins/apps/src/index.ts +++ b/packages/plugins/apps/src/index.ts @@ -2,116 +2,15 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2019-Present Datadog, Inc. -import { rm } from '@dd/core/helpers/fs'; import type { GetPlugins } from '@dd/core/types'; -import { InjectPosition } from '@dd/core/types'; -import chalk from 'chalk'; -import fsp from 'fs/promises'; -import os from 'os'; -import path from 'path'; -import { createArchive } from './archive'; -import type { Asset } from './assets'; -import { collectAssets } from './assets'; -import { extractExportedFunctions } from './backend/ast-parsing/extract-backend-functions'; -import { extractConnectionIds } from './backend/ast-parsing/extract-connection-ids'; -import { encodeQueryName } from './backend/encodeQueryName'; -import { generateProxyModule } from './backend/proxy-codegen'; -import type { BackendFunction } from './backend/types'; -import { BACKEND_FILE_RE, CONFIG_KEY, PLUGIN_NAME } from './constants'; -import { resolveIdentifier } from './identifier'; -import type { AppsManifest, AppsOptions } from './types'; -import { uploadArchive } from './upload'; +import { CONFIG_KEY, PLUGIN_NAME } from './constants'; +import type { AppsOptions } from './types'; import { validateOptions } from './validate'; import { getVitePlugin } from './vite/index'; export { CONFIG_KEY, PLUGIN_NAME }; -/** - * Build BackendFunction entries from discovered export names and generate - * the frontend proxy module that replaces the original backend code. - */ -function buildProxyModule( - exportNames: string[], - id: string, - buildRoot: string, - allowedConnectionIds: string[], -): { functions: BackendFunction[]; proxyCode: string } { - const relativePath = path.relative(buildRoot, id); - const refPath = relativePath.replace(BACKEND_FILE_RE, ''); - - const functions: BackendFunction[] = []; - const proxyExports: Array<{ exportName: string; queryName: string }> = []; - - for (const exportName of exportNames) { - const func = { - relativePath: refPath, - name: exportName, - absolutePath: id, - allowedConnectionIds, - }; - functions.push(func); - proxyExports.push({ exportName, queryName: encodeQueryName(func) }); - } - - return { functions, proxyCode: generateProxyModule(proxyExports) }; -} - -const yellow = chalk.yellow.bold; -const red = chalk.red.bold; -const MANIFEST_FILE_NAME = 'manifest.json'; - -/** - * Create a registry for tracking discovered backend functions. - * Uses a Map keyed by entryPath so that re-transforms (e.g. during HMR) - * replace stale entries for a file instead of appending duplicates. - */ -function createBackendFunctionRegistry() { - const functionsByEntryPath = new Map(); - - return { - /** Replace all entries for a given file. Handles HMR re-transforms. */ - setBackendFunctions(entryPath: string, functions: BackendFunction[]) { - functionsByEntryPath.set(entryPath, functions); - }, - /** Get a flat array of all currently registered backend functions. */ - getBackendFunctions(): BackendFunction[] { - return Array.from(functionsByEntryPath.values()).flat(); - }, - }; -} - -function buildManifest(backendFunctions: BackendFunction[]): AppsManifest { - const functions: AppsManifest['backend']['functions'] = {}; - for (const func of backendFunctions) { - functions[encodeQueryName(func)] = { - allowedConnectionIds: [...func.allowedConnectionIds], - }; - } - return { backend: { functions } }; -} - -async function writeManifestFile(backendFunctions: BackendFunction[]): Promise<{ - manifestAsset: Asset; - cleanup: () => Promise; -}> { - const manifestDir = await fsp.mkdtemp(path.join(os.tmpdir(), 'dd-apps-manifest-')); - const manifestPath = path.join(manifestDir, MANIFEST_FILE_NAME); - try { - await fsp.writeFile(manifestPath, JSON.stringify(buildManifest(backendFunctions), null, 2)); - } catch (error) { - await rm(manifestDir); - throw error; - } - return { - manifestAsset: { - absolutePath: manifestPath, - relativePath: MANIFEST_FILE_NAME, - }, - cleanup: () => rm(manifestDir), - }; -} - export type types = { // Add the types you'd like to expose here. AppsOptions: AppsOptions; @@ -119,7 +18,6 @@ export type types = { export const getPlugins: GetPlugins = ({ options, context, bundler }) => { const log = context.getLogger(PLUGIN_NAME); - let toThrow: Error | undefined; const validatedOptions = validateOptions(options); if (!validatedOptions.enable) { return []; @@ -130,186 +28,16 @@ export const getPlugins: GetPlugins = ({ options, context, bundler }) => { return []; } - // Inject the runtime that `globalThis.DD_APPS_RUNTIME.executeBackendFunction` - // is read from. The generated proxy modules (emitted by the transform hook - // below) reference that global. NOTE: This file is built alongside the - // bundler plugin via the `toBuild` entry in @dd/apps-plugin's package.json. - // - // Position MIDDLE is used instead of BEFORE so Vite's dev server injects - // the runtime as a