Skip to content
This repository was archived by the owner on Dec 5, 2019. It is now read-only.

Tree shaking not working - webpack 4 and uglifyjs-webpack-plugin #267

Closed
gpspake opened this issue Mar 23, 2018 · 29 comments
Closed

Tree shaking not working - webpack 4 and uglifyjs-webpack-plugin #267

gpspake opened this issue Mar 23, 2018 · 29 comments

Comments

@gpspake
Copy link

gpspake commented Mar 23, 2018

I have tried adding UglifyJSPlugin to a webpack 4 project, in accordance with the webpack tree shaking docs, and I'm still seeing dead code and even comments in my bundle which leads me to think that my uglify plugin config isn't being used. I posted this on Stack Overflow a couple of days ago before posting here.

Link to project

The docs state that "in order to take advantage of tree shaking, you must...

  • Use ES2015 module syntax (i.e. import and export). done
  • Add a "sideEffects" entry to your project's package.json file. done .
  • Include a minifier that supports dead code removal (e.g. the UglifyJSPlugin)." done

Still, the unused/unimported leftpad function and comments are being included in my bundle.

All of the config can be seen here. Based on the results I'm seeing, I suspect that this is related to the uglify settings in my webpack config.

To reproduce:

git clone https://github.com/gpspake/es6-todomvc.git
cd es6-todomvc
yarn install
yarn build
# check dist/bundle.js
# comment new UglifyJsPlugin() out in webpack config
yarn build
# check dist/bundle.js - it's identical to the previous bundle
@alexander-akait
Copy link
Member

Thanks for issue, dup #206

@alexander-akait
Copy link
Member

@gpspake feel free to ping me, if it is not help

@gpspake
Copy link
Author

gpspake commented Mar 23, 2018

@evilebottnawi, thanks. I read that thread before submitting and I just re-read it hoping to find a solution but I still don't understand why webpack seems to silently ignore UglifyJsPlugin. My project has a minimal configuration and I am not using React so the code is relatively straight forward for this example. I have tried a lot of the suggestions in that thread but, at the end of the day, treeshaking still isn't working. Can you give me any advice about what's causing this to happen and how I might fix it?

@alexander-akait
Copy link
Member

@gpspake tomorrow i will investigate

@gpspake
Copy link
Author

gpspake commented Mar 23, 2018

Hey @evilebottnawi, I see you added needs more info tag. Is there any additional info I can provide?

@alexander-akait
Copy link
Member

@gpspake i ping you if something need, in future i think we will use other label aka status: need investigation

@gpspake
Copy link
Author

gpspake commented Mar 25, 2018

I just want to add one piece of info that I confirmed this morning which is that adding UglifyJsPlugin to my webpack config doesn't have any effect at all. If I comment new UglifyJsPlugin out in my webpack config, I get the exact same output with webpack -p
I don't understand what I'm doing wrong, here. Is it a simple syntax issue? Is it a matter of options that I'm not passing? I'm going to amend my initial comment to suggest commenting UglifyJsPlugin out in webpack config and re-checking the bundle to see that it's exactly the same.

@shivkoirala
Copy link

Its happening with me also. Have a simple webpack.config.js and uglify does not get executed irrespective what the environment variable is.

@alexander-akait
Copy link
Member

@shivkoirala can you create minimum reproducible test repo?

@shivkoirala
Copy link

shivkoirala commented Mar 28, 2018

@evilebottnawi below are details let me know if you need anything more

Typescript version :- 2.7.2
Webpack :- 4.2.0
I tired everything webpack -p , webpack --mode production, changed environment variable of node, changed to ES5 / ES6 . Bundling is happening but not uglify.. If i run uglify individually it works.

var path = require('path');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');

module.exports = {
    entry: {
        CustomerModule: "./Modules/CustomerModule.ts",
        SupplierModule: "./Modules/SupplierModule.ts",
        Startup: ["./node_modules/core-js/client/shim.min.js",
            "./node_modules/zone.js/dist/zone.js",
            "./node_modules/reflect-metadata/Reflect.js",
            "./Startup.ts"
        ]
    },
    output: {
        path: path.join(__dirname, "dist"),
        publicPath: "/dist/",
        filename: "[name].bundle.js"
    },
    resolve: {
        extensions: ['.ts', '.js']
    },
    module: {
            rules: [
                {
                    test: /\.ts$/,
                    use: ["awesome-typescript-loader", "angular-router-loader"]
                }
            ]
    }
    , plugins: [new UglifyJSPlugin()]
};

tsconfig.json

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": false,
    "noStrictGenericChecks": true,
    "lib": [ "es2016", "dom" ]
  }
}

package.json

{
  "name": "angular-quickstart",
  "version": "1.0.0",
  "license": "ISC",
  "dependencies": {
    "@angular/common": "4.0.0",
    "@angular/compiler": "4.0.0",
    "@angular/core": "4.0.0",
    "@angular/forms": "4.0.0",
    "@angular/http": "4.0.0",
    "@angular/platform-browser": "4.0.0",
    "@angular/platform-browser-dynamic": "4.0.0",
    "@angular/router": "4.0.0",
    "@angular/upgrade": "4.0.0",
    "@types/jquery": "^3.3.1",
    "@types/node": "^9.6.0",
    "angular-in-memory-web-api": "0.3.2",
    "angular-router-loader": "^0.8.2",
    "awesome-typescript-loader": "^4.0.1",
    "bootstrap": "^3.3.6",
    "core-js": "^2.4.1",
    "http-server": "^0.10.0",
    "jquery": "^3.3.1",
    "npm": "^5.8.0",
    "reflect-metadata": "^0.1.3",
    "rxjs": "^5.4.1",
    "systemjs": "0.19.27",
    "ts-loader": "^4.1.0",
    "webpack-cli": "^2.0.13",
    "zone.js": "^0.8.4"
  },
  "devDependencies": {
    "@types/core-js": "^0.9.42",
    "typescript": "2.7.2",
    "uglifyjs-webpack-plugin": "^1.2.4",
    "webpack": "^4.0.0-beta.3",
    "html-webpack-plugin": "2.14.0"
  }
}

@alexander-akait
Copy link
Member

@shivkoirala can you create this as minimum reproducible test repo?

@granttchart
Copy link

granttchart commented Apr 3, 2018

I'm experiencing what I think is the same issue on this project. Since switching to Webpack 4, production builds are ~400kB larger than Webpack 3 builds with the same codebase.

@gpspake
Copy link
Author

gpspake commented Apr 3, 2018

Could we please get a minimal reproducable example of uglifyjs-webpack-plugin working with webpack 4? Has anyone actually used it successfully?
As far as I can tell, multiple examples have been provided that demonstrate the plugin has no effect but no one has shared a working example with tree shaking.
It seems like the plugin is currently incompatible with webpack 4. I'd love to be proven wrong.

@Legends
Copy link

Legends commented Apr 4, 2018

@evilebottnawi , @gpspake

Not sure, perhaps the new way of adding the plugin is using minimizer under optimization.
If this is the case, the docs have to be updated...

    optimization: {
            minimizer: [
                new UglifyJSPlugin({
                    uglifyOptions: {
                        ecma: 5,
                        warnings: true,
                        mangle: false,
                        keep_fnames: true,
                        output: {
                            beautify: true,
                            comments: true
                        }
                    }
                })
            ]
        }

@gpspake
Copy link
Author

gpspake commented Apr 4, 2018

Thanks @Legends. I updated my webpack config. Still no tree-shaking 😢 but at least webpack seems to be honoring my uglify config with that syntax. I'm losing my mind over this. My project is so simple and it seems like treeshaking should be working here based on a lot of the examples I've seen but nothing is working for me.

  • Here's where I declare and export the leftPad function. (It's not imported or referenced anywhere else in the app)
  • Here's my webpack config

Yet, somehow, leftpad and even the associated comments are being included in my bundle.

@Legends
Copy link

Legends commented Apr 4, 2018

I would say... probably a bug...

@Legends
Copy link

Legends commented Apr 7, 2018

When devtool is set to
eval, cheap-eval-source-map, cheap-module-eval-source-map, eval-source-map, eval-source-map it does not treeshake. Bug?

@gpspake
Copy link
Author

gpspake commented Apr 10, 2018

Thanks @Legends; That helps!

If I remove devtool from my config, I'm no longer seeing the "dead" code in my bundle. However, I guess the reason I was seeing it in the first place is because I was inadvertently setting sourcemap to eval for production and the "dead" code was actually just my sourcemap.

According to the devtool docs, devtool should be set to (none), source-map,hidden-source-map, or nosources-source-map for production. Although, I've set it to sourcemap and it doesn't seem to be outputting a "separate file" as the documentation implies. 🤔

So, I'm still a little confused about sourcemap behavior but I think it's safe to say that treeshaking is working.

@Legends
Copy link

Legends commented Apr 10, 2018

If you are still using UglifyJsPlugin:

When using the uglifyjs-webpack-plugin you must provide the sourceMap: true option to enable SourceMap support.

But this doesn't help either.

I would suggest to open a new issue, if it's not a bug, at least the docs could be updated regarding this..

@Legends
Copy link

Legends commented Apr 29, 2018

Is this solved?

@alexander-akait
Copy link
Member

@Legends looks no, feel free to docs/fix PR

@Legends
Copy link

Legends commented May 1, 2018

@evilebottnawi This can be closed, it's not an issue.

@zhangolve
Copy link

zhangolve commented May 25, 2018

I have the same issue : tree shaking seems not working for me .

part of my webpack.config.js:

        new webpack.DefinePlugin({
            IS_DEV_ENV: isDev,
            IS_PROD_ENV: env === 'prod'
        })
        optimization: {
            runtimeChunk: {
              name: 'manifest'
            },
            minimizer: [
            new UglifyJsPlugin({
                cache: true,
                parallel: true,
                sourceMap: true // set to true if you want JS source maps
            })
          ]
        devtool: isDev ? 'eval-source-map' : 'source-map',

Firstly, I am using React framework. Now, I am optimizing the homepage in my app, but I found my index.js import PageHeader from PageHeader.js file ,but PageHeader.js have more than one component ,I found tree shaking not working and the other unused components have also been imported to the new file (3.45b39897170fec6f3c4e.js),

I found this issue and try @gpspake 's idea, but not working for me .And I found @Legends created a new issue and closed it .I don't know why .

PS:

I using webpack 4.6 to do the test . the size of new file (about PageHeader) is big.But when I upgrade webpack to 4.8.3, the size of new file is bigger than previous one.I am confusing.

Updated:

I followed the steps in Tree Shaking Documentation:

Use ES2015 module syntax (i.e. import and export).
Add a "sideEffects" entry to your project's package.json file.
Include a minifier that supports dead code removal (e.g. the UglifyJSPlugin).

And also not work.

@rdalfonso
Copy link

Has anyone solved this issue? I'm using "webpack": "^4.5.0", "uglifyjs-webpack-plugin": "^1.2.7", and "react": "^16.3.1". Webpack creates my bundle without removing anycode.

@architextures
Copy link

Running production mode with UglifyJSPlugin enabled will strip the methods.
"scripts": { "build": "webpack --mode production --optimize-minimize" }

@mwanago
Copy link

mwanago commented Aug 11, 2018

My recent discovery was that you also need to use ModuleConcatenationPlugin for the tree shaking to take place. Maybe that will be of any help to anyone - I've created PR to the docs (was accepted). Cheers.

@FreemenL
Copy link

Has anyone solved this issue?

@nurycaroline
Copy link

I'm having the same problem. No code is removed in bundle generation

@tianyn1990
Copy link

Dead code isn't in my bundle while I remove modules: 'commonjs' in .babelrc(or babel.config.js).
This babel config will make Babel compile the import to a require and breaks the treeshaking.
You don't need this config unless using import and module.exports in the same file.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests