mirror of https://github.com/YunYouJun/valaxy
feat: use defineBasicLoader for vue-router data on demand load
This commit is contained in:
parent
b98cf26373
commit
3485803588
|
@ -32,6 +32,7 @@
|
|||
"cSpell.words": [
|
||||
"AGUI",
|
||||
"algoliasearch",
|
||||
"axios",
|
||||
"beian",
|
||||
"codepen",
|
||||
"defu",
|
||||
|
|
|
@ -52,6 +52,10 @@ export default defineConfig({
|
|||
sidebar: {
|
||||
'/typedoc/': typedocSidebar,
|
||||
'/notes': [
|
||||
{
|
||||
text: 'App Bundle Size',
|
||||
link: '/notes/app-bundle-size',
|
||||
},
|
||||
{
|
||||
text: 'Shiki 高亮耗时问题',
|
||||
link: '/notes/shiki-performance',
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
# 包体积优化
|
||||
|
||||
## Data Loaders (Vue Routers)
|
||||
|
||||
- [Data Loaders](https://uvr.esm.is/data-loaders/)
|
||||
|
||||
使用 Vue Router 的 [Data Loaders](https://uvr.esm.is/data-loaders/),按需加载对应文件的 `frontmatter`。(支持并行的数据获取)
|
||||
否则初始打包会合并在一个文件中。
|
||||
|
||||
```vue
|
||||
<script>
|
||||
import { defineBasicLoader } from 'unplugin-vue-router/data-loaders/basic'
|
||||
|
||||
export const usePageData = defineBasicLoader('/relativePath', async (_to) => {
|
||||
// custom basic loader
|
||||
}, {
|
||||
lazy: true,
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
```ts
|
||||
export function injectPageDataCode() {
|
||||
const vueContextImports = [
|
||||
`import { provide } from 'vue'`,
|
||||
`import { useRoute } from 'vue-router'`,
|
||||
|
||||
'const { data: pageData } = usePageData()',
|
||||
'const route = useRoute()',
|
||||
// $frontmatter contain runtime added data
|
||||
// for example, $frontmatter.partiallyEncryptedContents
|
||||
`const $frontmatter = Object.assign(route.meta.frontmatter || {}, pageData.frontmatter || {})
|
||||
route.meta.frontmatter = $frontmatter
|
||||
|
||||
provide('pageData', pageData)
|
||||
provide('valaxy:frontmatter', $frontmatter)
|
||||
`,
|
||||
]
|
||||
|
||||
return vueContextImports
|
||||
}
|
||||
|
||||
const loaderVuePath = path.resolve(options.pkgRoot, 'node/templates/loader.vue')
|
||||
let loaderVue = fs.readFileSync(loaderVuePath, 'utf-8')
|
||||
loaderVue = loaderVue
|
||||
.replace('/relativePath', pageData.relativePath.slice('/pages'.length - 1, -'.md'.length))
|
||||
.replace('// custom basic loader', `return ${transformObject(pageData)}`)
|
||||
code = loaderVue + code
|
||||
```
|
|
@ -90,6 +90,7 @@ declare module 'vue-router/auto-routes' {
|
|||
'/sponsors/': RouteRecordInfo<'/sponsors/', '/sponsors', Record<never, never>, Record<never, never>>,
|
||||
'/tags/': RouteRecordInfo<'/tags/', '/tags', Record<never, never>, Record<never, never>>,
|
||||
'/test/deadlinks': RouteRecordInfo<'/test/deadlinks', '/test/deadlinks', Record<never, never>, Record<never, never>>,
|
||||
'/test/define-basic-loader': RouteRecordInfo<'/test/define-basic-loader', '/test/define-basic-loader', Record<never, never>, Record<never, never>>,
|
||||
'/test/footnotes': RouteRecordInfo<'/test/footnotes', '/test/footnotes', Record<never, never>, Record<never, never>>,
|
||||
'/test/markdown-file-inclusion': RouteRecordInfo<'/test/markdown-file-inclusion', '/test/markdown-file-inclusion', Record<never, never>, Record<never, never>>,
|
||||
'/test/special-character': RouteRecordInfo<'/test/special-character', '/test/special-character', Record<never, never>, Record<never, never>>,
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
<script setup lang="ts">
|
||||
// @ts-expect-error not work
|
||||
const pageData = usePageData()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
PageData: {{ pageData }}
|
||||
</div>
|
||||
</template>
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
title: Define Basic Loader
|
||||
---
|
||||
|
||||
[Defining Data Loaders](https://uvr.esm.is/data-loaders/defining-loaders.html#defining-data-loaders)
|
||||
|
||||
<!-- not work -->
|
||||
<!-- <DefineBasicLoaderVue /> -->
|
|
@ -4,7 +4,7 @@ import axios from 'axios'
|
|||
|
||||
import consola from 'consola'
|
||||
import { ref, toRaw } from 'vue'
|
||||
import { pageData } from '../composables/app'
|
||||
import { activePath, pageData } from '../composables/app'
|
||||
|
||||
const props = defineProps<{
|
||||
frontmatter: PostFrontMatter
|
||||
|
@ -18,6 +18,7 @@ async function saveNewFm() {
|
|||
// })
|
||||
|
||||
const res = await axios.post('/valaxy-devtools-api/frontmatter', {
|
||||
path: activePath.value,
|
||||
pageData: pageData.value,
|
||||
frontmatter: toRaw(newFm.value),
|
||||
})
|
||||
|
|
|
@ -53,7 +53,7 @@ onMounted(async () => {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div id="yun-banner" :style="bannerStyles">
|
||||
<div id="yun-banner" border="b-1px b-solid b-$banner-line-color" :style="bannerStyles">
|
||||
<div class="banner-line-container">
|
||||
<div
|
||||
class="banner-line vertical-line-top"
|
||||
|
|
|
@ -1,26 +1,27 @@
|
|||
import type { ViteSSGContext } from 'vite-ssg'
|
||||
import { DataLoaderPlugin } from 'unplugin-vue-router/data-loaders'
|
||||
import { initValaxyConfig, valaxyConfigSymbol } from 'valaxy'
|
||||
import { setupLayouts } from 'virtual:generated-layouts'
|
||||
import { ViteSSG } from 'vite-ssg'
|
||||
import { routes } from 'vue-router/auto-routes'
|
||||
|
||||
import { routes } from 'vue-router/auto-routes'
|
||||
// import App from '/@valaxyjs/App.vue'
|
||||
import App from './App.vue'
|
||||
|
||||
import AppLink from './components/AppLink.vue'
|
||||
|
||||
import setupMain from './setup/main'
|
||||
import { setupValaxyDevTools } from './utils/dev'
|
||||
|
||||
import { setupValaxyDevTools } from './utils/dev'
|
||||
// reset styles, load css before app
|
||||
// import '@unocss/reset/tailwind.css'
|
||||
// https://unocss.dev/guide/style-reset#tailwind-compat
|
||||
// minus the background color override for buttons to avoid conflicts with UI frameworks
|
||||
import '@unocss/reset/tailwind-compat.css'
|
||||
|
||||
// css
|
||||
import './styles/css/css-vars.css'
|
||||
|
||||
import './styles/css/main.css'
|
||||
|
||||
// generate user styles
|
||||
import '/@valaxyjs/styles'
|
||||
import 'uno.css'
|
||||
|
@ -78,7 +79,10 @@ export const createApp = ViteSSG(
|
|||
},
|
||||
(ctx) => {
|
||||
// app-level provide
|
||||
const { app } = ctx
|
||||
const { app, router } = ctx
|
||||
|
||||
// Register the plugin before the router
|
||||
app.use(DataLoaderPlugin, { router })
|
||||
|
||||
app.provide(valaxyConfigSymbol, valaxyConfig)
|
||||
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
import type { PageData } from 'valaxy/types'
|
||||
import type { ResolvedValaxyOptions } from '../../../options'
|
||||
import path from 'node:path'
|
||||
import fs from 'fs-extra'
|
||||
import { transformObject } from '../../../utils'
|
||||
import { getValaxyMain } from '../../markdown/markdownToVue'
|
||||
|
||||
export function injectPageDataCode(
|
||||
data: PageData,
|
||||
) {
|
||||
export function injectPageDataCode() {
|
||||
const vueContextImports = [
|
||||
`import { provide } from 'vue'`,
|
||||
`import { useRoute } from 'vue-router'`,
|
||||
`
|
||||
const data = ${transformObject(data)}
|
||||
const route = useRoute()`,
|
||||
|
||||
'const { data: pageData } = usePageData()',
|
||||
'const route = useRoute()',
|
||||
// $frontmatter contain runtime added data
|
||||
// for example, $frontmatter.partiallyEncryptedContents
|
||||
`const $frontmatter = data.frontmatter || {}
|
||||
route.meta.frontmatter = Object.assign(route.meta.frontmatter || {}, data.frontmatter || {})
|
||||
provide('pageData', data)
|
||||
`const $frontmatter = Object.assign(route.meta.frontmatter || {}, pageData.frontmatter || {})
|
||||
route.meta.frontmatter = $frontmatter
|
||||
|
||||
provide('pageData', pageData)
|
||||
provide('valaxy:frontmatter', $frontmatter)
|
||||
`,
|
||||
]
|
||||
|
@ -27,21 +27,24 @@ export function injectPageDataCode(
|
|||
|
||||
export function createTransformMarkdown(options: ResolvedValaxyOptions) {
|
||||
return (code: string, id: string, pageData: PageData) => {
|
||||
const dataCode = injectPageDataCode(pageData)
|
||||
const isDev = options.mode === 'dev'
|
||||
if (!isDev) {
|
||||
// do not build path in production
|
||||
delete pageData.filePath
|
||||
}
|
||||
const dataCode = injectPageDataCode()
|
||||
const imports = [
|
||||
...dataCode,
|
||||
isDev
|
||||
? `
|
||||
window.$pageData = data
|
||||
`
|
||||
: '',
|
||||
isDev ? `globalThis.$pageData = pageData` : '',
|
||||
'globalThis.$frontmatter = $frontmatter',
|
||||
]
|
||||
|
||||
// const loaderVuePath = path.resolve(options.pkgRoot, 'node/templates/loader.vue')
|
||||
// const loaderVue = fs.readFileSync(loaderVuePath)
|
||||
// code = loaderVue + code
|
||||
const loaderVuePath = path.resolve(options.pkgRoot, 'node/templates/loader.vue')
|
||||
let loaderVue = fs.readFileSync(loaderVuePath, 'utf-8')
|
||||
loaderVue = loaderVue
|
||||
.replace('/relativePath', pageData.relativePath.slice('/pages'.length - 1, -'.md'.length))
|
||||
.replace('// custom basic loader', `return ${transformObject(pageData)}`)
|
||||
code = loaderVue + code
|
||||
|
||||
// inject imports to <script setup>
|
||||
const scriptSetupStart = code.indexOf('<script setup>')
|
||||
|
|
|
@ -38,7 +38,7 @@ export async function generatePageData(code: string, id: string, options: Resolv
|
|||
// not be used
|
||||
headers: options.env.headers || [],
|
||||
relativePath,
|
||||
path: id,
|
||||
filePath: id,
|
||||
}
|
||||
|
||||
// if (includeLastUpdatedData)
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
<script lang="ts">
|
||||
// import { defineBasicLoader } from 'unplugin-vue-router/data-loaders/basic'
|
||||
<script>
|
||||
import { defineBasicLoader } from 'unplugin-vue-router/data-loaders/basic'
|
||||
|
||||
// export const useUserData = defineBasicLoader('/users/[id]', async (to) => {
|
||||
// // return getUserById(to.params.id)
|
||||
// })
|
||||
export const usePageData = defineBasicLoader('/relativePath', async (_to) => {
|
||||
// custom basic loader
|
||||
}, {
|
||||
// @see https://uvr.esm.is/data-loaders/defining-loaders.html#non-blocking-loaders-with-lazy
|
||||
lazy: (to, from) => to.name === from.name,
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -7,8 +7,12 @@ export type CleanUrlsMode =
|
|||
| 'with-subfolders'
|
||||
|
||||
export interface PageData {
|
||||
path: string
|
||||
relativePath: string
|
||||
/**
|
||||
* differs from relativePath in case of path rewrites
|
||||
* absolute file path
|
||||
*/
|
||||
filePath?: string
|
||||
title: string
|
||||
titleTemplate?: string
|
||||
description: string
|
||||
|
|
Loading…
Reference in New Issue