Skip to content
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

New major version [complete rewrite] #24

Open
brillout opened this issue Oct 30, 2020 · 20 comments
Open

New major version [complete rewrite] #24

brillout opened this issue Oct 30, 2020 · 20 comments

Comments

@brillout
Copy link
Owner

brillout commented Oct 30, 2020

There are neat ideas out there waiting to be implemented such as:

  • Render functions.
  • Small code base. This can and should be a small tool. Under 3k LOC is possible.
  • Bundler agnostic. Bundlers come and go (e.g. Rome is coming). By default Parcel Vite is used.
  • TypeScript
  • Entirely flexible rendering (client-side + server-side, server-side only, client-side only, static). Thanks to the flexible architecture we will be able to support partial hydration (the React team is currently working on this).
@brillout
Copy link
Owner Author

@chriscalo Would you be up to join me in doing this? We could co-create a new GitHub Org

@chriscalo
Copy link

chriscalo commented Dec 20, 2020

Apologies for the slow reply. I started to respond a few time times but wanted to give it some more thought and research.

I definitely am still having some struggles in my dev workflow and could be convinced to contribute, though it would need to be a good match for addressing the problems I’m facing.

Let me know if any of this sounds interesting. If this doesn’t turn out to be a good match, it’s nevertheless useful for me to get these thoughts down on paper.


My wish list:

Support modern Vue app development

Development: fast, no-bundle dev server

  • Fast dev server startup and hot module reloading like what Snowpack and Vite offer

File-system based routing for static assets, dynamic pages, and API endpoints

The vision behind Zero Server feels perfect to me, though unfortunately I wasn’t able to get it to build:

  • Static files (nothing special here)
  • Pages:
    • / => ~/index.vue
    • /foo => ~/foo.vue or ~/foo/index.vue
  • API endpoints, too:
    • /api/foo => ~/api/foo.js or ~/api/foo/index.js
    • Like with Zero Server, each file just needs to export a single connect-compatible handler function.
    • Nuxt has a nice pattern for adding custom server middleware without needing to import it
  • And it would be nice if, on the server, calling relative API URLs just worked as it does in the browser: relative URLs should assume the same protocol, host, and port as the running server when not specified
    • /api/foo => http://localhost:8000/api/foo

Simple SSR

Production: optimized for serverless environments

With Nuxt I’m seeing response timeouts in Google App Engine after deployment or after the app is idle for a while. Not certain, but my guess is that when a new instance spins up to handle an incoming request, it runs npm install && npm run start, which times out. I failed at packaging all server-side run-time deps into a single bundle to see whether avoiding npm install fixes the issue.

Would be great to have:

  • Sub-100ms cold starts on serverless application platforms such as Google App Engine. With file-system based routing, it should be possible to start the server quickly without require()/import-ing any of the file-system based routing application code and instead only load modules as needed for individual requests.
  • Even better, is it possible to not explicitly build for production at all? With esbuild, does just-in-time compilation on each request (with caching) become feasible? This would make it possible to deploy un-built source files and have the server handle all compilation in real-time. This is the PHP-like experience everyone keeps asking for.

JavaScript API for easy integration

In addition to a CLI command for starting a server, it’s also nice to have a JavaScript API when more control over the server is needed. Two examples:

  • Snowpack v3 has a snowpack.handleRequest(req, res) method for explicit Connect/Express integrations and a startDevServer function for those who don’t want to use the shell command.
  • Nuxt has a similar nuxt.render(req, res) method and loadNuxt('start') and build(nuxt) functions for programmatic use

Thoughts? Any of this a good match for what you’re hoping to create?

@brillout
Copy link
Owner Author

My overarching motivation is that I want a lean do-one-thing-do-it-well tool, instead of having to use a big rigid monolith à la Next.js or Nuxt.

I believe it's possible to implement a lightweight core that is highly flexible:

  • works with any bundler/builder (webpack/parcel/rollup/rome/snowpack)
  • works with any view library (React/Vue/...)
  • renders views at build-time, at request-time on the server-side, and on the browser-side.

Core would implement:

  • Satic folders (Not only static/ at root, but also purchases/static/, users/static/, etc. for domain-driven development. I've implemented my last backend like this and it was a pleasure to be able to colocate files by concern.)
  • File-system based routing. (Totally agree with you. It was a mistake on my part to not implement that with Goldpage.)
  • The render function. (Your idea back then. I love it so much, first-of-its-kind level of SSR/SSG control, love it. Although I believe only few end-users will use the render function directly.)
  • Routing. (But the user can use a custom router by using the render function directly.)

Core can be used directly by the user or can be used with an "integrator". The role of the integrator is to stich core with a bundler/builder and a view library. There would be several integrators, for a example a Vue + Snowpack integrator, a Vue + Vite integrator, a React + React Server Components + Webpack integrator, etc.

The goal of the flexibility is actually that anyone with a wish list like yours can implement it. Core should not get in the way of your wish list.

So, when you ask whether your wish list matches my motivation, my answer is a clear yes since I want anyone, including you, to build whatever they want on top of core.

only load modules as needed for individual requests

Neat idea.

it’s also nice to have a JavaScript API

I agree, it's important for flexibility.

I'm increasingly liking Snowpack. And yes, it would be pretty neat to get rid of the build-step altogether. It's exciting to see Snowpack and Svelte starting using esbuild. It would be exciting to work on a Snowpack integrator together.

I'd suggest we take a shot at implementing a first rough prototype of core together where each LOC is reviewed by the other one.

What do you think?

How about a new name? RenderX? Other ideas for names?

@brillout
Copy link
Owner Author

@chriscalo Note that Vite is working on supporting SSR. This means that writing Goldpage/RenderX core + Vue/Vite integrator will be only a couple of kLOCs! This is an exciting opportunity to ship an interface we both deem user-friendly while not having to write much code. It's quite a comfy situation :-).

@chriscalo
Copy link

Well, that’s quite encouraging ☺️

I’d suggest we take a shot at implementing a first rough prototype of core together where each LOC is reviewed by the other one.

This seems reasonable, though even before that, how would you feel about starting with a few example projects that don’t actually work (yet) but instead attempt to illustrate how projects should work with Goldpage/RenderX? Essentially, this would help us capture the right developer experience before starting, but then those same example projects could later serve as a target to code against and even as automated tests. Thoughts?

I’m happy to give this an attempt, but I should be honest about my modest experience: I’ve only worked on fairly simple apps and packages/modules, so I would likely need a good amount of architectural guidance.


I want to call out this discussion of “buildless” SSR in the Vite repo:
vitejs/vite#1122

Essentially we could use require.extensions to convert .vue files to es modules, add a .ts extension and then handle them with ts-node... giving us the ability to use Vue components without the hassle of a build.

This is accomplished because the FIRST time any .ts file is run, it is transpiled and that transpiled version is cached via require.cache....

I believe that we could do the same with vue files. Transpile them and cache that result.

It seems pretty compelling to be able to just deploy source files and not have to worry about any build configuration. But if you want to you can do a manual build to “prime the cache.”

In the end I think buildless is compelling to the community because of a general fatigue of tooling and configuration, but it’s possible things are not quite there yet.

At the moment, all that really matters is that things Just Work without fussing with configuration or wiring things together. Maybe it’s too early for buildless, but I’m hopeful web tooling will eventually get there.

@brillout
Copy link
Owner Author

Well, that’s quite encouraging ☺️

Yep. And, even if we fail to popularize it, we will have built something beautiful we can be proud of :-).

starting with a few example projects that don’t actually work (yet) but instead attempt to illustrate how projects should work with Goldpage/RenderX

Yes, that's actually my thinking as well, I just forgot to mention it.

I’m happy to give this an attempt, but I should be honest about my modest experience: I’ve only worked on fairly simple apps and packages/modules, so I would likely need a good amount of architectural guidance.

With automated tests with good coverage, we'll be able to easily change the internal architecture of Goldpage/RenderX. TypeScript + automated tests make refactoring astonishingly easy.

We both care about exposing a minimal interface to the user which means good coverage will be easy to achieve. (We don't have to test all languages PostCSS/SASS/TypeScrip/JSX/SFC/etc. since these are already covered by Vite; we merely need to test our interface.)

So basically my answer here is that we can first implement things in a quick way and eventually make internal improvements.

buildless

Interesting idea - it would make building completely transparent. Neat.

At the moment, all that really matters is that things Just Work without fussing with configuration or wiring things together.

Yes same here. To me, what's important is that the user has to think only what's strictly necessary when using Goldpage/RenderX. In itself, that the user has to run a build step before deploying, although less aesthetically pleasing than buildless, is ok for now.

One reason why I value the core+integrator desgin: it will allow us to experiment and implement all kinds of neat things in the future while keeping the same DX. We can progressively implement these niceties with minimal breaking change for the user.

Let's think about the DX we want, and an exciting future will be ahead of us :). I'll be thinking about it this Weekend.

@brillout
Copy link
Owner Author

Started to think about the interface, but I'm not done.

@chriscalo
Copy link

Sounds like some interesting developments in Vite SSR (as you mentioned above).

https://twitter.com/youyuxi/status/1351225446902464516?s=21

The only thing I’m a little worried about is how long it will take to become stable enough for use in production. Although Vite is at 2.x, things don’t Just Work yet.

@brillout
Copy link
Owner Author

It seems more and more clear that SSR with good DX without framework is only a matter of time.

What I forsee is that Vite will be a low-level SSR solution. Goldpage/RenderX would be a higher-level solution (without being a framework).

But if Vite covers most DX/features we want, then it could replace what we are doing here.

I'll think more about the interface later today. If Vite ends up replacing Goldpage/RenderX then we would have contributed to Vite's SSR interface :). (We should open a ticket about our intentions on the Vite repo at some point.)

Thanks for the tweet pointer, it's great to see Evan caring and pushing the envelope.

@brillout
Copy link
Owner Author

The Interface

Basic usage:

  • SFCs ending with .page.vue are treated as pages.

  • Routing a la Next.js.

    pages/index.page.vue
    -> /
    pages/about.page.vue
    -> /about
    pages/faq/index.page.vue
    -> /faq
    
  • .page.vue files don't have to live in pages/.

    user/list.page.vue
    -> /user/list
    purchase/index.page.vue
    -> /purchase
    index.vue
    -> /
    
  • Dependencies in package.json: goldpage for core, and @goldpage/vue-vite for integrator.

  • Express middleware.

    const goldpage = require("goldpage");
    
    app.use(goldpage());
  • If we can achieve buildless: no CLI at all! Otherwise, a CLI with only one command goldpage build. No CLI for development.

That's all the user would have to do: the basic usage has zero config.

But config is possible for advanced "full control" usage.

  • User can define a .page-config.js file (colocated next to the .page.vue file) to control initialProps, routing, the outer HTML, where & when page is rendered:

    todo/item.page.vue
    todo/item.page-config.js
    
    // todo/item.page-config.js
    
    const Todo = require("./path/to/orm-model/Todo");
    
    export default {
      route: '/item/:itemId',
      renderToHtml: true,
      renderToDom: true,
      renderHtmlAtBuildTime: false,
      addInitialProps: ({ itemId }) => {
        const { text, isCompleted } = await Todo.findById(itemId);
        const item = { text, isCompleted };
        return { item };
      },
      title: ({ item: { text } }) => {
        return 'Todo - ' + item.text;
      },
      html: ({ renderedHtml, title, scripts, css }) => {
        // (All arguments (`renderedHtml`, `title`, ...) are sanitized.)
        return `
    <!DOCTYPE html>
    <html>
      <head>
        <title>${title}</title>
        ${css.join('\n')}
        ${scripts.join('\n')}
      </head>
      <body>
        ${renderedHtml}
      </body>
    </html>`;
      },
    };
  • User can define a .page-entry.js (colocated next to the .page.vue file) file to control the browser-side entry:

    todo/item.page.vue
    todo/item.page-entry.js
    
    // todo/item.page-entry.js
    
    init();
    
    async function init() {
      console.log("before hydration");
      await window.goldpage.hydratePage();
      // (`hydratePage` is defined on the global `window.goldpage` object for
      // reasons I don't mention in this comment.)
      console.log("after hydration");
    
      // Tools such as bootstrap, jQuery, etc. can be easily/naturally initialized here.
    }
  • User can control how views are rendered (allowing easy & natural integration of tools such as Redux/Vuex/ReactRouter/etc.)

    // goldpage/htmlRender.js
    
    const Vue = require("vue");
    const VueServerRenderer = require("vue-server-renderer");
    
    export { htmlRender };
    
    async function htmlRender({ view, initialProps }) {
      const vm = new Vue({
        render: (createElement) => createElement(view, { props: initialProps }),
      });
      const html = await renderer.renderToString(vm);
      return html;
    }
    // goldpage/domRender.js
    
    // ...
    // Similar to `htmlRender`
    // ...
  • User can define global defaults using the goldpage/ config directory:

    // goldpage/default.page-config.vue
    
    export default {
      // Global SSR opt-out
      renderToHtml: false,
      /*
        Etc.
      */
    };
    // goldpage/default.page-entry.vue
    
    init();
    
    async function init() {
      await window.goldpage.hydratePage();
      await installGoogleAnaytlics();
    }
    
    async function installGoogleAnalytics() {
      /* ... */
    }
    // goldpage/default.page.vue
    
    // This file can be used to define a gloabl Vue wrapper that defines
    // the same header and footer for all pages.

Furthermore, we can use the render function idea to enable the user full control over app integration. This will enable all kinds of advanced use cases.

// Full control over server integration

const { renderx } = require("goldpage");
const express = require("express");
const app = express();

app.render("/", async (req, res) => {
  const renderedHtml = await renderx("landing.page.vue");
  res.send(`<html><body>${renderedHtml}</div></html>`);
});
// Full control over SSG

const { renderx, saveToHtmlFile } = require("goldpage");
const Todo = require("./path/to/orm-model/Todo");

generateStaticPages();

async function generateStaticPages() {
  const items = await Todo.getAll();
  await Promise.all(
    items.map(async ({ id, text, isCompleted }) => {
      const renderedHtml = await renderx('todo/item.page.vue', { initialProps: { text, isCompleted } });
      await saveToHtmlFile(`<html><body>renderedHtml</body></html>', { route: `/item/${id}` });
    })
  )
}

This level of control is unseen before. This would be a wonderful do-one-thing-do-it-well tool for companies that need/want control over their app. (I've seen many companies relunctant to use frameworks such as Nuxt/Next.js.)

Thanks to Vite, we can keep the whole source code small.

Basic usage is and should be zero config.

@brillout
Copy link
Owner Author

@chriscalo Let me know if there is anything you don't like about the interface. I'd be curious to know what you think about it.

Vite SSR has landed vitejs/vite#1290 (comment).

I'll start playing with a rough implementation.

@chriscalo
Copy link

chriscalo commented Jan 22, 2021

I hadn't seen, that's a big deal. 👍 super curious to hear what it's like coding against the Vite SSR implementation.

I'll send a more detailed response this weekend, but an initial reaction is:

  • I'm curious whether .html files can be the entry points. what I love about Vue is that it feels native to the web platform, and this goes more in that direction. I think we lose a lot when we abstract away how HTML, CSS, and JS work.

regarding the proposed interface: the way my brain works, I feel like I need to think through things in this order, so it's a little difficult to talk through the interface before going through the use cases, though they're admittedly similar:

  1. examples / use cases / test cases
  2. interface
  3. implementation

Where's the best place to start capturing these use cases? Should I create a one-off repo to gather my thoughts?

@chriscalo
Copy link

chriscalo commented Jan 22, 2021

Also wanted to point out webpack's new lazyCompilation experiment: another step towards going fully buildless in development.

@brillout
Copy link
Owner Author

super curious to hear what it's like coding against the Vite SSR

Super curious as well 👍. I'll have a deeper look at it this Weekend.

what I love about Vue is that it feels native to the web platform

👍 I also like it when things are close to "bare metal".

I'm curious whether .html files can be the entry points.

Interesting idea. Although I'm thinking it can be tricky to share common HTML between pages. For example, pages usually have the same footer and header; how would you then share this same header and footer between all pages?

I need to think through things in this order,

Makes sense. One thing we could as well do is to ask ourselves what use cases would the interface not cover? It may be an efficient way to get intimate with the interface and develop use cases. Similar to writing tests that aim to bring code to fail. I find myself learning a lot when I write tests. Instead of tests, it would be uses case that try to fail the interface.

Where's the best place to start capturing these use cases? Should I create a one-off repo to gather my thoughts?

I guess we can write everything in this ticket for now.

Also wanted to point out webpack's new (lazyCompilation](https://github.com/webpack/webpack/releases/tag/v5.17.0) experiment: another step towards going fully buildless in development.

Neat. They only need a zero-config thing, then Webpack is back in the game :).

@brillout
Copy link
Owner Author

@brillout
Copy link
Owner Author

@chriscalo I published a beta. I'd be curious to know what you think! :-)

@chriscalo
Copy link

Fast progress!

I've been hoping to try this but haven't found some free time just yet. I have a few ideas that might simplify the developer experience, but will collect my thoughts and share.

Also check out recent developments in Nuxt 3: https://nuxtjs.slides.com/atinux/nuxt-3-in-action

@brillout
Copy link
Owner Author

I have a few ideas that might simplify the developer experience

Curious to ear about them!

but will collect my thoughts and share.

Feel free to share them raw and unpolished :)

Also check out recent developments in Nuxt 3: https://nuxtjs.slides.com/atinux/nuxt-3-in-action

Thanks for these pointers, I was actually looking for these slides.

@chriscalo
Copy link

chriscalo commented Feb 28, 2021

A few raw thoughts here, but a big caveat is that I haven't tried things out yet:


The .page.js / .page.vue file-naming convention feels quite nice to me 👍 it's a little verbose, causing slightly longer file names, but it's nicely explicit, which makes it really easy to put index.page.vue right next to MyHomePageTableComponent.vue and not have to do anything special to prevent the latter from being served as a page (which is what happens in Nuxt).

For example, here's the .nuxtignore file I have to use in a Nuxt project so I can keep both page components and sub-page components next to each other in the pages/ directory:

# ignore .js and .comp.vue files in the pages directory
pages/**/*.js
pages/**/*.comp.vue

Of course, I put shared components in the components/ directory following Nuxt conventions, but it's also really common to break functionality out of a page component into its own separate component file not for re-use, but instead purely for organizational purposes when the page component file gets too big or complex.

I expect some people to not love that naming convention, so I wonder if it would be good to offer an option to specify the glob pattern for pages (but also YAGNI).


I'd personally prefer not to use .route.js files at all and instead just use file naming conventions à la Nuxt 3:

pages/[slug].vue
pages/blog/[...all].vue

And you aren't required to write your own render() and hydrate() functions, right? Will things still work if you don't?


In a Nuxt project I ended up embracing the pattern of creating an API and fetching data from within Vue page (and sub-page) components in both Node (via SSR) and the browser. It uses Vue Apollo, and I have no idea how it works, but love that it seems to just work.

<script>
  import { Goals } from "./goals.graphql";
  
  export default {
    apollo: {
      goals: {
        query: Goals,
        prefetch: true,
      },
    },
  };
</script>

<template>
  <table>
    <thead>
      <tr>
        <td>Description</td>
        <td>Target Date</td>
      </tr>
    </thead>
    <tbody>
      <tr v-for="(goal, i) in goals">
      <td>{{ goal.description }}</td>
      <td>{{ goal.targetdate }}</td>
    </tr>
    </tbody>
  </table>
</template>

It does require the following nuxt.config.js to tell Vue Apollo what the API endpoint is:

const { HOST, PORT } = process.env;

export default {
  modules: [
    "@nuxtjs/apollo",
  ],
  apollo: {
    clientConfigs: {
      default: {
        httpEndpoint: `http://${HOST}:${PORT}/graphql`,
        browserHttpEndpoint: `/graphql`,
      },
    },
  },
};

I want to try some similar things with Vite SSR and see if I'm able to get a similar setup working without too much fuss.

In particular, I wonder if the .page.server.js and .page.client.js files make it simple to cleanly segregate server and client logic 🤔.


Thinking aloud, I feel like the fundamental issue is being able to create a "soft" dependency from a .page.vue file that needs to run in Node and in the browser to some Node-only logic for accessing a database. I say soft because you don't want to import and therefore bundle the server logic into your client-side code, but you want some really simple way of calling it.

I kinda wish a very similar pattern like .page.vue files could be used for API endpoints, too. Here's what I'm imagining:

  • a request comes in that's handled by Vite SSR
  • say the URL path is /foo
  • it looks for files that correspond, such as foo.page.vue or perhaps foo.api.js (unsure on the naming)
  • based on the file extension, the server knows how to instantiate that file to handle the request
  • if it's a foo.api.js file, it can just export a connect-compatible handler function to serve as an API endpoint, like below:
import query from "~/util/db.js";

export default async (req, res) => {
  res.json(await query(`select * from Foo`));
}

Then, in a index.page.vue file that's in the same directory as foo.api.js above, calling that endpoint whether from Node or the browser is perhaps as simple as:

<script>
  import http from "~/util/http"; // (axios instance)
  
  export default {
    async data() {
      return {
        // In the browser, the use of a relative path below just works.
        // I wonder what it would take to make the same work on the server.
        foo: await http.get("./foo"),
      };
    },
  };
</script>

<template>
  …
</template>

Here's a somewhat related tweet on making file-based API endpoints, though I don't love the (event, context) signature and would prefer to stick to the Node.js convention of the connect (req, res, next) signature.


I'm also wondering if there's an easy way to set <head> content from within a .page.vue file. There's a really nice pattern in @egoist/vue-head that sadly appears to have been abandoned. That's a shame because it's the only solution to this problem I've seen that resembled plain HTML (all other approaches ask you to write JS/JSON objects for setting <head> HTML, which feels like a step backwards).

<template>
  <Head>
    <title>Hello Vue</title>
    <meta name="description" content="Do you like it?" />
  </Head>
</template>

<script>
import { Head } from '@egoist/vue-head'

export default {
  components: {
    Head,
  },
}
</script>

Another big question: Vite seems really intent on providing only a dev server and not a production server, so I'm curious how you run this in production? I'd really love to not have to write my own server, to be honest. This is the PHP file-system-routing experience: I want to author page and API files, not write serving logic.

@brillout
Copy link
Owner Author

brillout commented Mar 3, 2021

Hi Chris,

I like your thoughts, as usual 😊.

I wonder if it would be good to offer an option to specify the glob pattern for pages

I share the sentiment but I also greatly care about minimal configuration and simplicty. Although the user has slightly more effort and has to type these .page.* suffixes, he'll appreciate a simple tool that has minimal configuration.

I expect some people to not love that naming convention

They'll eventually come to realize that "this is the way".

I'd personally prefer not to use .route.js files

I did think about supporting pages/[slug].vue and pages/blog/[...all].vue but I came to the conclusion not to.

Route srings are more powerful and such path trickery ultimately leads to a loss of dev time when the user ends up thinking "I wonder if I can cram that route string as a FS path?", "Will my FS fail with these non-ASCII characters?", "Will my deploy environemnt fail with that FS path?". Even if know the answers to these question, the user will likely not. All these questions vanish by forcing the user to use proper route strings defined in .page.route.js.

Clarity is more important than having a few extra files.

And you aren't required to write your own render() and hydrate() functions, right?

You actually are required to... and you have to write _default.page.client.js and _default.page.server.js. The idea of vite-plugin-ssr is to give you control over how your pages are rendered. You may loose some time setting up vite-plugin-ssr at first, but you'll eventually win a lot of time when trying to integrate tools. For example, good luck integrating a store tool (that is not Vuex) with Nuxt...

However, I am thinking of writing a framework that is basically a tiny ejectable wrapper on top of vite-plugin-ssr. A la CRA but on top of Vite instead.

It uses Vue Apollo [...] it seems to just work.

Neat, that is indeed convenient. I'll have a look at it.

without too much fuss.

With vite-plugin-ssr you implement all integrations. But the aforementioned framework would take care of integrating the most common tools.

In particular, I wonder if the .page.server.js and .page.client.js files make it simple to cleanly segregate server and client logic 🤔.

Yes exactly: .page.server.js always runs in Node.js while .page.client.js always runs in the browser.

I kinda wish a very similar pattern like .page.vue files could be used for API endpoints, too. Here's what I'm imagining:

Check out https://github.com/brillout/wildcard-api (Which I'm btw going to rename it to Telefunc, "Wildcard API" is a misnomer.)

Using vite-plugin-ssr (or even better the aforementioned framework) with Telefunc will provide a superb DX, similar to what you're describing.

I'm also wondering if there's an easy way to set content from within a .page.vue file

Yes, check out https://github.com/brillout/vite-plugin-ssr#html-head

Vite seems really intent on providing only a dev server and not a production server, so I'm curious how you run this in production?

You integrate vite-plugin-ssr with your server manually: https://github.com/brillout/vite-plugin-ssr/blob/master/create-vite-plugin-ssr/template-vue/server/index.js

I'd really love to not have to write my own server, to be honest. This is the PHP file-system-routing experience: I want to author page and API files, not write serving logic.

I share the sentiment but that's not vite-plugin-ssr's goal. That said, the aforementioned framework would give you what you want: a zero-config SSR framework that is progressively ejectable all the way down to do-one-thing-do-it-well libraries.

  • goldpage eject server -> ejects the server integration.
  • goldpage eject render -> ejects _default.page.client.js and _default.page.server.js.
  • goldpage eject vite -> ejects vite.config.js and replaces the goldpage CLI with the vite CLI.
  • goldpage eject all -> ejects all these three things at once.

Now imagine this with Telefunc. The long term goal of Telefunc is to completely replace Express.js: define your server as functions, that's it. (I'm currently working on file uploads and I've already a design for real-time, which would make Telefunc pretty much feature-complete.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants