Skip to content

Commit

Permalink
feat(loader): support fallback template
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma committed Mar 4, 2024
1 parent cfb2718 commit 0d75c0b
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 53 deletions.
22 changes: 11 additions & 11 deletions packages/hmr/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ class Watcher extends Service {
if (loader.internal!.loadCache.has(filename)) {
loader.exit()
} else {
await loader.reload()
await loader.start()
}
} else {
if (this.externals.has(filename)) {
Expand Down Expand Up @@ -290,6 +290,14 @@ class Watcher extends Service {
// emit reload event before replacing loader cache
this.ctx.emit('hmr/reload', reloads)

const reload = (plugin: any, children: ForkScope[]) => {
for (const oldFork of children) {
const fork = oldFork.parent.plugin(plugin, oldFork.config)
fork.entry = oldFork.entry
if (fork.entry) fork.entry.fork = fork
}
}

try {
for (const [plugin, { filename, children }] of reloads) {
const path = this.relative(filename)
Expand All @@ -302,11 +310,7 @@ class Watcher extends Service {
}

try {
for (const oldFork of children) {
const fork = oldFork.parent.plugin(attempts[filename], oldFork.config)
fork.entry = oldFork.entry
fork.entry.fork = fork
}
reload(attempts[filename], children)
this.ctx.logger.info('reload plugin at %c', path)
} catch (err) {
this.ctx.logger.warn('failed to reload plugin at %c', path)
Expand All @@ -320,11 +324,7 @@ class Watcher extends Service {
for (const [plugin, { filename, children }] of reloads) {
try {
this.ctx.registry.delete(attempts[filename])
for (const oldFork of children) {
const fork = oldFork.parent.plugin(plugin, oldFork.config)
fork.entry = oldFork.entry
fork.entry.fork = fork
}
reload(plugin, children)
} catch (err) {
this.ctx.logger.warn(err)
}
Expand Down
93 changes: 51 additions & 42 deletions packages/loader/src/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,12 @@ export namespace Loader {
export interface Options {
name: string
immutable?: boolean
fallback?: Fallback
}

export interface Fallback {
extension?: string
config: Omit<Entry.Options, 'id'>[]
}
}

Expand All @@ -153,7 +159,7 @@ export abstract class Loader<T extends Loader.Options = Loader.Options> extends
env: process.env,
}

public entryFork!: ForkScope<Context>
public entryFork: ForkScope<Context>
public suspend = false
public writable = false
public mimeType!: string
Expand All @@ -167,7 +173,39 @@ export abstract class Loader<T extends Loader.Options = Loader.Options> extends

constructor(public app: Context, public options: T) {
super(app, 'loader', true)
this.entryFork = this.app.plugin(group, [])
this.realms.root = app.root[Context.isolate]

this.app.on('dispose', () => {
this.exit()
})

this.app.on('internal/update', (fork) => {
const entry = this.entries[fork.entry?.options.id!]
if (!entry) return
fork.parent.emit('loader/entry', 'reload', entry)
})

this.app.on('internal/before-update', (fork, config) => {
if (!fork.entry) return
if (fork.entry.isUpdate) return fork.entry.isUpdate = false
const { schema } = fork.runtime
fork.entry.options.config = schema ? schema.simplify(config) : config
this.writeConfig()
})

this.app.on('internal/fork', (fork) => {
// fork.uid: fork is created (we only care about fork dispose event)
// fork.parent.runtime.plugin !== group: fork is not tracked by loader
if (fork.uid || !fork.entry) return
fork.parent.emit('loader/entry', 'unload', fork.entry)
// fork is disposed by main scope (e.g. hmr plugin)
// normal: ctx.dispose() -> fork / runtime dispose -> delete(plugin)
// hmr: delete(plugin) -> runtime dispose -> fork dispose
if (!this.app.registry.has(fork.runtime.plugin)) return
fork.entry.options.disabled = true
this.writeConfig()
})
}

async init(filename?: string) {
Expand Down Expand Up @@ -200,14 +238,21 @@ export abstract class Loader<T extends Loader.Options = Loader.Options> extends

private async findConfig() {
const files = await fs.readdir(this.baseDir)
for (const extname of supported) {
const filename = this.options.name + extname
for (const extension of supported) {
const filename = this.options.name + extension
if (files.includes(filename)) {
this.mimeType = writable[extname]
this.mimeType = writable[extension]
this.filename = path.resolve(this.baseDir, filename)
return
}
}
if (this.options.fallback) {
const { config, extension = '.yml' } = this.options.fallback
this.config = config as any
this.mimeType = writable[extension]
this.filename = path.resolve(this.baseDir, this.options.name + extension)
return this.writeConfig(true)
}
throw new Error('config file not found')
}

Expand Down Expand Up @@ -237,12 +282,6 @@ export abstract class Loader<T extends Loader.Options = Loader.Options> extends
if (!silent) this.app.emit('config')
}

async reload() {
const config = await this.readConfig()
this.entryFork.update(config)
this.app.emit('config')
}

interpolate(source: any) {
if (typeof source === 'string') {
return interpolate(source, this.params, /\$\{\{(.+?)\}\}/g)
Expand Down Expand Up @@ -300,38 +339,8 @@ export abstract class Loader<T extends Loader.Options = Loader.Options> extends

async start() {
await this.readConfig()
this.entryFork = this.app.plugin(group, this.config)

this.app.on('dispose', () => {
this.exit()
})

this.app.on('internal/update', (fork) => {
const entry = this.entries[fork.entry?.options.id!]
if (!entry) return
fork.parent.emit('loader/entry', 'reload', entry)
})

this.app.on('internal/before-update', (fork, config) => {
if (!fork.entry) return
if (fork.entry.isUpdate) return fork.entry.isUpdate = false
const { schema } = fork.runtime
fork.entry.options.config = schema ? schema.simplify(config) : config
this.writeConfig()
})

this.app.on('internal/fork', (fork) => {
// fork.uid: fork is created (we only care about fork dispose event)
// fork.parent.runtime.plugin !== group: fork is not tracked by loader
if (fork.uid || !fork.entry) return
fork.parent.emit('loader/entry', 'unload', fork.entry)
// fork is disposed by main scope (e.g. hmr plugin)
// normal: ctx.dispose() -> fork / runtime dispose -> delete(plugin)
// hmr: delete(plugin) -> runtime dispose -> fork dispose
if (!this.app.registry.has(fork.runtime.plugin)) return
fork.entry.options.disabled = true
this.writeConfig()
})
this.entryFork.update(this.config)
this.app.emit('config')

while (this.tasks.size) {
await Promise.all(this.tasks)
Expand Down

0 comments on commit 0d75c0b

Please sign in to comment.