-
Notifications
You must be signed in to change notification settings - Fork 47.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Consolidate build process with GCC #11483
Merged
Merged
Changes from 2 commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,10 +2,12 @@ | |
|
||
const rollup = require('rollup').rollup; | ||
const babel = require('rollup-plugin-babel'); | ||
const closure = require('rollup-plugin-closure-compiler-js'); | ||
const commonjs = require('rollup-plugin-commonjs'); | ||
const alias = require('rollup-plugin-alias'); | ||
const uglify = require('rollup-plugin-uglify'); | ||
const prettier = require('rollup-plugin-prettier'); | ||
const replace = require('rollup-plugin-replace'); | ||
const stripBanner = require('rollup-plugin-strip-banner'); | ||
const chalk = require('chalk'); | ||
const join = require('path').join; | ||
const resolve = require('path').resolve; | ||
|
@@ -24,7 +26,6 @@ const syncReactNativeRT = require('./sync').syncReactNativeRT; | |
const syncReactNativeCS = require('./sync').syncReactNativeCS; | ||
const Packaging = require('./packaging'); | ||
const Header = require('./header'); | ||
const closure = require('rollup-plugin-closure-compiler-js'); | ||
|
||
const UMD_DEV = Bundles.bundleTypes.UMD_DEV; | ||
const UMD_PROD = Bundles.bundleTypes.UMD_PROD; | ||
|
@@ -51,31 +52,16 @@ const errorCodeOpts = { | |
errorMapFilePath: 'scripts/error-codes/codes.json', | ||
}; | ||
|
||
function getHeaderSanityCheck(bundleType, globalName) { | ||
switch (bundleType) { | ||
case FB_DEV: | ||
case FB_PROD: | ||
case RN_DEV: | ||
case RN_PROD: | ||
let hasteFinalName = globalName; | ||
switch (bundleType) { | ||
case FB_DEV: | ||
case RN_DEV: | ||
hasteFinalName += '-dev'; | ||
break; | ||
case FB_PROD: | ||
case RN_PROD: | ||
hasteFinalName += '-prod'; | ||
break; | ||
} | ||
return hasteFinalName; | ||
case UMD_DEV: | ||
case UMD_PROD: | ||
return reactVersion; | ||
default: | ||
return null; | ||
} | ||
} | ||
const closureOptions = { | ||
compilationLevel: 'SIMPLE', | ||
languageIn: 'ECMASCRIPT5_STRICT', | ||
languageOut: 'ECMASCRIPT5_STRICT', | ||
env: 'CUSTOM', | ||
warningLevel: 'QUIET', | ||
applyInputSourceMaps: false, | ||
useTypesForOptimization: false, | ||
processCommonJsModules: false, | ||
}; | ||
|
||
function getBanner(bundleType, globalName, filename, moduleType) { | ||
if (moduleType === RECONCILER) { | ||
|
@@ -261,7 +247,6 @@ function getRollupOutputOptions( | |
return Object.assign( | ||
{}, | ||
{ | ||
banner: getBanner(bundleType, globalName, filename, moduleType), | ||
destDir: 'build/', | ||
file: | ||
'build/' + | ||
|
@@ -270,7 +255,6 @@ function getRollupOutputOptions( | |
filename, | ||
globalName | ||
), | ||
footer: getFooter(bundleType, filename, moduleType), | ||
format, | ||
globals, | ||
interop: false, | ||
|
@@ -280,13 +264,6 @@ function getRollupOutputOptions( | |
); | ||
} | ||
|
||
function stripEnvVariables(production) { | ||
return { | ||
__DEV__: production ? 'false' : 'true', | ||
'process.env.NODE_ENV': production ? "'production'" : "'development'", | ||
}; | ||
} | ||
|
||
function getFormat(bundleType) { | ||
switch (bundleType) { | ||
case UMD_DEV: | ||
|
@@ -323,86 +300,21 @@ function getFilename(name, globalName, bundleType) { | |
} | ||
} | ||
|
||
function getUglifyConfig(configs) { | ||
var mangle = configs.mangle; | ||
var preserveVersionHeader = configs.preserveVersionHeader; | ||
var removeComments = configs.removeComments; | ||
var headerSanityCheck = configs.headerSanityCheck; | ||
return { | ||
warnings: false, | ||
compress: { | ||
screw_ie8: true, | ||
dead_code: true, | ||
unused: true, | ||
drop_debugger: true, | ||
// we have a string literal <script> that we don't want to evaluate | ||
// for FB prod bundles (where we disable mangling) | ||
evaluate: mangle, | ||
booleans: true, | ||
// Our www inline transform combined with Jest resetModules is confused | ||
// in some rare cases unless we keep all requires at the top: | ||
hoist_funs: mangle, | ||
}, | ||
output: { | ||
beautify: !mangle, | ||
comments(node, comment) { | ||
if (preserveVersionHeader && comment.pos === 0 && comment.col === 0) { | ||
// Keep the very first comment (the bundle header) in prod bundles. | ||
if ( | ||
headerSanityCheck && | ||
comment.value.indexOf(headerSanityCheck) === -1 | ||
) { | ||
// Sanity check: this doesn't look like the bundle header! | ||
throw new Error( | ||
'Expected the first comment to be the file header but got: ' + | ||
comment.value | ||
); | ||
} | ||
return true; | ||
} | ||
return !removeComments; | ||
}, | ||
}, | ||
mangle: mangle | ||
? { | ||
toplevel: true, | ||
screw_ie8: true, | ||
} | ||
: false, | ||
}; | ||
} | ||
|
||
// FB uses require('React') instead of require('react'). | ||
// We can't set up a forwarding module due to case sensitivity issues. | ||
function rewriteFBReactImport() { | ||
return { | ||
transformBundle(source) { | ||
return source.replace(/require\(['"]react['"]\)/g, "require('React')"); | ||
}, | ||
}; | ||
} | ||
|
||
// Strip 'use strict' directives in individual modules | ||
// because we always emit them in the file headers. | ||
// The whole bundle is strict. | ||
function stripUseStrict() { | ||
return { | ||
transform(source) { | ||
return source.replace(/['"]use strict['"']/g, ''); | ||
}, | ||
}; | ||
} | ||
|
||
// Plugin that writes to the error code file so that by the time it is picked | ||
// up by Babel, the errors are already extracted. | ||
function writeErrorCodes() { | ||
const flush = extractErrorCodes(errorCodeOpts); | ||
return { | ||
transform(source) { | ||
flush(source); | ||
return source; | ||
}, | ||
}; | ||
function isProductionBundleType(bundleType) { | ||
switch (bundleType) { | ||
case UMD_DEV: | ||
case NODE_DEV: | ||
case FB_DEV: | ||
case RN_DEV: | ||
return false; | ||
case UMD_PROD: | ||
case NODE_PROD: | ||
case FB_PROD: | ||
case RN_PROD: | ||
return true; | ||
default: | ||
throw new Error(`Unknown type: ${bundleType}`); | ||
} | ||
} | ||
|
||
function getPlugins( | ||
|
@@ -416,88 +328,77 @@ function getPlugins( | |
modulesToStub, | ||
featureFlags | ||
) { | ||
const findAndRecordErrorCodes = extractErrorCodes(errorCodeOpts); | ||
const shims = Modules.getShims(bundleType, entry, featureFlags); | ||
const plugins = [ | ||
const isProduction = isProductionBundleType(bundleType); | ||
const isInGlobalScope = bundleType === UMD_DEV || bundleType === UMD_PROD; | ||
const isFBBundle = bundleType === FB_DEV || bundleType === FB_PROD; | ||
const isRNBundle = bundleType === RN_DEV || bundleType === RN_PROD; | ||
const shouldStayReadable = isFBBundle || isRNBundle; | ||
return [ | ||
// Extract error codes from invariant() messages into a file. | ||
shouldExtractErrors && writeErrorCodes(), | ||
shouldExtractErrors && { | ||
transform(source) { | ||
findAndRecordErrorCodes(source); | ||
return source; | ||
}, | ||
}, | ||
// Shim some modules for www custom behavior and optimizations. | ||
alias(shims), | ||
// Use Node resolution mechanism. | ||
resolvePlugin({ | ||
skip: externals, | ||
}), | ||
// Remove license headers from individual modules | ||
stripBanner({ | ||
exclude: 'node_modules/**/*', | ||
}), | ||
// Compile to ES5. | ||
babel(getBabelConfig(updateBabelOptions, bundleType)), | ||
stripUseStrict(), | ||
].filter(Boolean); | ||
|
||
const headerSanityCheck = getHeaderSanityCheck(bundleType, globalName); | ||
switch (bundleType) { | ||
case UMD_DEV: | ||
case NODE_DEV: | ||
plugins.push(replace(stripEnvVariables(false)), commonjs()); | ||
break; | ||
case UMD_PROD: | ||
case NODE_PROD: | ||
plugins.push( | ||
replace(stripEnvVariables(true)), | ||
commonjs(), | ||
closure({ | ||
compilationLevel: 'SIMPLE', | ||
languageIn: 'ECMASCRIPT5_STRICT', | ||
languageOut: 'ECMASCRIPT5_STRICT', | ||
env: 'CUSTOM', | ||
warningLevel: 'QUIET', | ||
// Remove 'use strict' from individual source files. | ||
{ | ||
transform(source) { | ||
return source.replace(/['"]use strict['"']/g, ''); | ||
}, | ||
}, | ||
// Turn __DEV__ and process.env checks into constants. | ||
replace({ | ||
__DEV__: isProduction ? 'false' : 'true', | ||
'process.env.NODE_ENV': isProduction ? "'production'" : "'development'", | ||
}), | ||
// We still need CommonJS for external deps like object-assign. | ||
commonjs(), | ||
// www still needs require('React') rather than require('react') | ||
isFBBundle && { | ||
transformBundle(source) { | ||
return source.replace(/require\(['"]react['"]\)/g, "require('React')"); | ||
}, | ||
}, | ||
// Apply dead code elimination and/or minification. | ||
isProduction && | ||
closure( | ||
Object.assign({}, closureOptions, { | ||
// Don't let it create global variables in the browser. | ||
// https://github.com/facebook/react/issues/10909 | ||
assumeFunctionWrapper: bundleType !== UMD_PROD, | ||
applyInputSourceMaps: false, | ||
useTypesForOptimization: false, | ||
processCommonJsModules: false, | ||
assumeFunctionWrapper: !isInGlobalScope, | ||
// Works because `google-closure-compiler-js` is forked in Yarn lockfile. | ||
// We can remove this if GCC merges my PR: | ||
// https://github.com/google/closure-compiler/pull/2707 | ||
// and then the compiled version is released via `google-closure-compiler-js`. | ||
renaming: !shouldStayReadable, | ||
}) | ||
); | ||
break; | ||
case FB_DEV: | ||
plugins.push( | ||
replace(stripEnvVariables(false)), | ||
commonjs(), | ||
rewriteFBReactImport() | ||
); | ||
break; | ||
case FB_PROD: | ||
plugins.push( | ||
replace(stripEnvVariables(true)), | ||
commonjs(), | ||
uglify( | ||
getUglifyConfig({ | ||
mangle: bundleType !== FB_PROD, | ||
preserveVersionHeader: bundleType === UMD_PROD, | ||
// leave comments in for source map debugging purposes | ||
// they will be stripped as part of FB's build process | ||
removeComments: bundleType !== FB_PROD, | ||
headerSanityCheck, | ||
}) | ||
), | ||
rewriteFBReactImport() | ||
); | ||
break; | ||
case RN_DEV: | ||
case RN_PROD: | ||
plugins.push( | ||
replace(stripEnvVariables(bundleType === RN_PROD)), | ||
commonjs(), | ||
uglify( | ||
getUglifyConfig({ | ||
mangle: false, | ||
preserveVersionHeader: true, | ||
removeComments: true, | ||
headerSanityCheck, | ||
}) | ||
) | ||
); | ||
break; | ||
} | ||
plugins.push( | ||
), | ||
// Add the whitespace back if necessary. | ||
shouldStayReadable && prettier(), | ||
// License and haste headers, top-level `if` blocks. | ||
{ | ||
transformBundle(source) { | ||
const banner = getBanner(bundleType, globalName, filename, moduleType); | ||
const footer = getFooter(bundleType, filename, moduleType); | ||
return banner + '\n' + source + '\n' + footer; | ||
}, | ||
}, | ||
// Record bundle size. | ||
sizes({ | ||
getSize: (size, gzip) => { | ||
const key = `${filename} (${bundleType})`; | ||
|
@@ -506,9 +407,8 @@ function getPlugins( | |
gzip, | ||
}; | ||
}, | ||
}) | ||
); | ||
return plugins; | ||
}), | ||
].filter(Boolean); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I’m not sure this is super obvious as to what’s happening? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
} | ||
|
||
function createBundle(bundle, bundleType) { | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’m not sure this is the best name. Maybe
isUMDBundle
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There may be more bundle types where top-level things are declared in global scope. In theory. :-)