Skip to content

Commit 294e48c

Browse files
authored
fix: #232 auto generate tabbar list item (#234)
* fix: #232 auto generate tabbar list item * fix: check page has changed after read * perf: reduce traversal * fix: typo error
1 parent 2e43a37 commit 294e48c

File tree

5 files changed

+113
-44
lines changed

5 files changed

+113
-44
lines changed

packages/core/src/context.ts

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { FSWatcher } from 'chokidar'
22
import type { Logger, ViteDevServer } from 'vite'
3+
import type { TabBar, TabBarItem } from './config'
34
import type { PagesConfig } from './config/types'
45
import type { PageMetaDatum, PagePath, ResolvedOptions, SubPageMetaDatum, UserOptions } from './types'
56
import path from 'node:path'
@@ -11,8 +12,8 @@ import dbg from 'debug'
1112
import detectIndent from 'detect-indent'
1213
import detectNewline from 'detect-newline'
1314
import { loadConfig } from 'unconfig'
14-
import { OUTPUT_NAME } from './constant'
1515

16+
import { OUTPUT_NAME } from './constant'
1617
import { writeDeclaration } from './declaration'
1718
import { checkPagesJsonFile, getPageFiles, readFileSync, writeFileSync } from './files'
1819
import { resolveOptions } from './options'
@@ -279,6 +280,37 @@ export class PageContext {
279280
debug.subPages(this.subPageMetaData)
280281
}
281282

283+
private async getTabBarMerged(): Promise<TabBar> {
284+
const tabBar = {
285+
...this.pagesGlobConfig?.tabBar,
286+
list: this.pagesGlobConfig?.tabBar?.list || [],
287+
}
288+
289+
const pagePaths = new Map<string, boolean>()
290+
for (const item of tabBar.list) {
291+
pagePaths.set(item.pagePath, true)
292+
}
293+
294+
const tabBarItems: (TabBarItem & { index: number })[] = []
295+
for (const [_, page] of this.pages) {
296+
const tabbar = await page.getTabBar()
297+
if (tabbar) {
298+
tabBarItems.push(tabbar)
299+
}
300+
}
301+
302+
tabBarItems.sort((a, b) => a.index - b.index)
303+
304+
for (const item of tabBarItems) {
305+
if (!pagePaths.has(item.pagePath)) {
306+
const { index: _, ...tabbar } = item
307+
tabBar.list.push(tabbar)
308+
}
309+
}
310+
311+
return tabBar
312+
}
313+
282314
async updatePagesJSON(filepath?: string) {
283315
if (filepath) {
284316
let page = this.pages.get(filepath)
@@ -292,9 +324,12 @@ export class PageContext {
292324
}
293325
page = subPage
294326
}
295-
if (page && !await page.hasChanged()) {
296-
debug.cache(`The route block on page ${filepath} did not send any changes, skipping`)
297-
return false
327+
if (page) {
328+
await page.read()
329+
if (!page.hasChanged()) {
330+
debug.cache(`The route block on page ${filepath} did not send any changes, skipping`)
331+
return false
332+
}
298333
}
299334
}
300335

@@ -331,6 +366,7 @@ export class PageContext {
331366
...this.pagesGlobConfig,
332367
pages: this.pageMetaData,
333368
subPackages: this.subPageMetaData,
369+
tabBar: await this.getTabBarMerged(),
334370
}
335371

336372
const pagesJson = cjStringify(

packages/core/src/page.ts

Lines changed: 51 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { SFCDescriptor, SFCParseOptions } from '@vue/compiler-sfc'
2+
import type { TabBarItem } from './config'
23
import type { PageContext } from './context'
34
import type { PageMetaDatum, PagePath, RouteBlockLang, UserPageMeta } from './types'
45
import { readFileSync } from 'node:fs'
@@ -15,60 +16,76 @@ export class Page {
1516
ctx: PageContext
1617

1718
path: PagePath
19+
uri: string
1820

19-
private rawOptions: string = ''
20-
private options: PageMetaDatum | undefined
21+
changed: boolean = true
22+
23+
private raw: string = ''
24+
private meta: UserPageMeta | undefined
2125

2226
constructor(ctx: PageContext, path: PagePath) {
2327
this.ctx = ctx
2428
this.path = path
29+
this.uri = normalizePath(path.relativePath.replace(extname(path.relativePath), ''))
2530
}
2631

27-
public async getPageMeta(forceUpdate = false) {
28-
if (forceUpdate || !this.options) {
29-
await this.readPageMeta()
32+
public async getPageMeta(forceUpdate = false): Promise<PageMetaDatum> {
33+
if (forceUpdate || !this.meta) {
34+
await this.read()
3035
}
31-
return this.options!
32-
}
3336

34-
public async hasChanged() {
35-
const { hasChanged } = await this.readPageMeta()
36-
return hasChanged
37+
const { path, tabBar: _, ...others } = this.meta!
38+
39+
return {
40+
path: path ?? this.uri,
41+
...others,
42+
}
3743
}
3844

39-
public async readPageMeta() {
40-
try {
41-
const { relativePath } = this.path
45+
public async getTabBar(forceUpdate = false): Promise<TabBarItem & { index: number } | undefined> {
46+
if (forceUpdate || !this.meta) {
47+
await this.read()
48+
}
4249

43-
const { path, ...others } = await this.readPageMetaFromFile()
44-
this.options = {
45-
path: path ?? normalizePath(relativePath.replace(extname(relativePath), '')),
46-
...others,
47-
}
50+
const { tabBar } = this.meta!
4851

49-
const raw = (this.options ? JSON.stringify(this.options) : '')
50-
const hasChanged = this.rawOptions !== raw
51-
this.rawOptions = raw
52-
return {
53-
options: this.options,
54-
hasChanged,
55-
}
52+
if (tabBar === undefined) {
53+
return undefined
5654
}
57-
catch (err: any) {
58-
throw new Error(`Read page options fail in ${this.path.relativePath}\n${err.message}`)
55+
56+
return {
57+
...tabBar,
58+
pagePath: tabBar.pagePath || this.uri,
59+
index: tabBar.index || 0,
5960
}
6061
}
6162

63+
public hasChanged() {
64+
return this.changed
65+
}
66+
67+
public async read() {
68+
this.meta = await this.readPageMetaFromFile()
69+
const raw = (this.meta ? JSON.stringify(this.meta) : '')
70+
this.changed = this.raw !== raw
71+
this.raw = raw
72+
}
73+
6274
private async readPageMetaFromFile(): Promise<UserPageMeta> {
63-
const content = readFileSync(this.path.absolutePath, 'utf-8')
64-
const sfc = parseSFC(content, { filename: this.path.absolutePath })
75+
try {
76+
const content = readFileSync(this.path.absolutePath, 'utf-8')
77+
const sfc = parseSFC(content, { filename: this.path.absolutePath })
6578

66-
const meta = await tryPageMetaFromMacro(sfc)
67-
if (meta) {
68-
return meta
69-
}
79+
const meta = await tryPageMetaFromMacro(sfc)
80+
if (meta) {
81+
return meta
82+
}
7083

71-
return tryPageMetaFromCustomBlock(sfc, this.ctx.options.routeBlockLang)
84+
return tryPageMetaFromCustomBlock(sfc, this.ctx.options.routeBlockLang)
85+
}
86+
catch (err: any) {
87+
throw new Error(`Read page meta fail in ${this.path.relativePath}\n${err.message}`)
88+
}
7289
}
7390
}
7491

packages/core/src/types.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { CommentJSONValue } from 'comment-json'
22
import type { LoadConfigSource } from 'unconfig'
3-
import type { GlobalStyle, PagesConfig } from './config'
3+
import type { GlobalStyle, PagesConfig, TabBarItem } from './config'
44
import type { PageContext } from './context'
55
import type { debug } from './utils'
66

@@ -144,12 +144,30 @@ export interface SubPageMetaDatum {
144144
pages: PageMetaDatum[]
145145
}
146146

147+
export interface UserTabBarItem extends Partial<TabBarItem> {
148+
/**
149+
* 配置页面路径
150+
* @deprecated 可选,将会根据文件路径自动生成
151+
*/
152+
pagePath?: string
153+
154+
/**
155+
* 排序,数字越小越靠前
156+
*/
157+
index?: number
158+
}
159+
147160
export interface UserPageMeta extends Partial<PageMetaDatum> {
148161
/**
149162
* 配置页面路径
150163
* @deprecated 可选,将会根据文件路径自动生成
151164
*/
152165
path?: string
166+
167+
/**
168+
* 底部 tabBar 的子项 [tabBar](https://uniapp.dcloud.net.cn/collocation/pages#tabBar)
169+
*/
170+
tabBar?: UserTabBarItem
153171
}
154172

155173
export type MaybePromise<T> = T | Promise<T>

packages/playground/src/pages/define-page/object.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ definePage({
66
middlewares: [
77
'auth',
88
],
9-
tabbar: {},
9+
tabBar: {},
1010
});
1111
</script>
1212

test/generate.spec.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,7 @@ describe('generate routes', () => {
145145
},
146146
"middlewares": [
147147
"auth"
148-
],
149-
"tabbar": {}
148+
]
150149
},
151150
{
152151
"path": "../packages/playground/src/pages/define-page/option-api",
@@ -309,8 +308,7 @@ describe('generate routes', () => {
309308
},
310309
"middlewares": [
311310
"auth"
312-
],
313-
"tabbar": {}
311+
]
314312
},
315313
{
316314
"path": "../packages/playground/src/pages/define-page/option-api",

0 commit comments

Comments
 (0)