fix(Module): HMR not working when edit component load too slow (#235)

* feat: add recast as deps

* refactor: use recast instead of ts-morph due to performance issue
This commit is contained in:
zernonia 2024-01-02 16:08:38 +08:00 committed by GitHub
parent f6f87d3cd6
commit 2f4f5a8291
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 26 additions and 20 deletions

View File

@ -36,6 +36,7 @@
}, },
"dependencies": { "dependencies": {
"@nuxt/kit": "^3.8.2", "@nuxt/kit": "^3.8.2",
"recast": "^0.23.4",
"ts-morph": "^19.0.0" "ts-morph": "^19.0.0"
}, },
"devDependencies": { "devDependencies": {

View File

@ -1,7 +1,7 @@
import { readdirSync } from 'node:fs' import { readFileSync, readdirSync } from 'node:fs'
import { join } from 'pathe' import { join } from 'node:path'
import { addComponent, createResolver, defineNuxtModule } from '@nuxt/kit' import { addComponent, createResolver, defineNuxtModule } from 'nuxt/kit'
import { Project } from 'ts-morph' import { parse } from 'recast'
// Module options TypeScript interface definition // Module options TypeScript interface definition
export interface ModuleOptions { export interface ModuleOptions {
@ -25,33 +25,35 @@ export default defineNuxtModule<ModuleOptions>({
prefix: '', prefix: '',
componentDir: './components/ui', componentDir: './components/ui',
}, },
async setup(options, nuxt) { async setup({ prefix, componentDir }, nuxt) {
const IGNORE_DIR = '**/components/ui' const COMPONENT_DIR_PATH = componentDir!
const COMPONENT_DIR_PATH = options.componentDir!
const ROOT_DIR_PATH = nuxt.options.rootDir const ROOT_DIR_PATH = nuxt.options.rootDir
const { resolve, resolvePath } = createResolver(ROOT_DIR_PATH) const { resolve, resolvePath } = createResolver(ROOT_DIR_PATH)
nuxt.options.ignore.push(IGNORE_DIR) nuxt.hook('components:dirs', (dirs) => {
nuxt._ignore?.add(IGNORE_DIR) dirs.unshift({
nuxt._ignorePatterns?.push(IGNORE_DIR) path: resolve(COMPONENT_DIR_PATH),
extensions: [],
})
})
try { try {
readdirSync(resolve(COMPONENT_DIR_PATH)) readdirSync(resolve(COMPONENT_DIR_PATH))
.forEach(async (dir) => { .forEach(async (dir) => {
const filePath = await resolvePath(join(COMPONENT_DIR_PATH, dir, 'index'), { extensions: ['.ts', '.js'] }) const filePath = await resolvePath(join(COMPONENT_DIR_PATH, dir, 'index'), { extensions: ['.ts', 'js'] })
const content = readFileSync(filePath, { encoding: 'utf8' })
const ast = parse(content)
const project = new Project() const exportedKeys: string[] = ast.program.body
project.addSourceFileAtPath(filePath) // @ts-expect-error parse return any
const sourceFile = project.getSourceFileOrThrow(filePath) .filter(node => node.type === 'ExportNamedDeclaration')
const exportedDeclarations = sourceFile.getExportedDeclarations() // @ts-expect-error parse return any
.flatMap(node => node.specifiers.map(specifier => specifier.exported.name))
// Filter out non-component export .filter((key: string) => /^[A-Z]/.test(key))
const exportedKeys = Array.from(exportedDeclarations.keys()).filter(key => /^[A-Z]/.test(key))
exportedKeys.forEach((key) => { exportedKeys.forEach((key) => {
addComponent({ addComponent({
name: `${options.prefix}${key}`, // name of the component to be used in vue templates name: `${prefix}${key}`, // name of the component to be used in vue templates
export: key, // (optional) if the component is a named (rather than default) export export: key, // (optional) if the component is a named (rather than default) export
filePath: resolve(filePath), filePath: resolve(filePath),
}) })

View File

@ -289,6 +289,9 @@ importers:
'@nuxt/kit': '@nuxt/kit':
specifier: ^3.8.2 specifier: ^3.8.2
version: 3.8.2(rollup@3.29.3) version: 3.8.2(rollup@3.29.3)
recast:
specifier: ^0.23.4
version: 0.23.4
ts-morph: ts-morph:
specifier: ^19.0.0 specifier: ^19.0.0
version: 19.0.0 version: 19.0.0