Skip to content

Commit

Permalink
fix(lifecycle): create multi-instances at the same time (#660) (#663)
Browse files Browse the repository at this point in the history
  • Loading branch information
qwqcode committed Dec 16, 2023
1 parent 87102cd commit c9ea8f6
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 71 deletions.
90 changes: 23 additions & 67 deletions ui/packages/artalk/src/artalk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,68 +10,54 @@ import { DefaultPlugins } from './plugins'
import * as Stat from './plugins/stat'
import Api from './api'

/** Global Plugins for all instances */
const GlobalPlugins: ArtalkPlugin[] = [ ...DefaultPlugins ]

/**
* Artalk
*
* @see https://artalk.js.org
*/
export default class Artalk {
private static instance?: Artalk

public static readonly defaults: ArtalkConfig = defaults

public conf!: ArtalkConfig
public ctx!: ContextApi
public $root!: HTMLElement

/** Plugins */
protected static plugins: ArtalkPlugin[] = [ ...DefaultPlugins ]
public static DisabledComponents: string[] = []
protected plugins: ArtalkPlugin[] = [ ...GlobalPlugins ]

constructor(conf: Partial<ArtalkConfig>) {
if (Artalk.instance) Artalk.destroy()

// 初始化基本配置
// Init Config
this.conf = handelCustomConf(conf)
if (this.conf.el instanceof HTMLElement) this.$root = this.conf.el

// 初始化 Context
// Init Context
this.ctx = new ConcreteContext(this.conf, this.$root)

// 内建服务初始化
// Init Services
Object.entries(Services).forEach(([name, initService]) => {
if (Artalk.DisabledComponents.includes(name)) return
const obj = initService(this.ctx)
if (obj) this.ctx.inject(name as any, obj) // auto inject deps to ctx
})

// 插件初始化 (global scope)
Artalk.plugins.forEach(plugin => {
if (typeof plugin === 'function')
plugin(this.ctx)
// Init Plugins
this.plugins.forEach(plugin => {
if (typeof plugin === 'function') plugin(this.ctx)
})

// Trigger inited event
this.ctx.trigger('inited')
}

/** Init Artalk */
public static init(conf: Partial<ArtalkConfig>): Artalk {
if (this.instance) Artalk.destroy()
this.instance = new Artalk(conf)
return this.instance
}

/** Use Plugin (plugin will be called in instance `use` func) */
public use(plugin: ArtalkPlugin) {
Artalk.plugins.push(plugin)
if (typeof plugin === 'function') plugin(this.ctx)
}

/** Update config of Artalk */
public update(conf: Partial<ArtalkConfig>) {
if (!Artalk.instance) throw Error('cannot call `update` function before call `load`')
Artalk.instance.ctx.updateConf(conf)
return Artalk.instance
this.ctx.updateConf(conf)
return this
}

/** Reload comment list of Artalk */
Expand All @@ -81,10 +67,8 @@ export default class Artalk {

/** Destroy instance of Artalk */
public destroy() {
if (!Artalk.instance) throw Error('cannot call `destroy` function before call `load`')
this.ctx.trigger('destroy')
Artalk.instance.$root.remove()
delete Artalk.instance
this.$root.remove()
}

/** Add an event listener */
Expand All @@ -108,48 +92,20 @@ export default class Artalk {
}

// ===========================
// Static methods
// Static Members
// ===========================

/** Use Plugin (static method) */
public static use(plugin: ArtalkPlugin) {
this.plugins.push(plugin)
if (this.instance && typeof plugin === 'function') plugin(this.instance.ctx)
}

/** Update config of Artalk */
public static update(conf: Partial<ArtalkConfig>) {
return this.instance?.update(conf)
}

/** Reload comment list of Artalk */
public static reload() {
this.instance?.reload()
}

/** Destroy instance of Artalk */
public static destroy() {
this.instance?.destroy()
}

/** Add an event listener */
public static on<K extends keyof EventPayloadMap>(name: K, handler: EventHandler<EventPayloadMap[K]>) {
this.instance?.on(name, handler)
}

/** Remove an event listener */
public static off<K extends keyof EventPayloadMap>(name: K, handler: EventHandler<EventPayloadMap[K]>) {
this.instance?.off(name, handler)
}
/** Default Configs */
public static readonly defaults: ArtalkConfig = defaults

/** Trigger an event */
public static trigger<K extends keyof EventPayloadMap>(name: K, payload?: EventPayloadMap[K]) {
this.instance?.trigger(name, payload)
/** Init Artalk */
public static init(conf: Partial<ArtalkConfig>): Artalk {
return new Artalk(conf)
}

/** Set dark mode */
public static setDarkMode(darkMode: boolean) {
this.instance?.setDarkMode(darkMode)
/** Use Plugin for all instances */
public static use(plugin: ArtalkPlugin) {
GlobalPlugins.push(plugin)
}

/** Load count widget */
Expand Down
3 changes: 3 additions & 0 deletions ui/packages/artalk/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ export function handelCustomConf(customConf: Partial<ArtalkConfig>): ArtalkConfi
// 合并默认配置
const conf: ArtalkConfig = Utils.mergeDeep(Defaults, customConf)

// TODO the type of el options may HTMLElement, use it directly instead of from mergeDeep
if (customConf.el) conf.el = customConf.el

// 绑定元素
if (typeof conf.el === 'string' && !!conf.el) {
try {
Expand Down
5 changes: 1 addition & 4 deletions ui/packages/artalk/src/plugins/conf-remoter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@ import type { ArtalkConfig, ArtalkPlugin, ContextApi } from '~/types'
import { handleConfFormServer } from '@/config'
import { showErrorDialog } from '../components/error-dialog'

let confLoaded = false

export const ConfRemoter: ArtalkPlugin = (ctx) => {
ctx.on('inited', () => {
if (!confLoaded) loadConf(ctx)
loadConf(ctx)
})
}

Expand All @@ -26,7 +24,6 @@ function loadConf(ctx: ContextApi) {
ctx.conf.remoteConfModifier && ctx.conf.remoteConfModifier(conf)

ctx.updateConf(conf)
confLoaded = true
}).catch((err) => {
ctx.updateConf({})

Expand Down

0 comments on commit c9ea8f6

Please sign in to comment.