CRA's sourcemaps don't match code in node_modules, which breaks IDE debugging
Created by: justingrant
React source code inside sourcemaps generated by create-react-app
adds many extra blank lines and extra indentation compared with React's node_modules
source. Because line and column numbers don't match between source maps and actual source, debuggers like VSCode don't accurately set breakpoints inside React source and can't accurately step into React source. Debuggers like Chrome are not affected because they use the sitemap source (not the on-disk files) to set breakpoints.
This issue is the cause of #6044 (closed) that @raiskila filed 6 weeks ago. I created a new issue with a new repro to simplify the repro case, to remove the need to install VSCode to reproduce the problem, and to clarify that all file-based debuggers will be affected (not just VSCode).
It's possible that the root cause of this problem might be https://github.com/webpack/webpack/issues/8302, although I don't know enough about webpack to know for sure one way or the other. It's also possible that the problem is caused by create-react-app
's webpack configuration. It's also possible that the problem might be in how React itself is transforming its source code before publishing generated source files like react-dom.development.js
to NPM.
Is this a bug report?
Yes
Did you try recovering your dependencies?
Yes. Well, really N/A because the repro starts with npm install -g npm@latest
and npx create-react-app
so there are no deps to recover!
NPM version is the latest: 6.7.0
Which terms did you search for in User Guide?
sourcemap sourcemaps "source map" "source maps" mismatch whitespace line breakpoint
Environment
Environment Info:
System:
OS: macOS 10.14.2
CPU: x64 Intel(R) Core(TM) i7-4980HQ CPU @ 2.80GHz
Binaries:
Node: 10.14.2 - /usr/local/bin/node
npm: 6.7.0 - /usr/local/bin/npm
Browsers:
Chrome: 71.0.3578.98
Firefox: 63.0.1
Safari: 12.0.2
npmPackages:
react: ^16.7.0 => 16.7.0
react-dom: ^16.7.0 => 16.7.0
react-scripts: 2.1.3 => 2.1.3
npmGlobalPackages:
create-react-app: Not Found
Steps to Reproduce
1. Create a new app
npm install -g npm@latest
npx create-react-app sourcemap-bug
cd sourcemap-bug
npm start
2. Load the sourcemap and extract code from it
- 2.1 download https://localhost:3000/static/js/1.chunk.js.map (if this doesn't return a sourcemap, then try https://localhost:3000/static/js/0.chunk.js.map instead). If you're using HTTP for your CRA (I'm using HTTPS), then use http:// URLs instead of https.
- 2.2 find the top of the
react-dom.developmment.js
source in the map by searching for "react-dom.development.js\n
" (without quotes) inside the sourcemap content. If it's not there, try http://localhost:3000/static/js/0.chunk.js.map instead. - 2.3 starting with
/** @license
which should be right before the found content, copy 40-50 lines of code. Here's an example of what I copied:
/** @license React v16.7.0\n * react-dom.development.js\n *\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n'use strict';\n\nif (process.env.NODE_ENV !== "production") {\n (function () {\n 'use strict';\n\n var React = require('react');\n\n var _assign = require('object-assign');\n\n var checkPropTypes = require('prop-types/checkPropTypes');\n\n var scheduler = require('scheduler');\n\n var tracing = require('scheduler/tracing');\n /**\n * Use invariant() to assert state which your program assumes to be true.\n *\n * Provide sprintf-style format (only %s is supported) and arguments\n * to provide information about what broke and what you were\n * expecting.\n *\n * The invariant message will be stripped in production, but the invariant\n * will remain to ensure logic does not differ in production.\n */\n\n\n var validateFormat = function validateFormat() {};\n\n {\n validateFormat = function validateFormat(format) {\n if (format === undefined) {\n throw new Error('invariant requires an error message argument');\n }\n };\n }\n\n
- 2.4 Now paste that code into an editor and replace all instances of
\n
with a newline and\"
with a regular single quote. You should end up with code like this:
/** @license React v16.7.0
* react-dom.development.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';
if (process.env.NODE_ENV !== "production") {
(function () {
'use strict';
var React = require('react');
var _assign = require('object-assign');
var checkPropTypes = require('prop-types/checkPropTypes');
var scheduler = require('scheduler');
var tracing = require('scheduler/tracing');
/**
* Use invariant() to assert state which your program assumes to be true.
*
* Provide sprintf-style format (only %s is supported) and arguments
* to provide information about what broke and what you were
* expecting.
*
* The invariant message will be stripped in production, but the invariant
* will remain to ensure logic does not differ in production.
*/
var validateFormat = function validateFormat() {};
{
validateFormat = function validateFormat(format) {
if (format === undefined) {
throw new Error('invariant requires an error message argument');
}
};
}
3. Compare the sourcemap code to actual source in node_modules/react-dom/cjs/react-dom.development.js
:
/** @license React v16.7.0
* react-dom.development.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';
if (process.env.NODE_ENV !== "production") {
(function() {
'use strict';
var React = require('react');
var _assign = require('object-assign');
var checkPropTypes = require('prop-types/checkPropTypes');
var scheduler = require('scheduler');
var tracing = require('scheduler/tracing');
/**
* Use invariant() to assert state which your program assumes to be true.
*
* Provide sprintf-style format (only %s is supported) and arguments
* to provide information about what broke and what you were
* expecting.
*
* The invariant message will be stripped in production, but the invariant
* will remain to ensure logic does not differ in production.
*/
var validateFormat = function () {};
{
validateFormat = function (format) {
if (format === undefined) {
throw new Error('invariant requires an error message argument');
}
};
}
Expected Behavior
Source is the same, which is required for VS Code's debugger breakpoints and step-into to work properly.
Actual Behavior
The "sourcemap source" has many extra blank lines compared with the "node_modules source". As a result of these whitespace differences, VSCode breakpoints won't work and VSCode will set focus to the wrong code line when stepping into React's source code.
Also, the "sourcemap source" is indented differently from the "node_modules source". This breaks columnar breakpoints in VSCode.
Note that the Chrome debugger only uses the "sourcemap source" (and ignores the actual source files) so it's not affected by this problem by default. However, if you use a Chrome devtools workspace to actually load the on-disk source files, it's possible that Chrome debugging may break too.
Refer to #6044 (closed) for screenshots demonstrating the impact on VSCode users. This issue is narrowly defined to highlight the root cause of #6044 (closed) (the mismatch in whitespace between sourcemaps code and node_modules code) without requiring VSCode to reproduce the problem.
Reproducible Demo
Repro is trivial and the problem reproduces with every create-react-app
project so I'm assuming that a hosted repro is not needed. If this is a bad assumption, let me know and I'll post a repro project.