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

Towards personalized SSG #4951

Merged
merged 2 commits into from
Aug 18, 2023
Merged

Towards personalized SSG #4951

merged 2 commits into from
Aug 18, 2023

Conversation

eric-burel
Copy link
Contributor

@eric-burel eric-burel commented Aug 16, 2023

Overview

What is it?

  • Feature / enhancement
  • Bug
  • Docs / tests / types / typos

Description

Hi folks,

I am just discovering Qwik, coming from Next.js with a solid experience regarding static rendering.

My pet peeve is the belief that static rendering is best for content that is the same for all visitors. I think this doesn't give static rendering justice, because SSG is also perfectly viable for content that is the same for groups of visitors.

So, my proposal:

  • first I've changed the doc in this PR to be clearer about the fact that SSG is not limited to content that is the same for all visitors. More on that below.
  • then, I think it would be interesting to open up the discussion and document more advanced patterns, like redirecting to static content depending on the request. Perhaps this has been discussed already, or considered very easy, then it would be interesting to include the relevant links directly in the documentation.

This is in my opinion a relatively important matter when trying to compare Qwik with say Next.js on use cases where Next.js shines, namely content app (e-commerce websites, media websites, basically any app where you have a strong marketing service behind with contradictory requirements between rich content, personalization and performances).

I'd be eager to get Qwik developers stance on this idea!

Use cases and why

The difference between "same for everybody" and "same for groups of people" seems subtle, but actually opens up so many use cases for static rendering:

  • A/B tests: some users see version A, some version B. But A and B are known in advance: let's statically render that!
  • i18n: some users see language FR, some se language EN, DE...
  • marketing segmentation: "top-notch VIP", "people who won't buy without a coupon", "new customers"
  • dark/light theme
  • multi-tenancy: the company logo in the layout changes depending on the organization you belong to.

And more broadly whatever personalization pattern you may encounter in the wild.

For previous art, I've opened similar issues with explanations:

And I've written articles on the topic:

That's for the rough idea. If you think a bit about this idea a bit more, you should quickly understand that the key to this personnalisation is to redirect the user towards the right version of the page.

In Next.js, this can be done natively using middlewares. I deplore the fact that Next.js only allows static rendering based on a route parameter, and not say cookies, headers, or URL search params. Hopefully this limitation can be bypassed by using URL rewrites. I've written another aticle showing this pattern: "Render anything statically with Next.js and the Megaparam" https://blog.vulcanjs.org/render-anything-statically-with-next-js-and-the-megaparam-4039e66ffde"

I think Qwik has a similar approach so could benefit from this pattern too but not sure about the specific implementation.

Lastly, you might think: "ok but this is actually SSR coupled with HTTP caching, not SSG". Yes but no, doing static personalization at "framework level" is more flexible. HTTP cache is not evenly supported, namely it's hard to cache variations depending on a subtile change like the precise value of one cookie (Vary header and such).

Bonus: you may encounter another kind of personalization, that is altering the page at the Edge (Eleventy-style). This is great too but often limited to slight adaptations, because you have to alter already rendered HTML so you can't rely on the rendering framework at this stage.

@netlify
Copy link

netlify bot commented Aug 16, 2023

👷 Deploy request for qwik-insights pending review.

Visit the deploys page to approve it

Name Link
🔨 Latest commit 7247c58

@stackblitz
Copy link

stackblitz bot commented Aug 16, 2023

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

@zanettin zanettin added WAITING FOR: team Waiting for one of the core team members to review and reply COMP: docs Improvements or additions to documentation TYPE: enhancement New feature or request labels Aug 16, 2023
@wmertens
Copy link
Member

FWIW, I've been doing cached SSR in my react apps since 2015 or so, make a key based on hash of build, request, user, mobile browser etc, and use that to check a cache, falling back to SSR. Works great.

For me though, SSG is for allowing deploying without any server component. Is that not the case?

@mhevery mhevery enabled auto-merge (squash) August 18, 2023 20:14
@eric-burel
Copy link
Contributor Author

FWIW, I've been doing cached SSR in my react apps since 2015 or so, make a key based on hash of build, request, user, mobile browser etc, and use that to check a cache, falling back to SSR. Works great.

I wish this was more common! Modern frameworks do not really let you do that easily, you have to twist Next.js a bit to achieve that and I am still trying to learn how it's done in Qwik/Vite.

For me though, SSG is for allowing deploying without any server component. Is that not the case?

I think a distinction should be made between having no rendering server and having no server at all. Cached SSR is about avoiding to useless re-renders but it doesn't tell much about when you render, either build-time or request-time, so let's suppose you render at first request and cache the thing.

The point of SSG is indeed to allow deployment without a rendering server (read a full-fledged Node.js server that can run JS), so you have to render everything at build-time.

But that doesn't mean you cannot have a server. Actually you need only one feature to support personalized static rendering: URL rewriting, in order to point a given request to the right prerendered path (which acts as your cache key). Nginx, Route 53, Edge functions/middlewares are smart enough to support that. You can assume that this feature is not hard to implement if the developer really wants it and more broadly that nothing prevents you from rendering personalized content at build-time that is different for many users.

@mhevery mhevery merged commit 380d50a into QwikDev:main Aug 18, 2023
16 checks passed
@lbensaad
Copy link
Contributor

lbensaad commented Aug 23, 2023

Thanks a lot for this effort. I am building an online ordering and invoicing SPA using Qwik. It is totally SSG served by nginx, a Jamstack. All pages are private behind auth. After each page load I fetch the needed data from Pocketbase. I loose some of the benefits of Qwik like server actions, but I found that jamstack is better me.

kodiakhq bot pushed a commit to ascorbic/unpic-img that referenced this pull request Aug 27, 2023
[![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)

This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [@builder.io/qwik](https://qwik.builder.io/) ([source](https://togithub.com/BuilderIO/qwik)) | [`1.2.7` -> `1.2.10`](https://renovatebot.com/diffs/npm/@builder.io%2fqwik/1.2.7/1.2.10) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@builder.io%2fqwik/1.2.10?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@builder.io%2fqwik/1.2.10?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@builder.io%2fqwik/1.2.7/1.2.10?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@builder.io%2fqwik/1.2.7/1.2.10?slim=true)](https://docs.renovatebot.com/merge-confidence/) |

---

### Release Notes

<details>
<summary>BuilderIO/qwik (@&#8203;builder.io/qwik)</summary>

### [`v1.2.10`](https://togithub.com/BuilderIO/qwik/releases/tag/v1.2.10)

[Compare Source](https://togithub.com/BuilderIO/qwik/compare/v1.2.9...v1.2.10)

##### What's Changed

-   fix: docs/cookbook/index.mdx link to portal page by [@&#8203;Craiqser](https://togithub.com/Craiqser) in [QwikDev/qwik#5022
-   qwik-labs: fix prettier estree error by [@&#8203;gioboa](https://togithub.com/gioboa) in [QwikDev/qwik#5027
-   insights: add existsSync check by [@&#8203;gioboa](https://togithub.com/gioboa) in [QwikDev/qwik#5026
-   chore(insights): correct DB migration script by [@&#8203;mhevery](https://togithub.com/mhevery) in [QwikDev/qwik#5024
-   fix(core): Report errors to browser global error handler by [@&#8203;mhevery](https://togithub.com/mhevery) in [QwikDev/qwik#5029
-   style(pnpm-lock.yaml): synchronize lockfile version with version of pnpm in use by [@&#8203;jensmeindertsma](https://togithub.com/jensmeindertsma) in [QwikDev/qwik#4905
-   fix(starter): missing key attrib on `routerHead` component on `1.2.9` by [@&#8203;zanettin](https://togithub.com/zanettin) in [QwikDev/qwik#5025
-   1.2.10 by [@&#8203;mhevery](https://togithub.com/mhevery) in [QwikDev/qwik#5035

**Full Changelog**: QwikDev/qwik@v1.2.9...v1.2.10

### [`v1.2.9`](https://togithub.com/BuilderIO/qwik/releases/tag/v1.2.9)

[Compare Source](https://togithub.com/BuilderIO/qwik/compare/v1.2.8...v1.2.9)

#### What's Changed

-   docs: Vercel environment variables by [@&#8203;gioboa](https://togithub.com/gioboa) in [QwikDev/qwik#4993
-   refactor(create-qwik): add yargs in create-qwik for better DX by [@&#8203;MrWaip](https://togithub.com/MrWaip) in [QwikDev/qwik#4932
-   feat(adapter): firebase adapter by [@&#8203;leifermendez](https://togithub.com/leifermendez) in [QwikDev/qwik#4778
-   Pr chore by [@&#8203;mhevery](https://togithub.com/mhevery) in [QwikDev/qwik#4994
-   fix: Link component `reload` functionality by [@&#8203;zanettin](https://togithub.com/zanettin) in [QwikDev/qwik#4917
-   docs(qwikcity): html attributes docs page by [@&#8203;bab2683](https://togithub.com/bab2683) in [QwikDev/qwik#4961
-   feat(qwik-city): add a way to get server-side env vars from `onStaticGenerate` by [@&#8203;Kocal](https://togithub.com/Kocal) in [QwikDev/qwik#4912
-   fix(eslint): allow eslint to accept FunctionComponent inside lexical scopes by [@&#8203;nynevi](https://togithub.com/nynevi) in [QwikDev/qwik#4900
-   refactor(cloudflare-pages): allow PlatformCloudflarePages.env to be undefined by [@&#8203;bangonkali](https://togithub.com/bangonkali) in [QwikDev/qwik#4941
-   docs: dynamic alt image by [@&#8203;the-r3aper7](https://togithub.com/the-r3aper7) in [QwikDev/qwik#4999
-   docs: add responsive image recipe by [@&#8203;fabiobiondi](https://togithub.com/fabiobiondi) in [QwikDev/qwik#5002
-   docs: community project update image url by [@&#8203;the-r3aper7](https://togithub.com/the-r3aper7) in [QwikDev/qwik#5000
-   docs: enhance image documentation by [@&#8203;fabiobiondi](https://togithub.com/fabiobiondi) in [QwikDev/qwik#5005
-   added qwik-meet in showcase by [@&#8203;harshmangalam](https://togithub.com/harshmangalam) in [QwikDev/qwik#5007
-   docs: Update index.mdx by [@&#8203;the-r3aper7](https://togithub.com/the-r3aper7) in [QwikDev/qwik#5010
-   docs: update side bar by [@&#8203;the-r3aper7](https://togithub.com/the-r3aper7) in [QwikDev/qwik#5009
-   fix(qwik-city): enable matching route and pathname with an optional t… by [@&#8203;pleclech](https://togithub.com/pleclech) in [QwikDev/qwik#5004
-   docs(image): add details by [@&#8203;fabiobiondi](https://togithub.com/fabiobiondi) in [QwikDev/qwik#5014
-   insights(feat): qwikInsights Vite Plugin + save symbol details by [@&#8203;gioboa](https://togithub.com/gioboa) in [QwikDev/qwik#5011
-   chore(insights): Remove deprecated InferModel by [@&#8203;mhevery](https://togithub.com/mhevery) in [QwikDev/qwik#5018
-   fix: add  options to qwik vite plugin by [@&#8203;jessezhang91](https://togithub.com/jessezhang91) in [QwikDev/qwik#4983
-   1.2.9 by [@&#8203;mhevery](https://togithub.com/mhevery) in [QwikDev/qwik#5021

#### New Contributors

-   [@&#8203;MrWaip](https://togithub.com/MrWaip) made their first contribution in [QwikDev/qwik#4932
-   [@&#8203;bab2683](https://togithub.com/bab2683) made their first contribution in [QwikDev/qwik#4961
-   [@&#8203;Kocal](https://togithub.com/Kocal) made their first contribution in [QwikDev/qwik#4912
-   [@&#8203;nynevi](https://togithub.com/nynevi) made their first contribution in [QwikDev/qwik#4900
-   [@&#8203;bangonkali](https://togithub.com/bangonkali) made their first contribution in [QwikDev/qwik#4941
-   [@&#8203;pleclech](https://togithub.com/pleclech) made their first contribution in [QwikDev/qwik#5004

**Full Changelog**: QwikDev/qwik@v1.2.8...v1.2.9

### [`v1.2.8`](https://togithub.com/BuilderIO/qwik/releases/tag/v1.2.8)

[Compare Source](https://togithub.com/BuilderIO/qwik/compare/v1.2.7...v1.2.8)

##### What's Changed

-   docs: cleanup by [@&#8203;mhevery](https://togithub.com/mhevery) in [QwikDev/qwik#4945
-   chore: update issue templates by [@&#8203;shairez](https://togithub.com/shairez) in [QwikDev/qwik#4962
-   docs: correctly generate edit URLs for github by [@&#8203;mhevery](https://togithub.com/mhevery) in [QwikDev/qwik#4963
-   Typo in FAQ by [@&#8203;ThatJSGuy](https://togithub.com/ThatJSGuy) in [QwikDev/qwik#4953
-   feat(qwik-city): Show current route in container by [@&#8203;mhevery](https://togithub.com/mhevery) in [QwikDev/qwik#4954
-   fix(docs): add overview link by [@&#8203;fabiobiondi](https://togithub.com/fabiobiondi) in [QwikDev/qwik#4958
-   Towards personalized SSG by [@&#8203;eric-burel](https://togithub.com/eric-burel) in [QwikDev/qwik#4951
-   fix(qwik-auth): remove qaction param from defaultCallbackUrl by [@&#8203;ulic75](https://togithub.com/ulic75) in [QwikDev/qwik#4936
-   fix(qwik-city): cleanup matchRouteRequest by [@&#8203;gioboa](https://togithub.com/gioboa) in [QwikDev/qwik#4967
-   fix(auth): Cookies get updated if session returns Updated Cookies by [@&#8203;aliyss](https://togithub.com/aliyss) in [QwikDev/qwik#4960
-   cli(library): fix release script by [@&#8203;fabiobiondi](https://togithub.com/fabiobiondi) in [QwikDev/qwik#4957
-   docs: Improved media, fixed height thumbnails by [@&#8203;the-r3aper7](https://togithub.com/the-r3aper7) in [QwikDev/qwik#4970
-   feat(qwik-city): Adding Script Tag to Head Tag via DocumentHead by [@&#8203;Harkunwar](https://togithub.com/Harkunwar) in [QwikDev/qwik#3230
-   fix: fix cookie parsing to allow invalid uri encoding by [@&#8203;jessezhang91](https://togithub.com/jessezhang91) in [QwikDev/qwik#4915
-   fix(qwikcity): respect X-Forwarded-Host header by [@&#8203;mhevery](https://togithub.com/mhevery) in [QwikDev/qwik#4982
-   chore(docs): fix broken cloudflare build by [@&#8203;mhevery](https://togithub.com/mhevery) in [QwikDev/qwik#4984
-   feat(insights): manage routes and timeline metrics by [@&#8203;gioboa](https://togithub.com/gioboa) in [QwikDev/qwik#4971
-   feat: complex form data by [@&#8203;ulic75](https://togithub.com/ulic75) in [QwikDev/qwik#4634
-   docs(portals): update the portal cookbook example by [@&#8203;mhevery](https://togithub.com/mhevery) in [QwikDev/qwik#4968
-   chore(insights): fix build by [@&#8203;mhevery](https://togithub.com/mhevery) in [QwikDev/qwik#4986
-   fix: only show qwik eslint errors in dev mode by [@&#8203;jessezhang91](https://togithub.com/jessezhang91) in [QwikDev/qwik#4985
-   docs: some progress on the update of the react-cheat-sheet section re… by [@&#8203;nsdonato](https://togithub.com/nsdonato) in [QwikDev/qwik#4976
-   chore(docs): Remove home-page from SSR to improve TTFB metric by [@&#8203;mhevery](https://togithub.com/mhevery) in [QwikDev/qwik#4988
-   Pr no ssr by [@&#8203;mhevery](https://togithub.com/mhevery) in [QwikDev/qwik#4989
-   cli: Add new Markdown route command by [@&#8203;brandonpittman](https://togithub.com/brandonpittman) in [QwikDev/qwik#4955
-   docs: update Prisma limitations by [@&#8203;ruheni](https://togithub.com/ruheni) in [QwikDev/qwik#4241
-   1.2.8 by [@&#8203;mhevery](https://togithub.com/mhevery) in [QwikDev/qwik#4992

##### New Contributors

-   [@&#8203;ThatJSGuy](https://togithub.com/ThatJSGuy) made their first contribution in [QwikDev/qwik#4953
-   [@&#8203;fabiobiondi](https://togithub.com/fabiobiondi) made their first contribution in [QwikDev/qwik#4958
-   [@&#8203;eric-burel](https://togithub.com/eric-burel) made their first contribution in [QwikDev/qwik#4951
-   [@&#8203;aliyss](https://togithub.com/aliyss) made their first contribution in [QwikDev/qwik#4960
-   [@&#8203;brandonpittman](https://togithub.com/brandonpittman) made their first contribution in [QwikDev/qwik#4955
-   [@&#8203;ruheni](https://togithub.com/ruheni) made their first contribution in [QwikDev/qwik#4241

**Full Changelog**: QwikDev/qwik@v1.2.7...v1.2.8

</details>

---

### Configuration

📅 **Schedule**: Branch creation - "after 9pm on sunday" (UTC), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://developer.mend.io/github/ascorbic/unpic-img).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNi42NC44IiwidXBkYXRlZEluVmVyIjoiMzYuNjQuOCIsInRhcmdldEJyYW5jaCI6Im1haW4ifQ==-->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
COMP: docs Improvements or additions to documentation TYPE: enhancement New feature or request WAITING FOR: team Waiting for one of the core team members to review and reply
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants