At Pierce County I worked on the county’s central GIS applications, including public-facing apps such as Call Before You Dig and CountyViewWeb (CVWeb), described on the county’s GIS Application Options page. Some of the work was internal, so this page describes it rather than linking to every app.
Moving Off Web AppBuilder
The county’s central GIS apps were built on Web AppBuilder and the ArcGIS Maps SDK for JavaScript 3.x, and Esri is ending support for both. Around a dozen applications, some public-facing and some internal, needed a new home. I worked on moving them to ArcGIS Experience Builder, including writing several custom Experience Builder widgets in JavaScript, TypeScript and Python.
Making the Platform Decision
Experience Builder was the obvious destination, but as a newcomer to the team I noticed its costs. Widgets were tightly coupled to individual apps, so logic got duplicated across projects, and custom widgets were harder to keep up to date than a conventional versioned codebase. Because the 3.x SDK is also going away, there was a risk of building everything in Experience Builder now and rebuilding it all on the 4.x SDK later.
I evaluated modern web frameworks as alternatives, then tested one specific idea with a working prototype instead of arguing about it in the abstract. The result informed how the team built from there.
Experiment: Reusable React Components for Experience Builder and the Maps SDK
In short: reusable React components can run inside Experience Builder, but the Maps SDK copy bundled with them conflicts with the one Experience Builder loads from its CDN. That made the pattern unworkable, and the team kept building custom widgets directly in Experience Builder instead.
The hypothesis. If the core functionality lived in pure React components, the same code could run in Experience Builder today and in a standalone Maps SDK app later. That would reduce duplicate work, let components be tested outside Experience Builder, and allow a gradual migration rather than an abrupt rewrite.
The prototype. I built an IdentifyAll widget, similar to Select By Location in ArcGIS Pro, but working across layers whether or not they are visible. It was made of three parts: a Sketch widget to draw a geometry, a query utility that finds features intersecting it, and a Calcite-based feature list that also draws the results on the map. I also made some UX improvements, such as moving feature details into a table so the list doesn’t scroll endlessly and grouping results by layer.
The packaging. The components were bundled with Vite as a versioned package, with React, the Maps SDK and Calcite marked as external dependencies so Experience Builder supplies them. The package was installed into a thin Experience Builder widget wrapper like any npm dependency, and the wrapper only had to pass in the map view.
What I found
- The React approach works: the components render in Experience Builder and can be developed and tested independently of it.
- It was not fully functional. The Sketch geometry did not draw on the map, although queries still ran and returned results. The console showed errors like
Assigning an instance of 'esri.Graphic' which is not a subclass of 'esri.Graphic'. - ChatGPT suggested a version mismatch, but I had already pinned the SDK to Experience Builder’s version. Esri Support reproduced the problem but couldn’t help debug custom code.
- At the Esri Developer & Technology Summit I learned the real cause: Experience Builder loads the Maps SDK and Calcite from a CDN, while my packaged components resolved their own copy. Two copies of the SDK means classes from one fail
instanceofchecks against the other, so the map and my components were effectively using different SDKs. - Keeping package dependency versions aligned with Experience Builder (v1.16 at the time) is a manual process that I couldn’t script.
Working with Esri. The summit conversations with Esri’s Maps SDK and Experience Builder teams confirmed my diagnosis. Esri was already considering this approach as a development pattern, and it’s likely to matter more as Esri moves toward web components. We planned to reproduce the problem with the simplest possible widget and to test packaging components so they use the CDN-loaded SDK.
Outcome. The SDK conflict was a deal breaker for this pattern, so the team didn’t adopt it. They continued building custom widgets directly in Experience Builder, and still do. The experiment answered a costly question with a small prototype, before the team committed to an architecture, and it clarified how Experience Builder loads its dependencies.
Sharing it. I presented the findings to the team on March 24th, 2025, covering the problem, the prototype, a live demo, the failure and the next steps. The slides are below, or you can open them full screen.
Team Practices
Although it wasn’t part of my job title, I helped establish modern development practices for the GIS solutions team: version control, CI/CD, Jira-based project management and documentation standards for application development. I also guided the team of four developers and a project manager in adopting Scrum, with three-week sprints and the full set of Scrum ceremonies, and I introduced code review to the team’s process.
Header photo: Mount Rainier over Tacoma by Lyn Topinka, USGS (public domain), via Wikimedia Commons.
