You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
370 lines
12 KiB
370 lines
12 KiB
"use strict";
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
exports.INTERNAL_CALLSITES_REGEX = exports.EXPO_DEBUG = void 0;
|
|
exports.getDefaultConfig = getDefaultConfig;
|
|
exports.loadAsync = loadAsync;
|
|
|
|
function _config() {
|
|
const data = require("@expo/config");
|
|
|
|
_config = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _paths() {
|
|
const data = require("@expo/config/paths");
|
|
|
|
_paths = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _chalk() {
|
|
const data = _interopRequireDefault(require("chalk"));
|
|
|
|
_chalk = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _getenv() {
|
|
const data = require("getenv");
|
|
|
|
_getenv = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _path() {
|
|
const data = _interopRequireDefault(require("path"));
|
|
|
|
_path = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _resolveFrom() {
|
|
const data = _interopRequireDefault(require("resolve-from"));
|
|
|
|
_resolveFrom = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _url() {
|
|
const data = require("url");
|
|
|
|
_url = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _getModulesPaths() {
|
|
const data = require("./getModulesPaths");
|
|
|
|
_getModulesPaths = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _getWatchFolders() {
|
|
const data = require("./getWatchFolders");
|
|
|
|
_getWatchFolders = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _importMetroFromProject() {
|
|
const data = require("./importMetroFromProject");
|
|
|
|
_importMetroFromProject = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
|
|
// Copyright 2021-present 650 Industries (Expo). All rights reserved.
|
|
const EXPO_DEBUG = (0, _getenv().boolish)('EXPO_DEBUG', false);
|
|
exports.EXPO_DEBUG = EXPO_DEBUG;
|
|
const EXPO_USE_EXOTIC = (0, _getenv().boolish)('EXPO_USE_EXOTIC', false); // Import only the types here, the values will be imported from the project, at runtime.
|
|
|
|
const INTERNAL_CALLSITES_REGEX = new RegExp(['/Libraries/Renderer/implementations/.+\\.js$', '/Libraries/BatchedBridge/MessageQueue\\.js$', '/Libraries/YellowBox/.+\\.js$', '/Libraries/LogBox/.+\\.js$', '/Libraries/Core/Timers/.+\\.js$', 'node_modules/react-devtools-core/.+\\.js$', 'node_modules/react-refresh/.+\\.js$', 'node_modules/scheduler/.+\\.js$', // Metro replaces `require()` with a different method,
|
|
// we want to omit this method from the stack trace.
|
|
// This is akin to most React tooling.
|
|
'/metro/.*/polyfills/require.js$', // Hide frames related to a fast refresh.
|
|
'/metro/.*/lib/bundle-modules/.+\\.js$', 'node_modules/react-native/Libraries/Utilities/HMRClient.js$', 'node_modules/eventemitter3/index.js', 'node_modules/event-target-shim/dist/.+\\.js$', // Ignore the log forwarder used in the expo package.
|
|
'/expo/build/logs/RemoteConsole.js$', // Improve errors thrown by invariant (ex: `Invariant Violation: "main" has not been registered`).
|
|
'node_modules/invariant/.+\\.js$', // Remove babel runtime additions
|
|
'node_modules/regenerator-runtime/.+\\.js$', // Remove react native setImmediate ponyfill
|
|
'node_modules/promise/setimmediate/.+\\.js$', // Babel helpers that implement language features
|
|
'node_modules/@babel/runtime/.+\\.js$', // Hide Hermes internal bytecode
|
|
'/InternalBytecode/InternalBytecode\\.js$', // Block native code invocations
|
|
`\\[native code\\]`].join('|'));
|
|
exports.INTERNAL_CALLSITES_REGEX = INTERNAL_CALLSITES_REGEX;
|
|
|
|
function isUrl(value) {
|
|
try {
|
|
// eslint-disable-next-line no-new
|
|
new (_url().URL)(value);
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
function readIsLegacyImportsEnabled(projectRoot) {
|
|
const config = (0, _config().getConfig)(projectRoot, {
|
|
skipSDKVersionRequirement: true
|
|
});
|
|
return (0, _config().isLegacyImportsEnabled)(config.exp);
|
|
}
|
|
|
|
function getProjectBabelConfigFile(projectRoot) {
|
|
return _resolveFrom().default.silent(projectRoot, './babel.config.js') || _resolveFrom().default.silent(projectRoot, './.babelrc') || _resolveFrom().default.silent(projectRoot, './.babelrc.js');
|
|
}
|
|
|
|
function getAssetPlugins(projectRoot) {
|
|
const assetPlugins = [];
|
|
let hashAssetFilesPath;
|
|
|
|
try {
|
|
hashAssetFilesPath = (0, _resolveFrom().default)(projectRoot, 'expo-asset/tools/hashAssetFiles');
|
|
} catch {// TODO: we should warn/throw an error if the user has expo-updates installed but does not
|
|
// have hashAssetFiles available, or if the user is in managed workflow and does not have
|
|
// hashAssetFiles available. but in a bare app w/o expo-updates, just using dev-client,
|
|
// it is not needed
|
|
}
|
|
|
|
if (hashAssetFilesPath) {
|
|
assetPlugins.push(hashAssetFilesPath);
|
|
}
|
|
|
|
return assetPlugins;
|
|
}
|
|
|
|
let hasWarnedAboutExotic = false;
|
|
|
|
function getDefaultConfig(projectRoot, options = {}) {
|
|
const isExotic = options.mode === 'exotic' || EXPO_USE_EXOTIC;
|
|
|
|
if (isExotic && !hasWarnedAboutExotic) {
|
|
hasWarnedAboutExotic = true;
|
|
console.log(_chalk().default.gray(`\u203A Unstable feature ${_chalk().default.bold`EXPO_USE_EXOTIC`} is enabled. Bundling may not work as expected, and is subject to breaking changes.`));
|
|
}
|
|
|
|
const MetroConfig = (0, _importMetroFromProject().importMetroConfigFromProject)(projectRoot);
|
|
|
|
const reactNativePath = _path().default.dirname((0, _resolveFrom().default)(projectRoot, 'react-native/package.json'));
|
|
|
|
try {
|
|
// Set the `EXPO_METRO_CACHE_KEY_VERSION` variable for use in the custom babel transformer.
|
|
// This hack is used because there doesn't appear to be anyway to resolve
|
|
// `babel-preset-fbjs` relative to the project root later (in `metro-expo-babel-transformer`).
|
|
const babelPresetFbjsPath = (0, _resolveFrom().default)(projectRoot, 'babel-preset-fbjs/package.json');
|
|
process.env.EXPO_METRO_CACHE_KEY_VERSION = String(require(babelPresetFbjsPath).version);
|
|
} catch {// noop -- falls back to a hardcoded value.
|
|
}
|
|
|
|
const isLegacy = readIsLegacyImportsEnabled(projectRoot); // Deprecated -- SDK 41 --
|
|
|
|
if (options.target) {
|
|
if (!isLegacy) {
|
|
console.warn(_chalk().default.yellow(`The target option is deprecated. Learn more: http://expo.fyi/expo-extension-migration`));
|
|
delete options.target;
|
|
}
|
|
} else if (process.env.EXPO_TARGET) {
|
|
console.error('EXPO_TARGET is deprecated. Learn more: http://expo.fyi/expo-extension-migration');
|
|
|
|
if (isLegacy) {
|
|
// EXPO_TARGET is used by @expo/metro-config to determine the target when getDefaultConfig is
|
|
// called from metro.config.js.
|
|
// @ts-ignore
|
|
options.target = process.env.EXPO_TARGET;
|
|
}
|
|
} else if (isLegacy) {
|
|
// Fall back to guessing based on the project structure in legacy mode.
|
|
options.target = (0, _config().getDefaultTarget)(projectRoot);
|
|
}
|
|
|
|
if (!options.target) {
|
|
// Default to bare -- no .expo extension.
|
|
options.target = 'bare';
|
|
} // End deprecated -- SDK 41 --
|
|
|
|
|
|
const {
|
|
target
|
|
} = options;
|
|
|
|
if (!(target === 'managed' || target === 'bare')) {
|
|
throw new Error(`Invalid target: '${target}'. Debug info: \n${JSON.stringify({
|
|
'options.target': options.target,
|
|
default: (0, _config().getDefaultTarget)(projectRoot)
|
|
}, null, 2)}`);
|
|
}
|
|
|
|
const sourceExtsConfig = {
|
|
isTS: true,
|
|
isReact: true,
|
|
isModern: false
|
|
};
|
|
const sourceExts = target === 'bare' ? (0, _paths().getBareExtensions)([], sourceExtsConfig) : (0, _paths().getManagedExtensions)([], sourceExtsConfig);
|
|
|
|
if (isExotic) {
|
|
// Add support for cjs (without platform extensions).
|
|
sourceExts.push('cjs');
|
|
}
|
|
|
|
const babelConfigPath = getProjectBabelConfigFile(projectRoot);
|
|
const isCustomBabelConfigDefined = !!babelConfigPath;
|
|
const resolverMainFields = []; // Disable `react-native` in exotic mode, since library authors
|
|
// use it to ship raw application code to the project.
|
|
|
|
if (!isExotic) {
|
|
resolverMainFields.push('react-native');
|
|
}
|
|
|
|
resolverMainFields.push('browser', 'main');
|
|
const watchFolders = (0, _getWatchFolders().getWatchFolders)(projectRoot); // TODO: nodeModulesPaths does not work with the new Node.js package.json exports API, this causes packages like uuid to fail. Disabling for now.
|
|
|
|
const nodeModulesPaths = (0, _getModulesPaths().getModulesPaths)(projectRoot);
|
|
|
|
if (EXPO_DEBUG) {
|
|
console.log();
|
|
console.log(`Expo Metro config:`);
|
|
|
|
try {
|
|
console.log(`- Version: ${require('../package.json').version}`);
|
|
} catch {}
|
|
|
|
console.log(`- Bundler target: ${target}`);
|
|
console.log(`- Legacy: ${isLegacy}`);
|
|
console.log(`- Extensions: ${sourceExts.join(', ')}`);
|
|
console.log(`- React Native: ${reactNativePath}`);
|
|
console.log(`- Babel config: ${babelConfigPath || 'babel-preset-expo (default)'}`);
|
|
console.log(`- Resolver Fields: ${resolverMainFields.join(', ')}`);
|
|
console.log(`- Watch Folders: ${watchFolders.join(', ')}`);
|
|
console.log(`- Node Module Paths: ${nodeModulesPaths.join(', ')}`);
|
|
console.log(`- Exotic: ${isExotic}`);
|
|
console.log();
|
|
}
|
|
|
|
const {
|
|
// Remove the default reporter which metro always resolves to be the react-native-community/cli reporter.
|
|
// This prints a giant React logo which is less accessible to users on smaller terminals.
|
|
reporter,
|
|
...metroDefaultValues
|
|
} = MetroConfig.getDefaultConfig.getDefaultValues(projectRoot); // Merge in the default config from Metro here, even though loadConfig uses it as defaults.
|
|
// This is a convenience for getDefaultConfig use in metro.config.js, e.g. to modify assetExts.
|
|
|
|
return MetroConfig.mergeConfig(metroDefaultValues, {
|
|
watchFolders,
|
|
resolver: {
|
|
resolverMainFields,
|
|
platforms: ['ios', 'android', 'native', 'testing'],
|
|
assetExts: metroDefaultValues.resolver.assetExts.filter(assetExt => !sourceExts.includes(assetExt)),
|
|
sourceExts,
|
|
nodeModulesPaths
|
|
},
|
|
serializer: {
|
|
getModulesRunBeforeMainModule: () => [require.resolve(_path().default.join(reactNativePath, 'Libraries/Core/InitializeCore')) // TODO: Bacon: load Expo side-effects
|
|
],
|
|
getPolyfills: () => require(_path().default.join(reactNativePath, 'rn-get-polyfills'))()
|
|
},
|
|
server: {
|
|
port: Number(process.env.RCT_METRO_PORT) || 8081
|
|
},
|
|
symbolicator: {
|
|
customizeFrame: frame => {
|
|
if (frame.file && isUrl(frame.file)) {
|
|
return { ...frame,
|
|
// HACK: This prevents Metro from attempting to read the invalid file URL it sent us.
|
|
lineNumber: null,
|
|
column: null,
|
|
// This prevents the invalid frame from being shown by default.
|
|
collapse: true
|
|
};
|
|
}
|
|
|
|
let collapse = Boolean(frame.file && INTERNAL_CALLSITES_REGEX.test(frame.file));
|
|
|
|
if (!collapse) {
|
|
var _frame$file;
|
|
|
|
// This represents the first frame of the stacktrace.
|
|
// Often this looks like: `__r(0);`.
|
|
// The URL will also be unactionable in the app and therefore not very useful to the developer.
|
|
if (frame.column === 3 && frame.methodName === 'global code' && (_frame$file = frame.file) !== null && _frame$file !== void 0 && _frame$file.match(/^https?:\/\//g)) {
|
|
collapse = true;
|
|
}
|
|
}
|
|
|
|
return { ...(frame || {}),
|
|
collapse
|
|
};
|
|
}
|
|
},
|
|
transformer: {
|
|
// `require.context` support
|
|
unstable_allowRequireContext: true,
|
|
allowOptionalDependencies: true,
|
|
babelTransformerPath: isExotic ? require.resolve('./transformer/metro-expo-exotic-babel-transformer') : isCustomBabelConfigDefined ? // If the user defined a babel config file in their project,
|
|
// then use the default transformer.
|
|
// Try to use the project copy before falling back on the global version
|
|
_resolveFrom().default.silent(projectRoot, 'metro-react-native-babel-transformer') : // Otherwise, use a custom transformer that uses `babel-preset-expo` by default for projects.
|
|
require.resolve('./transformer/metro-expo-babel-transformer'),
|
|
assetRegistryPath: 'react-native/Libraries/Image/AssetRegistry',
|
|
assetPlugins: getAssetPlugins(projectRoot)
|
|
}
|
|
});
|
|
}
|
|
|
|
async function loadAsync(projectRoot, {
|
|
reporter,
|
|
target,
|
|
...metroOptions
|
|
} = {}) {
|
|
let defaultConfig = getDefaultConfig(projectRoot, {
|
|
target
|
|
});
|
|
|
|
if (reporter) {
|
|
defaultConfig = { ...defaultConfig,
|
|
reporter
|
|
};
|
|
}
|
|
|
|
const MetroConfig = (0, _importMetroFromProject().importMetroConfigFromProject)(projectRoot);
|
|
return await MetroConfig.loadConfig({
|
|
cwd: projectRoot,
|
|
projectRoot,
|
|
...metroOptions
|
|
}, defaultConfig);
|
|
}
|
|
//# sourceMappingURL=ExpoMetroConfig.js.map
|