2 Commits

Author SHA1 Message Date
typist
7646830194 0.0.19
All checks were successful
Build and Push Docker Image / build (push) Successful in 1m6s
2025-10-29 08:50:18 +08:00
typist
59f998e8e3 feat: enhance tool loading and performance optimization
- Added DNS prefetch and preconnect links in index.html for improved API loading times.
- Implemented lazy loading for tool components to optimize performance and reduce initial load time.
- Wrapped tool components in Suspense with a loading fallback to enhance user experience during loading.
- Refactored Vite configuration to create manual chunks for better code splitting of React and UI libraries.
2025-10-29 08:49:25 +08:00
6 changed files with 67 additions and 22 deletions

View File

@@ -14,6 +14,10 @@
<!-- Favicon --> <!-- Favicon -->
<link rel="icon" type="image/svg+xml" href="/lite.svg" /> <link rel="icon" type="image/svg+xml" href="/lite.svg" />
<!-- DNS Prefetch & Preconnect for external APIs -->
<link rel="dns-prefetch" href="https://ipinfo.io">
<link rel="preconnect" href="https://ipinfo.io" crossorigin>
<!-- Open Graph / Facebook --> <!-- Open Graph / Facebook -->
<meta property="og:type" content="website" /> <meta property="og:type" content="website" />
<meta property="og:url" content="https://litek.typist.cc/" /> <meta property="og:url" content="https://litek.typist.cc/" />

View File

@@ -1,7 +1,7 @@
{ {
"name": "litek", "name": "litek",
"private": true, "private": true,
"version": "0.0.18", "version": "0.0.19",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",

View File

@@ -1,17 +1,22 @@
import type { ReactNode } from 'react'; import { lazy, type ReactNode, type ComponentType } from 'react';
import { FileJson, Hash, Binary, Network, Globe, Activity, Gauge, Wifi, MapPin } from 'lucide-react' import { FileJson, Hash, Binary, Network, Globe, Activity, Gauge, Wifi, MapPin } from 'lucide-react'
import UUID from './uuid' // 懒加载工具组件
import JSON from './json' const UUID = lazy(() => import('./uuid'))
import Base64 from './base64' const JSON = lazy(() => import('./json'))
import { DNS, Ping, TCPing, SpeedTest, IPQuery } from './network' const Base64 = lazy(() => import('./base64'))
const DNS = lazy(() => import('./network/dns'))
const Ping = lazy(() => import('./network/ping'))
const TCPing = lazy(() => import('./network/tcping'))
const SpeedTest = lazy(() => import('./network/speedtest'))
const IPQuery = lazy(() => import('./network/ipquery'))
export interface Tool { export interface Tool {
path: string; path: string;
name: string; name: string;
icon: ReactNode; icon: ReactNode;
description: string; description: string;
component?: ReactNode; component?: ComponentType;
children?: Tool[]; children?: Tool[];
} }
@@ -21,21 +26,21 @@ export const tools: Tool[] = [
name: "UUID Generator", name: "UUID Generator",
description: "Generate a UUID", description: "Generate a UUID",
icon: <Hash />, icon: <Hash />,
component: <UUID />, component: UUID,
}, },
{ {
path: "json", path: "json",
name: "JSON Formatter", name: "JSON Formatter",
description: "Format and validate JSON", description: "Format and validate JSON",
icon: <FileJson />, icon: <FileJson />,
component: <JSON />, component: JSON,
}, },
{ {
path: "base64", path: "base64",
name: "Base64 Encoder/Decoder", name: "Base64 Encoder/Decoder",
description: "Encode and decode Base64", description: "Encode and decode Base64",
icon: <Binary />, icon: <Binary />,
component: <Base64 />, component: Base64,
}, },
{ {
path: "network", path: "network",
@@ -48,35 +53,35 @@ export const tools: Tool[] = [
name: "DNS Lookup", name: "DNS Lookup",
description: "DNS query tool", description: "DNS query tool",
icon: <Globe />, icon: <Globe />,
component: <DNS />, component: DNS,
}, },
{ {
path: "ping", path: "ping",
name: "Ping", name: "Ping",
description: "Ping test tool", description: "Ping test tool",
icon: <Activity />, icon: <Activity />,
component: <Ping />, component: Ping,
}, },
{ {
path: "tcping", path: "tcping",
name: "TCPing", name: "TCPing",
description: "TCP port connectivity test", description: "TCP port connectivity test",
icon: <Wifi />, icon: <Wifi />,
component: <TCPing />, component: TCPing,
}, },
{ {
path: "speedtest", path: "speedtest",
name: "Speed Test", name: "Speed Test",
description: "Website speed test", description: "Website speed test",
icon: <Gauge />, icon: <Gauge />,
component: <SpeedTest />, component: SpeedTest,
}, },
{ {
path: "ipquery", path: "ipquery",
name: "IP Query", name: "IP Query",
description: "Query IP location, quality and risk info", description: "Query IP location, quality and risk info",
icon: <MapPin />, icon: <MapPin />,
component: <IPQuery />, component: IPQuery,
}, },
], ],
}, },

View File

@@ -1,6 +0,0 @@
export { default as DNS } from './dns';
export { default as Ping } from './ping';
export { default as TCPing } from './tcping';
export { default as SpeedTest } from './speedtest';
export { default as IPQuery } from './ipquery';

View File

@@ -1,3 +1,4 @@
import { Suspense, createElement } from "react";
import { import {
createBrowserRouter, createBrowserRouter,
redirect, redirect,
@@ -8,6 +9,19 @@ import {
import { tools, type Tool } from "@/components/tool"; import { tools, type Tool } from "@/components/tool";
import { Layout } from "./layout"; import { Layout } from "./layout";
// 加载中的占位组件
const LoadingFallback = () => (
<div className="flex items-center justify-center h-full">
<div className="text-center flex flex-col items-center gap-3">
<div className="relative">
<div className="h-12 w-12 rounded-full border-4 border-muted"></div>
<div className="absolute top-0 left-0 h-12 w-12 rounded-full border-4 border-primary border-t-transparent animate-spin"></div>
</div>
<p className="text-sm text-muted-foreground font-medium">Loading...</p>
</div>
</div>
);
const buildToolRoutes = (tools: Tool[]): RouteObject[] => { const buildToolRoutes = (tools: Tool[]): RouteObject[] => {
return tools.map((tool) => { return tools.map((tool) => {
const route: RouteObject = { const route: RouteObject = {
@@ -15,7 +29,12 @@ const buildToolRoutes = (tools: Tool[]): RouteObject[] => {
}; };
if (tool.component) { if (tool.component) {
route.element = tool.component; // 使用 Suspense 包裹懒加载组件
route.element = (
<Suspense fallback={<LoadingFallback />}>
{createElement(tool.component)}
</Suspense>
);
} }
if (tool.children && tool.children.length > 0) { if (tool.children && tool.children.length > 0) {

View File

@@ -11,4 +11,27 @@ export default defineConfig({
"@": path.resolve(__dirname, "./src"), "@": path.resolve(__dirname, "./src"),
}, },
}, },
build: {
rollupOptions: {
output: {
manualChunks: (id) => {
// React核心库
if (id.includes('node_modules/react') ||
id.includes('node_modules/react-dom') ||
id.includes('node_modules/react-router-dom')) {
return 'react-vendor';
}
// Radix UI组件
if (id.includes('node_modules/@radix-ui')) {
return 'ui-vendor';
}
// 图标库
if (id.includes('node_modules/lucide-react')) {
return 'icons';
}
},
},
},
chunkSizeWarningLimit: 500,
},
}) })