Beyond SPAs — all app types support. (SSR, MPA, Static Website, Backend-Only, ...)
See original GitHub issueThe zero-config usage of Parcel creates an SPA.
For many applications an SPA doesn’t work out. (Because of search engines, social sharing, and performance.)
The Problem
The main problem of our current tools is that they support only one app type. For example for React:
- create-react-app, Parcel, and webpack create an SPA.
- Next.js creates an SSR app (or a static website).
- Gatsby creates a static website.
By choosing one of these tools you are essentially choosing an app type and locking yourself into that app type. This means that before choosing one of these tools you have to research about what “SPA”, “SSR”, and “static website” mean and what the differences between them are. And that before even having started writing one line of code.
Even worse is that, most often than not, it’s not possible to predict which app type is the right one before having created and battle-tested a first prototype.
Strictly speaking, saying that Parcel and Webpack create an SPA is not true. But creating app types other than SPAs (e.g. an SSR app) is very difficult with Parcel/Webpack alone.
A Solution
From a user pespective, it would be neat to be able to use Parcel to easily create all kinds of app types. (SSR, MPA, Static Rendering, etc.) Basically having Parcel support all app types with (almost)-zero-config.
I can see that this would bring many problems from the perspective of Parcel’s code architectural design. And Parcel would be less do-one-thing-do-it-well.
But, now that Parcel v2’s core is small, maybe all app type support could be implemented as a suit of plugins instead of creeping all app type support into Parcel’s core.
The best UI for all app type support I’ve designed so far is centered around:
- Page configs
- Render functions
- Server middleware
Page configs:
// A page config
// Also works with any other isomorphic view library such as Vue
import React from 'react';
export default {
route: '/hello/:name',
view: ({name}) => (
<div>
Hello {name}, welcome.
</div>
),
// By default, an SPA is built:
renderToDom: true,
renderToHtml: false,
/* To add SSR:
renderToHtml: true,
*/
/* For Static Rendering:
renderToHtml: true,
renderHtmlAtBuildTime: true,
*/
/* To remove browser-side JavaScript:
renderToDom: false,
*/
};
Render functions:
// DOM Render
// This DOM render is for React but any kind of render can be written
// for Vue, Preact, React Native Web, etc.
import React from 'react';
import ReactDOM from 'react-dom';
export default domRender;
async function domRender({page, initialProps, CONTAINER_ID}) {
ReactDOM.hydrate(
React.createElement(page.view, initialProps),
document.getElementById(CONTAINER_ID)
);
}
// HTML Render
// This HTML render is for React but any kind of render can be written
// for Vue, Preact, React Native Web, etc.
const React = require('react');
const ReactDOMServer = require('react-dom/server');
module.exports = htmlRender;
async function htmlRender({page, initialProps}) {
const html = (
ReactDOMServer.renderToStaticMarkup(
React.createElement(page.view, initialProps)
)
);
return html;
}
Server middleware:
const express = require('express');
const parcel = require('@parcel/server');
const app = express();
// The `parcel` middleware serves your pages.
app.use(parcel);
// When the backend is a Node.js server, a middleware is super convenient.
// There are many reasons for that and I can elaborate more if you want.
To add SSR to a page you’d simply set renderToHtml: true
. A static website can be built by setting renderHtmlAtBuildTime: true
to all page configs. Browser-side JavaScript can be removed by setting renderToDom: true
(super important from a mobile performance perspective). And so on and so forth. All app types are supported that way. This also intoduces new app types that aren’t widespread (yet).
Not only does this design support all app types, but it also allows to easily switch from one app type to another. It would be super neat to have a (almost-)zero-config way to switch between app types. So that the user doesn’t have to research what “SPA” or “SSR” mean before writing his first prototype. He can start coding and take care of the right app type later.
As far as I can see, this design could be a sweat spot between ease of use and flexibility.
The design can be used with any isomorphic view library. (With isomorphic view library I mean a library that can render views to HTML as well as to the DOM.)
Is supporting all app types something Parcel would be interested in?
I’m asking because I suspect that supporting all app types will need changes in Parcel’s design, such as support for different targets for different entries.
It seems that a server middleware as shown above could be implemented as a reporter plugin. Instead of re-writing the dev server from scratch, maybe code from the current dev server could be re-used.
I’m busy at the moment but I’ll further dig into all that and into the Parcel plugin APIs later.
I’ve said it many times already, but again, thanks for zero-config. It’s wonderful to be able to quickly build an app without unnecessarily loosing time on infrastructure.
Issue Analytics
- State:
- Created 4 years ago
- Comments:8 (5 by maintainers)
@brillout awesome, I always thought Next.js was heading that way with their framework. But anyway that’s off topic for Parcel.
About my experiment with blazingly-ssr I’ll probably be rewriting it again once Parcel 2 is a bit more stable, not sure if I’d turn it into a production ready tool though (probably more an experiment to showcase the posibilities of Parcel 2). Anyway I’d also be up for any collaboration on that, hit me up on twitter for that as this issue is probably off-topic for the Parcel repo.
@DeMoorJasper
I understand that feasbibility is a concern from your perspective. But note that:
It’s not like effort for my tool = effort for Gatsby + effort CRA + effort Next.js. Not at all — my tool is only a page builder.
To give an order of magnitue of how small the tool is:
The core contains the logic for all-app-types support. The plugins are about integrations with various third-party libraries (path-to-regex for server-side routing, middlewares for express/koa/hapi, etc.)
What’s most interesting here is that out of 7k helpers, 5.5k is about managing the Webpack compilations. The Webpack API is far from great and it’s been a huge pain to build the tool on top of Webpack.
This means that more than half of the codebase is because of Webpack’s shortcomings. And all complex code are all related to this code. The rest of the codebase, including core, is actually fairly straightforward.
My hope here is that using Parcel instead of Webpack would cut my codebase size by up to two. It will then be easy to maintain my tool once/if it’s widely adpoted. E.g. the #3302 ticket will considerably help me.
Also I don’t want to compete here. I would actually very much welcome frameworks such as Next.js to use my tool. If they switch to parcel, they might as well use my parcel plugin(s) that I will implement. (If I implement my tool as Parcel plugin(s)).
Btw. I’ve seen your POC blazingly — I’d be up to collaborate.
@DeMoorJasper @Banou26 @devongovett
To me, this ticket is not about whether my tool will succeed. Where I may fail someone else may succeed.
This ticket is about this: as a Parcel community, do we want all-app-types support?
I will be writing more about the various benefits of all-app-types support in the coming weeks.
It’s not only about SSR and SPA. It’s also about new app types. For example what I call “Backend First App”: an app that is rendered to good old plain HTML (using React/Vue as HTML template engine). Almost everything is rendered to HTML and only a couple of interactive views are rendered to the DOM. This is wonderful for websites that are mostly about content, for example an online newspaper. Great mobile performance (since much less browser-side JavaScript), great SEO (since all content is rendered to HTML), interactive views, and fast dev speed (using React/Vue as HTML template engine is vastly simpler).
As far as I can see, all-app-types support will be obvious in the future. Just like it has become obvious that zero-config is the way to go for web app bundlers.