Refactoring Nuxt plugin

This commit is contained in:
Jarek Rozanski 2025-01-29 01:01:34 +01:00
parent 842cc6f499
commit c315cc2bcc
12 changed files with 122 additions and 109 deletions

View file

@ -87,11 +87,21 @@ export default defineNuxtConfig({
# Usage # Usage
The Wide Angle Analytics provides an instance of `waa` which can be then injected to your component. The Wide Angle Analytics provides a composable which can be used in your component.
```javascript ```javascript
const waa = useWaa(); <template>
waa.dispatchEvent('purchase', {'basket_element': 'dress'}, {'basket_item_price': 123.44}); <button @click="sendEvent">Send Event</button>
</template>
<script setup>
import { useWideAngle } from '#imports';
const sendEvent = () => {
useWideAngle().dispatchEvent('basket-open', {'page': 'catalogue'}, {'item-price': 599.00, 'basket-total': 1299.00});
}
</script>
``` ```
You will find a fully functional example in this [repository](playground/app.vue). You will find a fully functional example in this [repository](playground/app.vue).
@ -132,16 +142,14 @@ Example:
</template> </template>
<script setup> <script setup>
import { useWaa } from '#imports' import { useWideAngle } from '#imports'
const waa = useWaa();
const sendEvent = async () => { const sendEvent = async () => {
const params = { const params = {
session: 'cjhw92nf9aq', session: 'cjhw92nf9aq',
cohort: 'c1233' cohort: 'c1233'
} }
waa.dispatchEvent('interest', params); useWideAngle().dispatchEvent('interest', params);
} }
</script> </script>
``` ```
@ -196,9 +204,9 @@ Example usage:
```vue ```vue
<script setup> <script setup>
import { useWaa } from '#imports' import { useWideAngle } from '#imports'
const waa = useWaa(); const waa = useWideAngle();
waa.recordConsent('FHJ44111'); waa.recordConsent('FHJ44111');

View file

@ -34,8 +34,9 @@
"dev": "nuxi dev playground", "dev": "nuxi dev playground",
"dev:build": "nuxi build playground", "dev:build": "nuxi build playground",
"dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground", "dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground",
"release": "npm run lint && npm run prepack && changelogen --release && npm publish && git push --follow-tags", "release": "npm lint && npm test && npm prepack && changelogen --release && npm publish && git push --follow-tags",
"lint": "eslint ." "lint": "eslint .",
"lint:fix": "eslint . --fix"
}, },
"dependencies": { "dependencies": {
"@nuxt/kit": "^3.13.2", "@nuxt/kit": "^3.13.2",
@ -43,10 +44,10 @@
"defu": "^6.1.2" "defu": "^6.1.2"
}, },
"devDependencies": { "devDependencies": {
"@nuxt/eslint-config": "^0.7.4", "@nuxt/devtools": "latest",
"@nuxt/module-builder": "^0.8.4", "@nuxt/eslint-config": "^0.3.13",
"@nuxt/schema": "^3.13.2", "@nuxt/module-builder": "^0.8.1",
"@nuxt/test-utils": "^3.12.0", "@nuxt/schema": "^3.12.4",
"@types/node": "^18", "@types/node": "^18",
"changelogen": "^0.5.3", "changelogen": "^0.5.3",
"eslint": "^9.17.0", "eslint": "^9.17.0",

View file

@ -1,36 +0,0 @@
<template>
<main>
<h1>Nuxt Application</h1>
<button @click="trackClick">
Track Click
</button>
</main>
</template>
<script setup lang="ts">
import { useWaaEvent } from "#imports";
function trackClick() {
useWaaEvent("foo", {"name": "bar"}, {"count" : 2});
}
</script>
<style>
main {
font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
font-size: 2rem;
display: flex;
flex-direction: column;
max-width: 300px;
gap: 2rem;
align-items: center;
margin: 0 auto;
text-align: center;
}
button {
padding: 1rem;
}
</style>

View file

@ -0,0 +1,11 @@
<template>
<button @click="sendEvent">Send Event</button>
</template>
<script setup>
import { useWideAngle } from '#imports';
const sendEvent = () => {
useWideAngle().dispatchEvent('foo', {'param1': 'bar'}, {'value1': 123});
}
</script>

View file

@ -1,12 +1,17 @@
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({ export default defineNuxtConfig({
modules: ['../src/module'], devtools: { enabled: true },
compatibilityDate: "2025-01-28",
modules: ['wideangle-nuxt'],
// ssr: false,
runtimeConfig: { runtimeConfig: {
public: { public: {
wideangle: { wideangle: {
siteId: "7982G3B9ACB1BF4380", siteId: "8D27G3B9ACA01F4241",
fingerprint: true, domain: "events.wideangle.test",
supressDnt: true fingerprint: false,
suppressDnt: true
} }
} }
} }
}); })

View file

@ -1,4 +0,0 @@
{
"private": true,
"name": "wideangle-playground"
}

View file

@ -0,0 +1,7 @@
<template>
<div>
<h1>Wide Angle Analytics Playground</h1>
<sample-tracker/>
</div>
</template>

View file

@ -1,6 +1,5 @@
import { defineNuxtModule, addPlugin, addImports, createResolver, useLogger } from '@nuxt/kit' import { defineNuxtModule, addPlugin, addImportsDir, createResolver, useLogger } from '@nuxt/kit'
import { defu } from 'defu' import { defu } from 'defu'
import { fileURLToPath } from 'url'
const logger = useLogger('nuxt:wideangle') const logger = useLogger('nuxt:wideangle')
@ -20,40 +19,32 @@ export default defineNuxtModule<ModuleOptions>({
name: 'wideangle', name: 'wideangle',
configKey: 'wideangle', configKey: 'wideangle',
compatibility: { compatibility: {
nuxt: '>=3' nuxt: '>=3',
} },
}, },
defaults: { defaults: {
domain: "stats.wideangle.co", domain: 'stats.wideangle.co',
fingerprint: false, fingerprint: false,
suppressDnt: false, suppressDnt: false,
includeParams: [], includeParams: [],
excludePaths: [], excludePaths: [],
ignoreHash: false, ignoreHash: false,
consentMarker: null consentMarker: undefined,
}, },
setup (options, nuxt) { setup(options, nuxt) {
const runtimeDir = fileURLToPath(new URL('./runtime', import.meta.url)) const resolver = createResolver(import.meta.url)
nuxt.options.runtimeConfig.public.wideangle = defu( nuxt.options.runtimeConfig.public.wideangle = defu(
nuxt.options.runtimeConfig.public.wideangle, nuxt.options.runtimeConfig.public.wideangle,
options, options,
) )
nuxt.options.build.transpile.push(runtimeDir); nuxt.options.build.transpile.push(resolver.resolve('./runtime'))
const resolver = createResolver(import.meta.url);
logger.info('Adding Wide Angle Analytics runtime plugin'); logger.info('Adding Wide Angle Analytics (useWideAngle) import')
addImportsDir(resolver.resolve('./runtime/composables'))
addImports({ logger.info('Adding Wide Angle Analytics runtime plugin')
name: "useWaaEvent", addPlugin(resolver.resolve('./runtime/plugin.client'))
as: "useWaaEvent",
from: resolver.resolve('./runtime/composables/useWaaEvent')
});
addPlugin({ },
src: resolver.resolve('./runtime/plugin.client')
});
}
}) })

View file

@ -1,8 +0,0 @@
import { useNuxtApp } from '#imports';
function useWaa() {
const waa = useNuxtApp().$waa;
return waa.value;
}
export useWaa;

View file

@ -0,0 +1,27 @@
import {useNuxtApp} from '#imports'
import type {WideAngleApi} from "~/src/types";
class NoOpWideAngleAnalyticsApi implements WideAngleApi {
dispatchEvent(name: string, params: any, values: any): void {
console.debug(`[WideAngleApi#dispatchEvent] Defaulting to NoOp Wide Angle call with name "${name}", params: ${JSON.stringify(params)}, values: ${JSON.stringify(params)}`);
}
recordConsent(subjectsId: string): void {
console.debug(`[WideAngleApi#recordConsent] Defaulting to NoOp Wide Angle call with ${subjectsId}`);
}
revokeConsent() {
console.debug(`[WideAngleApi#revokeConsent] Defaulting to NoOp Wide Angle call`);
}
}
const noOpWideAngleApi = new NoOpWideAngleAnalyticsApi();
export function useWideAngle() {
const { $waa } = useNuxtApp()
if ($waa) {
return $waa.value;
} else {
return noOpWideAngleApi;
}
}

View file

@ -1,30 +1,36 @@
import { defineNuxtPlugin, useRuntimeConfig } from '#imports'; import { type Ref, ref} from 'vue'
import { ref } from 'vue'; import { initWideAngle } from 'wideangle-vuejs'
import { initWideAngle } from 'wideangle-vuejs'; import { defineNuxtPlugin, type NuxtApp } from '#app'
import { useRuntimeConfig } from "#imports";
import type { WideAngleApi } from "~/src/types";
export default defineNuxtPlugin(() => { export default defineNuxtPlugin(async (_nuxtApp) => {
if(import.meta.server) {
console.warn("[WAA] Plugin will not be enabled on server side."); if (import.meta.server) {
return; console.warn('[WAA] Plugin will not be enabled on server side.')
return
} }
const { wideangle: options } = useRuntimeConfig().public const { wideangle: options } = useRuntimeConfig().public
console.debug(`[WAA] Initializing Wide Angle Analytics with: ${JSON.stringify(options)}`); console.debug(`[WAA] Initializing Wide Angle Analytics with: ${JSON.stringify(options)}`)
if(options.siteId == null) {
throw new Error("[WAA] Wide Angle Analytics requires the site ID."); if (options.siteId == null) {
throw new Error('[WAA] Wide Angle Analytics requires the site ID.')
} }
const waa = ref() const waa = ref()
initWideAngle(options) initWideAngle(options)
.then(waaInstance => { .then((waaInstance) => {
waa.value = waaInstance; waa.value = waaInstance
console.debug("[WAA] Wide Angle Analytics instance available"); console.debug('[WAA] Wide Angle Analytics instance available')
}).catch(e => { console.error("[WAA] Failed to load Wide Angle Plugin", e)}); }).catch((e) => {
console.error('[WAA] Failed to load Wide Angle Plugin', e)
})
return { return {
provide: { provide: {
waa waa: waa as Ref<WideAngleApi>,
} },
} }
}) })

5
src/types.ts Normal file
View file

@ -0,0 +1,5 @@
export interface WideAngleApi {
dispatchEvent(name: string, params: any, values: any) : void;
recordConsent(subjectsId: string) : void;
revokeConsent() : void;
}