Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: add DevTools integration and update dependencies #50

Merged
merged 1 commit into from
Dec 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/nuxt/client/app.vue
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
<script lang="ts" setup>
</script>

<template>
<NuxtLayout>
<NuxtPage />
Expand Down
18 changes: 18 additions & 0 deletions packages/nuxt/client/composables/rpc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { onDevtoolsClientConnected } from '@nuxt/devtools-kit/iframe-client'
import type { BirpcReturn } from 'birpc'
import { ref } from 'vue'
import type { NuxtDevtoolsClient } from '@nuxt/devtools-kit/dist/types'
import type { ClientFunctions, ServerFunctions } from '../../src/types'
import { DEVTOOLS_RPC_NAMESPACE } from '../../src/constants'

export const devtools = ref<NuxtDevtoolsClient>()
export const devtoolsRpc = ref<NuxtDevtoolsClient['rpc']>()
export const rpc = ref<BirpcReturn<ServerFunctions, ClientFunctions>>()

onDevtoolsClientConnected(async (client) => {
devtoolsRpc.value = client.devtools.rpc
devtools.value = client.devtools

rpc.value = client.devtools.extendClientRpc<ServerFunctions, ClientFunctions>(DEVTOOLS_RPC_NAMESPACE, {
})
})
4 changes: 4 additions & 0 deletions packages/nuxt/client/composables/state.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { ref } from 'vue'
import type { ModuleOptions } from '../../src/module'

export const options = ref<ModuleOptions>()
3 changes: 2 additions & 1 deletion packages/nuxt/client/nuxt.config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { resolve } from 'pathe'
import { DEVTOOLS_UI_PATH } from '../src/constants'

export default defineNuxtConfig({
ssr: false,
Expand All @@ -11,6 +12,6 @@ export default defineNuxtConfig({
},
},
app: {
baseURL: '/__pergel',
baseURL: DEVTOOLS_UI_PATH,
},
})
82 changes: 20 additions & 62 deletions packages/nuxt/client/pages/index.vue
Original file line number Diff line number Diff line change
@@ -1,75 +1,33 @@
<script setup lang="ts">
import { onDevtoolsClientConnected, useDevtoolsClient } from '@nuxt/devtools-kit/iframe-client'
import type { ClientFunctions, ServerFunctions } from '../../src/rpc-types'
<script lang="ts" setup>
import { useDevtoolsClient } from '@nuxt/devtools-kit/iframe-client'

import { rpc } from '../composables/rpc'
import { options } from '../composables/state'

const client = useDevtoolsClient()
onDevtoolsClientConnected(async (client) => {
const rpc = client.devtools.extendClientRpc<ServerFunctions, ClientFunctions>('pergel-rpc', {
showNotification: (message) => {
console.log('showNotification')
console.log('showNotification', message)
},
})
const dd = await rpc.getMyModuleOptions()
console.log(dd)
})

async function getOptions() {
options.value = await rpc.value?.getOptions()
console.warn(client.value, 'client')
}
</script>

<template>
<NSectionBlock
icon="carbon-3d-mpr-toggle"
text="Active Modules"
container-class="grid grid-cols-minmax-400px gap3 px4"
:padding="false"
description="Total modules: "
>
asdasdas
</NSectionBlock>
<div class="relative p-10 n-bg-base flex flex-col h-screen">
<h1 class="text-3xl font-bold">
Pergel Module
My Module
</h1>
<div class="opacity-50 mb-4">
Powered by oku
</div>
<div
v-if="client"
class="flex flex-col gap-2"
>
<NTip
n="green"
icon="carbon-checkmark"
>
Nuxt DevTools is connected
</NTip>
<div>
The current app is using
<code class="text-green">vue@{{ client.host.nuxt.vueApp.version }}</code>
</div>
<div>
<NButton
n="green"
class="mt-4"
@click="client!.host.devtools.close()"
>
Close DevTools
</NButton>
</div>
Nuxt DevTools Integration
</div>
<div v-else>
<NTip n="yellow">
Failed to connect to the client. Did you open this page inside Nuxt DevTools?
</NTip>
</div>

<NuxtLink
to="/s3"
class="absolute top-0 right-0 p-4"
>
Go to S3
</NuxtLink>
<div flex="~ gap-2">
<NButton n="green" class="mt-4" @click="client!.host.devtools.close()">
Close DevTools
</NButton>

<div class="flex-auto" />
<ModuleAuthorNote class="mt-5 " />
<NButton n="green" class="mt-4" @click="getOptions()">
Get DevTools Options
</NButton>
</div>
</div>
</template>
5 changes: 4 additions & 1 deletion packages/nuxt/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,16 @@
"client:dev": "nuxi dev client --port 3300"
},
"dependencies": {
"@nuxt/devtools": "^1.0.5",
"@nuxt/devtools-kit": "^1.0.5",
"@nuxt/kit": "^3.8.2",
"@vueuse/core": "^10.7.0",
"defu": "^6.1.3",
"pathe": "^1.1.1",
"sirv": "^2.0.3"
},
"devDependencies": {
"@iconify-json/carbon": "^1.1.24",
"@nuxt/devtools": "^1.0.5",
"@nuxt/devtools-ui-kit": "^1.0.5",
"@nuxt/module-builder": "^0.5.4",
"@nuxt/schema": "^3.8.2",
Expand Down
13 changes: 9 additions & 4 deletions packages/nuxt/playground/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ import { resolve } from 'node:path'
import { defineNuxtModule } from '@nuxt/kit'
import { startSubprocess } from '@nuxt/devtools-kit'

import { DEVTOOLS_UI_PORT } from '../src/constants'

export default defineNuxtConfig({
devtools: {
enabled: true,
},
modules: [
'@nuxt/devtools',
/**
* My module
*/
Expand All @@ -22,16 +26,17 @@ export default defineNuxtConfig({
const subprocess = startSubprocess(
{
command: 'npx',
args: ['nuxi', 'dev', '--port', '3300'],
args: ['nuxi', 'dev', '--port', DEVTOOLS_UI_PORT.toString()],
cwd: resolve(__dirname, '../client'),
},
{
id: 'pergel:client',
name: 'My Module Client Dev',
id: 'nuxt-pergel:client',
name: 'Pergel Devtools RPC Client',
},
)

subprocess.getProcess().stdout?.on('data', (data) => {
// eslint-disable-next-line no-console
console.log(` sub: ${data.toString()}`)
})

Expand Down
8 changes: 8 additions & 0 deletions packages/nuxt/src/constants/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export const DEVTOOLS_UI_PATH = '/__nuxt-pergel-rpc'
export const DEVTOOLS_UI_PORT = 3300
export const DEVTOOLS_RPC_NAMESPACE = 'nuxt-pergel-rpc'

export const DEVTOOLS_MODULE_NAME = 'nuxt-pergel'
export const DEVTOOLS_MODULE_KEY = 'pergel'
export const DEVTOOLS_MODULE_TITLE = 'Pergel'
export const DEVTOOLS_MODULE_ICON = 'carbon:hinton-plot'
59 changes: 41 additions & 18 deletions packages/nuxt/src/devtools.ts
Original file line number Diff line number Diff line change
@@ -1,50 +1,73 @@
import { existsSync } from 'node:fs'
import type { Nuxt } from 'nuxt/schema'
import type { Resolver } from '@nuxt/kit'
import {
extendServerRpc,
onDevToolsInitialized,
} from '@nuxt/devtools-kit'
import type {
ClientFunctions,
ServerFunctions,
} from './types'
import type { ModuleOptions } from './module'
import { useViteWebSocket } from './utils'

const DEVTOOLS_UI_ROUTE = '/__pergel'
const DEVTOOLS_UI_LOCAL_PORT = 3300
import { setupRPC } from './rpc'
import {
DEVTOOLS_MODULE_ICON,
DEVTOOLS_MODULE_NAME,
DEVTOOLS_MODULE_TITLE,
DEVTOOLS_RPC_NAMESPACE,
DEVTOOLS_UI_PATH,
DEVTOOLS_UI_PORT,
} from './constants'

export function setupDevToolsUI(nuxt: Nuxt, resolver: Resolver) {
const clientPath = resolver.resolve('./client')
export function setupDevToolsUI(
options: ModuleOptions,
resolve: Resolver['resolve'],
nuxt: Nuxt,
) {
const clientPath = resolve('./client')
const isProductionBuild = existsSync(clientPath)
// Serve production-built client (used when package is published)

if (isProductionBuild) {
nuxt.hook('vite:serverCreated', async (server) => {
const sirv = await import('sirv').then(r => r.default || r)
server.middlewares.use(
DEVTOOLS_UI_ROUTE,
DEVTOOLS_UI_PATH,
sirv(clientPath, { dev: true, single: true }),
)
})
}
// In local development, start a separate Nuxt Server and proxy to serve the client
else {
nuxt.hook('vite:extendConfig', (config) => {
config.server = config.server || {}
config.server.proxy = config.server.proxy || {}
config.server.proxy[DEVTOOLS_UI_ROUTE] = {
target: `http://localhost:${DEVTOOLS_UI_LOCAL_PORT}${DEVTOOLS_UI_ROUTE}`,
config.server.proxy[DEVTOOLS_UI_PATH] = {
target: `http://localhost:${DEVTOOLS_UI_PORT}${DEVTOOLS_UI_PATH}`,
changeOrigin: true,
followRedirects: true,
rewrite: path => path.replace(DEVTOOLS_UI_ROUTE, ''),
rewrite: path => path.replace(DEVTOOLS_UI_PATH, ''),
}
})
}

nuxt.hook('devtools:customTabs', (tabs) => {
tabs.push({
// unique identifier
name: 'pergel',
// title to display in the tab
title: 'Pergel',
// any icon from Iconify, or a URL to an image
icon: 'carbon:apps',
// iframe view
name: DEVTOOLS_MODULE_NAME,
title: DEVTOOLS_MODULE_TITLE,
icon: DEVTOOLS_MODULE_ICON,
view: {
type: 'iframe',
src: DEVTOOLS_UI_ROUTE,
src: DEVTOOLS_UI_PATH,
},
})
})

const wsServer = useViteWebSocket(nuxt)
onDevToolsInitialized(async () => {
const rpcFunctions = setupRPC({ options, wsServer, nuxt })

extendServerRpc<ClientFunctions, ServerFunctions>(DEVTOOLS_RPC_NAMESPACE, rpcFunctions)
})
}
59 changes: 19 additions & 40 deletions packages/nuxt/src/module.ts
Original file line number Diff line number Diff line change
@@ -1,51 +1,30 @@
import { addPlugin, createResolver, defineNuxtModule } from '@nuxt/kit'
import { extendServerRpc, onDevToolsInitialized } from '@nuxt/devtools-kit'
import type { BirpcGroup } from 'birpc'
import {
createResolver,
defineNuxtModule,
logger,
} from '@nuxt/kit'
import { setupDevToolsUI } from './devtools'
import type { ModuleOptions } from './moduleType'
import type { ClientFunctions, ServerFunctions } from './rpc-types'
import { DEVTOOLS_MODULE_KEY, DEVTOOLS_MODULE_NAME } from './constants'

export interface ModuleOptions {
}

export default defineNuxtModule<ModuleOptions>({
meta: {
name: 'pergel',
configKey: 'pergel',
},
// Default configuration options of the Nuxt module
defaults: {
devtools: true,
test: 'test',
name: DEVTOOLS_MODULE_NAME,
configKey: DEVTOOLS_MODULE_KEY,
},
defaults: {},
async setup(options, nuxt) {
const resolver = createResolver(import.meta.url)

// Do not add the extension since the `.ts` will be transpiled to `.mjs` after `npm run prepack`
addPlugin(resolver.resolve('./runtime/plugin'))

let rpc: BirpcGroup<ClientFunctions, ServerFunctions> | undefined
if (options.devtools) {
setupDevToolsUI(nuxt, resolver)
const { resolve } = createResolver(import.meta.url)

const RPC_NAMESPACE = 'pergel-rpc'
const isDevToolsEnabled = typeof nuxt.options.devtools === 'boolean'
? nuxt.options.devtools
: nuxt.options.devtools.enabled

const setupRpc = () => {
rpc = extendServerRpc<ClientFunctions, ServerFunctions>(RPC_NAMESPACE, {
// register server RPC functions
getMyModuleOptions() {
return options
},
})
}
if (nuxt.options.dev && isDevToolsEnabled)
setupDevToolsUI(options, resolve, nuxt)

try {
setupRpc()
}
catch (error) {
// wait for DevTools to be initialized
onDevToolsInitialized(async () => {
setupRpc()
})
}
await rpc?.broadcast.showNotification('Hello from Nuxt module!')
}
logger.success(`${DEVTOOLS_MODULE_NAME} is ready!`)
},
})
10 changes: 0 additions & 10 deletions packages/nuxt/src/moduleType.ts

This file was deleted.

9 changes: 0 additions & 9 deletions packages/nuxt/src/rpc-types.ts

This file was deleted.

Loading