Skip to content

Commit

Permalink
feat(preview): add gitInfo in /__studio.json and support staging …
Browse files Browse the repository at this point in the history
…API for preview mode (#163)
  • Loading branch information
atinux authored Feb 7, 2024
1 parent 77b8020 commit 9b02f48
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 14 deletions.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@
"dependencies": {
"@nuxt/kit": "^3.9.3",
"defu": "^6.1.4",
"git-url-parse": "^14.0.0",
"nuxt-component-meta": "^0.6.3",
"parse-git-config": "^3.0.0",
"pkg-types": "^1.0.3",
"socket.io-client": "^4.7.4",
"ufo": "^1.3.2",
"untyped": "^1.4.2"
Expand Down
20 changes: 10 additions & 10 deletions pnpm-lock.yaml

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

94 changes: 93 additions & 1 deletion src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import { existsSync } from 'node:fs'
import path from 'path'
import { defu } from 'defu'
import { addPrerenderRoutes, installModule, defineNuxtModule, addPlugin, extendViteConfig, createResolver, logger, addComponentsDir, addServerHandler, resolveAlias, addVitePlugin } from '@nuxt/kit'
import { findNearestFile } from 'pkg-types'
// @ts-ignore
import gitUrlParse from 'git-url-parse'

const log = logger.withTag('@nuxt/studio')

Expand Down Expand Up @@ -88,9 +91,11 @@ export default defineNuxtModule<ModuleOptions>({

const apiURL = process.env.NUXT_PUBLIC_STUDIO_API_URL || process.env.STUDIO_API || 'https://api.nuxt.studio'
const publicToken = process.env.NUXT_PUBLIC_STUDIO_TOKENS
const gitInfo = await _getLocalGitInfo(nuxt.options.rootDir) || _getGitEnv() || {}
nuxt.options.runtimeConfig.studio = defu(nuxt.options.runtimeConfig.studio as any, {
publicToken,
project: options.project
project: options.project,
gitInfo
})
nuxt.options.runtimeConfig.public.studio = defu(nuxt.options.runtimeConfig.public.studio as any, { apiURL })

Expand Down Expand Up @@ -138,3 +143,90 @@ export default defineNuxtModule<ModuleOptions>({
})
}
})

// --- Utilities to get git info ---

interface GitInfo {
// Repository name
name: string,
// Repository owner/organization
owner: string,
// Repository URL
url: string,
}

async function _getLocalGitInfo (rootDir: string): Promise<GitInfo | void> {
const remote = await _getLocalGitRemote(rootDir)
if (!remote) {
return
}

// https://www.npmjs.com/package/git-url-parse#clipboard-example
const { name, owner, source } = gitUrlParse(remote) as Record<string, string>
const url = `https://${source}/${owner}/${name}`

return {
name,
owner,
url
}
}

async function _getLocalGitRemote (dir: string) {
try {
// https://www.npmjs.com/package/parse-git-config#options
const parseGitConfig = await import('parse-git-config' as string).then(
m => m.promise
) as (opts: { path: string }) => Promise<Record<string, Record<string, string>>>
const gitDir = await findNearestFile('.git/config', { startingFrom: dir })
const parsed = await parseGitConfig({ path: gitDir })
if (!parsed) {
return
}
const gitRemote = parsed['remote "origin"'].url
return gitRemote
} catch (err) {

}
}

function _getGitEnv (): GitInfo {
// https://github.com/unjs/std-env/issues/59
const envInfo = {
// Provider
provider: process.env.VERCEL_GIT_PROVIDER || // vercel
(process.env.GITHUB_SERVER_URL ? 'github' : undefined) || // github
'',
// Owner
owner: process.env.VERCEL_GIT_REPO_OWNER || // vercel
process.env.GITHUB_REPOSITORY_OWNER || // github
process.env.CI_PROJECT_PATH?.split('/').shift() || // gitlab
'',
// Name
name: process.env.VERCEL_GIT_REPO_SLUG ||
process.env.GITHUB_REPOSITORY?.split('/').pop() || // github
process.env.CI_PROJECT_PATH?.split('/').splice(1).join('/') || // gitlab
'',
// Url
url: process.env.REPOSITORY_URL || '' // netlify
}

if (!envInfo.url && envInfo.provider && envInfo.owner && envInfo.name) {
envInfo.url = `https://${envInfo.provider}.com/${envInfo.owner}/${envInfo.name}`
}

// If only url available (ex: Netlify)
if (!envInfo.name && !envInfo.owner && envInfo.url) {
try {
const { name, owner } = gitUrlParse(envInfo.url) as Record<string, string>
envInfo.name = name
envInfo.owner = owner
} catch {}
}

return {
name: envInfo.name,
owner: envInfo.owner,
url: envInfo.url
}
}
1 change: 1 addition & 0 deletions src/runtime/components/ContentPreviewMode.vue
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const closePreviewMode = async () => {
// Remove preview token from cookie and session storage
useCookie('previewToken').value = ''
window.sessionStorage.removeItem('previewToken')
window.sessionStorage.removeItem('previewAPI')
// Remove query params in url to refresh page
await router.replace({ query: { preview: undefined } })
Expand Down
7 changes: 4 additions & 3 deletions src/runtime/composables/useStudio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const useStudio = () => {
const nuxtApp = useNuxtApp()
const { studio: studioConfig, content: contentConfig } = useRuntimeConfig().public
const contentPathMap = {} as Record<string, ParsedContent>
const apiURL = window.sessionStorage.getItem('previewAPI') || studioConfig?.apiURL

// App config (required)
const initialAppConfig = useDefaultAppConfig()
Expand Down Expand Up @@ -135,7 +136,7 @@ export const useStudio = () => {
const previewToken = window.sessionStorage.getItem('previewToken')
// Fetch preview data from station
await $fetch<PreviewResponse>('api/projects/preview/sync', {
baseURL: studioConfig?.apiURL,
baseURL: apiURL,
method: 'POST',
params: {
token: previewToken
Expand All @@ -151,7 +152,7 @@ export const useStudio = () => {
document.body.appendChild(el)
createApp(ContentPreviewMode, {
previewToken,
apiURL: studioConfig?.apiURL,
apiURL,
syncPreview,
requestPreviewSyncAPI: requestPreviewSynchronization
}).mount(el)
Expand Down Expand Up @@ -223,7 +224,7 @@ export const useStudio = () => {
}

return {
apiURL: studioConfig?.apiURL,
apiURL,
contentStorage: storage,

syncPreviewFiles,
Expand Down
1 change: 1 addition & 0 deletions src/runtime/plugins/preview.client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export default defineNuxtPlugin((nuxtApp) => {
previewToken.value = String(route.query.preview)
}
window.sessionStorage.setItem('previewToken', String(previewToken.value))
window.sessionStorage.setItem('previewAPI', typeof route.query.staging !== 'undefined' ? 'https://dev-api.nuxt.studio' : runtimeConfig.apiURL)

// Listen to `content:storage` hook to get storage instance
// There is some cases that `content:storage` hook is called before initializing preview
Expand Down
1 change: 1 addition & 0 deletions src/runtime/server/routes/studio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export default eventHandler(async () => {
version,
project: studio?.project,
tokens: studio?.publicToken,
gitInfo: studio?.gitInfo || {},
// nuxt.schema for Nuxt Content frontmatter
contentSchema: contentSchema || {},
// app.config
Expand Down

0 comments on commit 9b02f48

Please sign in to comment.