feat: add hookable for lifecycle

This commit is contained in:
YunYouJun 2023-10-22 00:32:12 +08:00
parent 42ea60aaca
commit c285d80795
15 changed files with 173 additions and 3 deletions

View File

@ -8,6 +8,7 @@ import { addonAlgolia } from 'valaxy-addon-algolia'
import { addonWaline } from 'valaxy-addon-waline'
import { addonComponents } from 'valaxy-addon-components'
import { addonLightGallery } from 'valaxy-addon-lightgallery'
import { addonTest } from 'valaxy-addon-test'
const safelist = [
'i-ri-home-line',
@ -113,5 +114,6 @@ export default defineValaxyConfig<ThemeConfig>({
// addonTwikoo({
// envId: 'https://twikoo.vercel.app',
// }),
addonTest(),
],
})

View File

@ -0,0 +1,47 @@
---
title: Hooks
title_zh-CN: 钩子
categories:
- custom
end: false
---
::: tip
Valaxy 提供了钩子系统,以便你可以对生命周期的各个阶段进行定制。
:::
## Lifecycle {lang="en"}
## 生命周期 {lang="zh-CN"}
> 钩子的生命周期以排列顺序执行。
### Build Time
| Hook | Arguments | Description |
| ---- | --------- | ----------- |
| `options:resolved` | | 在 Valaxy 配置解析之后执行。|
| `config:init` | | 在 Vite 配置初始化(根据 Valaxy Options 进行初始化)之后执行。|
| `build:before` | | 在构建开始之前执行。|
| `build:done` | | 在构建完成之后执行。 |
```ts
// valaxy.config.ts
import { defineValaxyConfig } from 'valaxy'
export default defineValaxyConfig({
hooks: {
'config:init': () => {
console.log('config:init')
},
}
})
```
### App Client
| Hook | Arguments | Description |
| ---- | --------- | ----------- |
<!-- | `app:created` | | 在应用程序实例创建之后执行。| -->

View File

@ -80,6 +80,7 @@
"valaxy-addon-algolia": "workspace:*",
"valaxy-addon-components": "workspace:*",
"valaxy-addon-lightgallery": "workspace:*",
"valaxy-addon-test": "workspace:*",
"valaxy-addon-twikoo": "workspace:*",
"valaxy-addon-waline": "workspace:*",
"valaxy-theme-press": "workspace:*",

View File

@ -0,0 +1,3 @@
# valaxy-addon-test
This is a test addon for Valaxy.

View File

@ -0,0 +1 @@
export * from './node'

View File

@ -0,0 +1,15 @@
import { defineValaxyAddon } from 'valaxy'
import consola from 'consola'
import pkg from '../package.json'
export const addonTest = defineValaxyAddon(options => ({
name: pkg.name,
enable: true,
options,
setup(valaxy) {
valaxy.hook('build:before', () => {
consola.log('build:before')
})
},
}))

View File

@ -0,0 +1,5 @@
{
"name": "valaxy-addon-test",
"version": "0.0.0",
"private": true
}

View File

@ -0,0 +1,49 @@
import { createHooks } from 'hookable'
import type { ResolvedValaxyOptions } from '..'
import { version } from '../../package.json'
import type { ValaxyHooks, ValaxyNode } from '../types'
const buildHooks: (keyof ValaxyHooks)[] = [
'build:before',
'build:after',
]
/**
* Valaxy Node Instance
* @param options
*/
export function createValaxyNode(options: ResolvedValaxyOptions) {
const hooks = createHooks<ValaxyHooks>()
if (typeof options.config.hooks === 'object') {
Object.keys(options.config.hooks).forEach((name) => {
const hookName = name as keyof ValaxyHooks
const hook = options.config.hooks![hookName]
if (typeof hook !== 'function')
return
if (buildHooks.includes(hookName)) {
if (options.mode === 'build')
hooks.hook(hookName, hook)
}
else {
hooks.hook(hookName, hook)
}
})
}
const valaxyNode: ValaxyNode = {
version,
hooks,
hook: hooks.hook,
}
options.addons.forEach((addon) => {
if (typeof addon.setup === 'function')
addon.setup(valaxyNode)
})
return valaxyNode
}

View File

@ -28,6 +28,7 @@ import { registerNewCommand } from './cli/new'
import { setEnv, setEnvProd } from './utils/env'
import { commonOptions } from './cli/options'
import { createValaxyNode } from './app'
export const cli = yargs(hideBin(process.argv)).scriptName('valaxy')
.usage('$0 [args]')
@ -75,6 +76,8 @@ cli.command(
const port = userPort || await findFreePort(4859)
const options = await resolveOptions({ userRoot: root })
createValaxyNode(options)
const viteConfig: InlineConfig = mergeConfig({
// avoid load userRoot/vite.config.ts repeatedly
configFile: path.resolve(options.clientRoot, 'vite.config.ts'),
@ -171,6 +174,10 @@ cli.command(
const options = await resolveOptions({ userRoot: root }, 'build')
printInfo(options)
const valaxyApp = createValaxyNode(options)
// resolve options and create valaxy app
valaxyApp.hooks.callHook('options:resolved')
const valaxyViteConfig: InlineConfig = mergeConfig(await mergeViteConfigs(options, 'build'), options.config.vite || {})
const viteConfig: InlineConfig = mergeConfig(
valaxyViteConfig,
@ -185,6 +192,8 @@ cli.command(
logLevel: log as LogLevel,
},
)
// init config
valaxyApp.hooks.callHook('config:init')
// merge index.html
const templatePath = path.resolve(options.clientRoot, 'template.html')
@ -194,6 +203,9 @@ cli.command(
const indexHtml = await getIndexHtml(options)
await fs.writeFile(indexPath, indexHtml, 'utf-8')
// before build
valaxyApp.hooks.callHook('build:before')
try {
if (ssg) {
consola.info(`use ${yellow('vite-ssg')} to do ssg build...`)
@ -220,6 +232,9 @@ cli.command(
finally {
// await fs.unlink(indexPath)
await fs.copyFile(templatePath, indexPath)
// after build
valaxyApp.hooks.callHook('build:after')
}
},
)

View File

@ -1,9 +1,11 @@
import type { DefaultTheme, ValaxyAddon } from '../../types'
import type { ResolvedValaxyOptions } from '../options'
import type { ValaxyNodeConfig } from '../types'
import type { ValaxyAddonResolver, ValaxyNodeConfig } from '../types'
export function defineValaxyAddon<AddonOptions = object>(
addonFunc: (addonOptions?: AddonOptions, valaxyOptions?: ResolvedValaxyOptions) => ValaxyAddon,
addonFunc: (addonOptions?: AddonOptions, valaxyOptions?: ResolvedValaxyOptions) => ValaxyAddon & {
setup?: ValaxyAddonResolver['setup']
},
) {
return addonFunc
}

View File

@ -4,6 +4,7 @@ import type { VitePluginConfig as UnoCSSConfig } from 'unocss/vite'
import type Pages from 'vite-plugin-pages'
import type { UserConfig as ViteUserConfig } from 'vite'
import type { presetAttributify, presetIcons, presetTypography, presetUno } from 'unocss'
import type { Hookable } from 'hookable'
import type { DefaultTheme, PartialDeep, ValaxyAddon, ValaxyConfig } from '../types'
import type { ResolvedValaxyOptions } from './options'
import type { MarkdownOptions } from './markdown/types'
@ -16,6 +17,22 @@ export type UserValaxyNodeConfig<ThemeConfig = DefaultTheme.Config> = PartialDee
export type ValaxyConfigFn<ThemeConfig = DefaultTheme.Config> = (options: ResolvedValaxyOptions<ThemeConfig>) => ValaxyNodeConfig | Promise<ValaxyNodeConfig>
export type ValaxyConfigExport<ThemeConfig = DefaultTheme.Config> = ValaxyNodeConfig<ThemeConfig> | ValaxyConfigFn<ThemeConfig>
export type HookResult = Promise<void> | void
export interface ValaxyHooks {
'options:resolved': () => HookResult
'config:init': () => HookResult
'build:before': () => HookResult
'build:after': () => HookResult
}
export interface ValaxyNode {
version: string
hooks: Hookable<ValaxyHooks>
hook: ValaxyNode['hooks']['hook']
}
export interface ValaxyExtendConfig {
/**
* Markdown Feature
@ -57,6 +74,8 @@ export interface ValaxyExtendConfig {
path: string
}) => void
addons?: ValaxyAddons
hooks?: Partial<ValaxyHooks>
}
export type ValaxyAddonLike = ValaxyAddon | false | null | undefined
@ -74,4 +93,6 @@ export interface ValaxyAddonResolver {
options: Record<string, any>
configFile?: string
pkg: Record<string, any>
setup?: (node: ValaxyNode) => void
}

View File

@ -84,6 +84,7 @@
"fuse.js": "^6.6.2",
"global-dirs": "^3.0.1",
"gray-matter": "^4.0.3",
"hookable": "^5.5.3",
"html-to-text": "^9.0.5",
"is-installed-globally": "^0.4.0",
"jiti": "^1.20.0",

View File

@ -1,3 +1,4 @@
// for client
export interface ValaxyAddon<AddonOptions = Record<string, any>> {
name: string
/**

View File

@ -1,5 +1,4 @@
// do not export node type here
export * from './addon'
export * from './config'
export * from './data'

View File

@ -104,6 +104,9 @@ importers:
valaxy-addon-lightgallery:
specifier: workspace:*
version: link:packages/valaxy-addon-lightgallery
valaxy-addon-test:
specifier: workspace:*
version: link:packages/valaxy-addon-test
valaxy-addon-twikoo:
specifier: workspace:*
version: link:packages/valaxy-addon-twikoo
@ -286,6 +289,9 @@ importers:
gray-matter:
specifier: ^4.0.3
version: 4.0.3
hookable:
specifier: ^5.5.3
version: 5.5.3
html-to-text:
specifier: ^9.0.5
version: 9.0.5
@ -479,6 +485,8 @@ importers:
specifier: ^2.7.2
version: 2.7.2
packages/valaxy-addon-test: {}
packages/valaxy-addon-twikoo:
dependencies:
valaxy: