Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Treeshaking doesn't take place - lodash #6925

Closed
Legends opened this Issue Apr 1, 2018 · 22 comments

Comments

Projects
None yet
10 participants
@Legends
Copy link
Member

Legends commented Apr 1, 2018

Do you want to request a feature or report a bug?
Bug?

What is the current behavior?
I am loading a single export from lodash, but get the complete lodash in output-bundle.js.

If the current behavior is a bug, please provide the steps to reproduce.

page1.ts

import {add} from "lodash"
alert(add(5, 5));

Webpack.config.ts

// import { Options, Configuration, optimize, RulesRule } from "webpack";
import * as webpack from "webpack";
const path = require('path');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const cleanPlugin = require("clean-webpack-plugin");

let config: webpack.Configuration = {
  mode: "production",
  devtool: false,
  entry: {
    page1: "./src/pages/page1",
    page2: "./src/pages/page2"
  },
  optimization: {
    sideEffects: false
  },
  output: {
    filename: '[name].js',
    chunkFilename: '[name].js',
    path: path.resolve(__dirname, 'dist')
  },
  resolve: {
    extensions: [".ts", ".js", ".txt", ".json", ".css", ".less", ".scss", ".saas"],
    alias: {
      "#comp": path.resolve("./src/components/")
    }
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        loader: "ts-loader"
      },
      {
        test: /\.(less|css)$/,
        use: [{
          loader: 'css-loader',
          options: {
            sourceMap: true
          }
        }, {
          loader: 'less-loader',
          options: {
            sourceMap: true
          }
        }]
      }]
  },

  plugins: [new cleanPlugin("dist"),
  new UglifyJSPlugin({
    uglifyOptions: {
      warnings: true,
      mangle: false,
      output: {
        beautify: true,
        comments: true
      }
    }
  })
  ]
}

module.exports = config;

image

What is the expected behavior?
Treeshaked output.
If this is a feature request, what is motivation or use case for changing the behavior?

Please mention other relevant information such as the browser version, Node.js version, webpack version, and Operating System.
Win10 x64
webpack 4.4.1
node 8.10

@delphiactual

This comment has been minimized.

@Legends

This comment has been minimized.

Copy link
Member Author

Legends commented Apr 1, 2018

I know that I can use import {times} from 'lodash/times' but I thought webpack can treeshake it when doing import {times} from 'lodash'. Could be a future feature...

I cannot use es imports here, have to switch to var add = require("lodash/add") ,
because:

import {add} from "lodash/add";

@types/lodash/add"' resolves to a non-module entity and cannot be imported using this construct

@Legends Legends closed this Apr 1, 2018

@edmorley

This comment has been minimized.

Copy link
Member

edmorley commented Apr 3, 2018

This is expected, since the main lodash package still uses CJS imports/exports. However this should work now with webpack 4 and lodash-es, since it makes use of the new sideEffects option:
https://github.com/lodash/lodash/blob/4.17.8-es/package.json#L13

@Legends

This comment has been minimized.

Copy link
Member Author

Legends commented Apr 3, 2018

Yes, I saw that after looking into the lodash source file.
But still I got a problem to make this work with typescript, see here.

Could not find a declaration file for module 'lodash-es'

But the @types/lodash-es is installed...

@aj-r

This comment has been minimized.

Copy link

aj-r commented Apr 5, 2018

@Legends with TS >= 2.7, if you enable esModuleInterop, then you can do:

import times from 'lodash/times';

and it works.

@Legends

This comment has been minimized.

Copy link
Member Author

Legends commented Apr 5, 2018

@aj-r I have enabled interop, this is not an issue.
I have installed lodash-es again and it works now, why it didn't work before I don't know.


Treeshaking works if I install `lodash` and do: `import times from 'lodash/times';`

The issue I have now, is that treeshaking doesn't take place with lodash-es

Command:
tsc -p tsconfig.webpack.json && webpack --mode production --display-entrypoints --progress --display-modules --display-error-details

page2.ts

import {add} from "lodash-es"
alert(add(5, 5));

webpack.config.ts

 optimization: {
    runtimeChunk: false, 
    sideEffects: false,  
    minimizer: [
      new UglifyJSPlugin({
        uglifyOptions: {
          ecma: 5,
          warnings: true,
          mangle: false,
          keep_fnames: true,
          output: {
            beautify: true,
            comments: true
          }
        }
      })
    ]
  },
 module: {
    rules: [
      {
        test: /\.ts$/,
        loader: "ts-loader"
      },

image

@Legends Legends reopened this Apr 5, 2018

@gpspake

This comment has been minimized.

Copy link

gpspake commented Apr 6, 2018

Hey @Legends, I'm gonna reference webpack-contrib/uglifyjs-webpack-plugin#267 here in case it's related. I wonder if I should submit a separate issue. As far as I can tell, tree-shaking w uglify js plugin just isn't working in webpack 4 at all 😕

@sokra

This comment has been minimized.

Copy link
Member

sokra commented Apr 6, 2018

From the image you posted one can't see if treeshaking is working or not. It only affects the minimized size. All modules are still in the bundle (but smaller). Only the sideEffects optimization removes unused modules, but you disabled this optimization.

@gpspake

This comment has been minimized.

Copy link

gpspake commented Apr 6, 2018

@sokra what about my issue here
I've tried with optimization.sideEffects set to true and false and I still get the same output.
Does anyone have an example of treeshaking working with webpack 4?

@Legends

This comment has been minimized.

Copy link
Member Author

Legends commented Apr 6, 2018

I guess, I missunderstood sideEffects... now it works..

@Legends Legends closed this Apr 6, 2018

@Legends

This comment has been minimized.

Copy link
Member Author

Legends commented Apr 6, 2018

@gpspake can you create a little repo, that reproduces your problem, I (we) can take a look then.
Ah ok, I found your repo, I will take a look tomorrow

@gpspake

This comment has been minimized.

Copy link

gpspake commented Apr 6, 2018

@Legends we talked about it in this other thread (small world :)
I have a pretty simple example set up there.

@Legends

This comment has been minimized.

Copy link
Member Author

Legends commented Apr 7, 2018

I found the issue, it's coupled to devtool, I answered in the original thread.

After setting devtool to false, it works, sideEffects can be set to true or false it will prune unused code...

Treeshaking won't work, If devtool is set to:
eval, cheap-eval-source-map, cheap-module-eval-source-map, eval-source-map, eval-source-map

Bug?

All the code noted above does not contain side effects, so we can simply mark the property as false to inform webpack that it can safely prune unused exports.

??

@Oscar-ren

This comment has been minimized.

Copy link

Oscar-ren commented Jun 4, 2018

I have the same problem, webpack@4.10.2 and lodash-es still not treeshaking, and my webpack.config.js don't have the devtool config.

It seems like a bug, anyone successfully used sideEffects treeshaking?

thanks.

@Legends

This comment has been minimized.

Copy link
Member Author

Legends commented Jun 4, 2018

@Oscar-ren Are you running in production mode? If yes, can you create a little test repo which reproduces your problem

@Oscar-ren

This comment has been minimized.

Copy link

Oscar-ren commented Jun 5, 2018

thank you, there is my repository:
https://github.com/Oscar-ren/sideEffects

@Legends

This comment has been minimized.

Copy link
Member Author

Legends commented Jun 5, 2018

As far as I can see, everything looks good:

..lodash-es still not treeshaking..

image

@Oscar-ren

This comment has been minimized.

Copy link

Oscar-ren commented Jun 6, 2018

so sad, why my build is failed.
image
I change nothing.

...and I reinstall my node, npm and webpack, there is always no treeshaking.

node v8.11.2
node v6.1.0
webpack @4.11.0

@Oscar-ren

This comment has been minimized.

Copy link

Oscar-ren commented Jun 6, 2018

Sorry, I run the project on my cloud server, everything is ok, I will find the reason why my macbook doesn't...

Reason

I find the reason.
My mistake, I used other project .gitignore, it's hide my .babelrc file.
When I use babel-presets-env whithout options, the sideEffects doesn't work.
I change the config below will be ok.

{
  "presets": [
    ["env", {
      "modules": false
    }]
  ]
}

so thanks.

@nynka

This comment has been minimized.

Copy link

nynka commented Aug 2, 2018

@Oscar-ren Changing .babelrc file as per your suggestion solved the treeshaking issue for me.
Using:
webpack@4.16.3
babel-loader@7.1.5
react@16.4.2

{
    "presets" : [
        [
            "env", {
                "modules": false
            }
        ], 
        "react", 
        "stage-2"
    ]
}

Thanks

@victorfern91

This comment has been minimized.

Copy link

victorfern91 commented Nov 4, 2018

I'm facing same problem...

image

Why lodash.js is being imported in production? 🤔

@sdwvit

This comment has been minimized.

Copy link

sdwvit commented Mar 13, 2019

Helped for me to remove sourcemaps and add alias for lodash -> lodash-es!
also changed module to es2015 in tsconfig, not sure if it affects

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.