question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Class Decorator prevents tree-shaking

See original GitHub issue

Command

build

Is this a regression?

  • Yes, this behavior used to work in the previous version

The previous version in which this bug was not present was

No response

Description

A library component with a (non-Angular) decorator will not be tree-shaken. The same component, if inside an app, will be properly tree-shaken.

There is a history of issues related to this topic:

Minimal Reproduction

Reproduction repository: https://github.com/fischeversenker/ng-decorator-tree-shaking/tree/274524fde27002e87f1535ef6bbef2cf8088ec8d

The essence:

This library code:

import { Component } from '@angular/core';

/*@__PURE__*/
function noopDecoratorFactory() {
  return /*@__PURE__*/ (target: any) => target;
}

@noopDecoratorFactory()
@Component({
  selector: 'lib-my-library',
  template: `my-library works!`
})
export class MyLibraryComponent {}

turns into this:

let MyLibraryComponent = class MyLibraryComponent {
};
// ...
MyLibraryComponent = __decorate([
    noopDecoratorFactory()
], MyLibraryComponent);

which seems to not be tree-shakeable.

Exception or Error

No response

Your Environment

Angular CLI: 14.2.6
Node: 16.16.0
Package Manager: yarn 1.22.19 
OS: linux x64

Angular: 14.2.7
... animations, common, compiler, compiler-cli, core, forms
... platform-browser, platform-browser-dynamic, router

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1402.6
@angular-devkit/build-angular   14.2.6
@angular-devkit/core            14.2.6
@angular-devkit/schematics      14.2.6
@angular/cli                    14.2.6
@schematics/angular             14.2.6
ng-packagr                      14.2.2
rxjs                            7.5.7
typescript                      4.7.4

Anything else relevant?

The real-life use case where this adds huge amounts of unused code to our bundles is when using https://github.com/ngneat/until-destroy#use-with-ivy in library components.

Issue Analytics

  • State:closed
  • Created a year ago
  • Reactions:2
  • Comments:5 (2 by maintainers)

github_iconTop GitHub Comments

3reactions
alan-agius4commented, Oct 25, 2022

Why is this not added by default? Angular-CLI (I’m assuming ng-packagr) adds this flag to a library’s “built” package.json, so it already automatically assumes that any Angular library is side-effect-free. Why is the same not true when importing from the source directly?

Indeed the flag is added automatically by ng-packagr unless it’s already specified.

When importing the source directly you effective no longer have a library in terms of a compilation unit and boundary rules. Rather an additional directory in the application with a nested package manifest file.

Overall, It is not recommended to build the library as part of the application either through path mapping or depending directly on the source file. This is also highlighted in the docs here: https://angular.io/guide/creating-libraries#building-and-rebuilding-your-library

The CLI build command uses a different builder and invokes a different build tool for libraries than it does for applications.

The build system for applications, @angular-devkit/build-angular, is based on webpack, and is included in all new Angular CLI projects

  • The build system for libraries is based on ng-packagr. It is only added to your dependencies when you add a library using ng generate library my-lib.
  • The two build systems support different things, and even where they support the same things, they do those things differently. This means that the TypeScript source can result in different JavaScript code in a built library than it would in a built application.

For this reason, an application that depends on a library should only use TypeScript path mappings that point to the built library. TypeScript path mappings should not point to the library source .ts files.

Other than the above, there might also be cases when consuming the so called “library” as described above could result in a slow build and increase in bundle size due to the fact that the “library” ESM modules are not flattened (FESMs).

Also, the library in my reproduction repository got created with ng generate library … Would you consider adding “sideEffects”: false to the package.json template?

I am okay with that. Although we do expect libraries to be built prior to being consumed in an application.

0reactions
angular-automatic-lock-bot[bot]commented, Nov 26, 2022

This issue has been automatically locked due to inactivity. Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

Read more comments on GitHub >

github_iconTop Results From Across the Web

File / class deleted during tree shake despite the fact it's being ...
Tree-shaking will remove unused side-effect free code. In Angular custom decorators on classes are treated to be side effect free meaning ...
Read more >
Tree Shaking - webpack
Tree shaking is a term commonly used in the JavaScript context for dead-code elimination. It relies on the static structure of ES2015 module...
Read more >
dart - how can I prevent class and its members from being tree ...
I would like to make sure that a class and all its members are not tree shaken when compiled with Dart2JS.
Read more >
Tree-Shaking Problems with Component Libraries - Medium
Tree-shaking isn't magic, and much like the garbage collector, ... will prevent your components from being tree-shaken.
Read more >
Tree-Shaking: A Reference Guide - Smashing Magazine
Tree-shaking” is a must-have performance optimization when ... They're main purpose is to prevent repetition and to leverage reusability.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found