Piral is an open-source framework for microfrontends based on React. It brings everything to create amazing frontends using a scalable development approach.
The agenda should be almost identical in each post. We'll use
- Current progress to explain what has been done since the last post
- Future plans to explain what we are currently working on or have in our direct pipe
- Other thoughts to list some of the thoughts for future development
Please reach out to us in case of any feedback, ideas, or criticism. We'd love to improve!
This week we shipped Piral 0.9.0. The changelog is long. But the most important change should not be forgotten:
Piral now uses a special build of the Piral instance for pilet development!
Why that? We'll without referencing the original issue that spawned this one we can boil it down to three factors:
- The former build relied the original sources of the Piral instance and its dependencies, which could be quite heavy
- Previously, the integration of the debug build of a pilet was different to integration of the production build later on, resulting in potentially bad surprises and confusion
- During upgrade NPM could, unfortunately, install different versions leading to multiple packages with different versions - this, too, could lead to suprises and confusion
As a result, we wanted to introduce something that provides a super fast build and installation experience plus consistency. Debugging a pilet should be the same as running it later on - except that more debug output and other helpers are available.
How did we achieve this? We now provide two build artifacts on
piral build. The
--type option makes it possible select also just a single one (either
release; the default option
all produces both artifacts). While
release will provide a directory with files for upload to some storage,
develop creates a tarball for distribution (usually via some NPM feed, otherwise classically from disk).
As a consequence there is now no confusion on how a emulator / developer version (for pilets) of the Piral instance is created. It is created from the piral-cli, as all other stuff is.
Since we create a bundle there is also no need to ship the original code. Furthermore, no dependencies are needed. As a matter of fact, we'll still reference some dependencies, however, only the ones that may be needed to satisfy TypeScript and enable proper development for pilet devs using standard IDEs.
There are, however, two challenges that have been required to be solved using the new approach:
- What about TypeScript declarations for the Piral API?
- Since we have already a bundle available, how are the two connected / what about HMR?
The first one is covered quickly - we just generate them. The generation is not perfect (in a nutshell we just merge together all existing declaration files), but good enough that pilet devs only see the Pilet API - and nothing else from the app shell or Piral. This is exactly what it should provide.
The second one is more difficult. It required us to rethink how Parcel does HMR. In the end, our development build of the Piral instance contains a special mounting point that works against an API, which is coming from kras and connected to Parcel's dev server. Using this API (with an additional WebSocket connection) we've been able to perform a much better reload - essentially just swapping the pilet. In this reload (which we call
inject) we'll also clean all the registrations, however, leaving the persistent state untouched.
Consequently, the reloading of pilets now is clean and super efficient. It has some drawbacks, e.g.,
- if the state went rogue (or was changed in a breaking way) the pilet may crash
- all emitted / dirty parts are still dirty (e.g., a notification that was not clicked away is still visible)
Nevertheless, we concluded that the benefit outweighs the drawbacks. In case any of these drawbacks is hit, a (full) reload can be performed anyway.
What else was included in 0.9? Well, we super-charged server-side rendering (SSR). Now SSR is supported out-of-the-box! We have set up a small sample to guide potential implementations.
With 0.9.0 we also brought in some new converters. For 0.10.0 we plan to bring in another round of opt-in converters, making Piral the framework with the most integration points by far. Even better, Piral already allows not only mounting arbitrary components (e.g., mounting Angular, Angular.js, ... in the same app), but also including components to be mounted in those mounted components.
This is super important as fragments (e.g., a shopping basket extension) are written using one technology (e.g., React), but the target (e.g., a checkout page) was written in another technology (e.g., Vue). Piral makes it easy. Every integration supports displaying other Piral extensions implicitly via its converter.
For 0.10 we will potentially also invest time in making these integration points work nicely with lazy loading and other capabilities that are already supported by
Another area of work is the integration of more dev tooling such as a Chrome DevTools plugin or a VS Code plugin. It's not very likely that these tools are ready by the release of 0.10, but internally we should already be prepared to support such things.
The biggest benefit of 0.10 will be the consistency check of the Piral CLI. This will have a big impact on v1 ongoing. We'll check that the whole Piral instance (or pilets) are developed in a consistent way. As such developing the Piral instance with
piral 0.9.2, but using the
piral-cli 0.8.4 will not be allowed, however, developing it with, e.g.,
piral-cli 0.9.0 would be allowed. Here, semantic versioning is our friend. We'll make sure that its always the same (significant) major version number.
As mentioned the TypeScript declaration file generation is not perfect. To simplify we put every file in its own
declare module section. Technically, this is fine, however, some IDEs such as VS Code will now display all modules in an import declaration. Having 100+ modules will thus bloat the import declaration.
While only cosmetically, we think a better solution should be found. Either by "hiding" these modules somehow (but how?) or by merging the modules into one module - which is rather complicated. If somebody has an idea - we would appreciate hearing it!
Another point is regarding
react-arbiter. This package has been the foundation for developing Piral, but we think it served its duty. There are two reasons for it:
- It contains some crucial code, but is independent of the Piral mono repo. Changing it is thus slow.
- It should be functional at its core, but it depends on React and is opinionated where it should not be.
We think we may have something better. Something that does not depend on React. As a result it would allow building something like Piral without React as a basis, however, still using this (new) package and, e.g., the
piral-cli. Also, our feed service could thus be used.
Piral reaching v0.9 was a major milestone towards the v1. Right now we are positive that v1 can still be reached this year, but independent if we still release in December or early next year we think Piral has made great progress this year.
We started with the vision of generalizing our architecture / setup for microfrontends in a flexible yet powerful framework. Over time some of the ideas became reality, while others had to shift or be discarded. We are happy with the outcome as it is a powerful yet simple way to create microfrontends without much trouble.