Skip to content

Commit ede88b6

Browse files
authored
fix(ud): Better support for non-standard vite configs (#1825)
1 parent c9482b5 commit ede88b6

2 files changed

Lines changed: 174 additions & 2 deletions

File tree

packages/cli/src/commands/setup/deploy/__tests__/netlify.test.js

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,4 +246,131 @@ describe('netlify with --ud', () => {
246246
})"
247247
`)
248248
})
249+
250+
it('handles arrow-function wrapped defineConfig with destructured mode arg', async () => {
251+
vol.fromJSON({
252+
'/cedar-app/web/vite.config.ts': [
253+
"import dns from 'node:dns'",
254+
'',
255+
"import { defineConfig } from 'vite'",
256+
'',
257+
"import { cedar, cedarUniversalDeployPlugin } from '@cedarjs/vite'",
258+
'',
259+
"dns.setDefaultResultOrder('verbatim')",
260+
'',
261+
'export default defineConfig(({ mode }) => ({',
262+
' plugins: [cedar({ mode }), cedarUniversalDeployPlugin()],',
263+
' test: {',
264+
" environment: 'jsdom',",
265+
' },',
266+
'}))',
267+
].join('\n'),
268+
})
269+
270+
await handler({ force: true, ud: true })
271+
272+
const filesystem = vol.toJSON()
273+
274+
expect(filesystem['/cedar-app/web/vite.config.ts']).toMatchInlineSnapshot(`
275+
"import dns from 'node:dns'
276+
277+
import netlifyCompat from '@universal-deploy/netlify/vite'
278+
import netlify from '@netlify/vite-plugin'
279+
import { defineConfig } from 'vite'
280+
281+
import { cedar, cedarUniversalDeployPlugin } from '@cedarjs/vite'
282+
283+
dns.setDefaultResultOrder('verbatim')
284+
285+
export default defineConfig(({ mode }) => ({
286+
plugins: [
287+
netlify({ build: { enabled: true } }),
288+
netlifyCompat(),
289+
cedar({ mode }),
290+
cedarUniversalDeployPlugin(),
291+
],
292+
test: {
293+
environment: 'jsdom',
294+
},
295+
}))"
296+
`)
297+
})
298+
299+
it('handles arrow function with explicit block body and return statement', async () => {
300+
vol.fromJSON({
301+
'/cedar-app/web/vite.config.ts': [
302+
"import { defineConfig } from 'vite'",
303+
'',
304+
"import { cedar, cedarUniversalDeployPlugin } from '@cedarjs/vite'",
305+
'',
306+
'export default defineConfig(({ mode }) => {',
307+
' return {',
308+
' plugins: [cedar({ mode }), cedarUniversalDeployPlugin()],',
309+
' }',
310+
'})',
311+
].join('\n'),
312+
})
313+
314+
await handler({ force: true, ud: true })
315+
316+
const filesystem = vol.toJSON()
317+
318+
expect(filesystem['/cedar-app/web/vite.config.ts']).toMatchInlineSnapshot(`
319+
"import netlifyCompat from '@universal-deploy/netlify/vite'
320+
import netlify from '@netlify/vite-plugin'
321+
import { defineConfig } from 'vite'
322+
323+
import { cedar, cedarUniversalDeployPlugin } from '@cedarjs/vite'
324+
325+
export default defineConfig(({ mode }) => {
326+
return {
327+
plugins: [
328+
netlify({ build: { enabled: true } }),
329+
netlifyCompat(),
330+
cedar({ mode }),
331+
cedarUniversalDeployPlugin(),
332+
],
333+
}
334+
})"
335+
`)
336+
})
337+
338+
it('handles regular function expression with return statement', async () => {
339+
vol.fromJSON({
340+
'/cedar-app/web/vite.config.ts': [
341+
"import { defineConfig } from 'vite'",
342+
'',
343+
"import { cedar, cedarUniversalDeployPlugin } from '@cedarjs/vite'",
344+
'',
345+
'export default defineConfig(function ({ mode }) {',
346+
' return {',
347+
' plugins: [cedar({ mode }), cedarUniversalDeployPlugin()],',
348+
' }',
349+
'})',
350+
].join('\n'),
351+
})
352+
353+
await handler({ force: true, ud: true })
354+
355+
const filesystem = vol.toJSON()
356+
357+
expect(filesystem['/cedar-app/web/vite.config.ts']).toMatchInlineSnapshot(`
358+
"import netlifyCompat from '@universal-deploy/netlify/vite'
359+
import netlify from '@netlify/vite-plugin'
360+
import { defineConfig } from 'vite'
361+
362+
import { cedar, cedarUniversalDeployPlugin } from '@cedarjs/vite'
363+
364+
export default defineConfig(function ({ mode }) {
365+
return {
366+
plugins: [
367+
netlify({ build: { enabled: true } }),
368+
netlifyCompat(),
369+
cedar({ mode }),
370+
cedarUniversalDeployPlugin(),
371+
],
372+
}
373+
})"
374+
`)
375+
})
249376
})

packages/cli/src/commands/setup/deploy/helpers/index.js

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,51 @@ function posToIndex(str, line, column) {
139139
return index + column
140140
}
141141

142+
/**
143+
* Unwraps the config object from a `defineConfig(...)` call argument.
144+
*
145+
* Handles both direct object and arrow/function wrappers:
146+
* defineConfig({...}) → ObjectExpression
147+
* defineConfig(({ mode }) => ({...})) → ObjectExpression (arrow, implicit return)
148+
* defineConfig(() => { return {...} }) → ObjectExpression (arrow, explicit return)
149+
* defineConfig(function() { return {} }) → ObjectExpression (function expression)
150+
*
151+
* @param {object} arg - A babel AST node.
152+
* @returns The inner ObjectExpression, or `null` if not found.
153+
*/
154+
function resolveConfigObject(arg) {
155+
if (t.isObjectExpression(arg)) {
156+
return arg
157+
}
158+
159+
if (t.isArrowFunctionExpression(arg)) {
160+
// Implicit return: ({...})
161+
if (t.isObjectExpression(arg.body)) {
162+
return arg.body
163+
}
164+
// Block body with explicit return: { return {...} }
165+
if (t.isBlockStatement(arg.body)) {
166+
const returnStmt = arg.body.body.find((s) => t.isReturnStatement(s))
167+
if (returnStmt && t.isObjectExpression(returnStmt.argument)) {
168+
return returnStmt.argument
169+
}
170+
}
171+
return null
172+
}
173+
174+
if (t.isFunctionExpression(arg)) {
175+
if (t.isBlockStatement(arg.body)) {
176+
const returnStmt = arg.body.body.find((s) => t.isReturnStatement(s))
177+
if (returnStmt && t.isObjectExpression(returnStmt.argument)) {
178+
return returnStmt.argument
179+
}
180+
}
181+
return null
182+
}
183+
184+
return null
185+
}
186+
142187
/**
143188
* Inserts plugin call expressions before `cedar()` in the `plugins` array
144189
* of `defineConfig({...})` inside a vite config file.
@@ -175,8 +220,8 @@ export function insertPluginsBeforeCedar({ content, pluginCodes }) {
175220
return null
176221
}
177222

178-
const configArg = defaultExport.declaration.arguments[0]
179-
if (!t.isObjectExpression(configArg)) {
223+
const configArg = resolveConfigObject(defaultExport.declaration.arguments[0])
224+
if (!configArg) {
180225
return null
181226
}
182227

0 commit comments

Comments
 (0)