Create Decent App 2.0 Design Thoughts

I've got some developers interested in writing apps for the Decent Portal. And it occurred to me there is one important thing for me to fix in the create-decent-app (CDA) project generator to avoid annoying them.
Vendoring vs Package Imports
If you're not familiar with vendoring, it's when your project directly includes source rather than importing it via a package manager. I'm a big fan of vendoring, though no purist about using it 100% of the time. I decided to directly include source from other libraries of mine within the project code generated by CDA.
This fits the spirit of decent apps, which are meant to be highly transparent and easily understandable by their own developers. So instead of CDA apps importing React components from my not-well-known-at-all widget library (Github repo), the CDA template just includes some minimal source copied from that library for a handful of widgets.
For Node developers, another way of explaining vendoring: instead of having source for a library live under /node_modules/
, just copy the source from those projects under /src/
or maybe /src/vendor/
. And directly update the source as needed rather than rely on npm, yarn, or other package manager.
So in CDA 1.1, I have a very small number of dependencies - React, Wouter, and the mighty WebLLM (project site). Everything else is vendored. After you generate a project with CDA, you can easily remove and modify code. You can use Tailwind instead of my off-brand widgets and CSS. You can delete the stuff from my LLM API about maintaining chat history if your app doesn't need it. You can revise my persistent storage API to use session storage instead of IndexedDb. You can yank out all the PWA functionality in 15 minutes.
I don't like frameworks, black boxes, needless complexity, or lock-ins. I wrote my CDA-generated code to be hacked, ignored, or thrown away. Vendoring is good for that.
But the vendoring approach breaks down in one notable way...
Decent-Portal-Specific Code
There is a widget I call the "Decent Bar" which is meant to show at the top of any app that appears on the decent portal. It provides some portal-specific functionality, navigation, and consistent branding.

What if I need to update the Decent Bar widget to fix a bug? I don't want to ask all developers with apps on the Decent Portal to make specific source code changes. They shouldn't have to do anything besides update a version# in their package.json
. They might care about what the Decent Bar does, but they shouldn't have to. Encapsulation is appropriate here.
Similarly, there are some scripts for deploying decent apps to the Decent Portal that handle staging, promotion, and rollbacks on our portal hosting. I might need to update these devops scripts in the future. In that situation, I shouldn't ask a dev to hand-edit source for updates that are tightly coupled to my specific hosting setup. Again, this should just be a simple package manager update.
The general principle I'll follow for CDA is that source should be vendored/in-lined unless:
- The functionality is Decent-Portal-specific.
- The library is large or complex enough that most developers would prefer to not review or revise its implementation. (React, WebLLM)
So I will make a new library called "Decent Portal Lib" and refactor the Decent-Portal-specific stuff over to it. And I'll be certain to make that library easily removable from decent apps so that devs can use CDA to make apps that aren't destined for the Decent Portal.
Other 2.0 Changes Planned
No Wouter
I decided most decent app developers won't need Wouter. It's a React/Preact routing library (Github) from Alexey Taktarov. I much prefer it to the more popular React Router. Unlike React Router, I never had a single "why is it doing this?" moment with Wouter. And it's small and low-dependency.
But the CDA-generated app only has two screens - loading and home. And the home screen can simply show the loading UI when loading is needed, cutting the CDA-generated app down to just one route with CDA 2.0. In other words, the app doesn't need "/" and "/loading" URLs in the browser address bar - it can just be "/".
Also, every time you create a route, it implies the user can deep-link to that URL and do something useful when they arrive. If an app developer hasn't created a redirect HTML page for a new route and written deep link handling, the new route immediately creates one or more bugs to fix. So it seems better to have a single route for the app in the generated code - basically forcing all users of the app to come through the "front door".
If a developer wants to depart from this single-route default, they can add their preferred routing library or implement their own routing. And I don't have to foist Wouter on them, despite it being a great little library.
I love simplicity and removing dependencies. Wouter will take an honorable exit from the project.
Jest Replaced by Vitest (Probably)
There was a period of some months where I couldn't get a clean build from CDA-generated apps. They'd spout vulnerability warnings from NPM, indirectly due to Jest. The vulns were coming from transitive dependencies, so it wasn't exactly Jest's fault.

But I really didn't like those pesky build warnings, especially when privacy and security are defining principles of decent apps. If I've got all my deps updated to the latest versions, my build should run clean, dammit! Am I being ignorant here or holding an impossible standard? Yeah, maybe. I'm open to correction, and I never want to cast shade on a group of open source volunteers.
To be fair, today, April 5th, 2025, Jest builds clean with the rest of my project. It just took a long time for the different open source players involved to get the vulns resolved. This can be a symptom of a project having more transitive dependencies. The things a project can do to get external project issues fixed are limited and time-consuming. It's kind of like the fall of the Roman Empire - only so much management of far-flung barbarians is possible.
I've heard good things about Vitest. Runs faster. Less dependencies. Plus, CDA already uses Vite to build, which has given me a Golden Age of problem-free builds over the last year or so.
So I'll try replacing Jest with Vitest, and if it goes well, CDA 2.0 will move to it.
Enough for 2.0
My mind keeps racing to other fixes and features for CDA. I want to add subdomain persistent storage so that each app developer gets protection from cross-app tampering. And I'd like to copy the Docker image support and custom LLM stuff over from Hone. But... that can be 2.1 or 2.2 or something later.
My goal is keep an "MVP" mindset and get create-decent-app 2.0 shipped in April - not June.