@eventra_dev/cli-plugin-vue
v1.0.4
Published
Eventra CLI plugin — extract track() calls from Vue SFC (.vue) files
Maintainers
Readme
Eventra CLI Plugin — Vue
Official Eventra CLI plugin — extracts track() calls from Vue Single-File Components (.vue), so eventra sync/check/watch understand Vue and Nuxt code the same way they already understand plain TypeScript.
Overview
The CLI core is framework-agnostic and only walks .ts/.tsx/.js/.jsx. This plugin teaches it .vue: it parses each SFC with the real Vue compiler (@vue/compiler-sfc) — not a regex — and hands the CLI a single virtual TypeScript module per file, so every existing detection rule (direct SDK calls, function wrappers, cross-file propagation, dynamic-name reporting) applies to Vue code without any Vue-specific case in the core engine.
Vue and Nuxt .vue files are handled the same way — Nuxt pages/layouts/components are ordinary Vue SFCs. See Nuxt below for auto-import composables.
Installation
npm install -D @eventra_dev/cli-plugin-vue @eventra_dev/eventra-cli
# or
pnpm add -D @eventra_dev/cli-plugin-vue @eventra_dev/eventra-cliEnable it in eventra.json:
{
"plugins": ["@eventra_dev/cli-plugin-vue"],
"sync": {
"include": ["**/*.{ts,tsx,js,jsx}"],
"exclude": ["node_modules", "dist", ".next", ".git"]
}
}sync.include does not need **/*.vue added manually — the plugin registers it via includeGlobs.
What gets detected
<script> / <script setup>
Handled exactly like a regular .ts file — direct SDK calls, function wrappers, variables, ternaries, cross-file propagation all apply:
<script setup lang="ts">
import { Eventra } from "@eventra_dev/eventra-sdk";
const tracker = new Eventra({ apiKey: "YOUR_PROJECT_API_KEY" });
tracker.track("checkout.started");
</script><script> + <script setup> in the same file are merged in source order. defineProps/defineEmits/defineExpose/defineOptions/withDefaults pass through untouched.
<template> — literal event attributes
<template>
<Button event="checkout.cta" />
</template><template> — dynamic event attributes
<template>
<Button :event="computedEventName" />
</template>The expression is copied as-is into the same module scope as the script. If it resolves to a real script-level constant, the event name is detected normally; otherwise it's reported as a dynamic occurrence (same mechanism as tracker.track(someVariable) in plain TypeScript) instead of being silently dropped.
External blocks
<script src="./logic.ts"> and <template src="./view.html"> are resolved and read from disk.
Nuxt
Nuxt pages, layouts, and components are ordinary .vue SFCs — parsed identically, no extra configuration needed.
Composables auto-imported without an explicit import statement (Nuxt's own composables, or your own from composables//utils/) are intended to resolve once the project has run nuxt prepare/nuxt dev (so .nuxt/ exists and is wired into tsconfig.json — the CLI analyzes the project's real tsconfig.json, so Nuxt's generated ambient types are visible to it like any other TypeScript project). The host CLI's resolver understands the declare const x: typeof import("./module")["name"] shape Nuxt/unplugin-auto-import generate for these bindings (verified against a hand-written fixture reproducing that ambient shape) — but running a real nuxt prepare/nuxt build end-to-end has not been verified in this environment (blocked by a sandbox GLIBC incompatibility with Nuxt's native build tooling), so this is not confirmed against a real generated .nuxt/imports.d.ts.
Configuration
No plugin-specific config — it activates purely by being listed in eventra.json's plugins array (see Installation).
Plugin contract
export interface CliPluginVue {
readonly id: string;
readonly version: string;
readonly includeGlobs: readonly string[];
readonly staticSinks?: readonly CliPluginStaticCalleeSink[];
match(path: string): boolean;
transform(input: { path: string; source: string }): Promise<{
modules: Array<{ path: string; content: string }>;
}>;
}No dependency on @eventra_dev/eventra-cli — the CLI adapts this shape internally. .vue → one virtual .vue.ts module (compiled script content, then a function wrapping synthetic calls for every template event="..." binding). staticSinks describes those synthetic calls; the CLI builds its own sink detector from them. See @eventra_dev/eventra-cli's plugin docs for the full external-plugin contract.
Requirements
- Node.js 18+
@eventra_dev/eventra-clias the host CLI
Test Coverage
100% statement/branch/function/line coverage (v8 provider, pnpm test:coverage), enforced via a coverage.thresholds block in vitest.config.ts.
20 unit tests (vitest), covering:
| Area | Covers |
|---|---|
| SFC parsing | Script + script-setup merge order, comment safety, src= external files |
| Template — literal | Nested elements, v-if/v-for, slots, multiple template roots |
| Template — dynamic | Raw expression passthrough, resolution through the merged script scope |
| Script-setup macros | All five compiler macros (defineProps/defineEmits/defineExpose/defineOptions/withDefaults) pass through without special-casing |
| Virtual module output | Single combined .vue.ts, export stub when script/template are empty |
| Plugin contract | match(), includeGlobs, staticSinks, transform() |
The Nuxt ambient auto-import shape (declare const x: typeof import(...)) is covered by a unit test in the host CLI that hand-writes that shape — this is not the same as an end-to-end run against a real nuxt prepare/nuxt build, which has not been verified in this environment (see the Nuxt section above).
Run locally:
pnpm --filter @eventra_dev/cli-plugin-vue test
pnpm --filter @eventra_dev/cli-plugin-vue test:coverageLicense
MIT
