Skip to content

Improving the SolidOS Frontend

(Ongoing)

I recently joined the SolidOS project to improve various aspects of the frontend such as components, styles, design systems, and accessibility. Exactly my cup of tea!

Activity

Task started

I have been involved with the SolidOS team for a while, because I used to attend every meeting and I've kept in touch with most of the people. However, I hadn't contributed any actual code 😱. But this is definitely going to change, because Timea Turdean has offered me to join the NLNet grant, and I'm really happy to finally be working on a Solid project fulltime :D.

Now, I'm not sure how long that's going to last, since I'm technically still open for work and it's not like what's left of the grant can support all of us (we're already 3 people working on it: Timea, Sharon, and me). Nevertheless, it's really cool that I can spend some time working on one of the most impactful projects in the Solid ecosystem. And as I mentioned recently, I really like the way things are going.

I've spent the first week mostly understanding how the various repositories work, and starting to make some proposals for improvements. My main takeaway so far is that the project definitely needs some conventions. The use-case the project is trying to tackle is very complex at its core, given the flexibility of Solid/RDF and its ambitious vision. But, as it often happens in these types of projects, there's also a lot of accidental complication going on (watch that video if you haven't!). Hopefully, one of the things I can contribute is a way to reduce it.

On that line, one of the first things we've been talking about is how to standardize writing UI. Right now, there are different styles mixed in the codebase, such as using Lit or creating DOM nodes with vanilla JS (document.createElement('div'), etc.). After some discussions last week, we've decided that we'll move everything towards Web Components using Lit. In particular, we're going to have 3 types of components:

  • Generic Solid Components (published under the solid-web-components package)
  • SolidOS Design System Components (published under the solid-ui package)
  • Application Components (not published anywhere, used internally to build the frontend)

I have already opened a PR with a first draft for the second type of components, check it out if you're curious.

And that's about it for now! Given that this is going to become my main gig for a while, I may be writing these updates more often than usual. But I don't think it'll be more frequent than once a week, so hopefully this won't become too noisy for people subscribed to the feed.

In case you're interested in digging in further, the SolidOS team is also working in the open, so you can check their notes and blog posts:

Hi again!

This week I've felt a lot more productive than the last. Even though we've also had a couple of meetings (links at the end), I've started to work on more elaborate components and learned a lot more about Web Components in general. If you're interested, you can see a summary of this week's work in this PR: Implement reusable primitives.

I started the week with the idea of creating an "Account" component. I have a similar component in Aerogel, and the idea is that this component can be used to show either log in/sign up links, or the user menu. In my apps this makes a lot of sense because they are local-first, but even though SolidOS isn't, it happens to have the same pattern (because you can open pages without logging in). So that's nice :).

It seems like a simple component, but it involves a couple of things that are not so trivial, such as interacting with the authentication system, invoking business logic (login, sign up, logout), and opening overlays (the dropdown user menu). Additionally, another challenge is that I wanted this component to be part of the generic Solid Components, because this is something other apps will definitely need. But after some tinkering, I decided it would make more sense to build smaller reusable components, and the "account" component would be SolidOS-specific (still reusable, though!).

Maybe the most interesting thing I've done this week is the way I've implemented the authentication and business logic interaction. Though the truth is that I haven't 😅. Let me explain. As I mentioned last week, the idea with these generic Solid Components is that they can be used in any project, not just SolidOS, and ideally we want them to be interoperable with other Web Components in the Solid ecosystem. In order to support that, I've abstracted away all the interactions with the business logic of SolidOS behind an interface. I'm still not sure how the whole ecosystem will converge on this, given that it's still an open question, but at least whenever we do, in SolidOS we'll only need to swap up this interface with a different implementation. An additional benefit here is that I've also been able to implement a Storybook implementation, which allows us to see these components in a nice UI sandbox :).

Something else relevant this week, although not Solid specific, was implementing the dialogs and overlays. This one is still a work in progress, but honestly, all the headaches I'm having show some of my initial concerns about using Web Components :(. It's not that difficult to implement a working dropdown with Javascript/CSS, but it is very difficult to make it conform with ARIA specifications and native APIs such as the Popover API. In fact, I've been looking at Web Awesome's Dropdown and it doesn't 😱. I often use this browser extension called ARIA Devtools to check whether an app is built correctly or not, and their dropdowns don't even show up :/. So yeah, I don't know... Trying to learn about this talking with some AIs and whatnot, it seems like ARIA roles aren't really "that important" (at least for dropdowns), as long as the labels and keyboard interactions are configured properly. There's also the fact that I'm not sure we should be spending that much time building these things from scratch, so this week I'll try to discuss some alternatives to use 3rd party components. We'll see how this evolves!

And that's about it for this week! Tomorrow (at the time of this writing), we're having a meeting about Jeff's Web Components, so feel free to join if you're interested to participate. The main idea of the meeting is that he explains how those components work, and how we'll integrate them in SolidOS or what'll happen with that repository moving forward (as I mentioned, ideally we'll use it to publish the generic Solid Components). But something I'll make sure to bring up as well is the interoperability between libraries, and the business logic layer I've been abstracting away. The meeting is happening on Tuesday 26th at 18:00 CEST, you can join in the SolidOS Jitsi room.

This week's meeting notes:

This week, I finally ran the entire SolidOS stack locally!

SolidOS is made up of many packages, and in fact the main SolidOS repository is nothing more than a bunch of scripts to orchestrate cloning and running them. At some point, we should probably migrate to a monorepo, but even then it's likely that some package makes more sense in its own repository. This is also a problem I've faced in my own work, for example when I am working on an app and I need to change both Soukai and Aerogel code. Recently, I even created vite-plugin-multi-root-workspace to make this easier. But SolidOS is still using webpack, so I won't be able to use it here.

Anyways, the reason why I started running this locally is that I opened my first real PR! There isn't much more to mention that I didn't say last week, other than I have been cleaning up the components and finishing the login UI. If anything, I would reiterate that working with Web Components is not being a great experience :(. Last week I mentioned the challenges with ARIA roles and element references, and this week I realized that using a native <input> inside a Web Component is not enough to make it work with forms 😱. Web Components were supposed to be the "native" way to encapsulate functionality on the web, but so far it's feeling more restrictive than Vue or React. I'm being forced to reimplement a lot of the things that worked out of the box when using plain HTML 🤷.

This week, we also discussed how to tackle AI commits in the codebase. NLNet recently introduced a policy on the use of Generative AI, and it's not completely clear what we can or cannot do in the project. Or how to even communicate it. In my own work (not SolidOS), I've been using the Co-Authored-By git convention in commits that have been AI-generated, and I also include an AI summary of the work. However, it seems like NLNet requires that we also include the entire prompt history, so that may be a problem. For now, though, I haven't been using a lot of AI in this project (at least, not to generate code). But once the foundations are laid out and we want to start using the Design System everywhere, this may become an important point of friction.

Finally, this week we also had a meeting with Jeff explaining his web components, which were pretty cool and also show what I think Solid should be all about (you can find the video recording of his demo here: solid-web-components in data-kitchen). We also released a new version with milestone 2k (I didn't do much work here, it was all Timea and Sharon!). You can find notes about these and the weekly meeting here:

Following up from last week, I kept improving the login form. In particular, this week I started looking at some of the things outside of the design. It is very common that application designs in Figma are missing many of the edge cases, specially when the task for designers was basically to redesign the entire application (or a huge part of it). But I think they are also very important, and part of what make a great UX. Usually, I would talk it over with the designers, but given that we're working with an external agency that bills by the hour, I decided to take some initiative and just do it myself. I'm not talking about anything drastic, though, simply adding some loading states to buttons when submitting, and showing errors when something goes wrong.

However, I spent most of my week migrating to Vite! On the one hand, that's great, because I do like Vite a lot more than I like webpack. On the other hand, it's not going as well as I thought 😅. It's not like the migration is going wrong per-say, but part of migrating the build system is to make sure that I don't break any of the existing consumers of the library. But I'm afraid that's not going to be so easy :(. Basically, the way the solid-ui library is being bundled and used is not ideal, and I'm not sure how much we can improve the situation without introducing breaking changes. Still, it should be "fine" to introduce breaking changes in a new major version... I'll have to discuss it in the next weekly meeting.

Finally, this week marks the first month since I joined the project. Looking back, it's been a bit different from what I expected. My intention was (and still is) to improve the UI. But so far, I've spent most of my time fighting against web components, cleaning up the architecture, and tinkering with build systems. Of course, all of that is also very important for the project and should make the UI work a lot easier. But, as I mentioned in my first note, there is a lot of accidental complication going on. Hopefully once I'm done with all of this, I can be a lot faster at working on the UI!

Here's this week's meeting notes:

We're still going back an forth about the migration to Vite, but I think we're almost done with that. Certainly, I don't think I'll have to spend a lot more time working on it. One of the reasons for the delay is that it needed to be reviewed by multiple people. One of the main topics of discussion is how much we want this to change things. You can read the weekly meeting notes at the end, but if you want a TLDR I also added a brief explanation in the README.

I am aware that this PR is very likely to break some existing dependencies. But I think that's something we have to do at some point if we want to improve the library, and now it's probably the best time to do it given that we're migrating everything to Web Components and consumers will have to rewrite their code anyways. In theory, people using the library through npm shouldn't be affected that much, because dependency versions are not updated automatically (or shouldn't). But another problem is people who's using the library through CDNs, which was documented with an unversioned url. The main problem is that the CDN used the window.UI legacy pattern to expose helpers, but that's often frowned upon for new applications (often called "Global Scope Pollution"). Instead, new applications should rely on ESM imports which are now supported by most browsers.

This week we also had a couple of private meetings. First, we talked with Jeff about his new component-interop initiative, and then we talked with Samu about the ODI's new authentication library. Both are taking a new approach at solving some of the problems we've had in the ecosystem for a while, we'll see how they pan out.

After these meetings, we reached a decision about SolidOS's Web Components: We're not going to release 2 separate libraries. A few weeks ago I mentioned we wanted to make a library with generic components, completely decoupled from the solid-ui package and design system. But it seems that wasn't the right decision, because it just caused confusion and we didn't land on a name we were happy with. So we're just going to release Web Components through solid-ui, some more reusable than others. Hopefully, this should still serve the same end goal because the library is now (or will soon be) able to expose individual components and helpers.

Finally, at the tail end of the week, I started working on my next task: to start applying the new components and design system to other panes. I started with contacts-pane because it seemed simple enough (we'll see how true that is!). I thought it could be a simple migration, and essentially it is; but I'll probably need to migrate the build system to Vite as well to support Lit's decorators and so on. I'll also take this opportunity to standardize and maybe extract some of the helpers that are duplicated in every panel repository, such as the dev sandbox. More about this next week!

This week's meeting notes:

This week, we finally merged the migration to Vite in solid-ui, so Webpack is history! At least, for that repository. We still have a few more to go 😅. And that's one of the main things I've been working on, migrating the contacts-pane to using Vite and the new design system.

But I'm not migrating all the pane. Rather, I'm using it as an example of introducing the new components progressively. In particular, I started by rewriting the "Add Contact" form into a dialog. The change itself is not too big, and the new code is a lot simpler than the old (as it should!). But this involves a bit of work upfront, such as migrating the build system to Vite.

As I mentioned last week, I've also been working on extracting a dev sandbox for panes, and I'm doing that in a new package called solidos-toolkit. The idea is that this package will include all the tooling that can be reused across the SolidOS stack. Mostly on panes, but I'll probably end up using it in solid-ui as well.

All of this work looks like yak shaving, but it's aligned with of my favorite software development mantras: Make the change easy, then make the easy change.

Other than that, we're still working on fixing the CI and our release process. Things slowed down to a crawl this week, because we decided to do a new release including the migration of the authentication library. You can find more about it in this week's meeting notes, but TLDR it seems we weren't aligned on the roadmap because I thought the next release was scheduled to include all the migration to the design system. So I had to roll back some of my UI changes in preparation for the release. Hopefully next week we'll get back on track!

This week's meeting notes:

This week marks the halfway point for this task, given that I'm going on holidays in late July and I started working on this in late May. There's still the possibility that I keep working on the project after the summer, but I'm definitely going to close this task by then.

Keeping that in mind, I started thinking about tying some loose ends, and the first one was accessibility. Of course, I always have a11y in mind from the beginning. But as I mentioned in a previous weeknote, we had to decide whether to use 3rd party components or not. We actually reached out to NLNet's accessibility partners for some feedback, but 3 weeks later we still haven't heard back from them :(. So, at least for now, we've decided to rely on Web Awesome. I still have some doubts about accessibility for Web Components, but honestly, I'm pretty sure they are ok given that a11y is one of their selling points. Unfortunately, some components are not free, such as the Combobox, and we'll need to code them ourselves (buying is not an option, given that everything in SolidOS has to be open source).

Something else I've been looking into is code reusability between components. In particular, making form inputs with Web Components requires a lot of hand-wiring (it's not enough to simply render native <input> or <select> elements under the hood). The first reaction to this may be to think of creating a parent "FormInputComponent" class, that can be extended for individual components. But that would be a mistake. Or rather, not ideal. Instead, I have created a concept of "component traits" that hook into the component lifecycle and can be composed with other traits. TLDR, composition over inheritance :).

Finally, we've continued talking about CI and dependency management. We haven't reached a final conclusion yet, but I did write most of my thoughts on this in a PR comment. We had a meeting on Friday (notes below), and it seems like we're going to configure an "ecosystem CI" that runs the entire SolidOS stack once a day to make sure everything works together. Hopefully, that will take care of some of our headaches!

This week's meeting notes: