What's new in Piral #5
Florian Rappl
Posted on February 21, 2020
Piral is an open-source framework for microfrontends based on React. It brings everything to create amazing frontends using a scalable development approach.
This is the fifth blog post about our progress on Piral. We will continue to describe our progress and future plans here on dev.to.
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!
Current Progress
Right after we published the 0.10 release we looked into a couple of improvements for how Piral works.
What makes Piral truly unique and very cool are three things:
- You can debug / play around with your microfrontend without having a special instance online; the emulator covers you
- Everything feels like a standard web app - except that you have an exported
setup
function that "glues" your components to your app shell - There is no need for complicated infrastructures - you just deploy your microfrontend and everything else remains as-is
Of course, we could add many more features, but from a pure microfrontend perspective these three alone make it very cool.
Nevertheless, technically there is one problem: The root module needs to be evaluated in a special way to actually be able to call the setup
function and place a special require
function for the shared dependencies. While we (obviously) made this challenge work, we have not been pleased with this way (Hint: it involves new Function
).
Our ideal would have been to just use document.createElement('script')
for this purpose. The problem, however, was that could not get the setup
function in this way. Now we found a way.
Since we need to modify the pilet scripts (i.e., bundles) anyway to allow things such as dynamic resource loading or bundle splitting we can also insert a piece that actually attaches the exports to the currentScript
element.
This means that we can start with something like:
const s = document.createElement('script');
s.async = true;
s.src = link;
s.onload = () => resolve(checkPiletApp(name, s.app));
s.onerror = () => resolve(checkPiletApp(name));
document.body.appendChild(s);
This should be wrapped in a new Promise
that resolves when the pilet's root module has been loaded.
Since the main export will be stored in the app
field of the current script we can access it later.
This would roughly work, but two things are still missing. First, we will need to transport in the shared dependencies. Luckily, this is already handled by Parcel - which works against some global variable.
Using a function to derive a local snapshot of require
for the provided dependencies
the code for this part may be as simple as:
window[requireRef] = getLocalRequire(dependencies);
The requireRef
variable stores the name of the global variable used by Parcel. This is an addition to the feed service, which - for this format - would not only return where the pilet's script is located, but also how the requireRef
is called.
In a very lightweight way we could just call it globalRequire
and use everywhere the same name. Since Piral tries to isolate the different microfrontends this should, however, not be chosen.
But this is not everything ...
For us backwards compatibility is important. As such if a pilet is created with the currentScript
way in mind it should still work in older instances of Piral, or with older versions of the feed service. This is checked.
But what about the other way? How can we make sure that a modern feed service still works with an old pilet format?
This is where we introduce a special first line in the pilet.
//@pilet v:1(globalRequire)
...
The format of this line - if found - is that a special comment starting with @pilet
is found. The version specifier is just v:1
, which comes with an argument. The argument for v:1
is the name of the global require of this pilet.
Also the old format will be decorated explicitly, too:
//@pilet v:0
It will be possible to select the format even though v1
it chosen by default. The only difference (besides the different header) is that v1
also inserts the following line:
function define(getExports) {
if (typeof document !== 'undefined') {
document.currentScript.app = getExports();
}
};
define.amd = true;
This defines a function define
which will then be used by Parcel's own format to place the export properly.
Following the UMD format this custom define
function is only used if there is no module.exports
given - which is exactly the case for using the currentScript
approach.
Future Plans
The 0.10 series of releases slowly progresses towards a certain maturity. From the start we've been sure that one or the other problem would be detected in the declaration generation. After all - and as covered in the last post - this is a complicated thing.
Nevertheless, we have been able to make it somewhat stable. It can now deal with a great deal of types or TypeScript modules found out there. It seems to have the right balance between "take the inferred type" vs "take the originally declared type". One thing to potentially improve in the future are naming clashes.
Right now type naming collisions are not handled and may lead to invalid declarations (well, TypeScript is actually quite robust - so it will actually work with what is valid and ignore the other stuff as best as it can). In the future we will include a mapping table and choose different names.
For the 0.11 release we will extract the declaration generation code in a dedicated library / tool that can also be used outside of Piral. We believe that this kind of declaration generation is super powerful and very useful. Since it does not work with temporary files it is also quite efficient.
Another thing to consider for the 0.11 is more intelligent errors. While this is primarily for the Piral CLI we will also use this technique in Piral itself. Actually, we will most likely make it possible for anyone to have errors and warnings be handled via a link to the Piral docs. Right now no specific plans exist, however, we will soon make a GitHub story to track this.
Together with the improved errors and warnings we'll also improve the Piral CLI logging altogether. It will feature a more intelligent log grouping and finally respect the different log levels fully. Parcel will still log individually, but things such as the NPM installation log would by default not be shown. We will, however, show it if something fails.
Our goal is to make the Piral CLI experience as smooth and user friendly as possible. It should remain the standard tool for using Piral or Piral-like microfrontend applications.
Other Thoughts
We know that the 0.9 series was a big hit with the new mode (special emulator build). We covered that quite well I think. We also know that the 0.10 releases of Piral all had one or the other hiccup - mostly in the declaration generation space. This was also anticipated.
Our believe is that we are now hitting the plateau. All the really crucial things are included. Also some of the learnings we had since generalizing our modular frontend architecture with Piral are in there, too. We love our little community and feel that it is a welcoming and technically savvy one. Just the right community to make Piral successful.
We'll soon include videos in each of our guideline posts. Furthermore, some topics such as using kras
for mocking will get some additional attention. We also want to invest early in Parcel v2 as we are truly convinced of Parcel as the best possible solution for bundling. 🚀
To illustrate our commitment of an open platform even more we are currently in the process of outlining all processes necessary to build a Piral instance (for emulation purposes or as a release) or pilets. Potentially, we will cross check this specification by building a Webpack plugin, too. We still believe that the Piral CLI (incl. Parcel) will give the best experience, but likewise we also believe in freedom of choice.
Conclusion
Hard to believe it's already our fifth post in this series. Time flies! Also quite incredible to get such valuable feedback from the community. Much appreciated!
We will continue our journey in the microfrontends space. We still believe that microfrontends will be an important architecture for future web apps. The number of successful users today emphasize that, too.
We know that this series is mostly interesting for people already familiar with microfrontends and Piral. Nevertheless, our goal is to also reach newcomers to this topic. Let us know in the comments if you want to see something being covered or discussed in greater detail.
Posted on February 21, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.