You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

非框架适配DevqalySDK在Vue中报错`v is not defined`的解决及SDK构建咨询

说明

我知道此处可能并非此类问题的合适提问场所,但我寻求相关指导,并非需要确切的最终答案,因我明白该问题具有开放性。

背景介绍

我开发了一个用于监听浏览器点击、窗口缩放及其他各类事件的包DevqalySDK。

正常使用场景

在无框架的简单项目中(仅将TS转译为JS)本地导入该包时,可正常使用,一切功能正常运行:

<script type="module">
  import { DevqalySDK } from '/src/index.ts'
  const devqaly = new DevqalySDK({
    projectKey: '99851ecf-af1e-4e0b-9118-466babf48a3a',
  })

  devqaly.showRecordingButton()
</script>
Vue项目中的异常情况

当我在通过npx init vue@latest创建的Vue初始项目中尝试使用该包时:

<script setup lang="ts">
import { RouterLink, RouterView } from 'vue-router'
import HelloWorld from './components/HelloWorld.vue'
import {DevqalySDK} from '@devqaly/browser'
import { onMounted } from "vue";

onMounted(() => {
  const sdk = new DevqalySDK({
    projectKey: 'project-key'
  })

  sdk.showRecordingButton()

  console.log('asd')
})
</script>

出现如下错误:ReferenceError: v is not defined

经调试,定位到触发错误的代码部分:

// sdk.ts
import { writeRecordingScript } from './services/RecordingService'

export class DevqalySDK {
  private async onRecordingStart() {
    const newWindow = window.open()

    if (!newWindow) throw new DevqalyError('Cant create window')

    newWindow.document.write(writeRecordingScript())
  }
}

// RecordingService.ts
export function writeRecordingScript() {
  const code =
    '(' +
    function () {
      class RecordingService {
        stream
        recorder
        dataPromise

        async start() {
          const stream = await navigator.mediaDevices.getDisplayMedia()
          this.stream = stream
          const recorder = new MediaRecorder(stream, {
            mimeType: 'video/webm;codecs=vp9',
          })
          recorder.start()

          this.recorder = recorder

          const channel = new BroadcastChannel('devqaly')

          channel.onmessage = async _e => {
            this.stop()
          }

          this.recorder.ondataavailable = ev => {
            channel.postMessage(ev.data)
            window.close()
          }

          channel.postMessage('started')

          window.onbeforeunload = _e => {
            channel.postMessage('cancel')
          }
        }

        stop() {
          this.recorder.stop()
          this.stream.getTracks().forEach(t => t.stop())
          return this.dataPromise
        }
      }

      async function main() {
        const recorder = new RecordingService()

        const message = document.createElement('h1')

        try {
          await recorder.start()
          message.innerText =
            'Recording started, go back to your app and leave this tab open! Do not close this tab, closing it will cancel the session.'
        } catch (e) {
          message.innerText = 'User clicked cancel on the recording screen picker'
        }

        document.body.append(message)
      }

      main().catch(console.error)
    } +
    ')'

  return `
  <script>
    ${code}()
  </script>
  <body>
  </body>
  `
}

查看浏览器中转译后的生成代码,可见:

(function() {
    class e {
      constructor() {
        v(this, "stream");
        v(this, "recorder");
        v(this, "dataPromise");
      }
      async start() {
        const i = await navigator.mediaDevices.getDisplayMedia();
        this.stream = i;
        const o = new MediaRecorder(i, {
          mimeType: "video/webm;codecs=vp9"
        });
        o.start(), this.recorder = o;
        const l = new BroadcastChannel("devqaly");
        l.onmessage = async (f) => {
          this.stop();
        }, this.recorder.ondataavailable = (f) => {
          l.postMessage(f.data), window.close();
        }, l.postMessage("started"), window.onbeforeunload = (f) => {
          l.postMessage("cancel");
        };
      }
      stop() {
        return this.recorder.stop(), this.stream.getTracks().forEach((i) => i.stop()), this.dataPromise;
      }
    }
    async function t() {
      const n = new e(), i = document.createElement("h1");
      try {
        await n.start(), i.innerText = "Recording started, go back to your app and leave this tab open! Do not close this tab, closing it will cancel the session.";
      } catch {
        i.innerText = "User clicked cancel on the recording screen picker";
      }
      document.body.append(i);
    }
    t().catch(console.error);
  })()

其中构造函数中的v未定义,这正是报错原因。

问题咨询
  • 该错误是否与window.open()获取的是Shadow DOM而非普通DOM有关?我对此存疑,但已无其他调试思路
  • 如何构建既能适配无框架简单项目、又能兼容各类前端框架的DOM事件监听SDK?求相关学习资源
补充信息

SDK项目的tsconfig.json配置如下:

{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "module": "ESNext",
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "skipLibCheck": true,

    /* Bundler mode */
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,

    /* Linting */
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,
    "types": ["cypress", "@testing-library/cypress"]
  },
  "include": ["src", "src/services"]
}

内容的提问来源于stack exchange,提问作者Bruno Francisco

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 15:42:08