Skip to content

Commit ef2a223

Browse files
committed
feat: rework hooks system -d
1 parent 4d23949 commit ef2a223

File tree

28 files changed

+187
-306
lines changed

28 files changed

+187
-306
lines changed

@fiction/core/plugin-app/hooks.ts

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import '@fiction/core/plugin-env/hooks'
2+
import type { InlineConfig } from 'vite'
3+
import type { FictionAppEntry, ServiceList } from '../plugin-env'
4+
5+
declare module '@fiction/core/plugin-env/hooks' {
6+
interface FictionEnvHookDictionary {
7+
beforeAppMounted: { args: [FictionAppEntry] }
8+
appMounted: { args: [FictionAppEntry] }
9+
afterAppSetup: { args: [{ service: ServiceList }] }
10+
viteConfig: { args: [InlineConfig[]] }
11+
headTags: { args: [string, { pathname?: string }] }
12+
htmlBody: { args: [string, { pathname?: string }] }
13+
}
14+
}

@fiction/core/plugin-app/index.ts

+3-22
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import type * as vite from 'vite'
44
import type { Config as TailwindConfig } from 'tailwindcss'
55
import type { Express } from 'express'
66
import { createHead } from '@unhead/vue'
7-
import type { HookType } from '../utils'
87
import { initializeResetUi, isTest, runHooks, safeDirname, vue } from '../utils'
98
import type { FictionAppEntry, FictionEnv, ServiceConfig, ServiceList } from '../plugin-env'
109
import { FictionPlugin } from '../plugin'
@@ -16,17 +15,7 @@ import ElRoot from './ElRoot.vue'
1615
import type { FictionSitemap } from './sitemap'
1716
import type { SiteMapEntry } from './types'
1817

19-
type HookDictionary = {
20-
beforeAppMounted: { args: [FictionAppEntry] }
21-
appMounted: { args: [FictionAppEntry] }
22-
afterAppSetup: { args: [{ service: ServiceList }] }
23-
viteConfig: { args: [vite.InlineConfig[]] }
24-
headTags: { args: [string, { pathname?: string }] }
25-
htmlBody: { args: [string, { pathname?: string }] }
26-
}
27-
2818
export interface FictionAppSettings {
29-
hooks?: HookType<HookDictionary>[]
3019
mode?: 'production' | 'development'
3120
isTest?: boolean
3221
liveUrl?: string
@@ -119,10 +108,6 @@ export class FictionApp extends FictionPlugin<FictionAppSettings> {
119108
}
120109
}
121110

122-
public addHook(hook: HookType<HookDictionary>): void {
123-
this.hooks.push(hook)
124-
}
125-
126111
addSitemap(sitemap: SiteMapEntry) {
127112
this.sitemaps = [...this.sitemaps, sitemap]
128113
}
@@ -157,11 +142,7 @@ export class FictionApp extends FictionPlugin<FictionAppSettings> {
157142
if (renderRoute)
158143
await this.fictionRouter.replace({ path: renderRoute }, { caller: 'createVueApp' })
159144

160-
await runHooks<HookDictionary, 'afterAppSetup'>({
161-
list: this.hooks,
162-
hook: 'afterAppSetup',
163-
args: [{ service }],
164-
})
145+
await this.fictionEnv.runHooks('afterAppSetup', { service })
165146

166147
const app: vue.App = renderRoute
167148
? vue.createSSRApp(this.rootComponent)
@@ -197,7 +178,7 @@ export class FictionApp extends FictionPlugin<FictionAppSettings> {
197178
const entry = await this.createVueApp({ renderRoute, runVars, service })
198179

199180
if (typeof window !== 'undefined' && !this.fictionEnv.isSSR.value) {
200-
await runHooks({ list: this.hooks, hook: 'beforeAppMounted', args: [entry] })
181+
await this.fictionEnv.runHooks('beforeAppMounted', entry)
201182

202183
const mountEl = args.mountEl || document.querySelector(selector)
203184

@@ -212,7 +193,7 @@ export class FictionApp extends FictionPlugin<FictionAppSettings> {
212193
mountEl.classList.remove('loading')
213194
mountEl.classList.add('loaded')
214195

215-
await runHooks({ list: this.hooks, hook: 'appMounted', args: [entry] })
196+
await this.fictionEnv.runHooks('appMounted', entry)
216197
}
217198

218199
return entry

@fiction/core/plugin-app/plugin-render.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import type { Express, Request } from 'express'
1010
import unocss from 'unocss/vite'
1111
import presetIcons from '@unocss/preset-icons'
1212
import type tailwindcss from 'tailwindcss'
13-
import { createExpressApp, deepMergeAll, express, getRequire, importIfExists, isNode, requireIfExists, runHooks, safeDirname } from '../utils'
13+
import { createExpressApp, deepMergeAll, express, getRequire, importIfExists, isNode, requireIfExists, safeDirname } from '../utils'
1414
import type { FictionEnv } from '../plugin-env'
1515
import type { FictionRouter } from '../plugin-router'
1616
import { FictionBuild } from '../plugin-build'
@@ -210,7 +210,7 @@ export class FictionRender extends FictionPlugin<FictionRenderSettings> {
210210
appViteConfigFile || {},
211211
]
212212

213-
merge = await runHooks({ list: this.fictionApp.hooks, hook: 'viteConfig', args: [merge] })
213+
merge = await this.settings.fictionEnv.runHooks('viteConfig', merge)
214214

215215
const viteConfig = deepMergeAll(merge)
216216

@@ -235,8 +235,8 @@ export class FictionRender extends FictionPlugin<FictionRenderSettings> {
235235
if (!template)
236236
throw new Error('html template required')
237237

238-
headTags = await runHooks({ list: this.fictionApp.hooks, hook: 'headTags', args: [headTags, { pathname }] })
239-
htmlBody = await runHooks({ list: this.fictionApp.hooks, hook: 'htmlBody', args: [htmlBody, { pathname }] })
238+
headTags = await this.settings.fictionEnv.runHooks('headTags', headTags, { pathname })
239+
htmlBody = await this.settings.fictionEnv.runHooks('htmlBody', htmlBody, { pathname })
240240

241241
const debuggingInfo = `<!--${JSON.stringify({ renderedPathname: pathname, isProd })}-->`
242242

@fiction/core/plugin-db/hooks.ts

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import '@fiction/core/plugin-env/hooks'
2+
import type { FictionDbTable } from './objects'
3+
import type { FictionDb } from '.'
4+
5+
declare module '@fiction/core/plugin-env/hooks' {
6+
interface FictionEnvHookDictionary {
7+
dbOnConnected: { args: [FictionDb] }
8+
dbOnTables: { args: [FictionDbTable[]] }
9+
}
10+
}

@fiction/core/plugin-db/index.ts

+9-22
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ import type { Knex } from 'knex'
55
import knex from 'knex'
66
import knexStringcase from 'knex-stringcase'
77
import * as typebox from '@sinclair/typebox'
8-
import type { HookType } from '../utils'
9-
import { isActualBrowser, isTest, runHooks, safeDirname } from '../utils'
8+
import { isActualBrowser, isTest, safeDirname } from '../utils'
109
import type { FictionPluginSettings } from '../plugin'
1110
import { FictionPlugin } from '../plugin'
1211
import type { FictionEnv } from '../plugin-env'
@@ -24,14 +23,13 @@ vars.register(() => [
2423

2524
export type FictionDBTables = 'fiction_user' | 'fiction_post' | 'fiction_version'
2625

27-
export type FictionDbHookDictionary = {
28-
onStart: { args: [FictionDb] }
29-
tables: { args: [FictionDbTable[]] }
30-
}
26+
// export type FictionDbHookDictionary = {
27+
// onStart: { args: [FictionDb] }
28+
// tables: { args: [FictionDbTable[]] }
29+
// }
3130

3231
export type FictionDbSettings = {
3332
connectionUrl?: string
34-
hooks?: HookType<FictionDbHookDictionary>[]
3533
tables?: FictionDbTable[]
3634
fictionEnv?: FictionEnv
3735
fictionServer?: FictionServer // for DB utilities like username checking
@@ -40,7 +38,6 @@ export type FictionDbSettings = {
4038
export class FictionDb extends FictionPlugin<FictionDbSettings> {
4139
db?: Knex
4240
connectionUrl?: URL
43-
hooks: HookType<FictionDbHookDictionary>[]
4441
defaultConnectionUrl = 'http://test:test@localhost:5432/test'
4542
tables = this.settings.tables || []
4643
isInitialized = false
@@ -57,8 +54,6 @@ export class FictionDb extends FictionPlugin<FictionDbSettings> {
5754
constructor(settings: FictionDbSettings) {
5855
super('db', { root: safeDirname(import.meta.url), ...settings })
5956

60-
this.hooks = settings.hooks || []
61-
6257
if (isActualBrowser())
6358
return
6459

@@ -153,8 +148,8 @@ export class FictionDb extends FictionPlugin<FictionDbSettings> {
153148
tableKey: string,
154149
columns: FictionDbCol[] | readonly FictionDbCol[],
155150
) {
156-
this.hooks.push({
157-
hook: 'tables',
151+
this.settings.fictionEnv.hooks.push({
152+
hook: 'dbOnTables',
158153
callback: (tables: FictionDbTable[]) => {
159154
const tbl = tables.find(t => t.tableKey === tableKey)
160155

@@ -208,22 +203,14 @@ export class FictionDb extends FictionPlugin<FictionDbSettings> {
208203
await extendDb(db)
209204

210205
if (this.tables.length > 0) {
211-
const tables = await runHooks<FictionDbHookDictionary, 'tables'>({
212-
list: this.hooks,
213-
hook: 'tables',
214-
args: [this.tables],
215-
})
206+
const tables = await this.settings.fictionEnv.runHooks('dbOnTables', this.tables)
216207

217208
for (const table of tables)
218209
await table.create(db)
219210
}
220211

221212
this.log.info('extending db [done]')
222-
await runHooks<FictionDbHookDictionary>({
223-
list: this.hooks,
224-
hook: 'onStart',
225-
args: [this],
226-
})
213+
await this.settings.fictionEnv.runHooks('dbOnConnected', this)
227214

228215
const printUrl = this.connectionUrl.toString().replace(this.connectionUrl.password, '--password--')
229216
this.log.info('connected db [ready]', {

@fiction/core/plugin-env/generate.ts

+2-19
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ import fs from 'fs-extra'
33
import type { JSONSchema } from 'json-schema-to-typescript'
44
import { log } from '../plugin-log'
55
import { stringify } from '../utils/utils'
6-
import { runHooks } from '../utils/hook'
7-
import type { FictionEnvHookDictionary } from './types'
86
import type { FictionEnv } from '.'
97

108
export async function generateStaticConfig(fictionEnv: FictionEnv): Promise<void> {
@@ -23,15 +21,7 @@ export async function generateStaticConfig(fictionEnv: FictionEnv): Promise<void
2321
*/
2422
const title = 'CompiledServiceConfig'
2523

26-
const _staticSchemaProps = await runHooks<
27-
FictionEnvHookDictionary,
28-
'staticSchema'
29-
>({
30-
list: fictionEnv.hooks ?? [],
31-
hook: 'staticSchema',
32-
args: [{}],
33-
},
34-
)
24+
const _staticSchemaProps = await fictionEnv.runHooks('staticSchema', {})
3525

3626
const staticSchemaProps = _staticSchemaProps || {}
3727

@@ -59,14 +49,7 @@ export async function generateStaticConfig(fictionEnv: FictionEnv): Promise<void
5949

6050
const types = path.join(genConfigPath, 'config.ts')
6151

62-
/**
63-
* Handle config
64-
*/
65-
const staticConfig = await runHooks<FictionEnvHookDictionary, 'staticConfig'>({
66-
list: fictionEnv.hooks ?? [],
67-
hook: 'staticConfig',
68-
args: [{}],
69-
})
52+
const staticConfig = await fictionEnv.runHooks('staticConfig', {})
7053

7154
const stringed = stringify(staticConfig)
7255

@fiction/core/plugin-env/hooks.ts

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import type { JSONSchema } from 'json-schema-to-typescript'
2+
import type { CliOptions } from './types'
3+
4+
export interface FictionEnvHookDictionary {
5+
runCommand: {
6+
args: [string, CliOptions]
7+
}
8+
staticConfig: {
9+
args: [Record<string, unknown>]
10+
}
11+
staticSchema: {
12+
args: [JSONSchema['properties']]
13+
}
14+
}

@fiction/core/plugin-env/index.ts

+20-18
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,23 @@ import { camelToUpperSnake, getCrossVar, isApp, isDev, isNode, isTest, runHooks,
77
import { version as fictionVersion } from '../package.json'
88
import type { RunVars } from '../inject'
99
import { compileApplication } from './entry'
10-
import type * as types from './types'
10+
1111
import type { CliCommand } from './commands'
1212
import { standardAppCommands } from './commands'
1313
import { done } from './utils'
1414
import { generateStaticConfig } from './generate'
1515
import { commonServerOnlyModules } from './serverOnly'
1616
import { EnvVar, envConfig, vars } from './onImport'
17+
import type { CliOptions, CliVars, ServerModuleDef, ServiceConfig } from './types'
18+
import type { FictionEnvHookDictionary } from './hooks'
1719

1820
export { envConfig, vars, EnvVar }
1921
export * from './types'
2022
export * from './entry'
2123
export * from './commands'
2224

2325
export interface FictionControlSettings {
24-
hooks?: HookType<types.FictionEnvHookDictionary>[]
26+
hooks?: HookType<FictionEnvHookDictionary>[]
2527
envFiles?: string[]
2628
envFilesProd?: string[]
2729
env?: Record<string, string>
@@ -36,7 +38,7 @@ export interface FictionControlSettings {
3638
isApp?: boolean
3739
isTest?: boolean
3840
version?: string
39-
serverOnlyModules?: types.ServerModuleDef[]
41+
serverOnlyModules?: ServerModuleDef[]
4042
uiPaths?: string[]
4143
meta?: { version?: string, app?: { name?: string, email?: string, url?: string, domain?: string } }
4244
}
@@ -86,6 +88,14 @@ export class FictionEnv<
8688
// the services are then accessed via useService provide
8789
service = vue.shallowRef<{ runVars?: Partial<RunVars>, [key: string]: unknown }>({})
8890

91+
runHooks<T extends keyof FictionEnvHookDictionary>(hook: T, ...args: FictionEnvHookDictionary[T]['args']) {
92+
return runHooks<FictionEnvHookDictionary, T>({ list: this.hooks, hook, args })
93+
}
94+
95+
public addHook<T extends HookType<FictionEnvHookDictionary>>(hook: T): void {
96+
this.hooks.push(hook)
97+
}
98+
8999
constructor(settings: FictionControlSettings) {
90100
super('env', settings)
91101

@@ -147,7 +157,7 @@ export class FictionEnv<
147157
}
148158

149159
commandName = vue.ref(getCrossVar('COMMAND') || '')
150-
commandOpts = vue.ref(JSON.parse(getCrossVar('COMMAND_OPTS') || '{}') as types.CliOptions)
160+
commandOpts = vue.ref(JSON.parse(getCrossVar('COMMAND_OPTS') || '{}') as CliOptions)
151161

152162
currentCommand = vue.computed(() => {
153163
if (!this.commandName.value)
@@ -291,17 +301,13 @@ export class FictionEnv<
291301
await generateStaticConfig(this)
292302
}
293303

294-
public addHook(hook: HookType<types.FictionEnvHookDictionary>): void {
295-
this.hooks.push(hook)
296-
}
297-
298304
onCommand(
299305
commands: string[],
300-
callback: (command: string, options: types.CliOptions) => Promise<void>,
306+
callback: (command: string, options: CliOptions) => Promise<void>,
301307
): void {
302308
this.hooks.push({
303309
hook: 'runCommand',
304-
callback: async (command: string, opts: types.CliOptions) => {
310+
callback: async (command: string, opts: CliOptions) => {
305311
if (commands.includes(command))
306312
await callback(command, opts)
307313
},
@@ -314,8 +320,8 @@ export class FictionEnv<
314320
*/
315321
async crossRunCommand(args: {
316322
context: 'node' | 'app'
317-
serviceConfig: types.ServiceConfig
318-
cliVars?: Partial<types.CliVars>
323+
serviceConfig: ServiceConfig
324+
cliVars?: Partial<CliVars>
319325
runVars?: Partial<RunVars>
320326
}) {
321327
const { context, serviceConfig, cliVars, runVars } = args
@@ -326,17 +332,13 @@ export class FictionEnv<
326332

327333
const options = { command: cmd?.command, ...cmd?.options }
328334

329-
await runHooks<types.FictionEnvHookDictionary>({
330-
list: this.hooks,
331-
hook: 'runCommand',
332-
args: [options.command || 'not_set', options],
333-
})
335+
await runHooks({ list: this.hooks, hook: 'runCommand', args: [options.command || 'not_set', options] })
334336

335337
if (serviceConfig?.runCommand)
336338
await serviceConfig.runCommand({ context, command: options.command || 'not_set', options, cliVars, runVars })
337339
}
338340

339-
async serverRunCurrentCommand(args: { serviceConfig: types.ServiceConfig, cliVars: Partial<types.CliVars> }): Promise<void> {
341+
async serverRunCurrentCommand(args: { serviceConfig: ServiceConfig, cliVars: Partial<CliVars> }): Promise<void> {
340342
const { serviceConfig, cliVars } = args
341343

342344
const cliCommand = this.currentCommand.value

@fiction/core/plugin-env/types.ts

-13
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import type { MergeHead } from '@unhead/schema'
22
import type { VueHeadClient } from '@unhead/vue'
3-
import type { JSONSchema } from 'json-schema-to-typescript'
43
import type { Router } from 'vue-router'
54
import type { vue } from '../utils'
65
import type { PackageJson } from '../types'
@@ -10,18 +9,6 @@ import type { FictionEnv } from '../plugin-env'
109
import type { FictionObject, FictionPlugin } from '../plugin'
1110
import type { RunVars } from '../inject'
1211

13-
export type FictionEnvHookDictionary = {
14-
runCommand: {
15-
args: [string, CliOptions]
16-
}
17-
staticConfig: {
18-
args: [Record<string, unknown>]
19-
}
20-
staticSchema: {
21-
args: [JSONSchema['properties']]
22-
}
23-
}
24-
2512
export interface FictionAppEntry<T extends ServiceList = ServiceList> {
2613
app: vue.App
2714
router: Router

0 commit comments

Comments
 (0)