improved how bundles are built by exposing externals and making the process less "magical", also tidied up code and added more comments

This commit is contained in:
Dominic Gannaway
2017-03-20 14:52:03 +00:00
parent d5b91d36a2
commit 6aa9936529
3 changed files with 173 additions and 62 deletions
+19 -14
View File
@@ -14,13 +14,14 @@ const rimraf = require('rimraf');
const argv = require('minimist')(process.argv.slice(2));
const {
createModuleMap,
getExternalModules,
getNodeModules,
getInternalModules,
replaceInternalModules,
getFbjsModuleAliases,
replaceFbjsModuleAliases,
ignoreFBModules,
ignoreReactNativeModules,
getExternalModules,
} = require('./modules');
const {
bundles,
@@ -31,7 +32,7 @@ function getAliases(paths, bundleType) {
return Object.assign(
createModuleMap(paths),
getInternalModules(bundleType),
getExternalModules(bundleType),
getNodeModules(bundleType),
getFbjsModuleAliases(bundleType)
);
}
@@ -82,7 +83,8 @@ function updateBabelConfig(babelOpts, bundleType) {
function handleRollupWarnings(warning) {
if (warning.code === 'UNRESOLVED_IMPORT') {
return;
console.error(warning.message);
process.exit(1);
}
console.warn(warning.message || warning);
}
@@ -217,6 +219,8 @@ function createBundle({
name,
hasteName,
bundleTypes: bundleTypesToUse,
isRenderer,
externals,
}, bundleType) {
if ((inputBundleType && inputBundleType !== bundleType)
|| bundleTypesToUse.indexOf(bundleType) === -1) {
@@ -227,25 +231,26 @@ function createBundle({
const format = getFormat(bundleType);
return rollup({
entry: bundleType === bundleTypes.FB ? fbEntry : entry,
plugins: getPlugins(entry, babelOpts, paths, filename, bundleType),
external: getExternalModules(externals, bundleType, isRenderer),
onwarn: handleRollupWarnings,
plugins: getPlugins(entry, babelOpts, paths, filename, bundleType),
}).then(({write}) => write(
updateBundleConfig(config, filename, format, bundleType, hasteName)
)).catch(console.error);
)).catch(error => {
console.error(error);
process.exit(1);
});
}
// clear the build folder
rimraf(join('build', 'rollup'), () => {
bundles.forEach(bundle =>
createBundle(bundle, bundleTypes.DEV).then(() =>
createBundle(bundle, bundleTypes.PROD).then(() =>
createBundle(bundle, bundleTypes.NODE).then(() =>
createBundle(bundle, bundleTypes.FB).then(() =>
createBundle(bundle, bundleTypes.RN)
)
)
)
)
Promise.resolve()
.then(() => createBundle(bundle, bundleTypes.DEV))
.then(() => createBundle(bundle, bundleTypes.PROD))
.then(() => createBundle(bundle, bundleTypes.NODE))
.then(() => createBundle(bundle, bundleTypes.FB))
.then(() => createBundle(bundle, bundleTypes.RN))
);
});
+33
View File
@@ -35,8 +35,10 @@ const bundles = [
sourceMap: false,
},
entry: 'src/umd/ReactUMDEntry.js',
externals: [],
fbEntry: 'src/fb/ReactFBEntry.js',
hasteName: 'React-fb',
isRenderer: false,
name: 'react',
paths: [
'src/umd/ReactUMDEntry.js',
@@ -64,8 +66,10 @@ const bundles = [
sourceMap: false,
},
entry: 'src/umd/ReactDOMUMDEntry.js',
externals: [],
fbEntry: 'src/fb/ReactDOMFBEntry.js',
hasteName: 'ReactDOMStack-fb',
isRenderer: true,
name: 'react-dom',
paths: [
'src/umd/ReactDOMUMDEntry.js',
@@ -90,8 +94,10 @@ const bundles = [
sourceMap: false,
},
entry: 'src/renderers/dom/fiber/ReactDOMFiber.js',
externals: [],
fbEntry: 'src/fb/ReactDOMFiberFBEntry.js',
hasteName: 'ReactDOMFiber-fb',
isRenderer: true,
name: 'react-dom-fiber',
paths: [
'src/renderers/dom/**/*.js',
@@ -116,8 +122,10 @@ const bundles = [
sourceMap: false,
},
entry: 'src/umd/ReactDOMServerUMDEntry.js',
externals: [],
fbEntry: 'src/umd/ReactDOMServerUMDEntry.js',
hasteName: 'ReactDOMServerStack',
isRenderer: true,
// TODO: this is taken. Do we change the build task
// to understand react-dom/server?
name: 'react-dom-server',
@@ -146,8 +154,14 @@ const bundles = [
sourceMap: false,
},
entry: 'src/renderers/art/ReactARTStack.js',
externals: [
'art/modes/current',
'art/modes/fast-noSideEffects',
'art/core/transform',
],
fbEntry: 'src/renderers/art/ReactARTStack.js',
hasteName: 'ReactARTStack',
isRenderer: true,
name: 'react-art',
paths: [
// TODO: it relies on ReactDOMFrameScheduling. Need to move to shared/?
@@ -171,8 +185,14 @@ const bundles = [
sourceMap: false,
},
entry: 'src/renderers/art/ReactARTFiber.js',
externals: [
'art/modes/current',
'art/modes/fast-noSideEffects',
'art/core/transform',
],
fbEntry: 'src/renderers/art/ReactARTFiber.js',
hasteName: 'ReactARTFiber',
isRenderer: true,
name: 'react-art',
paths: [
// TODO: it relies on ReactDOMFrameScheduling. Need to move to shared/?
@@ -195,7 +215,20 @@ const bundles = [
sourceMap: false,
},
entry: 'src/renderers/native/ReactNative.js',
externals: [
'InitializeCore',
'RCTEventEmitter',
'UIManager',
'react/lib/ReactComponentTreeHook',
'react/lib/checkPropTypes',
'react/lib/ReactDebugCurrentFrame',
'deepDiffer',
'flattenStyle',
'TextInputState',
'deepFreezeAndThrowOnMutationInDev',
],
hasteName: 'ReactNative',
isRenderer: true,
name: 'react-native-renderer',
paths: [
'src/renderers/native/**/*.js',
+121 -48
View File
@@ -12,6 +12,31 @@ const exclude = [
'src/**/__mocks__/**/*.js',
];
// 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',
];
// 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) {
const moduleMap = {};
@@ -27,7 +52,10 @@ function createModuleMap(paths) {
return moduleMap;
}
function getExternalModules(bundleType) {
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 bundleTypes.DEV:
case bundleTypes.PROD:
@@ -55,6 +83,77 @@ function ignoreFBModules() {
];
}
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 = [];
switch (bundleType) {
case bundleTypes.DEV:
case bundleTypes.PROD:
if (isRenderer) {
externalModules = [
'react',
];
}
break;
case bundleTypes.NODE:
case bundleTypes.RN:
externalModules = [
'object-assign',
'fbjs/lib/warning',
'fbjs/lib/emptyObject',
'fbjs/lib/emptyFunction',
'fbjs/lib/invariant',
'react/lib/ReactCurrentOwner',
];
if (isRenderer) {
externalModules.push(
'react',
'ReactCurrentOwner',
...fbjsModules
);
}
break;
case bundleTypes.FB:
externalModules = [
// note: we don't put "ReactCurrentOwner" in here
// as we we're ignoring it from being processed
// by rollup so it remains inline in the bundle
'warning',
'emptyObject',
'emptyFunction',
'invariant',
];
if (isRenderer) {
const replacedFbModuleAliases = replaceFbjsModuleAliases(bundleType);
const aliases = Object.keys(replacedFbModuleAliases).map(
alias => replacedFbModuleAliases[alias]
);
externalModules.push(
'React',
...aliases
);
}
break;
}
externalModules.push(...externals);
return externalModules;
}
function getCommonInternalModules() {
// we tell Rollup where these files are located internally, otherwise
// it doesn't pick them up and assumes they're external
@@ -105,26 +204,14 @@ function getFbjsModuleAliases(bundleType) {
switch (bundleType) {
case bundleTypes.DEV:
case bundleTypes.PROD:
return {
// we want to bundle these modules, so we re-alias them to the actual
// file so Rollup can bundle them up
'fbjs/lib/warning': resolve('./node_modules/fbjs/lib/warning.js'),
'fbjs/lib/invariant': resolve('./node_modules/fbjs/lib/invariant.js'),
'fbjs/lib/emptyFunction': resolve('./node_modules/fbjs/lib/emptyFunction.js'),
'fbjs/lib/emptyObject': resolve('./node_modules/fbjs/lib/emptyObject.js'),
'fbjs/lib/hyphenateStyleName': resolve('./node_modules/fbjs/lib/hyphenateStyleName.js'),
'fbjs/lib/getUnboundedScrollPosition': resolve('./node_modules/fbjs/lib/getUnboundedScrollPosition.js'),
'fbjs/lib/camelizeStyleName': resolve('./node_modules/fbjs/lib/camelizeStyleName.js'),
'fbjs/lib/containsNode': resolve('./node_modules/fbjs/lib/containsNode.js'),
'fbjs/lib/shallowEqual': resolve('./node_modules/fbjs/lib/shallowEqual.js'),
'fbjs/lib/getActiveElement': resolve('./node_modules/fbjs/lib/getActiveElement.js'),
'fbjs/lib/focusNode': resolve('./node_modules/fbjs/lib/focusNode.js'),
'fbjs/lib/EventListener': resolve('./node_modules/fbjs/lib/EventListener.js'),
'fbjs/lib/memoizeStringOnly': resolve('./node_modules/fbjs/lib/memoizeStringOnly.js'),
'fbjs/lib/ExecutionEnvironment': resolve('./node_modules/fbjs/lib/ExecutionEnvironment.js'),
'fbjs/lib/createNodesFromMarkup': resolve('./node_modules/fbjs/lib/createNodesFromMarkup.js'),
'fbjs/lib/performanceNow': resolve('./node_modules/fbjs/lib/performanceNow.js'),
};
// 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 bundleTypes.NODE:
case bundleTypes.FB:
case bundleTypes.RN:
@@ -134,14 +221,6 @@ function getFbjsModuleAliases(bundleType) {
}
}
function ignoreReactNativeModules() {
return [
// This imports NativeMethodsMixin, causing
// a circular dependency.
'View',
];
}
function replaceFbjsModuleAliases(bundleType) {
switch (bundleType) {
case bundleTypes.DEV:
@@ -152,36 +231,30 @@ function replaceFbjsModuleAliases(bundleType) {
case bundleTypes.FB:
// the diff for Haste to support fbjs/lib/* hasn't landed, so this
// re-aliases them back to the non fbjs/lib/* versions
return {
'fbjs/lib/warning': 'warning',
'fbjs/lib/invariant': 'invariant',
'fbjs/lib/emptyFunction': 'emptyFunction',
'fbjs/lib/emptyObject': 'emptyObject',
'fbjs/lib/hyphenateStyleName': 'hyphenateStyleName',
'fbjs/lib/getUnboundedScrollPosition': 'getUnboundedScrollPosition',
'fbjs/lib/camelizeStyleName': 'camelizeStyleName',
'fbjs/lib/containsNode': 'containsNode',
'fbjs/lib/shallowEqual': 'shallowEqual',
'fbjs/lib/getActiveElement': 'getActiveElement',
'fbjs/lib/focusNode': 'focusNode',
'fbjs/lib/EventListener': 'EventListener',
'fbjs/lib/memoizeStringOnly': 'memoizeStringOnly',
'fbjs/lib/ExecutionEnvironment': 'ExecutionEnvironment',
'fbjs/lib/createNodesFromMarkup': 'createNodesFromMarkup',
'fbjs/lib/performanceNow': 'performanceNow',
// to do this, we ge the fbjsModules list of names and put them in
// an alias object removing the fbjs/lib/ bit from the name
const fbjsModulesAlias = {};
fbjsModules.forEach(fbjsModule => {
fbjsModulesAlias[fbjsModule] = fbjsModule.replace('fbjs/lib/', '');
});
// additionally we add mappings for "ReactCurrentOwner" and "react"
// so they work correctly on FB
return Object.assign(fbjsModulesAlias, {
'react/lib/ReactCurrentOwner': 'ReactCurrentOwner',
"'react'": "'React'",
};
});
}
}
module.exports = {
createModuleMap,
getExternalModules,
getNodeModules,
replaceInternalModules,
getInternalModules,
getFbjsModuleAliases,
replaceFbjsModuleAliases,
ignoreFBModules,
ignoreReactNativeModules,
getExternalModules,
};