Skip to content

Commit

Permalink
feat: support definePage macro
Browse files Browse the repository at this point in the history
  • Loading branch information
edwinhuish committed Mar 22, 2024
1 parent 71f60a2 commit db9b6b9
Show file tree
Hide file tree
Showing 24 changed files with 892 additions and 224 deletions.
26 changes: 25 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,31 @@ export default defineUniPages({

现在所有的 page 都会被自动发现!

### SFC 自定义块用于路由数据
### 页面调用方式(1): `definePage` 宏定义路由数据
```html
<!-- index.vue -->
<script setup>
// 参数为对象
definePage({
type: 'home',
style: { navigationBarTitleText: 'index page' }
})
</script>

<!-- other.vue -->
<script setup>
// 参数为函数
// 注意:暂未支持外部 import
definePage(() => {
const hello = ['hello', 'world']
return {
style: { navigationBarTitleText: hello.join(' ') }
}
})
</script>
```

### 页面调用方式(2):SFC 自定义块用于路由数据

通过添加一个 `<route>` 块到 SFC 中来添加路由元数据。这将会在路由生成后直接添加到路由中,并且会覆盖。

Expand Down
26 changes: 25 additions & 1 deletion packages/core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,31 @@ export default defineUniPages({

Now all pages will be found automatically!

### SFC custom block for Route Data
### Page usage (1): `definePage` macro define page options
```html
<!-- index.vue -->
<script setup>
// object argument
definePage({
type: 'home',
style: { navigationBarTitleText: 'index page' }
})
</script>

<!-- other.vue -->
<script setup>
// function argument
// Note: import is not supported yet
definePage(() => {
const hello = ['hello', 'world']
return {
style: { navigationBarTitleText: hello.join(' ') }
}
})
</script>
```

### Page usage (2): SFC custom block for Route Data

Add route meta to the route by adding a `<route>` block to the SFC. This will be
directly added to the route after it is generated, and will override it.
Expand Down
4 changes: 4 additions & 0 deletions packages/core/client.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@ declare module 'virtual:uni-pages' {
export const pages: import('.').PageMetaDatum[]
export const subPackages: import('.').SubPackage[]
}

declare module globalThis {
export const definePage: import('.').DefinePage
}
9 changes: 9 additions & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,28 @@
"stub": "unbuild --stub"
},
"dependencies": {
"@babel/core": "^7.24.3",
"@babel/generator": "^7.24.1",
"@babel/traverse": "^7.24.1",
"@babel/types": "^7.24.0",
"@uni-helper/uni-env": "^0.1.1",
"@vue/compiler-sfc": "^3.4.21",
"ast-kit": "^0.12.1",
"chokidar": "^3.6.0",
"debug": "^4.3.4",
"fast-glob": "^3.3.2",
"json5": "^2.2.3",
"lodash-unified": "^1.0.3",
"magic-string": "^0.30.8",
"tsx": "^4.7.1",
"unconfig": "^0.3.11",
"yaml": "^2.4.0"
},
"devDependencies": {
"@antfu/utils": "^0.7.7",
"@types/babel__core": "^7.20.5",
"@types/babel__generator": "^7.6.8",
"@types/babel__traverse": "^7.20.5",
"@types/debug": "^4.1.12",
"@types/node": "^20.11.24"
}
Expand Down
18 changes: 18 additions & 0 deletions packages/core/src/child-process.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { SpawnOptionsWithoutStdio } from 'node:child_process'
import { spawn } from 'node:child_process'
import process from 'node:process'

export function runProcess(command: string, args: string[] = [], options?: SpawnOptionsWithoutStdio) {
return new Promise<string>((resolve, reject) => {
const child = spawn(command, args, {
env: {
...process.env,
},
...options,
})
const output = [] as string[]
child.stdout.on('data', chunk => output.push(chunk))
child.on('close', () => resolve(output.join('').trim()))
child.on('error', error => reject(error))
})
}
2 changes: 2 additions & 0 deletions packages/core/src/constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ export const RESOLVED_MODULE_ID_VIRTUAL = `\0${MODULE_ID_VIRTUAL}`
export const OUTPUT_NAME = 'pages.json'

export const FILE_EXTENSIONS = ['vue', 'nvue', 'uvue']

export const DEFINE_PAGE = 'definePage'
93 changes: 56 additions & 37 deletions packages/core/src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,32 @@ import path from 'node:path'
import process from 'node:process'
import type { FSWatcher } from 'chokidar'
import type { Logger, ViteDevServer } from 'vite'
import { normalizePath } from 'vite'
import { loadConfig } from 'unconfig'
import { slash } from '@antfu/utils'
import dbg from 'debug'
import { platform } from '@uni-helper/uni-env'
import type { PagesConfig } from './config/types'
import type { PageMetaDatum, PagePath, ResolvedOptions, SubPageMetaDatum, UserOptions } from './types'
import { writeDeclaration } from './declaration'

import {
debug,
invalidatePagesModule,
isTargetFile,
mergePageMetaDataArray,
useCachedPages,
} from './utils'
import { resolveOptions } from './options'
import { checkPagesJsonFile, getPageFiles, writeFileSync } from './files'
import { getRouteBlock, getRouteSfcBlock } from './customBlock'
import { OUTPUT_NAME } from './constant'
import { Page } from './page'

let lsatPagesJson = ''

const { setCache, hasChanged } = useCachedPages()
export class PageContext {
private _server: ViteDevServer | undefined

pagesGlobConfig: PagesConfig | undefined
pagesConfigSourcePaths: string[] = []

pagesPath: PagePath[] = []
subPagesPath: Record<string, PagePath[]> = {}
pageMetaData: PageMetaDatum[] = []
subPageMetaData: SubPageMetaDatum[] = []

Expand All @@ -46,6 +40,9 @@ export class PageContext {

withUniPlatform = false

pages = new Map<string, Page>()
subPages = new Map<string, Map<string, Page>>()

constructor(userOptions: UserOptions, viteRoot: string = process.cwd()) {
this.rawOptions = userOptions
this.root = slash(viteRoot)
Expand Down Expand Up @@ -79,18 +76,34 @@ export class PageContext {
return { dir, files: getPagePaths(dir, this.options) }
})

this.pagesPath = pageDirFiles.map(page => page.files).flat()
debug.pages(this.pagesPath)
const paths = pageDirFiles.map(page => page.files).flat()
debug.pages(paths)

const pages: [string, Page][] = paths.map((path) => {
const page = this.pages.get(path.absolutePath) || new Page(this, path)
return [path.absolutePath, page]
})

this.pages = new Map(pages)
}

async scanSubPages() {
const subPagesPath: Record<string, PagePath[]> = {}
const paths: Record<string, PagePath[]> = {}
const subPages = new Map<string, Map<string, Page>>()
for (const dir of this.options.subPackages) {
const pagePaths = getPagePaths(dir, this.options)
subPagesPath[dir] = pagePaths
paths[dir] = pagePaths

const pages: [string, Page][] = pagePaths.map((path) => {
const page = this.subPages.get(dir)?.get(path.absolutePath) || new Page(this, path)
return [path.absolutePath, page]
})

subPages.set(dir, new Map(pages))
}
this.subPagesPath = subPagesPath
debug.subPages(this.subPagesPath)
debug.subPages(JSON.stringify(paths, null, 2))

this.subPages = subPages
}

setupViteServer(server: ViteDevServer) {
Expand Down Expand Up @@ -167,32 +180,20 @@ export class PageContext {
})
}

async parsePage(page: PagePath): Promise<PageMetaDatum> {
const { relativePath, absolutePath } = page
const routeSfcBlock = await getRouteSfcBlock(absolutePath)
const routeBlock = await getRouteBlock(absolutePath, routeSfcBlock, this.options)
setCache(absolutePath, routeSfcBlock)
const relativePathWithFileName = relativePath.replace(path.extname(relativePath), '')
const pageMetaDatum: PageMetaDatum = {
path: normalizePath(relativePathWithFileName),
type: routeBlock?.attr.type ?? 'page',
}

if (routeBlock)
Object.assign(pageMetaDatum, routeBlock.content)

return pageMetaDatum
}

/**
* parse pages rules && set page type
* @param pages page path array
* @param type page type
* @param overrides custom page config
* @returns pages rules
*/
async parsePages(pages: PagePath[], type: 'main' | 'sub', overrides?: PageMetaDatum[]) {
const generatedPageMetaData = await Promise.all(pages.map(async page => await this.parsePage(page)))
async parsePages(pages: Map<string, Page>, type: 'main' | 'sub', overrides?: PageMetaDatum[]) {
const generatedPageMetaData: PageMetaDatum[] = []
for (const [_, page] of pages) {
const opt = await page.getOptions()
generatedPageMetaData.push(opt)
}

const customPageMetaData = overrides || []

const result = customPageMetaData.length
Expand Down Expand Up @@ -231,7 +232,7 @@ export class PageContext {
}

async mergePageMetaData() {
const pageMetaData = await this.parsePages(this.pagesPath, 'main', this.pagesGlobConfig?.pages)
const pageMetaData = await this.parsePages(this.pages, 'main', this.pagesGlobConfig?.pages)
this.pageMetaData = pageMetaData
debug.pages(this.pageMetaData)
}
Expand All @@ -240,7 +241,7 @@ export class PageContext {
const subPageMaps: Record<string, PageMetaDatum[]> = {}
const subPackages = this.pagesGlobConfig?.subPackages || []

for (const [dir, pages] of Object.entries(this.subPagesPath)) {
for (const [dir, pages] of this.subPages) {
const root = path.basename(dir)

const globPackage = subPackages?.find(v => v.root === root)
Expand All @@ -260,9 +261,24 @@ export class PageContext {
debug.subPages(this.subPageMetaData)
}

private getPageByPath(absolutePath: string) {
const page = this.pages.get(absolutePath)
if (page)
return page

for (const [_, pages] of this.subPages) {
const subPage = pages.get(absolutePath)
if (subPage)
return subPage
}

return undefined
}

async updatePagesJSON(filepath?: string) {
if (filepath) {
if (!await hasChanged(filepath)) {
const page = this.getPageByPath(filepath)
if (page && !await page.hasChanged()) {
debug.cache(`The route block on page ${filepath} did not send any changes, skipping`)
return false
}
Expand Down Expand Up @@ -311,6 +327,8 @@ export class PageContext {
lsatPagesJson = pagesJson

this.options.onAfterWriteFile(this)

debug.pages('updatePagesJSON DONE.')
return true
}

Expand All @@ -328,12 +346,13 @@ export class PageContext {
return JSON.stringify(this.subPageMetaData, null, 2)
}

generateDeclaration() {
async generateDeclaration() {
if (!this.options.dts)
return

debug.declaration('generating')
return writeDeclaration(this, this.options.dts)
await writeDeclaration(this, this.options.dts)
debug.declaration('done.')
}
}

Expand Down
Loading

0 comments on commit db9b6b9

Please # to comment.