webpackwebpack-5tree-shaking

Webpack5 does not seem to tree-shake unused exports


I set up a small project with the following files

- src/
  - lib/
    - lib1.ts
      - export : func_lib1_1, func_lib1_2
    - lib2.ts
      - export : func_lib2_1, func_lib2_2
  - pkg1/
    - pkg1.ts
      - import & use : func_lib1_1, func_lib2_1
  - pkg2/
    - pkg2.ts
      - import & use : func_lib1_1
  - pkg3/
    - pkg3.ts
      - import & use : func_lib1_1

I configurated the various build/package/optimisation settings as per the official documentation :

webpack.config.js

    mode: "production",
    optimization: {
        usedExports: true,
    },

package.json

    "sideEffects": false,

pkgX.ts

    import { func_lib1_1 } from "../lib/lib1";
    
    console.log("pkgX");
    console.log(func_lib1_1());

But in the resuting bundles I still see the unused function func_lib1_2 and func_lib2_2 being inclued:

pkg1.bundle.js

    /***/ 119:
    /***/ ((__unused_webpack_module, exports) => {
    
    Object.defineProperty(exports, "__esModule", ({ value: true }));
    exports.func_lib1_2 = exports.func_lib1_1 = void 0;
    function func_lib1_1() {
        return "func_lib1_1";
    }
    exports.func_lib1_1 = func_lib1_1;
    function func_lib1_2() {
        return "unused, shouldn't be bundled";
    }
    exports.func_lib1_2 = func_lib1_2;
    
    /***/ }),

Do you know why? What can I do to fix this and get the by-the-book tree-shaking that I seek?

Minimal repro setup available here

Thanks in advance

Update : more infos from optimizationBailout: true

  modules by path ./src/lib/*.ts 666 bytes
    ./src/lib/lib1.ts 333 bytes [built] [code generated]
      Statement (ExpressionStatement) with side effects in source code at 2:0-62
      ModuleConcatenation bailout: Module is not an ECMAScript module
    ./src/lib/lib2.ts 333 bytes [built] [code generated]
      Statement (ExpressionStatement) with side effects in source code at 2:0-62
    ModuleConcatenation bailout: Module is not an ECMAScript module
  ./src/pkg1/pkg1.ts 263 bytes [built] [code generated]
    Statement (ExpressionStatement) with side effects in source code at 2:0-62
    ModuleConcatenation bailout: Module is not an ECMAScript module
  ./src/pkg2/pkg2.ts 182 bytes [built] [code generated]
    Statement (ExpressionStatement) with side effects in source code at 2:0-62
    ModuleConcatenation bailout: Module is not an ECMAScript module
  ./src/pkg3/pkg3.ts 182 bytes [built] [code generated]
    Statement (ExpressionStatement) with side effects in source code at 2:0-62
    ModuleConcatenation bailout: Module is not an ECMAScript module

This is intriguing. Is there something wrong with the way I declare my exports?

Update 2 : it works without ts-loader!

I tried changing all files to .js and removing the whole ts-loader thing. Tree-shaking now work as intented.

The updated question now is : how to make it work with typescript?

Similar questions that may be revelant, but with different context


Solution

  • I figured it out myself, auto-answer for the record :

    The tsconfig.json was wrong, it wasn't preserving the ES6 module syntaxe so webpack couldn't treeshake properly.

    More details on the correct configuration (optionally including Babel too) can be found here