dead-code-elimination: doesn't remove the value of unused const (let/var too?)
Describe the bug
I'm just experimenting with set of plugins and presets, plus terser to see what is happening.
In one of the if branches that I have, I have unused const variable, what dead-code-elimination is doing is that it's removing the const val = an the value remains.
To Reproduce
Minimal code to reproduce the bug
const foo = (str: string) => {
const pro = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
if (process.env.NODE === '123') {
return 1234
}
if (process.env.WAS === str) {
const someRe = new RegExp(`
# A regular expression for date.
(?<year>\\d{4})- # year part of a date
(?<month>\\d{2})- # month part of a date
(?<day>\\d{2}) # day part of a date
`, 'x');
return pro
}
return process.env.BAR || process.env.QUX === 'sas'
}
console.log(foo('was was'))
with config shown below.
And run it with
WAS='was was' babel index.ts -d dist -x .ts
Actual Output
Which outputs
const foo = str => {
const pro = /(\d{4})-(\d{2})-(\d{2})/;
if ("was was" === str) {
/(\d{4})-(\d{2})-(\d{2})/;
return pro;
}
return void 0 || void 0 === 'sas';
};
console.log(foo('was was'));
Now, you can see it's clearly not correct - the regex remains and changes the meaning completely. Only the const someRe = is removed. It's not some collision of the modern-regexp transform. When we remove that transform it still just removes the const someRe= instead of the whole regex thing block.
That is a problem, because the above output later can be minified with terser to a thing that means totally different thing:
const foo=o=>{return"was was"===o&&/(\d{4})-(\d{2})-(\d{2})/}
Where you can clearly see that it is not correct.
Expected Output
If this dead-code-elimination plugin was working right it would remove the const and the whole regex so the terser's output will be something like
const foo=o=>{return /(\d{4})-(\d{2})-(\d{2})/}
and the following when not minified
const foo = str => {
const pro = /(\d{4})-(\d{2})-(\d{2})/;
if ("was was" === str) {
return /(\d{4})-(\d{2})-(\d{2});
}
return void 0 || void 0 === 'sas';
};
console.log(foo('was was'));
Stack Trace
none
Configuration
Using pieces of babel-minify.
babel.config.js
const modernRegex = false
module.exports = {
presets: [
'@babel/preset-typescript',
'@babel/preset-modules'
],
plugins: [
'babel-plugin-annotate-pure-calls',
'babel-plugin-dev-expression',
'babel-plugin-minify-builtins',
'babel-plugin-transform-inline-environment-variables',
'babel-plugin-transform-modern-regexp',
'babel-plugin-transform-node-env-inline',
'babel-plugin-transform-undefined-to-void',
'babel-plugin-minify-dead-code-elimination',
'babel-plugin-unassert',
].filter(Boolean)
}
How are you using babel-minify?
Babel CLI
"dependencies": {
"@babel/cli": "^7.8.0",
"@babel/core": "^7.8.0",
"@babel/preset-modules": "^0.1.2",
"@babel/preset-typescript": "^7.8.0",
"@types/node": "^13.1.6",
"babel-plugin-annotate-pure-calls": "^0.4.0",
"babel-plugin-dev-expression": "^0.2.2",
"babel-plugin-minify-builtins": "^0.5.0",
"babel-plugin-minify-dead-code-elimination": "^0.5.1",
"babel-plugin-transform-inline-environment-variables": "^0.4.3",
"babel-plugin-transform-modern-regexp": "^0.0.6",
"babel-plugin-transform-node-env-inline": "^0.4.3",
"babel-plugin-transform-undefined-to-void": "^6.9.4",
"babel-plugin-unassert": "^3.0.1",
"terser": "^4.6.2"
}
Possible solution
Don't know.
If we experiment further and add const foobie = 'dasdasdasd'; in that WAS if block, before the someRe, the whole thing gets removed.
const foo = (str: string) => {
const pro = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
if (process.env.NODE === '123') {
return 1234
}
if (process.env.WAS === str) {
+ const foobie = 'dasdasdasd';
const someRe = new RegExp(`
# A regular expression for date.
(?<year>\\d{4})- # year part of a date
(?<month>\\d{2})- # month part of a date
(?<day>\\d{2}) # day part of a date
`, 'x');
return pro
}
return process.env.BAR || process.env.QUX === 'sas'
}
with correctly removing the whole foobie thing.
const foo = str => {
const pro = /(\d{4})-(\d{2})-(\d{2})/;
if ("was was" === str) {
/(\d{4})-(\d{2})-(\d{2})/;
return pro;
}
return void 0 || void 0 === 'sas';
};
console.log(foo('was was'));
So it's seems it's some problem with regexes for that transform. But probably okay since Terser alone has that problem too.
And it's not because of the xFlag.
If you have basic regex instead, it still happens
const foo = (str: string) => {
const pro = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
if (process.env.NODE === '123') {
return 1234
}
if (process.env.WAS === str) {
const foobie = 'dasdasdasd';
const someRe = /(\d{4})/
return pro
}
return process.env.BAR || process.env.QUX === 'sas'
}
console.log(foo('was was'))
output
const foo = str => {
const pro = /(\d{4})-(\d{2})-(\d{2})/;
if ("was was" === str) {
/(\d{4})/;
return pro;
}
return void 0 || void 0 === 'sas';
};
console.log(foo('was was'));