Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/rspack-import-meta.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tanstack/devtools': patch
---

Fix Rspack compatibility by avoiding direct `import.meta` access patterns and add a regression test to prevent reintroduction.
2 changes: 1 addition & 1 deletion packages/devtools/src/components/source-inspector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export const SourceInspector = () => {
e.stopPropagation()

// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
const baseUrl = new URL(import.meta?.env?.BASE_URL ?? '/', location.origin)
const baseUrl = new URL(import.meta.env?.BASE_URL ?? '/', location.origin)
const url = new URL(
`__tsd/open-source?source=${encodeURIComponent(
highlightState.dataSource,
Expand Down
2 changes: 1 addition & 1 deletion packages/devtools/src/core.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export class TanStackDevtoolsCore {
// tsup-preset-solid statically replaces this variable during build, which eliminates this code from server bundle
// can be run outside of vite so we ignore the rule
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (import.meta?.env?.SSR) return
if (import.meta.env?.SSR) return

if (this.#isMounted) {
throw new Error('Devtools is already mounted')
Expand Down
50 changes: 50 additions & 0 deletions packages/devtools/tests/import-meta-compat.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { readdirSync, readFileSync } from 'node:fs'
import { extname, join } from 'node:path'
import { describe, it } from 'vitest'

const sourceRoot = join(process.cwd(), 'src')
const sourceExtensions = new Set(['.ts', '.tsx'])
const forbiddenPatterns = [
/import\.meta\?\./,
/typeof\s+import\.meta(?!\.)/,
/=\s*import\.meta(?!\.)/,
]

const getSourceFiles = (dir: string): Array<string> => {
const entries = readdirSync(dir, { withFileTypes: true })
return entries.flatMap((entry) => {
const path = join(dir, entry.name)
if (entry.isDirectory()) {
return getSourceFiles(path)
}
if (sourceExtensions.has(extname(path))) {
return [path]
}
return []
})
}

describe('import.meta compatibility', () => {
it('avoids direct import.meta access that breaks Rspack parsing', () => {
const violations = getSourceFiles(sourceRoot).flatMap((path) => {
const content = readFileSync(path, 'utf8')
const lines = content.split('\n')
return lines.flatMap((line, index) => {
const hasViolation = forbiddenPatterns.some((pattern) =>
pattern.test(line),
)
return hasViolation ? [`${path}:${index + 1}`] : []
})
})

if (violations.length > 0) {
throw new Error(
[
'Found direct `import.meta` usage in devtools source.',
'Rspack only supports property access on `import.meta`.',
...violations,
].join('\n'),
)
}
})
})