refactor: env config (#769)

This commit is contained in:
三咲智子 Kevin Deng 2023-01-04 21:26:30 +08:00 committed by GitHub
parent 9d5dc1bc3d
commit f892722220
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 121 additions and 64 deletions

View file

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import buildInfo from 'virtual:build-info' import { buildInfo } from 'virtual:build-info'
const timeAgoOptions = useTimeAgoOptions() const timeAgoOptions = useTimeAgoOptions()
@ -35,10 +35,10 @@ function toggleDark() {
<span v-else> <span v-else>
{{ $t('nav.built_at', [$d(buildTimeDate, 'shortDate')]) }} {{ $t('nav.built_at', [$d(buildTimeDate, 'shortDate')]) }}
</span> </span>
<template v-if="buildInfo.version">
&middot; &middot;
v{{ buildInfo.version }} <!-- TODO click version to show changelog -->
</template> <span v-if="buildInfo.env === 'release'">v{{ buildInfo.version }}</span>
<span v-else>{{ buildInfo.env }}</span>
<template v-if="buildInfo.commit && buildInfo.branch !== 'release'"> <template v-if="buildInfo.commit && buildInfo.branch !== 'release'">
&middot; &middot;
<NuxtLink <NuxtLink

View file

@ -1,6 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
const env = useRuntimeConfig().public.env import { buildInfo } from 'virtual:build-info'
const sub = env === 'local' ? 'dev' : env === 'staging' ? 'preview' : 'alpha'
const { env } = buildInfo
</script> </script>
<template> <template>
@ -17,7 +18,7 @@ const sub = env === 'local' ? 'dev' : env === 'staging' ? 'preview' : 'alpha'
> >
<img :alt="$t('app_logo')" src="/logo.svg" shrink-0 aspect="1/1" sm:h-8 xl:h-10 class="rtl-flip"> <img :alt="$t('app_logo')" src="/logo.svg" shrink-0 aspect="1/1" sm:h-8 xl:h-10 class="rtl-flip">
<div hidden xl:block> <div hidden xl:block>
{{ $t('app_name') }} <sup text-sm italic text-secondary mt-1>{{ sub }}</sup> {{ $t('app_name') }} <sup text-sm italic text-secondary mt-1>{{ env === 'release' ? 'alpha' : env }}</sup>
</div> </div>
</NuxtLink> </NuxtLink>
</template> </template>

View file

@ -1,13 +1,11 @@
import { pwaInfo } from 'virtual:pwa-info' import { pwaInfo } from 'virtual:pwa-info'
import type { Link } from '@unhead/schema' import type { Link } from '@unhead/schema'
import type { Directions } from 'vue-i18n-routing' import type { Directions } from 'vue-i18n-routing'
import { buildInfo } from 'virtual:build-info'
import { APP_NAME } from '~/constants' import { APP_NAME } from '~/constants'
import type { LocaleObject } from '#i18n' import type { LocaleObject } from '#i18n'
export function setupPageHeader() { export function setupPageHeader() {
const isDev = process.dev
const isPreview = useRuntimeConfig().public.env === 'staging'
const i18n = useI18n() const i18n = useI18n()
const link: Link[] = [] const link: Link[] = []
@ -42,7 +40,13 @@ export function setupPageHeader() {
lang: () => i18n.locale.value, lang: () => i18n.locale.value,
dir: () => localeMap[i18n.locale.value] ?? 'auto', dir: () => localeMap[i18n.locale.value] ?? 'auto',
}, },
titleTemplate: title => `${title ? `${title} | ` : ''}${APP_NAME}${isDev ? ' (dev)' : isPreview ? ' (preview)' : ''}`, titleTemplate: (title) => {
let titleTemplate = title ? `${title} | ` : ''
titleTemplate += APP_NAME
if (buildInfo.env !== 'release')
titleTemplate += ` (${buildInfo.env})`
return titleTemplate
},
link, link,
}) })
} }

39
config/env.ts Normal file
View file

@ -0,0 +1,39 @@
import Git from 'simple-git'
import { isDevelopment } from 'std-env'
export { version } from '../package.json'
/**
* Environment variable `PULL_REQUEST` provided by Netlify.
* @see {@link https://docs.netlify.com/configure-builds/environment-variables/#git-metadata}
*
* Whether triggered by a GitHub PR
*/
export const isPR = process.env.PULL_REQUEST === 'true'
/**
* Environment variable `CONTEXT` provided by Netlify.
* @see {@link https://docs.netlify.com/configure-builds/environment-variables/#build-metadata}
*
* Whether triggered by PR, `deploy-preview` or `dev`.
*/
export const isPreview = isPR || process.env.CONTEXT === 'deploy-preview' || process.env.CONTEXT === 'dev'
const git = Git()
export const getGitInfo = async () => {
const branch = await git.revparse(['--abbrev-ref', 'HEAD'])
const commit = await git.revparse(['HEAD'])
return { branch, commit }
}
export const getEnv = async () => {
const { commit, branch } = await getGitInfo()
const env = isDevelopment
? 'dev'
: isPreview
? 'preview'
: branch === 'main'
? 'main'
: 'release'
return { commit, branch, env } as const
}

View file

@ -1,7 +1,7 @@
import { isCI, isDevelopment } from 'std-env' import { isCI, isDevelopment } from 'std-env'
import type { VitePWANuxtOptions } from '../modules/pwa/types' import type { VitePWANuxtOptions } from '../modules/pwa/types'
import { APP_NAME } from '../constants'
const isPreview = process.env.PULL_REQUEST === 'true' import { getEnv } from './env'
export const pwa: VitePWANuxtOptions = { export const pwa: VitePWANuxtOptions = {
mode: isCI ? 'production' : 'development', mode: isCI ? 'production' : 'development',
@ -13,12 +13,15 @@ export const pwa: VitePWANuxtOptions = {
strategies: 'injectManifest', strategies: 'injectManifest',
injectRegister: false, injectRegister: false,
includeManifestIcons: false, includeManifestIcons: false,
manifest: { manifest: async () => {
const { env } = await getEnv()
const envName = `${env !== 'release' ? '' : ` (${env})`}`
return {
scope: '/', scope: '/',
id: '/', id: '/',
name: `Elk${isCI ? isPreview ? ' (preview)' : '' : ' (dev)'}`, name: `${APP_NAME}${envName}`,
short_name: `Elk${isCI ? isPreview ? ' (preview)' : '' : ' (dev)'}`, short_name: `${APP_NAME}${envName}`,
description: `A nimble Mastodon Web Client${isCI ? isPreview ? ' (preview)' : '' : ' (development)'}`, description: `A nimble Mastodon Web Client${envName}`,
theme_color: '#ffffff', theme_color: '#ffffff',
icons: [ icons: [
{ {
@ -38,8 +41,9 @@ export const pwa: VitePWANuxtOptions = {
type: 'image/png', type: 'image/png',
purpose: 'any maskable', purpose: 'any maskable',
}, },
*/ */
], ],
}
}, },
injectManifest: { injectManifest: {
globPatterns: ['**/*.{js,json,css,html,txt,svg,png,ico,webp,woff,woff2,ttf,eot,otf,wasm}'], globPatterns: ['**/*.{js,json,css,html,txt,svg,png,ico,webp,woff,woff2,ttf,eot,otf,wasm}'],

View file

@ -1,20 +1,23 @@
import { addVitePlugin, defineNuxtModule } from '@nuxt/kit' import { addVitePlugin, defineNuxtModule } from '@nuxt/kit'
import Git from 'simple-git' import { getEnv, version } from '../config/env'
import { version } from '../package.json'
import type { BuildInfo } from '~/types' import type { BuildInfo } from '~/types'
export default defineNuxtModule({ export default defineNuxtModule({
meta: { meta: {
name: 'elk:build-info', name: 'elk:build-info',
}, },
async setup() { async setup(_options, nuxt) {
const git = Git() const { env, commit, branch } = await getEnv()
nuxt.options.runtimeConfig.public.env = env
const buildInfo: BuildInfo = { const buildInfo: BuildInfo = {
version, version,
time: +Date.now(), time: +Date.now(),
commit: await git.revparse(['HEAD']), commit,
branch: await git.revparse(['--abbrev-ref', 'HEAD']), branch,
env,
} }
addVitePlugin({ addVitePlugin({
name: 'elk:build-info', name: 'elk:build-info',
resolveId(id) { resolveId(id) {
@ -23,7 +26,7 @@ export default defineNuxtModule({
}, },
load(id) { load(id) {
if (id === 'virtual:build-info') if (id === 'virtual:build-info')
return `export default ${JSON.stringify(buildInfo, null, 2)}` return `export const buildInfo = ${JSON.stringify(buildInfo, null, 2)}`
}, },
}) })
}, },

View file

@ -1,5 +1,5 @@
import { defineNuxtModule } from '@nuxt/kit' import { defineNuxtModule } from '@nuxt/kit'
import type { VitePluginPWAAPI } from 'vite-plugin-pwa' import type { VitePWAOptions, VitePluginPWAAPI } from 'vite-plugin-pwa'
import { VitePWA } from 'vite-plugin-pwa' import { VitePWA } from 'vite-plugin-pwa'
import type { Plugin } from 'vite' import type { Plugin } from 'vite'
import type { VitePWANuxtOptions } from './types' import type { VitePWANuxtOptions } from './types'
@ -32,14 +32,17 @@ export default defineNuxtModule<VitePWANuxtOptions>({
if (plugin) if (plugin)
throw new Error('Remove vite-plugin-pwa plugin from Vite Plugins entry in Nuxt config file!') throw new Error('Remove vite-plugin-pwa plugin from Vite Plugins entry in Nuxt config file!')
}) })
nuxt.hook('vite:extendConfig', (viteInlineConfig, { isClient }) => { nuxt.hook('vite:extendConfig', async (viteInlineConfig, { isClient }) => {
viteInlineConfig.plugins = viteInlineConfig.plugins || [] viteInlineConfig.plugins = viteInlineConfig.plugins || []
const plugin = viteInlineConfig.plugins.find(p => p && typeof p === 'object' && 'name' in p && p.name === 'vite-plugin-pwa') const plugin = viteInlineConfig.plugins.find(p => p && typeof p === 'object' && 'name' in p && p.name === 'vite-plugin-pwa')
if (plugin) if (plugin)
throw new Error('Remove vite-plugin-pwa plugin from Vite Plugins entry in Nuxt config file!') throw new Error('Remove vite-plugin-pwa plugin from Vite Plugins entry in Nuxt config file!')
const resolvedOptions: Partial<VitePWAOptions> = {
configurePWAOptions(options, nuxt) ...options,
const plugins = VitePWA(options) manifest: options.manifest ? await options.manifest() : undefined,
}
configurePWAOptions(resolvedOptions, nuxt)
const plugins = VitePWA(resolvedOptions)
viteInlineConfig.plugins.push(plugins) viteInlineConfig.plugins.push(plugins)
if (isClient) if (isClient)
vitePwaClientPlugin = plugins.find(p => p.name === 'vite-plugin-pwa') as Plugin vitePwaClientPlugin = plugins.find(p => p.name === 'vite-plugin-pwa') as Plugin

View file

@ -1,6 +1,9 @@
import type { VitePWAOptions } from 'vite-plugin-pwa' import type { ManifestOptions, VitePWAOptions } from 'vite-plugin-pwa'
import type { Overwrite } from '../../types/utils'
export interface VitePWANuxtOptions extends Partial<VitePWAOptions> {} export type VitePWANuxtOptions = Overwrite<Partial<VitePWAOptions>, {
manifest?: () => Promise<Partial<ManifestOptions>>
}>
declare module '@nuxt/schema' { declare module '@nuxt/schema' {
interface NuxtConfig { interface NuxtConfig {

View file

@ -3,9 +3,9 @@ import Inspect from 'vite-plugin-inspect'
import { isCI, isDevelopment } from 'std-env' import { isCI, isDevelopment } from 'std-env'
import { i18n } from './config/i18n' import { i18n } from './config/i18n'
import { pwa } from './config/pwa' import { pwa } from './config/pwa'
import { isPreview } from './config/env'
const { resolve } = createResolver(import.meta.url) const { resolve } = createResolver(import.meta.url)
const isPreview = process.env.PULL_REQUEST === 'true' || process.env.CONTEXT === 'deploy-preview' || process.env.CONTEXT === 'dev'
export default defineNuxtConfig({ export default defineNuxtConfig({
typescript: { typescript: {
@ -90,7 +90,7 @@ export default defineNuxtConfig({
inviteToken: '', inviteToken: '',
}, },
public: { public: {
env: isCI ? isPreview ? 'staging' : 'production' : 'local', env: '', // set in build-info module
pwaEnabled: !isDevelopment || process.env.VITE_DEV_PWA === 'true', pwaEnabled: !isDevelopment || process.env.VITE_DEV_PWA === 'true',
translateApi: '', translateApi: '',
}, },

View file

@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import buildInfo from 'virtual:build-info' import { buildInfo } from 'virtual:build-info'
let showCommit = $ref(false) let showCommit = $ref(buildInfo.env !== 'release' && buildInfo.env !== 'dev')
const builtTime = useFormattedDateTime(buildInfo.time) const builtTime = useFormattedDateTime(buildInfo.time)
const handleShowCommit = () => { const handleShowCommit = () => {
@ -35,8 +35,8 @@ const handleShowCommit = () => {
> >
<template #content> <template #content>
<div font-mono> <div font-mono>
v{{ buildInfo.version }} <span>{{ buildInfo.env === 'release' ? `v${buildInfo.version}` : buildInfo.env }}</span>
<span v-if="showCommit">({{ buildInfo.commit.slice(0, 7) }})</span> <span v-if="showCommit"> ({{ buildInfo.commit.slice(0, 7) }})</span>
</div> </div>
</template> </template>
</SettingsItem> </SettingsItem>

View file

@ -39,7 +39,7 @@ async function fetchAppInfo(origin: string, server: string) {
const app: AppInfo = await $fetch(`https://${server}/api/v1/apps`, { const app: AppInfo = await $fetch(`https://${server}/api/v1/apps`, {
method: 'POST', method: 'POST',
body: { body: {
client_name: APP_NAME + (config.public.env === 'local' ? ' (dev)' : ''), client_name: APP_NAME + (config.public.env !== 'release' ? ` (${config.public.env})` : ''),
website: 'https://elk.zone', website: 'https://elk.zone',
redirect_uris: getRedirectURI(origin, server), redirect_uris: getRedirectURI(origin, server),
scopes: 'read write follow push', scopes: 'read write follow push',

3
shims.d.ts vendored
View file

@ -4,6 +4,5 @@
declare module 'virtual:build-info' { declare module 'virtual:build-info' {
import type { BuildInfo } from '~/types' import type { BuildInfo } from '~/types'
const buildInfo: BuildInfo export const buildInfo: BuildInfo
export default buildInfo
} }

View file

@ -69,6 +69,7 @@ export interface BuildInfo {
commit: string commit: string
time: number time: number
branch: string branch: string
env: 'preview' | 'main' | 'dev' | 'release'
} }
export type FontSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl' export type FontSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl'