Skip to content

Commit

Permalink
feat(react-query): universal react-query for suspensive 4 and 5 (#953)
Browse files Browse the repository at this point in the history
# Summary

`@suspensive/react-query` now automatically identifies the installed
version of `@tanstack/react-query` and uses either
`@suspensive/react-query-4` or `@suspensive/react-query-5` accordingly.

# Roadmaps

> This is the list of remaining tasks. It may be added to or revised.

- [x] Core 
- [x] Field Test
- [ ] CLI ⚠️
- [ ] Dependency Log
([comment](#953 (comment)))

# How it works

The mechanism for identifying the version of `@tanstack/react-query` and
selecting the appropriate `@suspensive/react-query-x` to use is similar
to `vue-demi`.

- https://github.com/vueuse/vue-demi

When `@suspsensive/react-query` is added as a dependency, the
`postinstall` script fetches the version of `@tanstack/react-query` and
overlays the build files of `@suspensive/react-query-x` at the entry
point (build root) to ensure the appropriate version is used.

```json
// package.json
// ...
"exports": {
  ".": {
    "import": {
      "types": "./dist/index.d.ts",
      "default": "./dist/index.js"
    },
    "require": {
      "types": "./dist/index.d.cts",
      "default": "./dist/index.cjs"
    }
  },
  "./package.json": "./package.json"
},
// ...
"postinstall": "node -e \"import('./scripts/postinstall.js').catch(e => console.error(e))\""
// ...
```

The `postinstall.js` script is executed during the `postinstall`
process.

```jsx
// script/postinstall.js
import { loadModule, switchVersion } from './utils.js'

const reactQueryPackageJson = loadModule('@tanstack/react-query/package.json')
const version = reactQueryPackageJson?.version

if (!version || typeof version !== 'string') {
  console.warn('@tanstack/react-query is not found.')
} else if (version.startsWith('4.')) {
  switchVersion(4)
} else if (version.startsWith('5.')) {
  switchVersion(5)
} else {
  console.warn('[@suspensive/react-query]', `version v${version} is not supported.`)
}
```

This script fetches the installed `@tanstack/react-query/package.json`,
checks the version, and copies the corresponding
`@suspensive/react-query-x` files to the library's root.

```bash
suspensive/packages/react-query/dist
# --- Library entry point
├── index.cjs
├── index.cjs.map
├── index.d.cts
├── index.d.ts
├── index.js
├── index.js.map
# ---
├── v4
# --- Copy files from this folder to the entry point if @tanstack/react-query@4 is detected
|  ├── index.cjs
|  ├── index.cjs.map
|  ├── index.d.cts
|  ├── index.d.ts
|  ├── index.js
|  └── index.js.map
# ---
└── v5
# --- Copy files from this folder to the entry point if @tanstack/react-query@5 is detected
   ├── index.cjs
   ├── index.cjs.map
   ├── index.d.cts
   ├── index.d.ts
   ├── index.js
   └── index.js.map
```

By following this process, `@suspensive/react-query` automatically uses
the appropriate version upon installation.

When added as a dependency, the version switching happens automatically
as shown in the logs below:

```bash
# case1: @tanstack/react-query@4
packages/react-query postinstall$ node -e "import('./scripts/postinstall.js').catch(e => console.error(e))"
│ [@suspensive/react-query] set version to v4
└─ Done in 56ms

# case2: @tanstack/react-query@5
packages/react-query postinstall$ node -e "import('./scripts/postinstall.js').catch(e => console.error(e))"
│ [@suspensive/react-query] set version to v5
└─ Done in 56ms
```

# Field Test

> These tests were conducted in isolated environments using `~.tgz`.
In all environments, `@suspensive/react": "^2.1.2-beta.0` was used
consistently, and versions 4 and 5 of `@tanstack/react-query` were
tested.
> 
- pnpm@9.4.0 ✅
- yarn@v1.22.22 ✅
- yarn berry@4.3.0 (pnp) ✅
- pnpm@9.4.9 (monorepo) ✅

# CLI

In typical environments (single repo), the version switches
automatically. However, for special cases, we have created the
`suspensive-react-query-switch` script, which forces the switching of
`@suspensive/react-query-x`.

```bash
npx suspensive-react-query-switch
[@suspensive/react-query], expecting version "4" or "5""

npx suspensive-react-query-switch 4
[@suspensive/react-query] set version to v4
```

Although it works in most environments, it does not work in the
following case:

- The CLI does not work properly in a monorepo environment. ⚠️
- The CLI does not work properly in a yarn-berry (pnp) environment. ⚠️

---------

Co-authored-by: Jonghyeon Ko <jonghyeon@toss.im>
  • Loading branch information
gwansikk and manudeli authored Jun 21, 2024
1 parent e829167 commit 3e9e4d5
Show file tree
Hide file tree
Showing 9 changed files with 86 additions and 4 deletions.
5 changes: 5 additions & 0 deletions .changeset/fair-mayflies-knock.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@suspensive/react-query": patch
---

feat(react-query): universal support for TanStack Query 4 and 5
3 changes: 3 additions & 0 deletions packages/react-query/bin/suspensive-react-query-switch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/usr/bin/env node
'use strict'
import '../scripts/switch.js'
12 changes: 9 additions & 3 deletions packages/react-query/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,13 @@
"types": "dist/index.d.ts",
"files": [
"dist",
"src"
"src",
"bin",
"scripts"
],
"bin": {
"suspensive-react-query-switch": "bin/suspensive-react-query-switch.js"
},
"scripts": {
"build": "tsup",
"ci:attw": "attw --pack",
Expand All @@ -49,7 +54,8 @@
"ci:type": "tsc --noEmit",
"clean": "rimraf ./dist && rimraf ./coverage",
"dev": "tsup --watch",
"prepack": "pnpm build"
"prepack": "pnpm build",
"postinstall": "node -e \"import('./scripts/postinstall.js').catch(e => console.error(e))\""
},
"dependencies": {
"@suspensive/react-query-4": "workspace:^0.0.1-beta.0",
Expand All @@ -69,7 +75,7 @@
},
"peerDependencies": {
"@suspensive/react": "workspace:^2.1.2-beta.0",
"@tanstack/react-query": "^4",
"@tanstack/react-query": "^4 || ^5",
"react": "^18"
},
"peerDependenciesMeta": {
Expand Down
14 changes: 14 additions & 0 deletions packages/react-query/scripts/postinstall.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { loadModule, switchVersion } from './utils.js'

const reactQueryPackageJson = loadModule('@tanstack/react-query/package.json')
const version = reactQueryPackageJson?.version

if (!version || typeof version !== 'string') {
console.warn('@tanstack/react-query is not found.')
} else if (version.startsWith('4.')) {
switchVersion(4)
} else if (version.startsWith('5.')) {
switchVersion(5)
} else {
console.warn('[@suspensive/react-query]', `version v${version} is not supported.`)
}
12 changes: 12 additions & 0 deletions packages/react-query/scripts/switch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { switchVersion } from './utils.js'

const version = process.argv[2]

if (version === '4') {
switchVersion(4)
} else if (version === '5') {
switchVersion(5)
} else {
console.warn('[@suspensive/react-query],', `expecting version "4" or "5""`)
process.exit(1)
}
40 changes: 40 additions & 0 deletions packages/react-query/scripts/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import fs from 'fs'
import path, { dirname } from 'path'
import { fileURLToPath } from 'url'

const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)

const dir = path.resolve(__dirname, '..', 'dist')

export function loadModule(name) {
try {
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-argument
return require(name)
} catch (e) {
return undefined
}
}

export function switchVersion(version) {
copy(version)
console.log('[@suspensive/react-query]', `set version to v${version}`)
}

function copy(version) {
const srcDir = path.join(dir, `v${version}`)
const files = fs.readdirSync(srcDir)

files.forEach((file) => {
const src = path.join(srcDir, file)
const dest = path.join(dir, file)
const content = fs.readFileSync(src, 'utf-8')

try {
fs.unlinkSync(dest)
} catch (e) {
/* empty */
}
fs.writeFileSync(dest, content, 'utf-8')
})
}
1 change: 1 addition & 0 deletions packages/react-query/src/v4/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from '@suspensive/react-query-4'
1 change: 1 addition & 0 deletions packages/react-query/src/v5/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from '@suspensive/react-query-5'
2 changes: 1 addition & 1 deletion packages/react-query/tsup.config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { options } from '@suspensive/tsup'
import { defineConfig } from 'tsup'

export default defineConfig(options)
export default defineConfig({ ...options, entry: ['src/**/index.ts'] })

0 comments on commit 3e9e4d5

Please sign in to comment.