Compare commits

...

7 Commits

Author SHA1 Message Date
Simon 4807d550a3 chore(version): bump version to 1.4.2 2026-03-03 21:54:41 +08:00
Simon f9722f0619 Merge branch 'main' of https://github.com/alibaba/page-agent 2026-03-03 21:53:35 +08:00
Simon e1557a5d2e Merge pull request #156 from hobostay/main
fix(actions): remove debug console.log statements
2026-03-03 21:53:05 +08:00
Simon 06280c2ba5 chore(core): add wait time between steps for the page to react 2026-03-03 21:51:10 +08:00
Simon 645a7ceb52 feat(website): loading time optimize 2026-03-03 21:38:29 +08:00
hobostay a47c72ce84 fix(actions): remove debug console.log statements
Remove [SCROLL DEBUG] console.log statements that were left over
from development in scrollVertically and scrollHorizontally
functions. These debug statements should not be in production code.
2026-03-03 21:36:59 +08:00
Simon dcc6cd1cf3 feat(website): reduce white screen time 2026-03-03 21:05:16 +08:00
19 changed files with 124 additions and 128 deletions
+2 -2
View File
@@ -49,8 +49,8 @@ Fastest way to try PageAgent with our free Demo LLM:
| Mirrors | URL | | Mirrors | URL |
| ------- | ---------------------------------------------------------------------------------- | | ------- | ---------------------------------------------------------------------------------- |
| Global | https://cdn.jsdelivr.net/npm/page-agent@1.4.1/dist/iife/page-agent.demo.js | | Global | https://cdn.jsdelivr.net/npm/page-agent@1.4.2/dist/iife/page-agent.demo.js |
| China | https://registry.npmmirror.com/page-agent/1.4.1/files/dist/iife/page-agent.demo.js | | China | https://registry.npmmirror.com/page-agent/1.4.2/files/dist/iife/page-agent.demo.js |
> **⚠️ For technical evaluation only.** This demo CDN uses our free [testing LLM API](https://alibaba.github.io/page-agent/docs/features/models#free-testing-api). By using it, you agree to its [terms](https://github.com/alibaba/page-agent/blob/main/docs/terms-and-privacy.md). > **⚠️ For technical evaluation only.** This demo CDN uses our free [testing LLM API](https://alibaba.github.io/page-agent/docs/features/models#free-testing-api). By using it, you agree to its [terms](https://github.com/alibaba/page-agent/blob/main/docs/terms-and-privacy.md).
+2 -2
View File
@@ -49,8 +49,8 @@
| Mirrors | URL | | Mirrors | URL |
| ------- | ---------------------------------------------------------------------------------- | | ------- | ---------------------------------------------------------------------------------- |
| Global | https://cdn.jsdelivr.net/npm/page-agent@1.4.1/dist/iife/page-agent.demo.js | | Global | https://cdn.jsdelivr.net/npm/page-agent@1.4.2/dist/iife/page-agent.demo.js |
| China | https://registry.npmmirror.com/page-agent/1.4.1/files/dist/iife/page-agent.demo.js | | China | https://registry.npmmirror.com/page-agent/1.4.2/files/dist/iife/page-agent.demo.js |
> **⚠️ 仅用于技术评估。** 该 Demo CDN 使用了免费的[测试 LLM API](https://alibaba.github.io/page-agent/docs/features/models#free-testing-api),使用即表示您同意其[条款](https://github.com/alibaba/page-agent/blob/main/docs/terms-and-privacy.md)。 > **⚠️ 仅用于技术评估。** 该 Demo CDN 使用了免费的[测试 LLM API](https://alibaba.github.io/page-agent/docs/features/models#free-testing-api),使用即表示您同意其[条款](https://github.com/alibaba/page-agent/blob/main/docs/terms-and-privacy.md)。
+18 -18
View File
@@ -1,12 +1,12 @@
{ {
"name": "root", "name": "root",
"version": "1.4.1", "version": "1.4.2",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "root", "name": "root",
"version": "1.4.1", "version": "1.4.2",
"license": "MIT", "license": "MIT",
"workspaces": [ "workspaces": [
"packages/page-controller", "packages/page-controller",
@@ -11161,11 +11161,11 @@
}, },
"packages/core": { "packages/core": {
"name": "@page-agent/core", "name": "@page-agent/core",
"version": "1.4.1", "version": "1.4.2",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@page-agent/llms": "1.4.1", "@page-agent/llms": "1.4.2",
"@page-agent/page-controller": "1.4.1", "@page-agent/page-controller": "1.4.2",
"chalk": "^5.6.2", "chalk": "^5.6.2",
"zod": "^4.3.5" "zod": "^4.3.5"
} }
@@ -11175,10 +11175,10 @@
"version": "0.1.8", "version": "0.1.8",
"hasInstallScript": true, "hasInstallScript": true,
"dependencies": { "dependencies": {
"@page-agent/core": "1.4.1", "@page-agent/core": "1.4.2",
"@page-agent/llms": "1.4.1", "@page-agent/llms": "1.4.2",
"@page-agent/page-controller": "1.4.1", "@page-agent/page-controller": "1.4.2",
"@page-agent/ui": "1.4.1", "@page-agent/ui": "1.4.2",
"ai-motion": "^0.4.8", "ai-motion": "^0.4.8",
"chalk": "^5.6.2", "chalk": "^5.6.2",
"zod": "^4.3.5" "zod": "^4.3.5"
@@ -11214,7 +11214,7 @@
}, },
"packages/llms": { "packages/llms": {
"name": "@page-agent/llms", "name": "@page-agent/llms",
"version": "1.4.1", "version": "1.4.2",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"chalk": "^5.6.2", "chalk": "^5.6.2",
@@ -11222,20 +11222,20 @@
} }
}, },
"packages/page-agent": { "packages/page-agent": {
"version": "1.4.1", "version": "1.4.2",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@page-agent/core": "1.4.1", "@page-agent/core": "1.4.2",
"@page-agent/llms": "1.4.1", "@page-agent/llms": "1.4.2",
"@page-agent/page-controller": "1.4.1", "@page-agent/page-controller": "1.4.2",
"@page-agent/ui": "1.4.1", "@page-agent/ui": "1.4.2",
"chalk": "^5.6.2", "chalk": "^5.6.2",
"zod": "^4.3.5" "zod": "^4.3.5"
} }
}, },
"packages/page-controller": { "packages/page-controller": {
"name": "@page-agent/page-controller", "name": "@page-agent/page-controller",
"version": "1.4.1", "version": "1.4.2",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"ai-motion": "^0.4.8" "ai-motion": "^0.4.8"
@@ -11243,12 +11243,12 @@
}, },
"packages/ui": { "packages/ui": {
"name": "@page-agent/ui", "name": "@page-agent/ui",
"version": "1.4.1", "version": "1.4.2",
"license": "MIT" "license": "MIT"
}, },
"packages/website": { "packages/website": {
"name": "@page-agent/website", "name": "@page-agent/website",
"version": "1.4.1", "version": "1.4.2",
"devDependencies": { "devDependencies": {
"@radix-ui/react-icons": "^1.3.2", "@radix-ui/react-icons": "^1.3.2",
"@radix-ui/react-separator": "^1.1.8", "@radix-ui/react-separator": "^1.1.8",
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "root", "name": "root",
"private": true, "private": true,
"version": "1.4.1", "version": "1.4.2",
"type": "module", "type": "module",
"workspaces": [ "workspaces": [
"packages/page-controller", "packages/page-controller",
+3 -3
View File
@@ -1,7 +1,7 @@
{ {
"name": "@page-agent/core", "name": "@page-agent/core",
"private": false, "private": false,
"version": "1.4.1", "version": "1.4.2",
"type": "module", "type": "module",
"main": "./dist/esm/page-agent-core.js", "main": "./dist/esm/page-agent-core.js",
"module": "./dist/esm/page-agent-core.js", "module": "./dist/esm/page-agent-core.js",
@@ -45,7 +45,7 @@
"dependencies": { "dependencies": {
"chalk": "^5.6.2", "chalk": "^5.6.2",
"zod": "^4.3.5", "zod": "^4.3.5",
"@page-agent/llms": "1.4.1", "@page-agent/llms": "1.4.2",
"@page-agent/page-controller": "1.4.1" "@page-agent/page-controller": "1.4.2"
} }
} }
+2
View File
@@ -342,6 +342,8 @@ export class PageAgentCore extends EventTarget {
await onAfterTask?.(this, result) await onAfterTask?.(this, result)
return result return result
} }
await waitFor(0.4) // @TODO: configurable
} }
} }
+4 -4
View File
@@ -38,10 +38,10 @@
"wxt": "^0.20.18" "wxt": "^0.20.18"
}, },
"dependencies": { "dependencies": {
"@page-agent/core": "1.4.1", "@page-agent/core": "1.4.2",
"@page-agent/llms": "1.4.1", "@page-agent/llms": "1.4.2",
"@page-agent/page-controller": "1.4.1", "@page-agent/page-controller": "1.4.2",
"@page-agent/ui": "1.4.1", "@page-agent/ui": "1.4.2",
"ai-motion": "^0.4.8", "ai-motion": "^0.4.8",
"chalk": "^5.6.2", "chalk": "^5.6.2",
"zod": "^4.3.5" "zod": "^4.3.5"
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@page-agent/llms", "name": "@page-agent/llms",
"version": "1.4.1", "version": "1.4.2",
"type": "module", "type": "module",
"main": "./dist/lib/page-agent-llms.js", "main": "./dist/lib/page-agent-llms.js",
"module": "./dist/lib/page-agent-llms.js", "module": "./dist/lib/page-agent-llms.js",
+5 -5
View File
@@ -1,7 +1,7 @@
{ {
"name": "page-agent", "name": "page-agent",
"private": false, "private": false,
"version": "1.4.1", "version": "1.4.2",
"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",
@@ -44,10 +44,10 @@
"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": {
"@page-agent/core": "1.4.1", "@page-agent/core": "1.4.2",
"@page-agent/llms": "1.4.1", "@page-agent/llms": "1.4.2",
"@page-agent/page-controller": "1.4.1", "@page-agent/page-controller": "1.4.2",
"@page-agent/ui": "1.4.1", "@page-agent/ui": "1.4.2",
"chalk": "^5.6.2", "chalk": "^5.6.2",
"zod": "^4.3.5" "zod": "^4.3.5"
} }
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@page-agent/page-controller", "name": "@page-agent/page-controller",
"version": "1.4.1", "version": "1.4.2",
"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 -71
View File
@@ -86,7 +86,7 @@ export async function clickElement(element: HTMLElement) {
// dispatch a click event // dispatch a click event
// element.click() // element.click()
await waitFor(0.1) // Wait to ensure click event processing completes await waitFor(0.2) // Wait to ensure click event processing completes
} }
// eslint-disable-next-line @typescript-eslint/unbound-method // eslint-disable-next-line @typescript-eslint/unbound-method
@@ -181,11 +181,6 @@ export async function scrollVertically(
// Element-specific scrolling if element is provided // Element-specific scrolling if element is provided
if (element) { if (element) {
const targetElement = element const targetElement = element
console.log(
'[SCROLL DEBUG] Starting direct container scroll for element:',
targetElement.tagName
)
let currentElement = targetElement as HTMLElement | null let currentElement = targetElement as HTMLElement | null
let scrollSuccess = false let scrollSuccess = false
let scrolledElement: HTMLElement | null = null let scrolledElement: HTMLElement | null = null
@@ -198,19 +193,6 @@ export async function scrollVertically(
const hasScrollableY = /(auto|scroll|overlay)/.test(computedStyle.overflowY) const hasScrollableY = /(auto|scroll|overlay)/.test(computedStyle.overflowY)
const canScrollVertically = currentElement.scrollHeight > currentElement.clientHeight const canScrollVertically = currentElement.scrollHeight > currentElement.clientHeight
console.log(
'[SCROLL DEBUG] Checking element:',
currentElement.tagName,
'hasScrollableY:',
hasScrollableY,
'canScrollVertically:',
canScrollVertically,
'scrollHeight:',
currentElement.scrollHeight,
'clientHeight:',
currentElement.clientHeight
)
if (hasScrollableY && canScrollVertically) { if (hasScrollableY && canScrollVertically) {
const beforeScroll = currentElement.scrollTop const beforeScroll = currentElement.scrollTop
const maxScroll = currentElement.scrollHeight - currentElement.clientHeight const maxScroll = currentElement.scrollHeight - currentElement.clientHeight
@@ -228,27 +210,10 @@ export async function scrollVertically(
const afterScroll = currentElement.scrollTop const afterScroll = currentElement.scrollTop
const actualScrollDelta = afterScroll - beforeScroll const actualScrollDelta = afterScroll - beforeScroll
console.log(
'[SCROLL DEBUG] Scroll attempt:',
currentElement.tagName,
'before:',
beforeScroll,
'after:',
afterScroll,
'delta:',
actualScrollDelta
)
if (Math.abs(actualScrollDelta) > 0.5) { if (Math.abs(actualScrollDelta) > 0.5) {
scrollSuccess = true scrollSuccess = true
scrolledElement = currentElement scrolledElement = currentElement
scrollDelta = actualScrollDelta scrollDelta = actualScrollDelta
console.log(
'[SCROLL DEBUG] Successfully scrolled container:',
currentElement.tagName,
'delta:',
actualScrollDelta
)
break break
} }
} }
@@ -344,11 +309,6 @@ export async function scrollHorizontally(
// Element-specific scrolling if element is provided // Element-specific scrolling if element is provided
if (element) { if (element) {
const targetElement = element const targetElement = element
console.log(
'[SCROLL DEBUG] Starting direct container scroll for element:',
targetElement.tagName
)
let currentElement = targetElement as HTMLElement | null let currentElement = targetElement as HTMLElement | null
let scrollSuccess = false let scrollSuccess = false
let scrolledElement: HTMLElement | null = null let scrolledElement: HTMLElement | null = null
@@ -361,19 +321,6 @@ export async function scrollHorizontally(
const hasScrollableX = /(auto|scroll|overlay)/.test(computedStyle.overflowX) const hasScrollableX = /(auto|scroll|overlay)/.test(computedStyle.overflowX)
const canScrollHorizontally = currentElement.scrollWidth > currentElement.clientWidth const canScrollHorizontally = currentElement.scrollWidth > currentElement.clientWidth
console.log(
'[SCROLL DEBUG] Checking element:',
currentElement.tagName,
'hasScrollableX:',
hasScrollableX,
'canScrollHorizontally:',
canScrollHorizontally,
'scrollWidth:',
currentElement.scrollWidth,
'clientWidth:',
currentElement.clientWidth
)
if (hasScrollableX && canScrollHorizontally) { if (hasScrollableX && canScrollHorizontally) {
const beforeScroll = currentElement.scrollLeft const beforeScroll = currentElement.scrollLeft
const maxScroll = currentElement.scrollWidth - currentElement.clientWidth const maxScroll = currentElement.scrollWidth - currentElement.clientWidth
@@ -391,27 +338,10 @@ export async function scrollHorizontally(
const afterScroll = currentElement.scrollLeft const afterScroll = currentElement.scrollLeft
const actualScrollDelta = afterScroll - beforeScroll const actualScrollDelta = afterScroll - beforeScroll
console.log(
'[SCROLL DEBUG] Scroll attempt:',
currentElement.tagName,
'before:',
beforeScroll,
'after:',
afterScroll,
'delta:',
actualScrollDelta
)
if (Math.abs(actualScrollDelta) > 0.5) { if (Math.abs(actualScrollDelta) > 0.5) {
scrollSuccess = true scrollSuccess = true
scrolledElement = currentElement scrolledElement = currentElement
scrollDelta = actualScrollDelta scrollDelta = actualScrollDelta
console.log(
'[SCROLL DEBUG] Successfully scrolled container:',
currentElement.tagName,
'delta:',
actualScrollDelta
)
break break
} }
} }
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@page-agent/ui", "name": "@page-agent/ui",
"version": "1.4.1", "version": "1.4.2",
"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",
+13 -2
View File
@@ -45,13 +45,24 @@
</script> </script>
</head> </head>
<body> <body>
<div id="root"></div> <div id="root">
<div id="sk">
<p class="sk-text" id="sk-text">Loading...</p>
<style>
#sk{display:flex;align-items:center;justify-content:center;min-height:100vh;background:linear-gradient(135deg,#eff6ff,#f5f3ff)}
@media(prefers-color-scheme:dark){#sk{background:linear-gradient(135deg,#111827,#1f2937)}}
.sk-text{font:400 14px/1 system-ui,sans-serif;color:#94a3b8;animation:skf 2s ease-in-out infinite}
@keyframes skf{0%,100%{opacity:.6}50%{opacity:.3}}
</style>
</div>
</div>
<script type="module" src="./src/main.tsx"></script> <script type="module" src="./src/main.tsx"></script>
<script> <script>
// Dynamically update html lang attribute based on i18n detection
const updateHtmlLang = () => { const updateHtmlLang = () => {
const lang = localStorage.getItem('i18nextLng') || navigator.language || 'zh-CN' const lang = localStorage.getItem('i18nextLng') || navigator.language || 'zh-CN'
document.documentElement.lang = lang document.documentElement.lang = lang
const el = document.getElementById('sk-text')
if (el) el.textContent = lang.startsWith('zh') ? '加载中...' : 'Loading...'
} }
updateHtmlLang() updateHtmlLang()
window.addEventListener('storage', updateHtmlLang) window.addEventListener('storage', updateHtmlLang)
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "@page-agent/website", "name": "@page-agent/website",
"private": true, "private": true,
"version": "1.4.1", "version": "1.4.2",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite --host 0.0.0.0", "dev": "vite --host 0.0.0.0",
+2 -2
View File
@@ -1,8 +1,8 @@
// Demo build (auto-init with demo LLM, for quick testing) // Demo build (auto-init with demo LLM, for quick testing)
export const CDN_DEMO_URL = export const CDN_DEMO_URL =
'https://cdn.jsdelivr.net/npm/page-agent@1.4.1/dist/iife/page-agent.demo.js' 'https://cdn.jsdelivr.net/npm/page-agent@1.4.2/dist/iife/page-agent.demo.js'
export const CDN_DEMO_CN_URL = export const CDN_DEMO_CN_URL =
'https://registry.npmmirror.com/page-agent/1.4.1/files/dist/iife/page-agent.demo.js' 'https://registry.npmmirror.com/page-agent/1.4.2/files/dist/iife/page-agent.demo.js'
// Demo LLM for website testing (homepage quick trial uses flash) // Demo LLM for website testing (homepage quick trial uses flash)
export const DEMO_MODEL = 'qwen3.5-flash' export const DEMO_MODEL = 'qwen3.5-flash'
+18 -6
View File
@@ -1,15 +1,27 @@
import FeaturesSection from './home/FeaturesSection' import { Suspense, lazy } from 'react'
import HeroSection from './home/HeroSection' import HeroSection from './home/HeroSection'
import OneMoreThingSection from './home/OneMoreThingSection'
import ScenariosSection from './home/ScenariosSection' const FeaturesSection = lazy(() => import('./home/FeaturesSection'))
const ScenariosSection = lazy(() => import('./home/ScenariosSection'))
const OneMoreThingSection = lazy(() => import('./home/OneMoreThingSection'))
export default function HomePage() { export default function HomePage() {
return ( return (
<> <>
<HeroSection /> <HeroSection />
<FeaturesSection /> <Suspense
<ScenariosSection /> fallback={
<OneMoreThingSection /> <div className="flex items-center justify-center gap-3 py-20 text-gray-400">
<div className="w-4 h-4 border-2 border-blue-500 border-t-transparent rounded-full animate-spin" />
Loading...
</div>
}
>
<FeaturesSection />
<ScenariosSection />
<OneMoreThingSection />
</Suspense>
</> </>
) )
} }
@@ -1,5 +1,5 @@
/* eslint-disable react-dom/no-dangerously-set-innerhtml */ /* eslint-disable react-dom/no-dangerously-set-innerhtml */
import { PageAgent } from 'page-agent' import type { PageAgent as PageAgentType } from 'page-agent'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { Link, useSearchParams } from 'wouter' import { Link, useSearchParams } from 'wouter'
@@ -16,6 +16,8 @@ import {
} from '../../constants' } from '../../constants'
import { useLanguage } from '../../i18n/context' import { useLanguage } from '../../i18n/context'
let pageAgentModule: Promise<typeof import('page-agent')> | null = null
function getInjection(useCN?: boolean) { function getInjection(useCN?: boolean) {
const cdn = useCN ? CDN_DEMO_CN_URL : CDN_DEMO_URL const cdn = useCN ? CDN_DEMO_CN_URL : CDN_DEMO_URL
@@ -55,13 +57,20 @@ export default function HeroSection() {
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 [cdnSource, setCdnSource] = useState<'international' | 'china'>('international')
const handleExecute = async () => { const [ready, setReady] = useState(false)
if (!task.trim()) return useEffect(() => {
pageAgentModule ??= import('page-agent')
pageAgentModule.then(() => setReady(true))
}, [])
const handleExecute = async () => {
if (!task.trim() || !ready || !pageAgentModule) return
const { PageAgent } = await pageAgentModule
const win = window as any const win = window as any
if (!win.pageAgent || win.pageAgent.disposed) { if (!win.pageAgent || win.pageAgent.disposed) {
win.pageAgent = new PageAgent({ win.pageAgent = new (PageAgent as typeof PageAgentType)({
interactiveBlacklist: [document.getElementById('root')!], interactiveBlacklist: [document.getElementById('root')!],
language: language, language: language,
@@ -208,10 +217,21 @@ export default function HeroSection() {
/> />
<button <button
onClick={handleExecute} onClick={handleExecute}
disabled={!ready}
className="absolute right-2 top-2 px-5 py-1.5 bg-linear-to-r from-blue-600 to-purple-600 text-white font-medium rounded-md hover:shadow-md transform hover:scale-105 transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed disabled:transform-none text-sm" className="absolute right-2 top-2 px-5 py-1.5 bg-linear-to-r from-blue-600 to-purple-600 text-white font-medium rounded-md hover:shadow-md transform hover:scale-105 transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed disabled:transform-none text-sm"
data-page-agent-not-interactive data-page-agent-not-interactive
> >
{isZh ? '执行' : 'Run'} {ready ? (
isZh ? (
'执行'
) : (
'Run'
)
) : (
<span className="animate-pulse">
{isZh ? '准备中...' : 'Preparing...'}
</span>
)}
</button> </button>
</div> </div>
<p className="text-xs text-gray-500 dark:text-gray-400 text-left"> <p className="text-xs text-gray-500 dark:text-gray-400 text-left">
+19 -3
View File
@@ -1,10 +1,12 @@
import { Suspense, useLayoutEffect } from 'react' import { Suspense, lazy, useEffect, useLayoutEffect } from 'react'
import { Route, Switch, useLocation } from 'wouter' import { Route, Switch, useLocation } from 'wouter'
import Footer from './components/Footer' import Footer from './components/Footer'
import Header from './components/Header' import Header from './components/Header'
import HomePage from './pages/Home' import HomePage from './pages/Home'
import DocsPages from './pages/docs/index'
const docsImport = () => import('./pages/docs/index')
const DocsPages = lazy(docsImport)
function ScrollToTop() { function ScrollToTop() {
const [pathname] = useLocation() const [pathname] = useLocation()
@@ -15,6 +17,11 @@ function ScrollToTop() {
} }
export default function Router() { export default function Router() {
useEffect(() => {
const id = requestIdleCallback(() => docsImport())
return () => cancelIdleCallback(id)
}, [])
return ( return (
<div className="flex min-h-screen flex-col"> <div className="flex min-h-screen flex-col">
<Header /> <Header />
@@ -32,7 +39,16 @@ export default function Router() {
<Route path="/docs" nest> <Route path="/docs" nest>
<div className="flex-1 bg-white dark:bg-gray-900"> <div className="flex-1 bg-white dark:bg-gray-900">
<DocsPages /> <Suspense
fallback={
<div className="flex items-center justify-center gap-3 py-20 text-gray-400">
<div className="w-4 h-4 border-2 border-blue-500 border-t-transparent rounded-full animate-spin" />
Loading...
</div>
}
>
<DocsPages />
</Suspense>
</div> </div>
</Route> </Route>
+5
View File
@@ -64,6 +64,11 @@ export default defineConfig(({ mode }) => ({
if (message.code === 'EVAL') return if (message.code === 'EVAL') return
handler(message) handler(message)
}, },
output: {
manualChunks: {
vendor: ['react', 'react-dom', 'wouter'],
},
},
}, },
}, },
resolve: { resolve: {