Skip to content

Commit

Permalink
Move useSyncExternalStore shim to a nested entrypoint
Browse files Browse the repository at this point in the history
Also renames `useSyncExternalStoreExtra` to
`useSyncExternalStoreWithSelector`.

- 'use-sync-external-store/shim' -> A shim for `useSyncExternalStore`
  that works in React 16 and 17 (any release that supports hooks). The
  module will first check if the built-in React API exists, before
  falling back to the shim.
- 'use-sync-external-store/with-selector' -> An extended version of
  `useSyncExternalStore` that also supports `selector` and `isEqual`
  options. It does _not_ shim `use-sync-external-store`; it composes the
  built-in React API. **Use this if you only support 18+.**
- 'use-sync-external-store/shim/with-selector' -> Same API, but it
  composes `use-sync-external-store/shim` instead. **Use this for
  compataibility with 16 and 17.**
- 'use-sync-external-store' -> Re-exports React's built-in API. Not
  meant to be used. It will warn and direct users to either the shim or
  the built-in API.
  • Loading branch information
acdlite committed Oct 31, 2021
1 parent 9c8161b commit 7f343de
Show file tree
Hide file tree
Showing 28 changed files with 274 additions and 77 deletions.
22 changes: 17 additions & 5 deletions packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ let ReactDOMFizzServer;
let Suspense;
let SuspenseList;
let useSyncExternalStore;
let useSyncExternalStoreExtra;
let useSyncExternalStoreWithSelector;
let PropTypes;
let textCache;
let window;
Expand All @@ -43,11 +43,23 @@ describe('ReactDOMFizzServer', () => {
Stream = require('stream');
Suspense = React.Suspense;
SuspenseList = React.SuspenseList;
useSyncExternalStore = React.unstable_useSyncExternalStore;
useSyncExternalStoreExtra = require('use-sync-external-store/extra')
.useSyncExternalStoreExtra;

PropTypes = require('prop-types');

if (gate(flags => flags.source)) {
// The `with-selector` module composes the main `use-sync-external-store`
// entrypoint. In the compiled artifacts, this is resolved to the `shim`
// implementation by our build config, but when running the tests against
// the source files, we need to tell Jest how to resolve it. Because this
// is a source module, this mock has no affect on the build tests.
jest.mock('use-sync-external-store/src/useSyncExternalStore', () =>
jest.requireActual('react'),
);
}
useSyncExternalStore = React.unstable_useSyncExternalStore;
useSyncExternalStoreWithSelector = require('use-sync-external-store/with-selector')
.useSyncExternalStoreWithSelector;

textCache = new Map();

// Test Environment
Expand Down Expand Up @@ -1767,7 +1779,7 @@ describe('ReactDOMFizzServer', () => {
}

function App() {
const {env} = useSyncExternalStoreExtra(
const {env} = useSyncExternalStoreWithSelector(
subscribe,
getClientSnapshot,
getServerSnapshot,
Expand Down
2 changes: 1 addition & 1 deletion packages/use-sync-external-store/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@

'use strict';

export * from './src/useSyncExternalStore';
export {useSyncExternalStore} from './src/useSyncExternalStore';
7 changes: 0 additions & 7 deletions packages/use-sync-external-store/npm/extra.js

This file was deleted.

7 changes: 0 additions & 7 deletions packages/use-sync-external-store/npm/index.native.js

This file was deleted.

7 changes: 7 additions & 0 deletions packages/use-sync-external-store/npm/shim/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
'use strict';

if (process.env.NODE_ENV === 'production') {
module.exports = require('../cjs/use-sync-external-store-shim.production.min.js');
} else {
module.exports = require('../cjs/use-sync-external-store-shim.development.js');
}
7 changes: 7 additions & 0 deletions packages/use-sync-external-store/npm/shim/index.native.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
'use strict';

if (process.env.NODE_ENV === 'production') {
module.exports = require('../cjs/use-sync-external-store-shim.native.production.min.js');
} else {
module.exports = require('../cjs/use-sync-external-store-shim.native.development.js');
}
7 changes: 7 additions & 0 deletions packages/use-sync-external-store/npm/shim/with-selector.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
'use strict';

if (process.env.NODE_ENV === 'production') {
module.exports = require('../cjs/use-sync-external-store-shim/with-selector.production.min.js');
} else {
module.exports = require('../cjs/use-sync-external-store-shim/with-selector.development.js');
}
7 changes: 7 additions & 0 deletions packages/use-sync-external-store/npm/with-selector.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
'use strict';

if (process.env.NODE_ENV === 'production') {
module.exports = require('./cjs/use-sync-external-store-with-selector.production.min.js');
} else {
module.exports = require('./cjs/use-sync-external-store-with-selector.development.js');
}
4 changes: 3 additions & 1 deletion packages/use-sync-external-store/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
"README.md",
"build-info.json",
"index.js",
"extra.js",
"index.native.js",
"with-selector.js",
"with-selector.native.js",
"shim/",
"cjs/"
],
"license": "MIT",
Expand Down
12 changes: 12 additions & 0 deletions packages/use-sync-external-store/shim/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/

'use strict';

export {useSyncExternalStore} from 'use-sync-external-store/src/useSyncExternalStoreShim';
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@

'use strict';

export * from './src/useSyncExternalStoreClient';
export {useSyncExternalStore} from 'use-sync-external-store/src/useSyncExternalStoreShim';
12 changes: 12 additions & 0 deletions packages/use-sync-external-store/shim/with-selector/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/

'use strict';

export {useSyncExternalStoreWithSelector} from 'use-sync-external-store/src/useSyncExternalStoreWithSelector';
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ let React;
let ReactNoop;
let Scheduler;
let useSyncExternalStore;
let useSyncExternalStoreExtra;
let useSyncExternalStoreWithSelector;
let act;

// This tests the userspace shim of `useSyncExternalStore` in a server-rendering
Expand Down Expand Up @@ -43,18 +43,30 @@ describe('useSyncExternalStore (userspace shim, server rendering)', () => {
return otherExports;
});

jest.mock('use-sync-external-store', () =>
jest.requireActual('use-sync-external-store/index.native'),
jest.mock('use-sync-external-store/shim', () =>
jest.requireActual('use-sync-external-store/shim/index.native'),
);

React = require('react');
ReactNoop = require('react-noop-renderer');
Scheduler = require('scheduler');
act = require('jest-react').act;
useSyncExternalStore = require('use-sync-external-store')

if (gate(flags => flags.source)) {
// The `shim/with-selector` module composes the main
// `use-sync-external-store` entrypoint. In the compiled artifacts, this
// is resolved to the `shim` implementation by our build config, but when
// running the tests against the source files, we need to tell Jest how to
// resolve it. Because this is a source module, this mock has no affect on
// the build tests.
jest.mock('use-sync-external-store/src/useSyncExternalStore', () =>
jest.requireActual('use-sync-external-store/shim'),
);
}
useSyncExternalStore = require('use-sync-external-store/shim')
.useSyncExternalStore;
useSyncExternalStoreExtra = require('use-sync-external-store/extra')
.useSyncExternalStoreExtra;
useSyncExternalStoreWithSelector = require('use-sync-external-store/shim/with-selector')
.useSyncExternalStoreWithSelector;
});

function Text({text}) {
Expand Down Expand Up @@ -130,7 +142,7 @@ describe('useSyncExternalStore (userspace shim, server rendering)', () => {
const store = createExternalStore({a: 0, b: 0});

function A() {
const {a} = useSyncExternalStoreExtra(
const {a} = useSyncExternalStoreWithSelector(
store.subscribe,
store.getState,
null,
Expand All @@ -140,7 +152,7 @@ describe('useSyncExternalStore (userspace shim, server rendering)', () => {
return <Text text={'A' + a} />;
}
function B() {
const {b} = useSyncExternalStoreExtra(
const {b} = useSyncExternalStoreWithSelector(
store.subscribe,
store.getState,
null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
'use strict';

let useSyncExternalStore;
let useSyncExternalStoreExtra;
let useSyncExternalStoreWithSelector;
let React;
let ReactDOM;
let Scheduler;
Expand All @@ -25,11 +25,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
beforeEach(() => {
jest.resetModules();

// Remove the built-in API from the React exports to force the package to
// use the shim.
if (!gate(flags => flags.supportsNativeUseSyncExternalStore)) {
// and the non-variant tests for the shim.
//
// Remove useSyncExternalStore from the React imports so that we use the
// shim instead. Also removing startTransition, since we use that to
// detect outdated 18 alphas that don't yet include useSyncExternalStore.
Expand Down Expand Up @@ -64,10 +60,21 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
// in both concurrent and legacy mode, I'm adding batching here.
act = cb => internalAct(() => ReactDOM.unstable_batchedUpdates(cb));

useSyncExternalStore = require('use-sync-external-store')
if (gate(flags => flags.source)) {
// The `shim/with-selector` module composes the main
// `use-sync-external-store` entrypoint. In the compiled artifacts, this
// is resolved to the `shim` implementation by our build config, but when
// running the tests against the source files, we need to tell Jest how to
// resolve it. Because this is a source module, this mock has no affect on
// the build tests.
jest.mock('use-sync-external-store/src/useSyncExternalStore', () =>
jest.requireActual('use-sync-external-store/shim'),
);
}
useSyncExternalStore = require('use-sync-external-store/shim')
.useSyncExternalStore;
useSyncExternalStoreExtra = require('use-sync-external-store/extra')
.useSyncExternalStoreExtra;
useSyncExternalStoreWithSelector = require('use-sync-external-store/shim/with-selector')
.useSyncExternalStoreWithSelector;
});

function Text({text}) {
Expand Down Expand Up @@ -595,7 +602,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {

function App() {
Scheduler.unstable_yieldValue('App');
const a = useSyncExternalStoreExtra(
const a = useSyncExternalStoreWithSelector(
store.subscribe,
store.getState,
null,
Expand Down Expand Up @@ -632,7 +639,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
const store = createExternalStore({a: 0, b: 0});

function A() {
const {a} = useSyncExternalStoreExtra(
const {a} = useSyncExternalStoreWithSelector(
store.subscribe,
store.getState,
null,
Expand All @@ -642,7 +649,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
return <Text text={'A' + a} />;
}
function B() {
const {b} = useSyncExternalStoreExtra(
const {b} = useSyncExternalStoreWithSelector(
store.subscribe,
store.getState,
null,
Expand Down Expand Up @@ -774,7 +781,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
Scheduler.unstable_yieldValue('Inline selector');
return [...state.items, 'C'];
};
const items = useSyncExternalStoreExtra(
const items = useSyncExternalStoreWithSelector(
store.subscribe,
store.getState,
null,
Expand Down Expand Up @@ -842,7 +849,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
const selector = state => state.a.toUpperCase();

function App() {
const a = useSyncExternalStoreExtra(
const a = useSyncExternalStoreWithSelector(
store.subscribe,
store.getState,
null,
Expand Down Expand Up @@ -877,7 +884,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
const isEqual = (left, right) => left.a.trim() === right.a.trim();

function App() {
const a = useSyncExternalStoreExtra(
const a = useSyncExternalStoreWithSelector(
store.subscribe,
store.getState,
null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ describe('useSyncExternalStore (userspace shim, server rendering)', () => {
ReactDOMServer = require('react-dom/server');
Scheduler = require('scheduler');

useSyncExternalStore = require('use-sync-external-store')
useSyncExternalStore = require('use-sync-external-store/shim')
.useSyncExternalStore;
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,4 @@
* @flow
*/

'use strict';

export * from './src/useSyncExternalStoreExtra';
export const isServerEnvironment = false;
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/

'use strict';

// Intentionally not using named imports because Rollup uses dynamic
// dispatch for CommonJS interop named imports.
import * as React from 'react';

export const useSyncExternalStore = React.unstable_useSyncExternalStore;
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/

'use strict';

// Intentionally not using named imports because Rollup uses dynamic
// dispatch for CommonJS interop named imports.
import * as shim from 'use-sync-external-store/shim';

export const useSyncExternalStore = shim.useSyncExternalStore;
12 changes: 12 additions & 0 deletions packages/use-sync-external-store/src/isServerEnvironment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/

import {canUseDOM} from 'shared/ExecutionEnvironment';

export const isServerEnvironment = !canUseDOM;
Loading

0 comments on commit 7f343de

Please sign in to comment.