Skip to content

Commit d6e9022

Browse files
feat: add @tanstack/devtools-rspack (1:1 Vite parity) + shared @tanstack/devtools-bundler-core (#484)
* feat(bundler-core): scaffold @tanstack/devtools-bundler-core package * feat(bundler-core): move framework-agnostic logic out of devtools-vite * feat(bundler-core): add dev-state singleton for loader/plugin sharing * refactor(devtools-vite): consume @tanstack/devtools-bundler-core * test(bundler-core): relocate handleDevToolsRequest routing tests from devtools-vite * feat(devtools-rspack): scaffold package with skeleton exports * feat(devtools-rspack): transform pipeline loader * feat(devtools-rspack): plugin (loader injection, event bus, dev middleware, package manager) + dev-server port routing * chore(devtools): fix core import ordering + guard rspack package-manager wiring in CI * test(devtools-rspack): entry factory test * test(devtools-rspack): react rspack example + e2e smoke * chore: changesets for devtools-bundler-core + devtools-rspack Also removes the redundant @rspack/core devDependency from devtools-rspack (already declared as peerDependency, unused otherwise per knip). * fix(devtools-rspack): process @TanStack node_modules for connection placeholder + runtime-bridge injection The single loader rule excluded all of node_modules, so the __TANSTACK_DEVTOOLS_* connection placeholders (which live in @tanstack/devtools-event-bus's client, under node_modules for real consumers) were never replaced -- breaking a custom eventBusConfig.port/host/protocol. Add a second loader rule scoped to @tanstack/devtools*|event-bus* under node_modules (flat + pnpm nested layouts), and normalize the step-4 id gate to posix so it matches on Windows. Matches vite's connection-injection, which does not exclude node_modules. * fix(devtools-rspack): eager event-bus connection, gate dep-refresh on package.json, port-routing tests, doc accuracy * fix(devtools-rspack): emit package-json-read on package.json change (vite parity) * chore(devtools): formatting + lint fixes * fix(devtools-rspack): make marketplace + go-to-source work under Rspack - Seed the shared global event target before wiring the package manager so the plugin receives the client's `mounted` event and replies with `package-json-read` (the marketplace stayed empty without it), and gate the wiring on the compiler mode instead of `process.env.NODE_ENV`, which isn't set at `apply()` time under `rspack serve`. - Normalize the module path before stripping cwd in enhance-logs and inject-source so Rspack's backslash ids on Windows don't leak an absolute path that breaks editor open. - Enable `connectToServerBus` in the react-rspack example so the client connects to the event bus. * ci: apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent d061f0c commit d6e9022

63 files changed

Lines changed: 3120 additions & 292 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@tanstack/devtools-bundler-core': minor
3+
---
4+
5+
Introduce `@tanstack/devtools-bundler-core`, the framework-agnostic core (transforms, editor integration, package-manager, dev-state) shared by the TanStack devtools bundler plugins.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@tanstack/devtools-vite': patch
3+
---
4+
5+
Internal refactor: consume `@tanstack/devtools-bundler-core` for shared logic. No public API or behavior change.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
'@tanstack/devtools-bundler-core': patch
3+
'@tanstack/devtools-rspack': patch
4+
---
5+
6+
Fix Rspack devtools integration on Windows and the plugin marketplace:
7+
8+
- Normalize the module path before stripping `cwd` when building the
9+
"Go to Source" link and the injected `data-tsd-source` attribute, so
10+
Rspack's backslash module ids on Windows no longer leak an absolute path
11+
that the editor-open handler then fails to resolve.
12+
- Seed the shared in-process event target before wiring the package manager,
13+
so the plugin actually receives the client's `mounted` event and replies with
14+
`package-json-read`. Without this the plugin marketplace never populated under
15+
Rspack. Also gate the wiring on the compiler's `mode` (`isDev`) rather than
16+
`process.env.NODE_ENV`, which isn't set at `apply()` time under `rspack serve`.

.changeset/rspack-plugin.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@tanstack/devtools-rspack': minor
3+
---
4+
5+
Add `@tanstack/devtools-rspack` — Rspack plugin with 1:1 feature parity to `@tanstack/devtools-vite` (source injection, enhanced logs, console piping, devtools removal on build, editor integration, event bus, package manager).

examples/react-rspack/index.html

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1" />
6+
<title>React Rspack Example - TanStack Devtools</title>
7+
</head>
8+
<body>
9+
<noscript>You need to enable JavaScript to run this app.</noscript>
10+
<div id="root"></div>
11+
</body>
12+
</html>

examples/react-rspack/package.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"name": "react-rspack-example",
3+
"private": true,
4+
"scripts": {
5+
"dev": "rspack serve",
6+
"build": "rspack build --mode=production"
7+
},
8+
"dependencies": {
9+
"@tanstack/devtools-rspack": "workspace:*",
10+
"@tanstack/react-devtools": "workspace:*",
11+
"react": "^19.2.0",
12+
"react-dom": "^19.2.0"
13+
},
14+
"devDependencies": {
15+
"@rspack/cli": "^1.5.0",
16+
"@rspack/core": "^1.5.0",
17+
"@rspack/dev-server": "^1.1.4",
18+
"@types/react": "^19.2.0",
19+
"@types/react-dom": "^19.2.0",
20+
"typescript": "^5.9.2"
21+
}
22+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// @ts-check
2+
import { HtmlRspackPlugin } from '@rspack/core'
3+
import { devtools } from '@tanstack/devtools-rspack'
4+
5+
// NOTE: `@tanstack/devtools-rspack` ships as an ESM-only package, so this
6+
// config is authored as ESM (`rspack.config.mjs`). A CommonJS config would
7+
// need `const { devtools } = await import('@tanstack/devtools-rspack')`.
8+
9+
/** @type {(env: unknown, argv: { mode?: string }) => import('@rspack/core').Configuration} */
10+
export default (_env, argv) => ({
11+
mode: argv.mode === 'production' ? 'production' : 'development',
12+
entry: './src/main.tsx',
13+
// No source maps in production so the devtools-strip check is unambiguous
14+
// (a source map would embed the original, un-stripped `TanStackDevtools` source).
15+
devtool: argv.mode === 'production' ? false : 'eval-source-map',
16+
plugins: [devtools(), new HtmlRspackPlugin({ template: './index.html' })],
17+
devServer: {
18+
port: 3100,
19+
},
20+
module: {
21+
rules: [
22+
{
23+
test: /\.[jt]sx?$/,
24+
exclude: /node_modules/,
25+
use: {
26+
loader: 'builtin:swc-loader',
27+
options: {
28+
jsc: {
29+
parser: {
30+
syntax: 'typescript',
31+
tsx: true,
32+
},
33+
transform: {
34+
react: {
35+
runtime: 'automatic',
36+
development: true,
37+
},
38+
},
39+
},
40+
},
41+
},
42+
},
43+
],
44+
},
45+
resolve: {
46+
extensions: ['.tsx', '.ts', '.jsx', '.js'],
47+
},
48+
})

examples/react-rspack/src/App.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { useState } from 'react'
2+
3+
export default function App() {
4+
const [count, setCount] = useState(0)
5+
6+
// enhanced-logs has something to transform
7+
console.log('React Rspack example mounted, count =', count)
8+
9+
return (
10+
<div style={{ padding: '20px', fontFamily: 'system-ui, sans-serif' }}>
11+
<h1>TanStack Devtools React + Rspack Example</h1>
12+
<p>Current count: {count}</p>
13+
<button onClick={() => setCount((c) => c + 1)}>Increment</button>
14+
</div>
15+
)
16+
}

examples/react-rspack/src/main.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { createRoot } from 'react-dom/client'
2+
import { TanStackDevtools } from '@tanstack/react-devtools'
3+
import App from './App'
4+
5+
function Root() {
6+
return (
7+
<>
8+
<App />
9+
<TanStackDevtools eventBusConfig={{ connectToServerBus: true }} />
10+
</>
11+
)
12+
}
13+
14+
const root = createRoot(document.getElementById('root')!)
15+
root.render(<Root />)
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"compilerOptions": {
3+
"target": "ESNext",
4+
"lib": ["DOM", "DOM.Iterable", "ESNext"],
5+
"module": "ESNext",
6+
"moduleResolution": "Bundler",
7+
"jsx": "react-jsx",
8+
"strict": true,
9+
"esModuleInterop": true,
10+
"skipLibCheck": true,
11+
"noEmit": true
12+
},
13+
"include": ["src"]
14+
}

0 commit comments

Comments
 (0)