babel-plugin-minify-dead-code-elimination: Function name gets removed when keepFnNames is enabled in some scenarios
- Dominant language
- JavaScript
- Stars
- 4.4k
- Forks
- 217
- PR merge metrics
- No merged PRs in 30d
Description
**Describe the bug**
The name of functions that infer their names from a variable name is being removed when `babel-plugin-minify-dead-code-elimination` is used with the `keepFnNames` option enabled.
All of these function definitions hav the name "func":
```js
function func() {}
console.log(func.name) // "func"
```
```js
const other = function func() {}
console.log(other.name) // "func"
```
```js
const func = function() {}
console.log(func.name) // "func"
```
```js
const func = () => {}
console.log(func.name) // "func"
```
If we return these definitions from a wrapping function before logging the name, the first two will retain the name from their definitions:
```js
function createFunc() {
return function func() {}
}
const func = createFunc()
console.log(func.name) // "func"
```
```js
function createFunc() {
const other = function func() {}
return other
}
const func = createFunc()
console.log(func.name) // "func"
```
However, the second two have lost their names:
```js
function createFunc() {
const func = function() {}
return func
}
const func = createFunc()
console.log(func.name) // ""
```
```js
function createFunc() {
const func = () => {}
return func;
}
const func = createFunc()
console.log(func.name) // ""
```
**To Reproduce**
Minimal code to reproduce the bug
```js
function createFunc1() {
return function func() {}
}
function createFunc2() {
const other = function func() {}
return other;
}
function createFunc3() {
const func = function() {}
return func;
}
function createFunc4() {
const func = () => {}
return func;
}
```
**Actual Output**
If there is no Error thrown,
```js
function createFunc1() {
return function func() {};
}
function createFunc2() {
return function func() {};
}
function createFunc3() {
return function () {};
}
function createFunc4() {
return () => {};
}
```
**Expected Output**
```js
function createFunc1() {
return function func() {}
}
function createFunc2() {
const other = function func() {}
return other;
}
function createFunc3() {
const func = function() {}
return func;
}
function createFunc4() {
const func = () => {}
return func;
}
```
**Configuration**
How are you using babel-minify?
babelrc.js:
```json5
module.exports = {
plugins: [
[require.resolve('babel-plugin-minify-dead-code-elimination'), { keepFnName: true }]
]
}
```
**Possible solution**
The issue seems to be coming from inlining the variable into the return of the function, losing the variable name to infer the function name from.
**Additional context**
I discovered this when function names were being stripped out of stack traces in error logs.
It also seems particularly problematic for React HOCs where the `displayName` for the wrapping component is derived from the function name for a function component, e.g.
```jsx
const withValue = (value) => (Component) => {
const WithValue = (props) => (
)
return WithValue
}
const WrappedComponent = withValue(SomeComponent)
```
Contributor guide
Research direction
Start at the babel-plugin-minify-dead-code-elimination entry point and reproduce the issue with the supplied createFunc1–createFunc4 examples while the keepFnNames option is enabled. Trace the variable inlining that occurs before the returned function is emitted; done means inferred names are preserved for all four cases and the regression is covered by a test.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- tooling
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100