Skip to content

Commit

Permalink
feat: rework hooks system -d
Browse files Browse the repository at this point in the history
  • Loading branch information
arpowers committed Apr 11, 2024
1 parent 4d23949 commit ef2a223
Show file tree
Hide file tree
Showing 28 changed files with 187 additions and 306 deletions.
14 changes: 14 additions & 0 deletions @fiction/core/plugin-app/hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import '@fiction/core/plugin-env/hooks'
import type { InlineConfig } from 'vite'
import type { FictionAppEntry, ServiceList } from '../plugin-env'

declare module '@fiction/core/plugin-env/hooks' {
interface FictionEnvHookDictionary {
beforeAppMounted: { args: [FictionAppEntry] }
appMounted: { args: [FictionAppEntry] }
afterAppSetup: { args: [{ service: ServiceList }] }
viteConfig: { args: [InlineConfig[]] }
headTags: { args: [string, { pathname?: string }] }
htmlBody: { args: [string, { pathname?: string }] }
}
}
25 changes: 3 additions & 22 deletions @fiction/core/plugin-app/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import type * as vite from 'vite'
import type { Config as TailwindConfig } from 'tailwindcss'
import type { Express } from 'express'
import { createHead } from '@unhead/vue'
import type { HookType } from '../utils'
import { initializeResetUi, isTest, runHooks, safeDirname, vue } from '../utils'
import type { FictionAppEntry, FictionEnv, ServiceConfig, ServiceList } from '../plugin-env'
import { FictionPlugin } from '../plugin'
Expand All @@ -16,17 +15,7 @@ import ElRoot from './ElRoot.vue'
import type { FictionSitemap } from './sitemap'
import type { SiteMapEntry } from './types'

type HookDictionary = {
beforeAppMounted: { args: [FictionAppEntry] }
appMounted: { args: [FictionAppEntry] }
afterAppSetup: { args: [{ service: ServiceList }] }
viteConfig: { args: [vite.InlineConfig[]] }
headTags: { args: [string, { pathname?: string }] }
htmlBody: { args: [string, { pathname?: string }] }
}

export interface FictionAppSettings {
hooks?: HookType<HookDictionary>[]
mode?: 'production' | 'development'
isTest?: boolean
liveUrl?: string
Expand Down Expand Up @@ -119,10 +108,6 @@ export class FictionApp extends FictionPlugin<FictionAppSettings> {
}
}

public addHook(hook: HookType<HookDictionary>): void {
this.hooks.push(hook)
}

addSitemap(sitemap: SiteMapEntry) {
this.sitemaps = [...this.sitemaps, sitemap]
}
Expand Down Expand Up @@ -157,11 +142,7 @@ export class FictionApp extends FictionPlugin<FictionAppSettings> {
if (renderRoute)
await this.fictionRouter.replace({ path: renderRoute }, { caller: 'createVueApp' })

await runHooks<HookDictionary, 'afterAppSetup'>({
list: this.hooks,
hook: 'afterAppSetup',
args: [{ service }],
})
await this.fictionEnv.runHooks('afterAppSetup', { service })

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

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

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

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

await runHooks({ list: this.hooks, hook: 'appMounted', args: [entry] })
await this.fictionEnv.runHooks('appMounted', entry)
}

return entry
Expand Down
8 changes: 4 additions & 4 deletions @fiction/core/plugin-app/plugin-render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type { Express, Request } from 'express'
import unocss from 'unocss/vite'
import presetIcons from '@unocss/preset-icons'
import type tailwindcss from 'tailwindcss'
import { createExpressApp, deepMergeAll, express, getRequire, importIfExists, isNode, requireIfExists, runHooks, safeDirname } from '../utils'
import { createExpressApp, deepMergeAll, express, getRequire, importIfExists, isNode, requireIfExists, safeDirname } from '../utils'
import type { FictionEnv } from '../plugin-env'
import type { FictionRouter } from '../plugin-router'
import { FictionBuild } from '../plugin-build'
Expand Down Expand Up @@ -210,7 +210,7 @@ export class FictionRender extends FictionPlugin<FictionRenderSettings> {
appViteConfigFile || {},
]

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

const viteConfig = deepMergeAll(merge)

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

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

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

Expand Down
10 changes: 10 additions & 0 deletions @fiction/core/plugin-db/hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import '@fiction/core/plugin-env/hooks'
import type { FictionDbTable } from './objects'
import type { FictionDb } from '.'

declare module '@fiction/core/plugin-env/hooks' {
interface FictionEnvHookDictionary {
dbOnConnected: { args: [FictionDb] }
dbOnTables: { args: [FictionDbTable[]] }
}
}
31 changes: 9 additions & 22 deletions @fiction/core/plugin-db/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import type { Knex } from 'knex'
import knex from 'knex'
import knexStringcase from 'knex-stringcase'
import * as typebox from '@sinclair/typebox'
import type { HookType } from '../utils'
import { isActualBrowser, isTest, runHooks, safeDirname } from '../utils'
import { isActualBrowser, isTest, safeDirname } from '../utils'
import type { FictionPluginSettings } from '../plugin'
import { FictionPlugin } from '../plugin'
import type { FictionEnv } from '../plugin-env'
Expand All @@ -24,14 +23,13 @@ vars.register(() => [

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

export type FictionDbHookDictionary = {
onStart: { args: [FictionDb] }
tables: { args: [FictionDbTable[]] }
}
// export type FictionDbHookDictionary = {
// onStart: { args: [FictionDb] }
// tables: { args: [FictionDbTable[]] }
// }

export type FictionDbSettings = {
connectionUrl?: string
hooks?: HookType<FictionDbHookDictionary>[]
tables?: FictionDbTable[]
fictionEnv?: FictionEnv
fictionServer?: FictionServer // for DB utilities like username checking
Expand All @@ -40,7 +38,6 @@ export type FictionDbSettings = {
export class FictionDb extends FictionPlugin<FictionDbSettings> {
db?: Knex
connectionUrl?: URL
hooks: HookType<FictionDbHookDictionary>[]
defaultConnectionUrl = 'http://test:test@localhost:5432/test'
tables = this.settings.tables || []
isInitialized = false
Expand All @@ -57,8 +54,6 @@ export class FictionDb extends FictionPlugin<FictionDbSettings> {
constructor(settings: FictionDbSettings) {
super('db', { root: safeDirname(import.meta.url), ...settings })

this.hooks = settings.hooks || []

if (isActualBrowser())
return

Expand Down Expand Up @@ -153,8 +148,8 @@ export class FictionDb extends FictionPlugin<FictionDbSettings> {
tableKey: string,
columns: FictionDbCol[] | readonly FictionDbCol[],
) {
this.hooks.push({
hook: 'tables',
this.settings.fictionEnv.hooks.push({
hook: 'dbOnTables',
callback: (tables: FictionDbTable[]) => {
const tbl = tables.find(t => t.tableKey === tableKey)

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

if (this.tables.length > 0) {
const tables = await runHooks<FictionDbHookDictionary, 'tables'>({
list: this.hooks,
hook: 'tables',
args: [this.tables],
})
const tables = await this.settings.fictionEnv.runHooks('dbOnTables', this.tables)

for (const table of tables)
await table.create(db)
}

this.log.info('extending db [done]')
await runHooks<FictionDbHookDictionary>({
list: this.hooks,
hook: 'onStart',
args: [this],
})
await this.settings.fictionEnv.runHooks('dbOnConnected', this)

const printUrl = this.connectionUrl.toString().replace(this.connectionUrl.password, '--password--')
this.log.info('connected db [ready]', {
Expand Down
21 changes: 2 additions & 19 deletions @fiction/core/plugin-env/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import fs from 'fs-extra'
import type { JSONSchema } from 'json-schema-to-typescript'
import { log } from '../plugin-log'
import { stringify } from '../utils/utils'
import { runHooks } from '../utils/hook'
import type { FictionEnvHookDictionary } from './types'
import type { FictionEnv } from '.'

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

const _staticSchemaProps = await runHooks<
FictionEnvHookDictionary,
'staticSchema'
>({
list: fictionEnv.hooks ?? [],
hook: 'staticSchema',
args: [{}],
},
)
const _staticSchemaProps = await fictionEnv.runHooks('staticSchema', {})

const staticSchemaProps = _staticSchemaProps || {}

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

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

/**
* Handle config
*/
const staticConfig = await runHooks<FictionEnvHookDictionary, 'staticConfig'>({
list: fictionEnv.hooks ?? [],
hook: 'staticConfig',
args: [{}],
})
const staticConfig = await fictionEnv.runHooks('staticConfig', {})

const stringed = stringify(staticConfig)

Expand Down
14 changes: 14 additions & 0 deletions @fiction/core/plugin-env/hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { JSONSchema } from 'json-schema-to-typescript'
import type { CliOptions } from './types'

export interface FictionEnvHookDictionary {
runCommand: {
args: [string, CliOptions]
}
staticConfig: {
args: [Record<string, unknown>]
}
staticSchema: {
args: [JSONSchema['properties']]
}
}
38 changes: 20 additions & 18 deletions @fiction/core/plugin-env/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,23 @@ import { camelToUpperSnake, getCrossVar, isApp, isDev, isNode, isTest, runHooks,
import { version as fictionVersion } from '../package.json'
import type { RunVars } from '../inject'
import { compileApplication } from './entry'
import type * as types from './types'

import type { CliCommand } from './commands'
import { standardAppCommands } from './commands'
import { done } from './utils'
import { generateStaticConfig } from './generate'
import { commonServerOnlyModules } from './serverOnly'
import { EnvVar, envConfig, vars } from './onImport'
import type { CliOptions, CliVars, ServerModuleDef, ServiceConfig } from './types'
import type { FictionEnvHookDictionary } from './hooks'

export { envConfig, vars, EnvVar }
export * from './types'
export * from './entry'
export * from './commands'

export interface FictionControlSettings {
hooks?: HookType<types.FictionEnvHookDictionary>[]
hooks?: HookType<FictionEnvHookDictionary>[]
envFiles?: string[]
envFilesProd?: string[]
env?: Record<string, string>
Expand All @@ -36,7 +38,7 @@ export interface FictionControlSettings {
isApp?: boolean
isTest?: boolean
version?: string
serverOnlyModules?: types.ServerModuleDef[]
serverOnlyModules?: ServerModuleDef[]
uiPaths?: string[]
meta?: { version?: string, app?: { name?: string, email?: string, url?: string, domain?: string } }
}
Expand Down Expand Up @@ -86,6 +88,14 @@ export class FictionEnv<
// the services are then accessed via useService provide
service = vue.shallowRef<{ runVars?: Partial<RunVars>, [key: string]: unknown }>({})

runHooks<T extends keyof FictionEnvHookDictionary>(hook: T, ...args: FictionEnvHookDictionary[T]['args']) {
return runHooks<FictionEnvHookDictionary, T>({ list: this.hooks, hook, args })
}

public addHook<T extends HookType<FictionEnvHookDictionary>>(hook: T): void {
this.hooks.push(hook)
}

constructor(settings: FictionControlSettings) {
super('env', settings)

Expand Down Expand Up @@ -147,7 +157,7 @@ export class FictionEnv<
}

commandName = vue.ref(getCrossVar('COMMAND') || '')
commandOpts = vue.ref(JSON.parse(getCrossVar('COMMAND_OPTS') || '{}') as types.CliOptions)
commandOpts = vue.ref(JSON.parse(getCrossVar('COMMAND_OPTS') || '{}') as CliOptions)

currentCommand = vue.computed(() => {
if (!this.commandName.value)
Expand Down Expand Up @@ -291,17 +301,13 @@ export class FictionEnv<
await generateStaticConfig(this)
}

public addHook(hook: HookType<types.FictionEnvHookDictionary>): void {
this.hooks.push(hook)
}

onCommand(
commands: string[],
callback: (command: string, options: types.CliOptions) => Promise<void>,
callback: (command: string, options: CliOptions) => Promise<void>,
): void {
this.hooks.push({
hook: 'runCommand',
callback: async (command: string, opts: types.CliOptions) => {
callback: async (command: string, opts: CliOptions) => {
if (commands.includes(command))
await callback(command, opts)
},
Expand All @@ -314,8 +320,8 @@ export class FictionEnv<
*/
async crossRunCommand(args: {
context: 'node' | 'app'
serviceConfig: types.ServiceConfig
cliVars?: Partial<types.CliVars>
serviceConfig: ServiceConfig
cliVars?: Partial<CliVars>
runVars?: Partial<RunVars>
}) {
const { context, serviceConfig, cliVars, runVars } = args
Expand All @@ -326,17 +332,13 @@ export class FictionEnv<

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

await runHooks<types.FictionEnvHookDictionary>({
list: this.hooks,
hook: 'runCommand',
args: [options.command || 'not_set', options],
})
await runHooks({ list: this.hooks, hook: 'runCommand', args: [options.command || 'not_set', options] })

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

async serverRunCurrentCommand(args: { serviceConfig: types.ServiceConfig, cliVars: Partial<types.CliVars> }): Promise<void> {
async serverRunCurrentCommand(args: { serviceConfig: ServiceConfig, cliVars: Partial<CliVars> }): Promise<void> {
const { serviceConfig, cliVars } = args

const cliCommand = this.currentCommand.value
Expand Down
13 changes: 0 additions & 13 deletions @fiction/core/plugin-env/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { MergeHead } from '@unhead/schema'
import type { VueHeadClient } from '@unhead/vue'
import type { JSONSchema } from 'json-schema-to-typescript'
import type { Router } from 'vue-router'
import type { vue } from '../utils'
import type { PackageJson } from '../types'
Expand All @@ -10,18 +9,6 @@ import type { FictionEnv } from '../plugin-env'
import type { FictionObject, FictionPlugin } from '../plugin'
import type { RunVars } from '../inject'

export type FictionEnvHookDictionary = {
runCommand: {
args: [string, CliOptions]
}
staticConfig: {
args: [Record<string, unknown>]
}
staticSchema: {
args: [JSONSchema['properties']]
}
}

export interface FictionAppEntry<T extends ServiceList = ServiceList> {
app: vue.App
router: Router
Expand Down

0 comments on commit ef2a223

Please sign in to comment.