The Isograph team are extremely proud to announce the release of Isograph v0.4! This release contains an absolutely monumental amount of features! The team is growing — since the last release, five new engineers have contributed to the project!
- There's a new VSCode extension, which provides syntax highlighting, auto format, hover info and go to definition.
- We introduced client pointers, which are functions from graph data to an ID. These allow the app developer to embed follow up queries in their isograph literals. They were the largest remaining missing primitive in Isograph.
- We introduced typesafe updaters, which provide an absolute top-notch developer experience for updating locally cached data.
- We introduced persisted queries. Instead of sending the entire query text, Isograph can send just a query ID, saving bandwidth and increasing security!
Let's talk about each of these, and more!
VSCode extension
The new VSCode extension deserves an Isograph release of its own. It completely changes the experience of working with Isograph. With syntax highlighting, go to definition and hover information, it becomes much easier to create a mental model of your app and the flow of data within it. Before this extension, Isograph literals were magic strings. With the extension, Isograph literals come alive!
And that's just a start! We spent much of the last year refactoring the Isograph compiler (more on that later) and laying the groundwork for future extension features. So stay tuned. Follow up features, like find all references, surfacing errors, autocomplete, etc. are in the works!
Client pointers
Yet another feature that deserves its own release! Client pointers are functions from some graph data, which return a (you guessed it) pointer to another object, and they were the largest remaining missing primitive in Isograph.
This might be best explained with an example. Consider a bestFriend
pointer, which selects a list of friends as well as the viewer's closeness
. The pointer
iterates over this list of friends, and returns a link to the friend with the highest closeness.
Now, in another isograph literal, we can select that bestFriend
field, and off of it, select name
(and hundreds of other fields). Great!
Now, when this is used, it will result in two queries. First, a query for all of the friends, their closenesses, and their IDs, and later, a follow up request for the best friend's name. Neat!
This allows us to avoid downloading the name
and hundreds of other fields for each friend, only to throw out most of that data. That's a waste of bandwidth and an unnecessary cost on your server.
Now, there are lots of additional features that we want to ship with client pointers, but it's extremely exciting to even get version one out!
Optimistic updates
And a third? We really should have cut some smaller releases in the mean time!
Isograph now allows you to tag certain selections as @updatable
, meaning that that client field will be passed a startUpdate
function, in which you can just modify that field. Just look at that developer experience! Just use mutate data. And not to mention, it's typesafe and performant. If you make multiple changes, they all get batched, and only components that actually read that modified field will be re-rendered!
An absolutely massive thanks to Patryk Wałach for working on client pointers and optimistic updates (and 50 million other features, besides.)
Persisted queries/trusted documents
A fourth?! Isograph now supports persisted queries. Previously, Isograph would send the full query text with every network request. This is bad — both because it requires sending the full query text twice, which is bad for bandwidth, and because this required you to expose a GraphQL endpoint.
Instead, with persisted queries, Isograph allows you to register these queries at build time, and send only an ID. This not only cuts down on bandwidth usage, but also allows you to not expose a GraphQL endpoint, drastically improving security!
See this article for more info.
Lazy loaded normalization and reader ASTs
The Isograph compiler generates many files that actually materialize the user experience you want. And one of those files is called the normalization AST. It's primarily used to write a network response into the Isograph store, and it's not necessary to kick off the network request.
And in this version of Isograph, you can annotate an entrypoint (which is like a query root) with @lazyLoad(normalization: true)
and have that entrypoint's normalization AST not be included as part of the parent bundle! Instead, Isograph will start fetching the normalization AST when it kicks off the request for data. Neat!
And if you annotate the entrypoint with @lazyLoad(normalization: true, reader: true)
, it will also not include the reader AST, which is to say, it will also not include the JavaScript for rendering the result of the query.
Isograph's north star is to allow you to build the app you want with the least amount of data and JavaScript. If it's extraneous, it should not be part of the initial bundle! And this is another example of how we're pulling that off.
Special thanks to Iha Shin and Edwin Santos, two developers who worked on this feature!
Experimental SWC plugin
Now, hitherto, Isograph has required a babel plugin. We know that isn't ideal for everyone!
So today, we're extremely excited to announce that we also shipped an experimental SWC plugin! It works with NextJS v15.0.0 to v15.0.2. We'll ship SWC plugins that work for more versions of NextJS soon.
A special thanks to Pablo Crovetto and Edmondo Porcu for working on this.
Incremental compiler
Last, and by no means least, I'd like to point out that the language server has been made possible by a massive rewrite of the Isograph compiler. It went from a batch mode compiler to an incremental one, where intermediate results are automatically reused.
Whereas in a batch compiler, any change causes the compiler to re-execute everything, in an incremental compiler, a small change (such as an update to one file), results in a small amount of work being redone (that file is reparsed, etc.) And a language server — that's sort of like a compiler where very little changes! For example, if you're hovering on one field and then on another, we should be able to reuse pretty much all of the work!
Now, one could add caching manually (for example, by file.) But that's really tough to extend and maintain, and risks opening up bugs.
So, we turned to a solution where functions can simply be annotated with a #[memo]
macro, and just like that, they're smartly cached. And we found that the developer experience was great!
And this is all powered by a homegrown framework that we're calling Pico (a smaller, simpler Salsa). This merits its own blog post, but for now, it is sufficient to point out that this was an absolutely monumental effort by Vadim Evseev (who also shipped persisted queries).
The work to make the compiler incremental is ongoing, it turns out that even with a good developer experience, it's a lot of work :).
Conclusion
Getting this release out has been a monumental effort, and this blog post didn't cover even cover everything! There is a tree sitter grammar, open telemetry integration and so many cool internal features I'd love to go on about. And since v0.3, five new contributors have helped out, including Ben Patton and Julio Teixeira. Bolt Foundry is all-in on Isograph, and having a great time using it. And now that the language server is out, there's never been an easier time to try out Isograph!
So go on, give the quickstart a try! Join the discord! Star the repository!