react/scripts/rollup/modules.js
Brian Vaughn 824d22c9d9 Prevent fiber from leaking into RN stack renderer (#9775)
Since stripEnvVariables was used to replace __DEV__ references, I assumed it (and other plugins) we run before requires statements were processed. Obviously I was wrong 😬 and as a result, the RN Stack and Fiber builds were way too large. This is an attempt to mimic the approach taken with DOM renderer and stub out modules that we explicitly don't want to include.

The alternative to this would have been to fork findNodeHandle, NativeMethodsMixin, ReactNativeBaseComponent, etc. and essentially avoid using the feature flag. That didn't seem tenable. The previous injection approach also doesn't work here because the circular references it resulted in caused Rollup to choke when creating the modules.
2017-05-25 18:14:46 +01:00

315 lines
8.4 KiB
JavaScript

'use strict';
const resolve = require('path').resolve;
const basename = require('path').basename;
const sync = require('glob').sync;
const bundleTypes = require('./bundles').bundleTypes;
const extractErrorCodes = require('../error-codes/extract-errors');
const exclude = [
'src/**/__benchmarks__/**/*.js',
'src/**/__tests__/**/*.js',
'src/**/__mocks__/**/*.js',
];
const UMD_DEV = bundleTypes.UMD_DEV;
const UMD_PROD = bundleTypes.UMD_PROD;
const NODE_DEV = bundleTypes.NODE_DEV;
const NODE_PROD = bundleTypes.NODE_PROD;
const FB_DEV = bundleTypes.FB_DEV;
const FB_PROD = bundleTypes.FB_PROD;
const RN_DEV = bundleTypes.RN_DEV;
const RN_PROD = bundleTypes.RN_PROD;
const errorCodeOpts = {
errorMapFilePath: 'scripts/error-codes/codes.json',
};
// these are the FBJS modules that are used throughout our bundles
const fbjsModules = [
'fbjs/lib/warning',
'fbjs/lib/invariant',
'fbjs/lib/emptyFunction',
'fbjs/lib/emptyObject',
'fbjs/lib/hyphenateStyleName',
'fbjs/lib/getUnboundedScrollPosition',
'fbjs/lib/camelizeStyleName',
'fbjs/lib/containsNode',
'fbjs/lib/shallowEqual',
'fbjs/lib/getActiveElement',
'fbjs/lib/focusNode',
'fbjs/lib/EventListener',
'fbjs/lib/memoizeStringOnly',
'fbjs/lib/ExecutionEnvironment',
'fbjs/lib/createNodesFromMarkup',
'fbjs/lib/performanceNow',
];
const devOnlyFilesToStubOut = [
"'ReactDebugCurrentFrame'",
"'ReactComponentTreeHook'",
"'ReactPerf'",
"'ReactTestUtils'",
];
const legacyModules = [
'create-react-class',
'create-react-class/factory',
'prop-types',
'prop-types/checkPropTypes',
];
// this function builds up a very niave Haste-like moduleMap
// that works to create up an alias map for modules to link
// up to their actual disk location so Rollup can properly
// bundle them
function createModuleMap(paths, extractErrors, bundleType) {
const moduleMap = {};
paths.forEach(path => {
const files = sync(path, {ignore: exclude});
files.forEach(file => {
if (extractErrors) {
extractErrors(file);
}
const moduleName = basename(file, '.js');
moduleMap[moduleName] = resolve(file);
});
});
// if this is FB, we want to remove ReactCurrentOwner, so we can
// handle it with a different case
if (bundleType === FB_DEV || bundleType === FB_PROD) {
delete moduleMap.ReactCurrentOwner;
}
return moduleMap;
}
function getNodeModules(bundleType) {
// rather than adding the rollup node resolve plugin,
// we can instead deal with the only node module that is used
// for UMD bundles - object-assign
switch (bundleType) {
case UMD_DEV:
case UMD_PROD:
return {
'object-assign': resolve('./node_modules/object-assign/index.js'),
// include the ART package modules directly by aliasing them from node_modules
'art/modes/current': resolve('./node_modules/art/modes/current.js'),
'art/modes/fast-noSideEffects': resolve(
'./node_modules/art/modes/fast-noSideEffects.js'
),
'art/core/transform': resolve('./node_modules/art/core/transform.js'),
};
case NODE_DEV:
case NODE_PROD:
case FB_DEV:
case FB_PROD:
case RN_DEV:
case RN_PROD:
return {};
}
}
function ignoreFBModules() {
return [
// At FB, we don't know them statically:
'ReactFeatureFlags',
'ReactDOMFeatureFlags',
// In FB bundles, we preserve an inline require to ReactCurrentOwner.
// See the explanation in FB version of ReactCurrentOwner in www:
'ReactCurrentOwner',
];
}
function ignoreReactNativeModules() {
return [
// This imports NativeMethodsMixin, causing
// a circular dependency.
'View',
];
}
function getExternalModules(externals, bundleType, isRenderer) {
// external modules tell Rollup that we should not attempt
// to bundle these modules and instead treat them as
// external depedencies to the bundle. so for CJS bundles
// this means having a require("name-of-external-module") at
// the top of the bundle. for UMD bundles this means having
// both a require and a global check for them
let externalModules = externals;
switch (bundleType) {
case UMD_DEV:
case UMD_PROD:
if (isRenderer) {
externalModules.push('react');
}
break;
case NODE_DEV:
case NODE_PROD:
case RN_DEV:
case RN_PROD:
fbjsModules.forEach(module => externalModules.push(module));
externalModules.push('object-assign');
if (isRenderer) {
externalModules.push('react');
}
break;
case FB_DEV:
case FB_PROD:
fbjsModules.forEach(module => externalModules.push(module));
externalModules.push('ReactCurrentOwner');
externalModules.push('lowPriorityWarning');
if (isRenderer) {
externalModules.push('React');
if (externalModules.indexOf('react-dom') > -1) {
externalModules.push('ReactDOM');
}
}
break;
}
return externalModules;
}
function getInternalModules() {
// we tell Rollup where these files are located internally, otherwise
// it doesn't pick them up and assumes they're external
return {
reactProdInvariant: resolve('./src/shared/utils/reactProdInvariant.js'),
};
}
function getFbjsModuleAliases(bundleType) {
switch (bundleType) {
case UMD_DEV:
case UMD_PROD:
// we want to bundle these modules, so we re-alias them to the actual
// file so Rollup can bundle them up
const fbjsModulesAlias = {};
fbjsModules.forEach(fbjsModule => {
fbjsModulesAlias[fbjsModule] = resolve(`./node_modules/${fbjsModule}`);
});
return fbjsModulesAlias;
case NODE_DEV:
case NODE_PROD:
case FB_DEV:
case FB_PROD:
case RN_DEV:
case RN_PROD:
// for FB we don't want to bundle the above modules, instead keep them
// as external require() calls in the bundle
return {};
}
}
function replaceFbjsModuleAliases(bundleType) {
switch (bundleType) {
case FB_DEV:
case FB_PROD:
// Haste at FB doesn't currently allow case sensitive names,
// and product code already uses "React". In the future,
// we will either allow both variants or migrate to lowercase.
return {
"'react'": "'React'",
"'react-dom'": "'ReactDOM'",
};
default:
return {};
}
}
const devOnlyModuleStub = `'${resolve('./scripts/rollup/shims/rollup/DevOnlyStubShim.js')}'`;
function replaceDevOnlyStubbedModules(bundleType) {
switch (bundleType) {
case UMD_DEV:
case NODE_DEV:
case FB_DEV:
case RN_DEV:
case RN_PROD:
return {};
case FB_PROD:
case UMD_PROD:
case NODE_PROD:
const devOnlyModuleAliases = {};
devOnlyFilesToStubOut.forEach(devOnlyModule => {
devOnlyModuleAliases[devOnlyModule] = devOnlyModuleStub;
});
return devOnlyModuleAliases;
}
}
function replaceLegacyModuleAliases(bundleType) {
switch (bundleType) {
case UMD_DEV:
case UMD_PROD:
const modulesAlias = {};
legacyModules.forEach(legacyModule => {
const modulePath = legacyModule.includes('/')
? legacyModule
: `${legacyModule}/index`;
const resolvedPath = resolve(`./node_modules/${modulePath}`);
modulesAlias[`'${legacyModule}'`] = `'${resolvedPath}'`;
});
return modulesAlias;
case NODE_DEV:
case NODE_PROD:
case FB_DEV:
case FB_PROD:
case RN_DEV:
case RN_PROD:
return {};
}
}
function replaceBundleStubModules(bundleModulesToStub) {
const stubbedModules = {};
if (Array.isArray(bundleModulesToStub)) {
bundleModulesToStub.forEach(module => {
stubbedModules[module] = devOnlyModuleStub;
});
}
return stubbedModules;
}
function getAliases(paths, bundleType, isRenderer, extractErrors) {
return Object.assign(
createModuleMap(
paths,
extractErrors && extractErrorCodes(errorCodeOpts),
bundleType
),
getInternalModules(),
getNodeModules(bundleType),
getFbjsModuleAliases(bundleType)
);
}
function getDefaultReplaceModules(bundleType, bundleModulesToStub) {
return Object.assign(
{},
replaceFbjsModuleAliases(bundleType),
replaceDevOnlyStubbedModules(bundleType),
replaceLegacyModuleAliases(bundleType),
replaceBundleStubModules(bundleModulesToStub)
);
}
function getExcludedHasteGlobs() {
return exclude;
}
module.exports = {
getExcludedHasteGlobs,
getDefaultReplaceModules,
getAliases,
ignoreFBModules,
ignoreReactNativeModules,
getExternalModules,
};