mirror of
https://github.com/react/react-native.git
synced 2026-09-28 13:23:09 +08:00
Expose 'react-native/setup-env' to replace InitializeCore (#57461)
Summary: Pull Request resolved: https://github.com/react/react-native/pull/57461 Replace `'react-native/Libraries/Core/InitializeCore'` with an explicit `'react-native/setup-env'` secondary export. This was previously a special-case path excluded from our ESLint warnings. It is now formalised. **Changes** - Add new `src/setup-env.js` entry point and `package.json` mapping. - Replace references in `packages/metro-config/` and `packages/community-cli-plugin/`. - Update `warn-on-deep-imports` ESLint rule. Changelog: [General][Added] - Add `'react-native/setup-env'` entry point. This replaces the previous side-effectful `'react-native/Libraries/Core/InitializeCore'`. [General][Deprecated] - Deprecate `'react-native/Libraries/Core/InitializeCore'`. Use `'react-native/setup-env'` instead. Reviewed By: rubennorte Differential Revision: D110890810 fbshipit-source-id: 3afe25efa45548d593a1b09c436e36038350b4c5
This commit is contained in:
committed by
meta-codesync[bot]
parent
857c3d24c1
commit
554baba159
@@ -56,6 +56,7 @@ experimental.multi_platform.extensions=.android
|
||||
munge_underscores=true
|
||||
|
||||
module.name_mapper='^react-native$' -> '<PROJECT_ROOT>/packages/react-native/index.js'
|
||||
module.name_mapper='^react-native/setup-env$' -> '<PROJECT_ROOT>/packages/react-native/src/setup-env.js'
|
||||
module.name_mapper='^react-native/\(.*\)$' -> '<PROJECT_ROOT>/packages/react-native/\1'
|
||||
module.name_mapper='^@react-native/dev-middleware$' -> '<PROJECT_ROOT>/packages/dev-middleware'
|
||||
module.name_mapper='^@?[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\|xml\|ktx\|heic\|heif\)$' -> '<PROJECT_ROOT>/packages/react-native/Libraries/Image/RelativeImageStub'
|
||||
|
||||
@@ -60,16 +60,17 @@ function getCommunityCliDefaultConfig(
|
||||
return {
|
||||
resolver,
|
||||
serializer: {
|
||||
// We can include multiple copies of InitializeCore here because metro will
|
||||
// We can include multiple copies of setup-env here because Metro will
|
||||
// only add ones that are already part of the bundle
|
||||
getModulesRunBeforeMainModule: () => [
|
||||
require.resolve(
|
||||
path.join(ctx.reactNativePath, 'Libraries/Core/InitializeCore'),
|
||||
{paths: [ctx.root]},
|
||||
),
|
||||
// NOTE: ctx.reactNativePath is an absolute path, therefore we need to
|
||||
// reference setup-env.js here by exact path specifier.
|
||||
require.resolve(path.join(ctx.reactNativePath, 'src/setup-env.js'), {
|
||||
paths: [ctx.root],
|
||||
}),
|
||||
...outOfTreePlatforms.map(platform =>
|
||||
require.resolve(
|
||||
`${ctx.platforms[platform].npmPackageName}/Libraries/Core/InitializeCore`,
|
||||
`${ctx.platforms[platform].npmPackageName}/setup-env`,
|
||||
{paths: [ctx.root]},
|
||||
),
|
||||
),
|
||||
|
||||
@@ -29,10 +29,10 @@ eslintTester.run('../no-deep-imports', rule, {
|
||||
"import Foo from 'react-native-foo';",
|
||||
"import Foo from 'react-native-foo/Foo';",
|
||||
"import Foo from 'react/native/Foo';",
|
||||
"import 'react-native/Libraries/Core/InitializeCore';",
|
||||
"require('react-native/Libraries/Core/InitializeCore');",
|
||||
"import Foo from 'react-native/src/fb_internal/Foo'",
|
||||
"require('react-native/src/fb_internal/Foo')",
|
||||
"import 'react-native/setup-env';",
|
||||
"require('react-native/setup-env');",
|
||||
],
|
||||
invalid: [
|
||||
{
|
||||
@@ -125,5 +125,31 @@ eslintTester.run('../no-deep-imports', rule, {
|
||||
],
|
||||
output: null,
|
||||
},
|
||||
{
|
||||
code: "import 'react-native/Libraries/Core/InitializeCore';",
|
||||
errors: [
|
||||
{
|
||||
messageId: 'useReplacementSource',
|
||||
data: {
|
||||
importPath: 'react-native/Libraries/Core/InitializeCore',
|
||||
replacementSource: 'react-native/setup-env',
|
||||
},
|
||||
},
|
||||
],
|
||||
output: "import 'react-native/setup-env';",
|
||||
},
|
||||
{
|
||||
code: "require('react-native/Libraries/Core/InitializeCore');",
|
||||
errors: [
|
||||
{
|
||||
messageId: 'useReplacementSource',
|
||||
data: {
|
||||
importPath: 'react-native/Libraries/Core/InitializeCore',
|
||||
replacementSource: 'react-native/setup-env',
|
||||
},
|
||||
},
|
||||
],
|
||||
output: "require('react-native/setup-env');",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
@@ -21,6 +21,8 @@ module.exports = {
|
||||
messages: {
|
||||
deepImport:
|
||||
"'{{importPath}}' React Native deep imports are deprecated. Please use the top level import instead.",
|
||||
useReplacementSource:
|
||||
"'{{importPath}}' is deprecated. Please import '{{replacementSource}}' instead.",
|
||||
},
|
||||
schema: [],
|
||||
fixable: 'code',
|
||||
@@ -31,12 +33,14 @@ module.exports = {
|
||||
ImportDeclaration(node) {
|
||||
if (
|
||||
!isDeepReactNativeImport(node.source) ||
|
||||
isInitializeCoreImport(node.source) ||
|
||||
isSecondaryEntryPoint(node.source) ||
|
||||
isFbInternalImport(node.source)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (reportReplacementSource(node.source)) {
|
||||
return;
|
||||
}
|
||||
if (isDefaultImport(node)) {
|
||||
const reactNativeSource = node.source.value.slice(
|
||||
'react-native/'.length,
|
||||
@@ -88,13 +92,16 @@ module.exports = {
|
||||
CallExpression(node) {
|
||||
if (
|
||||
!isDeepRequire(node) ||
|
||||
isInitializeCoreImport(node.arguments[0]) ||
|
||||
isSecondaryEntryPoint(node.arguments[0]) ||
|
||||
isFbInternalImport(node.arguments[0])
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (reportReplacementSource(node.arguments[0])) {
|
||||
return;
|
||||
}
|
||||
|
||||
const parent = node.parent;
|
||||
const importPath = node.arguments[0].value;
|
||||
|
||||
@@ -123,6 +130,26 @@ module.exports = {
|
||||
},
|
||||
};
|
||||
|
||||
function reportReplacementSource(source) {
|
||||
const reactNativeSource = source.value.slice('react-native/'.length);
|
||||
const mapping = publicAPIMapping[reactNativeSource];
|
||||
if (!mapping || !mapping.replacementSource) {
|
||||
return false;
|
||||
}
|
||||
context.report({
|
||||
node: source,
|
||||
messageId: 'useReplacementSource',
|
||||
data: {
|
||||
importPath: source.value,
|
||||
replacementSource: mapping.replacementSource,
|
||||
},
|
||||
fix(fixer) {
|
||||
return fixer.replaceText(source, `'${mapping.replacementSource}'`);
|
||||
},
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
function getStandardReport(source) {
|
||||
return {
|
||||
node: source,
|
||||
@@ -167,20 +194,15 @@ module.exports = {
|
||||
return parts.length > 1 && parts[0] === 'react-native';
|
||||
}
|
||||
|
||||
function isInitializeCoreImport(source) {
|
||||
if (source.type !== 'Literal' || typeof source.value !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return source.value === 'react-native/Libraries/Core/InitializeCore';
|
||||
}
|
||||
|
||||
function isSecondaryEntryPoint(source) {
|
||||
if (source.type !== 'Literal' || typeof source.value !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return source.value === 'react-native/asset-registry';
|
||||
return (
|
||||
source.value === 'react-native/asset-registry' ||
|
||||
source.value === 'react-native/setup-env'
|
||||
);
|
||||
}
|
||||
|
||||
function isFbInternalImport(source) {
|
||||
|
||||
@@ -37,6 +37,13 @@ const publicAPIMapping = {
|
||||
default: 'experimental_LayoutConformance',
|
||||
types: ['LayoutConformanceProps'],
|
||||
},
|
||||
'Libraries/Core/InitializeCore': {
|
||||
// `InitializeCore` has no public named export; the deep import must be
|
||||
// swapped for the `react-native/setup-env` entry point entirely.
|
||||
default: null,
|
||||
types: null,
|
||||
replacementSource: 'react-native/setup-env',
|
||||
},
|
||||
'Libraries/Lists/FlatList': {
|
||||
default: 'FlatList',
|
||||
types: ['FlatListProps'],
|
||||
|
||||
@@ -18,6 +18,11 @@ module.exports = {
|
||||
platforms: ['android', 'ios', 'native'],
|
||||
},
|
||||
moduleNameMapper: {
|
||||
// `setup-env` is a secondary entry point exposed via the package's
|
||||
// `exports`, but `./jest/resolver.js` strips `exports` and the generic
|
||||
// mapper below resolves subpaths as literal directory paths. Alias it
|
||||
// explicitly so it resolves to its `src/` implementation.
|
||||
'^react-native/setup-env$': `${path.dirname(require.resolve('react-native'))}/src/setup-env.js`,
|
||||
'^react-native($|/.*)': `${path.dirname(require.resolve('react-native'))}/$1`,
|
||||
},
|
||||
resolver: require.resolve('./jest/resolver.js'),
|
||||
|
||||
@@ -133,6 +133,7 @@ mock(
|
||||
'm#react-native/Libraries/Core/InitializeCore',
|
||||
'm#./mocks/InitializeCore',
|
||||
);
|
||||
mock('m#react-native/setup-env', 'm#./mocks/InitializeCore');
|
||||
mock('m#react-native/Libraries/Core/NativeExceptionsManager');
|
||||
mock('m#react-native/Libraries/Image/Image', 'm#./mocks/Image');
|
||||
mock(
|
||||
|
||||
@@ -61,7 +61,7 @@ export function getDefaultConfig(projectRoot: string): ConfigT {
|
||||
serializer: {
|
||||
// Note: This option is overridden in cli-plugin-metro (getOverrideConfig)
|
||||
getModulesRunBeforeMainModule: () => [
|
||||
require.resolve('react-native/Libraries/Core/InitializeCore'),
|
||||
require.resolve('react-native/setup-env'),
|
||||
],
|
||||
getPolyfills: () => require('@react-native/js-polyfills')(),
|
||||
isThirdPartyModule({path: modulePath}: Readonly<{path: string, ...}>) {
|
||||
|
||||
-14
@@ -82,17 +82,3 @@ test('import from other package', () => {
|
||||
`"import { foo } from 'react-native-foo';"`,
|
||||
);
|
||||
});
|
||||
|
||||
test('import react-native/Libraries/Core/InitializeCore', () => {
|
||||
const code = `
|
||||
import 'react-native/Libraries/Core/InitializeCore';
|
||||
require('react-native/Libraries/Core/InitializeCore');
|
||||
export * from 'react-native/Libraries/Core/InitializeCore';
|
||||
`;
|
||||
|
||||
expect(transform(code, [rnDeepImportsWarningPlugin])).toMatchInlineSnapshot(`
|
||||
"import 'react-native/Libraries/Core/InitializeCore';
|
||||
require('react-native/Libraries/Core/InitializeCore');
|
||||
export * from 'react-native/Libraries/Core/InitializeCore';"
|
||||
`);
|
||||
});
|
||||
|
||||
@@ -38,10 +38,6 @@ function isDeepReactNativeImport(source) {
|
||||
return parts.length > 1 && parts[0] === 'react-native';
|
||||
}
|
||||
|
||||
function isInitializeCoreImport(source) {
|
||||
return source === 'react-native/Libraries/Core/InitializeCore';
|
||||
}
|
||||
|
||||
function withLocation(node, loc) {
|
||||
if (!node.loc) {
|
||||
return {...node, loc};
|
||||
@@ -55,7 +51,7 @@ module.exports = ({types: t}) => ({
|
||||
ImportDeclaration(path, state) {
|
||||
const source = path.node.source.value;
|
||||
|
||||
if (isDeepReactNativeImport(source) && !isInitializeCoreImport(source)) {
|
||||
if (isDeepReactNativeImport(source)) {
|
||||
const loc = path.node.loc;
|
||||
state.import.push({source, loc});
|
||||
}
|
||||
@@ -71,10 +67,7 @@ module.exports = ({types: t}) => ({
|
||||
) {
|
||||
const source =
|
||||
args[0].node.type === 'StringLiteral' ? args[0].node.value : '';
|
||||
if (
|
||||
isDeepReactNativeImport(source) &&
|
||||
!isInitializeCoreImport(source)
|
||||
) {
|
||||
if (isDeepReactNativeImport(source)) {
|
||||
const loc = path.node.loc;
|
||||
state.require.push({source, loc});
|
||||
}
|
||||
@@ -83,11 +76,7 @@ module.exports = ({types: t}) => ({
|
||||
ExportNamedDeclaration(path, state) {
|
||||
const source = path.node.source;
|
||||
|
||||
if (
|
||||
source &&
|
||||
isDeepReactNativeImport(source.value) &&
|
||||
!isInitializeCoreImport(source)
|
||||
) {
|
||||
if (source && isDeepReactNativeImport(source.value)) {
|
||||
const loc = path.node.loc;
|
||||
state.export.push({source: source.value, loc});
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
* 1. Require system.
|
||||
* 2. Bridged modules.
|
||||
*
|
||||
* @deprecated Since 0.87. Use `'react-native/setup-env'` instead.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
"types": null,
|
||||
"default": "./src/asset-registry.js"
|
||||
},
|
||||
"./setup-env": "./src/setup-env.js",
|
||||
"./jest-preset": "./jest-preset.js",
|
||||
"./rn-get-polyfills": "./rn-get-polyfills.js",
|
||||
"./src/fb_internal/*": "./src/fb_internal/*",
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@
|
||||
'use strict';
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Secondary react-native/asset-registry entry point.
|
||||
// react-native/asset-registry
|
||||
//
|
||||
// This is an untyped secondary entry point intended to be referenced from
|
||||
// Metro's `transformer.assetRegistryPath` config option. This entry point may
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
'use client';
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// react-native/setup-env
|
||||
//
|
||||
// Side-effectful module that sets up the core React Native JavaScript
|
||||
// environment. This includes global timers (`setTimeout` etc), the global
|
||||
// `console` object, and hooks for printing stack traces with source maps.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
require('./private/setup/setUpDefaultReactNativeEnvironment').default();
|
||||
@@ -10,7 +10,8 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
require('react-native/Libraries/Core/InitializeCore');
|
||||
require('react-native/setup-env');
|
||||
|
||||
const React = require('react');
|
||||
const ReactNative = require('react-native');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user