mirror of
https://github.com/dreamhunter2333/cloudflare_temp_email.git
synced 2026-09-05 15:38:34 +08:00
feat: support runtime frontend configuration (#1135)
This commit is contained in:
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
|
- feat: |Frontend| 新增 `VITE_DEFAULT_LANG` 构建变量,并支持通过 `index.html` 运行时配置覆盖前端设置
|
||||||
- feat: |邮件| 新增可选的已读/未读状态,支持点击邮件自动已读和手动切换状态
|
- feat: |邮件| 新增可选的已读/未读状态,支持点击邮件自动已读和手动切换状态
|
||||||
- feat: |Admin| 数据库页面新增 D1 存储容量展示,支持选择并保存 Free 或 Workers Paid 套餐,对比当前数据库大小和容量上限
|
- feat: |Admin| 数据库页面新增 D1 存储容量展示,支持选择并保存 Free 或 Workers Paid 套餐,对比当前数据库大小和容量上限
|
||||||
- feat: |Admin| 创建邮箱页面支持一键生成随机邮箱名称(issue #1126)
|
- feat: |Admin| 创建邮箱页面支持一键生成随机邮箱名称(issue #1126)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
|
- feat: |Frontend| Add the `VITE_DEFAULT_LANG` build variable and support overriding frontend settings through runtime configuration in `index.html`
|
||||||
- feat: |Mail| Add optional read/unread status with click-to-read and manual status switching
|
- feat: |Mail| Add optional read/unread status with click-to-read and manual status switching
|
||||||
- feat: |Admin| Add D1 storage capacity details to the database page, with persistent Free and Workers Paid plan selection and a comparison between the current database size and capacity limit
|
- feat: |Admin| Add D1 storage capacity details to the database page, with persistent Free and Workers Paid plan selection and a comparison between the current database size and capacity limit
|
||||||
- feat: |Admin| Add one-click random email-name generation to the address creation page (issue #1126)
|
- feat: |Admin| Add one-click random email-name generation to the address creation page (issue #1126)
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
VITE_API_BASE=https://temp-email-api.xxx.xxx
|
VITE_API_BASE=https://temp-email-api.xxx.xxx
|
||||||
|
VITE_DEFAULT_LANG=zh
|
||||||
VITE_CF_WEB_ANALY_TOKEN=
|
VITE_CF_WEB_ANALY_TOKEN=
|
||||||
VITE_IS_TELEGRAM=false
|
VITE_IS_TELEGRAM=false
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
||||||
<link rel="icon" href="/logo.png" sizes="any">
|
<link rel="icon" href="/logo.png" sizes="any">
|
||||||
<link rel="apple-touch-icon" href="/logo.png">
|
<link rel="apple-touch-icon" href="/logo.png">
|
||||||
|
<script id="app-config" type="application/json">{}</script>
|
||||||
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit"></script>
|
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|||||||
@@ -12,12 +12,13 @@ import Footer from './views/Footer.vue';
|
|||||||
import { api } from './api'
|
import { api } from './api'
|
||||||
import { getNaiveLocaleConfig } from './i18n/naive-locale'
|
import { getNaiveLocaleConfig } from './i18n/naive-locale'
|
||||||
import { DEFAULT_LOCALE, isSupportedLocale } from './i18n/utils'
|
import { DEFAULT_LOCALE, isSupportedLocale } from './i18n/utils'
|
||||||
|
import { APP_CONFIG } from './config'
|
||||||
|
|
||||||
const {
|
const {
|
||||||
isDark, loading, useSideMargin, telegramApp, isTelegram
|
isDark, loading, useSideMargin, telegramApp, isTelegram
|
||||||
} = useGlobalState()
|
} = useGlobalState()
|
||||||
const adClient = import.meta.env.VITE_GOOGLE_AD_CLIENT;
|
const adClient = APP_CONFIG.GOOGLE_AD_CLIENT;
|
||||||
const adSlot = import.meta.env.VITE_GOOGLE_AD_SLOT;
|
const adSlot = APP_CONFIG.GOOGLE_AD_SLOT;
|
||||||
const { locale } = useI18n({ useScope: 'global' });
|
const { locale } = useI18n({ useScope: 'global' });
|
||||||
const theme = computed(() => isDark.value ? darkTheme : null)
|
const theme = computed(() => isDark.value ? darkTheme : null)
|
||||||
const localeConfig = computed(() => getNaiveLocaleConfig(isSupportedLocale(locale.value) ? locale.value : DEFAULT_LOCALE))
|
const localeConfig = computed(() => getNaiveLocaleConfig(isSupportedLocale(locale.value) ? locale.value : DEFAULT_LOCALE))
|
||||||
@@ -47,7 +48,7 @@ onMounted(async () => {
|
|||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
const token = import.meta.env.VITE_CF_WEB_ANALY_TOKEN;
|
const token = APP_CONFIG.CF_WEB_ANALY_TOKEN;
|
||||||
|
|
||||||
const exist = document.querySelector('script[src="https://static.cloudflareinsights.com/beacon.min.js"]') !== null
|
const exist = document.querySelector('script[src="https://static.cloudflareinsights.com/beacon.min.js"]') !== null
|
||||||
if (token && !exist) {
|
if (token && !exist) {
|
||||||
@@ -66,7 +67,7 @@ onMounted(async () => {
|
|||||||
|
|
||||||
|
|
||||||
// check if telegram is enabled
|
// check if telegram is enabled
|
||||||
const enableTelegram = import.meta.env.VITE_IS_TELEGRAM;
|
const enableTelegram = APP_CONFIG.IS_TELEGRAM;
|
||||||
if (
|
if (
|
||||||
(typeof enableTelegram === 'boolean' && enableTelegram === true)
|
(typeof enableTelegram === 'boolean' && enableTelegram === true)
|
||||||
||
|
||
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
// @vitest-environment jsdom
|
||||||
|
|
||||||
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||||
|
|
||||||
|
const setRuntimeConfig = (config) => {
|
||||||
|
const element = document.createElement('script')
|
||||||
|
element.id = 'app-config'
|
||||||
|
element.type = 'application/json'
|
||||||
|
element.textContent = JSON.stringify(config)
|
||||||
|
document.head.appendChild(element)
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('APP_CONFIG', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.resetModules()
|
||||||
|
vi.stubEnv('VITE_API_BASE', 'https://build.example.com')
|
||||||
|
vi.stubEnv('VITE_DEFAULT_LANG', 'zh')
|
||||||
|
vi.stubEnv('VITE_IS_TELEGRAM', 'false')
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
document.querySelector('#app-config')?.remove()
|
||||||
|
vi.unstubAllEnvs()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('uses build settings when runtime settings are absent', async () => {
|
||||||
|
const { APP_CONFIG } = await import('../config')
|
||||||
|
|
||||||
|
expect(APP_CONFIG.API_BASE).toBe('https://build.example.com')
|
||||||
|
expect(APP_CONFIG.DEFAULT_LANG).toBe('zh')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('overrides only settings provided by index.html', async () => {
|
||||||
|
setRuntimeConfig({ API_BASE: 'https://runtime.example.com', DEFAULT_LANG: 'en' })
|
||||||
|
|
||||||
|
const { APP_CONFIG } = await import('../config')
|
||||||
|
|
||||||
|
expect(APP_CONFIG.API_BASE).toBe('https://runtime.example.com')
|
||||||
|
expect(APP_CONFIG.DEFAULT_LANG).toBe('en')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('allows an explicit empty runtime value', async () => {
|
||||||
|
setRuntimeConfig({ API_BASE: '' })
|
||||||
|
|
||||||
|
const { APP_CONFIG } = await import('../config')
|
||||||
|
|
||||||
|
expect(APP_CONFIG.API_BASE).toBe('')
|
||||||
|
expect(APP_CONFIG.DEFAULT_LANG).toBe('zh')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('falls back to build settings for invalid runtime value types', async () => {
|
||||||
|
setRuntimeConfig({ API_BASE: {}, DEFAULT_LANG: 1, IS_TELEGRAM: [] })
|
||||||
|
|
||||||
|
const { APP_CONFIG } = await import('../config')
|
||||||
|
|
||||||
|
expect(APP_CONFIG.API_BASE).toBe('https://build.example.com')
|
||||||
|
expect(APP_CONFIG.DEFAULT_LANG).toBe('zh')
|
||||||
|
expect(APP_CONFIG.IS_TELEGRAM).toBe('false')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('reads runtime settings only once', async () => {
|
||||||
|
setRuntimeConfig({ DEFAULT_LANG: 'en' })
|
||||||
|
const firstImport = await import('../config')
|
||||||
|
|
||||||
|
document.querySelector('#app-config').textContent = JSON.stringify({ DEFAULT_LANG: 'de' })
|
||||||
|
const secondImport = await import('../config')
|
||||||
|
|
||||||
|
expect(secondImport.APP_CONFIG).toBe(firstImport.APP_CONFIG)
|
||||||
|
expect(secondImport.APP_CONFIG.DEFAULT_LANG).toBe('en')
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -6,8 +6,9 @@ import i18n from '../i18n'
|
|||||||
import { getFingerprint } from '../utils/fingerprint'
|
import { getFingerprint } from '../utils/fingerprint'
|
||||||
import { safeBearerHeader, safeHeaderValue } from '../utils/headers'
|
import { safeBearerHeader, safeHeaderValue } from '../utils/headers'
|
||||||
import { sanitizeHtml } from '../utils/sanitize-html'
|
import { sanitizeHtml } from '../utils/sanitize-html'
|
||||||
|
import { APP_CONFIG } from '../config'
|
||||||
|
|
||||||
const API_BASE = import.meta.env.VITE_API_BASE || "";
|
const API_BASE = APP_CONFIG.API_BASE || "";
|
||||||
const {
|
const {
|
||||||
loading, auth, jwt, settings, openSettings,
|
loading, auth, jwt, settings, openSettings,
|
||||||
userOpenSettings, userSettings, announcement,
|
userOpenSettings, userSettings, announcement,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { useScopedI18n } from '@/i18n/app'
|
import { useScopedI18n } from '@/i18n/app'
|
||||||
|
import { APP_CONFIG } from '@/config'
|
||||||
|
|
||||||
import { useGlobalState } from '../store'
|
import { useGlobalState } from '../store'
|
||||||
|
|
||||||
@@ -34,7 +35,7 @@ const modalShow = computed({
|
|||||||
set: (value) => emit('update:show', value),
|
set: (value) => emit('update:show', value),
|
||||||
})
|
})
|
||||||
|
|
||||||
const configuredApiBaseUrl = import.meta.env.VITE_API_BASE || ''
|
const configuredApiBaseUrl = APP_CONFIG.API_BASE || ''
|
||||||
const frontendBaseUrl = computed(() => window.location.origin)
|
const frontendBaseUrl = computed(() => window.location.origin)
|
||||||
const apiBaseUrl = computed(() => (configuredApiBaseUrl || frontendBaseUrl.value).replace(/\/$/, ''))
|
const apiBaseUrl = computed(() => (configuredApiBaseUrl || frontendBaseUrl.value).replace(/\/$/, ''))
|
||||||
const docLocale = computed(() => locale.value === 'zh' ? 'zh' : 'en')
|
const docLocale = computed(() => locale.value === 'zh' ? 'zh' : 'en')
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
type RuntimeConfig = Record<string, unknown>
|
||||||
|
|
||||||
|
const getRuntimeConfig = (): RuntimeConfig => {
|
||||||
|
if (typeof document === 'undefined') return {}
|
||||||
|
|
||||||
|
const content = document.querySelector('#app-config')?.textContent
|
||||||
|
if (!content?.trim()) return {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const config = JSON.parse(content)
|
||||||
|
return config && typeof config === 'object' && !Array.isArray(config) ? config : {}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to parse app config', error)
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const runtimeConfig = getRuntimeConfig()
|
||||||
|
|
||||||
|
const getStringConfigValue = (key: string, buildValue: string): string => {
|
||||||
|
const runtimeValue = runtimeConfig[key]
|
||||||
|
return typeof runtimeValue === 'string' ? runtimeValue : buildValue
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTelegramConfigValue = (buildValue: string): string | boolean => {
|
||||||
|
const runtimeValue = runtimeConfig.IS_TELEGRAM
|
||||||
|
return typeof runtimeValue === 'string' || typeof runtimeValue === 'boolean'
|
||||||
|
? runtimeValue
|
||||||
|
: buildValue
|
||||||
|
}
|
||||||
|
|
||||||
|
export const APP_CONFIG = {
|
||||||
|
API_BASE: getStringConfigValue('API_BASE', import.meta.env.VITE_API_BASE || ''),
|
||||||
|
DEFAULT_LANG: getStringConfigValue('DEFAULT_LANG', import.meta.env.VITE_DEFAULT_LANG || ''),
|
||||||
|
CF_WEB_ANALY_TOKEN: getStringConfigValue('CF_WEB_ANALY_TOKEN', import.meta.env.VITE_CF_WEB_ANALY_TOKEN || ''),
|
||||||
|
IS_TELEGRAM: getTelegramConfigValue(import.meta.env.VITE_IS_TELEGRAM || ''),
|
||||||
|
GOOGLE_AD_CLIENT: getStringConfigValue('GOOGLE_AD_CLIENT', import.meta.env.VITE_GOOGLE_AD_CLIENT || ''),
|
||||||
|
GOOGLE_AD_SLOT: getStringConfigValue('GOOGLE_AD_SLOT', import.meta.env.VITE_GOOGLE_AD_SLOT || ''),
|
||||||
|
} as const
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
import { LOCALE_REGISTRY, SUPPORTED_LOCALES } from './locale-registry'
|
import { LOCALE_REGISTRY, SUPPORTED_LOCALES } from './locale-registry'
|
||||||
|
import { APP_CONFIG } from '../config'
|
||||||
|
|
||||||
export { SUPPORTED_LOCALES } from './locale-registry'
|
export { SUPPORTED_LOCALES } from './locale-registry'
|
||||||
export type { SupportedLocale } from './locale-registry'
|
export type { SupportedLocale } from './locale-registry'
|
||||||
|
|
||||||
import type { SupportedLocale } from './locale-registry'
|
import type { SupportedLocale } from './locale-registry'
|
||||||
|
|
||||||
export const DEFAULT_LOCALE: SupportedLocale = 'zh'
|
|
||||||
export const FALLBACK_LOCALE: SupportedLocale = 'zh'
|
export const FALLBACK_LOCALE: SupportedLocale = 'zh'
|
||||||
export const PREFERRED_LOCALE_STORAGE_KEY = 'preferredLocale'
|
export const PREFERRED_LOCALE_STORAGE_KEY = 'preferredLocale'
|
||||||
export const EMPTY_LOCALE_MESSAGES = Object.fromEntries(
|
export const EMPTY_LOCALE_MESSAGES = Object.fromEntries(
|
||||||
@@ -29,6 +29,9 @@ export const resolveSupportedLocale = (locale: string | null | undefined): Suppo
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const DEFAULT_LOCALE: SupportedLocale = resolveSupportedLocale(APP_CONFIG.DEFAULT_LANG)
|
||||||
|
|| FALLBACK_LOCALE
|
||||||
|
|
||||||
export const matchSupportedLocale = (locale: string | null | undefined): SupportedLocale | null => {
|
export const matchSupportedLocale = (locale: string | null | undefined): SupportedLocale | null => {
|
||||||
if (!locale) return null
|
if (!locale) return null
|
||||||
const normalizedLocale = locale.trim().toLowerCase()
|
const normalizedLocale = locale.trim().toLowerCase()
|
||||||
@@ -135,4 +138,4 @@ const getLocaleAliasPath = (path: string, locale: SupportedLocale): string => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return getPathWithLocale(basePath, locale)
|
return getPathWithLocale(basePath, locale)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -140,6 +140,7 @@ function sidebarGuide(): DefaultTheme.SidebarItem[] {
|
|||||||
collapsed: false,
|
collapsed: false,
|
||||||
items: [
|
items: [
|
||||||
{ text: 'Worker Variables', link: 'worker-vars' },
|
{ text: 'Worker Variables', link: 'worker-vars' },
|
||||||
|
{ text: 'Frontend Variables', link: 'frontend-vars' },
|
||||||
{ text: 'Configure Email Sending', link: 'config-send-mail' },
|
{ text: 'Configure Email Sending', link: 'config-send-mail' },
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -140,6 +140,7 @@ function sidebarGuide(): DefaultTheme.SidebarItem[] {
|
|||||||
collapsed: false,
|
collapsed: false,
|
||||||
items: [
|
items: [
|
||||||
{ text: 'Worker 变量说明', link: 'worker-vars' },
|
{ text: 'Worker 变量说明', link: 'worker-vars' },
|
||||||
|
{ text: '前端变量说明', link: 'frontend-vars' },
|
||||||
{ text: '配置发送邮件', link: 'config-send-mail' },
|
{ text: '配置发送邮件', link: 'config-send-mail' },
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ Then go to the repository page `Settings` -> `Secrets and variables` -> `Actions
|
|||||||
|
|
||||||
| Name | Description |
|
| Name | Description |
|
||||||
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `FRONTEND_ENV` | Frontend configuration file used by the `Deploy Frontend` workflow. Copy the content from `frontend/.env.example`, [and modify it according to this guide](/en/guide/cli/pages.html). For separate frontend/backend deployment that talks to Worker directly, `VITE_API_BASE` should be the backend Worker API root URL, must start with `https://`, and must not include a trailing `/`. When this address is configured incorrectly, common symptoms are the `map` error or `405` API responses |
|
| `FRONTEND_ENV` | Frontend configuration file used by the `Deploy Frontend` workflow. Copy the content from `frontend/.env.example` and modify it according to [Frontend Variables](/en/guide/frontend-vars) |
|
||||||
| `FRONTEND_NAME` | The project name you created in Cloudflare Pages, can be created via [UI](https://temp-mail-docs.awsl.uk/en/guide/ui/pages.html) or [Command Line](https://temp-mail-docs.awsl.uk/en/guide/cli/pages.html) |
|
| `FRONTEND_NAME` | The project name you created in Cloudflare Pages, can be created via [UI](https://temp-mail-docs.awsl.uk/en/guide/ui/pages.html) or [Command Line](https://temp-mail-docs.awsl.uk/en/guide/cli/pages.html) |
|
||||||
| `FRONTEND_BRANCH` | (Optional) Branch for pages deployment, can be left unconfigured, defaults to `production` |
|
| `FRONTEND_BRANCH` | (Optional) Branch for pages deployment, can be left unconfigured, defaults to `production` |
|
||||||
| `PAGE_TOML` | (Optional) Used only by the `Deploy Frontend with page function` workflow. Required when using page functions to forward backend requests. Please copy the content from `pages/wrangler.toml` and modify the `service` field to your worker backend name according to actual situation. This workflow builds the frontend in Pages mode and uses same-origin requests, so it does not read `FRONTEND_ENV` |
|
| `PAGE_TOML` | (Optional) Used only by the `Deploy Frontend with page function` workflow. Required when using page functions to forward backend requests. Please copy the content from `pages/wrangler.toml` and modify the `service` field to your worker backend name according to actual situation. This workflow builds the frontend in Pages mode and uses same-origin requests, so it does not read `FRONTEND_ENV` |
|
||||||
|
|||||||
@@ -29,6 +29,12 @@ Change `VITE_API_BASE` to the `worker` `url` created in the previous step. Do no
|
|||||||
|
|
||||||
For example: `VITE_API_BASE=https://xxx.xxx.workers.dev`
|
For example: `VITE_API_BASE=https://xxx.xxx.workers.dev`
|
||||||
|
|
||||||
|
Set the frontend default language with `VITE_DEFAULT_LANG`. Supported values are `zh`, `en`, `es`, `pt-BR`, `ja`, and `de`; an unset or invalid value falls back to `zh`.
|
||||||
|
|
||||||
|
For example: `VITE_DEFAULT_LANG=en`
|
||||||
|
|
||||||
|
See [Frontend Variables](/en/guide/frontend-vars) for other settings.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pnpm build --emptyOutDir
|
pnpm build --emptyOutDir
|
||||||
# The first deployment will prompt you to create a project, for production branch enter production
|
# The first deployment will prompt you to create a project, for production branch enter production
|
||||||
@@ -47,6 +53,8 @@ The first deployment will prompt you to create a project. For the `production` b
|
|||||||
|
|
||||||
If your worker backend name is not `cloudflare_temp_email`, please modify `pages/wrangler.toml`.
|
If your worker backend name is not `cloudflare_temp_email`, please modify `pages/wrangler.toml`.
|
||||||
|
|
||||||
|
To set the default language, add `VITE_DEFAULT_LANG=en` to `frontend/.env.pages.local`. Same-origin requests do not require `VITE_API_BASE`; see [Frontend Variables](/en/guide/frontend-vars) for other settings.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd frontend
|
cd frontend
|
||||||
pnpm install
|
pnpm install
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
# Adding Google Ads to Your Website
|
# Adding Google Ads to Your Website
|
||||||
|
|
||||||
## Command Line Deployment
|
Google Ads uses the following two variables. See [Google AdSense](https://www.google.com/adsense/start/) for the values:
|
||||||
|
|
||||||
Modify the `.env.prod` file
|
```ini
|
||||||
|
|
||||||
Add the following two variables, refer to [Google AdSense](https://www.google.com/adsense/start/) for specific values
|
|
||||||
|
|
||||||
```txt
|
|
||||||
VITE_GOOGLE_AD_CLIENT=ca-pub-123456
|
VITE_GOOGLE_AD_CLIENT=ca-pub-123456
|
||||||
VITE_GOOGLE_AD_SLOT=123456
|
VITE_GOOGLE_AD_SLOT=123456
|
||||||
```
|
```
|
||||||
|
|
||||||
Then execute the following commands to redeploy pages.
|
Ads are not loaded when either variable is empty. See [Frontend Variables](/en/guide/frontend-vars) for their types and defaults.
|
||||||
|
|
||||||
|
## CLI Deployment
|
||||||
|
|
||||||
|
Add both variables to `frontend/.env.prod`, then rebuild and deploy:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pnpm build --emptyOutDir
|
pnpm build --emptyOutDir
|
||||||
@@ -19,11 +19,25 @@ pnpm build --emptyOutDir
|
|||||||
pnpm run deploy
|
pnpm run deploy
|
||||||
```
|
```
|
||||||
|
|
||||||
## GitHub Action Deployment
|
See [CLI Frontend Deployment](/en/guide/cli/pages) for the complete steps.
|
||||||
|
|
||||||
Modify `FRONTEND_ENV`, add the following two variables, refer to [Google AdSense](https://www.google.com/adsense/start/) for specific values, then redeploy pages.
|
## GitHub Actions Deployment
|
||||||
|
|
||||||
```txt
|
Add both variables to the existing `FRONTEND_ENV` secret, then run the `Deploy Frontend` workflow again.
|
||||||
VITE_GOOGLE_AD_CLIENT=ca-pub-123456
|
|
||||||
VITE_GOOGLE_AD_SLOT=123456
|
See [GitHub Actions Deployment](/en/guide/actions/github-action) for the complete steps.
|
||||||
|
|
||||||
|
## Manual ZIP Deployment
|
||||||
|
|
||||||
|
Edit `app-config` in the archive's `index.html` and use the field names without the `VITE_` prefix:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script id="app-config" type="application/json">
|
||||||
|
{
|
||||||
|
"GOOGLE_AD_CLIENT": "ca-pub-123456",
|
||||||
|
"GOOGLE_AD_SLOT": "123456"
|
||||||
|
}
|
||||||
|
</script>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
See [Manual ZIP Deployment](/en/guide/ui/pages) for the complete steps.
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
# Frontend Variables
|
||||||
|
|
||||||
|
Frontend configuration is public in the browser. Do not put passwords, API keys, or other secrets in these values.
|
||||||
|
|
||||||
|
## Configuration Methods
|
||||||
|
|
||||||
|
### ENV
|
||||||
|
|
||||||
|
For CLI deployment, add the variables to `frontend/.env.prod`. For Worker Assets or Page Functions deployment, use `frontend/.env.pages.local`. For the GitHub Actions `Deploy Frontend` workflow, put the same content in the `FRONTEND_ENV` repository secret. The `Deploy Frontend with page function` workflow does not read this secret.
|
||||||
|
|
||||||
|
```ini
|
||||||
|
VITE_API_BASE=https://temp-email-api.example.com
|
||||||
|
VITE_DEFAULT_LANG=en
|
||||||
|
```
|
||||||
|
|
||||||
|
See [CLI Deployment](/en/guide/cli/pages) and [GitHub Actions Deployment](/en/guide/actions/github-action) for complete steps.
|
||||||
|
|
||||||
|
### index.html
|
||||||
|
|
||||||
|
When using a prebuilt frontend ZIP, edit `app-config` in `index.html`. Field names do not use the `VITE_` prefix:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script id="app-config" type="application/json">
|
||||||
|
{
|
||||||
|
"API_BASE": "https://temp-email-api.example.com",
|
||||||
|
"DEFAULT_LANG": "en"
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
Fields set in `app-config` override ENV build values. Omitted fields, or a missing `app-config` tag, continue to use ENV build values. See [Manual ZIP Deployment](/en/guide/ui/pages) for complete steps.
|
||||||
|
|
||||||
|
## Variable Reference
|
||||||
|
|
||||||
|
No frontend variable is required for every deployment method. `VITE_API_BASE` is required only when the frontend and backend are deployed separately and the browser must request the Worker domain directly. Leave it empty for same-origin deployments such as Worker Assets or Page Functions.
|
||||||
|
|
||||||
|
| ENV Variable | `app-config` Field | Required | Type | Default | Description |
|
||||||
|
| --- | --- | --- | --- | --- | --- |
|
||||||
|
| `VITE_API_BASE` | `API_BASE` | Depends on deployment | Text | Empty | Backend API root URL beginning with `https://` and without a trailing `/`; an empty value uses the same-origin API |
|
||||||
|
| `VITE_DEFAULT_LANG` | `DEFAULT_LANG` | No | Text | `zh` | Default language: `zh`, `en`, `es`, `pt-BR`, `ja`, or `de` |
|
||||||
|
| `VITE_CF_WEB_ANALY_TOKEN` | `CF_WEB_ANALY_TOKEN` | No | Text | Empty | Cloudflare Web Analytics Token |
|
||||||
|
| `VITE_IS_TELEGRAM` | `IS_TELEGRAM` | No | Boolean | `false` | Whether to enable Telegram Mini App; see [Telegram Configuration](/en/guide/feature/telegram) |
|
||||||
|
| `VITE_GOOGLE_AD_CLIENT` | `GOOGLE_AD_CLIENT` | No | Text | Empty | Google AdSense Client ID; see [Google Ads Configuration](/en/guide/feature/google-ads) |
|
||||||
|
| `VITE_GOOGLE_AD_SLOT` | `GOOGLE_AD_SLOT` | No | Text | Empty | Google AdSense Slot ID; see [Google Ads Configuration](/en/guide/feature/google-ads) |
|
||||||
@@ -68,24 +68,34 @@ const generate = async () => {
|
|||||||
const arrayBuffer = await response.arrayBuffer();
|
const arrayBuffer = await response.arrayBuffer();
|
||||||
var zip = new JSZip();
|
var zip = new JSZip();
|
||||||
await zip.loadAsync(arrayBuffer);
|
await zip.loadAsync(arrayBuffer);
|
||||||
let target_path = ""
|
const indexEntry = zip.file("index.html");
|
||||||
const directory = zip.folder("assets");
|
if (!indexEntry) {
|
||||||
if (directory) {
|
errorMessage.value = "Could not find index.html. Generation failed"
|
||||||
for (const [relativePath, zipEntry] of Object.entries(directory.files)) {
|
|
||||||
console.log(relativePath);
|
|
||||||
if (relativePath.startsWith("assets/index-") && relativePath.endsWith(".js")){
|
|
||||||
let content = await zipEntry.async("string");
|
|
||||||
content = content.replaceAll("https://temp-email-api.xxx.xxx", normalizedDomain);
|
|
||||||
target_path = relativePath;
|
|
||||||
zip.file(relativePath, content);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!target_path) {
|
|
||||||
errorMessage.value = "Could not find the frontend entry file. Generation failed"
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
const content = await indexEntry.async("string");
|
||||||
|
const configPattern = /(<script id="app-config" type="application\/json">)([\s\S]*?)(<\/script>)/;
|
||||||
|
const configMatch = content.match(configPattern);
|
||||||
|
if (!configMatch) {
|
||||||
|
errorMessage.value = "Could not find app-config. Generation failed"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let appConfig = {};
|
||||||
|
try {
|
||||||
|
appConfig = JSON.parse(configMatch[2]);
|
||||||
|
} catch {
|
||||||
|
errorMessage.value = "Invalid app-config. Generation failed"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!appConfig || typeof appConfig !== "object" || Array.isArray(appConfig)) {
|
||||||
|
errorMessage.value = "Invalid app-config. Generation failed"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
appConfig.API_BASE = normalizedDomain;
|
||||||
|
zip.file("index.html", content.replace(
|
||||||
|
configPattern,
|
||||||
|
(_, openTag, _config, closeTag) => `${openTag}${JSON.stringify(appConfig)}${closeTag}`
|
||||||
|
));
|
||||||
const blob = await zip.generateAsync({ type: "blob" });
|
const blob = await zip.generateAsync({ type: "blob" });
|
||||||
const url = window.URL.createObjectURL(blob);
|
const url = window.URL.createObjectURL(blob);
|
||||||
errorMessage.value = ""
|
errorMessage.value = ""
|
||||||
@@ -133,12 +143,21 @@ const generate = async () => {
|
|||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
> You can also deploy manually. Download the zip from here: [frontend.zip](https://github.com/dreamhunter2333/cloudflare_temp_email/releases/latest/download/frontend.zip)
|
> You can also deploy manually. Download the zip from here: [frontend.zip](https://github.com/dreamhunter2333/cloudflare_temp_email/releases/latest/download/frontend.zip)
|
||||||
>
|
>
|
||||||
> Modify the index-xxx.js file in the archive, where xx is a random string
|
> Extract the archive and edit `app-config` in `index.html`. When finished, compress all files again and upload the archive. Do not include the outer directory in the archive.
|
||||||
>
|
|
||||||
> Search for `https://temp-email-api.xxx.xxx` and replace it with your worker's backend API root URL, then deploy the new zip file. If you replace it with the frontend Pages domain, common symptoms are the `map` error or `405` responses from API requests
|
|
||||||
>
|
>
|
||||||
> If you entered the wrong address the first time and still see errors after redeploying, test in an incognito window or clear browser cache so the browser stops using the old frontend assets.
|
> If you entered the wrong address the first time and still see errors after redeploying, test in an incognito window or clear browser cache so the browser stops using the old frontend assets.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script id="app-config" type="application/json">
|
||||||
|
{
|
||||||
|
"API_BASE": "https://temp-email-api.example.com",
|
||||||
|
"DEFAULT_LANG": "en"
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
`API_BASE` is the backend API root URL without a trailing `/`; `DEFAULT_LANG` supports `zh`, `en`, `es`, `pt-BR`, `ja`, and `de`. You can also set `CF_WEB_ANALY_TOKEN`, `IS_TELEGRAM`, `GOOGLE_AD_CLIENT`, and `GOOGLE_AD_SLOT`; see [Frontend Variables](/en/guide/frontend-vars) for their purpose and values. Fields present in `app-config` override the corresponding settings built into JavaScript, while omitted fields keep their existing settings.
|
||||||
|
|
||||||
4. Select `Pages`, click `Create Pages`, modify the name, upload the downloaded zip package
|
4. Select `Pages`, click `Create Pages`, modify the name, upload the downloaded zip package
|
||||||
|
|
||||||
> [!warning] Important: SPA Mode
|
> [!warning] Important: SPA Mode
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
|
|
||||||
| 名称 | 说明 |
|
| 名称 | 说明 |
|
||||||
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `FRONTEND_ENV` | `Deploy Frontend` workflow 使用的前端配置文件,请复制 `frontend/.env.example` 的内容,[并参考此处修改](/zh/guide/cli/pages.html)。如果是前后端分离直连 Worker,`VITE_API_BASE` 应填写后端 Worker API 根地址,并且以 `https://` 开头、末尾不要带 `/`。地址配置错误时,常见现象是前端报 `map` 错误或接口返回 `405` |
|
| `FRONTEND_ENV` | `Deploy Frontend` workflow 使用的前端配置文件,请复制 `frontend/.env.example` 的内容,并参考 [前端变量说明](/zh/guide/frontend-vars) 修改 |
|
||||||
| `FRONTEND_NAME` | 你在 Cloudflare Pages 创建的项目名称,可通过 [用户界面](https://temp-mail-docs.awsl.uk/zh/guide/ui/pages.html) 或者 [命令行](https://temp-mail-docs.awsl.uk/zh/guide/cli/pages.html) 创建 |
|
| `FRONTEND_NAME` | 你在 Cloudflare Pages 创建的项目名称,可通过 [用户界面](https://temp-mail-docs.awsl.uk/zh/guide/ui/pages.html) 或者 [命令行](https://temp-mail-docs.awsl.uk/zh/guide/cli/pages.html) 创建 |
|
||||||
| `FRONTEND_BRANCH` | (可选) pages 部署的分支,可不配置,默认 `production` |
|
| `FRONTEND_BRANCH` | (可选) pages 部署的分支,可不配置,默认 `production` |
|
||||||
| `PAGE_TOML` | (可选) 仅供 `Deploy Frontend with page function` workflow 使用。通过 page functions 转发后端请求时需要配置,请复制 `pages/wrangler.toml` 的内容,并根据实际情况修改 `service` 字段为你的 worker 后端名称。这个 workflow 会以 Pages 模式构建前端并走同域请求,因此不会读取 `FRONTEND_ENV` |
|
| `PAGE_TOML` | (可选) 仅供 `Deploy Frontend with page function` workflow 使用。通过 page functions 转发后端请求时需要配置,请复制 `pages/wrangler.toml` 的内容,并根据实际情况修改 `service` 字段为你的 worker 后端名称。这个 workflow 会以 Pages 模式构建前端并走同域请求,因此不会读取 `FRONTEND_ENV` |
|
||||||
|
|||||||
@@ -29,6 +29,12 @@ cp .env.example .env.prod
|
|||||||
|
|
||||||
例如: `VITE_API_BASE=https://xxx.xxx.workers.dev`
|
例如: `VITE_API_BASE=https://xxx.xxx.workers.dev`
|
||||||
|
|
||||||
|
可通过 `VITE_DEFAULT_LANG` 设置前端默认语言,支持 `zh`、`en`、`es`、`pt-BR`、`ja`、`de`,未配置或配置无效时使用 `zh`。
|
||||||
|
|
||||||
|
例如: `VITE_DEFAULT_LANG=en`
|
||||||
|
|
||||||
|
其他配置项请查看 [前端变量说明](/zh/guide/frontend-vars)。
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pnpm build --emptyOutDir
|
pnpm build --emptyOutDir
|
||||||
# 第一次部署会提示创建项目, production 分支请填写 production
|
# 第一次部署会提示创建项目, production 分支请填写 production
|
||||||
@@ -47,6 +53,8 @@ pnpm run deploy
|
|||||||
|
|
||||||
如果你的 worker 后端 名称不为 `cloudflare_temp_email` 请修改 `pages/wrangler.toml`
|
如果你的 worker 后端 名称不为 `cloudflare_temp_email` 请修改 `pages/wrangler.toml`
|
||||||
|
|
||||||
|
如需设置默认语言,在 `frontend/.env.pages.local` 中添加 `VITE_DEFAULT_LANG=en`。同域请求不需要设置 `VITE_API_BASE`,其他配置项请查看 [前端变量说明](/zh/guide/frontend-vars)。
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd frontend
|
cd frontend
|
||||||
pnpm install
|
pnpm install
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
# 给网页增加 Google Ads
|
# 给网页增加 Google Ads
|
||||||
|
|
||||||
## 命令行部署
|
Google Ads 使用以下两个变量,具体值请参考 [Google AdSense](https://www.google.com/adsense/start/):
|
||||||
|
|
||||||
修改 `.env.prod` 文件
|
```ini
|
||||||
|
|
||||||
增加下列两个变量, 具体的值请参考 [Google AdSense](https://www.google.com/adsense/start/) 的说明
|
|
||||||
|
|
||||||
```txt
|
|
||||||
VITE_GOOGLE_AD_CLIENT=ca-pub-123456
|
VITE_GOOGLE_AD_CLIENT=ca-pub-123456
|
||||||
VITE_GOOGLE_AD_SLOT=123456
|
VITE_GOOGLE_AD_SLOT=123456
|
||||||
```
|
```
|
||||||
|
|
||||||
然后执行下列命令, 重新部署 pages 即可.
|
任意一个变量为空时都不会加载广告。变量类型和默认值请查看 [前端变量说明](/zh/guide/frontend-vars)。
|
||||||
|
|
||||||
|
## CLI 部署
|
||||||
|
|
||||||
|
在 `frontend/.env.prod` 中添加上述两个变量,然后重新构建并部署:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pnpm build --emptyOutDir
|
pnpm build --emptyOutDir
|
||||||
@@ -19,11 +19,25 @@ pnpm build --emptyOutDir
|
|||||||
pnpm run deploy
|
pnpm run deploy
|
||||||
```
|
```
|
||||||
|
|
||||||
## GitHub Action 部署
|
完整步骤请查看 [CLI 部署前端](/zh/guide/cli/pages)。
|
||||||
|
|
||||||
修改 `FRONTEND_ENV`, 增加下列两个变量, 具体的值请参考 [Google AdSense](https://www.google.com/adsense/start/) 的说明, 重新部署 pages 即可.
|
## GitHub Actions 部署
|
||||||
|
|
||||||
```txt
|
在已有的 `FRONTEND_ENV` Secret 中添加上述两个变量,然后重新运行 `Deploy Frontend` workflow。
|
||||||
VITE_GOOGLE_AD_CLIENT=ca-pub-123456
|
|
||||||
VITE_GOOGLE_AD_SLOT=123456
|
完整步骤请查看 [GitHub Actions 部署](/zh/guide/actions/github-action)。
|
||||||
|
|
||||||
|
## 手动 ZIP 部署
|
||||||
|
|
||||||
|
编辑压缩包中 `index.html` 的 `app-config`,使用不带 `VITE_` 前缀的字段名:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script id="app-config" type="application/json">
|
||||||
|
{
|
||||||
|
"GOOGLE_AD_CLIENT": "ca-pub-123456",
|
||||||
|
"GOOGLE_AD_SLOT": "123456"
|
||||||
|
}
|
||||||
|
</script>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
完整步骤请查看 [手动 ZIP 部署](/zh/guide/ui/pages)。
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
# 前端变量说明
|
||||||
|
|
||||||
|
前端配置会公开在浏览器中,请勿填写密码、API 密钥等敏感信息。
|
||||||
|
|
||||||
|
## 配置方式
|
||||||
|
|
||||||
|
### ENV
|
||||||
|
|
||||||
|
通过 CLI 部署时,将变量写入 `frontend/.env.prod`;Worker Assets 或 Page Functions 部署写入 `frontend/.env.pages.local`。通过 GitHub Actions 的 `Deploy Frontend` workflow 部署时,将相同内容写入 Repository Secret `FRONTEND_ENV`;`Deploy Frontend with page function` workflow 不读取该 Secret。
|
||||||
|
|
||||||
|
```ini
|
||||||
|
VITE_API_BASE=https://temp-email-api.example.com
|
||||||
|
VITE_DEFAULT_LANG=en
|
||||||
|
```
|
||||||
|
|
||||||
|
完整步骤请查看 [CLI 部署](/zh/guide/cli/pages) 和 [GitHub Actions 部署](/zh/guide/actions/github-action)。
|
||||||
|
|
||||||
|
### index.html
|
||||||
|
|
||||||
|
使用构建好的前端 ZIP 时,可以编辑 `index.html` 中的 `app-config`。字段名不带 `VITE_` 前缀:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script id="app-config" type="application/json">
|
||||||
|
{
|
||||||
|
"API_BASE": "https://temp-email-api.example.com",
|
||||||
|
"DEFAULT_LANG": "en"
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
`app-config` 中填写的字段会覆盖 ENV 构建值;未填写字段或不存在 `app-config` 标签时继续使用 ENV 构建值。完整步骤请查看 [手动 ZIP 部署](/zh/guide/ui/pages)。
|
||||||
|
|
||||||
|
## 变量列表
|
||||||
|
|
||||||
|
没有所有部署方式都必须配置的前端变量。`VITE_API_BASE` 仅在前后端分离、前端需要直接请求 Worker 域名时配置;Worker Assets 或 Page Functions 等同域部署应留空。
|
||||||
|
|
||||||
|
| ENV 变量 | `app-config` 字段 | 是否必须 | 类型 | 默认值 | 说明 |
|
||||||
|
| --- | --- | --- | --- | --- | --- |
|
||||||
|
| `VITE_API_BASE` | `API_BASE` | 视部署方式 | 文本 | 空 | 以 `https://` 开头的后端 API 根地址,不要带结尾 `/`;空值表示使用同域 API |
|
||||||
|
| `VITE_DEFAULT_LANG` | `DEFAULT_LANG` | 否 | 文本 | `zh` | 默认语言,支持 `zh`、`en`、`es`、`pt-BR`、`ja`、`de` |
|
||||||
|
| `VITE_CF_WEB_ANALY_TOKEN` | `CF_WEB_ANALY_TOKEN` | 否 | 文本 | 空 | Cloudflare Web Analytics Token |
|
||||||
|
| `VITE_IS_TELEGRAM` | `IS_TELEGRAM` | 否 | 布尔值 | `false` | 是否启用 Telegram Mini App,详见 [Telegram 配置](/zh/guide/feature/telegram) |
|
||||||
|
| `VITE_GOOGLE_AD_CLIENT` | `GOOGLE_AD_CLIENT` | 否 | 文本 | 空 | Google AdSense Client ID,详见 [Google Ads 配置](/zh/guide/feature/google-ads) |
|
||||||
|
| `VITE_GOOGLE_AD_SLOT` | `GOOGLE_AD_SLOT` | 否 | 文本 | 空 | Google AdSense Slot ID,详见 [Google Ads 配置](/zh/guide/feature/google-ads) |
|
||||||
@@ -68,24 +68,34 @@ const generate = async () => {
|
|||||||
const arrayBuffer = await response.arrayBuffer();
|
const arrayBuffer = await response.arrayBuffer();
|
||||||
var zip = new JSZip();
|
var zip = new JSZip();
|
||||||
await zip.loadAsync(arrayBuffer);
|
await zip.loadAsync(arrayBuffer);
|
||||||
let target_path = ""
|
const indexEntry = zip.file("index.html");
|
||||||
const directory = zip.folder("assets");
|
if (!indexEntry) {
|
||||||
if (directory) {
|
errorMessage.value = "没有找到 index.html,生成失败"
|
||||||
for (const [relativePath, zipEntry] of Object.entries(directory.files)) {
|
|
||||||
console.log(relativePath);
|
|
||||||
if (relativePath.startsWith("assets/index-") && relativePath.endsWith(".js")){
|
|
||||||
let content = await zipEntry.async("string");
|
|
||||||
content = content.replaceAll("https://temp-email-api.xxx.xxx", normalizedDomain);
|
|
||||||
target_path = relativePath;
|
|
||||||
zip.file(relativePath, content);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!target_path) {
|
|
||||||
errorMessage.value = "没有找到前端入口文件,生成失败"
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
const content = await indexEntry.async("string");
|
||||||
|
const configPattern = /(<script id="app-config" type="application\/json">)([\s\S]*?)(<\/script>)/;
|
||||||
|
const configMatch = content.match(configPattern);
|
||||||
|
if (!configMatch) {
|
||||||
|
errorMessage.value = "没有找到 app-config,生成失败"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let appConfig = {};
|
||||||
|
try {
|
||||||
|
appConfig = JSON.parse(configMatch[2]);
|
||||||
|
} catch {
|
||||||
|
errorMessage.value = "app-config 格式错误,生成失败"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!appConfig || typeof appConfig !== "object" || Array.isArray(appConfig)) {
|
||||||
|
errorMessage.value = "app-config 格式错误,生成失败"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
appConfig.API_BASE = normalizedDomain;
|
||||||
|
zip.file("index.html", content.replace(
|
||||||
|
configPattern,
|
||||||
|
(_, openTag, _config, closeTag) => `${openTag}${JSON.stringify(appConfig)}${closeTag}`
|
||||||
|
));
|
||||||
const blob = await zip.generateAsync({ type: "blob" });
|
const blob = await zip.generateAsync({ type: "blob" });
|
||||||
const url = window.URL.createObjectURL(blob);
|
const url = window.URL.createObjectURL(blob);
|
||||||
errorMessage.value = ""
|
errorMessage.value = ""
|
||||||
@@ -133,12 +143,21 @@ const generate = async () => {
|
|||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
> 你也可以手动部署,从这里下载 zip, [frontend.zip](https://github.com/dreamhunter2333/cloudflare_temp_email/releases/latest/download/frontend.zip)
|
> 你也可以手动部署,从这里下载 zip, [frontend.zip](https://github.com/dreamhunter2333/cloudflare_temp_email/releases/latest/download/frontend.zip)
|
||||||
>
|
>
|
||||||
> 修改压缩包里面的 index-xxx.js 文件 ,xx 是随机的字符串
|
> 解压后编辑 `index.html` 中的 `app-config`,完成后重新压缩全部文件并上传。不要把外层目录一起压缩。
|
||||||
>
|
|
||||||
> 搜索 `https://temp-email-api.xxx.xxx` ,替换成你 worker 的后端 API 根地址,然后部署新的 zip 文件。如果填成前端 Pages 域名,常见现象就是页面报 `map` 错误或接口返回 `405`
|
|
||||||
>
|
>
|
||||||
> 如果第一次填错后重新部署仍然报错,请用无痕窗口测试或清理浏览器缓存,避免浏览器继续使用旧的前端资源。
|
> 如果第一次填错后重新部署仍然报错,请用无痕窗口测试或清理浏览器缓存,避免浏览器继续使用旧的前端资源。
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script id="app-config" type="application/json">
|
||||||
|
{
|
||||||
|
"API_BASE": "https://temp-email-api.example.com",
|
||||||
|
"DEFAULT_LANG": "en"
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
`API_BASE` 是后端 API 根地址,不要带结尾 `/`;`DEFAULT_LANG` 支持 `zh`、`en`、`es`、`pt-BR`、`ja`、`de`。还可以设置 `CF_WEB_ANALY_TOKEN`、`IS_TELEGRAM`、`GOOGLE_AD_CLIENT`、`GOOGLE_AD_SLOT`,用途和取值请查看 [前端变量说明](/zh/guide/frontend-vars)。`app-config` 中存在的字段会覆盖构建进 JS 的对应配置,未填写的字段继续使用原配置。
|
||||||
|
|
||||||
4. 选择 `Pages`,点击 `Create Pages`, 修改名称,上传下载的 zip 包
|
4. 选择 `Pages`,点击 `Create Pages`, 修改名称,上传下载的 zip 包
|
||||||
|
|
||||||
> [!warning] 重要:SPA 模式
|
> [!warning] 重要:SPA 模式
|
||||||
|
|||||||
Reference in New Issue
Block a user