From d9b4115fab6a229a6c4404647075e67bf4103fac Mon Sep 17 00:00:00 2001 From: Sheraff Date: Mon, 4 May 2026 20:47:35 +0200 Subject: [PATCH 1/5] fix(plugin): faster hashing --- docs/start/framework/react/guide/isr.md | 4 +--- docs/start/framework/react/guide/server-functions.md | 4 +--- packages/router-generator/src/generator.ts | 2 +- packages/start-plugin-core/src/start-compiler/compiler.ts | 2 +- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/docs/start/framework/react/guide/isr.md b/docs/start/framework/react/guide/isr.md index ad1e3221305..8cf332f7693 100644 --- a/docs/start/framework/react/guide/isr.md +++ b/docs/start/framework/react/guide/isr.md @@ -342,9 +342,7 @@ const etagMiddleware = createMiddleware().server(async ({ next }) => { // Generate ETag from response content const etag = crypto - .createHash('md5') - .update(JSON.stringify(result.data)) - .digest('hex') + .hash('md5', JSON.stringify(result.data), 'hex') result.response.headers.set('ETag', `"${etag}"`) diff --git a/docs/start/framework/react/guide/server-functions.md b/docs/start/framework/react/guide/server-functions.md index 32a342b8c8f..ca9081ad46d 100644 --- a/docs/start/framework/react/guide/server-functions.md +++ b/docs/start/framework/react/guide/server-functions.md @@ -380,9 +380,7 @@ export default defineConfig({ generateFunctionId: ({ filename, functionName }) => { // Return a custom ID string return crypto - .createHash('sha1') - .update(`${filename}--${functionName}`) - .digest('hex') + .hash('sha1', `${filename}--${functionName}`, 'hex') // If you return undefined, the default is used // return undefined diff --git a/packages/router-generator/src/generator.ts b/packages/router-generator/src/generator.ts index f951beb05ba..3e67a8135de 100644 --- a/packages/router-generator/src/generator.ts +++ b/packages/router-generator/src/generator.ts @@ -1243,7 +1243,7 @@ ${acc.routeTree.map((child) => `${child.variableName}Route: typeof ${getResolved private getTempFileName(filePath: string) { const absPath = path.resolve(filePath) - const hash = crypto.createHash('md5').update(absPath).digest('hex') + const hash = crypto.hash('md5', absPath, 'hex') // lazy initialize sessionId to only create tmpDir when it is first needed if (!this.sessionId) { // ensure the directory exists diff --git a/packages/start-plugin-core/src/start-compiler/compiler.ts b/packages/start-plugin-core/src/start-compiler/compiler.ts index ec42547fc2b..d729382f257 100644 --- a/packages/start-plugin-core/src/start-compiler/compiler.ts +++ b/packages/start-plugin-core/src/start-compiler/compiler.ts @@ -600,7 +600,7 @@ export class StartCompiler { }) } if (!functionId) { - functionId = crypto.createHash('sha256').update(entryId).digest('hex') + functionId = crypto.hash('sha256', entryId, 'hex') } // Deduplicate in case the generated id conflicts with an existing id if (this.functionIds.has(functionId)) { From b646e152a39b277f650541a995615b7518b481ce Mon Sep 17 00:00:00 2001 From: Sheraff Date: Mon, 4 May 2026 20:49:10 +0200 Subject: [PATCH 2/5] changeset --- .changeset/many-ads-smile.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/many-ads-smile.md diff --git a/.changeset/many-ads-smile.md b/.changeset/many-ads-smile.md new file mode 100644 index 00000000000..1bce54d424f --- /dev/null +++ b/.changeset/many-ads-smile.md @@ -0,0 +1,6 @@ +--- +'@tanstack/start-plugin-core': patch +'@tanstack/router-generator': patch +--- + +Use node crypto.hash instead of crypto.createHash for single string hashes From 1b97a1525dd9db2e49537ce4d806935455c3a9a4 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Mon, 4 May 2026 18:50:49 +0000 Subject: [PATCH 3/5] ci: apply automated fixes --- docs/start/framework/react/guide/isr.md | 3 +-- docs/start/framework/react/guide/server-functions.md | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/start/framework/react/guide/isr.md b/docs/start/framework/react/guide/isr.md index 8cf332f7693..805467eee6d 100644 --- a/docs/start/framework/react/guide/isr.md +++ b/docs/start/framework/react/guide/isr.md @@ -341,8 +341,7 @@ const etagMiddleware = createMiddleware().server(async ({ next }) => { const result = await next() // Generate ETag from response content - const etag = crypto - .hash('md5', JSON.stringify(result.data), 'hex') + const etag = crypto.hash('md5', JSON.stringify(result.data), 'hex') result.response.headers.set('ETag', `"${etag}"`) diff --git a/docs/start/framework/react/guide/server-functions.md b/docs/start/framework/react/guide/server-functions.md index ca9081ad46d..0bd937c7a85 100644 --- a/docs/start/framework/react/guide/server-functions.md +++ b/docs/start/framework/react/guide/server-functions.md @@ -379,8 +379,7 @@ export default defineConfig({ serverFns: { generateFunctionId: ({ filename, functionName }) => { // Return a custom ID string - return crypto - .hash('sha1', `${filename}--${functionName}`, 'hex') + return crypto.hash('sha1', `${filename}--${functionName}`, 'hex') // If you return undefined, the default is used // return undefined From 2c9651c64a11d76f4919089e603394766bad16e1 Mon Sep 17 00:00:00 2001 From: Sheraff Date: Mon, 4 May 2026 21:55:25 +0200 Subject: [PATCH 4/5] utility hash for backwards compat --- .changeset/many-ads-smile.md | 1 + packages/router-generator/src/generator.ts | 3 ++- packages/router-utils/src/hash.ts | 17 +++++++++++++++++ packages/router-utils/src/index.ts | 1 + .../src/start-compiler/compiler.ts | 5 ++--- 5 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 packages/router-utils/src/hash.ts diff --git a/.changeset/many-ads-smile.md b/.changeset/many-ads-smile.md index 1bce54d424f..87c0133fb95 100644 --- a/.changeset/many-ads-smile.md +++ b/.changeset/many-ads-smile.md @@ -1,6 +1,7 @@ --- '@tanstack/start-plugin-core': patch '@tanstack/router-generator': patch +'@tanstack/router-utils': patch --- Use node crypto.hash instead of crypto.createHash for single string hashes diff --git a/packages/router-generator/src/generator.ts b/packages/router-generator/src/generator.ts index 3e67a8135de..bd3bd0bbaaf 100644 --- a/packages/router-generator/src/generator.ts +++ b/packages/router-generator/src/generator.ts @@ -3,6 +3,7 @@ import * as fsp from 'node:fs/promises' import { existsSync, mkdirSync } from 'node:fs' import crypto from 'node:crypto' import { rootRouteId } from '@tanstack/router-core' +import { hash as hashString } from '@tanstack/router-utils' import { logging } from './logger' import { isVirtualConfigFile, @@ -1243,7 +1244,7 @@ ${acc.routeTree.map((child) => `${child.variableName}Route: typeof ${getResolved private getTempFileName(filePath: string) { const absPath = path.resolve(filePath) - const hash = crypto.hash('md5', absPath, 'hex') + const hash = hashString('md5', absPath, 'hex') // lazy initialize sessionId to only create tmpDir when it is first needed if (!this.sessionId) { // ensure the directory exists diff --git a/packages/router-utils/src/hash.ts b/packages/router-utils/src/hash.ts new file mode 100644 index 00000000000..470cd42bcfc --- /dev/null +++ b/packages/router-utils/src/hash.ts @@ -0,0 +1,17 @@ +import crypto from 'node:crypto' +import type { BinaryLike, BinaryToTextEncoding } from 'node:crypto' + +const nativeHashAvailable = typeof crypto.hash === 'function' + +export function hash( + algorithm: string, + data: BinaryLike, + outputEncoding: BinaryToTextEncoding = 'hex', +): string { + + if (nativeHashAvailable) { + return crypto.hash(algorithm, data, outputEncoding) + } + + return crypto.createHash(algorithm).update(data).digest(outputEncoding) +} diff --git a/packages/router-utils/src/index.ts b/packages/router-utils/src/index.ts index 3b072ae4199..a47b194b7a7 100644 --- a/packages/router-utils/src/index.ts +++ b/packages/router-utils/src/index.ts @@ -7,5 +7,6 @@ export { } from './ast' export type { ParseAstOptions, ParseAstResult, GeneratorResult } from './ast' export { logDiff } from './logger' +export { hash } from './hash' export { copyFilesPlugin } from './copy-files-plugin' diff --git a/packages/start-plugin-core/src/start-compiler/compiler.ts b/packages/start-plugin-core/src/start-compiler/compiler.ts index d729382f257..ed75e5be06e 100644 --- a/packages/start-plugin-core/src/start-compiler/compiler.ts +++ b/packages/start-plugin-core/src/start-compiler/compiler.ts @@ -1,10 +1,9 @@ -/* eslint-disable import/no-commonjs */ -import crypto from 'node:crypto' import * as t from '@babel/types' import { deadCodeElimination, findReferencedIdentifiers, generateFromAst, + hash, parseAst, } from '@tanstack/router-utils' import babel from '@babel/core' @@ -600,7 +599,7 @@ export class StartCompiler { }) } if (!functionId) { - functionId = crypto.hash('sha256', entryId, 'hex') + functionId = hash('sha256', entryId, 'hex') } // Deduplicate in case the generated id conflicts with an existing id if (this.functionIds.has(functionId)) { From 0afbadb494866bf685e90ae2fe761318f052433c Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Mon, 4 May 2026 19:56:56 +0000 Subject: [PATCH 5/5] ci: apply automated fixes --- packages/router-utils/src/hash.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/router-utils/src/hash.ts b/packages/router-utils/src/hash.ts index 470cd42bcfc..92b0bf92160 100644 --- a/packages/router-utils/src/hash.ts +++ b/packages/router-utils/src/hash.ts @@ -8,7 +8,6 @@ export function hash( data: BinaryLike, outputEncoding: BinaryToTextEncoding = 'hex', ): string { - if (nativeHashAvailable) { return crypto.hash(algorithm, data, outputEncoding) }