The usage and demand for large-scale Micro-Frontend Applications (MFEs) and highly performant Multi-Page Applications (MPAs) has increased over the years. Although a large amount of tech enthusiast is still new to some of the concepts surrounding such applications, today, there are tons of tools that enable efficient and extensive development of scalable, more efficient frontend applications.
We are going to be looking at Astro, a Multi-Page Application (MPA) development framework that introduces new and exciting ways to better handle multiple frontend modules and independent components in frontend applications using a concept called ‘Astro Islands’.
In this article, we will cover some of the details challenges and possibilities with using Astro to build your large scale multi framework front-end project or simply migrating existing suites, portals, or web applications. The aim is to present Astro as a potential choice for large, medium and small-scale projects while outlining potential problems and challenges. Since we will be integrating multiple frameworks with Astro, we will try not to go too deep into the intricate details to keep the reading short while still giving you value for your time.
There are some features and functionalities in Astro that are worth mentioning, since most people may be used to building large applications using other technologies and architecture, here are a few things that Astro does differently from other frameworks and libraries.
While Multi Page Applications (MPAs) are not a new concept, a lot of web apps today are Single Page Applications (SPAs), especially where such applications are based on React, Angular or Vue. Complex MFE components and projects benefit a lot from MPA architecture. It reduces complexity and boosts overall performance of application when it comes to rendering, optimization, security, routing and some other aspect of application since by default Astro comes with server-side rendering (SSR) and handles a lot of processes behind the scenes. That in turn reduces the time the browser spends making basic decisions.
Not all applications will benefit from the MPA approach, and one should understand the differences of both before investing time into it.
Astro introduces a concept called “Astro Island”. The feature along with other functionalities allows the framework to combine components from different frameworks into a single page without conflicts or problems of one framework or library affecting the other.
Built-in default routing setup that does not need any additional setup, once a project is created. There is no additional config file or any setup to get basic routing up and running. No need to specifically define routes or configure paths; everything is based on what pages you have and how they have been named / placed in their respective folders. In the case where there is a need to configure more complex routing situations, Astro does provide developers with an effortless way to customize the routes. Overall, it is possible to speed up the process of setting up Astro projects just by using this feature.
Astro provides developers with a list of official plugins that enable integration with third party libraries, tools, frameworks and serverless solutions. Adding support for these tools such as React, Vue and Netlify is as easy as running a command using the Astro command line tool.
While a command line tool is not the most innovative thing, it is worth mentioning that the Astro CLI does a bit more than just build and create new projects. It also provides developers with commands such as adding support for third party tools, serving the project, type checking and other useful commands for day-to-day development.
For those already familiar with MPA’s you will agree with me that this point is not so much of a downside if you understand the concept of working with data in MPA’s leveraging cookies, local and session storage, caching, query / path variables and generally storing only the basic things you need. It is also a good thing from an architectural perspective as it encourages your independent components to be ‘truly independent’.
Setting up an Astro project is easy partly because of the command line tool available. One of the commands available is the create command that provides the possibility to create a new project npm create astro@latest Once the command is executed, a new project which gives you a starter template to work from is generated. If you do not want the starter template, one can easily select the blank project option and by default, the support for .astro files, .html files and custom web components is included in basic Astro projects from the start.
With Astro, it is possible to combine multiple frameworks into one project. The idea might come across as strange for a lot of people. There are many use cases for such implementation, especially with products containing various standalone functionalities or products with multiple teams developing distinctive features that need to work together in the same wrapper project. Most often, companies might use similar technologies across the board, in other cases, there might be big differences in what teams use.
Where a large product is involved, Astro’s ‘Island’ approach to isolating components helps with properly separating concerns with many independent components. This functionality is so robust that I would say it gives birth to the possibility of using different frameworks / technologies combined in a single Astro wrapper project.
For our example, we will consider projects using the following technologies to be bundled into our sample Astro wrapper project:
For Astro components we use the default components that comes with the starter template and added some simple html pages and JS. Astro had no problem rendering its own components or working with regular html, css and js files. Code samples can be seen at https://github.com/itmaginationdemos/astro-multiframework-demo.
Using the create-astro command line tool, a new project is generated rather quickly. Since Astro provides a built-in routing using file structure, a new folder is created under the pages sub folder.
We do not need to install any additional plugins to use custom web components in astro as it is supported by default. After creating a new project, we may go ahead, and create a custom web component along with its html, css and js code and add it to an .astro file under the pages/web-component sub folder.
The project compiles successfully and we can see the component rendered with functionalities working.
Note: With .astro files, Web components can be imported and rendered without errors as long as other framework support are not added to astro.config.mjs. if additional supports are added for any framework e.g React or Vue, the custom component is affected and Astro tries to pre-render it causing it to run into a DOM related issue particularly when using methods from the windows class. In such cases, using the registered tag as opposed to an imported class should resolve the issue permanently.
Out of the box routing worked like a charm, passing data through attributes to the component worked as expected. Using built-in component methods also works. Rendering the custom component through the registered tag name as well as the Astro imported class works with ease. If you are looking to run Web Components on Astro, then we are sure you will be able to do so. You may find an example on our GitHub, here.
Using the astro add lit command, Lit Element support can be added automatically to project. There is also a manual guide to adding lit support which includes the packages to add and configurations to change in the astro.config.mjs file. Lit Element components and Astro components can be rendered in the same .astro file as well in separate html files.
Note: With Lit Element, annotations and annotated properties do not work out of the box, additional efforts need to be made to make them compactable. Instead, static properties are used as seen in our example.
Key features seem to work out of the box, however, there are some pitfalls to pay attention to when including the components into Astro projects and most of them are documented in a guide that can be found on Astro’s website. It was discovered that there is no support for adding annotations out of the box and some additional effort is needed to get them working.
Astro supports React components. Using the MFA framework and your existing React components is straightforward as we can add support for react using astro add react, which sets up everything needed to get going with react components.
Note: You might need to disable server-side rendering using the client:only=’react’ in specific instances where a component needs to pass props or render an update to internal components in a dynamic way that is not supported by server-side rendering. These cases may be rare and even not there for much longer as the Astro developers are actively working to improve the platform.
It seems the developers paid a lot of attention to the React integration as React components work seamlessly with Astro and currently has the least amount of bugs / integration challenges. For most of the react sample setup process, react functionalities was implemented with ease as seen with the Todo list example above.
Just as it is the case with Lit or React, adding Vue is a frictionless process. All you need to do is execute the astro add vue command and support for Vue components will be added. Using Vue components in .astro files and in independent .html file in Astro project was successful based on the example below.
Vue components, features and methods are supported and there are no major concerns with integrating Vue with Astro.
Astro does not have an official plugin for bridging Angular components with Astro BUT there is a third-party plugin listed on the official website of astro called analogjs. This plugin does allow us to integrate Angular components into our astro project and using the inbuilt command astro add @analogjs/astro-angular we can add support for Angular components to our Astro wrapper project.
At a glance, it seemed the angular package adds the highest number of dependencies when installed, this could be partly due to the fact that angular modules / components are not engineered to be pulled apart and added to third party projects in raw / un-compiled form and as such all the additional dependencies that make up a fully functional angular project are needed, it could also be related with the fact that the support is provided through a third party framework / library (analogjs) and due to how the library is built it needs all the additional packages. Since we do not go into smaller details in this article, we will leave the thoughts open for comments.
Creating and using Angular component in Astro requires an addition of typescript config file tsconfig.app.json and as well component code should be written in .ts files as this is the default for angular projects. Adding ts support here also shows that other components in Astro wrapper project could also be written in TypeScript if proper configuration for them is present.
After the initial setup, Angular components' change detection did not work and ‘astro run dev’ command stopped working. After further investigation, we discovered, that:
1. Angular + Astro project seemed to be slower compared to Astro without Angular and this is when you do manage to get it to work as seen in the example by Brandon Roberts https://github.com/brandonroberts/angular-astro-islands
2. Astro run dev command gives errors when trying to visit the site such as out of memory, this happens when multiple frameworks are used but not reproducible with only Angular and Astro in one project.
Note: As described in the article by brandon roberts, The Angular integration only supports rendering standalone components. For all angular projects built before the development and release of standalone component support in Angular framework, there is work to do before the project can be compactable with Astro.
Angular components in .astro files are somewhat functional. Aside from the obvious challenges, working with angular in astro is indeed possible but not recommended with current setup if you the astro project will also host components from other libraries. Currently, Angular framework presents the biggest challenges while working in a multi framework Astro project. There might be some ways around it like building the final Angular project and adding it to Astro project as compiled html,js, and css files which worked as intended in our example but trying to use the components directly, especially when working with a robust project leveraging multiple frameworks, will bring some challenges and struggles.
It is important to note that Angular is not the only framework with challenges during integrations as seen in previous frameworks, there will always be some downsides with the process of migration and adding functionalities but so far, the support available for the TypeScript framework for large apps in Astro is the least promising.
Furthermore, by using the new static site generator, we solve the issue of Angular on the JAMStack. It is already addressed by Scully, though Astro.js gives us much more flexibility.
Using All Components on One Page
After implementing the various frameworks, pulling them together for use anywhere in the Astro project was the easiest part. The components were imported into the .astro file and the custom element tags referenced in the html section of the file. There were no issues with building or rendering this .astro file, making the verdict for using Astro in this way positive.
Astro handled most of the integration like a champ, displaying the excellent engineering that has gone into making the platform so far. Quite frankly, we are impressed with the result.
There are some differences between using components in .astro files and using them in .html files directly. One such difference is importing component from JS or own framework files into .html files, this proved challenging for each project as they either need to be loaded as modules which Astro supports or kept in the public folder to be able to properly import them by referencing the source for example using the script tag <script src=”my-component.js”></script> where my-component.js is in the public folder.
This can place a limitation on project organization and although it might be customizable, most of the examples where components are rendered in their own html files now feature a single component with all needed code bundled into the .html file. We would say this restriction is by design as the concept of islands is reflected in this behaviour and forces the developer to ensure that components are as independent as possible through organization of related code and proper encapsulation of logics.
In general, we would recommend using .astro files as much as possible to reduce the amount of effort needed to properly configure these projects to be compliant with Astro. Quite frankly, you could drop all other JS libraries and frameworks, and use only Astro’s native files, though sometimes it cannot be the case.
Astro showed great prospects throughout the development of the example project and hopefully it gets more adoption and development time. The code sample made for this project can be found at https://github.com/itmaginationdemos/astro-multiframework-demo Feedback is most welcome, and you may reach the author of this article, and of the demo, on Twitter @ZinoAdidi.