转载于:https://mp.weixin.qq.com/s/XCBSh5h92MOWUgz2vLApzg

better-auth 官方Demo

  • 官方登录Demo页:https://demo.better-auth.com/
  • 官方example: https://github.com/better-auth/examples
  • 使用nuxt-example作为例子

运行命令

pnpm install
pnpm dev

可能遇到的错误

better-sqlite3

如果better-sqlite3有问题,导致demo无法运行,考虑如下方法:升级为最新版或者从源代码编译

pnpm install better-sqlite3@latest
pnpm add better-sqlite3 --config.build-from-source=true

cn全局导入

export default defineNuxtConfig({
  imports: {
    presets: [
      {
        // 目标文件路径(支持别名)
        from: '@/lib/utils',
        // 需要全局自动导入的方法名
        imports: ['cn'],
      },
    ],
  },
})

Button

  • 错误描述
 ERROR  [request error] [unhandled] [GET] http://localhost:3000/                                                               13:41:24
ℹ Error: _ctx.buttonVariants is not a function
 ⁃ at _sfc_ssrRender (components/ui/button/Button.vue:39:106)
   1617<template>
   18<Primitive
   19:as="as"
   20:as-child="asChild"
   21:class="cn(buttonVariants({ variant, size }), props.class)"
   22>
   23<slot />
   24</Primitive>
   25</template>
   26
  • 解决方法,按照如下方法修改
//将
import { type ButtonVariants } from ".";
//修改为
import {buttonVariants, type ButtonVariants} from ".";

Label

  • 错误描述
 ERROR  [unhandledRejection] Maximum call stack size exceeded                                                                  13:50:33
    at Reflect.get (<anonymous>)
    at ReadonlyReactiveHandler.get (node_modules/.pnpm/@vue+reactivity@3.5.25/node_modules/@vue/reactivity/dist/reactivity.cjs.js:993:25)
    at ComputedRefImpl.fn (components/ui/label/Label.vue:29:28)
    at refreshComputed (node_modules/.pnpm/@vue+reactivity@3.5.25/node_modules/@vue/reactivity/dist/reactivity.cjs.js:395:28)
    at get value (node_modules/.pnpm/@vue+reactivity@3.5.25/node_modules/@vue/reactivity/dist/reactivity.cjs.js:1695:5)
    at unref (node_modules/.pnpm/@vue+reactivity@3.5.25/node_modules/@vue/reactivity/dist/reactivity.cjs.js:1522:29)
    at Object.get (node_modules/.pnpm/@vue+reactivity@3.5.25/node_modules/@vue/reactivity/dist/reactivity.cjs.js:1528:64)
    at _sfc_ssrRender (components/ui/label/Label.vue:41:116)
    at renderComponentSubTree (node_modules/.pnpm/@vue+server-renderer@3.5.25_vue@3.5.25_typescript@5.6.3_/node_modules/@vue/server-renderer/dist/server-renderer.cjs.js:737:9)
    at renderComponentVNode (node_modules/.pnpm/@vue+server-renderer@3.5.25_vue@3.5.25_typescript@5.6.3_/node_modules/@vue/server-renderer/dist/server-renderer.cjs.js:686:12)
  • 解决方法
<script setup lang="ts">  
import { type HTMLAttributes, computed } from "vue";  
import { type LabelProps } from "radix-vue";  
const props = defineProps<LabelProps & { class?: HTMLAttributes["class"] }>();  
const delegatedProps = computed(() => {  
  const { class: _, ...delegated } = props;  
  return delegated;  
});  
</script>  

<template>  
  <Label    v-bind="delegatedProps"  
    :class="  
      cn(  
        'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70',  
        props.class,  
      )  
    "  
  >  
    <slot />  
  </Label>
</template>

修改为

<script setup lang="ts">  
import { type HTMLAttributes, computed } from "vue";  
// 🎯 核心修复:必须把真实的组件实例导进来,并重命名为 RadixLabel 避免套娃  
import { Label as RadixLabel, type LabelProps } from "radix-vue";  
const props = defineProps<LabelProps & { class?: HTMLAttributes["class"] }>();  
const delegatedProps = computed(() => {  
  const { class: _, ...delegated } = props;  
  return delegated;  
});  
</script>  
  
<template>  
  <!-- 🎯 核心修复:把这里的标签从 <Label> 改为 <RadixLabel> -->  
  <RadixLabel  
      v-bind="delegatedProps"  
      :class="  
      cn(  
        'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70',  
        props.class,  
      )  
    "  
  >  
    <slot />  
  </RadixLabel>
</template>

效果显示

  • 登录
  • 注册
  • 重置密码

vue3 demo

  • 参考 https://better-auth.com/docs/concepts/client
  • Component从上面官方的nuxt项目中借鉴

创建项目

创建

lixiaobo@lixiaobodeMacBook-Pro test % npm create vite@latest better-auth-cloudflare-ui-vue-demo --template vue-ts
> npx
> create-vite better-auth-cloudflare-ui-vue-demo vue-ts
│
◇  Select a framework:
│  Vue
│
◇  Select a variant:
│  TypeScript
│
◇  Install with npm and start now?
│  No
│
◇  Scaffolding project in /Users/lixiaobo/cloudflare/test/better-auth-cloudflare-ui-vue-demo...
│
└  Done. Now run:
  cd better-auth-cloudflare-ui-vue-demo
  npm install
  npm run dev

添加依赖

# 安装 Tailwind v4 的 Vite 原生插件、核心库与动画增强包 
npm install -D @tailwindcss/vite@latest tailwindcss@latest tailwindcss-animate 
# 安装 Better-Auth、Shadcn 核心运行依赖与自动导入 
npm install better-auth radix-vue clsx tailwind-merge class-variance-authority lucide-vue-next @vueuse/core 
npm install -D unplugin-auto-import unplugin-vue-components
npm install -D @types/node
npm install vue-router

tailwindcss配置

vite.config.ts中配置tailwindcss插件

export default defineConfig({  
  plugins: [  
      vue(),  
      tailwindcss()  
  ],  
})

shadcn-vue配置

  • 配置tsconfig.json中的compilerOptions,添加
"baseUrl": ".",  
"paths": {  
  "@/*": ["./src/*"]  
}
  • 配置vite.config.ts,添加resolve
resolve: {  
    alias: {  
        '@': path.resolve(__dirname, './src'),  
    }  
}
  • 导入tailwind
    创建assets/css/tailwind.css文件,并添加语句@import 'tailwindcss';,否则后续init的时候找不到tailwindcss
  • 初始化
lixiaobo@lixiaobodeMacBook-Pro better-auth-cloudflare-ui-vue-demo % npx shadcn-vue@latest init
✔ Preflight checks.
✔ Verifying framework. Found Vite.
✔ Validating Tailwind CSS config. Found v4.
✔ Validating import alias.
✔ **Which** **component library** **would you like to use?** › Reka UI
✔ **Which** **icon library** **would you like to use?** › Lucide
✔ **Which** **font** **would you like to use?** › Inter
✔ **Which color would you like to use as the** **base color****?** › Zinc
✔ Writing components.json.
✔ Checking registry.
✔ Updating CSS variables in src/assets/css/tailwind.css
added 1 package, and audited 148 packages in 11s
37 packages are looking for funding
  run `npm fund` for details
found **0** vulnerabilities
added 1 package, and audited 149 packages in 2s
38 packages are looking for funding
  run `npm fund` for details
found **0** vulnerabilities
✔ Installing dependencies.
✔ Created 1 file:
  - src/lib/utils.ts                                                                                            10:02:24
Success! Project initialization completed.                                                                      10:02:24
You may now add components.
  • 尝试导入组件
lixiaobo@lixiaobodeMacBook-Pro better-auth-cloudflare-ui-vue-demo % npx shadcn-vue@latest add card input label button
✔ Checking registry.
✔ Updating CSS variables in src/assets/css/tailwind.css
added 2 packages, and audited 151 packages in 3s
39 packages are looking for funding
  run `npm fund` for details
found **0** vulnerabilities
✔ Installing dependencies.
✔ Created 14 files:
  - src/components/ui/card/Card.vue                                                                             10:08:31
  - src/components/ui/card/CardAction.vue                                                                       10:08:31
  - src/components/ui/card/CardContent.vue                                                                      10:08:31
  - src/components/ui/card/CardDescription.vue                                                                  10:08:31
  - src/components/ui/card/CardFooter.vue                                                                       10:08:31
  - src/components/ui/card/CardHeader.vue                                                                       10:08:31
  - src/components/ui/card/CardTitle.vue                                                                        10:08:31
  - src/components/ui/card/index.ts                                                                             10:08:31
  - src/components/ui/input/Input.vue                                                                           10:08:31
  - src/components/ui/input/index.ts                                                                            10:08:31
  - src/components/ui/label/Label.vue                                                                           10:08:31
  - src/components/ui/label/index.ts                                                                            10:08:31
  - src/components/ui/button/Button.vue                                                                         10:08:31
  - src/components/ui/button/index.ts                                                                           10:08:31
  • 配置自动导入,无须import
Components({  
    dirs: [  
        'src/components/ui',
        'src/components'  
    ],  
    extensions: ['vue'],
    deep: true,                  // 开启深度递归扫描,支持 ui/button/ 这种子目录层级  
    directoryAsNamespace: false, // 保持组件名为纯净的 <Button>  
    dts: 'src/components.d.ts',   // 自动在 src 下生成组件的 TS 类型声明文件  
    resolvers: [  
        RekaUIResolver()  
    ]  
})
  • utils问题
TS2307: Cannot find module @/lib/utils or its corresponding type declarations.

解决上面的问题的方法就是在tsconfig.json里面配置

"include": [  
  "src/**/*.vue",  
]

因为,默认情况下ts不解析vue文件

配置better-auth

创建src/lib/auth-client.ts

import { createAuthClient } from "better-auth/vue"  
export const authClient = createAuthClient({  
    baseURL: "http://localhost:8787" // The base URL of your auth server  
})  
  
export const {  
    signIn,  
    signOut,  
    signUp,  
    useSession,  
    requestPasswordReset,  
    resetPassword,  
} = authClient;

创建views

  • sign-in.vue
<script setup lang="ts">  
// 🌟 彻底去掉了错误的 .js 后缀  
import { signIn } from "@/lib/auth-client";  
import { ref } from "vue";  
  
const email = ref("");  
const password = ref("");  
  
const handleSignIn = async () => {  
  await signIn.email(  
      {  
        email: email.value,  
        password: password.value,  
        callbackURL: "/",  
      },  
      {  
        onError(context) {  
          alert(context.error.message);  
        },  
      },  
  );  
};  
</script>  
  
<template>  
  <div class="h-screen flex justify-center items-center bg-background">  
    <Card class="mx-auto w-full max-w-sm">  
      <CardHeader>        <CardTitle class="text-2xl font-bold"> Login </CardTitle>  
        <CardDescription> Enter your email below to login to your account </CardDescription>  
      </CardHeader>      <CardContent>        <div class="grid gap-4">  
          <div class="grid gap-2">  
            <Label for="email">Email</Label>  
            <Input id="email" type="email" placeholder="m@example.com" v-model="email" required />  
          </div>  
          <div class="grid gap-2">  
            <!-- 🛠️ 终极彻底修复:全面抛弃常规 Flex,改用双列 Grid(两列等宽)并强行将左右元素各自对齐 -->  
            <!-- 这在 Tailwind v4 中拥有最高级别的布局权重,没有任何组件样式能够拦截它 -->            <div class="grid grid-cols-2 w-full items-center">  
              <Label for="password" class="justify-self-start text-sm font-medium">Password</Label>  
              <a href="/forget-password" class="justify-self-end text-sm underline text-muted-foreground hover:text-foreground text-right whitespace-nowrap">  
                Forgot your password?  
              </a>  
            </div>            <Input id="password" type="password" placeholder="password" v-model="password" required />  
          </div>  
          <Button type="submit" class="w-full" @click="handleSignIn">  
            Login  
          </Button>  
  
          <Button variant="outline" class="w-full" @click="async () => { await signIn.social({ provider: 'google', callbackURL: '/' }) }">  
            Login with Google  
          </Button>  
        </div>  
        <div class="mt-4 text-center text-sm text-muted-foreground">  
          Don't have an account?  
          <a href="/sign-up" class="underline text-foreground">  
            Sign up  
          </a>  
        </div>      </CardContent>    </Card>  </div></template>
  • sing-up.vue
<script lang="ts" setup>  
import { signUp } from "@/lib/auth-client";  
import {ref} from "vue";  
import {useRouter} from "vue-router";  
  
const firstName = ref("");  
const lastName = ref("");  
const email = ref("");  
const password = ref("");  
  
const handleSignUp = async () => {  
  const user = {  
   firstName: firstName.value,  
   lastName: lastName.value,  
   email: email.value,  
   password: password.value,  
  };  
  await signUp.email({  
   email: user.email,  
   password: user.password,  
   name: `${user.firstName} ${user.lastName}`,  
   callbackURL: "/",  
   fetchOptions: {  
    onError(context) {  
     alert(context.error.message);  
    },  
    onSuccess() {  
     useRouter().push("/dashboard");  
    },  
   },  
  });  
};  
</script>  
  
<template>  
  <div class="h-screen flex justify-center items-center">  
   <Card class="mx-auto max-w-sm">  
    <CardHeader>     <CardTitle class="text-xl">Sign Up</CardTitle>  
     <CardDescription>      Enter your information to create an account  
     </CardDescription>  
    </CardHeader>    <CardContent>     <div class="grid gap-4">  
      <div class="grid grid-cols-2 gap-4">  
       <div class="grid gap-2">  
        <Label for="first-name">First name</Label>  
        <Input id="first-name" placeholder="Max" required v-model="firstName" />  
       </div>       <div class="grid gap-2">  
        <Label for="last-name">Last name</Label>  
        <Input id="last-name" placeholder="Robinson" required v-model="lastName" />  
       </div>      </div>      <div class="grid gap-2">  
       <Label for="email">Email</Label>  
       <Input id="email" type="email" placeholder="m@example.com" required v-model="email" />  
      </div>      <div class="grid gap-2">  
       <Label for="password">Password</Label>  
       <Input id="password" type="password" v-model="password" />  
      </div>      <Button type="button" class="w-full" @click="handleSignUp">Create an account</Button>  
     </div>     <div class="mt-4 text-center text-sm">  
      Already have an account?  
      <a href="/sign-in" class="underline"> Sign in </a>  
     </div>    </CardContent>   </Card>  </div></template>
  • forget-password.vue
<script lang="ts" setup>  
// 🌟 1. API 全量规范自动挂载(如果你配置了 AutoImport,这里甚至可以不写 import)  
import { requestPasswordReset } from "@/lib/auth-client";  
import { ref } from "vue";  
  
const email = ref("");  
  
const handleRequestPasswordReset = async () => {  
  if (!email.value) {  
    alert("Please enter your email address");  
    return;  
  }  
  
  await requestPasswordReset(  
      {  
        email: email.value,  
        // 🌟 Better Auth 业务提示:指向你的重置输入密码页面,系统会自动在该路径后追加 ?token=xxx 票据  
        redirectTo: "/reset-password",  
      },  
      {  
        onSuccess() {  
          alert("Password reset link sent to your email! (Please check your terminal/email box)");  
          window.location.href = "/sign-in";  
        },  
        onError(context) {  
          alert(context.error.message);  
        },  
      },  
  );  
};  
</script>  
  
<template>  
  <div class="h-screen flex justify-center items-center bg-background">  
    <!-- 🌟 2. 宽度锁定,对冲任何可能在屏幕缩放时产生的突兀断行 -->  
    <Card class="mx-auto w-full max-w-sm shadow-md border border-border">  
      <CardHeader class="pb-4">  
        <CardTitle class="text-2xl font-bold tracking-tight">Reset Password</CardTitle>  
        <CardDescription class="text-sm text-muted-foreground">  
          Enter your email below to reset your password  
        </CardDescription>  
      </CardHeader>  
      <CardContent class="p-6 pt-0">  
        <!-- 🛠️ 核心修复:全面改用纵向管道 Flex 布局加物理垂直隔离(space-y-4-->  
        <!-- 这在 Tailwind v4 下拥有最高级别的静态占位解析权重,绝不产生黏连塌陷 -->        <div class="flex flex-col space-y-4 w-full">  
  
          <!-- 邮箱输入区域小盒子 -->  
          <div class="flex flex-col space-y-1.5 w-full">  
            <Label for="email" class="text-sm font-medium">Email</Label>  
            <Input id="email" type="email" placeholder="m@example.com" required v-model="email" class="w-full" />  
          </div>  
          <!-- 发送请求按钮 -->  
          <Button type="button" class="w-full mt-2 cursor-pointer" @click="handleRequestPasswordReset">  
            Send Reset Link  
          </Button>  
  
          <!-- 🛠️ 界面细节升级:完美向下隔离,将返回登录链接优雅地沉在最底部并配上响应式换色 -->  
          <div class="pt-2 text-center text-sm text-muted-foreground">  
            <a href="/sign-in" class="underline text-foreground hover:opacity-80 transition-opacity">  
              Back to Sign In  
            </a>  
          </div>  
        </div>      </CardContent>    </Card>  </div></template>
  • reset-password.vue
<script lang="ts" setup>  
import { resetPassword } from "@/lib/auth-client.js";  
import {ref} from "vue";  
  
const confirmPassword = ref("");  
const password = ref("");  
  
const handleResetPassword = async () => {  
  if (confirmPassword.value !== password.value) {  
   alert("Please enter same passwords");  
   return;  
  }  
  
  await resetPassword({  
   newPassword: password.value,  
   fetchOptions: {  
    onSuccess(context) {  
     window.location.href = "/sign-in";  
    },  
    onError(context) {  
     alert(context.error.message);  
    },  
   },  
  });  
};  
</script>  
  
<template>  
  <div class="h-screen flex justify-center items-center">  
   <Card class="mx-auto max-w-sm">  
    <CardHeader>     <CardTitle class="text-2xl">Reset Password</CardTitle>  
     <CardDescription>Enter your new password below</CardDescription>  
    </CardHeader>    <CardContent>     <div class="grid gap-4">  
      <div class="grid gap-2">  
       <Label for="password">New Password</Label>  
       <Input id="password" type="password" required v-model="password" placeholder="New Password" />  
      </div>      <div class="grid gap-2">  
       <Label for="password">Confirm Password</Label>  
       <Input id="password" type="password" required placeholder="Confirm Password"  
        v-model="confirmPassword" />  
      </div>      <Button type="button" class="w-full" @click="handleResetPassword">Reset</Button>  
     </div>    </CardContent>   </Card>  </div></template>
  • dashboard.vue
<script setup lang="ts">  
import { useSession, signOut } from "@/lib/auth-client";  
const session = useSession();  
</script>  
  
<template>  
    <div class="min-h-[80vh] flex items-center justify-center overflow-hidden no-visible-scrollbar px-6 md:px-0">  
        <Card class="w-[350px]">  
            <CardHeader>                <CardTitle>                    User  
                </CardTitle>  
            </CardHeader>            <CardContent>                <div class="flex gap-2 items-center">  
                    <Avatar>                        <AvatarImage :src="session?.data?.user.image || ''" alt="User profile" />  
                        <AvatarFallback>{{ session?.data?.user.name[0] }}</AvatarFallback>  
                    </Avatar>                    <div>                        <p class="text-sm">  
                            {{ session?.data?.user?.name }}  
                        </p>  
                        <p class="text-xs">  
                            {{ session?.data?.user?.email }}  
                        </p>  
                    </div>                </div>            </CardContent>            <CardFooter>                <Button @click="async () => {  
                    await signOut()  
                    // router.push('/')  
                }" variant="secondary">  
                    Sing Out  
                </Button>  
            </CardFooter>        </Card>    </div></template>
  • index.vue
<script setup lang="ts">  
import { ref } from "vue";  
// 🛠️ 改造 1:在纯 Vue 3 中,必须通过标准的组件引入或全量路由包导入  
// 如果你用的是 Vue Router,需要导入 RouterLink  
import { RouterLink } from "vue-router";  
  
// 🛠️ 改造 2:纯 Vue 3 没有 Nuxt 的全局自动导入,必须手动显式引入你的 Auth 客户端方法  
import { useSession } from "@/lib/auth-client";  
// 🛠️ 改造 3:必须手动显式引入你的 UI 组件(例如 Shadcn Vue 或你本地的 Button)  
import { Button } from "@/components/ui/button";  
  
const features = [  
  "Email & Password",  
  "Organization | Teams",  
  "Passkeys",  
  "Multi Factor",  
  "Password Reset",  
  "Email Verification",  
  "Roles & Permissions",  
  "Rate Limiting",  
  "Session Management",  
];  
  
const session = useSession();  
console.log(session);  
</script>  
  
<template>  
  <div class="min-h-[80vh] flex items-center justify-center overflow-hidden no-visible-scrollbar px-6 md:px-0">  
    <main class="flex flex-col gap-4 row-start-2 items-center justify-center">  
      <div class="flex flex-col gap-1">  
        <h3 class="font-bold text-4xl text-black dark:text-white text-center">  
          Better Auth.  
        </h3>  
        <p class="text-center break-words text-sm md:text-base">  
          Official demo to showcase  
          <!-- 🛠️ 改造 4:修复了 React 的 className 错误,改回标准 Vue 的 class -->  
          <a href="https://better-auth.com" target="_blank" class="italic underline">  
            better-auth  
          </a>  
          features and capabilities.  
          <br />  
        </p>        <div class="flex flex-col gap-3 pt-2 flex-wrap">  
          <div class="border-y py-2 border-dotted bg-secondary/60 opacity-80">  
            <div class="text-xs flex items-center gap-2 justify-center text-muted-foreground">  
              <span class="text-center">  
                All features on this demo are Implemented with Better Auth without any custom backend code  
              </span>  
            </div>          </div>          <div class="flex gap-2 justify-center flex-wrap">  
            <div v-for="feature in features" :key="feature">  
              <span class="border-b pb-1 text-muted-foreground text-xs cursor-pointer hover:text-foreground duration-150 ease-in-out transition-all hover:border-foreground flex items-center gap-1">  
                {{ feature }}  
              </span>  
            </div>          </div>        </div>  
        <div class="flex items-center gap-2 mt-2 mx-auto">  
          <!-- 🛠️ 改造 5:将 Nuxt 专属的 <NuxtLink> 替换为 Vue Router 标准的 <RouterLink> -->  
          <RouterLink to="/sign-in" v-if="!session.data">  
            <Button variant="outline" class="rounded-none">  
              Sign In  
            </Button>  
          </RouterLink>  
          <RouterLink to="/dashboard" v-if="session.data">  
            <Button variant="outline" class="rounded-none">  
              Dashboard  
            </Button>  
          </RouterLink>        </div>      </div>    </main>  </div></template>

创建路由

  • 创建env.d.ts,防止路由里面无法识别@/views等路径
declare module '*.vue' {  
    import type { DefineComponent } from 'vue'  
    const component: DefineComponent<{}, {}, any>  
    export default component  
}
  • 创建文件src/router/index.ts
import {createRouter, createWebHistory} from 'vue-router'  
  
const routes = [  
    {  
        path: "/",  
        name: "home",  
        component: ()=> import('@/views/index.vue'),  
    },  
    { path: '/sign-in', name: "sign-in", component: () => import('@/views/sign-in.vue') },  
    { path: '/sign-up', name: "sign-up",  component: () => import('@/views/sign-up.vue') },  
    { path: '/forget-password', name: "forget-password",  component: () => import('@/views/forget-password.vue') },  
    { path: '/reset-password', name: "reset-password",  component: () => import('@/views/reset-password.vue') },  
  
]  
  
const router = createRouter({  
    history: createWebHistory(),  
    routes  
})  
  
export default router

页面效果

  • index
  • signin
  • singup
  • forget

cors

为了本地测试能够通过,需要添加如下配置

  • 在cloudflare worker的auth.ts添加
trustedOrigins: [  
    "http://localhost:5173"  
],
  • 在cloudflare worker的index.ts添加
app.use('/api/auth/*', cors({  
    // 直接将前端发过来的请求源(c.req.header('Origin'))原封不动地动态塞回去。  
    // 这样管它是 localhost 还是带有 75aa0f36 随机哈希的预览域名,Hono 都会在 OPTIONS 预检和真正 POST 时秒发“特别通行证”!    
    origin: (origin) => {  
        return origin; // 100% 动态信任并回传当前前端发起的域名  
    },  
    allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],  
    allowHeaders: ['Content-Type', 'Authorization'],  
    exposeHeaders: ['Content-Length', 'X-Kuma-Revision'],  
    maxAge: 600,  
    credentials: true, // 🌟 必须设为 true,否则 Better Auth 的 Session 无法写入浏览器 Cookie  
}))

发布到cloudflare

配置auth-client.ts

export const authClient = createAuthClient({  
    baseURL: "https://better-auth-cloudflare-demo.shakingwaves.workers.dev/api/auth", // The base URL of your auth server
    fetchOptions: {  
        credentials: "include"  
    }  
})

编译

lixiaobo@lixiaobodeMacBook-Pro better-auth-cloudflare-ui-vue-demo % npm run build
> better-auth-cloudflare-ui-vue-demo@0.0.0 build
> vue-tsc -b && vite build
vite v8.1.4 building client environment for production...
✓ 697 modules transformed.
computing gzip size...
dist/index.html                                    **0.57 kB** │ gzip:  0.35 kB
dist/assets/index-CAWqWHIQ.css                    **24.54 kB** │ gzip:  5.24 kB
dist/assets/forget-password-kXYPRVc-.js            **1.88 kB** │ gzip:  0.95 kB
dist/assets/reset-password-OetIz09M.js             **1.92 kB** │ gzip:  0.84 kB
dist/assets/views-1t-piWyo.js                      **2.20 kB** │ gzip:  1.09 kB
dist/assets/sign-in-BPG8k_4g.js                    **2.22 kB** │ gzip:  1.01 kB
dist/assets/sign-up-DdEw2C2N.js                    **2.40 kB** │ gzip:  1.00 kB
dist/assets/CardTitle-CZ0451W0.js                  **5.89 kB** │ gzip:  2.30 kB
dist/assets/index-B_Sscwc3.js                     **32.99 kB** │ gzip: 13.18 kB
dist/assets/runtime-core.esm-bundler-3gagyTuT.js  **56.55 kB** │ gzip: 22.23 kB
dist/assets/auth-client-DrlXBgJb.js               **59.07 kB** │ gzip: 20.54 kB
✓ built in 393ms

发布

 wrangler pages deploy dist --project-name=better-auth-cloudflare-ui-vue-demo
▲ [WARNING] **Proxy environment variables detected. We'll use your proxy for fetch requests.**
 ⛅️ wrangler 4.106.0 (update available 4.110.0)
───────────────────────────────────────────────
✨ Success! Uploaded 9 files (4 already uploaded) (4.76 sec)
✨ Uploading _redirects
🌎 Deploying...
✨ Deployment complete! Take a peek over at https://6a9c138d.better-auth-cloudflare-ui-vue-demo.pages.dev

注册演示

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐