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

RFC for builders #25

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions text/0000-builders.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
- Start Date: 2020-06-25
- RFC PR:
- Svelte Issue: ]

# Sapper Builders

## Summary

This RFC proposes a method of modularising build output from Sapper for ease of deployment across a variety of targets.

## Motivation

Sapper's current build output comprises of a series of files:

1. A build manifest
1. A client bundle
1. A server bundle (in non-exported mode)
1. An (optional) legacy client bundle
1. Static files

Deploying this is relatively simple, but certainly not optimised for certain deployment strategies such as serverless (lambda), and often relies on third-party, platform-specific builders.

If Sapper were to produce its output in a more modular fashion, it would facilitate the creation of a number of officially supported "builders" for major platforms, as well as opening the doors for third parties to easily produce builders which targetted other platforms.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One way to think about this is that there should be no __sapper__/build/index.js.

Instead, we should emit enough information for someone to run a completely separate tool against the sapper build output. Something like sapper serve ...

This command would read the routes from the given directory and serve them directly. This would also make it straightforward for others to write deploy commands that can package things up for various hosting providers.


Additionally, it would ease the creation of some desirable features:

1. Per-route bundle splitting
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pngwn pointed out that you might want the splitting to happen for both the server-side and client-side code: sveltejs/sapper#1346 (comment)

1. [Differential rendering on a per-route basis](https://github.com/sveltejs/sapper/issues/1324) - Allowing SSR, SSG, SPA, [JAM](https://github.com/sveltejs/sapper/issues/1093), on a per-route basis.
1. [Faster cold-boot time for serverless functions](https://github.com/sveltejs/sapper/issues/356)
1. [SPA Mode](https://github.com/sveltejs/sapper/issues/383)

It would facilitate easier deployment on some new platforms:

1. [Azure Functions](https://azure.microsoft.com/en-gb/services/functions)
1. [AWS Lambda](https://aws.amazon.com/lambda/)
1. [Google Cloud Functions](https://cloud.google.com/functions)
1. [IBM Cloud Functions](https://www.ibm.com/uk-en/cloud/functions)
1. [IPFS](https://ipfs.io/)
1. [Begin.com](https://begin.com/)
1. [Netlify](https://www.netlify.com/)
1. [Cloudflare Workers](https://blog.cloudflare.com/introducing-cloudflare-workers/)
1. [Fastly Edge](https://www.fastly.com/products/edge-compute)

## Detailed design

> This is the bulk of the RFC.

> Explain the design in enough detail for somebody
familiar with the framework to understand, and for somebody familiar with the
implementation to implement. This should get into specifics and corner-cases,
and include examples of how the feature is used. Any new terminology should be
defined here.

* Client-side bundle goes into static dir (SPA)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When you say "static dir" I'm guessing you mean __sapper__/build/client/ and not static/?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is my understanding.

There is additional complexity here. We obviously need this information in the server builder as well, but if we are moving towards facilitating 'faas' deployment then we might want to consider greater support for plopping your assets on a CDN, there have been some issues about this in the past. I think this is quite difficult right now, if it is possible at all.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main difficulty right now that I'm aware of is that the images don't have hashes in their names, so they're not cacheable. I sent a PR to the template to address this: sveltejs/sapper-template#248

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re "if it is possible at all": Right now I'm deploying my sapper app to a CDN by parsing the routes directly out of manifest source code and generating CDN configuration for it.

* Individual modules built for each route
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean by "modules" here? An npm module? Or just a file or collection of files?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is the per route code-splitting part, essentially having distinct individually deployable pieces of code for each route. There are benefits to this approach but it might also not be necessary, we'd need to validate. It could be that it becomes more significant over a certain size.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My instinct here is that there are at least 2 reasons to put things into the same function bundle:

  • they always change together (less risk of them getting out of sync during deployment)
  • they use the same set of (third party) dependencies

Along these lines, there are at least 2 reasons to put things in different bundles:

  • they use different secrets (e.g. one has a secret token for Stripe, the other has a secret token for AWS)
  • avoid loading unnecessary code to keep cold starts as fast as possible

* entrypoint imports individual route modules (for local development + simple `node` deployment)
* `@sapper/[architecture]-builder` packages
* Removing export (an application which has no dynamic routes is automatically SSG)

Discuss:

1. How do we determine which routes are:
* SPA (No preload)
* SSG (?)
* Hybrid / SSR (Preload function exists) - current behaviour

2. Questions around treatment of server routes

## How we teach this

> What names and terminology work best for these concepts and why? How is this
idea best presented? As a continuation of existing Svelte patterns, or as a
wholly new one?

> Would the acceptance of this proposal mean the Svelte guides must be
re-organized or altered? Does it change how Svelte is taught to new users
at any level?

> How should this feature be introduced and taught to existing Svelte
users?

To define:

SSG: Server-side generated pages
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be statically generated? (i.e. at compile time)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SPA: Single-page App
SSR: Server-side Rendering

## Drawbacks
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One of the major questions this might raise is whether to keep support Webpack. Depending on the implementation, we may decide it's not worth implementing for Webpack (at least until someone from the community contributes a new Webpack implemention)

I think about 2/3 of our users use Rollup based on the numbers from the plugins:

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would ditch webpack entirely. We don't have the resource to support multiple bundlers, and 5 is probably different enough to require a re-implementation anyway. Rollup is fast becoming the preferred choice for other projects anyway, and we have a distinct advantage in having a certain project author on our team.

I am very much in favour of abstracting the build, I wouldn't build it for any specific bundler, but I also wouldn't go too deep in abstracting it.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am in favor of only focusing on rollup in the near-term, although I don't think we should allow any rollup-specific abstractions into the core algorithms of this stuff. This will: reduce the total amount of knowledge someone will need to understand the core algorithms, insulate us from changes to rollup, and make it easier to support other bundlers


This approach provides many benefits, however one potential drawback is the additional complexity of moving from a two-bundle, encapsulated deployment, served up by a single javascript file `node /__sapper__/build/index.js` into a collection of files relating to routes. It's important that a builder exists (and is possibly the default) for running the simplest possible instance of the app, with just node and a http server installed.

## Alternatives

NextJS [already has a solution for this](https://github.com/vercel/next.js/issues/9524), borne of a constraint in the architecture, however it has proven itself as a highly desirable feature. We can draw inspiration from the way they have addressed this problem. It's also worth noting that their problem is understandably very targetted to users hosting on their own Vercel platform, whereas the Sapper solution should consider a range of platforms.

Builders are a feature that Vercel uses quite heavily. However they can be quite complicated due to the abstraction they work over (such as serving serverless GO, PHP, etc). Since we control the input, Sapper builders should be a simple mapping excercise in most cases.

## Unresolved questions

> Optional, but suggested for first drafts. What parts of the design are still
TBD?