lukeed / freshie

(WIP) A fresh take on building universal applications with support for pluggable frontends and backends.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Question: Freshie vs X

JakubKoralewski opened this issue · comments

Hi, I'm coming here straight after watching your very interesting talk and given that documentation is still a WIP I'd very much appreciate a small description of what your project's big picture goal is here (since I know it's a WIP so the current state is not representative of your vision). I think the easiest way would be to outline the differences with other similar projects I've seen:

Few "competitors":

  • SvelteKit

    Given that SvelteKit is said to be available SOONTM, do you think what you're trying to achieve with freshie (built-in Cloudflare Workers routing support) will be possible to implement with SvelteKit's adapter API? Do you see freshie supporting Svelte after SvelteKit launches still?

  • fab

    From skimming the README I'm assuming the projects are very similar, but freshie actually supports Svelte SSR?

Since my knowledge is very superficial, I'm asking to learn more as the concept of Svelte + Cloudflare Workers is very appealing. I hope this issue can be helpful to others visiting the repo who are also both interested and confused at the same time.

Hey, thanks~! Sure:

  1. Svelte Kit is very similar – and it's inevitable since I'm involved there too :) SvelteKit is Svelte-specific, which means that, as a framework, it'll be able to lean more into optimizations/shortcut that Svelte alone can offer. Because freshie is meant to be agnostic/compatible across all major UI libraries, there may be some future, unique features that Svelte offers & nothing else can match. In that case, because there wouldn't be a way for freshie to make X available across all integrations, freshie wouldn't take advantage of X whereas SvelteKit can & would. The projects are also similar in that Svelte Kit will be back-end agnostic. I'd like to think that was my idea, as I was already working on that here with freshie (and with Polka before that)

  2. Admittedly I didn't know too much about FAB until some time after my talk. It's a cool idea – but the difference is that FAB is sorta like a deploy-time glue and/or modifier. It isn't – and doesn't want to be – a framework. It wants you to use existing tools/frameworks to author your apps – FAB takes the result (a FAB-plugin may be required as part of build, though) and deploys it to your target platform. Freshie is different in that it is an authoring framework too. Instead of working with Next.js/etc, it aims to replace those tools, which allows freshie to inline whatever build-time changes & optimizations that might be needed.

Hope that helps~! Closing as it's not an issue, but happy to keep the discussion going.

Thank you for the detailed answer, really had to take the time to think about what you wrote 😅.

Regarding SvelteKit, do you have some specific optimizations/shortcut that Svelte alone can offer, or an idea of what these future features could be?

Also, regarding the compatibility across major UI libraries, if e.g. Svelte offered a custom feature would it be possible to enable that custom feature for just Svelte+Freshie projects or is your mindset that this feature must be available in all UI libraries to be available from Freshie? Really a solid example of that kind of feature would be nice, cause I can't think of anything specfic right now.

Third question, are you familiar with https://github.com/blitz-js/blitz? In short I think of Blitzjs as what it is currently doing for Nextjs, is the same as what Nextjs did for React - further abstraction & simplification. Specifically the "Zero-API" data layer they include is really fantastic. Do you think Freshie codebase is structured in such a way that this kind of RPC/HTTP "Zero-API" abstraction layer would be possible to implement? More importantly is this something you would consider? Or am I bending Freshie's goals too much towards my expectations and away from what you see it to be? Similarly to what Blitz did for Nextjs I see Freshie having the potential to do the same for all UI libraries.

Blitzjs has other nice features:

  • code generation
  • code scaffolding
  • built-in authentication
  • installer recipes
  • and probably more idk

But these are just QoL imo and could come with time whereas the "Zero-API" data layer is something that I think would need to be actively pursued.

I haven't used Blitzjs, but I did write a Nextjs app and I see how repetitive, creativity-hindering and flow-breaking manual API creation is. Cons of Blitzjs is that it supports only React/Next.js (which Freshie already fixes), that includes Next.js cons, such as super-long build-times (due to Babel, Webpack, Typescript and probably more reasons idk about) that could be fixed with modern build tools such as ESBuild, SWC, Snowpack etc (which Freshie could do).

All-in-all, I think the selling point for me right now is the Cloudflare Workers support, but there is potential for more. Would you agree?

You're welcome :)

Going to combine your two questions since they're related, but specifically addressing this:

Also, regarding the compatibility across major UI libraries, if e.g. Svelte offered a custom feature would it be possible to enable that custom feature for just Svelte+Freshie projects or is your mindset that this feature must be available in all UI libraries to be available from Freshie? Really a solid example of that kind of feature would be nice, cause I can't think of anything specfic right now.

A current example is <svelte:head> which allows for built-in/easy <head> management. Svelte users (only) can make use of this (and are encouraged to!) but all other UI layers would require another work around to achieve the same feature. This would have to provisioned by freshie (I don't have anything for this yet) – or just tell other fwk users to bring their own solutions (not ideal).

This might mean something like:

import { Head } from from 'freshie/head';
// or 
import { Head } from from '@freshie/ui.preact';

... but TBD. My current thought is to involve #10 in this.

I know Blitz exists but I've never used or looked into it. While I'm sure it's great, helpful, and time-saving, I never used it because of the same CONs list you mentioned.

There will be code generation and scaffolding in the future – though it may stop at the freshie new command.
Ideally there would be other recipes/templates to do things like authentication, too. I don't like to spend too much time on those kind of examples, because after a certain point, there's enough there to illustrate needs/concepts & templates are rarely used exactly as is anyway... there'll always be customization.

Thanks very much (again), hope I'm not too annoying with all these questions.

  1. What's fwk?

  2. re: blitz

    I know Blitz exists but I've never used or looked into it. While I'm sure it's great, helpful, and time-saving, I never used it because of the same CONs list you mentioned.

    Sooo, I'm trying to bend your answer to fit my question about adding the "Zero API" data layer to Freshie, (i.e. at build time replacing function invocations with network calls) - what you're saying is it's not something you thought about and not something you're going to implement / have the time / interest; but if one were to create a PR with sth like that would you accept it?

    Not saying I will cause I tend to scrape my projects sometimes before even starting them, that's why I have huge respect for you for publishing this (among ur other projects ofc).

Not at all :)

  1. framework – I was lazy lol

  2. Sorry, forgot to address this specifically. It might come in the future, but most likely an add-on package/preset. It would have to require a lot of thought to make sure it's compatible with all target backends too, while (hopefully) still being flexible enough to swap out REST/GraphQL/etc. My inclination is that because this would be such a big/tricky addition, it would require me to be heavily involved in its development. I'm not opposed to the idea (we had similar conversations RE: Sapper, but Svelte Kit was decided), but it'll be an effort and freshie isn't quite ready for that yet. More core/important things first imo.

    That said, Blitz is very much still using an API layer – it just generates one for you automatically. Not sure that it's a huge leap to just avoid attaching server routes w/ the server-code you've already written. Mounting/defining API routes is a one-time event per route – and it's not traceable unless you know what's going on – so I'd be weighing how much needs to be added or changed in order to save the ~10s it takes to do the manual route.

    While not exactly the same, freshie's preload can be made environment-specific. If done through the freshie/env submodule, all code can be statically analyzed, which means that server-specific code isn't sent to the browser & vice versa. This means that if you set up your models/utilities with a nice organization, it's very easy (w/ minimal maintenance) to import the relevant bits where needed. Below is just a simple example, and while it does require you to setup a Polka/whatever API, it's not time-hungry & won't be where the bulk of your time is spent:

// models/article.js
import { DB } from 'server/database';

export async function list() {
	const rows = await DB`select * from articles`;
	return rows || [];
}

// routes/blog/[slug].svelte
<script module="context">
	import * as http from 'freshie/http';
	import { BROWSER } from 'freshie/env';
	import * as Article from 'models/article.js';

	export async function preload(req, context) {
		let items = [];

		if (BROWSER) {
			// make HTTP call on browsers
			const res = await http.send(GET, 'https://api.foobar/articles');
			items = res.data || [];
		} else {
			// make Database query on server
			items = await Article.list();
		}

		return { items };
	}
</script>

// server/routes.js
import Polka from 'polka';
import send from '@polka/send';
import * as Article from 'models/article';

Polka()
	// ...
	.get('/articles', async (req, res) => {
		try {
			send(res, 200, await Article.list());
		} catch (err) {
			console.log('GET /articles', err.stack || err);
			send(res, 500, 'Error loading articles');
		}
	})