From 2f4f5a829181495fd153e2e0366c6a03136445b6 Mon Sep 17 00:00:00 2001 From: zernonia <59365435+zernonia@users.noreply.github.com> Date: Tue, 2 Jan 2024 16:08:38 +0800 Subject: [PATCH] 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 --- packages/module/package.json | 1 + packages/module/src/module.ts | 42 ++++++++++++++++++----------------- pnpm-lock.yaml | 3 +++ 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/packages/module/package.json b/packages/module/package.json index b09da038..66d8903d 100644 --- a/packages/module/package.json +++ b/packages/module/package.json @@ -36,6 +36,7 @@ }, "dependencies": { "@nuxt/kit": "^3.8.2", + "recast": "^0.23.4", "ts-morph": "^19.0.0" }, "devDependencies": { diff --git a/packages/module/src/module.ts b/packages/module/src/module.ts index a5b58655..04a71e2a 100644 --- a/packages/module/src/module.ts +++ b/packages/module/src/module.ts @@ -1,7 +1,7 @@ -import { readdirSync } from 'node:fs' -import { join } from 'pathe' -import { addComponent, createResolver, defineNuxtModule } from '@nuxt/kit' -import { Project } from 'ts-morph' +import { readFileSync, readdirSync } from 'node:fs' +import { join } from 'node:path' +import { addComponent, createResolver, defineNuxtModule } from 'nuxt/kit' +import { parse } from 'recast' // Module options TypeScript interface definition export interface ModuleOptions { @@ -25,33 +25,35 @@ export default defineNuxtModule({ prefix: '', componentDir: './components/ui', }, - async setup(options, nuxt) { - const IGNORE_DIR = '**/components/ui' - const COMPONENT_DIR_PATH = options.componentDir! + async setup({ prefix, componentDir }, nuxt) { + const COMPONENT_DIR_PATH = componentDir! const ROOT_DIR_PATH = nuxt.options.rootDir - const { resolve, resolvePath } = createResolver(ROOT_DIR_PATH) - nuxt.options.ignore.push(IGNORE_DIR) - nuxt._ignore?.add(IGNORE_DIR) - nuxt._ignorePatterns?.push(IGNORE_DIR) + nuxt.hook('components:dirs', (dirs) => { + dirs.unshift({ + path: resolve(COMPONENT_DIR_PATH), + extensions: [], + }) + }) try { readdirSync(resolve(COMPONENT_DIR_PATH)) .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() - project.addSourceFileAtPath(filePath) - const sourceFile = project.getSourceFileOrThrow(filePath) - const exportedDeclarations = sourceFile.getExportedDeclarations() - - // Filter out non-component export - const exportedKeys = Array.from(exportedDeclarations.keys()).filter(key => /^[A-Z]/.test(key)) + const exportedKeys: string[] = ast.program.body + // @ts-expect-error parse return any + .filter(node => node.type === 'ExportNamedDeclaration') + // @ts-expect-error parse return any + .flatMap(node => node.specifiers.map(specifier => specifier.exported.name)) + .filter((key: string) => /^[A-Z]/.test(key)) exportedKeys.forEach((key) => { 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 filePath: resolve(filePath), }) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4c7de87b..c4c910f4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -289,6 +289,9 @@ importers: '@nuxt/kit': specifier: ^3.8.2 version: 3.8.2(rollup@3.29.3) + recast: + specifier: ^0.23.4 + version: 0.23.4 ts-morph: specifier: ^19.0.0 version: 19.0.0