From ea1bd5c7e26dc2510bccb0157253859fdb7fa8ca Mon Sep 17 00:00:00 2001 From: Alem Tuzlak Date: Thu, 18 Sep 2025 11:15:22 +0200 Subject: [PATCH 1/5] feat: remove devtools from build bundles --- .changeset/nice-loops-decide.md | 5 + examples/react/basic/vite.config.ts | 4 +- .../{tests => src}/inject-source.test.ts | 2 +- packages/devtools-vite/src/plugin.ts | 25 ++ .../devtools-vite/src/remove-devtools.test.ts | 230 ++++++++++++++++++ packages/devtools-vite/src/remove-devtools.ts | 70 ++++++ 6 files changed, 334 insertions(+), 2 deletions(-) create mode 100644 .changeset/nice-loops-decide.md rename packages/devtools-vite/{tests => src}/inject-source.test.ts (99%) create mode 100644 packages/devtools-vite/src/remove-devtools.test.ts create mode 100644 packages/devtools-vite/src/remove-devtools.ts diff --git a/.changeset/nice-loops-decide.md b/.changeset/nice-loops-decide.md new file mode 100644 index 00000000..5881d9fa --- /dev/null +++ b/.changeset/nice-loops-decide.md @@ -0,0 +1,5 @@ +--- +'@tanstack/devtools-vite': minor +--- + +Allow the vite plugin to remove the devtools completely from the build output bundle for 0 production footprint diff --git a/examples/react/basic/vite.config.ts b/examples/react/basic/vite.config.ts index ff6cabe2..9eb5bf61 100644 --- a/examples/react/basic/vite.config.ts +++ b/examples/react/basic/vite.config.ts @@ -6,7 +6,9 @@ import Inspect from 'vite-plugin-inspect' // https://vite.dev/config/ export default defineConfig({ plugins: [ - devtools(), + devtools({ + removeDevtoolsOnBuild: true + }), Inspect(), react({ // babel: { diff --git a/packages/devtools-vite/tests/inject-source.test.ts b/packages/devtools-vite/src/inject-source.test.ts similarity index 99% rename from packages/devtools-vite/tests/inject-source.test.ts rename to packages/devtools-vite/src/inject-source.test.ts index edc0fb52..b145f799 100644 --- a/packages/devtools-vite/tests/inject-source.test.ts +++ b/packages/devtools-vite/src/inject-source.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest' -import { addSourceToJsx } from '../src/inject-source' +import { addSourceToJsx } from './inject-source' const removeEmptySpace = (str: string) => { return str.replace(/\s/g, '').trim() diff --git a/packages/devtools-vite/src/plugin.ts b/packages/devtools-vite/src/plugin.ts index dfe2669a..976305c7 100644 --- a/packages/devtools-vite/src/plugin.ts +++ b/packages/devtools-vite/src/plugin.ts @@ -3,6 +3,7 @@ import chalk from 'chalk' import { ServerEventBus } from '@tanstack/devtools-event-bus/server' import { handleDevToolsViteRequest } from './utils' import { DEFAULT_EDITOR_CONFIG, handleOpenSource } from './editor' +import { removeDevtools } from './remove-devtools' import { addSourceToJsx } from './inject-source' import type { EditorConfig } from './editor' import type { ServerEventBusConfig } from '@tanstack/devtools-event-bus/server' @@ -27,6 +28,11 @@ export type TanStackDevtoolsViteConfig = { */ enabled: boolean } + /** + * Whether to remove devtools from the production build. + * @default true + */ + removeDevtoolsOnBuild?: boolean /** * Configuration for source injection. */ @@ -46,6 +52,7 @@ export const devtools = (args?: TanStackDevtoolsViteConfig): Array => { let port = 5173 const enhancedLogsConfig = args?.enhancedLogs ?? { enabled: true } const injectSourceConfig = args?.injectSource ?? { enabled: true } + const removeDevtoolsOnBuild = args?.removeDevtoolsOnBuild ?? true const bus = new ServerEventBus(args?.eventBusConfig) return [ @@ -116,6 +123,24 @@ export const devtools = (args?: TanStackDevtoolsViteConfig): Array => { ) }, }, + { + name: '@tanstack/devtools:remove-devtools-on-build', + apply(_, { command }) { + return command === 'build' && removeDevtoolsOnBuild + }, + enforce: "pre", + transform(code, id) { + if ( + id.includes('node_modules') || + id.includes('?raw') || + id.includes('dist') || + id.includes('build') + ) + return code + + return removeDevtools(code, id) + }, + }, { name: '@tanstack/devtools:better-console-logs', enforce: 'pre', diff --git a/packages/devtools-vite/src/remove-devtools.test.ts b/packages/devtools-vite/src/remove-devtools.test.ts new file mode 100644 index 00000000..cfb7cd92 --- /dev/null +++ b/packages/devtools-vite/src/remove-devtools.test.ts @@ -0,0 +1,230 @@ +import { describe, expect, test } from "vitest"; +import { removeDevtools } from "./remove-devtools"; + +const removeEmptySpace = (str: string) => { + return str.replace(/\s/g, '').trim() +} + +describe("remove-devtools", () => { + test("it removes devtools if Imported directly", () => { + const output = removeEmptySpace( + removeDevtools( + ` + import { ReactQueryDevtoolsPanel } from '@tanstack/react-query-devtools' +import { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools' +import { + Link, + Outlet, + RouterProvider, + createRootRoute, + createRoute, + createRouter, +} from '@tanstack/react-router' +import { TanStackDevtools } from '@tanstack/react-devtools' + + + +export default function DevtoolsExample() { + return ( + <> + , + }, + { + name: 'TanStack Router', + render: , + }, + /* { + name: "The actual app", + render: