loco-rs / loco

🚂 🦀 The one-person framework for Rust for side-projects and startups
https://loco.rs
Apache License 2.0
5.53k stars 236 forks source link

RFC: towards a single template master generation -- with options. #864

Open jondot opened 1 month ago

jondot commented 1 month ago

We'd like to move to a single master starter template, but have all major options available for users.

By evolution and iteration, we've learned that there are 3 types of starters:

  1. Lightweight service (e.g. "Sinatra/Padrino" in Ruby world)
  2. API (e.g. Rails API)
  3. SaaS (e.g. Rails omakase)

Unlike Rails and Devise and their relationship, we've added User auth to API and SaaS by default. We think it's OK to leave it there, and have users just delete it when they don't need it.

We'd like to create a way for us to maintain just one starter, but to preserve the level of safety and testing we have today (which is great, we simply go into a starter project and test it out as a living thing).

Rails has rails-templates, and some custom way of specifying a starter -- which I'm not sure how maintainable it is for a small team of maintainers.

In addition we may need to introduce some unification or infrastructure at the Loco side to support better testing for various starter templates.


We'd like to get some feedback:

Any other feedback or ideas are welcome

Sillyvan commented 1 month ago

I like the 3 options. Personally i barely see use cases for the lightweight service but i dont think it hurts. In terms of auth im not sure. Either having it in by default or having an additional CLI command to generate it seems good. Putting an option in loco new would just make things harder.

In terms of Ui i dont like the frontend option. I know Loco is supposed to be opinionated but just shipping some random react starter just dosent feel good to me and adds a ton of additional maintance if done correctly. I think a simple step by step guide to add a frontend in the Docs would be a better choice. This would also make the whole decision about "auto generated admin / login / etc" a lot easier. Love the options for HTML or HTMX

nagashi commented 1 month ago

Sillyvan makes a good point. One question I have, is React the only frontend option? If not, is the simple step by step guide to add a frontend to the docs applicable to other choices?

Sillyvan commented 1 month ago

I can spring in here. the answer is it depends

So first up your classic SPA aka React, Vue, Svelte etc do all work. As long as you can run a command which ends up building an html file + js + the rest. Basically like the good old days where you dropped ur build folder in some FTP. With Loco we can easily just serve the HTML file which does all the magic for us. No additional work required.

On the other hand if you want to use the so called "metaframeworks" so Next, Remix, Nuxt, SvelteKit etc it dosent make sense to have them inside ur Loco. Those frameworks will require Node on the server to render ur HTML for you etc. You CAN do this and its not bad! BUT its a standalone App which can talk with Loco over the network with a Rest API or what ever.

Back to your question. is the simple step by step guide to add a frontend to the docs applicable to other choices? Almost. You will always need a build command and a folder for loco to serve. How you do that can be a bit different but if you choose a frontend framework you are very likely to know how this works. Even with SvelteKit you can use a so called Adapter-Static which as the name implies gives you a static output. Realistically if one guide, lets say react is written up. You can probably add docs for another one in a matter of <10 minutes. Just have the correct output folder in ur config. and run npm run build. Biggest difference here is probably Vite vs Rsbuild because they have different config files.

I really dislike writing docs but if someone ends up making a good one i would happily help to add all the common frameworks myself

Maybe we could even get away with just showing the user to edit their vite/rspack config and choosing the build folder to be /frontend

nagashi commented 1 month ago

The codebase should be as lean as possible, which puts the weight on the document. Sillyvan, like you, I find coding much more fun than documenting. What does make a good document to you, one that will provide a rich user experience? I think it should be easy for newbies to understand, while at the same time informative for those who are more technical. Thoughts?

Sillyvan commented 1 month ago

In my opinion a "newbie" should just stick to the templating engine (server assets) if you dont know how a frontend framework works, you will end up a lot slower.

And the ones that do know how to use it will not struggle if they know that loco just serves their static output.

isaacdonaldson commented 1 month ago

My vote is to make Tera and server-side rendering the default and then have guides in the docs on adding in client-side assets.

In regards to keeping one starter, we could keep a lean starter that has data api routes, rendered views, mailer, and a singular model (as an example?). Adding in Auth, Tasks, Workers, and other things could be done on the CLI though an AuthGenerator, WorkerGenerator, and so on. This does have the downside of having to maintain the generators (which could be tough) but could allow for having a single starter template.

joshka commented 1 month ago

In regards to keeping one starter, we could keep a lean starter that has data api routes, rendered views, mailer, and a singular model (as an example?).

+1. A bit of a meta answer to number of starter templates question is that the light/api/saas can be collapsed into one if each of the parts that make up the saas / api can be generated and added at any time using the cli tool. I.e., if loco new myapp --template saas generates the same exact code as loco new myapp --template clean; loco generate auth; loco generate api; loco generate worker, ..., then this leads to something which it really doesn't matter whether you started clean or with all the trimmings.

jondot commented 1 month ago

To add to the discussion, 2 techniques that are found "in the wild" are:

//
// starter.rhai
//

// major app building blocks that are seperatable, pre-packaged files that are just "dumped" into the project
add_models
add_controllers
add_auth

// uses the CLI generator under the hood
gen_worker "DownloadWorker"
gen_model "movies title:string"
Sillyvan commented 1 month ago

In the JS world you often see just 1 simple create command and then a another CLI that allows you to add the rest. Actually here svelte just dropped their new CLI maybe that can be an inspiration as well?

https://github.com/sveltejs/cli/tree/main

lerina commented 1 month ago

Preloading an elaborate front-end "solution" introduces external complication to loco. I'd rather see a serverside out of the box experience.

Like isaacdonaldson "My vote is to make Tera and server-side rendering the default and then have guides in the docs on adding in client-side assets."

As Sillyvan said: "This would also make the whole decision about "auto generated admin / login / etc" a lot easier. Love the options for HTML or HTMX". => Yes a second that.

Sillyvan commented 1 month ago

I generally prefer a minimalistic approach if you want a standalone frontend anyway.

So somewhen we could have a simple CLI command to maybe generate a js file that just exports available routes and maybe the types of api endpoints for a "more end2end feeling"

sytherax commented 3 weeks ago

Not sure if this is the right place but, Can we also add support for inline templates? for eg. I'd like to get something like this working as well, without having to create a file just for this view reusing macros.


pub fn search_results(v: &impl ViewRenderer, items: &Vec<MarketView>) -> Result<Response> {
    format::render().template(
        r#"
    {% import "markets/macros.html" as markets %}

      {% for item in items %}
      {{
        markets::render_symbol_list_item(
        item=item,
        onselect_action="
          selectedSymbol = '" ~ item.symbol ~ "';
          selectedIcon = '" ~ item.base_icon_url ~ "';
          UIkit.toggle('#cmd2').toggle()
        ")
      }}
      {% endfor %}
    "#,
        data!({"items": items}),
    )
}```