@tanstack/devtools-vite 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -18,10 +18,36 @@ const transform = (ast, filePath, port) => {
18
18
  location.start.column
19
19
  ];
20
20
  const finalPath = `${filePath}:${lineNumber}:${column + 1}`;
21
- path.node.arguments.unshift(
21
+ const logMessage = `${chalk.magenta("LOG")} ${chalk.blueBright(`${finalPath}`)}
22
+ → `;
23
+ const serverLogMessage = t.arrayExpression([
24
+ t.stringLiteral(logMessage)
25
+ ]);
26
+ const browserLogMessage = t.arrayExpression([
27
+ // LOG with css formatting specifiers: %c
22
28
  t.stringLiteral(
23
- `${chalk.magenta("LOG")} ${chalk.blueBright(`${finalPath} - http://localhost:${port}/__tsd/open-source?source=${encodeURIComponent(finalPath)}`)}
29
+ `%c${"LOG"}%c %c${`Go to Source: http://localhost:${port}/__tsd/open-source?source=${encodeURIComponent(finalPath)}`}%c
24
30
  → `
31
+ ),
32
+ // magenta
33
+ t.stringLiteral("color:#A0A"),
34
+ t.stringLiteral("color:#FFF"),
35
+ // blueBright
36
+ t.stringLiteral("color:#55F"),
37
+ t.stringLiteral("color:#FFF")
38
+ ]);
39
+ const checkServerCondition = t.binaryExpression(
40
+ "===",
41
+ t.unaryExpression("typeof", t.identifier("window")),
42
+ t.stringLiteral("undefined")
43
+ );
44
+ path.node.arguments.unshift(
45
+ t.spreadElement(
46
+ t.conditionalExpression(
47
+ checkServerCondition,
48
+ serverLogMessage,
49
+ browserLogMessage
50
+ )
25
51
  )
26
52
  );
27
53
  didTransform = true;
@@ -1 +1 @@
1
- {"version":3,"file":"enhance-logs.js","sources":["../../src/enhance-logs.ts"],"sourcesContent":["import chalk from 'chalk'\nimport { normalizePath } from 'vite'\nimport { gen, parse, t, trav } from './babel'\nimport type { types as Babel } from '@babel/core'\nimport type { ParseResult } from '@babel/parser'\n\nconst transform = (\n ast: ParseResult<Babel.File>,\n filePath: string,\n port: number,\n) => {\n let didTransform = false\n\n trav(ast, {\n CallExpression(path) {\n const callee = path.node.callee\n // Match console.log(...) or console.error(...)\n if (\n callee.type === 'MemberExpression' &&\n callee.object.type === 'Identifier' &&\n callee.object.name === 'console' &&\n callee.property.type === 'Identifier' &&\n (callee.property.name === 'log' || callee.property.name === 'error')\n ) {\n const location = path.node.loc\n if (!location) {\n return\n }\n const [lineNumber, column] = [\n location.start.line,\n location.start.column,\n ]\n const finalPath = `${filePath}:${lineNumber}:${column + 1}`\n path.node.arguments.unshift(\n t.stringLiteral(\n `${chalk.magenta('LOG')} ${chalk.blueBright(`${finalPath} - http://localhost:${port}/__tsd/open-source?source=${encodeURIComponent(finalPath)}`)}\\n → `,\n ),\n )\n didTransform = true\n }\n },\n })\n\n return didTransform\n}\n\nexport function enhanceConsoleLog(code: string, id: string, port: number) {\n const [filePath] = id.split('?')\n // eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain\n const location = filePath?.replace(normalizePath(process.cwd()), '')!\n\n try {\n const ast = parse(code, {\n sourceType: 'module',\n plugins: ['jsx', 'typescript'],\n })\n const didTransform = transform(ast, location, port)\n if (!didTransform) {\n return\n }\n return gen(ast, {\n sourceMaps: true,\n retainLines: true,\n filename: id,\n sourceFileName: filePath,\n })\n } catch (e) {\n return\n }\n}\n"],"names":[],"mappings":";;;;;AAMA,MAAM,YAAY,CAChB,KACA,UACA,SACG;AACH,MAAI,eAAe;AAEnB,OAAK,KAAK;AAAA,IACR,eAAe,MAAM;AACnB,YAAM,SAAS,KAAK,KAAK;AAEzB,UACE,OAAO,SAAS,sBAChB,OAAO,OAAO,SAAS,gBACvB,OAAO,OAAO,SAAS,aACvB,OAAO,SAAS,SAAS,iBACxB,OAAO,SAAS,SAAS,SAAS,OAAO,SAAS,SAAS,UAC5D;AACA,cAAM,WAAW,KAAK,KAAK;AAC3B,YAAI,CAAC,UAAU;AACb;AAAA,QACF;AACA,cAAM,CAAC,YAAY,MAAM,IAAI;AAAA,UAC3B,SAAS,MAAM;AAAA,UACf,SAAS,MAAM;AAAA,QAAA;AAEjB,cAAM,YAAY,GAAG,QAAQ,IAAI,UAAU,IAAI,SAAS,CAAC;AACzD,aAAK,KAAK,UAAU;AAAA,UAClB,EAAE;AAAA,YACA,GAAG,MAAM,QAAQ,KAAK,CAAC,IAAI,MAAM,WAAW,GAAG,SAAS,uBAAuB,IAAI,6BAA6B,mBAAmB,SAAS,CAAC,EAAE,CAAC;AAAA;AAAA,UAAA;AAAA,QAClJ;AAEF,uBAAe;AAAA,MACjB;AAAA,IACF;AAAA,EAAA,CACD;AAED,SAAO;AACT;AAEO,SAAS,kBAAkB,MAAc,IAAY,MAAc;AACxE,QAAM,CAAC,QAAQ,IAAI,GAAG,MAAM,GAAG;AAE/B,QAAM,WAAW,UAAU,QAAQ,cAAc,QAAQ,IAAA,CAAK,GAAG,EAAE;AAEnE,MAAI;AACF,UAAM,MAAM,MAAM,MAAM;AAAA,MACtB,YAAY;AAAA,MACZ,SAAS,CAAC,OAAO,YAAY;AAAA,IAAA,CAC9B;AACD,UAAM,eAAe,UAAU,KAAK,UAAU,IAAI;AAClD,QAAI,CAAC,cAAc;AACjB;AAAA,IACF;AACA,WAAO,IAAI,KAAK;AAAA,MACd,YAAY;AAAA,MACZ,aAAa;AAAA,MACb,UAAU;AAAA,MACV,gBAAgB;AAAA,IAAA,CACjB;AAAA,EACH,SAAS,GAAG;AACV;AAAA,EACF;AACF;"}
1
+ {"version":3,"file":"enhance-logs.js","sources":["../../src/enhance-logs.ts"],"sourcesContent":["import chalk from 'chalk'\nimport { normalizePath } from 'vite'\nimport { gen, parse, t, trav } from './babel'\nimport type { types as Babel } from '@babel/core'\nimport type { ParseResult } from '@babel/parser'\n\nconst transform = (\n ast: ParseResult<Babel.File>,\n filePath: string,\n port: number,\n) => {\n let didTransform = false\n\n trav(ast, {\n CallExpression(path) {\n const callee = path.node.callee\n // Match console.log(...) or console.error(...)\n if (\n callee.type === 'MemberExpression' &&\n callee.object.type === 'Identifier' &&\n callee.object.name === 'console' &&\n callee.property.type === 'Identifier' &&\n (callee.property.name === 'log' || callee.property.name === 'error')\n ) {\n const location = path.node.loc\n if (!location) {\n return\n }\n const [lineNumber, column] = [\n location.start.line,\n location.start.column,\n ]\n const finalPath = `${filePath}:${lineNumber}:${column + 1}`\n const logMessage = `${chalk.magenta('LOG')} ${chalk.blueBright(`${finalPath}`)}\\n `\n\n const serverLogMessage = t.arrayExpression([\n t.stringLiteral(logMessage),\n ])\n const browserLogMessage = t.arrayExpression([\n // LOG with css formatting specifiers: %c\n t.stringLiteral(\n `%c${'LOG'}%c %c${`Go to Source: http://localhost:${port}/__tsd/open-source?source=${encodeURIComponent(finalPath)}`}%c \\n → `,\n ),\n // magenta\n t.stringLiteral('color:#A0A'),\n t.stringLiteral('color:#FFF'),\n // blueBright\n t.stringLiteral('color:#55F'),\n t.stringLiteral('color:#FFF'),\n ])\n\n // typeof window === \"undefined\"\n const checkServerCondition = t.binaryExpression(\n '===',\n t.unaryExpression('typeof', t.identifier('window')),\n t.stringLiteral('undefined'),\n )\n\n // ...(isServer ? serverLogMessage : browserLogMessage)\n path.node.arguments.unshift(\n t.spreadElement(\n t.conditionalExpression(\n checkServerCondition,\n serverLogMessage,\n browserLogMessage,\n ),\n ),\n )\n\n didTransform = true\n }\n },\n })\n\n return didTransform\n}\n\nexport function enhanceConsoleLog(code: string, id: string, port: number) {\n const [filePath] = id.split('?')\n // eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain\n const location = filePath?.replace(normalizePath(process.cwd()), '')!\n\n try {\n const ast = parse(code, {\n sourceType: 'module',\n plugins: ['jsx', 'typescript'],\n })\n const didTransform = transform(ast, location, port)\n if (!didTransform) {\n return\n }\n return gen(ast, {\n sourceMaps: true,\n retainLines: true,\n filename: id,\n sourceFileName: filePath,\n })\n } catch (e) {\n return\n }\n}\n"],"names":[],"mappings":";;;;;AAMA,MAAM,YAAY,CAChB,KACA,UACA,SACG;AACH,MAAI,eAAe;AAEnB,OAAK,KAAK;AAAA,IACR,eAAe,MAAM;AACnB,YAAM,SAAS,KAAK,KAAK;AAEzB,UACE,OAAO,SAAS,sBAChB,OAAO,OAAO,SAAS,gBACvB,OAAO,OAAO,SAAS,aACvB,OAAO,SAAS,SAAS,iBACxB,OAAO,SAAS,SAAS,SAAS,OAAO,SAAS,SAAS,UAC5D;AACA,cAAM,WAAW,KAAK,KAAK;AAC3B,YAAI,CAAC,UAAU;AACb;AAAA,QACF;AACA,cAAM,CAAC,YAAY,MAAM,IAAI;AAAA,UAC3B,SAAS,MAAM;AAAA,UACf,SAAS,MAAM;AAAA,QAAA;AAEjB,cAAM,YAAY,GAAG,QAAQ,IAAI,UAAU,IAAI,SAAS,CAAC;AACzD,cAAM,aAAa,GAAG,MAAM,QAAQ,KAAK,CAAC,IAAI,MAAM,WAAW,GAAG,SAAS,EAAE,CAAC;AAAA;AAE9E,cAAM,mBAAmB,EAAE,gBAAgB;AAAA,UACzC,EAAE,cAAc,UAAU;AAAA,QAAA,CAC3B;AACD,cAAM,oBAAoB,EAAE,gBAAgB;AAAA;AAAA,UAE1C,EAAE;AAAA,YACA,KAAK,KAAK,QAAQ,kCAAkC,IAAI,6BAA6B,mBAAmB,SAAS,CAAC,EAAE;AAAA;AAAA,UAAA;AAAA;AAAA,UAGtH,EAAE,cAAc,YAAY;AAAA,UAC5B,EAAE,cAAc,YAAY;AAAA;AAAA,UAE5B,EAAE,cAAc,YAAY;AAAA,UAC5B,EAAE,cAAc,YAAY;AAAA,QAAA,CAC7B;AAGD,cAAM,uBAAuB,EAAE;AAAA,UAC7B;AAAA,UACA,EAAE,gBAAgB,UAAU,EAAE,WAAW,QAAQ,CAAC;AAAA,UAClD,EAAE,cAAc,WAAW;AAAA,QAAA;AAI7B,aAAK,KAAK,UAAU;AAAA,UAClB,EAAE;AAAA,YACA,EAAE;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,YAAA;AAAA,UACF;AAAA,QACF;AAGF,uBAAe;AAAA,MACjB;AAAA,IACF;AAAA,EAAA,CACD;AAED,SAAO;AACT;AAEO,SAAS,kBAAkB,MAAc,IAAY,MAAc;AACxE,QAAM,CAAC,QAAQ,IAAI,GAAG,MAAM,GAAG;AAE/B,QAAM,WAAW,UAAU,QAAQ,cAAc,QAAQ,IAAA,CAAK,GAAG,EAAE;AAEnE,MAAI;AACF,UAAM,MAAM,MAAM,MAAM;AAAA,MACtB,YAAY;AAAA,MACZ,SAAS,CAAC,OAAO,YAAY;AAAA,IAAA,CAC9B;AACD,UAAM,eAAe,UAAU,KAAK,UAAU,IAAI;AAClD,QAAI,CAAC,cAAc;AACjB;AAAA,IACF;AACA,WAAO,IAAI,KAAK;AAAA,MACd,YAAY;AAAA,MACZ,aAAa;AAAA,MACb,UAAU;AAAA,MACV,gBAAgB;AAAA,IAAA,CACjB;AAAA,EACH,SAAS,GAAG;AACV;AAAA,EACF;AACF;"}
@@ -96,7 +96,15 @@ const devtools = (args) => {
96
96
  },
97
97
  enforce: "pre",
98
98
  transform(code, id) {
99
- if (id.includes("node_modules") || id.includes("?raw")) return;
99
+ const devtoolPackages = [
100
+ "@tanstack/react-devtools",
101
+ "@tanstack/preact-devtools",
102
+ "@tanstack/solid-devtools",
103
+ "@tanstack/vue-devtools",
104
+ "@tanstack/devtools"
105
+ ];
106
+ if (id.includes("node_modules") || id.includes("?raw") || !devtoolPackages.some((pkg) => code.includes(pkg)))
107
+ return;
100
108
  const transform = removeDevtools(code, id);
101
109
  if (!transform) return;
102
110
  if (logging) {
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sources":["../../src/plugin.ts"],"sourcesContent":["import { devtoolsEventClient } from '@tanstack/devtools-client'\nimport { ServerEventBus } from '@tanstack/devtools-event-bus/server'\nimport { normalizePath } from 'vite'\nimport chalk from 'chalk'\nimport { handleDevToolsViteRequest, readPackageJson } from './utils'\nimport { DEFAULT_EDITOR_CONFIG, handleOpenSource } from './editor'\nimport { removeDevtools } from './remove-devtools'\nimport { addSourceToJsx } from './inject-source'\nimport { enhanceConsoleLog } from './enhance-logs'\nimport { detectDevtoolsFile, injectPluginIntoFile } from './inject-plugin'\nimport {\n addPluginToDevtools,\n emitOutdatedDeps,\n installPackage,\n} from './package-manager'\nimport type { Plugin } from 'vite'\nimport type { EditorConfig } from './editor'\nimport type { ServerEventBusConfig } from '@tanstack/devtools-event-bus/server'\n\nexport type TanStackDevtoolsViteConfig = {\n /**\n * Configuration for the editor integration. Defaults to opening in VS code\n */\n editor?: EditorConfig\n /**\n * The configuration options for the server event bus\n */\n eventBusConfig?: ServerEventBusConfig & {\n /**\n * Should the server event bus be enabled or not\n * @default true\n */\n enabled?: boolean // defaults to true\n }\n /**\n * Configuration for enhanced logging.\n */\n enhancedLogs?: {\n /**\n * Whether to enable enhanced logging.\n * @default true\n */\n enabled: boolean\n }\n /**\n * Whether to remove devtools from the production build.\n * @default true\n */\n removeDevtoolsOnBuild?: boolean\n\n /**\n * Whether to log information to the console.\n * @default true\n */\n logging?: boolean\n /**\n * Configuration for source injection.\n */\n injectSource?: {\n /**\n * Whether to enable source injection via data-tsd-source.\n * @default true\n */\n enabled: boolean\n /**\n * List of files or patterns to ignore for source injection.\n */\n ignore?: {\n files?: Array<string | RegExp>\n components?: Array<string | RegExp>\n }\n }\n}\n\nexport const defineDevtoolsConfig = (config: TanStackDevtoolsViteConfig) =>\n config\n\nexport const devtools = (args?: TanStackDevtoolsViteConfig): Array<Plugin> => {\n let port = 5173\n const logging = args?.logging ?? true\n const enhancedLogsConfig = args?.enhancedLogs ?? { enabled: true }\n const injectSourceConfig = args?.injectSource ?? { enabled: true }\n const removeDevtoolsOnBuild = args?.removeDevtoolsOnBuild ?? true\n const serverBusEnabled = args?.eventBusConfig?.enabled ?? true\n\n let devtoolsFileId: string | null = null\n let devtoolsPort: number | null = null\n\n return [\n {\n enforce: 'pre',\n name: '@tanstack/devtools:inject-source',\n apply(config) {\n return config.mode === 'development' && injectSourceConfig.enabled\n },\n transform(code, id) {\n if (\n id.includes('node_modules') ||\n id.includes('?raw') ||\n id.includes('dist') ||\n id.includes('build')\n )\n return\n\n return addSourceToJsx(code, id, args?.injectSource?.ignore)\n },\n },\n {\n name: '@tanstack/devtools:config',\n enforce: 'pre',\n config(_, { command }) {\n // we do not apply any config changes for build\n if (command !== 'serve') {\n return\n }\n\n /* const solidDedupeDeps = [\n 'solid-js',\n 'solid-js/web',\n 'solid-js/store',\n 'solid-js/html',\n 'solid-js/h',\n ]\n\n return {\n resolve: {\n dedupe: solidDedupeDeps,\n },\n optimizeDeps: {\n include: solidDedupeDeps,\n },\n } */\n },\n },\n {\n enforce: 'pre',\n name: '@tanstack/devtools:custom-server',\n apply(config) {\n // Custom server is only needed in development for piping events to the client\n return config.mode === 'development'\n },\n async configureServer(server) {\n if (serverBusEnabled) {\n const preferredPort = args?.eventBusConfig?.port ?? 4206\n const bus = new ServerEventBus({\n ...args?.eventBusConfig,\n port: preferredPort,\n })\n // start() now handles EADDRINUSE and returns the actual port\n devtoolsPort = await bus.start()\n }\n\n server.middlewares.use((req, _res, next) => {\n if (req.socket.localPort && req.socket.localPort !== port) {\n port = req.socket.localPort\n }\n next()\n })\n if (server.config.server.port) {\n port = server.config.server.port\n }\n\n server.httpServer?.on('listening', () => {\n port = server.config.server.port\n })\n\n const editor = args?.editor ?? DEFAULT_EDITOR_CONFIG\n const openInEditor: EditorConfig['open'] = async (\n path,\n lineNum,\n columnNum,\n ) => {\n if (!path) {\n return\n }\n await editor.open(path, lineNum, columnNum)\n }\n server.middlewares.use((req, res, next) =>\n handleDevToolsViteRequest(req, res, next, (parsedData) => {\n const { data, routine } = parsedData\n if (routine === 'open-source') {\n return handleOpenSource({\n data: { type: data.type, data },\n openInEditor,\n })\n }\n return\n }),\n )\n },\n },\n {\n name: '@tanstack/devtools:remove-devtools-on-build',\n apply(config, { command }) {\n // Check both command and mode to support various hosting providers\n // Some providers (Cloudflare, Netlify, Heroku) might not use 'build' command\n // but will always set mode to 'production' for production builds\n return (\n (command !== 'serve' || config.mode === 'production') &&\n removeDevtoolsOnBuild\n )\n },\n enforce: 'pre',\n transform(code, id) {\n if (id.includes('node_modules') || id.includes('?raw')) return\n const transform = removeDevtools(code, id)\n if (!transform) return\n if (logging) {\n console.log(\n `\\n${chalk.greenBright(`[@tanstack/devtools-vite]`)} Removed devtools code from: ${id.replace(normalizePath(process.cwd()), '')}\\n`,\n )\n }\n return transform\n },\n },\n {\n name: '@tanstack/devtools:event-client-setup',\n apply(config, { command }) {\n if (\n process.env.CI ||\n process.env.NODE_ENV !== 'development' ||\n command !== 'serve'\n )\n return false\n return config.mode === 'development'\n },\n async configureServer() {\n const packageJson = await readPackageJson()\n const outdatedDeps = emitOutdatedDeps().then((deps) => deps)\n\n // Listen for package installation requests\n devtoolsEventClient.on('install-devtools', async (event) => {\n const result = await installPackage(event.payload.packageName)\n devtoolsEventClient.emit('devtools-installed', {\n packageName: event.payload.packageName,\n success: result.success,\n error: result.error,\n })\n\n // If installation was successful, automatically add the plugin to devtools\n if (result.success) {\n const { packageName, pluginName, pluginImport } = event.payload\n\n console.log(\n chalk.blueBright(\n `[@tanstack/devtools-vite] Auto-adding ${packageName} to devtools...`,\n ),\n )\n\n const injectResult = addPluginToDevtools(\n devtoolsFileId,\n packageName,\n pluginName,\n pluginImport,\n )\n\n if (injectResult.success) {\n // Emit plugin-added event so the UI updates\n devtoolsEventClient.emit('plugin-added', {\n packageName,\n success: true,\n })\n\n // Also re-read package.json to update the UI with the newly installed package\n const updatedPackageJson = await readPackageJson()\n devtoolsEventClient.emit('package-json-read', {\n packageJson: updatedPackageJson,\n })\n }\n }\n })\n\n // Listen for add plugin to devtools requests\n devtoolsEventClient.on('add-plugin-to-devtools', (event) => {\n const { packageName, pluginName, pluginImport } = event.payload\n\n console.log(\n chalk.blueBright(\n `[@tanstack/devtools-vite] Adding ${packageName} to devtools...`,\n ),\n )\n\n const result = addPluginToDevtools(\n devtoolsFileId,\n packageName,\n pluginName,\n pluginImport,\n )\n\n devtoolsEventClient.emit('plugin-added', {\n packageName,\n success: result.success,\n error: result.error,\n })\n })\n\n // Handle bump-package-version event\n devtoolsEventClient.on('bump-package-version', async (event) => {\n const {\n packageName,\n devtoolsPackage,\n pluginName,\n minVersion,\n pluginImport,\n } = event.payload\n\n console.log(\n chalk.blueBright(\n `[@tanstack/devtools-vite] Bumping ${packageName} to version ${minVersion}...`,\n ),\n )\n\n // Install the package with the minimum version\n const packageWithVersion = minVersion\n ? `${packageName}@^${minVersion}`\n : packageName\n\n const result = await installPackage(packageWithVersion)\n\n if (!result.success) {\n console.log(\n chalk.redBright(\n `[@tanstack/devtools-vite] Failed to bump ${packageName}: ${result.error}`,\n ),\n )\n devtoolsEventClient.emit('devtools-installed', {\n packageName: devtoolsPackage,\n success: false,\n error: result.error,\n })\n return\n }\n\n console.log(\n chalk.greenBright(\n `[@tanstack/devtools-vite] Successfully bumped ${packageName} to ${minVersion}!`,\n ),\n )\n\n // Check if we found the devtools file\n if (!devtoolsFileId) {\n console.log(\n chalk.yellowBright(\n `[@tanstack/devtools-vite] Devtools file not found. Skipping auto-injection.`,\n ),\n )\n devtoolsEventClient.emit('devtools-installed', {\n packageName: devtoolsPackage,\n success: true,\n })\n return\n }\n\n // Now inject the devtools plugin\n console.log(\n chalk.blueBright(\n `[@tanstack/devtools-vite] Adding ${devtoolsPackage} to devtools...`,\n ),\n )\n\n const injectResult = injectPluginIntoFile(devtoolsFileId, {\n packageName: devtoolsPackage,\n pluginName,\n pluginImport,\n })\n\n if (injectResult.success) {\n console.log(\n chalk.greenBright(\n `[@tanstack/devtools-vite] Successfully added ${devtoolsPackage} to devtools!`,\n ),\n )\n\n devtoolsEventClient.emit('plugin-added', {\n packageName: devtoolsPackage,\n success: true,\n })\n\n // Re-read package.json to update the UI\n const updatedPackageJson = await readPackageJson()\n devtoolsEventClient.emit('package-json-read', {\n packageJson: updatedPackageJson,\n })\n } else {\n console.log(\n chalk.redBright(\n `[@tanstack/devtools-vite] Failed to add ${devtoolsPackage} to devtools: ${injectResult.error}`,\n ),\n )\n\n devtoolsEventClient.emit('plugin-added', {\n packageName: devtoolsPackage,\n success: false,\n error: injectResult.error,\n })\n }\n })\n\n // whenever a client mounts we send all the current info to the subscribers\n devtoolsEventClient.on('mounted', async () => {\n devtoolsEventClient.emit('outdated-deps-read', {\n outdatedDeps: await outdatedDeps,\n })\n devtoolsEventClient.emit('package-json-read', {\n packageJson,\n })\n })\n },\n async handleHotUpdate({ file }) {\n if (file.endsWith('package.json')) {\n const newPackageJson = await readPackageJson()\n devtoolsEventClient.emit('package-json-read', {\n packageJson: newPackageJson,\n })\n emitOutdatedDeps()\n }\n },\n },\n {\n name: '@tanstack/devtools:better-console-logs',\n enforce: 'pre',\n apply(config) {\n return config.mode === 'development' && enhancedLogsConfig.enabled\n },\n transform(code, id) {\n // Ignore anything external\n if (\n id.includes('node_modules') ||\n id.includes('?raw') ||\n id.includes('dist') ||\n id.includes('build') ||\n !code.includes('console.')\n )\n return\n\n return enhanceConsoleLog(code, id, port)\n },\n },\n {\n name: '@tanstack/devtools:inject-plugin',\n apply(config, { command }) {\n return config.mode === 'development' && command === 'serve'\n },\n transform(code, id) {\n // First pass: find where TanStackDevtools is imported\n if (!devtoolsFileId && detectDevtoolsFile(code)) {\n // Extract actual file path (remove query params)\n const [filePath] = id.split('?')\n if (filePath) {\n devtoolsFileId = filePath\n }\n }\n\n return undefined\n },\n },\n {\n name: '@tanstack/devtools:port-injection',\n apply(config, { command }) {\n return config.mode === 'development' && command === 'serve'\n },\n transform(code, id) {\n // Only transform @tanstack packages that contain the port placeholder\n if (!code.includes('__TANSTACK_DEVTOOLS_PORT__')) return\n if (\n !id.includes('@tanstack/devtools') &&\n !id.includes('@tanstack/event-bus')\n )\n return\n\n // Replace placeholder with actual port (or fallback to 4206 if not resolved yet)\n const portValue = devtoolsPort ?? 4206\n return code.replace(/__TANSTACK_DEVTOOLS_PORT__/g, String(portValue))\n },\n },\n ]\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"plugin.js","sources":["../../src/plugin.ts"],"sourcesContent":["import { devtoolsEventClient } from '@tanstack/devtools-client'\nimport { ServerEventBus } from '@tanstack/devtools-event-bus/server'\nimport { normalizePath } from 'vite'\nimport chalk from 'chalk'\nimport { handleDevToolsViteRequest, readPackageJson } from './utils'\nimport { DEFAULT_EDITOR_CONFIG, handleOpenSource } from './editor'\nimport { removeDevtools } from './remove-devtools'\nimport { addSourceToJsx } from './inject-source'\nimport { enhanceConsoleLog } from './enhance-logs'\nimport { detectDevtoolsFile, injectPluginIntoFile } from './inject-plugin'\nimport {\n addPluginToDevtools,\n emitOutdatedDeps,\n installPackage,\n} from './package-manager'\nimport type { Plugin } from 'vite'\nimport type { EditorConfig } from './editor'\nimport type { ServerEventBusConfig } from '@tanstack/devtools-event-bus/server'\n\nexport type TanStackDevtoolsViteConfig = {\n /**\n * Configuration for the editor integration. Defaults to opening in VS code\n */\n editor?: EditorConfig\n /**\n * The configuration options for the server event bus\n */\n eventBusConfig?: ServerEventBusConfig & {\n /**\n * Should the server event bus be enabled or not\n * @default true\n */\n enabled?: boolean // defaults to true\n }\n /**\n * Configuration for enhanced logging.\n */\n enhancedLogs?: {\n /**\n * Whether to enable enhanced logging.\n * @default true\n */\n enabled: boolean\n }\n /**\n * Whether to remove devtools from the production build.\n * @default true\n */\n removeDevtoolsOnBuild?: boolean\n\n /**\n * Whether to log information to the console.\n * @default true\n */\n logging?: boolean\n /**\n * Configuration for source injection.\n */\n injectSource?: {\n /**\n * Whether to enable source injection via data-tsd-source.\n * @default true\n */\n enabled: boolean\n /**\n * List of files or patterns to ignore for source injection.\n */\n ignore?: {\n files?: Array<string | RegExp>\n components?: Array<string | RegExp>\n }\n }\n}\n\nexport const defineDevtoolsConfig = (config: TanStackDevtoolsViteConfig) =>\n config\n\nexport const devtools = (args?: TanStackDevtoolsViteConfig): Array<Plugin> => {\n let port = 5173\n const logging = args?.logging ?? true\n const enhancedLogsConfig = args?.enhancedLogs ?? { enabled: true }\n const injectSourceConfig = args?.injectSource ?? { enabled: true }\n const removeDevtoolsOnBuild = args?.removeDevtoolsOnBuild ?? true\n const serverBusEnabled = args?.eventBusConfig?.enabled ?? true\n\n let devtoolsFileId: string | null = null\n let devtoolsPort: number | null = null\n\n return [\n {\n enforce: 'pre',\n name: '@tanstack/devtools:inject-source',\n apply(config) {\n return config.mode === 'development' && injectSourceConfig.enabled\n },\n transform(code, id) {\n if (\n id.includes('node_modules') ||\n id.includes('?raw') ||\n id.includes('dist') ||\n id.includes('build')\n )\n return\n\n return addSourceToJsx(code, id, args?.injectSource?.ignore)\n },\n },\n {\n name: '@tanstack/devtools:config',\n enforce: 'pre',\n config(_, { command }) {\n // we do not apply any config changes for build\n if (command !== 'serve') {\n return\n }\n\n /* const solidDedupeDeps = [\n 'solid-js',\n 'solid-js/web',\n 'solid-js/store',\n 'solid-js/html',\n 'solid-js/h',\n ]\n\n return {\n resolve: {\n dedupe: solidDedupeDeps,\n },\n optimizeDeps: {\n include: solidDedupeDeps,\n },\n } */\n },\n },\n {\n enforce: 'pre',\n name: '@tanstack/devtools:custom-server',\n apply(config) {\n // Custom server is only needed in development for piping events to the client\n return config.mode === 'development'\n },\n async configureServer(server) {\n if (serverBusEnabled) {\n const preferredPort = args?.eventBusConfig?.port ?? 4206\n const bus = new ServerEventBus({\n ...args?.eventBusConfig,\n port: preferredPort,\n })\n // start() now handles EADDRINUSE and returns the actual port\n devtoolsPort = await bus.start()\n }\n\n server.middlewares.use((req, _res, next) => {\n if (req.socket.localPort && req.socket.localPort !== port) {\n port = req.socket.localPort\n }\n next()\n })\n if (server.config.server.port) {\n port = server.config.server.port\n }\n\n server.httpServer?.on('listening', () => {\n port = server.config.server.port\n })\n\n const editor = args?.editor ?? DEFAULT_EDITOR_CONFIG\n const openInEditor: EditorConfig['open'] = async (\n path,\n lineNum,\n columnNum,\n ) => {\n if (!path) {\n return\n }\n await editor.open(path, lineNum, columnNum)\n }\n server.middlewares.use((req, res, next) =>\n handleDevToolsViteRequest(req, res, next, (parsedData) => {\n const { data, routine } = parsedData\n if (routine === 'open-source') {\n return handleOpenSource({\n data: { type: data.type, data },\n openInEditor,\n })\n }\n return\n }),\n )\n },\n },\n {\n name: '@tanstack/devtools:remove-devtools-on-build',\n apply(config, { command }) {\n // Check both command and mode to support various hosting providers\n // Some providers (Cloudflare, Netlify, Heroku) might not use 'build' command\n // but will always set mode to 'production' for production builds\n return (\n (command !== 'serve' || config.mode === 'production') &&\n removeDevtoolsOnBuild\n )\n },\n enforce: 'pre',\n transform(code, id) {\n const devtoolPackages = [\n '@tanstack/react-devtools',\n '@tanstack/preact-devtools',\n '@tanstack/solid-devtools',\n '@tanstack/vue-devtools',\n '@tanstack/devtools',\n ]\n if (\n id.includes('node_modules') ||\n id.includes('?raw') ||\n !devtoolPackages.some((pkg) => code.includes(pkg))\n )\n return\n const transform = removeDevtools(code, id)\n if (!transform) return\n if (logging) {\n console.log(\n `\\n${chalk.greenBright(`[@tanstack/devtools-vite]`)} Removed devtools code from: ${id.replace(normalizePath(process.cwd()), '')}\\n`,\n )\n }\n return transform\n },\n },\n {\n name: '@tanstack/devtools:event-client-setup',\n apply(config, { command }) {\n if (\n process.env.CI ||\n process.env.NODE_ENV !== 'development' ||\n command !== 'serve'\n )\n return false\n return config.mode === 'development'\n },\n async configureServer() {\n const packageJson = await readPackageJson()\n const outdatedDeps = emitOutdatedDeps().then((deps) => deps)\n\n // Listen for package installation requests\n devtoolsEventClient.on('install-devtools', async (event) => {\n const result = await installPackage(event.payload.packageName)\n devtoolsEventClient.emit('devtools-installed', {\n packageName: event.payload.packageName,\n success: result.success,\n error: result.error,\n })\n\n // If installation was successful, automatically add the plugin to devtools\n if (result.success) {\n const { packageName, pluginName, pluginImport } = event.payload\n\n console.log(\n chalk.blueBright(\n `[@tanstack/devtools-vite] Auto-adding ${packageName} to devtools...`,\n ),\n )\n\n const injectResult = addPluginToDevtools(\n devtoolsFileId,\n packageName,\n pluginName,\n pluginImport,\n )\n\n if (injectResult.success) {\n // Emit plugin-added event so the UI updates\n devtoolsEventClient.emit('plugin-added', {\n packageName,\n success: true,\n })\n\n // Also re-read package.json to update the UI with the newly installed package\n const updatedPackageJson = await readPackageJson()\n devtoolsEventClient.emit('package-json-read', {\n packageJson: updatedPackageJson,\n })\n }\n }\n })\n\n // Listen for add plugin to devtools requests\n devtoolsEventClient.on('add-plugin-to-devtools', (event) => {\n const { packageName, pluginName, pluginImport } = event.payload\n\n console.log(\n chalk.blueBright(\n `[@tanstack/devtools-vite] Adding ${packageName} to devtools...`,\n ),\n )\n\n const result = addPluginToDevtools(\n devtoolsFileId,\n packageName,\n pluginName,\n pluginImport,\n )\n\n devtoolsEventClient.emit('plugin-added', {\n packageName,\n success: result.success,\n error: result.error,\n })\n })\n\n // Handle bump-package-version event\n devtoolsEventClient.on('bump-package-version', async (event) => {\n const {\n packageName,\n devtoolsPackage,\n pluginName,\n minVersion,\n pluginImport,\n } = event.payload\n\n console.log(\n chalk.blueBright(\n `[@tanstack/devtools-vite] Bumping ${packageName} to version ${minVersion}...`,\n ),\n )\n\n // Install the package with the minimum version\n const packageWithVersion = minVersion\n ? `${packageName}@^${minVersion}`\n : packageName\n\n const result = await installPackage(packageWithVersion)\n\n if (!result.success) {\n console.log(\n chalk.redBright(\n `[@tanstack/devtools-vite] Failed to bump ${packageName}: ${result.error}`,\n ),\n )\n devtoolsEventClient.emit('devtools-installed', {\n packageName: devtoolsPackage,\n success: false,\n error: result.error,\n })\n return\n }\n\n console.log(\n chalk.greenBright(\n `[@tanstack/devtools-vite] Successfully bumped ${packageName} to ${minVersion}!`,\n ),\n )\n\n // Check if we found the devtools file\n if (!devtoolsFileId) {\n console.log(\n chalk.yellowBright(\n `[@tanstack/devtools-vite] Devtools file not found. Skipping auto-injection.`,\n ),\n )\n devtoolsEventClient.emit('devtools-installed', {\n packageName: devtoolsPackage,\n success: true,\n })\n return\n }\n\n // Now inject the devtools plugin\n console.log(\n chalk.blueBright(\n `[@tanstack/devtools-vite] Adding ${devtoolsPackage} to devtools...`,\n ),\n )\n\n const injectResult = injectPluginIntoFile(devtoolsFileId, {\n packageName: devtoolsPackage,\n pluginName,\n pluginImport,\n })\n\n if (injectResult.success) {\n console.log(\n chalk.greenBright(\n `[@tanstack/devtools-vite] Successfully added ${devtoolsPackage} to devtools!`,\n ),\n )\n\n devtoolsEventClient.emit('plugin-added', {\n packageName: devtoolsPackage,\n success: true,\n })\n\n // Re-read package.json to update the UI\n const updatedPackageJson = await readPackageJson()\n devtoolsEventClient.emit('package-json-read', {\n packageJson: updatedPackageJson,\n })\n } else {\n console.log(\n chalk.redBright(\n `[@tanstack/devtools-vite] Failed to add ${devtoolsPackage} to devtools: ${injectResult.error}`,\n ),\n )\n\n devtoolsEventClient.emit('plugin-added', {\n packageName: devtoolsPackage,\n success: false,\n error: injectResult.error,\n })\n }\n })\n\n // whenever a client mounts we send all the current info to the subscribers\n devtoolsEventClient.on('mounted', async () => {\n devtoolsEventClient.emit('outdated-deps-read', {\n outdatedDeps: await outdatedDeps,\n })\n devtoolsEventClient.emit('package-json-read', {\n packageJson,\n })\n })\n },\n async handleHotUpdate({ file }) {\n if (file.endsWith('package.json')) {\n const newPackageJson = await readPackageJson()\n devtoolsEventClient.emit('package-json-read', {\n packageJson: newPackageJson,\n })\n emitOutdatedDeps()\n }\n },\n },\n {\n name: '@tanstack/devtools:better-console-logs',\n enforce: 'pre',\n apply(config) {\n return config.mode === 'development' && enhancedLogsConfig.enabled\n },\n transform(code, id) {\n // Ignore anything external\n if (\n id.includes('node_modules') ||\n id.includes('?raw') ||\n id.includes('dist') ||\n id.includes('build') ||\n !code.includes('console.')\n )\n return\n\n return enhanceConsoleLog(code, id, port)\n },\n },\n {\n name: '@tanstack/devtools:inject-plugin',\n apply(config, { command }) {\n return config.mode === 'development' && command === 'serve'\n },\n transform(code, id) {\n // First pass: find where TanStackDevtools is imported\n if (!devtoolsFileId && detectDevtoolsFile(code)) {\n // Extract actual file path (remove query params)\n const [filePath] = id.split('?')\n if (filePath) {\n devtoolsFileId = filePath\n }\n }\n\n return undefined\n },\n },\n {\n name: '@tanstack/devtools:port-injection',\n apply(config, { command }) {\n return config.mode === 'development' && command === 'serve'\n },\n transform(code, id) {\n // Only transform @tanstack packages that contain the port placeholder\n if (!code.includes('__TANSTACK_DEVTOOLS_PORT__')) return\n if (\n !id.includes('@tanstack/devtools') &&\n !id.includes('@tanstack/event-bus')\n )\n return\n\n // Replace placeholder with actual port (or fallback to 4206 if not resolved yet)\n const portValue = devtoolsPort ?? 4206\n return code.replace(/__TANSTACK_DEVTOOLS_PORT__/g, String(portValue))\n },\n },\n ]\n}\n"],"names":[],"mappings":";;;;;;;;;;;AA0EO,MAAM,uBAAuB,CAAC,WACnC;AAEK,MAAM,WAAW,CAAC,SAAqD;AAC5E,MAAI,OAAO;AACX,QAAM,UAAU,MAAM,WAAW;AACjC,QAAM,qBAAqB,MAAM,gBAAgB,EAAE,SAAS,KAAA;AAC5D,QAAM,qBAAqB,MAAM,gBAAgB,EAAE,SAAS,KAAA;AAC5D,QAAM,wBAAwB,MAAM,yBAAyB;AAC7D,QAAM,mBAAmB,MAAM,gBAAgB,WAAW;AAE1D,MAAI,iBAAgC;AACpC,MAAI,eAA8B;AAElC,SAAO;AAAA,IACL;AAAA,MACE,SAAS;AAAA,MACT,MAAM;AAAA,MACN,MAAM,QAAQ;AACZ,eAAO,OAAO,SAAS,iBAAiB,mBAAmB;AAAA,MAC7D;AAAA,MACA,UAAU,MAAM,IAAI;AAClB,YACE,GAAG,SAAS,cAAc,KAC1B,GAAG,SAAS,MAAM,KAClB,GAAG,SAAS,MAAM,KAClB,GAAG,SAAS,OAAO;AAEnB;AAEF,eAAO,eAAe,MAAM,IAAI,MAAM,cAAc,MAAM;AAAA,MAC5D;AAAA,IAAA;AAAA,IAEF;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,MACT,OAAO,GAAG,EAAE,WAAW;AAErB,YAAI,YAAY,SAAS;AACvB;AAAA,QACF;AAAA,MAkBF;AAAA,IAAA;AAAA,IAEF;AAAA,MACE,SAAS;AAAA,MACT,MAAM;AAAA,MACN,MAAM,QAAQ;AAEZ,eAAO,OAAO,SAAS;AAAA,MACzB;AAAA,MACA,MAAM,gBAAgB,QAAQ;AAC5B,YAAI,kBAAkB;AACpB,gBAAM,gBAAgB,MAAM,gBAAgB,QAAQ;AACpD,gBAAM,MAAM,IAAI,eAAe;AAAA,YAC7B,GAAG,MAAM;AAAA,YACT,MAAM;AAAA,UAAA,CACP;AAED,yBAAe,MAAM,IAAI,MAAA;AAAA,QAC3B;AAEA,eAAO,YAAY,IAAI,CAAC,KAAK,MAAM,SAAS;AAC1C,cAAI,IAAI,OAAO,aAAa,IAAI,OAAO,cAAc,MAAM;AACzD,mBAAO,IAAI,OAAO;AAAA,UACpB;AACA,eAAA;AAAA,QACF,CAAC;AACD,YAAI,OAAO,OAAO,OAAO,MAAM;AAC7B,iBAAO,OAAO,OAAO,OAAO;AAAA,QAC9B;AAEA,eAAO,YAAY,GAAG,aAAa,MAAM;AACvC,iBAAO,OAAO,OAAO,OAAO;AAAA,QAC9B,CAAC;AAED,cAAM,SAAS,MAAM,UAAU;AAC/B,cAAM,eAAqC,OACzC,MACA,SACA,cACG;AACH,cAAI,CAAC,MAAM;AACT;AAAA,UACF;AACA,gBAAM,OAAO,KAAK,MAAM,SAAS,SAAS;AAAA,QAC5C;AACA,eAAO,YAAY;AAAA,UAAI,CAAC,KAAK,KAAK,SAChC,0BAA0B,KAAK,KAAK,MAAM,CAAC,eAAe;AACxD,kBAAM,EAAE,MAAM,QAAA,IAAY;AAC1B,gBAAI,YAAY,eAAe;AAC7B,qBAAO,iBAAiB;AAAA,gBACtB,MAAM,EAAE,MAAM,KAAK,MAAM,KAAA;AAAA,gBACzB;AAAA,cAAA,CACD;AAAA,YACH;AACA;AAAA,UACF,CAAC;AAAA,QAAA;AAAA,MAEL;AAAA,IAAA;AAAA,IAEF;AAAA,MACE,MAAM;AAAA,MACN,MAAM,QAAQ,EAAE,WAAW;AAIzB,gBACG,YAAY,WAAW,OAAO,SAAS,iBACxC;AAAA,MAEJ;AAAA,MACA,SAAS;AAAA,MACT,UAAU,MAAM,IAAI;AAClB,cAAM,kBAAkB;AAAA,UACtB;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QAAA;AAEF,YACE,GAAG,SAAS,cAAc,KAC1B,GAAG,SAAS,MAAM,KAClB,CAAC,gBAAgB,KAAK,CAAC,QAAQ,KAAK,SAAS,GAAG,CAAC;AAEjD;AACF,cAAM,YAAY,eAAe,MAAM,EAAE;AACzC,YAAI,CAAC,UAAW;AAChB,YAAI,SAAS;AACX,kBAAQ;AAAA,YACN;AAAA,EAAK,MAAM,YAAY,2BAA2B,CAAC,gCAAgC,GAAG,QAAQ,cAAc,QAAQ,IAAA,CAAK,GAAG,EAAE,CAAC;AAAA;AAAA,UAAA;AAAA,QAEnI;AACA,eAAO;AAAA,MACT;AAAA,IAAA;AAAA,IAEF;AAAA,MACE,MAAM;AAAA,MACN,MAAM,QAAQ,EAAE,WAAW;AACzB,YACE,QAAQ,IAAI,MACZ,QAAQ,IAAI,aAAa,iBACzB,YAAY;AAEZ,iBAAO;AACT,eAAO,OAAO,SAAS;AAAA,MACzB;AAAA,MACA,MAAM,kBAAkB;AACtB,cAAM,cAAc,MAAM,gBAAA;AAC1B,cAAM,eAAe,iBAAA,EAAmB,KAAK,CAAC,SAAS,IAAI;AAG3D,4BAAoB,GAAG,oBAAoB,OAAO,UAAU;AAC1D,gBAAM,SAAS,MAAM,eAAe,MAAM,QAAQ,WAAW;AAC7D,8BAAoB,KAAK,sBAAsB;AAAA,YAC7C,aAAa,MAAM,QAAQ;AAAA,YAC3B,SAAS,OAAO;AAAA,YAChB,OAAO,OAAO;AAAA,UAAA,CACf;AAGD,cAAI,OAAO,SAAS;AAClB,kBAAM,EAAE,aAAa,YAAY,aAAA,IAAiB,MAAM;AAExD,oBAAQ;AAAA,cACN,MAAM;AAAA,gBACJ,yCAAyC,WAAW;AAAA,cAAA;AAAA,YACtD;AAGF,kBAAM,eAAe;AAAA,cACnB;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,YAAA;AAGF,gBAAI,aAAa,SAAS;AAExB,kCAAoB,KAAK,gBAAgB;AAAA,gBACvC;AAAA,gBACA,SAAS;AAAA,cAAA,CACV;AAGD,oBAAM,qBAAqB,MAAM,gBAAA;AACjC,kCAAoB,KAAK,qBAAqB;AAAA,gBAC5C,aAAa;AAAA,cAAA,CACd;AAAA,YACH;AAAA,UACF;AAAA,QACF,CAAC;AAGD,4BAAoB,GAAG,0BAA0B,CAAC,UAAU;AAC1D,gBAAM,EAAE,aAAa,YAAY,aAAA,IAAiB,MAAM;AAExD,kBAAQ;AAAA,YACN,MAAM;AAAA,cACJ,oCAAoC,WAAW;AAAA,YAAA;AAAA,UACjD;AAGF,gBAAM,SAAS;AAAA,YACb;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UAAA;AAGF,8BAAoB,KAAK,gBAAgB;AAAA,YACvC;AAAA,YACA,SAAS,OAAO;AAAA,YAChB,OAAO,OAAO;AAAA,UAAA,CACf;AAAA,QACH,CAAC;AAGD,4BAAoB,GAAG,wBAAwB,OAAO,UAAU;AAC9D,gBAAM;AAAA,YACJ;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UAAA,IACE,MAAM;AAEV,kBAAQ;AAAA,YACN,MAAM;AAAA,cACJ,qCAAqC,WAAW,eAAe,UAAU;AAAA,YAAA;AAAA,UAC3E;AAIF,gBAAM,qBAAqB,aACvB,GAAG,WAAW,KAAK,UAAU,KAC7B;AAEJ,gBAAM,SAAS,MAAM,eAAe,kBAAkB;AAEtD,cAAI,CAAC,OAAO,SAAS;AACnB,oBAAQ;AAAA,cACN,MAAM;AAAA,gBACJ,4CAA4C,WAAW,KAAK,OAAO,KAAK;AAAA,cAAA;AAAA,YAC1E;AAEF,gCAAoB,KAAK,sBAAsB;AAAA,cAC7C,aAAa;AAAA,cACb,SAAS;AAAA,cACT,OAAO,OAAO;AAAA,YAAA,CACf;AACD;AAAA,UACF;AAEA,kBAAQ;AAAA,YACN,MAAM;AAAA,cACJ,iDAAiD,WAAW,OAAO,UAAU;AAAA,YAAA;AAAA,UAC/E;AAIF,cAAI,CAAC,gBAAgB;AACnB,oBAAQ;AAAA,cACN,MAAM;AAAA,gBACJ;AAAA,cAAA;AAAA,YACF;AAEF,gCAAoB,KAAK,sBAAsB;AAAA,cAC7C,aAAa;AAAA,cACb,SAAS;AAAA,YAAA,CACV;AACD;AAAA,UACF;AAGA,kBAAQ;AAAA,YACN,MAAM;AAAA,cACJ,oCAAoC,eAAe;AAAA,YAAA;AAAA,UACrD;AAGF,gBAAM,eAAe,qBAAqB,gBAAgB;AAAA,YACxD,aAAa;AAAA,YACb;AAAA,YACA;AAAA,UAAA,CACD;AAED,cAAI,aAAa,SAAS;AACxB,oBAAQ;AAAA,cACN,MAAM;AAAA,gBACJ,gDAAgD,eAAe;AAAA,cAAA;AAAA,YACjE;AAGF,gCAAoB,KAAK,gBAAgB;AAAA,cACvC,aAAa;AAAA,cACb,SAAS;AAAA,YAAA,CACV;AAGD,kBAAM,qBAAqB,MAAM,gBAAA;AACjC,gCAAoB,KAAK,qBAAqB;AAAA,cAC5C,aAAa;AAAA,YAAA,CACd;AAAA,UACH,OAAO;AACL,oBAAQ;AAAA,cACN,MAAM;AAAA,gBACJ,2CAA2C,eAAe,iBAAiB,aAAa,KAAK;AAAA,cAAA;AAAA,YAC/F;AAGF,gCAAoB,KAAK,gBAAgB;AAAA,cACvC,aAAa;AAAA,cACb,SAAS;AAAA,cACT,OAAO,aAAa;AAAA,YAAA,CACrB;AAAA,UACH;AAAA,QACF,CAAC;AAGD,4BAAoB,GAAG,WAAW,YAAY;AAC5C,8BAAoB,KAAK,sBAAsB;AAAA,YAC7C,cAAc,MAAM;AAAA,UAAA,CACrB;AACD,8BAAoB,KAAK,qBAAqB;AAAA,YAC5C;AAAA,UAAA,CACD;AAAA,QACH,CAAC;AAAA,MACH;AAAA,MACA,MAAM,gBAAgB,EAAE,QAAQ;AAC9B,YAAI,KAAK,SAAS,cAAc,GAAG;AACjC,gBAAM,iBAAiB,MAAM,gBAAA;AAC7B,8BAAoB,KAAK,qBAAqB;AAAA,YAC5C,aAAa;AAAA,UAAA,CACd;AACD,2BAAA;AAAA,QACF;AAAA,MACF;AAAA,IAAA;AAAA,IAEF;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,MACT,MAAM,QAAQ;AACZ,eAAO,OAAO,SAAS,iBAAiB,mBAAmB;AAAA,MAC7D;AAAA,MACA,UAAU,MAAM,IAAI;AAElB,YACE,GAAG,SAAS,cAAc,KAC1B,GAAG,SAAS,MAAM,KAClB,GAAG,SAAS,MAAM,KAClB,GAAG,SAAS,OAAO,KACnB,CAAC,KAAK,SAAS,UAAU;AAEzB;AAEF,eAAO,kBAAkB,MAAM,IAAI,IAAI;AAAA,MACzC;AAAA,IAAA;AAAA,IAEF;AAAA,MACE,MAAM;AAAA,MACN,MAAM,QAAQ,EAAE,WAAW;AACzB,eAAO,OAAO,SAAS,iBAAiB,YAAY;AAAA,MACtD;AAAA,MACA,UAAU,MAAM,IAAI;AAElB,YAAI,CAAC,kBAAkB,mBAAmB,IAAI,GAAG;AAE/C,gBAAM,CAAC,QAAQ,IAAI,GAAG,MAAM,GAAG;AAC/B,cAAI,UAAU;AACZ,6BAAiB;AAAA,UACnB;AAAA,QACF;AAEA,eAAO;AAAA,MACT;AAAA,IAAA;AAAA,IAEF;AAAA,MACE,MAAM;AAAA,MACN,MAAM,QAAQ,EAAE,WAAW;AACzB,eAAO,OAAO,SAAS,iBAAiB,YAAY;AAAA,MACtD;AAAA,MACA,UAAU,MAAM,IAAI;AAElB,YAAI,CAAC,KAAK,SAAS,4BAA4B,EAAG;AAClD,YACE,CAAC,GAAG,SAAS,oBAAoB,KACjC,CAAC,GAAG,SAAS,qBAAqB;AAElC;AAGF,cAAM,YAAY,gBAAgB;AAClC,eAAO,KAAK,QAAQ,+BAA+B,OAAO,SAAS,CAAC;AAAA,MACtE;AAAA,IAAA;AAAA,EACF;AAEJ;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/devtools-vite",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "TanStack Vite plugin used to enhance the core devtools with additional functionalities",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
@@ -94,7 +94,6 @@ describe('remove-devtools', () => {
94
94
  3000,
95
95
  )!.code,
96
96
  )
97
- console.log('output', output)
98
97
  expect(
99
98
  output.includes(
100
99
  'http://localhost:3000/__tsd/open-source?source=test.jsx',
@@ -114,4 +113,20 @@ describe('remove-devtools', () => {
114
113
  )
115
114
  expect(output).toBe(undefined)
116
115
  })
116
+
117
+ test('it adds enhanced console.log with css formatting to console.log()', () => {
118
+ const output = removeEmptySpace(
119
+ enhanceConsoleLog(
120
+ `
121
+ console.log('This is a log')
122
+ `,
123
+ 'test.jsx',
124
+ 3000,
125
+ )!.code,
126
+ )
127
+ expect(output.includes('color:#A0A')).toEqual(true)
128
+ expect(output.includes('color:#FFF')).toEqual(true)
129
+ expect(output.includes('color:#55F')).toEqual(true)
130
+ expect(output.includes('color:#FFF')).toEqual(true)
131
+ })
117
132
  })
@@ -31,11 +31,42 @@ const transform = (
31
31
  location.start.column,
32
32
  ]
33
33
  const finalPath = `${filePath}:${lineNumber}:${column + 1}`
34
- path.node.arguments.unshift(
34
+ const logMessage = `${chalk.magenta('LOG')} ${chalk.blueBright(`${finalPath}`)}\n → `
35
+
36
+ const serverLogMessage = t.arrayExpression([
37
+ t.stringLiteral(logMessage),
38
+ ])
39
+ const browserLogMessage = t.arrayExpression([
40
+ // LOG with css formatting specifiers: %c
35
41
  t.stringLiteral(
36
- `${chalk.magenta('LOG')} ${chalk.blueBright(`${finalPath} - http://localhost:${port}/__tsd/open-source?source=${encodeURIComponent(finalPath)}`)}\n → `,
42
+ `%c${'LOG'}%c %c${`Go to Source: http://localhost:${port}/__tsd/open-source?source=${encodeURIComponent(finalPath)}`}%c \n → `,
43
+ ),
44
+ // magenta
45
+ t.stringLiteral('color:#A0A'),
46
+ t.stringLiteral('color:#FFF'),
47
+ // blueBright
48
+ t.stringLiteral('color:#55F'),
49
+ t.stringLiteral('color:#FFF'),
50
+ ])
51
+
52
+ // typeof window === "undefined"
53
+ const checkServerCondition = t.binaryExpression(
54
+ '===',
55
+ t.unaryExpression('typeof', t.identifier('window')),
56
+ t.stringLiteral('undefined'),
57
+ )
58
+
59
+ // ...(isServer ? serverLogMessage : browserLogMessage)
60
+ path.node.arguments.unshift(
61
+ t.spreadElement(
62
+ t.conditionalExpression(
63
+ checkServerCondition,
64
+ serverLogMessage,
65
+ browserLogMessage,
66
+ ),
37
67
  ),
38
68
  )
69
+
39
70
  didTransform = true
40
71
  }
41
72
  },
package/src/plugin.ts CHANGED
@@ -202,7 +202,19 @@ export const devtools = (args?: TanStackDevtoolsViteConfig): Array<Plugin> => {
202
202
  },
203
203
  enforce: 'pre',
204
204
  transform(code, id) {
205
- if (id.includes('node_modules') || id.includes('?raw')) return
205
+ const devtoolPackages = [
206
+ '@tanstack/react-devtools',
207
+ '@tanstack/preact-devtools',
208
+ '@tanstack/solid-devtools',
209
+ '@tanstack/vue-devtools',
210
+ '@tanstack/devtools',
211
+ ]
212
+ if (
213
+ id.includes('node_modules') ||
214
+ id.includes('?raw') ||
215
+ !devtoolPackages.some((pkg) => code.includes(pkg))
216
+ )
217
+ return
206
218
  const transform = removeDevtools(code, id)
207
219
  if (!transform) return
208
220
  if (logging) {