Reducing bundle size with GoJS 2.0

Thanks for adding GoJS 2.0.0-beta5 to NPM and I now have it in our ReactJS app. With the rewrite of GoJS 2.0 does it support webpack tree shaking and do you have any examples of how to reduce bundle size? With GoJS 1.8 we did this:

import go from 'gojs';

With 2.0 I’m in the process of doing this:

import {
  CommandHandler,
  Diagram as GoJsDiagram,
  Geometry,
  GraphLinksModel,
  GraphObject,
  Link,
  List,
  Node,
  PathFigure,
  PathSegment,
  Point,
  Shape,
  Size,
  Spot,
  ToolManager
} from 'gojs';

I’m hoping doing the above will reduce our go.js footprint down from 1.26MB. The one thing is there a function or class I can import that will handle this?

go.licenseKey = process.env.REACT_APP_GO_LICENSE;

Currently I’m importing the entire go object to handle this.

Unfortunately right now you can take advantage of tree-shaking only when building from the TypeScript source code. With the TS source, you can build your own go.js bundle. But the current go.js files still contain everything and cannot be tree-shaken (they’re minified ES5 JS after all).

For some info on building from the source, see this page: Building GoJS from Source -- Northwoods Software

We have example projects for building from the source, which will be on GitHub when 2.0 is released, and I can share them with you if you also plan to get the source. (If you have a current valid license, we are happy to send you the 2.0 source even though it is in Beta).

Some words of caution on building from source and total payload size, though: The go.js file is highly optimized (and is smaller than go-debug.js, and has also gotten smaller for 2.0). This is especially true if you compare gzipped sizes. We pass our code through the Google Closure Compiler, with some custom steps before and afterwards, to achieve this small size.

In order to “beat” its size you will have to remove a considerable amount of GoJS functionality, which may not be possible for your project, or you must be sure to use a very good minifier, which may take considerable work to do correctly owing to the size of GoJS.

It may be possible in the future that we release a go.js file that is capable of tree-shaking using Webpack. We are currently experimenting with an ES6 module build of go.js, which may be capable of doing that eventually, but not just yet. (If it works well, it will be released as soon as it’s ready in the 2.0 branch. We won’t delay releasing it for another version.)

But separately, where are you getting 1.26MB?

@simon Thanks for your quick reply and I’ll keep an eye out on if you release a version that supports tree shaking. go.js is 228KB Gzipped which is currently 28% of our app size.

To prepare for tree shaking, and it might be a better practice to do this anyway, we can move away from importing just go to importing the classes we use. In order to do this is there a way to set the license key with a class method instead of having to use the go object?

go.licenseKey = process.env.REACT_APP_GO_LICENSE;

What if we made it a static member of Diagram?

Diagram.licenseKey = ...

For compatibility, users will be able to set it on either.

Diagram.licenseKey would be great!

On a different subject, with 1.8 we imported using this:

import go from 'gojs';

With 2.0 my IntelliJ gives this warning “Default export is not declared in imported module”. It compiles and runs just fine but wondering if there is a new way to import ‘go’ using 2.0? Even though it appears to be working I would like to get rid of the warning.

What if you do import * as go from 'gojs'; ?

We cannot declare a default export because we cannot use the export keyword in the go.js file and keep ES5 (down to IE9) compatibility. As of 2.0 we do however now have: https://gojs.net/beta/release/go-module.js

Which ends with:

export const go = self.go;

Which I think ameliorates your warning, but this file may be broken(!) in the current Beta release.

Your first line solution works.

I did also try this before my previous post but got the same warning.

import go from 'gojs/release/go-module';

So everything works as expected then?

For now, go-module.js is simply ES5 code that ends with the export statement. In the future I would prefer if it was really ES6, so we don’t intend to publicize it just yet and it may change significantly.

I do wonder, though, why your old statement works in 1.8 and not 2.0. It would be a shame to force all customers to change the import line if it worked before, so we will investigate that too, but again I can’t guarantee anything.

Since there are no default exports (even in 1.8) I would expect import { go } from 'gojs'; to work, even if sans-curly-braces doesn’t. Since it compiles fine, I think this is actually a difference with our .d.ts file, and not the go.js file.

Yes import * as go from 'gojs'; makes IntelliJ happy and compiles and runs just fine.

A co-worker using Visual Studio Code says it doesn’t complain about this with 2.0:

import go from 'gojs';

My IntelliJ gives this warning:

Default export is not declared in imported module 
Inspection info: Validate ES6 imports

It also complains about this import:

import { go } from 'gojs';

With this warning:

Cannot resolve symbol 'go'
Inspection info: Validate ES6 imports

IntelliJ was happy with import go from 'gojs'; using 1.8.X.

BTW I have a simple project if you want to see the warning in IntelliJ or WebStorm. You can download the 30 day trail of WebStorm here:

I have a 176KB project ZIP - if you want it let me know how to get it to you (looks like only images allowed here).