From 8780fad1b03f9ae4208f2658181ce85aa5a5f29e Mon Sep 17 00:00:00 2001 From: Lachlan Collins <1667261+lachlancollins@users.noreply.github.com> Date: Sat, 26 Sep 2026 08:31:40 +1000 Subject: [PATCH 1/4] chore(angular-query): migrate to tsdown --- .../angular-query-experimental/package.json | 35 +++--- .../tsconfig.prod.json | 7 +- .../tsdown.config.ts | 16 +++ .../angular-query-experimental/vite.config.ts | 101 +----------------- pnpm-lock.yaml | 20 ---- 5 files changed, 32 insertions(+), 147 deletions(-) create mode 100644 packages/angular-query-experimental/tsdown.config.ts diff --git a/packages/angular-query-experimental/package.json b/packages/angular-query-experimental/package.json index 119887324d1..55bb9b082df 100644 --- a/packages/angular-query-experimental/package.json +++ b/packages/angular-query-experimental/package.json @@ -39,48 +39,46 @@ "test:types:ts70": "node ../../node_modules/typescript70/lib/tsc.js --project tsconfig.json --outDir .cache/test-types/ts70 --tsBuildInfoFile .cache/test-types/ts70.tsbuildinfo", "test:lib": "vitest", "test:lib:dev": "pnpm run test:lib --watch", - "test:build": "pnpm pack && publint ./dist/*.tgz --strict && attw ./dist/*.tgz; premove ./dist/*.tgz", - "build": "vite build", - "prepack": "node scripts/prepack.js" + "test:build": "publint --strict && attw --pack", + "build": "tsdown --tsconfig tsconfig.prod.json" }, "type": "module", - "types": "dist/index.d.ts", + "types": "dist/index.d.mts", "module": "dist/index.mjs", "exports": { + "@tanstack/custom-condition": "./src/index.ts", ".": { - "@tanstack/custom-condition": "./src/index.ts", - "types": "./dist/index.d.ts", + "types": "./dist/index.d.mts", "default": "./dist/index.mjs" }, "./package.json": "./package.json", "./inject-queries-experimental": { - "types": "./dist/inject-queries-experimental/index.d.ts", + "types": "./dist/inject-queries-experimental/index.d.mts", "default": "./dist/inject-queries-experimental/index.mjs" }, "./devtools": { - "types": "./dist/devtools/index.d.ts", + "types": "./dist/devtools/index.d.mts", "development": "./dist/devtools/index.mjs", "default": "./dist/devtools/stub.mjs" }, "./devtools/production": { - "types": "./dist/devtools/production/index.d.ts", + "types": "./dist/devtools/production/index.d.mts", "default": "./dist/devtools/index.mjs" }, "./devtools-panel": { - "types": "./dist/devtools-panel/index.d.ts", + "types": "./dist/devtools-panel/index.d.mts", "development": "./dist/devtools-panel/index.mjs", "default": "./dist/devtools-panel/stub.mjs" }, "./devtools-panel/production": { - "types": "./dist/devtools-panel/production/index.d.ts", + "types": "./dist/devtools-panel/production/index.d.mts", "default": "./dist/devtools-panel/index.mjs" } }, "sideEffects": false, "files": [ - "**/*.d.ts", - "**/*.mjs", - "**/*.mjs.map" + "dist", + "src" ], "dependencies": { "@tanstack/query-core": "workspace:*" @@ -93,10 +91,7 @@ "@tanstack/query-test-utils": "workspace:*", "@testing-library/angular": "^18.0.0", "npm-run-all2": "^9.0.3", - "rxjs": "^7.8.2", - "vite-plugin-dts": "4.2.3", - "vite-plugin-externalize-deps": "^0.9.0", - "vite-tsconfig-paths": "^5.1.4" + "rxjs": "^7.8.2" }, "optionalDependencies": { "@tanstack/query-devtools": "workspace:*" @@ -104,9 +99,5 @@ "peerDependencies": { "@angular/common": ">=16.0.0", "@angular/core": ">=16.0.0" - }, - "publishConfig": { - "directory": "dist", - "linkDirectory": false } } diff --git a/packages/angular-query-experimental/tsconfig.prod.json b/packages/angular-query-experimental/tsconfig.prod.json index 0f5fee44cf4..2bb29fdf02a 100644 --- a/packages/angular-query-experimental/tsconfig.prod.json +++ b/packages/angular-query-experimental/tsconfig.prod.json @@ -3,12 +3,7 @@ "compilerOptions": { "incremental": false, "composite": false, - "rootDir": "../../", - "customConditions": null, - // vite-plugin-dts must not depend on a generated query-core build. - "paths": { - "@tanstack/query-core": ["../query-core/src/index.ts"] - } + "rootDir": "../../" }, "include": ["src"], "exclude": ["src/__tests__"] diff --git a/packages/angular-query-experimental/tsdown.config.ts b/packages/angular-query-experimental/tsdown.config.ts new file mode 100644 index 00000000000..7d7a328a2d5 --- /dev/null +++ b/packages/angular-query-experimental/tsdown.config.ts @@ -0,0 +1,16 @@ +import { defineConfig } from 'tsdown' + +export default defineConfig({ + entry: ['src/**/*.ts', '!src/__tests__/**'], + format: ['esm'], + target: ['chrome91', 'firefox90', 'edge91', 'safari15', 'ios15', 'opera77'], + // Rolldown lowers private fields for browser target arrays. Keep the + // transform target at ES2022 to match the syntax that tsup emitted. + inputOptions: { transform: { target: 'es2022' } }, + outDir: 'dist', + unbundle: true, + dts: true, + fixedExtension: true, + sourcemap: true, + clean: true, +}) diff --git a/packages/angular-query-experimental/vite.config.ts b/packages/angular-query-experimental/vite.config.ts index d5337c94ea6..5ae7a3f751a 100644 --- a/packages/angular-query-experimental/vite.config.ts +++ b/packages/angular-query-experimental/vite.config.ts @@ -1,30 +1,5 @@ -import { defineConfig, mergeConfig } from 'vitest/config' -import { externalizeDeps } from 'vite-plugin-externalize-deps' -import tsconfigPaths from 'vite-tsconfig-paths' -import dts from 'vite-plugin-dts' +import { defineConfig } from 'vitest/config' import packageJson from './package.json' -import type { Options } from '@tanstack/vite-config' - -function ensureImportFileExtension({ - content, - extension, -}: { - content: string - extension: string -}) { - // replace e.g. `import { foo } from './foo'` with `import { foo } from './foo.js'` - content = content.replace( - /(im|ex)port\s[\w{}/*\s,]+from\s['"](?:\.\.?\/)+?[^.'"]+(?=['"];?)/gm, - `$&.${extension}`, - ) - - // replace e.g. `import('./foo')` with `import('./foo.js')` - content = content.replace( - /import\(['"](?:\.\.?\/)+?[^.'"]+(?=['"];?)/gm, - `$&.${extension}`, - ) - return content -} const config = defineConfig({ // fix from https://github.com/vitest-dev/vitest/issues/6992#issuecomment-2509408660 @@ -56,76 +31,4 @@ const config = defineConfig({ }, }) -// copy from @tanstack/config/vite with changes: -// - build - lib - fileName: [name.mjs] -// - rollup - output - preserveModulesRoot: src -export const tanstackViteConfig = (options: Options) => { - const outDir = options.outDir ?? 'dist' - const cjs = options.cjs ?? true - - return defineConfig({ - plugins: [ - externalizeDeps({ include: options.externalDeps ?? [] }), - tsconfigPaths({ - projects: options.tsconfigPath ? [options.tsconfigPath] : undefined, - }), - dts({ - outDir, - entryRoot: options.srcDir, - include: options.srcDir, - exclude: options.exclude, - tsconfigPath: options.tsconfigPath, - compilerOptions: { - module: 99, // ESNext - declarationMap: false, - }, - beforeWriteFile: (filePath, content) => { - return { - filePath, - content: ensureImportFileExtension({ content, extension: 'js' }), - } - }, - afterDiagnostic: (diagnostics) => { - if (diagnostics.length > 0) { - console.error('Please fix the above type errors') - process.exit(1) - } - }, - }), - ], - build: { - outDir, - minify: false, - sourcemap: true, - lib: { - entry: options.entry, - formats: cjs ? ['es', 'cjs'] : ['es'], - fileName: () => '[name].mjs', - }, - rollupOptions: { - output: { - preserveModules: true, - preserveModulesRoot: 'src', - }, - }, - }, - }) -} - -export default mergeConfig( - config, - tanstackViteConfig({ - cjs: false, - entry: [ - './src/index.ts', - './src/inject-queries-experimental/index.ts', - './src/devtools-panel/index.ts', - './src/devtools-panel/stub.ts', - './src/devtools/index.ts', - './src/devtools/stub.ts', - ], - exclude: ['src/__tests__'], - srcDir: './src', - tsconfigPath: 'tsconfig.prod.json', - }), -) +export default config diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2672ef1602b..4bcf31ff1d4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2638,21 +2638,10 @@ importers: rxjs: specifier: ^7.8.2 version: 7.8.2 - vite-plugin-dts: - specifier: 4.2.3 - version: 4.2.3(@types/node@22.19.15)(rollup@4.60.1)(supports-color@7.2.0)(typescript@6.0.3)(vite@6.4.1(@types/node@22.19.15)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.90.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)) - vite-plugin-externalize-deps: - specifier: ^0.9.0 - version: 0.9.0(vite@6.4.1(@types/node@22.19.15)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.90.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)) - vite-tsconfig-paths: - specifier: ^5.1.4 - version: 5.1.4(supports-color@7.2.0)(typescript@6.0.3)(vite@6.4.1(@types/node@22.19.15)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.90.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)) - linkDirectory: false optionalDependencies: '@tanstack/query-devtools': specifier: workspace:* version: link:../query-devtools - publishDirectory: dist packages/angular-query-persist-client: dependencies: @@ -16287,11 +16276,6 @@ packages: peerDependencies: vite: ^6.4.1 - vite-plugin-externalize-deps@0.9.0: - resolution: {integrity: sha512-wg3qb5gCy2d1KpPKyD9wkXMcYJ84yjgziHrStq9/8R7chhUC73mhQz+tVtvhFiICQHsBn1pnkY4IBbPqF9JHNw==} - peerDependencies: - vite: ^6.4.1 - vite-plugin-solid@2.11.11: resolution: {integrity: sha512-YMZCXsLw9kyuvQFEdwLP27fuTQJLmjNoHy90AOJnbRuJ6DwShUxKFo38gdFrWn9v11hnGicKCZEaeI/TFs6JKw==} peerDependencies: @@ -33027,10 +33011,6 @@ snapshots: dependencies: vite: 6.4.1(@types/node@22.19.15)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.90.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0) - vite-plugin-externalize-deps@0.9.0(vite@6.4.1(@types/node@22.19.15)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.90.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)): - dependencies: - vite: 6.4.1(@types/node@22.19.15)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.90.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0) - vite-plugin-solid@2.11.11(@testing-library/jest-dom@6.9.1)(solid-js@1.9.12)(supports-color@10.2.2)(vite@6.4.1(@types/node@22.19.15)(jiti@1.21.7)(lightningcss@1.32.0)(sass@1.90.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)): dependencies: '@babel/core': 7.29.7(supports-color@10.2.2) From a7ab710fbd8a1a12cd23a9ebb2a93673ea443949 Mon Sep 17 00:00:00 2001 From: Lachlan Collins <1667261+lachlancollins@users.noreply.github.com> Date: Sat, 26 Sep 2026 08:49:41 +1000 Subject: [PATCH 2/4] Add changeset --- .changeset/metal-games-hang.md | 5 +++++ packages/angular-query-experimental/package.json | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 .changeset/metal-games-hang.md diff --git a/.changeset/metal-games-hang.md b/.changeset/metal-games-hang.md new file mode 100644 index 00000000000..b1ed2381b8d --- /dev/null +++ b/.changeset/metal-games-hang.md @@ -0,0 +1,5 @@ +--- +"@tanstack/angular-query-experimental": patch +--- + +build: switch to tsdown diff --git a/packages/angular-query-experimental/package.json b/packages/angular-query-experimental/package.json index 55bb9b082df..24cd6c82a3a 100644 --- a/packages/angular-query-experimental/package.json +++ b/packages/angular-query-experimental/package.json @@ -51,7 +51,6 @@ "types": "./dist/index.d.mts", "default": "./dist/index.mjs" }, - "./package.json": "./package.json", "./inject-queries-experimental": { "types": "./dist/inject-queries-experimental/index.d.mts", "default": "./dist/inject-queries-experimental/index.mjs" From 87e8cce207f76e32772af9b521a73b934fb2ecb9 Mon Sep 17 00:00:00 2001 From: Lachlan Collins <1667261+lachlancollins@users.noreply.github.com> Date: Sat, 26 Sep 2026 09:44:07 +1000 Subject: [PATCH 3/4] Fix types --- knip.ts | 4 - .../angular-query-experimental/package.json | 2 +- .../scripts/prepack.js | 106 ------------------ 3 files changed, 1 insertion(+), 111 deletions(-) delete mode 100644 packages/angular-query-experimental/scripts/prepack.js diff --git a/knip.ts b/knip.ts index 68d2c4a93d7..080dd26ab0a 100644 --- a/knip.ts +++ b/knip.ts @@ -12,10 +12,6 @@ export default { ignoreDependencies: ['react', 'react-dom'], }, 'packages/angular-query-experimental': { - entry: [ - 'src/devtools/production/index.ts!', - 'src/devtools-panel/production/index.ts!', - ], // Strict mode excludes optional dependencies. Read the declared names // so removing a declaration still causes an unlisted dependency error. ignoreDependencies: Object.keys( diff --git a/packages/angular-query-experimental/package.json b/packages/angular-query-experimental/package.json index 24cd6c82a3a..7557dbc0163 100644 --- a/packages/angular-query-experimental/package.json +++ b/packages/angular-query-experimental/package.json @@ -46,8 +46,8 @@ "types": "dist/index.d.mts", "module": "dist/index.mjs", "exports": { - "@tanstack/custom-condition": "./src/index.ts", ".": { + "@tanstack/custom-condition": "./src/index.ts", "types": "./dist/index.d.mts", "default": "./dist/index.mjs" }, diff --git a/packages/angular-query-experimental/scripts/prepack.js b/packages/angular-query-experimental/scripts/prepack.js deleted file mode 100644 index bf4bef0cc75..00000000000 --- a/packages/angular-query-experimental/scripts/prepack.js +++ /dev/null @@ -1,106 +0,0 @@ -import fs from 'node:fs' -import path from 'node:path' - -/** - * Prepack script that prepares the package for publishing by: - * 1. Creating a modified package.json without dev dependencies, publishConfig and build scripts - * 2. Updating file paths to remove 'dist/' prefixes (since files will be at root in published package) - * 3. Writing this modified package.json to the `dist` directory - * 4. Copying additional files like README.md to the dist directory - * - * Type declarations need to be in the package root or corresponding sub-path to support - * sub-path exports in applications still using `moduleResolution: node`. - */ - -console.log('Running prepack script') - -/** - * Files to copy to the dist directory - * @type {string[]} - */ -const FILES_TO_COPY = ['README.md'] - -/** - * Fields to remove from the package.json copy - * @type {string[]} - */ -const FIELDS_TO_REMOVE = [ - 'devDependencies', - 'files', - 'publishConfig', - 'scripts', -] - -/** - * Replaces 'dist/' or './dist/' prefix from a file path with './' - * Only matches at the start of the path to avoid false matches - * @param {string} filePath - The file path to process - * @returns {string} The path without dist prefix - */ -function replaceDist(filePath) { - // Only match dist/ at the beginning of the path, followed by a filename - // This prevents matching strings like "distributed/file.js" or "some/dist/path" - return filePath.replace(/^(?:\.\/)?dist\/(?=.+)/, './') -} - -/** - * Recursively processes package.json `exports` to remove dist prefixes - * @param {Record} exports - The exports object to process - * @returns {Record} The processed exports object - */ -function processExports(exports) { - return Object.fromEntries( - Object.entries(exports).map(([key, value]) => [ - key, - typeof value === 'string' - ? replaceDist(value) - : typeof value === 'object' && value !== null - ? processExports(value) - : value, - ]), - ) -} - -console.log('Copying modified package.json') - -/** @type {Record} */ -const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8')) - -const modifiedPackageJson = { ...packageJson } - -if (modifiedPackageJson.types) { - modifiedPackageJson.types = replaceDist(modifiedPackageJson.types) -} - -if (modifiedPackageJson.module) { - modifiedPackageJson.module = replaceDist(modifiedPackageJson.module) -} - -if (modifiedPackageJson.exports) { - modifiedPackageJson.exports = processExports(modifiedPackageJson.exports) -} - -for (const field of FIELDS_TO_REMOVE) { - delete modifiedPackageJson[field] -} - -if (!fs.existsSync('dist')) { - fs.mkdirSync('dist', { recursive: true }) -} - -fs.writeFileSync( - path.join('dist', 'package.json'), - JSON.stringify(modifiedPackageJson, null, 2), -) - -console.log('Copying other files') -for (const file of FILES_TO_COPY) { - if (fs.existsSync(file)) { - fs.copyFileSync(file, path.join('dist', file)) - console.log(`${file}`) - } else { - console.log(`${file} not found, skipping`) - } -} - -console.log('prepack complete') From aab0e2700a6a552f3b489f0510ecf75d615ab6f6 Mon Sep 17 00:00:00 2001 From: Lachlan Collins <1667261+lachlancollins@users.noreply.github.com> Date: Sat, 26 Sep 2026 09:53:10 +1000 Subject: [PATCH 4/4] Fix attw --- knip.ts | 1 + .../angular-query-experimental/package.json | 1 - .../scripts/prepack.js | 106 ++++++++++++++++++ .../tsdown.config.ts | 7 ++ 4 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 packages/angular-query-experimental/scripts/prepack.js diff --git a/knip.ts b/knip.ts index 080dd26ab0a..f86cb38bacb 100644 --- a/knip.ts +++ b/knip.ts @@ -12,6 +12,7 @@ export default { ignoreDependencies: ['react', 'react-dom'], }, 'packages/angular-query-experimental': { + ignore: ['scripts/prepack.js'], // Strict mode excludes optional dependencies. Read the declared names // so removing a declaration still causes an unlisted dependency error. ignoreDependencies: Object.keys( diff --git a/packages/angular-query-experimental/package.json b/packages/angular-query-experimental/package.json index 7557dbc0163..451901949c0 100644 --- a/packages/angular-query-experimental/package.json +++ b/packages/angular-query-experimental/package.json @@ -39,7 +39,6 @@ "test:types:ts70": "node ../../node_modules/typescript70/lib/tsc.js --project tsconfig.json --outDir .cache/test-types/ts70 --tsBuildInfoFile .cache/test-types/ts70.tsbuildinfo", "test:lib": "vitest", "test:lib:dev": "pnpm run test:lib --watch", - "test:build": "publint --strict && attw --pack", "build": "tsdown --tsconfig tsconfig.prod.json" }, "type": "module", diff --git a/packages/angular-query-experimental/scripts/prepack.js b/packages/angular-query-experimental/scripts/prepack.js new file mode 100644 index 00000000000..bf4bef0cc75 --- /dev/null +++ b/packages/angular-query-experimental/scripts/prepack.js @@ -0,0 +1,106 @@ +import fs from 'node:fs' +import path from 'node:path' + +/** + * Prepack script that prepares the package for publishing by: + * 1. Creating a modified package.json without dev dependencies, publishConfig and build scripts + * 2. Updating file paths to remove 'dist/' prefixes (since files will be at root in published package) + * 3. Writing this modified package.json to the `dist` directory + * 4. Copying additional files like README.md to the dist directory + * + * Type declarations need to be in the package root or corresponding sub-path to support + * sub-path exports in applications still using `moduleResolution: node`. + */ + +console.log('Running prepack script') + +/** + * Files to copy to the dist directory + * @type {string[]} + */ +const FILES_TO_COPY = ['README.md'] + +/** + * Fields to remove from the package.json copy + * @type {string[]} + */ +const FIELDS_TO_REMOVE = [ + 'devDependencies', + 'files', + 'publishConfig', + 'scripts', +] + +/** + * Replaces 'dist/' or './dist/' prefix from a file path with './' + * Only matches at the start of the path to avoid false matches + * @param {string} filePath - The file path to process + * @returns {string} The path without dist prefix + */ +function replaceDist(filePath) { + // Only match dist/ at the beginning of the path, followed by a filename + // This prevents matching strings like "distributed/file.js" or "some/dist/path" + return filePath.replace(/^(?:\.\/)?dist\/(?=.+)/, './') +} + +/** + * Recursively processes package.json `exports` to remove dist prefixes + * @param {Record} exports - The exports object to process + * @returns {Record} The processed exports object + */ +function processExports(exports) { + return Object.fromEntries( + Object.entries(exports).map(([key, value]) => [ + key, + typeof value === 'string' + ? replaceDist(value) + : typeof value === 'object' && value !== null + ? processExports(value) + : value, + ]), + ) +} + +console.log('Copying modified package.json') + +/** @type {Record} */ +const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8')) + +const modifiedPackageJson = { ...packageJson } + +if (modifiedPackageJson.types) { + modifiedPackageJson.types = replaceDist(modifiedPackageJson.types) +} + +if (modifiedPackageJson.module) { + modifiedPackageJson.module = replaceDist(modifiedPackageJson.module) +} + +if (modifiedPackageJson.exports) { + modifiedPackageJson.exports = processExports(modifiedPackageJson.exports) +} + +for (const field of FIELDS_TO_REMOVE) { + delete modifiedPackageJson[field] +} + +if (!fs.existsSync('dist')) { + fs.mkdirSync('dist', { recursive: true }) +} + +fs.writeFileSync( + path.join('dist', 'package.json'), + JSON.stringify(modifiedPackageJson, null, 2), +) + +console.log('Copying other files') +for (const file of FILES_TO_COPY) { + if (fs.existsSync(file)) { + fs.copyFileSync(file, path.join('dist', file)) + console.log(`${file}`) + } else { + console.log(`${file} not found, skipping`) + } +} + +console.log('prepack complete') diff --git a/packages/angular-query-experimental/tsdown.config.ts b/packages/angular-query-experimental/tsdown.config.ts index 7d7a328a2d5..b2ac75a1f1c 100644 --- a/packages/angular-query-experimental/tsdown.config.ts +++ b/packages/angular-query-experimental/tsdown.config.ts @@ -13,4 +13,11 @@ export default defineConfig({ fixedExtension: true, sourcemap: true, clean: true, + publint: { + strict: true, + }, + attw: { + profile: 'esm-only', + level: 'error', + }, })