2 Commits

Author SHA1 Message Date
严浩
e82b8575d1 ci: 更新项目依赖并优化测试工作流 2025-09-12 12:14:33 +08:00
严浩
3b76e57df5 build(deps): 使用 rolldown-vite 包 2025-09-11 16:18:49 +08:00
11 changed files with 608 additions and 528 deletions

View File

@@ -12,7 +12,7 @@ on:
workflow_dispatch: workflow_dispatch:
jobs: jobs:
build-and-deploy: lint-build-and-typecheck:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: gitea/runner-images:ubuntu-latest-slim # https://github.com/cloudflare/wrangler-action/issues/329#issuecomment-3046747722 container: gitea/runner-images:ubuntu-latest-slim # https://github.com/cloudflare/wrangler-action/issues/329#issuecomment-3046747722
@@ -44,8 +44,33 @@ jobs:
- name: ✅ 类型检查 - name: ✅ 类型检查
run: pnpm run type-check # 要先 build保证 components.d.ts 存在 run: pnpm run type-check # 要先 build保证 components.d.ts 存在
- name: 🚀 部署到 Cloudflare deploy:
runs-on: ubuntu-latest
needs: lint-build-and-typecheck
if: github.ref == 'refs/heads/main' if: github.ref == 'refs/heads/main'
# https://github.com/cloudflare/wrangler-action/issues/329#issuecomment-3046747722
container:
image: gitea/runner-images:ubuntu-latest-slim
steps:
- name: 🛠️ 设置Node环境
uses: yanhao98/composite-actions/setup-node-environment@25eb4dc0c134cc9df2b7c569aa54140a366b45a8
- name: 📦 构建项目
run: pnpm run build-only
env:
VITE_BUILD_COMMIT: ${{ github.sha }}
# - name: 🚀 上传版本到 Cloudflare
# uses: cloudflare/wrangler-action@v3
# id: upload
# with:
# apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
# accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
# command: versions upload --tag "${{ github.sha }}" --message "Deploy commit ${{ github.sha }} from ${{ github.ref_name }}"
- name: 🚀 部署到 Cloudflare
uses: cloudflare/wrangler-action@v3 uses: cloudflare/wrangler-action@v3
with: with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}

View File

@@ -18,6 +18,8 @@ jobs:
uses: yanhao98/composite-actions/setup-node-environment@25eb4dc0c134cc9df2b7c569aa54140a366b45a8 uses: yanhao98/composite-actions/setup-node-environment@25eb4dc0c134cc9df2b7c569aa54140a366b45a8
# - name: 📥 安装 Playwright 浏览器 # - name: 📥 安装 Playwright 浏览器
# run: pnpm exec playwright install --with-deps # run: pnpm exec playwright install --with-deps
- name: 🔄 更新依赖
run: pnpm update --latest
- name: 📦 构建项目 - name: 📦 构建项目
run: pnpm run build-only run: pnpm run build-only
- name: ▶️ 运行 Playwright 测试 - name: ▶️ 运行 Playwright 测试

2
.npmrc
View File

@@ -1,4 +1,4 @@
# registry=https://registry.npmmirror.com/ registry=https://registry.npmmirror.com/
# https://pnpm.io/zh/npmrc#node-mirrorltreleasedir # https://pnpm.io/zh/npmrc#node-mirrorltreleasedir
use-node-version=24.7.0 use-node-version=24.7.0

View File

@@ -55,5 +55,6 @@ test.describe('Vue App', () => {
await page.goto('/') await page.goto('/')
const appLayout = page.locator('.app-layout') const appLayout = page.locator('.app-layout')
await expect(appLayout).toBeVisible() await expect(appLayout).toBeVisible()
await expect(appLayout).toContainText('AppLayout')
}) })
}) })

View File

@@ -17,7 +17,7 @@ export default defineConfigWithVueTs(
files: ['**/*.{ts,mts,tsx,vue}'], files: ['**/*.{ts,mts,tsx,vue}'],
}, },
globalIgnores(['worker-configuration.d.ts', '**/dist/**', '**/dist-ssr/**', '**/coverage/**']), globalIgnores(['**/dist/**', '**/dist-ssr/**', '**/coverage/**']),
pluginVue.configs['flat/essential'], pluginVue.configs['flat/essential'],
vueTsConfigs.recommended, vueTsConfigs.recommended,

View File

@@ -33,7 +33,6 @@
"wrangler:deploy": "pnpm run build && wrangler deploy", "wrangler:deploy": "pnpm run build && wrangler deploy",
"wrangler:versions:upload": "pnpm run build && wrangler versions upload", "wrangler:versions:upload": "pnpm run build && wrangler versions upload",
"cf-typegen": "wrangler types", "cf-typegen": "wrangler types",
"postinstall": "wrangler types",
"_dep:dedupe": "pnpm dedupe", "_dep:dedupe": "pnpm dedupe",
"_dep:update": "pnpm dlx taze major --interactive", "_dep:update": "pnpm dlx taze major --interactive",
"_sizecheck:Treemap": "pnpm dlx vite-bundle-visualizer -t treemap", "_sizecheck:Treemap": "pnpm dlx vite-bundle-visualizer -t treemap",
@@ -50,7 +49,9 @@
] ]
}, },
"pnpm": { "pnpm": {
"overrides": {} "overrides": {
"vite": "$vite"
}
}, },
"dependencies": { "dependencies": {
"@commitlint/cli": "^19.8.1", "@commitlint/cli": "^19.8.1",
@@ -70,7 +71,7 @@
"vue-router": "^4.5.1" "vue-router": "^4.5.1"
}, },
"devDependencies": { "devDependencies": {
"@cloudflare/vite-plugin": "^1.13.2", "@cloudflare/vite-plugin": "^1.12.4",
"@commitlint/types": "^19.8.1", "@commitlint/types": "^19.8.1",
"@intlify/unplugin-vue-i18n": "^11.0.0", "@intlify/unplugin-vue-i18n": "^11.0.0",
"@playwright/test": "^1.55.0", "@playwright/test": "^1.55.0",
@@ -89,7 +90,7 @@
"@vue/test-utils": "^2.4.6", "@vue/test-utils": "^2.4.6",
"@vue/tsconfig": "^0.8.1", "@vue/tsconfig": "^0.8.1",
"eslint": "^9.35.0", "eslint": "^9.35.0",
"eslint-plugin-oxlint": "~1.15.0", "eslint-plugin-oxlint": "~1.14.0",
"eslint-plugin-playwright": "^2.2.2", "eslint-plugin-playwright": "^2.2.2",
"eslint-plugin-vue": "~10.4.0", "eslint-plugin-vue": "~10.4.0",
"husky": "^9.1.7", "husky": "^9.1.7",
@@ -98,7 +99,7 @@
"lint-staged": "^16.1.6", "lint-staged": "^16.1.6",
"npm-run-all2": "^8.0.4", "npm-run-all2": "^8.0.4",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"oxlint": "~1.15.0", "oxlint": "~1.14.0",
"prettier": "3.6.2", "prettier": "3.6.2",
"typescript": "~5.9.2", "typescript": "~5.9.2",
"unocss": "^66.5.1", "unocss": "^66.5.1",
@@ -108,7 +109,7 @@
"unplugin-vue-components": "^29.0.0", "unplugin-vue-components": "^29.0.0",
"unplugin-vue-markdown": "^29.1.0", "unplugin-vue-markdown": "^29.1.0",
"unplugin-vue-router": "^0.15.0", "unplugin-vue-router": "^0.15.0",
"vite": "^7.1.5", "vite": "npm:rolldown-vite@^7.1.9",
"vite-plugin-checker": "^0.10.3", "vite-plugin-checker": "^0.10.3",
"vite-plugin-fake-server": "^2.2.0", "vite-plugin-fake-server": "^2.2.0",
"vite-plugin-image-optimizer": "^2.0.2", "vite-plugin-image-optimizer": "^2.0.2",
@@ -118,6 +119,6 @@
"vitest": "^3.2.4", "vitest": "^3.2.4",
"vue-macros": "3.0.0-beta.23", "vue-macros": "3.0.0-beta.23",
"vue-tsc": "^3.0.6", "vue-tsc": "^3.0.6",
"wrangler": "^4.37.1" "wrangler": "^4.35.0"
} }
} }

840
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -11,37 +11,19 @@ const getName = async () => {
</script> </script>
<template> <template>
<div class="app-container bg-slate-50 min-h-screen"> <div>
<div class="container mx-auto px-6 py-8"> <h1>You did it!</h1>
<h1 class="text-4xl font-extrabold text-emerald-600 mb-6 text-center">You did it!</h1> <p>
<div class="bg-white rounded-lg shadow-lg p-8 mb-8"> Visit <a href="https://vuejs.org/" target="_blank" rel="noopener">vuejs.org</a> to read the
<p class="text-lg text-gray-700 mb-6 text-center"> documentation
Visit
<a
href="https://vuejs.org/"
target="_blank"
rel="noopener"
class="text-emerald-500 hover:text-emerald-700 underline font-semibold"
>
vuejs.org
</a>
to read the documentation
</p> </p>
<div class="flex justify-center"> <button class="green" @click="getName" aria-label="get name">
<button
class="bg-emerald-500 hover:bg-emerald-600 text-white font-bold py-3 px-6 rounded-lg transition-colors duration-200 shadow-md hover:shadow-lg"
@click="getName"
aria-label="get name"
>
Name from API is: {{ name }} Name from API is: {{ name }}
</button> </button>
</div> </div>
</div>
</div>
<DynamicDialog /> <DynamicDialog /> <ConfirmDialog /> <Toast />
<ConfirmDialog />
<Toast />
<RouterView /> <RouterView />
</div>
</template> </template>
<style scoped></style>

View File

@@ -1,10 +1,9 @@
<script setup lang="ts"></script> <script setup lang="ts"></script>
<template> <template>
<div class="app-layout min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100"> <div class="app-layout">
<main class="max-w-7xl mx-auto px-4 py-8"> <div>AppLayout</div>
<router-view /> <router-view />
</main>
</div> </div>
</template> </template>

View File

@@ -1,31 +1,7 @@
<script setup lang="ts"></script> <script setup lang="ts"></script>
<template> <template>
<div <div></div>
class="hero-section bg-gradient-to-r from-purple-400 via-pink-500 to-red-500 rounded-xl p-8 shadow-2xl"
>
<div class="text-center">
<h2 class="text-3xl font-bold text-white mb-4 animate-bounce">🎉 This is the index page</h2>
<p class="text-white/90 text-lg mb-6">Welcome to your awesome Vue.js application!</p>
<div class="flex justify-center space-x-4">
<div
class="bg-white/20 backdrop-blur-sm rounded-lg p-4 hover:bg-white/30 transition-all duration-300"
>
<span class="text-white font-semibold">Feature 1</span>
</div>
<div
class="bg-white/20 backdrop-blur-sm rounded-lg p-4 hover:bg-white/30 transition-all duration-300"
>
<span class="text-white font-semibold">Feature 2</span>
</div>
<div
class="bg-white/20 backdrop-blur-sm rounded-lg p-4 hover:bg-white/30 transition-all duration-300"
>
<span class="text-white font-semibold">Feature 3</span>
</div>
</div>
</div>
</div>
</template> </template>
<style scoped></style> <style scoped></style>

View File

@@ -1,6 +1,6 @@
/* eslint-disable */ /* eslint-disable */
// Generated by Wrangler by running `wrangler types` (hash: a5d3a0d06638640f4072385a766cb44d) // Generated by Wrangler by running `wrangler types` (hash: a5d3a0d06638640f4072385a766cb44d)
// Runtime types generated with workerd@1.20250906.0 2025-09-09 // Runtime types generated with workerd@1.20250902.0 2025-09-09
declare namespace Cloudflare { declare namespace Cloudflare {
interface Env { interface Env {
KV: KVNamespace; KV: KVNamespace;
@@ -414,7 +414,7 @@ interface DurableObjectId {
equals(other: DurableObjectId): boolean; equals(other: DurableObjectId): boolean;
readonly name?: string; readonly name?: string;
} }
declare abstract class DurableObjectNamespace<T extends Rpc.DurableObjectBranded | undefined = undefined> { interface DurableObjectNamespace<T extends Rpc.DurableObjectBranded | undefined = undefined> {
newUniqueId(options?: DurableObjectNamespaceNewUniqueIdOptions): DurableObjectId; newUniqueId(options?: DurableObjectNamespaceNewUniqueIdOptions): DurableObjectId;
idFromName(name: string): DurableObjectId; idFromName(name: string): DurableObjectId;
idFromString(id: string): DurableObjectId; idFromString(id: string): DurableObjectId;
@@ -432,7 +432,6 @@ interface DurableObjectNamespaceGetDurableObjectOptions {
} }
interface DurableObjectState { interface DurableObjectState {
waitUntil(promise: Promise<any>): void; waitUntil(promise: Promise<any>): void;
props: any;
readonly id: DurableObjectId; readonly id: DurableObjectId;
readonly storage: DurableObjectStorage; readonly storage: DurableObjectStorage;
container?: Container; container?: Container;
@@ -475,7 +474,6 @@ interface DurableObjectStorage {
deleteAlarm(options?: DurableObjectSetAlarmOptions): Promise<void>; deleteAlarm(options?: DurableObjectSetAlarmOptions): Promise<void>;
sync(): Promise<void>; sync(): Promise<void>;
sql: SqlStorage; sql: SqlStorage;
kv: SyncKvStorage;
transactionSync<T>(closure: () => T): T; transactionSync<T>(closure: () => T): T;
getCurrentBookmark(): Promise<string>; getCurrentBookmark(): Promise<string>;
getBookmarkForTime(timestamp: number | Date): Promise<string>; getBookmarkForTime(timestamp: number | Date): Promise<string>;
@@ -2047,7 +2045,6 @@ interface TraceItem {
readonly scriptVersion?: ScriptVersion; readonly scriptVersion?: ScriptVersion;
readonly dispatchNamespace?: string; readonly dispatchNamespace?: string;
readonly scriptTags?: string[]; readonly scriptTags?: string[];
readonly durableObjectId?: string;
readonly outcome: string; readonly outcome: string;
readonly executionModel: string; readonly executionModel: string;
readonly truncated: boolean; readonly truncated: boolean;
@@ -2569,23 +2566,6 @@ declare class MessageChannel {
interface MessagePortPostMessageOptions { interface MessagePortPostMessageOptions {
transfer?: any[]; transfer?: any[];
} }
interface SyncKvStorage {
get<T = unknown>(key: string): T | undefined;
list<T = unknown>(options?: SyncKvListOptions): Iterable<[
string,
T
]>;
put<T>(key: string, value: T): void;
delete(key: string): boolean;
}
interface SyncKvListOptions {
start?: string;
startAfter?: string;
end?: string;
prefix?: string;
reverse?: boolean;
limit?: number;
}
type AiImageClassificationInput = { type AiImageClassificationInput = {
image: number[]; image: number[];
}; };
@@ -5460,7 +5440,7 @@ type AIGatewayHeaders = {
[key: string]: string | number | boolean | object; [key: string]: string | number | boolean | object;
}; };
type AIGatewayUniversalRequest = { type AIGatewayUniversalRequest = {
provider: AIGatewayProviders | string; // eslint-disable-line provider: AIGatewayProviders | string;
endpoint: string; endpoint: string;
headers: Partial<AIGatewayHeaders>; headers: Partial<AIGatewayHeaders>;
query: unknown; query: unknown;
@@ -5476,7 +5456,7 @@ declare abstract class AiGateway {
gateway?: UniversalGatewayOptions; gateway?: UniversalGatewayOptions;
extraHeaders?: object; extraHeaders?: object;
}): Promise<Response>; }): Promise<Response>;
getUrl(provider?: AIGatewayProviders | string): Promise<string>; // eslint-disable-line getUrl(provider?: AIGatewayProviders | string): Promise<string>;
} }
interface AutoRAGInternalError extends Error { interface AutoRAGInternalError extends Error {
} }
@@ -6575,7 +6555,6 @@ type ImageOutputOptions = {
format: 'image/jpeg' | 'image/png' | 'image/gif' | 'image/webp' | 'image/avif' | 'rgb' | 'rgba'; format: 'image/jpeg' | 'image/png' | 'image/gif' | 'image/webp' | 'image/avif' | 'rgb' | 'rgba';
quality?: number; quality?: number;
background?: string; background?: string;
anim?: boolean;
}; };
interface ImagesBinding { interface ImagesBinding {
/** /**
@@ -6634,108 +6613,6 @@ interface ImagesError extends Error {
readonly message: string; readonly message: string;
readonly stack?: string; readonly stack?: string;
} }
/**
* Media binding for transforming media streams.
* Provides the entry point for media transformation operations.
*/
interface MediaBinding {
/**
* Creates a media transformer from an input stream.
* @param media - The input media bytes
* @returns A MediaTransformer instance for applying transformations
*/
input(media: ReadableStream<Uint8Array>): MediaTransformer;
}
/**
* Media transformer for applying transformation operations to media content.
* Handles sizing, fitting, and other input transformation parameters.
*/
interface MediaTransformer {
/**
* Applies transformation options to the media content.
* @param transform - Configuration for how the media should be transformed
* @returns A generator for producing the transformed media output
*/
transform(transform: MediaTransformationInputOptions): MediaTransformationGenerator;
}
/**
* Generator for producing media transformation results.
* Configures the output format and parameters for the transformed media.
*/
interface MediaTransformationGenerator {
/**
* Generates the final media output with specified options.
* @param output - Configuration for the output format and parameters
* @returns The final transformation result containing the transformed media
*/
output(output: MediaTransformationOutputOptions): MediaTransformationResult;
}
/**
* Result of a media transformation operation.
* Provides multiple ways to access the transformed media content.
*/
interface MediaTransformationResult {
/**
* Returns the transformed media as a readable stream of bytes.
* @returns A stream containing the transformed media data
*/
media(): ReadableStream<Uint8Array>;
/**
* Returns the transformed media as an HTTP response object.
* @returns The transformed media as a Response, ready to store in cache or return to users
*/
response(): Response;
/**
* Returns the MIME type of the transformed media.
* @returns The content type string (e.g., 'image/jpeg', 'video/mp4')
*/
contentType(): string;
}
/**
* Configuration options for transforming media input.
* Controls how the media should be resized and fitted.
*/
type MediaTransformationInputOptions = {
/** How the media should be resized to fit the specified dimensions */
fit?: 'contain' | 'cover' | 'scale-down';
/** Target width in pixels */
width?: number;
/** Target height in pixels */
height?: number;
};
/**
* Configuration options for Media Transformations output.
* Controls the format, timing, and type of the generated output.
*/
type MediaTransformationOutputOptions = {
/**
* Output mode determining the type of media to generate
*/
mode?: 'video' | 'spritesheet' | 'frame' | 'audio';
/** Whether to include audio in the output */
audio?: boolean;
/**
* Starting timestamp for frame extraction or start time for clips. (e.g. '2s').
*/
time?: string;
/**
* Duration for video clips, audio extraction, and spritesheet generation (e.g. '5s').
*/
duration?: string;
/**
* Output format for the generated media.
*/
format?: 'jpg' | 'png' | 'm4a';
};
/**
* Error object for media transformation operations.
* Extends the standard Error interface with additional media-specific information.
*/
interface MediaError extends Error {
readonly code: number;
readonly message: string;
readonly stack?: string;
}
type Params<P extends string = any> = Record<P, string | string[]>; type Params<P extends string = any> = Record<P, string | string[]>;
type EventContext<Env, P extends string, Data> = { type EventContext<Env, P extends string, Data> = {
request: Request<unknown, IncomingRequestCfProperties<unknown>>; request: Request<unknown, IncomingRequestCfProperties<unknown>>;
@@ -7122,17 +6999,21 @@ declare namespace TailStream {
readonly tag?: string; readonly tag?: string;
readonly message?: string; readonly message?: string;
} }
interface Trigger {
readonly traceId: string;
readonly invocationId: string;
readonly spanId: string;
}
interface Onset { interface Onset {
readonly type: "onset"; readonly type: "onset";
readonly attributes: Attribute[]; readonly attributes: Attribute[];
// id for the span being opened by this Onset event.
readonly spanId: string;
readonly dispatchNamespace?: string; readonly dispatchNamespace?: string;
readonly entrypoint?: string; readonly entrypoint?: string;
readonly executionModel: string; readonly executionModel: string;
readonly scriptName?: string; readonly scriptName?: string;
readonly scriptTags?: string[]; readonly scriptTags?: string[];
readonly scriptVersion?: ScriptVersion; readonly scriptVersion?: ScriptVersion;
readonly trigger?: Trigger;
readonly info: FetchEventInfo | JsRpcEventInfo | ScheduledEventInfo | AlarmEventInfo | QueueEventInfo | EmailEventInfo | TraceEventInfo | HibernatableWebSocketEventInfo | CustomEventInfo; readonly info: FetchEventInfo | JsRpcEventInfo | ScheduledEventInfo | AlarmEventInfo | QueueEventInfo | EmailEventInfo | TraceEventInfo | HibernatableWebSocketEventInfo | CustomEventInfo;
} }
interface Outcome { interface Outcome {
@@ -7144,8 +7025,6 @@ declare namespace TailStream {
interface SpanOpen { interface SpanOpen {
readonly type: "spanOpen"; readonly type: "spanOpen";
readonly name: string; readonly name: string;
// id for the span being opened by this SpanOpen event.
readonly spanId: string;
readonly info?: FetchEventInfo | JsRpcEventInfo | Attributes; readonly info?: FetchEventInfo | JsRpcEventInfo | Attributes;
} }
interface SpanClose { interface SpanClose {
@@ -7168,10 +7047,6 @@ declare namespace TailStream {
readonly level: "debug" | "error" | "info" | "log" | "warn"; readonly level: "debug" | "error" | "info" | "log" | "warn";
readonly message: object; readonly message: object;
} }
// This marks the worker handler return information.
// This is separate from Outcome because the worker invocation can live for a long time after
// returning. For example - Websockets that return an http upgrade response but then continue
// streaming information or SSE http connections.
interface Return { interface Return {
readonly type: "return"; readonly type: "return";
readonly info?: FetchResponseInfo; readonly info?: FetchResponseInfo;
@@ -7185,28 +7060,9 @@ declare namespace TailStream {
readonly info: Attribute[]; readonly info: Attribute[];
} }
type EventType = Onset | Outcome | SpanOpen | SpanClose | DiagnosticChannelEvent | Exception | Log | Return | Attributes; type EventType = Onset | Outcome | SpanOpen | SpanClose | DiagnosticChannelEvent | Exception | Log | Return | Attributes;
// Context in which this trace event lives.
interface SpanContext {
// Single id for the entire top-level invocation
// This should be a new traceId for the first worker stage invoked in the eyeball request and then
// same-account service-bindings should reuse the same traceId but cross-account service-bindings
// should use a new traceId.
readonly traceId: string;
// spanId in which this event is handled
// for Onset and SpanOpen events this would be the parent span id
// for Outcome and SpanClose these this would be the span id of the opening Onset and SpanOpen events
// For Hibernate and Mark this would be the span under which they were emitted.
// spanId is not set ONLY if:
// 1. This is an Onset event
// 2. We are not inherting any SpanContext. (e.g. this is a cross-account service binding or a new top-level invocation)
readonly spanId?: string;
}
interface TailEvent<Event extends EventType> { interface TailEvent<Event extends EventType> {
// invocation id of the currently invoked worker stage.
// invocation id will always be unique to every Onset event and will be the same until the Outcome event.
readonly invocationId: string; readonly invocationId: string;
// Inherited spanContext for this event. readonly spanId: string;
readonly spanContext: SpanContext;
readonly timestamp: Date; readonly timestamp: Date;
readonly sequence: number; readonly sequence: number;
readonly event: Event; readonly event: Event;