2021-09-29 10:10:46 +00:00
|
|
|
import { promises as fsp } from 'fs'
|
2021-04-02 11:47:01 +00:00
|
|
|
import defu from 'defu'
|
|
|
|
import { applyDefaults } from 'untyped'
|
2021-10-02 18:31:00 +00:00
|
|
|
import consola from 'consola'
|
2021-10-26 14:42:10 +00:00
|
|
|
import { dirname } from 'pathe'
|
2021-11-21 16:14:46 +00:00
|
|
|
import type { Nuxt, NuxtTemplate, NuxtModule, LegacyNuxtModule, ModuleOptions } from '@nuxt/schema'
|
|
|
|
import { useNuxt, nuxtCtx } from '../context'
|
|
|
|
import { isNuxt2, checkNuxtCompatibilityIssues } from '../compatibility'
|
|
|
|
import { templateUtils, compileTemplate } from '../internal/template'
|
2021-04-02 11:47:01 +00:00
|
|
|
|
2021-04-15 18:49:29 +00:00
|
|
|
/**
|
|
|
|
* Define a Nuxt module, automatically merging defaults with user provided options, installing
|
|
|
|
* any hooks that are provided, and calling an optional setup function for full control.
|
|
|
|
*/
|
2021-04-02 11:47:01 +00:00
|
|
|
export function defineNuxtModule<OptionsT extends ModuleOptions> (input: NuxtModule<OptionsT> | ((nuxt: Nuxt) => NuxtModule<OptionsT>)): LegacyNuxtModule {
|
|
|
|
let mod: NuxtModule<OptionsT>
|
|
|
|
|
|
|
|
function wrappedModule (inlineOptions: OptionsT) {
|
|
|
|
// Get nuxt context
|
|
|
|
const nuxt: Nuxt = this.nuxt || useNuxt()
|
|
|
|
|
|
|
|
// Resolve function
|
|
|
|
if (typeof input === 'function') {
|
2021-06-24 14:06:16 +00:00
|
|
|
mod = input(nuxt)
|
2021-04-02 11:47:01 +00:00
|
|
|
} else {
|
|
|
|
mod = input
|
|
|
|
}
|
|
|
|
|
|
|
|
// Install hooks
|
|
|
|
if (mod.hooks) {
|
2021-11-21 12:35:37 +00:00
|
|
|
if (isNuxt2(nuxt)) {
|
|
|
|
nuxt.addHooks(mod.hooks)
|
|
|
|
} else {
|
|
|
|
nuxt.hooks.addHooks(mod.hooks)
|
|
|
|
}
|
2021-04-02 11:47:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Stop if no install provided
|
|
|
|
if (typeof mod.setup !== 'function') {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-10-02 18:31:00 +00:00
|
|
|
// check nuxt version range
|
|
|
|
if (mod.requires) {
|
|
|
|
const issues = checkNuxtCompatibilityIssues(mod.requires, nuxt)
|
|
|
|
if (issues.length) {
|
|
|
|
consola.warn(`Module \`${mod.name}\` is disabled due to incompatibility issues:\n${issues.toString()}`)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-02 11:47:01 +00:00
|
|
|
// Resolve options
|
|
|
|
const configKey = mod.configKey || mod.name
|
|
|
|
const userOptions = defu(inlineOptions, nuxt.options[configKey]) as OptionsT
|
|
|
|
const resolvedOptions = applyDefaults(mod.defaults as any, userOptions) as OptionsT
|
|
|
|
|
2021-06-24 14:06:16 +00:00
|
|
|
// Ensure nuxt instance exists (nuxt2 compatibility)
|
|
|
|
if (!nuxtCtx.use()) {
|
|
|
|
nuxtCtx.set(nuxt)
|
|
|
|
// @ts-ignore
|
|
|
|
if (!nuxt.__nuxtkit_close__) {
|
|
|
|
nuxt.hook('close', () => nuxtCtx.unset())
|
|
|
|
// @ts-ignore
|
|
|
|
nuxt.__nuxtkit_close__ = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-29 10:10:46 +00:00
|
|
|
if (isNuxt2()) {
|
|
|
|
// Support virtual templates with getContents() by writing them to .nuxt directory
|
|
|
|
let virtualTemplates: NuxtTemplate[]
|
|
|
|
nuxt.hook('builder:prepared', (_builder, buildOptions) => {
|
|
|
|
virtualTemplates = []
|
|
|
|
buildOptions.templates.forEach((template, index, arr) => {
|
|
|
|
if (!template.getContents) { return }
|
|
|
|
// Remove template from template array to handle it ourselves
|
|
|
|
arr.splice(index, 1)
|
|
|
|
virtualTemplates.push(template)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
nuxt.hook('build:templates', async (templates) => {
|
|
|
|
const context = {
|
|
|
|
nuxt,
|
|
|
|
utils: templateUtils,
|
|
|
|
app: {
|
|
|
|
dir: nuxt.options.srcDir,
|
|
|
|
extensions: nuxt.options.extensions,
|
|
|
|
plugins: nuxt.options.plugins,
|
|
|
|
templates: [
|
|
|
|
...templates.templatesFiles,
|
|
|
|
...virtualTemplates
|
2021-10-26 12:59:05 +00:00
|
|
|
],
|
|
|
|
templateVars: templates.templateVars
|
2021-09-29 10:10:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
for await (const template of virtualTemplates) {
|
|
|
|
const contents = await compileTemplate({ ...template, src: '' }, context)
|
2021-10-26 14:42:10 +00:00
|
|
|
await fsp.mkdir(dirname(template.dst), { recursive: true })
|
2021-09-29 10:10:46 +00:00
|
|
|
await fsp.writeFile(template.dst, contents)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-04-02 11:47:01 +00:00
|
|
|
// Call setup
|
2021-06-24 14:06:16 +00:00
|
|
|
return mod.setup.call(null, resolvedOptions, nuxt)
|
2021-04-02 11:47:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
wrappedModule.meta = mod
|
|
|
|
|
|
|
|
return wrappedModule
|
|
|
|
}
|