I've found a strange issue with React when packaged using webpack. The issue doesn't make sense, as both the browser (when used in development mode) and the webpack build pipeline throw SyntaxError on ternary operator's :. Not sure who to blame: webpack, auth0-lock or React, but everything fails inside of React, so here we go.
Here is my setup:
https://github.com/Remper/react_bug
It's an empty Angular2 application that shows auth0-lock.
Auth0-lock uses React as a dependency and everything is being bundled by webpack (the exact config is in the repository as well).
Now when I try to launch this setup I get a SyntaxError which points to a perfectly valid line in React sources. In particular, it doesn't like ternary operators much: if I replace them with ifs manually — it breaks somewhere else inside of React:
ERROR in js/app.6a0a1796a34dcc432afe.js from UglifyJs
SyntaxError: Unexpected token: punc (:) [./~/react/lib/ReactComponentTreeHook.js:164,0][js/app.6a0a1796a34dcc432afe.js:13802,8]
This is how it looks when I disable UglifyJs: http://remper.ru/bug/
React should work when included as a dependency and packaged with webpack.
npm run build shouldn't report any issues.
What is the exact line at js/app.6a0a1796a34dcc432afe.js:13802,8?
@gaearon
Looks like this in app.js:
"use strict";
eval("/**\n * Copyright 2013-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n *\n */\n\n'use strict';\n\nvar _assign = __webpack_require__(10);\n\nvar ReactChildren = __webpack_require__(693);\nvar ReactComponent = __webpack_require__(242);\nvar ReactPureComponent = __webpack_require__(697);\nvar ReactClass = __webpack_require__(694);\nvar ReactDOMFactories = __webpack_require__(695);\nvar ReactElement = __webpack_require__(71);\nvar ReactPropTypes = __webpack_require__(696);\nvar ReactVersion = __webpack_require__(701);\n\nvar onlyChild = __webpack_require__(395);\nvar warning = __webpack_require__(35);\n\nvar createElement = ReactElement.createElement;\nvar createFactory = ReactElement.createFactory;\nvar cloneElement = ReactElement.cloneElement;\n\nif ({\"ENV\":\"server\"}.NODE_ENV !== 'production') {\n var ReactElementValidator = __webpack_require__(393);\n createElement = ReactElementValidator.createElement;\n createFactory = ReactElementValidator.createFactory;\n cloneElement = ReactElementValidator.cloneElement;\n}\n\nvar __spread = _assign;\n\nif ({\"ENV\":\"server\"}.NODE_ENV !== 'production') {\n var warned = false;\n __spread = function () {\n {\"ENV\":\"server\"}.NODE_ENV !== 'production' ? warning(warned, 'React.__spread is deprecated and should not be used. Use ' + 'Object.assign directly or another helper function with similar ' + 'semantics. You may be seeing this warning due to your compiler. ' + 'See https://fb.me/react-spread-deprecation for more details.') : void 0;\n warned = true;\n return _assign.apply(null, arguments);\n };\n}\n\nvar React = {\n\n // Modern\n\n Children: {\n map: ReactChildren.map,\n forEach: ReactChildren.forEach,\n count: ReactChildren.count,\n toArray: ReactChildren.toArray,\n only: onlyChild\n },\n\n Component: ReactComponent,\n PureComponent: ReactPureComponent,\n\n createElement: createElement,\n cloneElement: cloneElement,\n isValidElement: ReactElement.isValidElement,\n\n // Classic\n\n PropTypes: ReactPropTypes,\n createClass: ReactClass.createClass,\n createFactory: createFactory,\n createMixin: function (mixin) {\n // Currently a noop. Will be used to validate and trace mixins.\n return mixin;\n },\n\n // This looks DOM specific but these are actually isomorphic helpers\n // since they are just generating DOM strings.\n DOM: ReactDOMFactories,\n\n version: ReactVersion,\n\n // Deprecated hook for JSX spread, don't use this for anything.\n __spread: __spread\n};\n\nmodule.exports = React;//# sourceMappingURL=data:application/json;charset=utf-8;base64,<huge base64 string omitted>");
And browser shows that SyntaxError is here:
process.env.NODE_ENV !== 'production' ? warning(warned, 'React.__spread is deprecated and should not be used. Use ' + 'Object.assign directly or another helper function with similar ' + 'semantics. You may be seeing this warning due to your compiler. ' + 'See https://fb.me/react-spread-deprecation for more details.') : void 0;
@Remper if you disable UglifyJsPlugin in your webpack config, do you get the same error?
@Aweary build succeeded, but then I get the same error when I open it in a browser: http://remper.ru/bug/
@Remper alright, I cloned down the project and I think I figured out the problem. It's not an issue with your ternary operator, it's an issue with how process.env.NODE_ENV is being replaced by DefinePlugin.
I removed NoErrorsPlugin from the config so the assets would still be emitted, and then ran it in the browser. The offending line is:
{"ENV":"build"}.NODE_ENV !== 'production' ? warning(element, 'ReactComponentTreeHook: Missing React element for debugID %s when ' + 'building stack', id) : void 0;
The issue is with:
{"ENV":"build"}.NODE_ENV
Which is coming from:
new webpack.DefinePlugin({
// Environment helpers
'process.env': {
ENV: JSON.stringify(ENV)
}
}),
The problem here is that you're not replacing process.env.NODE_ENV, you're just replacing process.env with an object that has an ENV property. You can't do property access on an object literal definition, so it throws.
You can fix this by properly replacing instances of process.env.NODE_ENV by changing ENV to NODE_ENV
new webpack.DefinePlugin({
// Environment helpers
'process.env': {
NODE_ENV: JSON.stringify(ENV)
}
}),
I tested this locally and it built successfully 👍
@Aweary thanks a lot!
Most helpful comment
@Remper alright, I cloned down the project and I think I figured out the problem. It's not an issue with your ternary operator, it's an issue with how
process.env.NODE_ENVis being replaced byDefinePlugin.I removed
NoErrorsPluginfrom the config so the assets would still be emitted, and then ran it in the browser. The offending line is:The issue is with:
Which is coming from:
The problem here is that you're not replacing
process.env.NODE_ENV, you're just replacingprocess.envwith an object that has anENVproperty. You can't do property access on an object literal definition, so it throws.You can fix this by properly replacing instances of
process.env.NODE_ENVby changingENVtoNODE_ENVI tested this locally and it built successfully 👍