Skip to content

Commit

Permalink
fix: ESM compliant bundling (#3521)
Browse files Browse the repository at this point in the history
* fix various bundling issues

* add package.json to exports

* remove @svgr/rollup

* remove node v12 from CI

* support devtools/development

* do not alias react-query

* add side effect

* remove "module"

* fix

* fix exports

* add "module"

* update @babel/runtime

* don't preserve modules

* switch back to babel

* add migration note

* update babel

* update rollup

* downgrade @rollup/plugin-commonjs
  • Loading branch information
sachinraja committed Apr 26, 2022
1 parent 1af25c6 commit 3fabd41
Show file tree
Hide file tree
Showing 31 changed files with 427 additions and 1,326 deletions.
6 changes: 4 additions & 2 deletions .babelrc.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const { NODE_ENV, BABEL_ENV } = process.env
const cjs = NODE_ENV === 'test' || BABEL_ENV === 'commonjs'
const es = BABEL_ENV === 'es'
const loose = true

module.exports = {
Expand All @@ -20,10 +21,11 @@ module.exports = {
],
plugins: [
cjs && ['@babel/transform-modules-commonjs', { loose }],
[
es && ['babel-plugin-add-import-extension', { extension: 'mjs' }],
// no runtime for umd builds
BABEL_ENV && [
'@babel/transform-runtime',
{
useESModules: !cjs,
version: require('./package.json').dependencies[
'@babel/runtime'
].replace(/^[^0-9]*/, ''),
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test-and-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node: [12, 14, 16]
node: [14, 16]
react: [17, 18]
steps:
- uses: actions/checkout@v2
Expand Down
1 change: 1 addition & 0 deletions broadcastQueryClient-experimental/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from '../lib/broadcastQueryClient-experimental'
1 change: 1 addition & 0 deletions broadcastQueryClient-experimental/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('../lib/broadcastQueryClient-experimental/index')
1 change: 1 addition & 0 deletions core/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from '../lib/core'
1 change: 1 addition & 0 deletions core/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('../lib/core/index')
6 changes: 0 additions & 6 deletions core/package.json

This file was deleted.

1 change: 1 addition & 0 deletions createAsyncStoragePersister/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from '../lib/createAsyncStoragePersister'
1 change: 1 addition & 0 deletions createAsyncStoragePersister/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('../lib/createAsyncStoragePersister/index')
6 changes: 0 additions & 6 deletions createAsyncStoragePersister/package.json

This file was deleted.

1 change: 1 addition & 0 deletions createWebStoragePersister/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from '../lib/createWebStoragePersister'
1 change: 1 addition & 0 deletions createWebStoragePersister/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('../lib/createWebStoragePersister/index')
6 changes: 0 additions & 6 deletions createWebStoragePersister/package.json

This file was deleted.

1 change: 1 addition & 0 deletions devtools/development/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from '../../lib/devtools'
1 change: 1 addition & 0 deletions devtools/development/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('../../lib/devtools/index')
6 changes: 0 additions & 6 deletions devtools/development/package.json

This file was deleted.

1 change: 1 addition & 0 deletions devtools/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from '../lib/devtools'
11 changes: 2 additions & 9 deletions devtools/index.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
if (process.env.NODE_ENV !== 'development') {
module.exports = {
ReactQueryDevtools: function () {
return null
},
ReactQueryDevtoolsPanel: function () {
return null
},
}
module.exports = require('../lib/devtools/noop')
} else {
module.exports = require('./development')
module.exports = require('../lib/devtools/index')
}
6 changes: 0 additions & 6 deletions devtools/package.json

This file was deleted.

48 changes: 26 additions & 22 deletions docs/src/pages/guides/migrating-to-react-query-4.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ title: Migrating to React Query 4

## Breaking Changes

### ESM Support

React Query now supports [package.json `"exports"`](https://nodejs.org/api/packages.html#exports) and is fully compatible with Node's native resolution for both CommonJS and ESM. We don't expect this to be a breaking change for most users, but this restricts the files you can import into your project to only the entry points we officially support.

### Query Keys (and Mutation Keys) need to be an Array

In v3, Query and Mutation Keys could be a String or an Array. Internally, React Query has always worked with Array Keys only, and we've sometimes exposed this to consumers. For example, in the `queryFn`, you would always get the key as an Array to make working with [Default Query Functions](./default-query-function) easier.
Expand Down Expand Up @@ -222,12 +226,12 @@ Even though React Query is an Async State Manager that can be used for anything
new QueryClient({
defaultOptions: {
queries: {
networkMode: 'offlineFirst'
networkMode: 'offlineFirst',
},
mutations: {
networkmode: 'offlineFirst'
}
}
networkmode: 'offlineFirst',
},
},
})
```

Expand All @@ -240,7 +244,6 @@ The `useQueries` hook now accepts an object with a `queries` prop as its input.
+ useQueries({ queries: [{ queryKey1, queryFn1, options1 }, { queryKey2, queryFn2, options2 }] })
```


### Removed undocumented methods from the `queryClient`, `query` and `mutation`

The methods `cancelMutatations` and `executeMutation` on the `QueryClient` were undocumented and unused internally, so we removed them. Since it was just a wrapper around a method available on the `mutationCache`, you can still use the functionality of `executeMutation`
Expand Down Expand Up @@ -289,10 +292,7 @@ In order to make bailing out of updates possible by returning `undefined`, we ha
Further, it is an easy bug to produce `Promise<void>` by adding logging in the queryFn:

```js
useQuery(
['key'],
() => axios.get(url).then(result => console.log(result.data))
)
useQuery(['key'], () => axios.get(url).then(result => console.log(result.data)))
```

This is now disallowed on type level; at runtime, `undefined` will be transformed to a _failed Promise_, which means you will get an `error`, which will also be logged to the console in development mode.
Expand Down Expand Up @@ -349,19 +349,18 @@ React Query defaults to "tracking" query properties, which should give you a nic
When using the [functional updater form of setQueryData](../reference/QueryClient#queryclientsetquerydata), you can now bail out of the update by returning `undefined`. This is helpful if `undefined` is given to you as `previousValue`, which means that currently, no cached entry exists and you don't want to / cannot create one, like in the example of toggling a todo:

```js
queryClient.setQueryData(
['todo', id],
(previousTodo) => previousTodo ? { ...previousTodo, done: true } : undefined
queryClient.setQueryData(['todo', id], previousTodo =>
previousTodo ? { ...previousTodo, done: true } : undefined
)
```
```

### Custom Contexts for Multiple Providers
### Custom Contexts for Multiple Providers

Custom contexts can now be specified to pair hooks with their matching `Provider`. This is critical when there may be multiple React Query `Provider` instances in the component tree, and you need to ensure your hook uses the correct `Provider` instance.

An example:

1) Create a data package.
1. Create a data package.

```tsx
// Our first data package: @my-scope/container-data
Expand All @@ -375,42 +374,47 @@ export const useUser = () => {
})
}

export const ContainerDataProvider = ({ children }: { children: React.ReactNode}) => {
export const ContainerDataProvider = ({
children,
}: {
children: React.ReactNode
}) => {
return (
<QueryClientProvider client={queryClient} context={context}>
{children}
</QueryClientProvider>
)
}
```

2) Create a second data package.
2. Create a second data package.

```tsx
// Our second data package: @my-scope/my-component-data

const context = React.createContext<QueryClient | undefined>(undefined)
const queryClient = new QueryClient()

export const useItems = () => {
return useQuery(ITEMS_KEY, ITEMS_FETCHER, {
context,
})
}

export const MyComponentDataProvider = ({ children }: { children: React.ReactNode}) => {
export const MyComponentDataProvider = ({
children,
}: {
children: React.ReactNode
}) => {
return (
<QueryClientProvider client={queryClient} context={context}>
{children}
</QueryClientProvider>
)
}
```

3) Use these two data packages in your application.
3. Use these two data packages in your application.

```tsx
// Our application
Expand Down
99 changes: 68 additions & 31 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,60 @@
"url": "https://github.com/sponsors/tannerlinsley"
},
"main": "lib/index.js",
"module": "lib/index.mjs",
"types": "lib/index.d.ts",
"unpkg": "dist/react-query.development.js",
"types": "types/index.d.ts",
"module": "es/index.js",
"sideEffects": [
"es/index.js",
"es/reactjs/index.js",
"es/reactjs/setBatchUpdatesFn.js",
"lib/index.js",
"lib/index.mjs",
"lib/reactjs/index.js",
"lib/reactjs/setBatchUpdatesFn.js"
"lib/reactjs/index.mjs",
"lib/reactjs/setBatchUpdatesFn.js",
"lib/reactjs/setBatchUpdatesFn.mjs"
],
"exports": {
".": {
"import": "./lib/index.mjs",
"default": "./lib/index.js"
},
"./package.json": "./package.json",
"./core": {
"import": "./lib/core/index.mjs",
"default": "./lib/core/index.js"
},
"./reactjs": {
"import": "./lib/reactjs/index.mjs",
"default": "./lib/reactjs/index.js"
},
"./devtools": {
"development": {
"import": "./lib/devtools/index.mjs",
"default": "./lib/devtools/index.js"
},
"import": "./lib/devtools/noop.mjs",
"default": "./lib/devtools/noop.js"
},
"./devtools/development": {
"import": "./lib/devtools/index.mjs",
"default": "./lib/devtools/index.js"
},
"./persistQueryClient": {
"import": "./lib/persistQueryClient/index.mjs",
"default": "./lib/persistQueryClient/index.js"
},
"./createWebStoragePersister": {
"import": "./lib/createWebStoragePersister/index.mjs",
"default": "./lib/createWebStoragePersister/index.js"
},
"./createAsyncStoragePersister": {
"import": "./lib/createAsyncStoragePersister/index.mjs",
"default": "./lib/createAsyncStoragePersister/index.js"
},
"./broadcastQueryClient-experimental": {
"import": "./lib/broadcastQueryClient-experimental/index.mjs",
"default": "./lib/broadcastQueryClient-experimental/index.js"
}
},
"scripts": {
"test": "is-ci \"test:ci\" \"test:dev\"",
"test:dev": "npm run test:types && npm run test:format && npm run test:eslint && npm run test:codemod && jest --watch",
Expand All @@ -34,42 +77,38 @@
"test:size": "yarn build:umd && bundlewatch",
"test:codemod": "jest --config codemods/jest.config.js",
"build": "yarn build:commonjs && yarn build:es && yarn build:umd && yarn build:types",
"build:commonjs": "rimraf ./lib && cross-env BABEL_ENV=commonjs babel --extensions .ts,.tsx --ignore ./src/**/tests/**/* ./src --out-dir lib",
"build:es": "rimraf ./es && babel --extensions .ts,.tsx --ignore ./src/**/tests/**/* ./src --out-dir es",
"build:commonjs": "rimraf './lib/**/*.js' && cross-env BABEL_ENV=commonjs babel --extensions .ts,.tsx --ignore ./src/**/tests/**/* ./src --out-dir lib",
"build:es": "rimraf './lib/**/*.mjs' && cross-env BABEL_ENV=es babel --extensions .ts,.tsx --ignore ./src/**/tests/**/* ./src --out-dir lib --out-file-extension .mjs",
"build:umd": "rimraf ./dist && cross-env NODE_ENV=production rollup -c && rollup-plugin-visualizer stats-react.json",
"build:types": "rimraf ./types && tsc --project ./tsconfig.types.json && replace 'import type' 'import' ./types -r --silent && replace 'export type' 'export' ./types -r --silent",
"watch": "yarn watch:commonjs & yarn watch:es & yarn watch:umd & yarn watch:types",
"watch:commonjs": "rimraf ./lib && cross-env BABEL_ENV=commonjs babel --watch --extensions .ts,.tsx --ignore ./src/**/tests/**/* ./src --out-dir lib",
"watch:es": "rimraf ./es && babel --watch --extensions .ts,.tsx --ignore ./src/**/tests/**/* ./src --out-dir es",
"build:types": "rimraf './lib/**/*.d.ts' && tsc --project ./tsconfig.types.json",
"watch": "yarn watch:commonjs && watch:es & yarn watch:umd & yarn watch:types",
"watch:commonjs": "rimraf './lib/**/*.js' && cross-env BABEL_ENV=commonjs babel --watch --extensions .ts,.tsx --ignore ./src/**/tests/**/* ./src --out-dir lib",
"watch:es": "rimraf './lib/**/*.mjs' && cross-env BABEL_ENV=es babel --watch --extensions .ts,.tsx --ignore ./src/**/tests/**/* ./src --out-dir lib --out-file-extension .mjs",
"watch:umd": "rimraf ./dist && cross-env NODE_ENV=production rollup -w -c && rollup-plugin-visualizer stats-react.json",
"watch:types": "rimraf ./types && tsc --watch --project ./tsconfig.types.json && replace 'import type' 'import' ./types -r --silent && replace 'export type' 'export' ./types -r --silent",
"watch:types": "rimraf './lib/**/*.d.ts' && tsc --watch --project ./tsconfig.types.json",
"now-build": "yarn && cd www && yarn && yarn build",
"prettier": "prettier \"{.,src,src/**,example/src,example/src/**,types}/*.{md,js,jsx,ts,tsx,json}\"",
"start": "yarn watch",
"format": "yarn prettier --write",
"stats": "open ./stats.html"
},
"files": [
"core",
"dist",
"es",
"hydration",
"lib",
"core",
"devtools",
"persistQueryClient",
"createWebStoragePersister",
"createAsyncStoragePersister",
"broadcastQueryClient-experimental",
"lib",
"reactjs",
"scripts",
"types",
"codemods",
"!codemods/jest.config.js",
"!codemods/**/__testfixtures__",
"!codemods/**/__tests__"
],
"dependencies": {
"@babel/runtime": "^7.5.5",
"@babel/runtime": "^7.17.9",
"@types/use-sync-external-store": "^0.0.3",
"broadcast-channel": "^3.4.1",
"match-sorter": "^6.0.2",
Expand All @@ -88,16 +127,18 @@
},
"devDependencies": {
"@babel/cli": "^7.17.6",
"@babel/core": "^7.17.5",
"@babel/core": "^7.17.9",
"@babel/plugin-transform-runtime": "^7.17.0",
"@babel/preset-env": "^7.16.11",
"@babel/preset-react": "^7.16.7",
"@babel/preset-typescript": "^7.16.7",
"@rollup/plugin-replace": "^3.0.0",
"@svgr/rollup": "^6.1.1",
"@rollup/plugin-babel": "^5.3.1",
"@rollup/plugin-commonjs": "21.1.0",
"@rollup/plugin-node-resolve": "^13.2.1",
"@rollup/plugin-replace": "^4.0.0",
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^13.0.0",
"@testing-library/react-17": "npm:@testing-library/react@^12.1.4",
"@testing-library/jest-dom": "^5.14.1",
"@types/jest": "^26.0.4",
"@types/jscodeshift": "^0.11.3",
"@types/node": "^16.11.10",
Expand All @@ -107,6 +148,7 @@
"@typescript-eslint/parser": "^5.6.0",
"babel-eslint": "^10.1.0",
"babel-jest": "^26.0.1",
"babel-plugin-add-import-extension": "^1.6.0",
"bundlewatch": "^0.3.2",
"cross-env": "^7.0.2",
"eslint": "7.x",
Expand Down Expand Up @@ -134,13 +176,8 @@
"react-error-boundary": "^3.1.4",
"replace": "^1.2.0",
"rimraf": "^3.0.2",
"rollup": "^2.68.0",
"rollup-plugin-babel": "^4.4.0",
"rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-jscc": "^2.0.0",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-peer-deps-external": "^2.2.4",
"rollup-plugin-prettier": "^2.2.2",
"rollup": "^2.70.2",
"rollup-plugin-node-externals": "^4.0.0",
"rollup-plugin-size": "^0.2.2",
"rollup-plugin-terser": "^7.0.2",
"rollup-plugin-visualizer": "^5.6.0",
Expand Down
1 change: 1 addition & 0 deletions persistQueryClient/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from '../lib/persistQueryClient'
Loading

0 comments on commit 3fabd41

Please sign in to comment.