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

SSR and Serverless experiments [DO NOT MERGE] #812

Closed
wants to merge 6 commits into from

Conversation

thescientist13
Copy link
Member

@thescientist13 thescientist13 commented Nov 30, 2021

Overview

Opening this for demonstration and discussion purposes and to flesh out ideas and architecture for implementing server side and serverless capabilities for Greenwood. The goal is to see what an implementation might look like, how it plays together with other parts of the system, and what implications there are that should be accounted for ahead of actually intending to submit a PR.

SSR

Screen Shot 2021-11-24 at 6 53 49 PM

I think what's really cool about the possibilities here is how seamless it would be to run a hybrid application, such that you can have a set of static and dynamic pages and routes that can all share the same static resources, yet still feel like one app.

src/
  pages/
    about.md
    index.html
    contact.html
  routes/
    artists.js
    artist.js
  templates/
    app.html
    page.html
    product.html
  styles/
    theme.css
    artist.css
    main.css

In this way

  • your landing / marketing "pages" can consist of static pages at build time (either as markdown or from a headless CMS)
  • that can co-locate with "routes" that can be server rendered, but still re-use the same templating system

I tried to demonstrate that here in this PR with the "Artists" page, though obviously this will not work on Netlify, but you can try it locally!

Testing

To run this branch on a server

  1. Spin up a server, like an EC2 instance
  2. git clone the repo and checkout this branch
  3. Run yarn install
  4. Run yarn serve

From your public IP (make sure to open up port 8080 through your SGs, etc)

  • http://x.x.x.x:8080/
  • http://x.x.x.x:8080/artists

Live Demos (make sure I've started the server first!)

Screen Shot 2021-11-26 at 7 48 57 PM
Screen Shot 2021-11-26 at 7 49 04 PM

Caveats

Serverless

Screen Shot 2021-12-01 at 12 18 37 PM

Since there are typically size constraints related to running serverless, for this reason, to limit size, it may be advisable to:

  • Do this in a standalone repo
  • Manually delete puppeteer from node_modules

Testing

  1. Create a directory and run npx @greenwood/init --install
  2. cd into that directory and delete puppeteer from node_modules
  3. From this PR, copy the contents of the following files from packages/cli/ in your own local node_modules/@greenwood/cli/ directory
    • index.js
    • src/plugins/resource/plugin-standard-html.js
    • src/commands/serve.js
    • src/lifecycles/config.js
    • src/lifecycles/context.js
    • src/lifecycles/serve.js
    • src/plugins/resource/plugin-standard-html.js
  4. Copy / paste in index.js as the Lambda handler

Or you can clone this reference repo.

Workflow

  1. To test locally, uncomment the run() function in index.js and then run node ./index.js
  2. To create an upload for Lamda by creaunge a zip file
    $ zip -r upload.zip . -x ".git/*"
  3. Or bundle using Rollup by running yarn dist
  4. Upload this to your cloud hosting and invoke the function

Live Demos

Screen Shot 2021-12-01 at 12 18 21 PM
Screen Shot 2021-12-01 at 12 19 03 PM

For testing, I used AWS Lambda + API Gateway.

Caveats

Notes / Takeaways

  1. Noticed that ESM has a caching mechanism of modules which is something to be mindful of for development
  2. With routes, we'll want to investigate what a hydration strategy could look like for more idiomatic SSR solutions like Lit
  3. We will need to open up the ability for users to set ports, not just for the dev server
  4. I think we should rethink the mode config option, and remove it entirely? I would like to implement "progressive configuration" such that if we see a user has pages and / or routes, or just an index.html, we can handle that without needing to have it configured by the user. I think this is because now we really have a hybrid situation and it should be easy for users to static and add / go dynamic, would be sweet. Instead, we turn mpa mode into a staticRouter config such that if users want this static route (since it's not designed for SPA) they can use that instead.
  5. We really need to make puppeteer optional i think, and potentially have prerender off by default. The website builds sooooo much faster without it, so it is definitely probably better for us to not force that long time as default, especially if you really just want a static site.

Open Items

  1. Properly encode Lambda response (remove escaping and line breaks from the response) - this resource helped a lot!
  2. Bundling (rollup) routes (SSR)
  3. Prerendering (puppeteer) routes (SSR)
  4. Bikeshed on serverless API
  5. Handle dynamic routes, e.g. /artist/:id
  6. Draft issue for no mode
  7. Draft issue for optional puppeteer

@thescientist13 thescientist13 added todos SSR discussion tied to an ongoing discussion or meeting notes labels Nov 30, 2021
@thescientist13 thescientist13 added this to the 1.0 milestone Nov 30, 2021
@thescientist13 thescientist13 self-assigned this Nov 30, 2021
@thescientist13 thescientist13 changed the title [DO NOT MERGE] SSR (and serverless) experiments SSR and Serverless experiments [DO NOT MERGE] Nov 30, 2021
return '<h1>Content goes here</h1>';
}

async function getMetadata() {
Copy link
Member Author

@thescientist13 thescientist13 Dec 1, 2021

Choose a reason for hiding this comment

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

One good point that was brought up during the call was that we could this getMetadata function to provide more hints to Greenwood such that even if routes exist in the project, but the user still wants to statically export them (so no server at runtime) we could definitely handle this:

async function getMetadata() {
  return {
    staticExport: true
  }
}

This would provide NextJS like behavior in that you can author purely dynamic content at build time but still reuse your templates / components / styles, and get a completely static artifact just as if it was in the pages/ directory. 📦 🙌

@thescientist13
Copy link
Member Author

Interesting thread that could help us with designing an entry file that is both main and bin when working in ESM - nodejs/node#49440

if (command === 'serverless') {
Copy link
Member Author

@thescientist13 thescientist13 Nov 9, 2022

Choose a reason for hiding this comment

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

Maybe this would be helpful for detecting if run from JS or run from the CLI; import.meta.main - https://github.com/nodejs/modules/issues/274#issuecomment-1302971322

@thescientist13 thescientist13 added invalid This doesn't seem right and removed invalid This doesn't seem right todos labels May 20, 2023
@thescientist13
Copy link
Member Author

Serverless support released as part of v0.29.0! 🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
discussion tied to an ongoing discussion or meeting notes SSR
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant