Skip to content

Commit 4213eb6

Browse files
committed
perf: avoid merging empty object in record
1 parent 835df1f commit 4213eb6

File tree

3 files changed

+76
-6
lines changed

3 files changed

+76
-6
lines changed

packages/router/src/unplugin/core/context.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,10 +166,10 @@ export function createRoutesContext(options: ResolvedOptions) {
166166

167167
async function writeRouteInfoToNode(node: TreeNode, filePath: string) {
168168
const content = await fs.readFile(filePath, 'utf8')
169-
// TODO: cache the result of parsing the SFC (in the extractDefinePageAndName) so the transform can reuse the parsing
170-
node.hasDefinePage ||= content.includes('definePage')
171169
// TODO: track if it changed and to not always trigger HMR
172170
const definedPageInfo = extractDefinePageInfo(content, filePath)
171+
// TODO: add a test that this can be set to true and then to false
172+
node.hasDefinePage = definedPageInfo?.hasRemainingProperties ?? false
173173
// TODO: track if it changed and if generateRoutes should be called again
174174
const routeBlock = getRouteBlock(filePath, content, options)
175175
// TODO: should warn if hasDefinePage and customRouteBlock

packages/router/src/unplugin/core/definePage.spec.ts

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ definePage({
183183
expect(extractDefinePageInfo(sampleCode, 'src/pages/basic.vue')).toEqual({
184184
name: 'custom',
185185
path: '/custom',
186+
hasRemainingProperties: false,
186187
})
187188
})
188189

@@ -217,6 +218,7 @@ definePage({
217218
expect(
218219
extractDefinePageInfo(codeWithAllParams, 'src/pages/test.vue')
219220
).toEqual({
221+
hasRemainingProperties: false,
220222
params: {
221223
path: {
222224
userId: 'int',
@@ -253,6 +255,7 @@ definePage({
253255
`
254256
expect(extractDefinePageInfo(code, 'src/pages/test.vue')).toEqual({
255257
alias: ['/other'],
258+
hasRemainingProperties: false,
256259
})
257260
})
258261

@@ -266,6 +269,7 @@ definePage({
266269
`
267270
expect(extractDefinePageInfo(code, 'src/pages/test.vue')).toEqual({
268271
alias: ['/a', '/b'],
272+
hasRemainingProperties: false,
269273
})
270274
})
271275

@@ -277,7 +281,9 @@ definePage({
277281
})
278282
</script>
279283
`
280-
expect(extractDefinePageInfo(code, 'src/pages/test.vue')).toEqual({})
284+
expect(extractDefinePageInfo(code, 'src/pages/test.vue')).toEqual({
285+
hasRemainingProperties: false,
286+
})
281287
expect(
282288
'route alias must be a string literal or an array of string literals'
283289
).toHaveBeenWarned()
@@ -292,7 +298,9 @@ definePage({
292298
})
293299
</script>
294300
`
295-
expect(extractDefinePageInfo(code, 'src/pages/test.vue')).toEqual({})
301+
expect(extractDefinePageInfo(code, 'src/pages/test.vue')).toEqual({
302+
hasRemainingProperties: false,
303+
})
296304
expect(
297305
'route alias must be a string literal or an array of string literals'
298306
).toHaveBeenWarned()
@@ -308,6 +316,51 @@ definePage({
308316
`
309317
expect(extractDefinePageInfo(code, 'src/pages/test.vue')).toEqual({
310318
alias: ['/a', '/b'],
319+
hasRemainingProperties: false,
320+
})
321+
322+
expect(
323+
`route alias array must only contain string literals.`
324+
).toHaveBeenWarned()
325+
})
326+
327+
describe('hasRemainingProperties', () => {
328+
it('is false when only name/path/alias/params are present', () => {
329+
const code = vue`
330+
<script setup>
331+
definePage({
332+
name: 'home',
333+
path: '/home',
334+
alias: ['/'],
335+
params: { path: { id: 'int' } },
336+
})
337+
</script>
338+
`
339+
const result = extractDefinePageInfo(code, 'src/pages/test.vue')
340+
expect(result?.hasRemainingProperties).toBe(false)
341+
})
342+
343+
it('is true when meta is present', () => {
344+
const code = vue`
345+
<script setup>
346+
definePage({
347+
name: 'home',
348+
meta: { requiresAuth: true },
349+
})
350+
</script>
351+
`
352+
const result = extractDefinePageInfo(code, 'src/pages/test.vue')
353+
expect(result?.hasRemainingProperties).toBe(true)
354+
})
355+
356+
it('is false for empty definePage object', () => {
357+
const code = vue`
358+
<script setup>
359+
definePage({})
360+
</script>
361+
`
362+
const result = extractDefinePageInfo(code, 'src/pages/test.vue')
363+
expect(result?.hasRemainingProperties).toBe(false)
311364
})
312365
})
313366

@@ -383,6 +436,7 @@ export default {
383436
).toEqual({
384437
name: 'custom',
385438
path: '/custom',
439+
hasRemainingProperties: false,
386440
})
387441
})
388442

packages/router/src/unplugin/core/definePage.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import type {
1414
ObjectProperty,
1515
Program,
1616
Statement,
17+
StringLiteral,
1718
} from '@babel/types'
1819
import { generate } from '@babel/generator'
1920
import { walkAST } from 'ast-walker-scope'
@@ -215,6 +216,11 @@ export interface DefinePageInfo {
215216
path?: string
216217
alias?: string[]
217218
params?: CustomRouteBlock['params']
219+
/**
220+
* Whether definePage has properties beyond the statically extracted ones
221+
* (name, path, alias, params)
222+
*/
223+
hasRemainingProperties: boolean
218224
}
219225

220226
/**
@@ -265,7 +271,7 @@ export function extractDefinePageInfo(
265271
)
266272
}
267273

268-
const routeInfo: DefinePageInfo = {}
274+
const routeInfo: DefinePageInfo = { hasRemainingProperties: false }
269275

270276
for (const prop of routeRecord.properties) {
271277
if (prop.type === 'ObjectProperty' && prop.key.type === 'Identifier') {
@@ -293,6 +299,8 @@ export function extractDefinePageInfo(
293299
if (prop.value.type === 'ObjectExpression') {
294300
routeInfo.params = extractParamsInfo(prop.value, id)
295301
}
302+
} else {
303+
routeInfo.hasRemainingProperties = true
296304
}
297305
}
298306
}
@@ -436,7 +444,15 @@ export function extractRouteAlias(
436444
return aliasValue.type === 'StringLiteral'
437445
? [aliasValue.value]
438446
: aliasValue.elements
439-
.filter(node => node?.type === 'StringLiteral')
447+
.filter((node): node is StringLiteral => {
448+
if (node?.type === 'StringLiteral') {
449+
return true
450+
}
451+
warn(
452+
`route alias array must only contain string literals. Found ${node?.type ? `"${node.type}" ` : ''}in "${id}".`
453+
)
454+
return false
455+
})
440456
.map(el => el.value)
441457
}
442458
return undefined

0 commit comments

Comments
 (0)