shlomiassaf / ngrid

A angular grid for the enterprise

Home Page:https://shlomiassaf.github.io/ngrid

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Missing fields on table when targeting ES2015 or higher

magnusbakken opened this issue · comments

What is the expected behavior?

Targeting ES2015+ should be possible.

What is the current behavior?

When targeting ES2015 you get errors like Cannot read property 'controller' of undefined when loading pbl-ngrid elements. The precise error seems to vary somewhat, since there are multiple pieces of code that disappear from the bundle.

What are the steps to reproduce?

I don't think I can make a StackBlitz since you can't change the tsconfig.json file there, but here's how I would reproduce the error:

  1. Create a StackBlitz from the starter package: stackblitz.com/edit/pebula-ngrid-starter.
  2. Download the StackBlitz zip.
  3. Change the target to "es2015" in tsconfig.json.
  4. Add a standard environments folder inside app, with the files environment.ts and environment.prod.ts (the latter with production: true of course).
  5. I also had to add the line declare var require: any in app/datasource/index.ts to get the build to work.
  6. Run ng serve --prod.

Which versions of Angular, CDK, Material, NGrid, OS, TypeScript, browsers are affected?

I've been testing with the 1.0.0-alpha.13 version on Angular 7.2 and TS 3.2. The error happens in both Chrome and Firefox, although interestingly they actually get different errors in my test project (in Chrome it complains about controller, in Firefox it's _plugin). The discrepancy is probably just because multiple things are missing in the bundle, and different browsers load things in slightly different orders.

Is there anything else we should know?

I've seen the same problem before in rintoj/ngx-virtual-scroller#323. At least in that case the error was actually caused by the build optimizer, which will remove certain functions if it erroneously thinks they're unused. You can verify that this is the cause by setting "buildOptimizer": false in angular.json, upon which the errors disappear.

The solution in that other issue was to add "sideEffects": true in package.json. I think the same thing will fix the problem here as well, but there may be some other solution.

@magnusbakken Thank you for pointing out!

I'm familiar with this issue from other projects I have, and yes setting "sideEffects": true will solve it.

The price however, is loosing tree shake support for the library.

I would first prefer to investigate which library cause this (ngrid or ngrid-material) and more deeply which plugin(s) inside of them is the root cause.

The reason for this is probably the plugin architecture which at times might be implemented through prototype extensions outside of a class method, that is, extending the prototype directly on the module file.

I suspect it's mostly common when adding column features and properties.

For example, the drag plugin add's drag & drop functionality through mouse/touch and with it some additional column properties that the user can set.

This is how the augmentation looks like in the plugin:

declare module '@pebula/ngrid/lib/table/columns/column' {
  interface PblColumn {

    reorder: boolean;
    /**
     * When true, the item can be reordered based on the `reorder` property but
     * will not move (budge) when other items are reordered.
     */
    wontBudge: boolean;

    /**
     * Checks if the by switching between this column and the provided column the `lockColumns` constraint is triggered.
     * The lockColumns constraint is set on a group and restrict splitting of groups.
     * A Column with a locked group will not be allowed to leave the group nor new items are allowed that split the group.
     *
     * The process will check both scenarios.
     */
    checkGroupLockConstraint(column: PblColumn): boolean;
  }
}

declare module '@pebula/ngrid/lib/table/columns/group-column' {
  interface PblColumnGroup {
    /**
     * Lock column in the group, preventing the group from splitting.
     * Splitting is block actively (column from the group dragged outside) and passively (column outside of the group dragging into the group).
     */
    lockColumns?: boolean;
  }
}

declare module '@pebula/ngrid/lib/table/columns/types' {
  interface PblColumnDefinition {
    reorder?: boolean;
    /**
     * When true, the item can be reordered based on the `reorder` property but
     * will not move (budge) when other items are reordered.
     */
    wontBudge?: boolean;
  }
  interface PblColumnGroupDefinition {
    /**
     * Lock column in the group, preventing the group from splitting.
     * Splitting is block actively (column from the group dragged outside) and passively (column outside of the group dragging into the group).
     */
    lockColumns?: boolean;
  }
}

To support the logic for these user-defined options some runtime code is required:

function checkGroupLockConstraint(this: PblColumn, column: PblColumn): boolean {
  for (const id of this.groups) {
    const g = this.groupStore.find(id);
    if (g && g.lockColumns && !column.isInGroup(g)) {
      return false;
    }
  }
  return true;
}

PblColumn.extendProperty('reorder');
PblColumn.extendProperty('wontBudge');
PblColumn.prototype.checkGroupLockConstraint = function (this: PblColumn, column: PblColumn): boolean {
  return checkGroupLockConstraint.call(this, column) && checkGroupLockConstraint.call(column, this);
}

PblColumnGroup.extendProperty('lockColumns');

The tree shaker can remove these.

This is just one thing that can be tree-shaked, there might be others, I need to see.

Instead of setting "sideEffects": true right away I would like to solve it with the following points in mind, falling back to the lower point if the previous failed:

  • Understand the causes and try to write them in a tree-shakable way
  • Try to understand why it happens when targeting ES2015 and not when target a lower spec
  • Try to see if specific files can be marked with sideEffects and the majority is left tree-shakable. (webpack should support this)
  • Finally, if nothing can be done, temporally set sideEffects to true and figure out a long-term solution.

Any help with resolving this issue is much appreciated!

UPDATE

First, make sure module is commonjs when targeting ES6/ES2015. This is a TS rule, however will not solve the problem.

Indeed, setting "buildOptimizer": false will make this go away which means that the terser minifier is not to blame, most probably angular's transformation along with tsickle are responsible.

I'v found strange things... really strange!!!

For example, in the grid's constructor, 2 method calls are magically removed when the build optimizer is on... What makes this more strange is the fact the the optimizer DID NOT remove the methods code but removed the call to them in the constructor ?!?!?

Ok, I wrote the code within the constructor just for testing, moving on, just to find out that super calls in another class is omitted, while explicitly set in TS code (which will not compile otherwise)

I'm quite clueless at the moment :) really strange behaviour.

I will have to debug this deep through, find out what annotation is added to these places before they go over to tsickle and / or being processed by the closure compiler in the build (I guess...)

@magnusbakken I think this is angular issue, see angular/angular-cli#12112

While it looks like solved, I see recent reports from people about this issue occurring after the fix issued.

We will have to wait on this i'm afraid...

I've tried the latest packages (LTS) including a new package build with them and using it in the demo app, no luck.

ohh boy this is a nasty bug, wasted 4 hours of my life, hope the angular team will appreciate it and solve this one for us.

angular/angular-cli#14416 (comment)

Wow, good work! This was a much more complex issue than I anticipated.

It sounds like those bugs in the build optimizer won't be trivial to fix. In the meantime, can you think of a reasonable workaround for this problem when using NGrid? Preferably one where it's still possible to target ES2015+ and have the build optimizer enabled?

@magnusbakken Based on this answer it seems that the angular team will not fix the issue for the 7.x.x release but it will get fixed for 8+.

Once I will have a release for V8 it should be solved