generated from Hebilicious/nuxt-module-template
-
-
Notifications
You must be signed in to change notification settings - Fork 3
/
module.ts
110 lines (95 loc) · 4.2 KB
/
module.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import { existsSync, promises as fsp } from "node:fs"
import { resolve as pathResolve } from "node:path"
import { addPlugin, createResolver, defineNuxtModule, useNitro } from "@nuxt/kit"
import ExtractSFCBlock from "@hebilicious/extract-sfc-block"
import { loadFile } from "magicast"
import type { NitroEventHandler } from "nitropack"
import { SupportedMethods, getRoute, logger, makePathShortener, writeHandlers } from "./utils"
export async function* walkFiles(dir: string): AsyncGenerator<string> {
const entries = await fsp.readdir(dir, { withFileTypes: true })
for (const entry of entries) {
const res = pathResolve(dir, entry.name)
if (entry.isDirectory()) {
yield * walkFiles(res)
}
else {
yield res
}
}
}
const name = "server-block"
const serverOutput = "server/.generated" as const
export default defineNuxtModule({
meta: {
name,
compatibility: { nuxt: ">=3.0.0" }
},
async setup(userOptions, nuxt) {
const { resolve } = createResolver(import.meta.url)
const shortened = makePathShortener(nuxt.options.srcDir)
logger.info(`Adding ${name} module...`)
// 0. Create directories and .gitignore
const serverGeneratedDirectoryPath = resolve(nuxt.options.srcDir, "server/.generated")
if (existsSync(serverGeneratedDirectoryPath)) await fsp.rm(serverGeneratedDirectoryPath, { recursive: true })
await fsp.mkdir(serverGeneratedDirectoryPath, { recursive: true })
await fsp.writeFile(`${serverGeneratedDirectoryPath}/.gitignore`, "*")
// 1. Add Volar plugin
nuxt.options.typescript.tsConfig ||= {}
nuxt.options.typescript.tsConfig.vueCompilerOptions ||= {}
nuxt.options.typescript.tsConfig.vueCompilerOptions.plugins ||= []
nuxt.options.typescript.tsConfig.vueCompilerOptions.plugins.push("@hebilicious/sfc-server-volar")
// 2. Add vite extract-sfc-block plugin
nuxt.hook("vite:extendConfig", (config) => {
config.plugins ||= []
config.plugins.push(
ExtractSFCBlock({
output: serverOutput,
sourceDir: "pages",
blockType: "server",
defaultPath: "api"
})
)
})
const allHandlers = new Map<string, NitroEventHandler>()
const addHandlers = async (path: string, event?: string) => {
if (!existsSync(path)) return // Return early if the path doesn't exist.
if (path.includes(serverOutput)) {
if (!path.endsWith(".ts")) return // skip non-ts files
if (path.includes("server/.generated/.loader")) return // skip files in .loader
if (SupportedMethods.map(m => `.${m.toLowerCase()}.ts`).some(s => path.includes(s))) return // skip .[method].ts
logger.info(`[update] '@${event}'`, shortened(path))
const route = getRoute(path) // This will throw if there's no generated handlers.
const file = await loadFile(path)
if (file) {
logger.info(`[update]: Adding new handler(s) @${route}`)
const handlers = await writeHandlers(file, path, serverGeneratedDirectoryPath)
for (const handler of handlers) {
logger.success(`[update] Wrote ${handler.method} handler @${handler.route} : ${shortened(handler.handler)}`)
allHandlers.set(handler.handler, handler)
if (useNitro().options.handlers.find(h => h.handler === handler.handler)) continue
useNitro().options.handlers.push({ ...handler, lazy: true })
}
}
// await useNuxt().hooks.callHookParallel("app:data:refresh") @todo find a way to refresh data here
logger.info("[update]: Nitro Handlers \n", useNitro().options.handlers.map(h => h.route))
}
}
// 3.Add handlers on build.
nuxt.hook("build:before", async () => {
for await (const loaderPath of walkFiles(serverGeneratedDirectoryPath)) {
await addHandlers(loaderPath, "build:before")
}
})
// 4.Watch directories, split handlers and add them to Nitro/Nuxt
nuxt.hook("builder:watch", async (event, path) => {
try {
await addHandlers(path, event)
}
catch (error) {
logger.error(`error while handling '${event}'`, error)
}
})
addPlugin(resolve("./runtime/plugin"))
logger.success(`Added ${name} module successfully.`)
}
})