webpack.js.org icon indicating copy to clipboard operation
webpack.js.org copied to clipboard

Webpack does not transpile arrow functions and template strings passed to higher order functions

Open usmanbuilds opened this issue 4 years ago • 13 comments

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.

  1. 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();
  1. 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];
  1. Set a browserslist config of "defaults", in package.json. This includes IE 11 so should be transpiling down to ES5.

  2. 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:

usmanbuilds avatar Nov 05 '20 18:11 usmanbuilds

Webpack does not transpile JS - Babel does. Have you tried using the Babel loader?

https://webpack.js.org/loaders/babel-loader/

csvan avatar Nov 05 '20 22:11 csvan

Answer above

alexander-akait avatar Nov 06 '20 10:11 alexander-akait

@chenxsan I think we need update description about target, we don't transpile code, only generate code code for esX compatibility

alexander-akait avatar Nov 06 '20 10:11 alexander-akait

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).

usmanbuilds avatar Nov 06 '20 14:11 usmanbuilds

yep, we need improve description about this

alexander-akait avatar Nov 06 '20 14:11 alexander-akait

@evilebottnawi Is there any explanation as to why part of the JS provided is being transpiled to es5 syntax?

usmanbuilds avatar Nov 06 '20 14:11 usmanbuilds

Yes, we don't change your code, it is out of scope webpack, we just generate es5 webpack runtime in your case

alexander-akait avatar Nov 06 '20 14:11 alexander-akait

Yes, we don't change your code, it is out of scope webpack, we just generate es5 webpack 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?

usmanbuilds avatar Nov 06 '20 17:11 usmanbuilds

bundler !== transpiler, what is the problem? You need babel-loader to tranpile your source to es5

alexander-akait avatar Nov 06 '20 17:11 alexander-akait

@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.

csvan avatar Nov 06 '20 19:11 csvan

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.

chenxsan avatar Nov 07 '20 01:11 chenxsan

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.

chenxsan avatar Nov 07 '20 01:11 chenxsan

@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.

usmanbuilds avatar Nov 09 '20 12:11 usmanbuilds