Skip to content

Commit 0de8724

Browse files
sdkennedy2claude
andcommitted
Extract shared vite.build config for production and dev backend builds
Move common build options (configFile, logLevel, minify, target, treeshake, preserveEntrySignatures, onwarn, resolve, output format, and virtual module plugin) into a shared getBaseBackendBuildConfig() helper. Each caller now only specifies what differs: production writes multi-entry output to disk, dev builds a single function in-memory. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent e9cec68 commit 0de8724

3 files changed

Lines changed: 90 additions & 78 deletions

File tree

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
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+
import type { BuildOptions, InlineConfig, Plugin } from 'vite';
6+
7+
/**
8+
* Create the virtual module resolver plugin used by both production and dev builds.
9+
* Maps virtual IDs to their generated source content.
10+
*/
11+
export function createVirtualPlugin(name: string, virtualEntries: Record<string, string>): Plugin {
12+
return {
13+
name,
14+
enforce: 'pre',
15+
resolveId(id: string) {
16+
if (virtualEntries[id]) {
17+
return { id, moduleSideEffects: true };
18+
}
19+
return null;
20+
},
21+
load(id: string) {
22+
if (virtualEntries[id]) {
23+
return virtualEntries[id];
24+
}
25+
return null;
26+
},
27+
};
28+
}
29+
30+
/**
31+
* Shared Vite/Rollup config for building backend functions.
32+
* Both the production build (write to disk) and dev build (in-memory)
33+
* use this as a base, overriding only what differs.
34+
*/
35+
export function getBaseBackendBuildConfig(
36+
root: string,
37+
virtualEntries: Record<string, string>,
38+
): InlineConfig & {
39+
build: BuildOptions & { rollupOptions: NonNullable<BuildOptions['rollupOptions']> };
40+
} {
41+
return {
42+
configFile: false,
43+
root,
44+
logLevel: 'silent',
45+
build: {
46+
minify: false,
47+
target: 'esnext',
48+
rollupOptions: {
49+
output: { format: 'es', exports: 'named' },
50+
preserveEntrySignatures: 'exports-only',
51+
treeshake: false,
52+
onwarn(warning, defaultHandler) {
53+
if (warning.code === 'MODULE_LEVEL_DIRECTIVE') {
54+
return;
55+
}
56+
defaultHandler(warning);
57+
},
58+
},
59+
},
60+
resolve: {
61+
extensions: ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs', '.json'],
62+
},
63+
plugins: [createVirtualPlugin('dd-backend-resolve', virtualEntries)],
64+
};
65+
}

packages/plugins/apps/src/backend/vite/dev-server.ts

Lines changed: 14 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import type { build } from 'vite';
1313
import type { BackendFunction } from '../discovery';
1414
import { generateDevVirtualEntryContent } from '../virtual-entry';
1515

16+
import { getBaseBackendBuildConfig } from './build-config';
17+
1618
type BundleFn = (func: BackendFunction, args: unknown[]) => Promise<string>;
1719

1820
const DEV_VIRTUAL_PREFIX = 'virtual:dd-backend-dev:';
@@ -71,56 +73,25 @@ async function bundleBackendFunction(
7173

7274
log.debug(`Bundling backend function "${func.name}" from ${func.entryPath}`);
7375

76+
const baseConfig = getBaseBackendBuildConfig(projectRoot, { [virtualId]: virtualContent });
77+
78+
// Dev: build a single function in-memory per request so we can send the
79+
// bundled script to the Datadog API without writing temp files.
80+
// Uses a plain "virtual:" prefix instead of \0 because Rollup generates
81+
// empty chunks when \0-prefixed IDs are used as input entries.
82+
// inlineDynamicImports collapses everything into one chunk since we only
83+
// have a single entry (incompatible with multi-entry builds).
7484
const result = await viteBuild({
75-
configFile: false,
76-
root: projectRoot,
77-
logLevel: 'silent',
85+
...baseConfig,
7886
build: {
87+
...baseConfig.build,
7988
write: false,
80-
minify: false,
81-
// Target esnext to avoid unnecessary transforms.
82-
target: 'esnext',
8389
rollupOptions: {
90+
...baseConfig.build.rollupOptions,
8491
input: virtualId,
85-
output: { format: 'es', exports: 'named', inlineDynamicImports: true },
86-
treeshake: false,
87-
// Disable tree-shaking so action-catalog bridges and argument passing stay
88-
// fully intact in the generated backend bundle.
89-
// preserveEntrySignatures ensures the main() export isn't removed.
90-
preserveEntrySignatures: 'exports-only',
91-
// Silence "use client" directive warnings from third-party deps.
92-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
93-
onwarn(warning: any, defaultHandler: any) {
94-
if (warning.code === 'MODULE_LEVEL_DIRECTIVE') {
95-
return;
96-
}
97-
defaultHandler(warning);
98-
},
92+
output: { ...baseConfig.build.rollupOptions.output, inlineDynamicImports: true },
9993
},
10094
},
101-
// Re-enable Vite's built-in resolve and esbuild transform for TypeScript support.
102-
// Without this, .ts imports from the virtual entry won't be processed.
103-
resolve: {
104-
extensions: ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs', '.json'],
105-
},
106-
plugins: [
107-
{
108-
name: 'dd-backend-dev-resolve',
109-
enforce: 'pre',
110-
resolveId(id: string) {
111-
if (id === virtualId) {
112-
return { id, moduleSideEffects: true };
113-
}
114-
return null;
115-
},
116-
load(id: string) {
117-
if (id === virtualId) {
118-
return virtualContent;
119-
}
120-
return null;
121-
},
122-
},
123-
],
12495
});
12596

12697
const output = Array.isArray(result) ? result[0] : result;

packages/plugins/apps/src/backend/vite/index.ts

Lines changed: 11 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import type { build } from 'vite';
1111
import type { BackendFunction } from '../discovery';
1212
import { generateVirtualEntryContent } from '../virtual-entry';
1313

14+
import { getBaseBackendBuildConfig } from './build-config';
1415
import { createDevServerMiddleware } from './dev-server';
1516

1617
const VIRTUAL_PREFIX = '\0dd-backend:';
@@ -43,50 +44,25 @@ async function buildBackendFunctions(
4344

4445
log.debug(`Building ${functions.length} backend function(s) via vite.build()`);
4546

47+
const baseConfig = getBaseBackendBuildConfig(buildRoot, virtualEntries);
48+
49+
// Production: build all functions in one vite.build() call, writing each to
50+
// disk as a named file so the archive/upload step can collect them.
51+
// Uses multi-entry input (one per function) with \0-prefixed virtual IDs —
52+
// the \0 convention prevents other plugins from processing these IDs.
4653
const result = await viteBuild({
47-
configFile: false,
48-
root: buildRoot,
49-
logLevel: 'silent',
54+
...baseConfig,
5055
build: {
56+
...baseConfig.build,
5157
write: true,
5258
outDir,
5359
emptyOutDir: false,
54-
minify: false,
55-
target: 'esnext',
5660
rollupOptions: {
61+
...baseConfig.build.rollupOptions,
5762
input,
58-
output: { format: 'es', exports: 'named', entryFileNames: '[name].js' },
59-
preserveEntrySignatures: 'exports-only',
60-
treeshake: false,
61-
onwarn(warning, defaultHandler) {
62-
if (warning.code === 'MODULE_LEVEL_DIRECTIVE') {
63-
return;
64-
}
65-
defaultHandler(warning);
66-
},
63+
output: { ...baseConfig.build.rollupOptions.output, entryFileNames: '[name].js' },
6764
},
6865
},
69-
resolve: {
70-
extensions: ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs', '.json'],
71-
},
72-
plugins: [
73-
{
74-
name: 'dd-backend-resolve',
75-
enforce: 'pre',
76-
resolveId(id: string) {
77-
if (virtualEntries[id]) {
78-
return { id, moduleSideEffects: true };
79-
}
80-
return null;
81-
},
82-
load(id: string) {
83-
if (virtualEntries[id]) {
84-
return virtualEntries[id];
85-
}
86-
return null;
87-
},
88-
},
89-
],
9066
});
9167

9268
const output = Array.isArray(result) ? result[0] : result;

0 commit comments

Comments
 (0)