DEV Community

paulmojicatech
paulmojicatech

Posted on • Edited on

Evolution of Web Development

In this post, we will take a look a new pattern emerging on the front end development world called islands architecture. Much of this article is inspired from patterns.dev.

History

Let's go ahead and start with the history of web development. In the beginning, we server rendered everything on the web. This means that we had a web server that ran all the code. A user would open a browser, type the web site address, and be routed to a web server hosting the web site. That web server would would execute the code to run the web site.

The problem with this approach is that the web site is static. This means that the data would be retrieved and consumed by a file that the website would serve and the user would see the web site on the screen but they could not really interact with the page. All they could do was consume the document on the screen that the web server served.

But this was not enough. Users needed to interact with the screen. They needed to click a button that would show or hide some part of the screen. They needed to show a dialog to ask the user if they really wanted to click that button. Enter javascript. Now, when a user goes to a web site, the web server send back a file with some javascript along with the document. Javascript allowed code to be executed on the client (the user's machine). Now there was a way for a user to actually interact with the document on their screen.

But there was still a problem. When a user wants to go to a different screen, another request need to go back over the network, the web server would serve a completely different document. Whatever items that were shared between the previous screen and the next one, needed to exist in both documents. The code needed be executed on the previous document would need to be executed again. The back and forth between the web server and the client (the user's computer) happened many times as the user navigated the website. Also, all of the state during the user session was stored on the server. The client, for the most part, didn't really have access to it.

This lead to the next stage of evolution, SPAs. A SPA (single page application) flipped the paradigm where the client would run all the code. When a user navigates to a web site, the web server would serve only one document, the index.html file. But along with that file, the web server would send down all the javascript files needed to execute for the web site to run. The index.html file would have references to the javascript that would run on the client. This means that would a user navigates between screens, the client doesn't need to go over the network unless it needs data from the server. Also, a developer can layout a screen so that parts of the application can be shared between screens. Another benefit is the application state moves from the server to the client. This gives the user a smoother experience, especially navigating between screens.

This sounds great right. We have now solved the world's problems. Not so fast... SPAs have a significant drawback. As web applications grew in complexity, so did the size of the javascript files that needed to go over the wire. It only makes sense right, the more complex the application, the more code that needs to be executed. The more code to execute the bigger the files that need to be shipped to the client. Some frameworks "solved" this problem with bundling and lazy loading. This was accomplished by the need of a compile step to break the javascript files up into smaller chunks (or bundles). Lazy loading made it so that not all javascript needed to go over the wire right away. The web server would only send the javascript that needed to be executed on the first screen. As the user navigates to a new screen, the existing javascript would know to call over the network to fetch new javascript for the new screen.

The big problem with this approach is it had its performance issues when rendering the new javascript. When new javascript came in, the client needed to understand how to consume it. This is what is called hydration. The new javascript would come down and the client needs to know where on the screen to render the new data or updates. Different frameworks handled this different ways. Some tracked the state of the DOM (this document and its elements) and the new javascript would make its updates in a virtual DOM (clone of the current DOM) and then sync the changes. Some frameworks completely destroyed the old DOM and reconstructed it again with the new javascript. Either way, more compute was happening on the client that needed to happen.

Some attempts to fix this was to go back to SSR (server side rendered) applications but we still have client side hydration. This helped with screen load time since the web page can be rendered on the server right away while the parts that the client needed for interactivity was sent over the wire. When a user navigates to a new screen, the request would be sent to the web server and a new document would be rendered and new javascript files sent over the wire. However, this did not solve the hydration problem. While hydration still could happen on the client, that hydration would still need a way to keep track of how to update the DOM. This again caused code to execute on the client that to keep track of the DOM state.

And finally we get to the latest pattern, islands architecture.

What is it?

Islands architecture tries to solve the problem by having multiple entry points on a screen. Static content would be served on the server while the dynamic parts of the application would be encapsulated into another entry point that contains the javascript to execute. The execution only happens within that entry point, hence the code living on an "island". This can also be described as micro-frontends. Each dynamic "island" doesn't care about any other part of the screen, so there is no need to keep track of the entire DOM on the screen. Code is executed only as needed.

This is still a fairly new paradigm so implementation is still at its infancy. There are currently several frameworks that hope to help implementing this pattern. One is Astro. Astro is explicitly aimed at implementing island architecture. It has integrations with React, Svelte, and Vue to name a few frameworks that can be used.

Another framework that hopes to aid with the implementation is a framework created by Misko Hevery called Qwik. Misko was also the author of one the first highly adopted SPA frameworks AngularJs and later Angular. Qwik's strategy is around what they call "resumablility". This means that the web server sends only the HTML and CSS over the network. It serializes all of the bindings for the DOM elements in the HTML. This framework know that javascript needs to be fetched by parsing the serialized data. When a user interacts with an element that needs new javascript, the framework fetches the javascript, parses the serialized data, and "resumes" the application by executing the javascript based on the bindings. This means that it does not need to rehydrate other elements on the screen. The javascript knows which parts to update based on the serialized binding data.

A third framework is called Fresh. Fresh runs on the Deno runtime. Deno is a newer javascript runtime created by the original Node author Ryan Dahl (Deno itself is a whole other topic). Astro and Fresh are very similar is philosophies, the major difference being Fresh is run in a Deno environment.

Conclusion

The evolution of web development has seem different stages, from fully rendering on the server, to fully rendering on the client, to loading partly on the server and partly on the client using hydration for interactivity. The next big shift is the islands architecture. It boasts faster load times and even allows for interacting with a web site with javascript turned off. It accomplishes this by providing multiple entry points to a web site. The static parts of the side site is served on the server with no javascript needed. The dynamic parts are encapsulated into an entry point that executes the javascript on the client. If javascript is turned off, the static parts of the app still work.

Hopefully you enjoyed reading this article. I am hoping to do a deeper dive into the different frameworks in future articles.

Follow me on Bluesky.

Top comments (0)