You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Imported variable bindings have difficult to debug names. #3957
Do you want to request a feature or report a bug?
Feature, improvement to debugging webpack-built projects.
What is the current behavior?
Webpack renames variable bindings in ES6 imports when it replaces them with __webpack_require__ calls. In this example the imported binding foo is compiled to __WEBPACK_IMPORTED_MODULE_0__foo__["a" /* foo */]. If you use dev tools debugger you cannot watch or executefoo because it is not defined.
Debugging is difficult, you can't watch or reference the original binding. This is made worse by sourcemaps because you can't see new name in the original source. It's not immediately apparent why a line copied from the current context into the console results in not defined errors. Chrome even removes code that has a corresponding source map, so it becomes difficult to find the in-code name of an imported value.
If the current behavior is a bug, please provide the steps to reproduce. Simple reproduction.
What is the expected behavior?
Variable bindings should be preserved by name.
If this is a feature request, what is motivation or use case for changing the behavior?
Debugging a project built by webpack today is more difficult than it aught to be.
Reacted by Rincewind3d, d-werner, Steven Pribilinskiy, Mikhail Pospelov, 0nse, Nathan Black, Denis Karabaza, Ulysse Buonomo, yang, JFGHT and 65 more
I'm not familiar with webpack's internals, or intricacies of the ES6 spec, so I understand why this could be harder than an outside observer would think.
I guess I see the problem, if the module ./foo were to redefine it's export foo the binding in index.js would be out of date.
yes, that's the problem. ES import are live bindings. Actually the a property in __webpack_require__(0) is a getter that may return different values each time.
Regarding whether it's possible, babel transforms exported binding assignments to export assignments directly. e.g.
// fromexportleta=5;exportfunctionsetAto10(){a=10// <------- from a simple variable assignment}// toexports.setAto10=setAto10;vara=exports.a=5;functionsetAto10(){exports.a=a=10// <------- to an exported variable assignment}
This solves the issue and avoids the need to use a getter. I can't think of any reason why the approach wouldn't work with webpack however I've only been digging into this problem as of tonight.
@olsonpm This issue is about imported variables not exported.
The only way which I see to fix it is:
/* harmony import */var__WEBPACK_IMPORTED_MODULE_0__foo__=__webpack_require__(0);with({getfoo(){return__WEBPACK_IMPORTED_MODULE_0__foo__["a"];}}){// your code// debugger could access `foo`}
For projects that don't care for the live binding requirement and do care about a sane interactive debugging experience, can there be an option to just treat imports like regular bindings? (I imagine there are many such projects.)
Reacted by JFGHT, dkravcovs, Chris Warren, Vitaly, Huynh Tan, Tony B, Silviu, Jan Tržický, Siva Kannan, Vitalii Mishchenko and 1 more
Hmmm... what if webpack just flipped the variable name to be first and then appends the __WEBPACK_IMPORTED_MODULE_X stuff to the end? That way at least you could try to find the variable with tab autocompletion?
but you can go around this issue by something like this
(()=>{constscope={getname(){return'cotne'}}// strict mode does not apply here so we can use "with" statement with(scope){(()=>{"use strict"// package code goes here where strict mode applies // you can't use "with" statement here but outer one is fineconsole.log(name)})()}})()
@sokra: stupid question. Could we just add an option to webpack which will make it assume that the harmony bindings are not live when turned on. Maybe somebody could correct me, but I can't think of any code where live bindings would be really useful/be a good practice. At least in our code base, I believe this to be the case. To me, it contradicts the whole concept ES6 import/export declaration being static. Or would this introduce a problem with stuff from node_modules/? Although in that case we can have some sort of regex to determine which modules to do this for...
I don’t think suggesting to treat modules not per spec is a good idea. I wouldn’t like to see an option to disable live bindings, it’s only going to cause endless confusion.
Rollup somehow is able to preserve names in live bindings (due to module concatenation). I doubt that would be fast enough for development, but thought it’s worth mentioning.
Rather than going with a with block, we could wrap the whole file with a IIFE with named parameters. That would work with debugging the 99% case when exports are constant, while still allowing the actual code run as defined in ES6. Also, this would only apply if in dev mode.
@sokra , May support mutated imports, if register setter in consumer module, as the getter is now registered in the source module?
Sоmething like this:
consumer.js
import{fooasbar}from'./source';setInterval(()=>console.log(bar),1000);// -->// when changed(=, +=, ...) export `foo` in module `sourceModuleId`, then need call setters of all consumer modules__webpack_require__.registerSetter(__webpack_exports__,sourceModuleId,"foo",function(val){bar=val;})letbar;setInterval(()=>console.log(bar),1000);//no changes. imported variable available as is
source.js:
exportletfoo=123;setInterval(()=>{foo=foo+1;},1000);// ---->letfoo;__webpack_require__.notify(sourceModuleId,'foo',foo=123);setInterval(()=>{//exported variable available in scope as is__webpack_require__.notify(sourceModuleId,'foo',foo=foo+1);},1000);
Of course, this solution can lead to performance problems, but this behavior has the right to live in development mode.
If you guys don't mind me asking, what is the debugging process supposed to look like with imports like this? How do you track down "unexpected behaviour" style bugs if you can't easily identify what you're looking at and what the values are? This is almost like debugging uglified/obfuscated code.
If you guys don't mind me asking, what is the debugging process supposed to look like with imports like this? How do you track down "unexpected behaviour" style bugs if you can't easily identify what you're looking at and what the values are? This is almost like debugging uglified/obfuscated code.
It's not convenient at all. my strategies are:
Disable source maps temporarily. Then you can see the real variable names and debug them properly.
Memorise the webpack naming conventions. If you are at a breakpoint, and your import is similar to import UserModel from 'xxx'. Then the webpack bindings are usually called __WEBPACK_IMPORTED_MODULE_0__UserModel__. The devtools are usually friendly enough to autocomplete for you if you start typing __ and then go from there.
Reacted by Nicolas Boisteault, Konstantinos Stratis and Matt Chaney
For webpack 4, use this plugin. This will simplify names if you're using eval and allow straight import vars to be used with source maps when debugging (if they're not reassigned, which probably counts for 99.9% of the cases).
So this code:
importa,{b,casd}from'foo'a()
becomes
var__foo=webpack_require('...');let{default: a, b,c: d}=__foo;if(typeofd==="undefined")d=_foo_foo.a()
I think in development build imports should work in next way:
At top level of the module declare empty variable with readable name of imported variable. At very beginning this variable will be empty because imported module could has no export defined yet.
At entrance to code block, where imported variable is used - assign value to such a top level variable from module exports. So it is will become visible in debugger at the moment we need it. And now generated code can access to imported variables by its real name without go to imported module exports each time.
Activity
sokra commentedon Jan 14, 2017
If you tell me how this is possible, I'll do it.
everett1992 commentedon Jan 15, 2017
I'm not familiar with webpack's internals, or intricacies of the ES6 spec, so I understand why this could be harder than an outside observer would think.
Why can't the example in the issue be compiled to
I guess I see the problem, if the module
./foowere to redefine it's exportfoothe binding inindex.jswould be out of date.sokra commentedon Jan 16, 2017
yes, that's the problem. ES import are live bindings. Actually the
aproperty in__webpack_require__(0)is a getter that may return different values each time.Rincewind3d commentedon Jan 25, 2017
Yeah, this is a problem for me, too. Debugging is much harder now :-(
olsonpm commentedon Feb 15, 2017
Regarding whether it's possible, babel transforms exported binding assignments to export assignments directly. e.g.
This solves the issue and avoids the need to use a getter. I can't think of any reason why the approach wouldn't work with webpack however I've only been digging into this problem as of tonight.
sokra commentedon Feb 15, 2017
@olsonpm This issue is about imported variables not exported.
The only way which I see to fix it is:
But... no...
sdwio commentedon Mar 31, 2017
One small step could be to preserve the variable names in the
__WEBPACK_IMPORTED_MODULE_0__foo__array. In the example it is not that obvious since the file and variable are named foo. If you have
the three variables will end up as "a", "b", and "c". If they would be visible as
etc. it would not be perfect but usable.
Yet I have no idea if this might cause other complications.
yang commentedon Sep 29, 2017
For projects that don't care for the live binding requirement and do care about a sane interactive debugging experience, can there be an option to just treat imports like regular bindings? (I imagine there are many such projects.)
valscion commentedon Oct 1, 2017
Hmmm... what if webpack just flipped the variable name to be first and then appends the
__WEBPACK_IMPORTED_MODULE_Xstuff to the end? That way at least you could try to find the variable with tab autocompletion?input:
output:
Then you could write
__fooand locate the correct variable from the autocomplete result.thecotne commentedon Nov 7, 2017
@sokra that is actually very good for development (i think you also need set function to preserve all behaviors ...)
and for production you will stick with current version (so uglify can do his things)
am i missing something?
thecotne commentedon Nov 7, 2017
i did some research and i am missing strict mode
but you can go around this issue by something like this
MagicDuck commentedon Jan 6, 2018
@sokra: stupid question. Could we just add an option to webpack which will make it assume that the harmony bindings are not live when turned on. Maybe somebody could correct me, but I can't think of any code where live bindings would be really useful/be a good practice. At least in our code base, I believe this to be the case. To me, it contradicts the whole concept ES6 import/export declaration being static. Or would this introduce a problem with stuff from node_modules/? Although in that case we can have some sort of regex to determine which modules to do this for...
gaearon commentedon Jan 9, 2018
I don’t think suggesting to treat modules not per spec is a good idea. I wouldn’t like to see an option to disable live bindings, it’s only going to cause endless confusion.
Rollup somehow is able to preserve names in live bindings (due to module concatenation). I doubt that would be fast enough for development, but thought it’s worth mentioning.
MagicDuck commentedon Jan 9, 2018
@gaearon and the weird import names are not causing endless confusion...? 😆
gaearon commentedon Jan 9, 2018
They are a debugging inconvenience, sure. (Potentially solvable by tooling.)
Coming up with your own language semantics for an existing language feature to avoid an inconvenience is a much harder problem to unravel.
14 remaining items
NikhilVerma commentedon Nov 14, 2019
If this has performance implications it can only be enabled for
developmentmodeGvozd commentedon Nov 30, 2019
@sokra , May support mutated imports, if register setter in consumer module, as the getter is now registered in the source module?
Sоmething like this:
consumer.js
source.js:
Of course, this solution can lead to performance problems, but this behavior has the right to live in development mode.
Moghul commentedon Dec 20, 2019
If you guys don't mind me asking, what is the debugging process supposed to look like with imports like this? How do you track down "unexpected behaviour" style bugs if you can't easily identify what you're looking at and what the values are? This is almost like debugging uglified/obfuscated code.
NikhilVerma commentedon Dec 20, 2019
It's not convenient at all. my strategies are:
import UserModel from 'xxx'. Then the webpack bindings are usually called__WEBPACK_IMPORTED_MODULE_0__UserModel__. The devtools are usually friendly enough to autocomplete for you if you start typing__and then go from there.Moghul commentedon Dec 22, 2019
Ok so what you're saying is "use commonjs".
Yehonal commentedon Jun 12, 2020
I think it's an issue with all kind of transpilers: microsoft/TypeScript#9627 (comment)
staeke commentedon Jun 19, 2020
For webpack 4, use this plugin. This will simplify names if you're using
evaland allow straight import vars to be used with source maps when debugging (if they're not reassigned, which probably counts for 99.9% of the cases).So this code:
becomes
https://gist.github.com/staeke/f197ff144e379aa884f91b95003f4ee1
epikhighs commentedon Dec 15, 2020
I couldn't get
transform-es2015-modules-commonjs-simpleto work anymore, but settingmodules: "cjs"in babel config's@babel/preset-envseems to work for me. https://babeljs.io/docs/en/babel-preset-env#modulesMegabyteceer commentedon Aug 27, 2021
I think in development build imports should work in next way:
At top level of the module declare empty variable with readable name of imported variable. At very beginning this variable will be empty because imported module could has no export defined yet.
At entrance to code block, where imported variable is used - assign value to such a top level variable from module exports. So it is will become visible in debugger at the moment we need it. And now generated code can access to imported variables by its real name without go to imported module exports each time.
Trias commentedon Jan 28, 2022
Based on @staeke 's comment i've created a webpack plugin which will add debug names to generated files (with @staeke permission).
See https://github.com/Trias/debug-import-vars-webpack-plugin
Happy debugging!
feat: resolve imported ESM bindings by name in a debugger
feat: resolve imported ESM bindings by name in a debugger
feat: resolve imported ESM bindings by name in a debugger
feat: resolve imported ESM bindings by name in a debugger
feat: resolve imported ESM bindings by name in a debugger