feat: 添加 Cloudflare Workers 支持

- 在 package.json 中添加 @cloudflare/vite-plugin 依赖
- 新增 server/index.ts 文件实现 Cloudflare Workers 逻辑
- 更新 vite.config.ts 配置,添加 cloudflare 插件
- 新增 tsconfig.worker.json 配置 TypeScript 编译选项
- 更新 App.vue,添加从 API 获取名称的功能
This commit is contained in:
严浩
2025-09-09 12:28:27 +08:00
parent 07e8ca247f
commit 7c92f4496e
10 changed files with 7579 additions and 3 deletions

View File

@@ -22,7 +22,8 @@
"wrangler:deploy:preview": "wrangler pages deploy dist --project-name=vue-ts-example-2025 --branch=preview", "wrangler:deploy:preview": "wrangler pages deploy dist --project-name=vue-ts-example-2025 --branch=preview",
"wrangler:deploy:prod": "wrangler pages deploy dist --project-name=vue-ts-example-2025", "wrangler:deploy:prod": "wrangler pages deploy dist --project-name=vue-ts-example-2025",
"deploy:preview": "run-s build-only wrangler:deploy:preview", "deploy:preview": "run-s build-only wrangler:deploy:preview",
"deploy:prod": "run-s build-only wrangler:deploy:prod" "deploy:prod": "run-s build-only wrangler:deploy:prod",
"cf-typegen": "wrangler types"
}, },
"dependencies": { "dependencies": {
"pinia": "^3.0.3", "pinia": "^3.0.3",
@@ -30,6 +31,7 @@
"vue-router": "^4.5.1" "vue-router": "^4.5.1"
}, },
"devDependencies": { "devDependencies": {
"@cloudflare/vite-plugin": "^1.12.3",
"@playwright/test": "^1.54.1", "@playwright/test": "^1.54.1",
"@prettier/plugin-oxc": "^0.0.4", "@prettier/plugin-oxc": "^0.0.4",
"@tsconfig/node22": "^22.0.2", "@tsconfig/node22": "^22.0.2",

37
pnpm-lock.yaml generated
View File

@@ -18,6 +18,9 @@ importers:
specifier: ^4.5.1 specifier: ^4.5.1
version: 4.5.1(vue@3.5.21(typescript@5.8.3)) version: 4.5.1(vue@3.5.21(typescript@5.8.3))
devDependencies: devDependencies:
'@cloudflare/vite-plugin':
specifier: ^1.12.3
version: 1.12.3(rolldown-vite@7.1.8(@types/node@22.18.1)(esbuild@0.25.9)(jiti@2.5.1))(workerd@1.20250902.0)(wrangler@4.34.0)
'@playwright/test': '@playwright/test':
specifier: ^1.54.1 specifier: ^1.54.1
version: 1.55.0 version: 1.55.0
@@ -258,6 +261,12 @@ packages:
workerd: workerd:
optional: true optional: true
'@cloudflare/vite-plugin@1.12.3':
resolution: {integrity: sha512-kdXo0/qERVs7xQfv03O1Z5vZ8+nfdISY5dTKf2qWmqPQHEc4QRD5ImFG9SfDFZvcYZwEkX10mqNCZl3HXagdgA==}
peerDependencies:
vite: ^6.1.0 || ^7.0.0
wrangler: ^4.34.0
'@cloudflare/workerd-darwin-64@1.20250902.0': '@cloudflare/workerd-darwin-64@1.20250902.0':
resolution: {integrity: sha512-mwC/YEtDUGfnjXdbW5Lya+bgODrpJ5RxxqpaTjtMJycqnjR0RZgVpOqISwGfBHIhseykU3ahPugM5t91XkBKTg==} resolution: {integrity: sha512-mwC/YEtDUGfnjXdbW5Lya+bgODrpJ5RxxqpaTjtMJycqnjR0RZgVpOqISwGfBHIhseykU3ahPugM5t91XkBKTg==}
engines: {node: '>=16'} engines: {node: '>=16'}
@@ -1006,6 +1015,9 @@ packages:
resolution: {integrity: sha512-UGXe+g/rSRbglL0FOJiar+a+nUrst7KaFmsg05wYbKiInGWP6eAj/f8A2Uobgo5KxEtb2X10zeflNH6RK2xeIQ==} resolution: {integrity: sha512-UGXe+g/rSRbglL0FOJiar+a+nUrst7KaFmsg05wYbKiInGWP6eAj/f8A2Uobgo5KxEtb2X10zeflNH6RK2xeIQ==}
engines: {node: '>=14'} engines: {node: '>=14'}
'@remix-run/node-fetch-server@0.8.0':
resolution: {integrity: sha512-8/sKegb4HrM6IdcQeU0KPhj9VOHm5SUqswJDHuMCS3mwbr/NRx078QDbySmn0xslahvvZoOENd7EnK40kWKxkg==}
'@rolldown/binding-android-arm64@1.0.0-beta.36': '@rolldown/binding-android-arm64@1.0.0-beta.36':
resolution: {integrity: sha512-0y4+MDSw9GzX4VZtATiygDv+OtijxsRtNBZW6qA3OUGi0fq6Gq+MnvFHMjdJxz3mv/thIHMmJ0AL7d8urYBCUw==} resolution: {integrity: sha512-0y4+MDSw9GzX4VZtATiygDv+OtijxsRtNBZW6qA3OUGi0fq6Gq+MnvFHMjdJxz3mv/thIHMmJ0AL7d8urYBCUw==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
@@ -1905,6 +1917,10 @@ packages:
resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
get-port@7.1.0:
resolution: {integrity: sha512-QB9NKEeDg3xxVwCCwJQ9+xycaz6pBB6iQ76wiWMl1927n0Kir6alPiP+yuiICLLU4jpMe08dXfpebuQppFA2zw==}
engines: {node: '>=16'}
get-stream@9.0.1: get-stream@9.0.1:
resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==} resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==}
engines: {node: '>=18'} engines: {node: '>=18'}
@@ -3198,6 +3214,23 @@ snapshots:
optionalDependencies: optionalDependencies:
workerd: 1.20250902.0 workerd: 1.20250902.0
'@cloudflare/vite-plugin@1.12.3(rolldown-vite@7.1.8(@types/node@22.18.1)(esbuild@0.25.9)(jiti@2.5.1))(workerd@1.20250902.0)(wrangler@4.34.0)':
dependencies:
'@cloudflare/unenv-preset': 2.7.2(unenv@2.0.0-rc.20)(workerd@1.20250902.0)
'@remix-run/node-fetch-server': 0.8.0
get-port: 7.1.0
miniflare: 4.20250902.0
picocolors: 1.1.1
tinyglobby: 0.2.15
unenv: 2.0.0-rc.20
vite: rolldown-vite@7.1.8(@types/node@22.18.1)(esbuild@0.25.9)(jiti@2.5.1)
wrangler: 4.34.0
ws: 8.18.0
transitivePeerDependencies:
- bufferutil
- utf-8-validate
- workerd
'@cloudflare/workerd-darwin-64@1.20250902.0': '@cloudflare/workerd-darwin-64@1.20250902.0':
optional: true optional: true
@@ -3701,6 +3734,8 @@ snapshots:
dependencies: dependencies:
oxc-parser: 0.74.0 oxc-parser: 0.74.0
'@remix-run/node-fetch-server@0.8.0': {}
'@rolldown/binding-android-arm64@1.0.0-beta.36': '@rolldown/binding-android-arm64@1.0.0-beta.36':
optional: true optional: true
@@ -4650,6 +4685,8 @@ snapshots:
gensync@1.0.0-beta.2: {} gensync@1.0.0-beta.2: {}
get-port@7.1.0: {}
get-stream@9.0.1: get-stream@9.0.1:
dependencies: dependencies:
'@sec-ant/readable-stream': 0.4.1 '@sec-ant/readable-stream': 0.4.1

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

12
server/index.ts Normal file
View File

@@ -0,0 +1,12 @@
export default {
fetch(request) {
const url = new URL(request.url);
if (url.pathname.startsWith("/api/")) {
return Response.json({
name: "Cloudflare",
});
}
return new Response(null, { status: 404 });
},
} satisfies ExportedHandler<Env>;

View File

@@ -1,4 +1,14 @@
<script setup lang="ts"></script> <script setup lang="ts">
import { ref } from 'vue'
const name = ref('Unknown')
const getName = async () => {
const res = await fetch('/api/')
const data = await res.json()
name.value = data.name
}
</script>
<template> <template>
<h1>You did it!</h1> <h1>You did it!</h1>
@@ -6,6 +16,7 @@
Visit <a href="https://vuejs.org/" target="_blank" rel="noopener">vuejs.org</a> to read the Visit <a href="https://vuejs.org/" target="_blank" rel="noopener">vuejs.org</a> to read the
documentation documentation
</p> </p>
<button class="green" @click="getName" aria-label="get name">Name from API is: {{ name }}</button>
</template> </template>
<style scoped></style> <style scoped></style>

View File

@@ -9,6 +9,9 @@
}, },
{ {
"path": "./tsconfig.vitest.json" "path": "./tsconfig.vitest.json"
},
{
"path": "./tsconfig.worker.json"
} }
] ]
} }

8
tsconfig.worker.json Normal file
View File

@@ -0,0 +1,8 @@
{
"extends": "./tsconfig.node.json",
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.worker.tsbuildinfo",
"types": [ "./worker-configuration.d.ts","vite/client"],
},
"include": ["server"],
}

View File

@@ -5,9 +5,11 @@ import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx' import vueJsx from '@vitejs/plugin-vue-jsx'
import vueDevTools from 'vite-plugin-vue-devtools' import vueDevTools from 'vite-plugin-vue-devtools'
import { cloudflare } from '@cloudflare/vite-plugin'
// https://vite.dev/config/ // https://vite.dev/config/
export default defineConfig({ export default defineConfig({
plugins: [vue(), vueJsx(), vueDevTools()], plugins: [vue(), vueJsx(), vueDevTools(), cloudflare()],
resolve: { resolve: {
alias: { alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)), '@': fileURLToPath(new URL('./src', import.meta.url)),

7455
worker-configuration.d.ts vendored Normal file

File diff suppressed because it is too large Load Diff

46
wrangler.jsonc Normal file
View File

@@ -0,0 +1,46 @@
/**
* For more details on how to configure Wrangler, refer to:
* https://developers.cloudflare.com/workers/wrangler/configuration/
*/
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "vue-ts-example-2025",
"compatibility_date": "2025-09-09",
"main": "server/index.ts",
"assets": {
"not_found_handling": "single-page-application",
},
"observability": {
"enabled": true,
},
/**
* Smart Placement
* Docs: https://developers.cloudflare.com/workers/configuration/smart-placement/#smart-placement
*/
// "placement": { "mode": "smart" }
/**
* Bindings
* Bindings allow your Worker to interact with resources on the Cloudflare Developer Platform, including
* databases, object storage, AI inference, real-time communication and more.
* https://developers.cloudflare.com/workers/runtime-apis/bindings/
*/
/**
* Environment Variables
* https://developers.cloudflare.com/workers/wrangler/configuration/#environment-variables
*/
// "vars": { "MY_VARIABLE": "production_value" }
/**
* Note: Use secrets to store sensitive data.
* https://developers.cloudflare.com/workers/configuration/secrets/
*/
/**
* Static Assets
* https://developers.cloudflare.com/workers/static-assets/binding/
*/
// "assets": { "directory": "./public/", "binding": "ASSETS" }
/**
* Service Bindings (communicate between multiple Workers)
* https://developers.cloudflare.com/workers/wrangler/configuration/#service-bindings
*/
// "services": [{ "binding": "MY_SERVICE", "service": "my-service" }]
}