diff --git a/package.json b/package.json index 86613d9225afa..69e8fec2e5620 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,6 @@ "babel-jest": "20.1.0-delta.1", "babel-plugin-check-es2015-constants": "^6.5.0", "babel-plugin-external-helpers": "^6.22.0", - "babel-plugin-minify-dead-code-elimination": "^0.1.7", "babel-plugin-syntax-trailing-function-commas": "^6.5.0", "babel-plugin-transform-async-to-generator": "^6.22.0", "babel-plugin-transform-class-properties": "^6.11.5", @@ -33,7 +32,6 @@ "babel-plugin-transform-es3-property-literals": "^6.5.0", "babel-plugin-transform-object-rest-spread": "^6.6.5", "babel-plugin-transform-react-jsx-source": "^6.8.0", - "babel-preset-minify": "0.0.0", "babel-preset-react": "^6.5.0", "babel-traverse": "^6.9.0", "babylon": "6.15.0", @@ -88,7 +86,7 @@ "through2": "^2.0.0", "tmp": "~0.0.28", "typescript": "~1.8.10", - "uglify-js": "2.8.29", + "uglify-js": "^2.8.29", "yargs": "^6.3.0" }, "devEngines": { diff --git a/packages/react/index.js b/packages/react/index.js index 42e5f9ba5c4f6..be66e66a687f9 100644 --- a/packages/react/index.js +++ b/packages/react/index.js @@ -1,9 +1,50 @@ 'use strict'; +function testMinificationUsedDCE() { + // use scoped variable for our initial test, in case + // 'top-level' mangling is not enabled. + const source = testMinificationUsedDCE.toString(); + const longVariableName = source; + if (longVariableName && source.match(/longVariableName/g).length === 3) { + // We are not minified. + // This might be a Node environment where DCE is not expected anyway. + return; + } + if (process.env.NODE_ENV === 'development') { + // We expect this method only to be called in production. + throw new Error('This is unreachable'); + } + try { + if (source.match(/toString/g).length !== 2) { + // We always look for two matches: + // The actual occurence and then the call to 'match' + // + // We know for a fact the above line exists so there should be 2 + // matches. + // Therefore the browser gave us invalid source. + return; + } + if (source.match(/unreachable/g).length === 2) { + // We always look for two matches: + // The actual occurence and then the call to 'match' + + // Dead code elimination would have stripped that branch + // because it is impossible to reach in production. + setTimeout(function() { + // Ensure it gets reported to production logging + throw new Error( + 'React is running in production mode, but dead code ' + + 'elimination has not been applied. Read how to correctly ' + + 'configure React for production: ' + + 'https://fburl.com/react-perf-use-the-production-build' + ); + }); + } + } catch (e) {} +} if (process.env.NODE_ENV === 'production') { - // TODO: actually update the build process so this works. - (require('./cjs/testMinificationUsedDCE.js'))(); + testMinificationUsedDCE(); module.exports = require('./cjs/react.production.min.js'); } else { module.exports = require('./cjs/react.development.js'); diff --git a/scripts/rollup/packaging.js b/scripts/rollup/packaging.js index 8e9d60d5d7abd..ca6cbf7826f25 100644 --- a/scripts/rollup/packaging.js +++ b/scripts/rollup/packaging.js @@ -30,11 +30,6 @@ const reactNativeSrcDependencies = [ 'src/renderers/native/ReactNativeTypes.js', ]; -// these files need to be copied to the react build -const reactPackageDependencies = [ - 'src/shared/utils/testMinificationUsedDCE.js', -]; - function getPackageName(name) { if (name.indexOf('/') !== -1) { return name.split('/')[0]; @@ -104,7 +99,7 @@ function copyBundleIntoNodePackage(packageName, filename, bundleType) { from = resolve(`./build/dist/${filename}`); to = `${packageDirectory}/umd/${filename}`; } - const promises = []; + // for NODE bundles we have to move the files into a cjs directory // within the package directory. we also need to set the from // to be the root build from directory @@ -115,31 +110,13 @@ function copyBundleIntoNodePackage(packageName, filename, bundleType) { fs.mkdirSync(distDirectory); } to = `${packageDirectory}/cjs/${filename}`; - if (packageName === 'react') { - // we are building the React package - let promises = []; - // we also need to copy over some specific files from src - // defined in reactPackageDependencies - for (const srcDependency of reactPackageDependencies) { - // TODO: the srcDependency needs to be processed - // before this step. - var specificFrom = resolve(srcDependency); - var specificTo = resolve(`${distDirectory}/${basename(srcDependency)}`); - promises.push( - asyncCopyTo(specificFrom, specificTo) - ); - } - } } - promises.push( - asyncCopyTo(from, to).then(() => { - // delete the old file if this is a not a UMD bundle - if (bundleType !== UMD_DEV && bundleType !== UMD_PROD) { - fs.unlinkSync(from); - } - }) - ); - return Promise.all(promises); + return asyncCopyTo(from, to).then(() => { + // delete the old file if this is a not a UMD bundle + if (bundleType !== UMD_DEV && bundleType !== UMD_PROD) { + fs.unlinkSync(from); + } + }); } else { return Promise.resolve(); } diff --git a/src/shared/utils/__tests__/testMinificationUsedDCE-test.js b/src/shared/utils/__tests__/testMinificationUsedDCE-test.js deleted file mode 100644 index 29fcce2bfdbf2..0000000000000 --- a/src/shared/utils/__tests__/testMinificationUsedDCE-test.js +++ /dev/null @@ -1,144 +0,0 @@ -/** - * Copyright 2013-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @emails react-core - */ -'use strict'; - -const babel = require('babel-core'); -const UglifyJs = require('uglify-js'); -let testMinificationUsedDCE; - -describe('in the production environment', () => { - let oldProcess; - beforeEach(() => { - __DEV__ = false; - - // Mutating process.env.NODE_ENV would cause our babel plugins to do the - // wrong thing. If you change this, make sure to test with jest --no-cache. - oldProcess = process; - global.process = { - ...process, - env: {...process.env, NODE_ENV: 'production'}, - }; - - jest.resetModules(); - testMinificationUsedDCE = require('testMinificationUsedDCE'); - }); - - afterEach(() => { - __DEV__ = true; - global.process = oldProcess; - }); - - describe('when not minified', () => { - it('should not throw', () => { - expect(() => { - testMinificationUsedDCE(); - jest.runAllTimers(); - }).not.toThrow(); - }); - }); - - describe('with uglifyjs', () => { - describe('when envified first, then minification with *no* DCE', () => { - it('should throw', () => { - // envify: change `process.env.NODE_ENV` to `"production"` - const rawCode = testMinificationUsedDCE - .toString() - .replace(/process\.env\.NODE_ENV/, '"production"'); - const code = {'file.js': rawCode}; - const options = {fromString: true, parse: {dead_code: false}}; - const result = UglifyJs.minify(code, options); - const minifiedWithNoDCE = () => eval('(' + result.code + ')()'); - expect(() => { - minifiedWithNoDCE(); - jest.runAllTimers(); - }).toThrow( - 'React is running in production mode, but dead code elimination ' + - 'has not been applied.', - ); - }); - }); - - describe('when envified first, then minified and *yes* successful DCE', () => { - it('should not throw', () => { - // envify: change `process.env.NODE_ENV` to `"production"` - const rawCode = testMinificationUsedDCE - .toString() - .replace(/process\.env\.NODE_ENV/g, '"production"'); - const code = {'file.js': rawCode}; - const options = {fromString: true, parse: {dead_code: true}}; - const result = UglifyJs.minify(code, options); - const minifiedWithNoDCE = () => eval('(' + result.code + ')()'); - expect(() => { - minifiedWithNoDCE(); - jest.runAllTimers(); - }).not.toThrow(); - }); - }); - - describe('when minified first with *unsuccessful* DCE, then envified', () => { - it('should throw', () => { - const code = {'file.js': testMinificationUsedDCE.toString()}; - const options = {fromString: true, parse: {dead_code: true}}; - const result = UglifyJs.minify(code, options); - // late envify: change `process.env.NODE_ENV` to `"production"` - const resultCode = result.code.replace( - /process\.env\.NODE_ENV/g, - '"production"', - ); - const minifiedWithNoDCE = () => eval('(' + resultCode + ')()'); - expect(() => { - minifiedWithNoDCE(); - jest.runAllTimers(); - }).toThrow( - 'React is running in production mode, but dead code elimination ' + - 'has not been applied.', - ); - }); - }); - }); - - describe('when minified with babel/minify with *no* DCE', () => { - xit('should throw', () => { - const babelOpts = { - presets: ['babel-preset-minify'], - }; - // TODO: Why is this not actually minifying the code???? - const minifiedWithNoDCE = () => { - eval( - babel.transform(testMinificationUsedDCE.toString(), babelOpts).code, - ); - }; - expect(() => { - minifiedWithNoDCE(); - jest.runAllTimers(); - }).toThrow(); - }); - }); - - describe('when minified with babel/minify with DCE', () => { - xit('should not throw', () => { - const babelOpts = { - plugins: ['minify-dead-code-elimination'], - presets: ['babel-preset-minify'], - }; - // TODO: Why is this not actually minifying the code???? - const minifiedWithDCE = () => { - eval( - babel.transform(testMinificationUsedDCE.toString(), babelOpts).code, - ); - }; - expect(() => { - testMinificationUsedDCE(); - jest.runAllTimers(); - }).not.toThrow(); - }); - }); -}); diff --git a/src/shared/utils/testMinificationUsedDCE.js b/src/shared/utils/testMinificationUsedDCE.js deleted file mode 100644 index 344a612338aef..0000000000000 --- a/src/shared/utils/testMinificationUsedDCE.js +++ /dev/null @@ -1,59 +0,0 @@ -/** - * Copyright 2014-2015, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @providesModule testMinificationUsedDCE - */ - -'use strict'; - -function testMinificationUsedDCE() { - if (process.env.NODE_ENV === 'production') { - // use scoped variable for our initial test, in case - // 'top-level' mangling is not enabled. - const source = testMinificationUsedDCE.toString(); - const longVariableName = source; - if (longVariableName && source.match(/longVariableName/g).length === 3) { - // We are not minified. - // This might be a Node environment where DCE is not expected anyway. - return; - } - if (process.env.NODE_ENV === 'development') { - // We expect this method only to be called in production. - throw new Error('This is unreachable'); - } - try { - if (source.match(/toString/g).length !== 2) { - // We always look for two matches: - // The actual occurence and then the call to 'match' - // - // We know for a fact the above line exists so there should be 2 - // matches. - // Therefore the browser gave us invalid source. - return; - } - if (source.match(/unreachable/g).length === 2) { - // We always look for two matches: - // The actual occurence and then the call to 'match' - - // Dead code elimination would have stripped that branch - // because it is impossible to reach in production. - setTimeout(function() { - // Ensure it gets reported to production logging - throw new Error( - 'React is running in production mode, but dead code ' + - 'elimination has not been applied. Read how to correctly ' + - 'configure React for production: ' + - 'https://fburl.com/react-perf-use-the-production-build', - ); - }); - } - } catch (e) {} - } -} - -module.exports = testMinificationUsedDCE;