@logicflow/vue-node-registry 在 Vite 中无法解析的踩坑记录与解决方案

7 阅读4分钟

@logicflow/vue-node-registry 在 Vite 中无法解析的踩坑记录与解决方案

前言

在使用 LogicFlow 的 Vue 节点注册库 @logicflow/vue-node-registry 时,特别是在 Vite 构建工具环境下,开发者经常会遇到模块解析失败的问题。本文记录了一次完整的踩坑过程,从 Failed to resolve entry 到类型声明缺失,最终到内部 API 访问的各种问题,并提供系统性的解决方案。


问题一:Pre-transform Error - 无法解析包入口

错误现象

Pre-transform error: Failed to resolve entry for package "@logicflow/vue-node-registry". 
The package may have incorrect main/module/exports specified in its package.json.

根本原因

Vite 无法正确识别 @logicflow/vue-node-registry 的入口文件。这通常是因为:

  1. 包的 package.jsonexports 字段配置不规范
  2. Vite 的依赖预构建(optimizeDeps)未能正确处理该包
  3. 版本兼容性问题(如使用 2.0.x 版本的 LogicFlow 却搭配了不兼容的 registry 版本)

解决方案

1. 配置 Vite Alias(必须使用绝对路径)
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'

export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: {
      // ❌ 错误:相对路径会导致 Vite 在项目根目录查找
      // '@logicflow/vue-node-registry': '@logicflow/vue-node-registry/dist/index.js'
      
      // ✅ 正确:使用 path.resolve 转换为绝对路径
      '@logicflow/vue-node-registry': path.resolve(
        __dirname, 
        'node_modules/@logicflow/vue-node-registry/dist/index.esm.js'
      )
    }
  },
  optimizeDeps: {
    include: ['@logicflow/vue-node-registry', '@logicflow/core']
  }
})

关键要点:Vite 的 alias 必须使用绝对路径,否则会报 was not an absolute path 警告,并导致模块重复或找不到文件。

2. 对于 ES Module 项目(package.json 中 "type": "module")
import { fileURLToPath } from 'url'
import { dirname } from 'path'

const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)

export default defineConfig({
  resolve: {
    alias: {
      '@logicflow/vue-node-registry': path.resolve(
        __dirname,
        'node_modules/@logicflow/vue-node-registry/dist/index.esm.js'
      )
    }
  }
})

问题二:TypeScript 类型声明缺失

错误现象

找不到模块“@logicflow/vue-node-registry”或其相应的类型声明。

根本原因

虽然 Vite 能解析模块,但 TypeScript 编译器无法找到对应的 .d.ts 类型声明文件。

解决方案

方案 A:创建类型声明文件(推荐)

在项目 src 目录下创建 types/logicflow.d.ts

declare module '@logicflow/vue-node-registry' {
  import { DefineComponent } from 'vue'
  import LogicFlow, { NodeModel } from '@logicflow/core'

  export interface VueNodeConfig {
    type: string
    view: DefineComponent<{}, {}, any>
    model?: typeof NodeModel
  }

  export function register(options: VueNodeConfig, lf: LogicFlow): void
  export function getTeleport(): DefineComponent<{}, {}, any>
  export class VueNodeModel extends NodeModel {
    static extendKey: string
  }
}
方案 B:配置 tsconfig.json 路径映射
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@logicflow/vue-node-registry": [
        "node_modules/@logicflow/vue-node-registry/dist/index.d.ts"
      ]
    }
  }
}

问题三:内部 API 访问限制 - vueNodesMap

错误现象

模块“"@logicflow/vue-node-registry"”没有导出的成员“vueNodesMap”。

根本原因

vueNodesMap@logicflow/vue-node-registry内部实现细节,主要用于在 Vue 节点组件内部监听属性变化。它不是官方公开的 API,因此在类型声明中默认不存在。

正确使用方式

vueNodesMap 应该只在自定义节点组件内部使用,配合 inject 获取节点实例:

<script lang="ts">
import { defineComponent, inject } from 'vue'
import { EventType } from '@logicflow/core'
// @ts-ignore 或扩展类型声明
import { vueNodesMap } from '@logicflow/vue-node-registry'

export default defineComponent({
  name: 'CustomVueNode',
  
  setup() {
    const getNode = inject('getNode') as () => any
    const getGraph = inject('getGraph') as () => any
    
    const node = getNode()
    const graph = getGraph()
    
    // 监听属性变化
    graph.eventCenter.on(EventType.NODE_PROPERTIES_CHANGE, (eventData) => {
      const content = vueNodesMap[node.type]
      if (content && eventData.id === node.id) {
        const { effect } = content
        if (!effect || eventData.keys.some((key) => effect.includes(key))) {
          // 处理属性变化逻辑
        }
      }
    })
    
    return {}
  }
})
</script>

如需在业务代码中使用

扩展类型声明文件:

// src/types/logicflow.d.ts
declare module '@logicflow/vue-node-registry' {
  import { Component } from 'vue'
  import LogicFlow, { NodeModel } from '@logicflow/core'

  export interface VueNodeConfig {
    type: string
    view: Component
    model?: typeof NodeModel
    effect?: string[] // 需要监听的属性 key
  }

  // 内部映射表,谨慎使用
  export const vueNodesMap: Record<string, VueNodeConfig>
  
  export function register(options: VueNodeConfig, lf: LogicFlow): void
  export function getTeleport(): Component
}

⚠️ 警告vueNodesMap 作为内部 API,可能在版本更新中变更。建议仅在必要时使用,并关注官方更新日志。


完整配置参考

项目结构

project/
├── src/
│   ├── types/
│   │   └── logicflow.d.ts      # 类型声明文件
│   ├── nodes/                  # 自定义节点目录
│   │   ├── CustomNode.vue
│   │   └── config.ts
│   └── main.ts
├── vite.config.ts
└── tsconfig.json

vite.config.ts

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'

export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: {
      '@logicflow/vue-node-registry': path.resolve(
        __dirname,
        'node_modules/@logicflow/vue-node-registry/dist/index.esm.js'
      )
    }
  },
  optimizeDeps: {
    include: ['@logicflow/vue-node-registry', '@logicflow/core']
  },
  build: {
    commonjsOptions: {
      transformMixedEsModules: true
    }
  }
})

使用示例

// src/main.ts
import { createApp } from 'vue'
import LogicFlow from '@logicflow/core'
import { register, getTeleport } from '@logicflow/vue-node-registry'
import CustomNode from './nodes/CustomNode.vue'

const app = createApp(App)
const lf = new LogicFlow({ container: document.getElementById('app')! })

// 注册 Vue 节点
register({
  type: 'custom-vue-node',
  view: CustomNode,
  model: LogicFlow.NodeModel
}, lf)

// 使用 Teleport 容器
const TeleportContainer = getTeleport()
app.component('TeleportContainer', TeleportContainer)

版本兼容性建议

根据社区实践,推荐以下版本组合:

{
  "dependencies": {
    "@logicflow/core": "^2.0.12",
    "@logicflow/extension": "^2.0.14",
    "@logicflow/vue-node-registry": "^1.0.12"
  }
}

注意vue-node-registry 1.2.x 版本目前为 alpha 状态,生产环境建议使用 1.0.x 或 1.1.x 稳定版。


总结

问题核心原因解决方案
Failed to resolve entrypackage.json exports 配置问题 / Vite 解析失败配置绝对路径 alias + optimizeDeps.include
找不到类型声明TypeScript 无法识别模块类型创建 .d.ts 声明文件或配置 tsconfig paths
vueNodesMap 未导出内部 API 未公开扩展类型声明 + @ts-ignore,或在组件内部使用

通过以上配置,可以彻底解决 @logicflow/vue-node-registry 在 Vite 环境下的各种解析问题,实现 Vue 组件作为 LogicFlow 节点的无缝集成。