Skip to content

devtools-vite open-source handler prepends process.cwd() to absolute source paths in monorepos #461

@pavle-rgb

Description

@pavle-rgb

TanStack Devtools version

  • @tanstack/devtools-vite@0.7.0
  • @tanstack/react-devtools@0.10.2
  • transitive @tanstack/devtools@0.11.2
  • Vite 7.3.3

Framework/Library version

  • React 19.2.6
  • Vite 7.3.3
  • pnpm workspace / monorepo
  • Browser tested: Chrome/Chromium on Linux

Describe the bug and the steps to reproduce it

In a pnpm monorepo, @tanstack/devtools-vite source opening works for files inside the running app package, but fails for files from shared workspace packages.

The difference appears to be the source path shape injected into data-tsd-source:

  • app-local files are displayed as app-relative paths, for example:
src/routes/~_protected/~index/~route.tsx:12:7
  • shared workspace package files are displayed as absolute paths, for example:
/home/user/project/packages/ui/src/components/router/router-error.tsx:17:5

When clicking a shared-package element, the Vite open-source middleware appears to prepend process.cwd() even when the source path is already absolute. In this setup, the Vite server cwd is the app package, for example:

/home/user/project/apps/admin

So the absolute source path becomes an invalid doubled path like:

/home/user/project/apps/admin/home/user/project/packages/ui/src/components/router/router-error.tsx

As a result, editor opening fails for shared package files, while app-local src/... files work.

Reproduction setup:

project/
  apps/
    admin/
      vite.config.ts
      src/routes/...
  packages/
    ui/
      src/components/router/router-error.tsx

The app aliases shared packages through Vite, for example:

resolve: {
  alias: {
    "@acme/ui": path.resolve(appDir, "../../packages/ui/src"),
  },
}

Reproduction steps:

  1. Start the Vite app from apps/admin.
  2. Render a component imported from packages/ui/src/....
  3. Hold Ctrl+Alt+Shift.
  4. Hover the shared-package component.
  5. Observe that the source label is an absolute path under the workspace root.
  6. Click the element.

Expected behavior:

  • If the source path is already absolute, the open-source handler should pass it through unchanged.
  • If the source path is relative, it should resolve it against the Vite app cwd.

Actual behavior:

  • App-local src/... files open.
  • Shared workspace package files do not open because the absolute source path is resolved as if it were relative to process.cwd().

The relevant code appears to be in the open-source request handler:

source: file ? normalizePath(`${process.cwd()}/${file}`) : undefined

That works for relative src/... paths, but not for absolute paths.

Minimal reproducible example

I do not have a public minimal repro yet. This was reproduced in a private pnpm monorepo with a Vite app consuming source from a local workspace package through a Vite alias.

I can try to create a minimal public reproduction if needed, but the path behavior above should be reproducible with any Vite app whose source injection includes JSX from a workspace package outside process.cwd().

Workaround

I worked around this in a shared Vite config by normalizing the path before passing it to launch-editor:

const resolveEditorFilePath = (filePath: string, appDir: string, workspaceDir: string) => {
  if (existsSync(filePath)) return filePath;

  const workspacePathIndex = filePath.lastIndexOf(workspaceDir);
  if (workspacePathIndex > 0) {
    const workspaceFilePath = filePath.slice(workspacePathIndex);

    if (existsSync(workspaceFilePath)) return workspaceFilePath;
  }

  const workspaceRelativeFilePath = path.resolve(workspaceDir, filePath.replace(/^\/+/, ""));
  if (existsSync(workspaceRelativeFilePath)) return workspaceRelativeFilePath;

  const srcIndex = filePath.indexOf("/src/");
  if (srcIndex === -1) return filePath;

  const appRelativeFilePath = filePath.slice(srcIndex + 1);
  const appFilePath = path.resolve(appDir, appRelativeFilePath);

  return existsSync(appFilePath) ? appFilePath : filePath;
};

This handles:

  • app-local src/...
  • workspace-relative packages/...
  • clean absolute paths
  • doubled absolute paths caused by cwd prepending

A likely upstream fix would be to check whether file is already absolute before prepending process.cwd().

Screenshots or Videos

Not attached. The source label visibly shows the absolute package path, but editor opening only succeeds after normalizing the doubled path in userland.

Do you intend to try to help solve this bug with your own PR?

Yes, I think I know how to fix it and will discuss it in the comments of this issue

Terms & Code of Conduct

  • I agree to follow this project's Code of Conduct
  • I understand that if my bug cannot be reliably reproduced in a debuggable environment, it will probably not get fixed and this issue may even be closed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions