webpack.js.org
                                
                                 webpack.js.org copied to clipboard
                                
                                    webpack.js.org copied to clipboard
                            
                            
                            
                        Webpack does not transpile arrow functions and template strings passed to higher order functions
Bug report
What is the current behavior?
Arrow functions (including those that contain template strings) are not transpiled down to ES5 only when they are passed to higher order functions like filter() and map(). My setup uses browserslist to supply targets so I haven't included "web" and "es5" in my webpack config intentionally.
If the current behavior is a bug, please provide the steps to reproduce.
- Create a new JS file and paste this in it. Note there are three arrow functions in total and two of them contain template literals.
const someObj = {
    'key1': 'value1',
    'key2': 'value2',
    'key3': 'value3',
};
const filterFunc = m => someObj[m];
const mapFunc = m => `${m}=${someObj[m]}`;
const params = Object.keys(someObj)
    .filter(filterFunc)
    .map(mapFunc)
    .join('&');
const arrowFunction = () => console.log(`arrow function containing template literal ${someObj['key1']}`);
arrowFunction();
- Create a minimal webpack.config.js.
const path = require('path');
const demoConfig = {
entry: [path.resolve(__dirname, '/path/to/js')],
  output: {
    path: path.resolve(__dirname, '/path/to/output'),
    filename: 'foo.js',
  }
}
module.exports = [demoConfig];
- 
Set a browserslist config of "defaults", in package.json. This includes IE 11 so should be transpiling down to ES5. 
- 
Build the JS and note that of the three arrow functions, two are still present in the transpiled code and the last one isn't. The first template literal hasn't been transpiled whilst the second one has. It looks like an issue specifically transpiling arrow functions and template literals that go into higher order functions. 
What is the expected behavior?
No arrow functions or template literals should be present in bundled code.
Other relevant information: webpack version: 5.4.0 ([email protected]) Node.js version: 10.23.0 Operating System: Mojave 10.14.6 Additional tools:
Webpack does not transpile JS - Babel does. Have you tried using the Babel loader?
https://webpack.js.org/loaders/babel-loader/
Answer above
@chenxsan I think we need update description about target, we don't transpile code, only generate code code for esX compatibility
Webpack does not transpile JS - Babel does. Have you tried using the Babel loader?
https://webpack.js.org/loaders/babel-loader/
I was looking at these migration docs for reference.
- By default, webpack will use your browserslist config to decide which code style to emit.
- Without a browserslist it would emit ES6 style. You can use target: ["web", "es5"] to change it to ES5.
This suggests webpack would transpile and based on the code I've provided, it doesn't explain why one arrow function is being transpiled to es5 and only those passed to higher order functions aren't being transpiled.
I ended up using babel in this case but have other repos where webpack is able to do the job without babel and using only targets browserslist provides (hence my confusion).
yep, we need improve description about this
@evilebottnawi Is there any explanation as to why part of the JS provided is being transpiled to es5 syntax?
Yes, we don't change your code, it is out of scope webpack, we just generate es5 webpack runtime in your case
Yes, we don't change your code, it is out of scope webpack, we just generate
es5webpack runtime in your case
Thanks for your response. Just so I understand, this is the code webpack has generated based on the JS in the original post.
!function(){
    const e={key1:"value1",key2:"value2",key3:"value3"};
    Object.keys(e).filter((n=>e[n])).map((n=>`${n}=${e[n]}`)).join("&"),
    console.log("arrow function containing template literal "+e.key1)
}();
The thing that led me to believe webpack was transpiling was the arrow function around the console.log has been taken out. Can you tell me why that's the case?
Is webpack smart enough to realise that it's a redundant arrow function and the expression can be extracted from the arrow function to generate a smaller bundle?
bundler !== transpiler, what is the problem? You need babel-loader to tranpile your source to es5
@usmanbuilds I don't know everything about the Webpack internals, but my guess is that what is doing the above is the Terser plugin. It is used automatically in production builds, and is extremely good at shaving down bundle sizes as much as possible. It's very possible that it's detecting (and removing) the redundant call.
We do have a warning here https://webpack.js.org/guides/getting-started/#modules:
Note that webpack will not alter any code other than import and export statements. If you are using other ES2015 features, make sure to use a transpiler such as Babel or Bublé via webpack's loader system.
But yeah, users might pay no attention to it. Maybe we can add a similar paragraph under Target.
If anyone's interested in helping, I think this file https://github.com/webpack/webpack.js.org/blob/master/src/content/concepts/targets.md is where we can edit. Otherwise I'll document it later.
@usmanbuilds I don't know everything about the Webpack internals, but my guess is that what is doing the above is the Terser plugin. It is used automatically in production builds, and is extremely good at shaving down bundle sizes as much as possible. It's very possible that it's detecting (and removing) the redundant call.
Thank you very much. Exactly what I was looking for.