Thanks to visit codestin.com
Credit goes to github.com

Skip to content
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
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@
"db0": "^0.3.2",
"defu": "^6.1.4",
"destr": "^2.0.5",
"execa": "^9.6.0",
"get-port-please": "^3.2.0",
"h3": "^1.15.4",
"mime": "^4.0.7",
"nitro-cloudflare-dev": "^0.2.2",
Expand Down
6 changes: 6 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

142 changes: 138 additions & 4 deletions src/utils/devtools.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,120 @@
import { addCustomTab } from '@nuxt/devtools-kit'
import { logger } from '@nuxt/kit'
import type { Nuxt } from 'nuxt/schema'
import type { HubConfig } from '../features'
import { checkPort, getPort } from 'get-port-please'
import { existsSync } from 'node:fs'
import { writeFile } from 'node:fs/promises'
import { detectPackageManager, dlxCommand } from 'nypm'
import { execa } from 'execa'
import { join } from 'pathe'

export function addDevToolsCustomTabs(nuxt: Nuxt, _hub: HubConfig) {
nuxt.hook('listen', (_) => {
nuxt.options.nitro.experimental?.openAPI && addCustomTab({
let isReady = false
let promise: Promise<any> | null = null
let port = 4983

const log = logger.withTag('nuxt:hub')

async function launchDrizzleStudio(nuxt: Nuxt) {
const packageManager = await detectPackageManager(nuxt.options.rootDir)
if (!packageManager) {
throw new Error('Could not detect package manager')
}

port = await getPort({ port: 4983 })
let cmd = `${packageManager.name} run drizzle-kit studio --port ${port}`

try {
// Check if there's a drizzle.config.ts in the project root
const drizzleConfigPath = join(nuxt.options.rootDir, 'drizzle.config.ts')
const drizzleConfigNuxtPath = join(nuxt.options.buildDir, 'drizzle.config.ts')
const drizzleConfigExists = existsSync(drizzleConfigPath)

let configPath = drizzleConfigPath

// If no drizzle.config.ts exists, create one using nitro database config
if (!drizzleConfigExists) {
const dbConfig = nuxt.options.nitro.devDatabase?.db
if (!dbConfig?.connector) {
throw new Error('No database configuration found. Please configure your database in nuxt.config.ts')
}

// Determine dialect from connector
let dialect: string
let dbCredentials: any

if (dbConfig.connector === 'postgresql' || dbConfig.connector === 'pglite') {
dialect = 'postgresql'
if (dbConfig.connector === 'pglite') {
dbCredentials = {
url: dbConfig.options?.dataDir || './database/'
}
} else {
dbCredentials = {
url: dbConfig.options?.url
}
}
} else if (['better-sqlite3', 'bun-sqlite', 'bun', 'node-sqlite', 'sqlite3'].includes(dbConfig.connector)) {
dialect = 'sqlite'
dbCredentials = {
url: dbConfig.options?.path
}
} else if (dbConfig.connector === 'mysql2') {
dialect = 'mysql'
dbCredentials = {
url: dbConfig.options?.url || process.env.DATABASE_URL
}
} else {
throw new Error(`Unsupported database connector: ${dbConfig.connector}`)
}

// Generate drizzle config content
const drizzleConfig = `import { defineConfig } from "drizzle-kit";

export default defineConfig({
dialect: "${dialect}"${dbConfig.connector === 'pglite' ? ',\n driver: "pglite"' : ''},
dbCredentials: ${JSON.stringify(dbCredentials, null, 2)}
});`
await writeFile(drizzleConfigNuxtPath, drizzleConfig, 'utf-8')
configPath = join(nuxt.options.buildDir, 'drizzle.config.ts')

cmd = dlxCommand(packageManager.name, 'drizzle-kit', {
args: [
'studio',
'--config', configPath,
'--port', port.toString()
],
packages: [dbConfig.connector, 'drizzle-orm', 'drizzle-kit']
})
}

// Launch Drizzle Studio
log.info(`Launching Drizzle Studio...`)

execa(cmd, {
cwd: nuxt.options.rootDir,
stdio: 'inherit',
shell: true
})

// Wait for Drizzle Studio to be ready
const checkInterval = 100 // 100ms
while (!isReady) {
const portCheck = await checkPort(port)
if (portCheck !== false) {
isReady = true
break
}
await new Promise(resolve => setTimeout(resolve, checkInterval))
}
} catch (error) {
log.error('Failed to launch Drizzle Studio:', error)
throw error
}
}

export function addDevToolsCustomTabs(nuxt: Nuxt, hub: HubConfig) {
nuxt.hook('devtools:customTabs', (tabs) => {
if (nuxt.options.nitro.experimental?.openAPI)({
category: 'server',
name: 'hub-open-api',
title: 'OpenAPI',
Expand All @@ -14,5 +124,29 @@ export function addDevToolsCustomTabs(nuxt: Nuxt, _hub: HubConfig) {
src: `/_scalar`
}
})

if (hub.database) tabs.push({
category: 'server',
name: 'hub-database',
title: 'Database',
icon: 'i-lucide-database',
view: isReady && port
? {
type: 'iframe',
src: `https://local.drizzle.studio?port=${port}`
}
: {
type: 'launch',
description: 'Launch Drizzle Studio',
actions: [{
label: promise ? 'Starting...' : 'Launch',
pending: isReady,
handle() {
promise = promise || launchDrizzleStudio(nuxt)
return promise
}
}]
}
})
})
}
Loading