Home > Enterprise >  How to provide Webpack tree-shaking for the usage of library distributing as ES20XX-modules
How to provide Webpack tree-shaking for the usage of library distributing as ES20XX-modules

Time:10-02

Unfortunately, there were not the working solution for the question How to setup the TypeScript compiler for the library so that the unused modules will be cut off by Webpack in the dependents projects? (for the Sep. 2021). The solution suggested by Mr. Craig Hicks works only locally and can not be used for the distributable library (I'll explan the details below).

However, from the Mr. Hicks's answer I knew that to make Webpack three-shaking available it's required to distribute the library as ES modules. It makes the issues for usage with Node.js native and ts-node, but I afraid I will be downoved if try to consider all of these problems in single question.

Target

The target library @yamato-daiwa/es-extensions has a lot of functionality and even in big applications a part of it will not be used. Theoretically, the Webpack's three shaking could cut off the unused functionality, but actually it works with huge limitations as it will be shown in experiments below.

In the sample below, I am expecting that only isUndefined function will be bundled and any other functionality will NOT be:

import { isUndefined } from "@yamato-daiwa/es-extensions"

const test: string | undefined = "ALPHA";
console.log(isUndefined(test));

console.log("End of the script");

Here is the full repository with reproduction consists from the local copy of @yamato-daiwa/[email protected] (Library directory) and consuming project (ConsumingProject directory).

Experiment 1: Close to real

In this experiment, I'll install the library as usual:

{
  /* ... */
  "dependencies": {
    "@yamato-daiwa/es-extensions": "1.0.1-experimental2"
  }
}

For the trial results, I'll remove all dependencies before install them:

npm run "Clear dependencies and reinstall"

where Clear dependencies and reinstall is:

"scripts": {
  "Clear dependencies and reinstall": "(rm node_modules || del node_modules /F /Q) && npm i",
  "Webpack:ProductionBuild": "webpack --mode production"
}

Next, I'll run the "Webpack:ProductionBuild". In compiled BrowserJS.js we can see that whole library has been bundled (1 row and 21579 columns for minified version):

(()=>{"use strict";function e(e){return null!==e}function t(e){return void 0!==e}function i(e,t){return void 0===e?t:e}
/* and so on ... */

This experiment available in the "experiment1-close_to_real" branch.

Experiment 2: Get the library locally

Now the ConsumptingProject refers locally to Library:

"dependencies": {
  "@yamato-daiwa/es-extensions": "../Library"
}

It's important to clean previous node_modules and reinstall the dependencies:

npm run "Clear dependencies and reinstall"

Then,

npm run "Webpack:ProductionBuild"

The output BrowserJS.js has exactly 21579 columns as in previous experiment.

This experiment is available in experiment2-local_dependency branch.

Experiment 3: Getting the library locally from Distributable directory

Now the library will be got from the Distributable directory of the Library:

"dependencies": {
  "@yamato-daiwa/es-extensions": "../Library/Distributable"
}

This is what Mr. Hicks suggested.

Let's clean the previous node_modules and reinstall the dependencies:

npm run "Clear dependencies and reinstall"

And if we execute the "Webpack:ProductionBuild", the unused functinality finally will be cut off:

(()=>{"use strict";console.log(!1),console.log("End of the script")})();

But what this solution matters for the published library? Normally, the library will be installed as @yamato-daiwa/es-extensions, so what I and library users need three shaking works for this case. By other works, in the Experiment 1 we need same results as in this, third experiment.

This experiment available in "experiment3-local_distributable" branch.

CodePudding user response:

It appears that declaring "sideEffects": false is the responsibility of each package an application consumes, so setting it in the application's root package.json isn't enough.

The package.json of @yamato-daiwa/es-extensions needs to include "sideEffects": false, so applications know that package is side-effect free. I tried this in your first example repo, and the final build gave me the expected:

(()=>{"use strict";console.log(!1),console.log("End of the script")})();
  • Related