Compare commits

...

10 Commits

Author SHA1 Message Date
Simon b36a0c0261 chore(version): bump version to 0.0.13 2025-12-17 19:32:24 +08:00
Simon 339b066d2d fix(UMD): delay init 2025-12-17 19:31:28 +08:00
Simon c8efffa80a fix: update dotenv import and load config 2025-12-17 15:27:15 +08:00
Simon 59235263ad Merge pull request #80 from alibaba/fix/isPageDark
fix: isPageDark robust
2025-12-17 14:44:17 +08:00
Simon bc1e8fea3c fix: handle null body element 2025-12-17 14:40:11 +08:00
Simon 85a4096b2d chore(version): bump version to 0.0.12 2025-12-17 14:18:28 +08:00
Simon 0ef84bac13 chore: simplify Vite configuration 2025-12-16 20:38:15 +08:00
Simon a7834c77e1 docs: CDN and mirror 2025-12-16 20:23:17 +08:00
Simon 030e5cfc54 docs: stable CDN 2025-12-16 20:21:46 +08:00
Simon aa694e3b85 docs: stable CDN 2025-12-16 20:17:58 +08:00
19 changed files with 180 additions and 145 deletions
+5 -4
View File
@@ -31,10 +31,11 @@
### CDN 集成 ### CDN 集成
```html ```html
<!-- 临时 CDN URL. 未来会变更 --> // CDN - https://cdn.jsdelivr.net/npm/page-agent@latest/dist/umd/page-agent.js
<script // Mirror(CN) - https://registry.npmmirror.com/page-agent/latest/files/dist/umd/page-agent.js
src="https://hwcxiuzfylggtcktqgij.supabase.co/storage/v1/object/public/demo-public/v0.0.4/page-agent.js" <script
crossorigin="true" src="https://registry.npmmirror.com/page-agent/latest/files/dist/umd/page-agent.js"
crossorigin="true"
type="text/javascript" type="text/javascript"
></script> ></script>
``` ```
+5 -4
View File
@@ -31,10 +31,11 @@ The GUI Agent Living in Your Webpage. Control web interfaces with natural langua
### CDN Integration ### CDN Integration
```html ```html
<!-- temporary CDN URL. May change in the future --> // CDN - https://cdn.jsdelivr.net/npm/page-agent@latest/dist/umd/page-agent.js
<script // Mirror(CN) - https://registry.npmmirror.com/page-agent/latest/files/dist/umd/page-agent.js
src="https://hwcxiuzfylggtcktqgij.supabase.co/storage/v1/object/public/demo-public/v0.0.4/page-agent.js" <script
crossorigin="true" src="https://cdn.jsdelivr.net/npm/page-agent@latest/dist/umd/page-agent.js"
crossorigin="true"
type="text/javascript" type="text/javascript"
></script> ></script>
``` ```
+8 -8
View File
@@ -1,12 +1,12 @@
{ {
"name": "root", "name": "root",
"version": "0.0.11", "version": "0.0.13",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "root", "name": "root",
"version": "0.0.11", "version": "0.0.13",
"license": "MIT", "license": "MIT",
"workspaces": [ "workspaces": [
"packages/page-controller", "packages/page-controller",
@@ -7184,23 +7184,23 @@
} }
}, },
"packages/page-agent": { "packages/page-agent": {
"version": "0.0.11", "version": "0.0.13",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@page-agent/page-controller": "0.0.11", "@page-agent/page-controller": "0.0.13",
"@page-agent/ui": "0.0.11", "@page-agent/ui": "0.0.13",
"chalk": "^5.6.2", "chalk": "^5.6.2",
"zod": "^4.2.0" "zod": "^4.2.0"
} }
}, },
"packages/page-controller": { "packages/page-controller": {
"name": "@page-agent/page-controller", "name": "@page-agent/page-controller",
"version": "0.0.11", "version": "0.0.13",
"license": "MIT" "license": "MIT"
}, },
"packages/ui": { "packages/ui": {
"name": "@page-agent/ui", "name": "@page-agent/ui",
"version": "0.0.11", "version": "0.0.13",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"ai-motion": "^0.4.7" "ai-motion": "^0.4.7"
@@ -7208,7 +7208,7 @@
}, },
"packages/website": { "packages/website": {
"name": "@page-agent/website", "name": "@page-agent/website",
"version": "0.0.11", "version": "0.0.13",
"devDependencies": { "devDependencies": {
"@tailwindcss/vite": "^4.1.18", "@tailwindcss/vite": "^4.1.18",
"@types/react": "^19.2.2", "@types/react": "^19.2.2",
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "root", "name": "root",
"private": true, "private": true,
"version": "0.0.11", "version": "0.0.13",
"type": "module", "type": "module",
"workspaces": [ "workspaces": [
"packages/page-controller", "packages/page-controller",
+5 -5
View File
@@ -1,7 +1,7 @@
{ {
"name": "page-agent", "name": "page-agent",
"private": false, "private": false,
"version": "0.0.11", "version": "0.0.13",
"type": "module", "type": "module",
"main": "./dist/esm/page-agent.js", "main": "./dist/esm/page-agent.js",
"module": "./dist/esm/page-agent.js", "module": "./dist/esm/page-agent.js",
@@ -37,16 +37,16 @@
}, },
"homepage": "https://alibaba.github.io/page-agent/", "homepage": "https://alibaba.github.io/page-agent/",
"scripts": { "scripts": {
"build": "vite build && MODE=umd vite build", "build": "vite build && vite build --config vite.umd.config.js",
"serve": "npx serve dist/umd -p 5173", "serve": "npx serve dist/umd -p 5173",
"dev:umd": "concurrently \"MODE=umd vite build --watch\" \"npm run serve\"", "dev:umd": "concurrently \"vite build --config vite.umd.config.js --watch\" \"npm run serve\"",
"prepublishOnly": "node -e \"const fs=require('fs');['README.md','LICENSE'].forEach(f=>fs.copyFileSync('../../'+f,f))\"", "prepublishOnly": "node -e \"const fs=require('fs');['README.md','LICENSE'].forEach(f=>fs.copyFileSync('../../'+f,f))\"",
"postpublish": "node -e \"['README.md','LICENSE'].forEach(f=>{try{require('fs').unlinkSync(f)}catch{}})\"" "postpublish": "node -e \"['README.md','LICENSE'].forEach(f=>{try{require('fs').unlinkSync(f)}catch{}})\""
}, },
"dependencies": { "dependencies": {
"chalk": "^5.6.2", "chalk": "^5.6.2",
"zod": "^4.2.0", "zod": "^4.2.0",
"@page-agent/page-controller": "0.0.11", "@page-agent/page-controller": "0.0.13",
"@page-agent/ui": "0.0.11" "@page-agent/ui": "0.0.13"
} }
} }
+20 -16
View File
@@ -20,21 +20,25 @@ const DEMO_MODEL = 'PAGE-AGENT-FREE-TESTING-RANDOM'
const DEMO_BASE_URL = 'https://hwcxiuzfylggtcktqgij.supabase.co/functions/v1/llm-testing-proxy' const DEMO_BASE_URL = 'https://hwcxiuzfylggtcktqgij.supabase.co/functions/v1/llm-testing-proxy'
const DEMO_API_KEY = 'PAGE-AGENT-FREE-TESTING-RANDOM' const DEMO_API_KEY = 'PAGE-AGENT-FREE-TESTING-RANDOM'
const currentScript = document.currentScript as HTMLScriptElement | null // in case document.x is not ready yet
if (currentScript) { // @todo give a switch to disable auto-init
console.log('🚀 page-agent.js detected current script:', currentScript.src) setTimeout(() => {
const url = new URL(currentScript.src) const currentScript = document.currentScript as HTMLScriptElement | null
const model = url.searchParams.get('model') || DEMO_MODEL if (currentScript) {
const baseURL = url.searchParams.get('baseURL') || DEMO_BASE_URL console.log('🚀 page-agent.js detected current script:', currentScript.src)
const apiKey = url.searchParams.get('apiKey') || DEMO_API_KEY const url = new URL(currentScript.src)
const language = (url.searchParams.get('lang') as 'zh-CN' | 'en-US') || 'zh-CN' const model = url.searchParams.get('model') || DEMO_MODEL
const config: PageAgentConfig = { model, baseURL, apiKey, language } const baseURL = url.searchParams.get('baseURL') || DEMO_BASE_URL
window.pageAgent = new PageAgent(config) const apiKey = url.searchParams.get('apiKey') || DEMO_API_KEY
} else { const language = (url.searchParams.get('lang') as 'zh-CN' | 'en-US') || 'zh-CN'
console.log('🚀 page-agent.js no current script detected, using default demo config') const config: PageAgentConfig = { model, baseURL, apiKey, language }
window.pageAgent = new PageAgent() window.pageAgent = new PageAgent(config)
} } else {
console.log('🚀 page-agent.js no current script detected, using default demo config')
window.pageAgent = new PageAgent()
}
console.log('🚀 page-agent.js initialized with config:', window.pageAgent.config) console.log('🚀 page-agent.js initialized with config:', window.pageAgent.config)
window.pageAgent.panel.show() // Show panel window.pageAgent.panel.show() // Show panel
})
+2 -62
View File
@@ -1,7 +1,4 @@
// @ts-check // @ts-check
import chalk from 'chalk'
import 'dotenv/config'
import process from 'node:process'
import { dirname, resolve } from 'path' import { dirname, resolve } from 'path'
import dts from 'unplugin-dts/vite' import dts from 'unplugin-dts/vite'
import { fileURLToPath } from 'url' import { fileURLToPath } from 'url'
@@ -10,11 +7,8 @@ import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js'
const __dirname = dirname(fileURLToPath(import.meta.url)) const __dirname = dirname(fileURLToPath(import.meta.url))
// ============================================================================
// ES Module for NPM Package // ES Module for NPM Package
// ============================================================================ export default defineConfig({
/** @type {import('vite').UserConfig} */
const esmConfig = {
clearScreen: false, clearScreen: false,
plugins: [ plugins: [
dts({ tsconfigPath: './tsconfig.dts.json', bundleTypes: true }), dts({ tsconfigPath: './tsconfig.dts.json', bundleTypes: true }),
@@ -47,58 +41,4 @@ const esmConfig = {
define: { define: {
'process.env.NODE_ENV': '"production"', 'process.env.NODE_ENV': '"production"',
}, },
} })
// ============================================================================
// UMD Bundle for CDN
// - alias all local packages so that they can be build in
// - no external
// - no d.ts. dts does not work with monorepo aliasing
// ============================================================================
/** @type {import('vite').UserConfig} */
const umdConfig = {
plugins: [cssInjectedByJsPlugin({ relativeCSSInjection: true })],
publicDir: false,
esbuild: {
keepNames: true,
},
resolve: {
alias: {
'@page-agent/page-controller': resolve(__dirname, '../page-controller/src/PageController.ts'),
'@page-agent/ui': resolve(__dirname, '../ui/src/index.ts'),
},
},
build: {
lib: {
entry: resolve(__dirname, 'src/umd.ts'),
name: 'PageAgent',
fileName: 'page-agent',
formats: ['umd'],
},
outDir: resolve(__dirname, 'dist', 'umd'),
rollupOptions: {
output: {
entryFileNames: 'page-agent.js', // 强制指定完整文件名
},
},
cssCodeSplit: true,
},
define: {
'process.env.NODE_ENV': '"production"',
},
}
// ============================================================================
const MODE = process.env.MODE
console.log(chalk.cyan(`📦 Build mode: ${chalk.bold(MODE || 'esm')}`))
let config
if (MODE === 'umd') {
config = umdConfig
} else {
config = esmConfig
}
export default defineConfig(config)
+44
View File
@@ -0,0 +1,44 @@
// @ts-check
import { dirname, resolve } from 'path'
import { fileURLToPath } from 'url'
import { defineConfig } from 'vite'
import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js'
const __dirname = dirname(fileURLToPath(import.meta.url))
// UMD Bundle for CDN
// - alias all local packages so that they can be build in
// - no external
// - no d.ts. dts does not work with monorepo aliasing
export default defineConfig({
plugins: [cssInjectedByJsPlugin({ relativeCSSInjection: true })],
publicDir: false,
esbuild: {
keepNames: true,
},
resolve: {
alias: {
'@page-agent/page-controller': resolve(__dirname, '../page-controller/src/PageController.ts'),
'@page-agent/ui': resolve(__dirname, '../ui/src/index.ts'),
},
},
build: {
lib: {
entry: resolve(__dirname, 'src/umd.ts'),
name: 'PageAgent',
fileName: 'page-agent',
formats: ['umd'],
},
outDir: resolve(__dirname, 'dist', 'umd'),
rollupOptions: {
output: {
// force use .js as extension
entryFileNames: 'page-agent.js',
},
},
cssCodeSplit: true,
},
define: {
'process.env.NODE_ENV': '"production"',
},
})
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@page-agent/page-controller", "name": "@page-agent/page-controller",
"version": "0.0.11", "version": "0.0.13",
"type": "module", "type": "module",
"main": "./dist/lib/page-controller.js", "main": "./dist/lib/page-controller.js",
"module": "./dist/lib/page-controller.js", "module": "./dist/lib/page-controller.js",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@page-agent/ui", "name": "@page-agent/ui",
"version": "0.0.11", "version": "0.0.13",
"type": "module", "type": "module",
"main": "./dist/lib/page-agent-ui.js", "main": "./dist/lib/page-agent-ui.js",
"module": "./dist/lib/page-agent-ui.js", "module": "./dist/lib/page-agent-ui.js",
+23 -18
View File
@@ -3,14 +3,14 @@
* @returns {boolean} - True if a common dark mode class is found. * @returns {boolean} - True if a common dark mode class is found.
*/ */
function hasDarkModeClass() { function hasDarkModeClass() {
const DFEAULT_DARK_MODE_CLASSES = ['dark', 'dark-mode', 'theme-dark', 'night', 'night-mode'] const DEFAULT_DARK_MODE_CLASSES = ['dark', 'dark-mode', 'theme-dark', 'night', 'night-mode']
const htmlElement = document.documentElement const htmlElement = document.documentElement
const bodyElement = document.body const bodyElement = document.body || document.documentElement // can be null in some cases
// Check class names on <html> and <body> // Check class names on <html> and <body>
for (const className of DFEAULT_DARK_MODE_CLASSES) { for (const className of DEFAULT_DARK_MODE_CLASSES) {
if (htmlElement.classList.contains(className) || bodyElement.classList.contains(className)) { if (htmlElement.classList.contains(className) || bodyElement?.classList.contains(className)) {
return true return true
} }
} }
@@ -70,7 +70,7 @@ function isColorDark(colorString: string, threshold = 128) {
function isBackgroundDark() { function isBackgroundDark() {
// We check both <html> and <body> because some pages set the color on <html> // We check both <html> and <body> because some pages set the color on <html>
const htmlStyle = window.getComputedStyle(document.documentElement) const htmlStyle = window.getComputedStyle(document.documentElement)
const bodyStyle = window.getComputedStyle(document.body) const bodyStyle = window.getComputedStyle(document.body || document.documentElement)
// Get background colors // Get background colors
const htmlBgColor = htmlStyle.backgroundColor const htmlBgColor = htmlStyle.backgroundColor
@@ -93,18 +93,23 @@ function isBackgroundDark() {
* @returns {boolean} - True if the page is likely dark. * @returns {boolean} - True if the page is likely dark.
*/ */
export function isPageDark() { export function isPageDark() {
// Strategy 1: Check for common dark mode classes try {
if (hasDarkModeClass()) { // Strategy 1: Check for common dark mode classes
return true if (hasDarkModeClass()) {
return true
}
// Strategy 2: Analyze the computed background color
if (isBackgroundDark()) {
return true
}
// @TODO add more checks here, e.g., analyzing text color,
// or checking the background of major layout elements like <main> or #app.
return false
} catch (error) {
console.warn('Error determining if page is dark:', error)
return false
} }
// Strategy 2: Analyze the computed background color
if (isBackgroundDark()) {
return true
}
// @TODO add more checks here, e.g., analyzing text color,
// or checking the background of major layout elements like <main> or #app.
return false
} }
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "@page-agent/website", "name": "@page-agent/website",
"private": true, "private": true,
"version": "0.0.11", "version": "0.0.13",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
+3
View File
@@ -0,0 +1,3 @@
export const CDN_URL = 'https://cdn.jsdelivr.net/npm/page-agent@latest/dist/umd/page-agent.js'
export const CDN_CN_URL =
'https://registry.npmmirror.com/page-agent/latest/files/dist/umd/page-agent.js'
@@ -1,5 +1,6 @@
import BetaNotice from '@/components/BetaNotice' import BetaNotice from '@/components/BetaNotice'
import CodeEditor from '@/components/CodeEditor' import CodeEditor from '@/components/CodeEditor'
import { CDN_CN_URL, CDN_URL } from '@/constants'
export default function CdnSetup() { export default function CdnSetup() {
return ( return (
@@ -15,11 +16,16 @@ export default function CdnSetup() {
<CodeEditor <CodeEditor
className="mb-8" className="mb-8"
code={` code={`
// 仅供测试使用,稳定 CDN 待定 // CDN: \t${CDN_URL}
<script src="https://hwcxiuzfylggtcktqgij.supabase.co/storage/v1/object/public/demo-public/v0.0.4/page-agent.js" crossorigin="true" type="text/javascript"></script> // Mirror: \t${CDN_CN_URL}
<script
src="${CDN_URL}"
crossorigin="true"
type="text/javascript"
></script>
<script> <script>
window.pageAgent.panel.show() // window.pageAgent
</script>`} </script>`}
/> />
@@ -2,6 +2,7 @@ import { useTranslation } from 'react-i18next'
import BetaNotice from '@/components/BetaNotice' import BetaNotice from '@/components/BetaNotice'
import CodeEditor from '@/components/CodeEditor' import CodeEditor from '@/components/CodeEditor'
import { CDN_CN_URL, CDN_URL } from '@/constants'
export default function QuickStart() { export default function QuickStart() {
const { t } = useTranslation('docs') const { t } = useTranslation('docs')
@@ -23,8 +24,9 @@ export default function QuickStart() {
<div> <div>
<p className="text-sm font-medium mb-2">{t('quick_start.step1_cdn')}</p> <p className="text-sm font-medium mb-2">{t('quick_start.step1_cdn')}</p>
<CodeEditor <CodeEditor
code={`// 仅供测试使用 code={`// CDN: \t${CDN_URL}
<script src="https://hwcxiuzfylggtcktqgij.supabase.co/storage/v1/object/public/demo-public/v0.0.4/page-agent.js" crossorigin="true" type="text/javascript"></script>`} // Mirror: \t${CDN_CN_URL}
<script src="${CDN_URL}" crossorigin="true" type="text/javascript"></script>`}
language="html" language="html"
/> />
</div> </div>
@@ -18,6 +18,9 @@ export default {
step1_content: 'Show your bookmarks bar', step1_content: 'Show your bookmarks bar',
step2_title: 'Step 2:', step2_title: 'Step 2:',
step2_content: 'Drag this button to your bookmarks', step2_content: 'Drag this button to your bookmarks',
cdn_label: 'CDN Source',
cdn_international: 'International',
cdn_china: 'China Mirror',
step3_title: 'Step 3:', step3_title: 'Step 3:',
step3_content: 'Click the bookmark on any site to activate', step3_content: 'Click the bookmark on any site to activate',
notice_title: '⚠️ Heads Up', notice_title: '⚠️ Heads Up',
@@ -17,6 +17,9 @@ export default {
step1_content: '显示收藏夹栏', step1_content: '显示收藏夹栏',
step2_title: '步骤 2:', step2_title: '步骤 2:',
step2_content: '拖拽下面按钮到收藏夹栏', step2_content: '拖拽下面按钮到收藏夹栏',
cdn_label: 'CDN 源',
cdn_international: '国际',
cdn_china: '国内镜像',
step3_title: '步骤 3:', step3_title: '步骤 3:',
step3_content: '在其他网站点击收藏夹中的按钮即可使用', step3_content: '在其他网站点击收藏夹中的按钮即可使用',
notice_title: '⚠️ 注意', notice_title: '⚠️ 注意',
+38 -18
View File
@@ -6,23 +6,27 @@ import { Link, useSearchParams } from 'wouter'
import Footer from './components/Footer' import Footer from './components/Footer'
import Header from './components/Header' import Header from './components/Header'
import { CDN_CN_URL, CDN_URL } from './constants'
const injection = encodeURI( function getInjection(useCN?: boolean) {
"javascript:(function(){var s=document.createElement('script');s.src=`https://hwcxiuzfylggtcktqgij.supabase.co/storage/v1/object/public/demo-public/v0.0.4/page-agent.js?t=${Math.random()}`;s.setAttribute('crossorigin', true);s.type=`text/javascript`;s.onload=()=>console.log('PageAgent script loaded!');document.body.appendChild(s);})();" const cdn = useCN ? CDN_CN_URL : CDN_URL
)
const injectionA = ` const injection = encodeURI(
<a `javascript:(function(){var s=document.createElement('script');s.src=\`${cdn}?t=\${Math.random()}\`;s.setAttribute('crossorigin', true);s.type="text/javascript";s.onload=()=>console.log('PageAgent script loaded!');document.body.appendChild(s);})();`
href=${injection} )
class="inline-flex items-center text-xs px-3 py-2 bg-blue-500 text-white font-medium rounded-lg hover:shadow-md transform hover:scale-105 transition-all duration-200 cursor-move border-2 border-dashed border-green-300"
draggable="true"
onclick="return false;"
title="Drag me to your bookmarks bar!"
>
✨PageAgent
</a>
` return `
<a
href=${injection}
class="inline-flex items-center text-xs px-3 py-2 bg-blue-500 text-white font-medium rounded-lg hover:shadow-md transform hover:scale-105 transition-all duration-200 cursor-move border-2 border-dashed border-green-300"
draggable="true"
onclick="return false;"
title="Drag me to your bookmarks bar!"
>
✨PageAgent
</a>
`
}
export default function HomePage() { export default function HomePage() {
const { t, i18n } = useTranslation(['home', 'common']) const { t, i18n } = useTranslation(['home', 'common'])
@@ -38,6 +42,7 @@ export default function HomePage() {
const isOther = params.has('try_other') const isOther = params.has('try_other')
const [activeTab, setActiveTab] = useState<'try' | 'other'>(isOther ? 'other' : 'try') const [activeTab, setActiveTab] = useState<'try' | 'other'>(isOther ? 'other' : 'try')
const [cdnSource, setCdnSource] = useState<'international' | 'china'>('international')
const handleExecute = async () => { const handleExecute = async () => {
if (!task.trim()) return if (!task.trim()) return
@@ -194,10 +199,25 @@ export default function HomePage() {
</span>{' '} </span>{' '}
{t('home:try_other.step2_content')} {t('home:try_other.step2_content')}
</p> </p>
<div <div className="flex items-center justify-center gap-3">
className="flex items-center justify-center gap-2 text-gray-500 dark:text-gray-400" <select
dangerouslySetInnerHTML={{ __html: injectionA }} value={cdnSource}
></div> onChange={(e) =>
setCdnSource(e.target.value as 'international' | 'china')
}
className="px-2 py-1.5 text-xs border border-gray-300 dark:border-gray-500 rounded bg-white dark:bg-gray-600 text-gray-700 dark:text-gray-200"
>
<option value="international">
{t('home:try_other.cdn_international')}
</option>
<option value="china">{t('home:try_other.cdn_china')}</option>
</select>
<div
dangerouslySetInnerHTML={{
__html: getInjection(cdnSource === 'china'),
}}
></div>
</div>
</div> </div>
{/* Usage Instructions */} {/* Usage Instructions */}
+4 -1
View File
@@ -1,6 +1,6 @@
import tailwindcss from '@tailwindcss/vite' import tailwindcss from '@tailwindcss/vite'
import react from '@vitejs/plugin-react-swc' import react from '@vitejs/plugin-react-swc'
import 'dotenv/config' import { config as dotenvConfig } from 'dotenv'
import process from 'node:process' import process from 'node:process'
import { dirname, resolve } from 'path' import { dirname, resolve } from 'path'
import { fileURLToPath } from 'url' import { fileURLToPath } from 'url'
@@ -8,6 +8,9 @@ import { defineConfig } from 'vite'
const __dirname = dirname(fileURLToPath(import.meta.url)) const __dirname = dirname(fileURLToPath(import.meta.url))
// Load .env from repo root
dotenvConfig({ path: resolve(__dirname, '../../.env') })
// Website Config (React Documentation Site) // Website Config (React Documentation Site)
export default defineConfig({ export default defineConfig({
base: './', base: './',