Description
This issue tracks commits that rewrite require()
calls to use standard module paths instead of Haste module names. This brings the RN repo closer to how the React repo is set up, and also opens the door for greater compatibility with the last 10 years of tooling that uses path-based module locations, and eliminates the entire class of issues related to the Haste map outside of the Facebook context.
All modules in the RN repository will still be requireable via Haste. That is, if there's Facebook application code that uses Haste, there will be no change.
This is a spiritual continuation of #18598, which has more technical details.
- Let Flow support Haste & Node simultaneously for now (pre-req):
[standards][flow] Set up .flowconfig to support Haste and path-based imports #24318 - RNTester:
[standards] Rewrite imports in RNTester to use standard paths #24317 - RNTester (TurboModules):
[standards] Migrate TurboModule example in RNTester to use path-based requires #24754 - Code under the Libraries directory:
[standards] Migrate "Libraries" from Haste to standard path-based requires (sans vendor & renderers) #24749,[standards] Replace more Haste imports with path-based imports #25001 - IntegrationTests:
[standards] Migrate IntegrationTests from Haste to path-based requires #24750 - Jest setup script:
[standards] Migrate Jest setup scripts from Haste to path-based requires #24753 - androidTest JS:
[standards] Migrate "androidTest" JS from Haste to path-based requires #24813 - Vendored libraries (
[standards] Migrate vendored JS from Haste to path-based imports #24769):[standards] Migrate vendored code from Haste to path-based imports #24807 - React renderers (
[standards] Migrate React renderers from Haste to path-based imports #24770):[standards] ReactPrivate, an explicit interface between the renderer and RN #24782,[react-native] Use path-based imports instead of Haste for the RN renderer react#15604,Sync React with Haste-style imports rewritten to use path-based imports instead #25100,[react-native] Rewrite Haste imports in RN shims and add .fb.js extension react#15786 - react-native-implementation (
[standards] Migrate react-native-implementation.js from Haste to path-based imports #24771) - Lint rule to prevent more Haste:
[lint] Add a lint rule to disallow Haste imports #25058 - Disable Haste outside of Facebook (
Jest hasteImpl, .flowconfig, Metro):[jest] Explicitly separate mocked native modules from mocked JS modules #24809(Jest mocks),[jest] Delete hasteImpl, providesModuleNodeModules, and modulePathNameMapper #24811(Jest hasteImpl),[standards] Make Flow configs use path-based imports instead of Haste #24812(.flowconfig),[breaking] Turn off providesModuleNodeModules by default metro#410(Metro default providesModuleNodeModules)
Draft Announcement Notes
Replacing Haste with standard imports
In the 0.61 release of React Native, we are internally replacing "Haste"-style module imports with standard path-based imports. Instead of require('View')
, React Native will internally use require('./View')
. Haste is a proprietary module system with a global namespace that is used within Facebook. Path-based imports are used by browsers, Node.js, and various tools and libraries in the greater JavaScript ecosystem. Moving to the standard means React Native will be more compatible with the ecosystem. Also, this creates a path to optimize the bundling step, as the bundler no longer needs to scan all files to create the Haste module map.
Some out-of-tree implementations of other platforms, like React Native Windows, may be affected by this change if they rely on overriding files using overlapping Haste module names. There are two potential solutions for maintainers of platforms like this.
Vendoring React Native
One solution is to follow React Native for Web's approach of vendoring (copying) React Native's code into the out-of-tree platform repository. This approach is also more future-proof and works if React Native were to publish itself as a single "flat bundle" in the same manner as React, which would also be a breaking change for out-of-tree platform implementations. It also simplifies the work required if React Native were to rely on the JS interpreter's built-in import/export module system, which does not implement Haste.
React Native for Web's entry point (index.js
) exports web-specific implementations of all the public APIs in React Native. But, sometimes, parts of React Native's code also run on the web without any changes. To share code with React Native, React Native for Web imports the code it vendored from React Native. For example, React Native for Web's implementation of PanResponder
uses React Native's implementation:
import PanResponder from '../../vendor/react-native/PanResponder';
export default PanResponder;
Finally, React Native for Web provides a Babel plugin that rewrites all imports of react-native
in your application code to import react-native-web
instead. For example, import { View } from 'react-native'
is rewritten to import { View } from 'react-native-web'
.
React Native for Web's approach provides stability, as newly published patch versions of React Native -- which may have internal breaking changes despite keeping the public API unchanged -- will not affect the vendored code at all until the maintainer intentionally updates it.
Overriding imports with Babel
Another solution is to write a Babel plugin that rewrites imports to files that need to be overridden. For example, let's say an out-of-tree platform needs to override React Native's View.js
and that the overriding file is under react-native-xx/View.xx.js
. Using a Babel plugin, one can rewrite all imports of React Native's View.js
to instead import react-native-xx/View.xx.js
. This Babel plugin simulates the current behavior of overriding files using Haste.