New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DISCUSSION: packaging / release strategy for UI component modules? #4
Comments
Appreciate these reflections @pospi. I'm not particularly partial to either of the options you've outlined. For me, the important factors to consider are:
I've no experience building & maintaining a design system, so I don't think I can offer much more that what I've listed above! |
FWIW, I also see two distinct types of reusable components we want to provide for applet developers:
for (1) it makes sense to maintain this lib on npm.js, however for (2), I not sure that makes the most sense? For (2), I think we would be building out own custom component (widget) registration and persistence system. For example, these widgets can be developed by applet developers, and then we want them to get added to a NH wide widget registry where CAs and other NH participants can configure which widgets are used to create assessments (as well as along which dimensions). Perhaps there is a core set of assessment widgets (actually I think this makes sense) so that applet developer could just make use of those and not have to write their custom implementations if they don't want to. So maybe these would be part of (1)? The other thought I have is that just as we plan on creating an applet marketplace, we may want to support a widget marketplace as well. Either way, if we are to handle widget registration/persistence within NHs we will need to decide on how exactly the widgets are serialized. For that, 2 approaches come to mind:
|
I think all these concerns are important, but I think mostly a separate-but-related issue? I see content delivery concerns within "native" Neighbourhoods as a second-order concern of UI component bundling and packaging (packaging has to work first). But- prior to either of these things functioning there needs to be an ability to load and link these components as dependencies through a standardised (ESModule) package manager; in order to get them into a build pipeline for packaging and delivering to NHs. These preliminary (current day, non-NHs) linking / importing / developer ergonomics concerns are the focus of this issue. For clarity, I want to be able to simply do I think it's also important to state that our aim should be to enable composing and reusing NHs UI components elsewhere in other "normal" UI application projects, and not just in NHs Applets or just in our low-code UI builders. Things should be modular, simple and flexible all the way up the stack. |
Thanks for the clarification,
Yeah after reading this I agree, what I brought up was a bit off the mark of this specific discussion.
Got it.
Definitely! |
After doing some experimentation with Valueflows UI it seems like there are going to be tradeoffs in different packaging approaches. What first becomes obvious is that LitElement simplifies things greatly for component library bundling since it only provides a few simple abstractions over the base browser-supplied So, though Lit is not the most ergonomic library to work with and can take longer to develop components it may be worth focusing on it as a core component library for simplicity reasons. It should be noted that LitElement components can of course also be bundled and minified similarly to what occurs when components developed in other frameworks are compiled; though this is actually sub-optimal when such modules are included in a compiled ESModule project for reasons of code duplication. In fact, there are 4 possible versions of a packaged component that other projects might import:
I am probably going to stop experimenting for a while and await feedback on omissions or various combinations of these options before proceeding on polishing any build systems, since the shared components I am focused on presently are built with Lit and packaging in format 1 is all that's needed currently. For more complex components with build steps my current thought for Svelte components already a part of VF-UI is to aim for a combination of options 2-4. With some work we should be able to get all 4 options if we spend some time on using PNPM to script per-component Vite configs; but at face value 3 seems to have the best tradeoffs even if we need to be somewhat cautious of overall library size (read: let's not be putting binary assets in there). To get a combination of 2 & 3 requires duplicating component builds on NPM but I think that's not so bad if scripted within a single repo. For clarity, here's what dependent code would look like for all 4 options:
Note that we can include format 4 along with any other module formats if we simply include the raw uncompiled source file at a known path within any module and ensure it appears in What do we think? Are these assumptions making sense so far? Am I trying to get the best of too many worlds at once? Would anybody like to express a strong preference or objections to any formats outlined above? |
Some notes on Svelte component libraries, after doing a little research on Svelte 4 today:
|
I guess there is a fifth format, one which is optimal for modern build systems and now configured for the NH Design System Components repository:
In other words, "what the TypeScript compiler gives you by default". |
Ya I think we can maybe close this too @nick-stebbings. I wanted to put a little more work into my build toolchain in order to be able to have a mixed-framework compilation strategy but I think that's distinct from packaging decisions; which I think we have agreed on as "combined pure ESModules" +
...correct? I think in many ways this is actually less work in managing build artifacts & packaging data. My strategy was going to be:
|
I'd like to ask a package organising / naming question here, maybe for @nick-stebbings @weswalla @adaburrows I am thinking that there are:
What do you think about this suggested naming & grouping? We can still develop all of these components as part of https://github.com/neighbour-hoods/design-system-components if we want to, and publish multiple packages from different directories. Or we can finalise our Storybook / UI component library architectural patterns & scripts and have separate repos. (If we do that, we should provide a scaffolding tool for component libs and create protocol around mirroring updates from there back onto all repos.) |
Moving forward with some decisions:
|
So one of the ideas that I had in mind when creating the one repo for the design system was being able to structure the repo like most of the other ones out there, which makes it a bit easier for both devs and designers to work on the same repo. There's tons of examples, so I'll include a few just so you all can get a flavor. Note, since we're not using the paid version of Token Studio for Figma, it produces a giant tokens.json file that I had to write a script to parse the themes out of. In many of the following examples, there is a design-tokens directory that contains further directories that correspond to the nested entries in the tokens.json file. However, there is a really great example of moving everything into a separate design org and breaking everything out into separate repos over and American Airlines:
Mozilla's corporate design system however, is probably more similar in scope to ours and they've taken the approach of breaking things down into tokens, assets, and the main design system with components and scss.
I happen to prefer the way Mozilla structured it, but I'm not opposed to putting everything into one giant repository like salesforce. I thought I had more examples of design systems, but I can't find them at the moment. |
This might also provide more context for those who might want a more comprehensive view of a design system: |
I have held back on commenting so far as I am not too knowledgeable about different ways of packaging things up but I will take a look at some of these examples this week. I would also like to make a library for easy mocking of a store in testing (basically consolidate some of mine and @pospi 's work and hide the gory bits), and perhaps create a simple API - just pass on options object to a constructor to define the form of the returned mock data store like e.g. ... and with realistic (i.e. better than mine) factory objects, as mine are a bit rushed and now we are getting to more complex testing requirements they are not cutting it so much. |
Current Problem
We don't as yet have a coherent understanding of how we will name, encapsulate / isolate, bundle and deliver Neighbourhoods UI components to consumers of our modules.
Additionally, we should aim to ensure that:
import
Proposed Solution
In the Valueflows UI project it seems to be making sense to move toward separate ESModules for each
CustomElement
(i.e.@vf-ui/component-*
). Managing this is straightforward with PNPM, which at this stage I believe almost (if not) all of the NHs projects have been converted to. It's a good way of ensuring that the modules are genuinely zero-dependency because all dependencies must be explicitly recorded inpackage.json
in order to be available to a module in a PNPM-managed workspace.We then simply need to set
"private": true
in anypackage.json
files under the workspace which should not be published to NPM; and initialise any"version"
fields as needed for those which should.The other thing to decide on is a module naming convention. In the case of separate modules per UI control, my vote would be
@neighbourhoods/component-
as a prefix.From there it is just a case of running
pnpm -r publish --access public
from a repository root after each update. Changes to each package"version"
are compared to what's on NPM and published if the module metadata has been changed.Alternatives
Bundling all UI components to a single
@neighbourhoods/design-system-components
NPM module seems to be the other alternative. On one hand it's clean and doesn't pollute the global NPM namespace; on the other it relies on tree-shaking to remove unneeded bloat and can blow out the application size with some bundling configurations.Care should be taken to standardise module metadata and README files in all packages run through a publication pipeline, such that references to git repositories match that of the workspace. We want to ensure that navigation from NPM to these modules is straightforward whilst they're spread across multiple project repos.
We could make a pass at extracting shared UI components to a separate "storybook" / "styleguide" repository for the NH design system and update all Applet repositories to reference the canonical versions of the code. But I don't know that this is necessary at this stage, so long as a component is being published by only one repository.
For components in use in multiple Applets maybe it's a case-by-case decision as to where that component should live? Some of them could be considered NH Launcher widgets (eg. "create or join NH"). Others are Applet-specific widgets (eg. "time entry"). Still others could come from
@holochain-open-dev/profiles
. Maybe take the approach of de-duplicating as we go, and if we bump into cases where we can't decide where something lives then that is a pretty good indicator that there's a more abstractCustomElement
module that both components could be inheriting from?Sorta thinking out loud. Reflections appreciated.
Adittional context
I'm feeling some additional push toward this with the implementation of a second Applet. Re-use of generic components already created in Applet 1 for Applet 2 would be nice. But currently the situation is unwieldly use of
pnpm link
and the social encryption of knowing which of the various repositories to have checked out, because nothing is published to NPM.I think that despite lingering dependencies on Material UI and Shoelace, what we have is "good enough" to publish as a first alpha and iterate on from there even if some of them look kludgy. Hopefully it will also help us to standardise and update the shared components we already have? (eg.
@neighbourhoods/component-create-or-join-nh
).Also to note that both the Timetracking Applet and Marketplace Applet define and export modules to the
@vf-ui/
NPM organisation as well as to@neighbourhoods/
, as they each implement some backend-agnostic pure-Valueflows UI controls. However, though consistency is desirable there is no real reason that all modules within each of these workspaces must respect the same format so the VF and NH modules need not have the same naming convention.The text was updated successfully, but these errors were encountered: