Skip to content

Commit ece28b9

Browse files
committed
Drop @datadog/apps-function-query, inject apps runtime via globalThis.DD_APPS_RUNTIME
1 parent 7e46940 commit ece28b9

11 files changed

Lines changed: 76 additions & 43 deletions

File tree

Binary file not shown.

LICENSES-3rdparty.csv

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,6 @@ Component,Origin,Licence,Copyright
116116
@babel/types,npm,MIT,The Babel Team (https://babel.dev/docs/en/next/babel-types)
117117
@bcoe/v8-coverage,npm,MIT,Charles Samborski (https://demurgos.github.io/v8-coverage)
118118
@cspotcode/source-map-support,npm,MIT,(https://www.npmjs.com/package/@cspotcode/source-map-support)
119-
@datadog/apps-function-query,npm,Apache-2.0,Datadog (https://datadoghq.com)
120119
@datadog/browser-core,npm,Apache-2.0,(https://www.npmjs.com/package/@datadog/browser-core)
121120
@datadog/browser-rum,virtual,Apache-2.0,(https://www.npmjs.com/package/@datadog/browser-rum)
122121
@datadog/browser-rum-core,npm,Apache-2.0,(https://www.npmjs.com/package/@datadog/browser-rum-core)

packages/plugins/apps/package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@
1414
"buildPlugin": {
1515
"hideFromRootReadme": true
1616
},
17+
"toBuild": {
18+
"apps-runtime": {
19+
"entry": "./src/built/apps-runtime.ts",
20+
"format": ["esm"]
21+
}
22+
},
1723
"exports": {
1824
".": "./src/index.ts",
1925
"./*": "./src/*.ts"
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Unless explicitly stated otherwise all files in this repository are licensed under the MIT License.
2+
// This product includes software developed at Datadog (https://www.datadoghq.com/).
3+
// Copyright 2019-Present Datadog, Inc.
4+
5+
/* eslint-env browser */
6+
/* global globalThis */
7+
import { executeBackendFunction } from '../vite/proxy-codegen/execute-backend-function';
8+
9+
// Exposed on `globalThis.DD_APPS_RUNTIME` by the apps plugin injection so
10+
// generated proxy modules can call `executeBackendFunction` without importing
11+
// a runtime package. Internal API — consumers (generated .backend.ts proxy
12+
// modules) are produced by the apps plugin itself, not authored by users.
13+
const globalAny: any = globalThis;
14+
globalAny.DD_APPS_RUNTIME = { executeBackendFunction };

packages/plugins/apps/src/index.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import * as identifier from '@dd/apps-plugin/identifier';
88
import * as uploader from '@dd/apps-plugin/upload';
99
import { getPlugins } from '@dd/apps-plugin';
1010
import * as fsHelpers from '@dd/core/helpers/fs';
11+
import { InjectPosition } from '@dd/core/types';
1112
import type { PluginOptions } from '@dd/core/types';
1213
import {
1314
getGetPluginsArg,
@@ -58,6 +59,29 @@ describe('Apps Plugin - getPlugins', () => {
5859
expect(getPlugins(getArgs())).toHaveLength(1);
5960
});
6061

62+
test('Should inject the apps runtime at the top of the user bundle when enabled', () => {
63+
const injectMock = jest.fn();
64+
getPlugins(
65+
getGetPluginsArg(
66+
{ apps: {} },
67+
{ bundler: { ...getMockBundler({ name: 'vite' }), outDir }, inject: injectMock },
68+
),
69+
);
70+
71+
expect(injectMock).toHaveBeenCalledWith({
72+
type: 'file',
73+
position: InjectPosition.MIDDLE,
74+
value: expect.stringContaining('apps-runtime.mjs'),
75+
});
76+
});
77+
78+
test('Should not inject the runtime when disabled', () => {
79+
const injectMock = jest.fn();
80+
getPlugins(getGetPluginsArg({ apps: { enable: false } }, { inject: injectMock }));
81+
82+
expect(injectMock).not.toHaveBeenCalled();
83+
});
84+
6185
test('Should log an error when identifier cannot be resolved', async () => {
6286
const collectSpy = jest.spyOn(assets, 'collectAssets').mockResolvedValue([]);
6387
const uploadSpy = jest.spyOn(uploader, 'uploadArchive').mockResolvedValue({

packages/plugins/apps/src/index.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import { rm } from '@dd/core/helpers/fs';
66
import type { GetPlugins } from '@dd/core/types';
7+
import { InjectPosition } from '@dd/core/types';
78
import chalk from 'chalk';
89
import path from 'path';
910

@@ -83,6 +84,21 @@ export const getPlugins: GetPlugins = ({ options, context, bundler }) => {
8384
return [];
8485
}
8586

87+
// Inject the runtime that `globalThis.DD_APPS_RUNTIME.executeBackendFunction`
88+
// is read from. The generated proxy modules (emitted by the transform hook
89+
// below) reference that global. NOTE: This file is built alongside the
90+
// bundler plugin via the `toBuild` entry in @dd/apps-plugin's package.json.
91+
//
92+
// Position MIDDLE is used instead of BEFORE so Vite's dev server injects
93+
// the runtime as a <script type="module"> via `transformIndexHtml` — BEFORE
94+
// is served via Rollup's `banner()` output hook which only fires at build
95+
// time, leaving the runtime undefined during `vite` (dev).
96+
context.inject({
97+
type: 'file',
98+
position: InjectPosition.MIDDLE,
99+
value: path.join(__dirname, './apps-runtime.mjs'),
100+
});
101+
86102
const { setBackendFunctions, getBackendFunctions } = createBackendFunctionRegistry();
87103

88104
const handleUpload = async (backendOutputs: Map<string, string>) => {

packages/plugins/apps/src/vite/proxy-codegen.test.ts

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,16 @@
55
import { generateProxyModule } from '@dd/apps-plugin/vite/proxy-codegen';
66

77
describe('Proxy Codegen - generateProxyModule', () => {
8-
test('Should generate a proxy module with a pre-computed query name', () => {
8+
test('Should generate a proxy module that reads executeBackendFunction off the runtime global', () => {
99
const result = generateProxyModule([{ exportName: 'add', queryName: 'a1b2c3d4e5f6.add' }]);
1010

11+
expect(result).toContain('export async function add(...args)');
1112
expect(result).toContain(
12-
"import { executeBackendFunction } from '@datadog/apps-function-query'",
13+
'globalThis.DD_APPS_RUNTIME.executeBackendFunction("a1b2c3d4e5f6.add", args)',
1314
);
14-
expect(result).toContain('export async function add(...args)');
15-
expect(result).toContain('executeBackendFunction("a1b2c3d4e5f6.add", args)');
15+
expect(result).not.toContain('@datadog/apps-function-query');
16+
expect(result).not.toContain('virtual:dd-apps-runtime');
17+
expect(result).not.toMatch(/^\s*import\s/m);
1618
});
1719

1820
test('Should generate a proxy module for multiple exports', () => {
@@ -38,15 +40,4 @@ describe('Proxy Codegen - generateProxyModule', () => {
3840
expect(result).not.toContain('.backend');
3941
expect(result).toContain('"deadbeef1234.login"');
4042
});
41-
42-
test('Should import executeBackendFunction exactly once', () => {
43-
const result = generateProxyModule([
44-
{ exportName: 'a', queryName: 'abc123.a' },
45-
{ exportName: 'b', queryName: 'abc123.b' },
46-
{ exportName: 'c', queryName: 'abc123.c' },
47-
]);
48-
49-
const importCount = (result.match(/import.*executeBackendFunction/g) || []).length;
50-
expect(importCount).toBe(1);
51-
});
5243
});

packages/plugins/apps/src/vite/proxy-codegen.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,25 @@ interface ProxyExport {
1111

1212
/**
1313
* Generate a proxy module for a `.backend.ts` file. Each exported function
14-
* is replaced with a wrapper that calls `executeBackendFunction` with the
15-
* pre-computed query name string.
14+
* is replaced with a wrapper that calls `executeBackendFunction` from the
15+
* runtime exposed on `globalThis.DD_APPS_RUNTIME` by the apps plugin's
16+
* injection (see packages/plugins/apps/src/built/apps-runtime.ts).
1617
*
17-
* The raw backend file path is never present in the generated
18-
* code — only the hashed query name appears, preventing backend file
19-
* structure from leaking into frontend bundles.
18+
* The raw backend file path is never present in the generated code — only
19+
* the hashed query name appears, preventing backend file structure from
20+
* leaking into frontend bundles.
2021
*
2122
* @param exports - The export name + pre-computed query name for each export
2223
* @returns Generated proxy module source code
2324
*/
2425
export function generateProxyModule(exports: ProxyExport[]): string {
2526
const lines: string[] = [];
2627

27-
lines.push("import { executeBackendFunction } from '@datadog/apps-function-query';");
28-
lines.push('');
29-
3028
for (const { exportName, queryName } of exports) {
3129
lines.push(`export async function ${exportName}(...args) {`);
32-
lines.push(` return executeBackendFunction(${JSON.stringify(queryName)}, args);`);
30+
lines.push(
31+
` return globalThis.DD_APPS_RUNTIME.executeBackendFunction(${JSON.stringify(queryName)}, args);`,
32+
);
3333
lines.push('}');
3434
lines.push('');
3535
}

packages/published/vite-plugin/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@
5050
"watch": "yarn build --watch"
5151
},
5252
"dependencies": {
53-
"@datadog/apps-function-query": "0.0.1",
5453
"@datadog/js-instrumentation-wasm": "1.0.8",
5554
"async-retry": "1.3.3",
5655
"chalk": "2.3.1",

packages/tools/src/commands/integrity/dependencies.ts

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,7 @@ const dependencyExceptions = [
3434
// Dependencies that are added directly to a published package and should not
3535
// be removed by the integrity check, even though they don't come from an
3636
// internal plugin's dependency tree.
37-
const publishedPackageExtraDependencies: Record<string, Record<string, string>> = {
38-
// The apps plugin generates proxy modules that import executeBackendFunction
39-
// at runtime in the user's frontend bundle. Only the vite-plugin supports
40-
// .backend.ts files, so this dependency is scoped here rather than in the
41-
// internal plugin (which would propagate it to all published packages).
42-
'@datadog/vite-plugin': {
43-
'@datadog/apps-function-query': '0.0.1',
44-
},
45-
};
37+
const publishedPackageExtraDependencies: Record<string, Record<string, string>> = {};
4638

4739
// Some filters.
4840
const allDependencies = (dependencyName: string) => !dependencyExceptions.includes(dependencyName);

0 commit comments

Comments
 (0)