Select to view content in your preferred language

How to save on build time for ES modules with Webpack?

526
5
04-01-2024 08:19 PM
JasonDoingMaps
New Contributor III

Per the Build with ES modules guide, I'm using the @ArcGIS/core NPM package along with TypeScript and Webpack. A significant portion of the build-time for my app is spent compiling the ArcGIS JS SDK dependency. This is particularly noticeable when producing production builds on a build server. I want to reduce the build-time impact to as close to zero as possible.

What I'd ultimately like, is a pre-compiled version of the library. I do this with many other large 3rd party libraries, typically taking a local copy of the library and making use of Webpacks externals configuration. Without a pre-compiled ESM JS library (other than the "for testing only" / not optimised CDN version), I don't see a way to do this.

An alternative I explored was using Webpacks DllPlugin, thinking that if I still must compile it myself, I could at least compile it far less frequently. My apps own code is changed and re-compiled many times per day, but I don't change ArcGIS JS SDK version anywhere near that often. Why be forever re-building the same thing again and again? But ArcGIS JS SDK doesn't seem immediately friendly to DllPlugin, per my own quick experimentation, and this other question in the forum.

AMD modules would give me a pre-compiled option, but I'd like to keep TypeScript type-checking, and I see that's now deprecated for AMD. https://github.com/Esri/jsapi-resources/tree/main/typescript
"The AMD TypeScript declaration files and the arcgis-js-api npm package have been deprecated at 4.29 and will be retired at 4.31. if you are building a new application, we recommend using the @ArcGIS/core ES modules"

The only remaining option I can think if is a bit "outside of the box", and that's to create another entry point in my Webpack build dedicated to ArcGIS JS dependencies, and be selective about when I build that. That could be a bit clumsy though.

Am I missing anything? Does anyone have any insight into the future of ArcGIS JS SDK on this point? I see there's web components in (unsupported) beta for example, it looks like that might offer a pre-compiled option.

0 Kudos
5 Replies
AndyGup
Esri Regular Contributor

@JasonDoingMapsto speed up your webpack/TypeScript dev builds, you might look into https://www.npmjs.com/package/esbuild-loader.

0 Kudos
JasonDoingMaps
New Contributor III

Thanks for the pointer @AndyGup , that's a project I wasn't familiar with. The performance improvement switching from ts-loader to esbuild-loader in my case is... modest. On my dev PC (which is a lot faster than the build server), the build went from 55 seconds down to 48 seconds. So a saving of about 13%. It took a little tweaking too, as the default settings resulted in build errors.

On the other hand, removing all references to ArcGIS JS SDK from my project takes the build time down to 17 seconds while still using ts-loader. A saving of about 70%. The vast majority of my apps build time is spent building (and re-building every single time), the ArcGIS library.

Hence, far and away the biggest improvement I could get in build performance, is an approach that doesn't always re-build the ArcGIS library dependency. The pre-built AMD modules served that scenario, but per above, the TypeScript typings for that are being deprecated. A pre-built / bundled set of ES modules would work well, but the ESM build on the CDN is "not for production". It just seems like such a strange ask that consumers of the ArcGIS JS SDK have to build + bundle it themselves, whereas every other library I use has a pre-built / bundled offering with TypeScript typings. The problem is further exacerbated by the fact that the ArcGIS JS SDK is so big. Why is the biggest library I reference (by a huge margin) the only one that doesn't come with a viable pre-compiled option?

AndyGup
Esri Regular Contributor

Do you require the Webpack-specific tooling? If not, you might take a look at Vite.js.

> The pre-built AMD modules served that scenario, but per above, the TypeScript typings for that are being deprecated.

If/when you migrate to (new) map web components, those are typed.

> Why is the biggest library I reference (by a huge margin) the only one that doesn't come with a viable pre-compiled option?

TL;DR - It stems from a well-known limitation of ES modules. Components will make life much easier in that respect.

Currently for ESM there's no ECMA-standard equivalent to the AMD dojo build layers. Those are what makes the AMD ArcGIS CDN much more performant than the ESM ArcGIS CDN. For example, JavaScript module declarations have been in TC39 Stage 2 since 2022, and it could be quite a while before it gets finalized as a standard and then adopted in browsers.

JasonDoingMaps
New Contributor III

Thanks for the reply Andy.

I am tied to Webpack for the time being, but will look into Vite as a possibility for the future.

I'm trying to read between the lines in your response though, as to why ArcGIS specifically is the only JS library I'm using that doesn't come precompiled. As in, why is it more optimal for me to be re-building ArcGIS JS with every release I do, as opposed to the Esri team distributing a precompiled version? Every other library I'm using comes with a ".min.js", and most also happily point to a CDN. Are they somehow sub-optimal? Why is ArcGIS different? Is it the size of it? Even if it is the size, I still don't see how that makes it better for my build-server being the one doing the work.

What is the well-known limitation of ES modules you mention - it's not known by me!

0 Kudos
AndyGup
Esri Regular Contributor

> What is the well-known limitation of ES modules you mention

I mentioned it above. Basically, unbundled ES modules (ESM) such as "@arcgis/core" typically perform poorly in a production environment. We are constantly optimizing the ArcGIS JS Maps SDK, however ESM builds require a combination of treeshaking, lazy-load and code splitting (chunking) to create an optimal build output. This isn't specific to ArcGIS, for example you can read about why bundling is recommended in the Vite.js documentation:  https://vitejs.dev/guide/why.html#why-bundle-for-production.

> Hence, far and away the biggest improvement I could get in build performance, is an approach that doesn't always re-build the ArcGIS library dependency.

Vite.js could really help with your use case of having fast(er) build times. Vite does dependency pre-building to dramatically speed up builds: https://vitejs.dev/guide/dep-pre-bundling. Try this sample app: https://github.com/Esri/jsapi-resources/tree/main/esm-samples/jsapi-vite-ts. On my 5 year old machine it takes 20 seconds for a production build.  For dev builds, it's pretty close to zero on my machine - it takes about 150 - 170ms (milliseconds), and rebuilds are almost instant.

And, also to reiterate checking out the new map-components. You can access those via CDN and they include TypeScript types: https://developers.arcgis.com/javascript/latest/components-get-started-cdn/.

0 Kudos