[APPS] Add vite dev server middleware for backend functions#291
[APPS] Add vite dev server middleware for backend functions#291sdkennedy2 wants to merge 11 commits intosdkennedy2/apps-vite-backend-buildfrom
Conversation
|
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
a1630ef to
4f85ed9
Compare
264286b to
2f9f167
Compare
7e20d87 to
e465412
Compare
2f9f167 to
d682d52
Compare
sarenji
left a comment
There was a problem hiding this comment.
Some initial thoughts on this
95203d8 to
a0932f3
Compare
yoannmoinet
left a comment
There was a problem hiding this comment.
You should check in the other parts of the code for hints on how to use what's available to you in the repo.
|
|
||
| describe('Dev Server Middleware', () => { | ||
| beforeEach(() => { | ||
| jest.clearAllMocks(); |
There was a problem hiding this comment.
nit: this is unnecessary as it is part of the Jest configuration.
| // Wait for async handler to complete. | ||
| await new Promise((resolve) => setTimeout(resolve, 100)); |
There was a problem hiding this comment.
Same, and for all the followings as well.
You should not be doing this.
| ], | ||
| }); | ||
|
|
||
| const output = (Array.isArray(result) ? result[0] : result) as RollupOutput; |
There was a problem hiding this comment.
Why do you need the as RollupOutput part here?
This should be typed from viteBuild, which should not have a basic Function type.
807bbdf to
c0be60c
Compare
|
✅ Tests 🎉 All green!❄️ No new flaky tests detected 🔗 Commit SHA: 81b50d1 | Docs | Datadog PR Page | Was this helpful? React with 👍/👎 or give us feedback! |
146a8f6 to
9c96053
Compare
d2b2a1b to
03c5f9c
Compare
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…try bug - Replace raw fetch calls with doRequest from @dd/core/helpers/request for retry support and consistency with codebase conventions. - Replace flaky setTimeout waits in tests with deterministic res.done promise. - Replace as-any casts with as-unknown-as-Type for proper type narrowing. - Fix generateDevVirtualEntryContent calling undefined generateMainBody by inlining the main body generation (matching production entry pattern). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>
6c22cb8 to
0de8724
Compare
yoannmoinet
left a comment
There was a problem hiding this comment.
I'm really not confident about the tests on the dev-server.
| middleware(req, res, jest.fn()); | ||
| await res.done; | ||
|
|
||
| expect(res.statusCode).toBe(500); |
There was a problem hiding this comment.
Is it 500 or 400 that we're expecting for a bad request?
| middleware(req, res, jest.fn()); | ||
| await res.done; | ||
|
|
||
| expect(res.statusCode).toBe(500); |
| middleware(req, res, jest.fn()); | ||
| await res.done; | ||
|
|
||
| expect(res.statusCode).toBe(500); |
| expect(res.statusCode).toBe(500); | ||
| const body = JSON.parse(res.getBody()); | ||
| expect(body.success).toBe(false); | ||
| expect(body.error).toContain('HTTP 403'); |
There was a problem hiding this comment.
403 now?
These tests are not re-assuring to be honest.
There was a problem hiding this comment.
It would be better to return a 403 here so the developer gets a clear signal that their credentials are wrong rather than a generic 500. However, doRequest throws a plain Error with the status code embedded in the message string ("HTTP 403 Forbidden") rather than a structured error with a .status property. To forward upstream status codes cleanly, we'd need to refactor doRequest to throw a typed error class — which would be a broader change across the codebase. Would you prefer we tackle that refactor as part of this PR or handle it as a follow-up?
There was a problem hiding this comment.
From a perspective of unblocking onboarding design partners I'd advocate we leave this as is.
There was a problem hiding this comment.
Makes sense to tackle this later.
I guess the error in question is this one?
| const maxRetries = 10; | ||
|
|
||
| for (let attempt = 0; attempt < maxRetries; attempt++) { |
There was a problem hiding this comment.
Isn't this all covered by doRequest already?
I don't understand what this does that doRequest doesn't support yet.
There was a problem hiding this comment.
These serve different purposes. doRequest handles HTTP-level retries — transient network failures, 5xx responses, etc. The poll loop here is application-level: the long-polling endpoint returns HTTP 200 with { done: false } when its server-side wait window (~30s) expires before the query finishes. We re-poll with a fresh request until done: true. doRequest can't express this because the HTTP request itself succeeds — it's the response payload that says "not ready yet, ask again."
Additionally, doRequest doesn't expose enough structure in its error handling to support this pattern — it throws a plain Error with the status code baked into the message string rather than a typed error object, so there's no way to programmatically distinguish between "server said not ready" vs "server returned an error" without string parsing. The poll loop gives us clean control over both cases. I'll add a comment to make the distinction clearer in the code.
There was a problem hiding this comment.
Sounds good, maybe a comment explaining this would be helpful.
There was a problem hiding this comment.
Good call 👍. I added a comment.
| if (!fullAuth) { | ||
| sendError( | ||
| res, | ||
| 503, |
There was a problem hiding this comment.
403 seems more appropriate here.

Motivation
High Code Apps backend functions need a local development experience. Currently, backend functions are only built at production build time — there's no way to invoke them during local development with hot reload.
Changes
Adds a Vite dev server middleware that intercepts requests to backend function endpoints, bundles the target function on-the-fly using Vite's
buildAPI, executes it, and returns the result. This gives developers a local dev loop for backend functions without needing a full production build.Key pieces:
dev-server.ts— Express-style middleware that handles/execute-actionrequests. On each invocation it bundles the requested function using Vite's in-memory build, evaluates the bundle, and returns the result. Includes long-poll support for streaming responses.build-config.ts— Extracted shared Vite build config (getBaseBackendBuildConfig) used by both the production multi-entry build and the dev single-function build, eliminating duplication of config options (resolve conditions, output format, virtual module plugin, etc.).virtual-entry.ts— AddedgenerateDevVirtualEntryContentfor the dev build's virtual entry point, alongside the existing production entry generator.doRequestfrom@dd/core/helpers/requestfor outbound calls (consistency with codebase conventions, retry support).QA Instructions
yarn devin a project with backend functionsBlast Radius