Skip to content

Commit

Permalink
feat(tpc): build-time third-party-capital composables (#81)
Browse files Browse the repository at this point in the history
Co-authored-by: Julien Huang <julien.huang@leetchi.com>
  • Loading branch information
huang-julien and Julien Huang committed Jun 12, 2024
1 parent e9af679 commit 1b7d96d
Show file tree
Hide file tree
Showing 13 changed files with 1,695 additions and 296 deletions.
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@
"@unhead/vue",
"@unhead/schema",
"#nuxt-scripts",
"#nuxt-scripts-validator"
"#nuxt-scripts-validator",
"third-party-capital",
"knitwork"
]
},
"dependencies": {
Expand All @@ -81,7 +83,7 @@
"shiki": "^1.6.2",
"sirv": "^2.0.4",
"std-env": "^3.7.0",
"third-party-capital": "^1.0.28",
"third-party-capital": "^1.0.30",
"ufo": "^1.5.3",
"unimport": "^3.7.2",
"unplugin": "^1.10.1",
Expand All @@ -99,6 +101,7 @@
"bumpp": "^9.4.1",
"changelogen": "^0.5.5",
"eslint": "9.4.0",
"knitwork": "^1.1.0",
"nuxt": "^3.11.2",
"playwright-core": "^1.44.1",
"typescript": "^5.4.5",
Expand Down
2 changes: 1 addition & 1 deletion playground/pages/third-parties/google-tag-manager.vue
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ $script.then(({ google_tag_manager, dataLayer }) => {
<div>
<ClientOnly>
<div>
status: {{ $script.status.value }}
status: {{ $script.status }}
</div>
</ClientOnly>
</div>
Expand Down
1,472 changes: 1,314 additions & 158 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

14 changes: 13 additions & 1 deletion src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import type {
RegistryScript,
RegistryScripts,
} from './runtime/types'
import addGoogleAnalyticsRegistry from './tpc/google-analytics'
import addGoogleTagManagerRegistry from './tpc/google-tag-manager'

export interface ModuleOptions {
/**
Expand Down Expand Up @@ -74,6 +76,12 @@ export interface ModuleHooks {
'scripts:registry': (registry: RegistryScripts) => void | Promise<void>
}

declare module '@nuxt/schema' {
interface NuxtHooks {
'scripts:registry': ModuleHooks['scripts:registry']
}
}

export default defineNuxtModule<ModuleOptions>({
meta: {
name: '@nuxt/scripts',
Expand Down Expand Up @@ -125,9 +133,13 @@ export default defineNuxtModule<ModuleOptions>({
})

const scripts = registry(resolve)

addGoogleAnalyticsRegistry()
addGoogleTagManagerRegistry()

nuxt.hooks.hook('modules:done', async () => {
const registryScripts = [...scripts]
// @ts-expect-error runtime

await nuxt.hooks.callHook('scripts:registry', registryScripts)
const withComposables = registryScripts.filter(i => !!i.import?.name) as Required<RegistryScript>[]
addImports(withComposables.map((i) => {
Expand Down
25 changes: 1 addition & 24 deletions src/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,15 @@ import type { IntercomInput } from './runtime/registry/intercom'
import type { SegmentInput } from './runtime/registry/segment'
import type { NpmInput } from './runtime/registry/npm'
import type { PlausibleAnalyticsInput } from './runtime/registry/plausible-analytics'
import type { GoogleAnalyticsInput } from './runtime/registry/google-analytics'
import type { RegistryScripts } from './runtime/types'
import type { GoogleAdsenseInput } from './runtime/registry/google-adsense'

// avoid nuxt/kit dependency here so we can use in docs

export const registry: (resolve?: (s: string) => string) => RegistryScripts = (resolve?: (s: string) => string) => {
resolve = resolve || ((s: string) => s)

return [
// analytics
{
label: 'Google Analytics',
category: 'analytics',
logo: `<svg xmlns="http://www.w3.org/2000/svg" width="28.85" height="32" viewBox="0 0 256 284"><path fill="#F9AB00" d="M256.003 247.933a35.224 35.224 0 0 1-39.376 35.161c-18.044-2.67-31.266-18.371-30.826-36.606V36.845C185.365 18.591 198.62 2.881 216.687.24a35.221 35.221 0 0 1 39.316 35.16z"/><path fill="#E37400" d="M35.101 213.193c19.386 0 35.101 15.716 35.101 35.101c0 19.386-15.715 35.101-35.101 35.101S0 267.68 0 248.295c0-19.386 15.715-35.102 35.101-35.102m92.358-106.387c-19.477 1.068-34.59 17.406-34.137 36.908v94.285c0 25.588 11.259 41.122 27.755 44.433a35.161 35.161 0 0 0 42.146-34.56V142.089a35.222 35.222 0 0 0-35.764-35.282"/></svg>`,
scriptBundling: (options?: GoogleAnalyticsInput) => withQuery('https://www.googletagmanager.com/gtag/js', {
id: options?.id,
}),
import: {
name: 'useScriptGoogleAnalytics',
from: resolve('./runtime/registry/google-analytics'),
},
},
{
label: 'Plausible Analytics',
category: 'analytics',
Expand Down Expand Up @@ -69,16 +56,6 @@ export const registry: (resolve?: (s: string) => string) => RegistryScripts = (r
from: resolve('./runtime/registry/matomo-analytics'),
},
},
// tracking
{
label: 'Google Tag Manager',
category: 'tracking',
logo: `<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 256 256"><path fill="#8AB4F8" d="m150.262 245.516l-44.437-43.331l95.433-97.454l46.007 45.091z"/><path fill="#4285F4" d="M150.45 53.938L106.176 8.731L9.36 104.629c-12.48 12.48-12.48 32.713 0 45.207l95.36 95.986l45.09-42.182l-72.654-76.407z"/><path fill="#8AB4F8" d="m246.625 105.37l-96-96c-12.494-12.494-32.756-12.494-45.25 0c-12.495 12.495-12.495 32.757 0 45.252l96 96c12.494 12.494 32.756 12.494 45.25 0c12.495-12.495 12.495-32.757 0-45.251"/><circle cx="127.265" cy="224.731" r="31.273" fill="#246FDB"/></svg>`,
import: {
name: 'useScriptGoogleTagManager',
from: resolve('./runtime/registry/google-tag-manager'),
},
},
{
label: 'Segment',
scriptBundling: (options?: SegmentInput) => {
Expand Down
59 changes: 0 additions & 59 deletions src/runtime/registry/google-analytics.ts

This file was deleted.

49 changes: 0 additions & 49 deletions src/runtime/registry/google-tag-manager.ts

This file was deleted.

4 changes: 2 additions & 2 deletions src/runtime/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@ import type { MetaPixelInput } from './registry/meta-pixel'
import type { FathomAnalyticsInput } from './registry/fathom-analytics'
import type { HotjarInput } from './registry/hotjar'
import type { IntercomInput } from './registry/intercom'
import type { GoogleAnalyticsInput } from './registry/google-analytics'
import type { GoogleMapsInput } from './registry/google-maps'
import type { GoogleTagManagerInput } from './registry/google-tag-manager'
import type { MatomoAnalyticsInput } from './registry/matomo-analytics'
import type { StripeInput } from './registry/stripe'
import type { VimeoPlayerInput } from './registry/vimeo-player'
Expand All @@ -21,6 +19,8 @@ import type { YouTubePlayerInput } from './registry/youtube-player'
import type { PlausibleAnalyticsInput } from './registry/plausible-analytics'
import type { NpmInput } from './registry/npm'
import type { LemonSqueezyInput } from './registry/lemon-squeezy'
import type { Input as GoogleTagManagerInput } from '#build/nuxt-scripts/tpc/google-tag-manager'
import type { Input as GoogleAnalyticsInput } from '#build/nuxt-scripts/tpc/google-analytics'

export type NuxtUseScriptOptions<T = any> = Omit<UseScriptOptions<T>, 'trigger'> & {
/**
Expand Down
54 changes: 54 additions & 0 deletions src/tpc/google-analytics.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { addImports, addTemplate, useNuxt } from '@nuxt/kit'
import type { Output } from 'third-party-capital'
import { GooglaAnalyticsData, GoogleAnalytics } from 'third-party-capital'
import type { RegistryScript } from '../runtime/types'
import { getTpcScriptContent } from './utils'

export default function googleAnalitycsRegistry() {
const nuxt = useNuxt()
const { dst } = addTemplate({
getContents() {
return getTpcScriptContent({
data: GooglaAnalyticsData as Output,
scriptFunctionName: 'useScriptGoogleAnalytics',
use: () => {
return { dataLayer: window.dataLayer, gtag: window.gtag }
},
// allow dataLayer to be accessed on the server
stub: ({ fn }) => {
return fn === 'dataLayer' ? [] : undefined
},
tpcKey: 'gtag',
tpcTypeImport: 'GoogleAnalyticsApi',
augmentWindowTypes: true,
})
},
filename: 'nuxt-scripts/tpc/google-analytics.ts',
})

addImports({
from: dst,
name: 'useScriptGoogleAnalytics',
})
const registry: RegistryScript = {
label: 'Google Tag Manager',
category: 'tracking',
logo: `<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 256 256"><path fill="#8AB4F8" d="m150.262 245.516l-44.437-43.331l95.433-97.454l46.007 45.091z"/><path fill="#4285F4" d="M150.45 53.938L106.176 8.731L9.36 104.629c-12.48 12.48-12.48 32.713 0 45.207l95.36 95.986l45.09-42.182l-72.654-76.407z"/><path fill="#8AB4F8" d="m246.625 105.37l-96-96c-12.494-12.494-32.756-12.494-45.25 0c-12.495 12.495-12.495 32.757 0 45.252l96 96c12.494 12.494 32.756 12.494 45.25 0c12.495-12.495 12.495-32.757 0-45.251"/><circle cx="127.265" cy="224.731" r="31.273" fill="#246FDB"/></svg>`,
import: {
name: 'useScriptGoogleAnalytics',
from: dst,
},
scriptBundling(options) {
const data = GoogleAnalytics(options)
const mainScript = data.scripts?.find(({ key }) => key === 'gtag')

if (mainScript && 'url' in mainScript && mainScript.url)
return mainScript.url

return false
},
}
nuxt.hook('scripts:registry', (scripts) => {
scripts.push(registry)
})
}
57 changes: 57 additions & 0 deletions src/tpc/google-tag-manager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { addImports, addTemplate, useNuxt } from '@nuxt/kit'
import type { Output } from 'third-party-capital'
import { GoogleTagManager, GoogleTagManagerData } from 'third-party-capital'

import type { RegistryScript } from '../runtime/types'
import { getTpcScriptContent } from './utils'

export default function googleTagManagerRegistry() {
const nuxt = useNuxt()

const { dst } = addTemplate({
getContents() {
return getTpcScriptContent({
data: GoogleTagManagerData as Output,
scriptFunctionName: 'useScriptGoogleTagManager',
use: () => {
return { dataLayer: window.dataLayer, google_tag_manager: window.google_tag_manager }
},
stub: ({ fn }) => {
return fn === 'dataLayer' ? [] : undefined
},
tpcKey: 'gtm',
tpcTypeImport: 'GoogleTagManagerApi',
augmentWindowTypes: true,
})
},
filename: 'nuxt-scripts/tpc/google-tag-manager.ts',
})

addImports({
from: dst,
name: 'useScriptGoogleTagManager',
})

const registry: RegistryScript = {
label: 'Google Tag Manager',
category: 'tracking',
logo: `<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 256 256"><path fill="#8AB4F8" d="m150.262 245.516l-44.437-43.331l95.433-97.454l46.007 45.091z"/><path fill="#4285F4" d="M150.45 53.938L106.176 8.731L9.36 104.629c-12.48 12.48-12.48 32.713 0 45.207l95.36 95.986l45.09-42.182l-72.654-76.407z"/><path fill="#8AB4F8" d="m246.625 105.37l-96-96c-12.494-12.494-32.756-12.494-45.25 0c-12.495 12.495-12.495 32.757 0 45.252l96 96c12.494 12.494 32.756 12.494 45.25 0c12.495-12.495 12.495-32.757 0-45.251"/><circle cx="127.265" cy="224.731" r="31.273" fill="#246FDB"/></svg>`,
import: {
name: 'useScriptGoogleTagManager',
from: dst,
},
scriptBundling(options) {
const data = GoogleTagManager(options)
const mainScript = data.scripts?.find(({ key }) => key === 'gtm')

if (mainScript && 'url' in mainScript && mainScript.url)
return mainScript.url

return false
},
}

nuxt.hook('scripts:registry', (scripts) => {
scripts.push(registry)
})
}
Loading

0 comments on commit 1b7d96d

Please sign in to comment.