Skip to content

Dev: better-auth/client/plugins fails to resolve when auth is enabled (the better-auth/client alias matches it as a prefix) #565

Open

Description

@karthickeyan-dev

Description

With auth enabled, void dev aliases better-auth/client (and /react, /vue, /svelte, /solid) to absolute file paths. A string alias in Vite also matches subpaths, so better-auth/client/plugins, where Better Auth's client plugins such as adminClient() live, is rewritten to …/better-auth/dist/client/index.mjs/plugins, which doesn't exist. Any app that passes a Better Auth client plugin to createAuthClient breaks in dev. void build is not affected, because the alias is only added for serve.

Steps to reproduce

  1. Enable auth in void.config.ts: auth: { providers: ['email'] }.

  2. Add better-auth as a dependency (the same version Void uses).

  3. Create a client with a plugin and import it from a page:

    // src/lib/auth-client.ts
    import { adminClient } from 'better-auth/client/plugins';
    import { createAuthClient } from 'void/client';
    
    export const authClient = createAuthClient({
      basePath: '/api/auth',
      plugins: [adminClient()],
    });
  4. Run void dev and open that page.

Actual behavior

  • Client: Pre-transform error: Failed to resolve import "better-auth/client/plugins" from "src/lib/auth-client.ts". Does the file exist?
  • SSR: the page returns 500 with Error: No such module "workers/runner-worker/file:/…/better-auth/dist/client/plugins/index.mjs".

Expected behavior

better-auth/client/plugins resolves to better-auth/dist/client/plugins/index.mjs, as it does in void build and in Node.

Cause

packages/void/src/plugin-routing.ts (main @ 6ba3dbcc3a, lines 616–622):

const betterAuthSubpaths = ['client', 'react', 'vue', 'svelte', 'solid'];
const resolvedAliases = betterAuthSubpaths.flatMap((sub) => {
  try {
    return [{ find: `better-auth/${sub}`, replacement: resolveFile(`better-auth/${sub}`) }];
  } catch {
    return [];
  }
});

A string find matches the exact id and any id that starts with find + '/', replacing the prefix. resolveFile('better-auth/client') is …/dist/client/index.mjs, so better-auth/client/plugins becomes …/dist/client/index.mjs/plugins.

Possible fix

Anchor the patterns so they only match the exact specifier, and pre-resolve client/plugins too if it should avoid the lazy-discovery reload the comment mentions:

const betterAuthSubpaths = ['client', 'client/plugins', 'react', 'vue', 'svelte', 'solid'];
// …
return [{ find: new RegExp(`^better-auth/${sub}$`), replacement: resolveFile(`better-auth/${sub}`) }];

Workaround

A plugin listed after voidPlugin() adds an exact-match alias. Aliases from a later plugin's config hook are tried first, so this one wins:

// vite.config.ts
import { createRequire } from 'node:module';
import type { Plugin } from 'vite-plus';

const require = createRequire(import.meta.url);

function betterAuthClientPlugins(): Plugin {
  return {
    name: 'better-auth-client-plugins',
    config: () => ({
      resolve: {
        alias: [
          {
            find: /^better-auth\/client\/plugins$/,
            replacement: require.resolve('better-auth/client/plugins'),
          },
        ],
      },
    }),
  };
}

// plugins: [voidPlugin(), voidReact(), betterAuthClientPlugins()]

Related

#554 edits the same block (adds authConfigEnvironmentConfig to the returned config) but keeps the prefix aliases.

Environment

  • void 1.2.1 (also on 1.1.12), better-auth 1.7.11
  • vite-plus 1.3.0, Node 22.23.3, macOS 26.6

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions