[MGNLFE-88] Support for Next.js Created: 16/Dec/20  Updated: 17/Dec/21  Resolved: 17/Dec/21

Status: Closed
Project: Magnolia Frontend Helpers
Component/s: None
Affects Version/s: None
Fix Version/s: 1.2.0

Type: Story Priority: Major
Reporter: Christopher Zimmermann Assignee: Bartosz Staryga
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: 1d
Original Estimate: Not Specified

Attachments: Zip Archive external-spa-pd-jars-6-2-13.zip    
Issue Links:
Relates
dependency
depends upon PAGES-238 Load SPA from external server Closed
depends upon PAGES-488 More versatile url property in templa... Closed
documentation
to be documented by MGNLFE-111 DOC: Use Next.js in your React SPA Closed
Template:
Acceptance criteria:
Empty
Task DoD:
[X]* Doc/release notes changes? Comment present?
[X]* Downstream builds green?
[X]* Solution information and context easily available?
[X]* Tests
[X]* FixVersion filled and not yet released
[X]  Architecture Decision Record (ADR)
Date of First Response:
Epic Link: External SPA
Sprint: HL & LD 37, HL & LD 38, HL & LD 39, HL & LD 40, HL & LD 41
Story Points: 3

 Description   

User story:

As a SPA developer, I can use Next.js in my React SPA, and there is clear documentation on how to do so.

Acceptance criteria:

  • Supports everything that is supported with our current React demos (including minimal and the one used in free trials).
  • The SPA in the page editor is running on an external Nextjs server.
  • The SPA can be deployed to production on a Nextjs server.
  • SSR is supported
  • SSG is supported

This is now demonstrated in the minimal demo project - See notes in readme for SSR and SSG.

https://git.magnolia-cms.com/projects/DEMOS/repos/minimal-headless-spa-demos/browse

(Also See basic sample project from bstarygahttps://github.com/bartoszstaryga/mgnl-spa-next-js)



 Comments   
Comment by Christopher Zimmermann [ 07/Aug/21 ]

bstaryga Could you help us out with this one?
I think a good first step would be getting the minimal demo running on Nextjs with this new production SPA External feature (even if the feature itself is still a little buggy). 
Or could make sense to start with the cloud-page-headless-demo for SaaS, but keep in mind that we do need a demo project that works without the SaaS first (like the minimal one)- since the SaaS comes later!
(cc: rsiska, apchelintcev)

Comment by Bartosz Staryga [ 23/Aug/21 ]

czimmermann
I have a basic setup for SSR and SSG here:
https://git.magnolia-cms.com/projects/DEMOS/repos/minimal-headless-spa-demos/browse?at=refs%2Fheads%2Fnextjs

Things that need to be still sorted for the renderer

  • no icons in green bars (I've heard you already work on it )
  • no auto created areas nodes (I've heard you already work on it )
  • iframe URL must contain pathname bit for child pages (canh.nguyen is already aware)

Once those 3 things are sorted SSR is good to go.

SSG is bit more complex.
Next.js uses the concept of preview API to bypass SSG.
For us to support it we will have to allow to change how we build the preview iframe URL.

For regular SSR we have
In YAML url: http://localhost:3000
For root page iframe preview src will be http://localhost:3000?mgnlPreview=false&mgnlChannel=desktop
For child-1 page iframe preview src will be http://localhost:3000/child-1?mgnlPreview=false&mgnlChannel=desktop

For SSG we will need (apchelintcev this will interest you)
In YAML url: http://localhost:3000/api/preview
For root page iframe preview src will be http://localhost:3000/api/preview?mgnlPreview=false&mgnlChannel=desktop&slug=/
For child-1 page iframe preview src will be http://localhost:3000/api/preview?mgnlPreview=false&mgnlChannel=desktop&slug=/child-1
So moving the page pathname from iframe src to query param slug.

Comment by Christopher Zimmermann [ 23/Aug/21 ]

Thank you! Cool.

[[[...pathname]].js|https://git.magnolia-cms.com/projects/DEMOS/repos/minimal-headless-spa-demos/commits/4da76f79a786a7b225cbc71306d828270dc05d8f#spa/nextjs-minimal/pages/%5B%5B...pathname%5D%5D.js] looks redundant with ssg_[[...pathname]].js - are those "lib" files just for reference, or were you moving in direction that [[...pathname]].js uses those libs? I didn't look too closely yet - maybe I miss somethjing.

Comment by Bartosz Staryga [ 23/Aug/21 ]

Both files are there for reference. Either ones content needs to be copy to pages/[[…pathname]].js depending on what approach you’d like to use. This file is the only difference between approaches so I did not wanna create new next project. The “what to do” will be explained in readme

Comment by Aleksandr Pchelintcev [ 24/Aug/21 ]

bstarygathanks a lot for this! Couple of questions:

  • about preview mode: so the secure token shenanigans can be skipped altogether (described as step one here). The context path management pushed to "slug" is indeed smth we need to account for. However, the complexity imo is in the fact that we need to support it for several similar systems, which may have different ways of facilitating this functionality (so some definition based approach would be desired I guess).
  • do you know from the top of your head about the mechanics of the getStaticPaths function - is it called only once per build? I see that in your demo implementation, it just basically walks the whole SPA sub-tree, does it have to be this way? As a side note here - the URL management is completely on the middle-ware side, so if we'd want to e.g. somehow have pages for our activities app/CT, we'd need to add an if path matches some /.../activities/ clause and a query to an endpoint different to the nav one, right?
Comment by Bartosz Staryga [ 24/Aug/21 ]

apchelintcev
Token
Yep it can be skipped It is purely in code of response handling inside next to check against it.

if (req.query.secret !== 'MY_SECRET_TOKEN' || !req.query.slug) {
    return res.status(401).json({ message: 'Invalid token' })
}

So it is definitely nice to have, but not a must

I agree that each SSG system might do previews differently. Gatsby does sth with spinning preview server (not many docs around it).

Some form or felixibitly of the iframe src building would be nice. It would then allow adding different things to that URL e.g. token

getStaticPaths
This function needs to return all paths that need to be built during generation.
It needs to look like:

[
{ params: { pathname: [] },
{ params: { pathname: ['contact'] },
{ params: { pathname: ['contact', 'contact-child'] }
...
]

How is that list achieved it's fully up to us.
I just reused the existing navigation endpoint to build such an array.
If I had e.g. list of posts on the stories app, I would create a new endpoint to get those paths too and combined both lists together.

Comment by Christopher Zimmermann [ 12/Oct/21 ]

bstaryga I updated the nextjs branch to point to new FEHelpers and added routeTemplate to templates, but did not see it working yet. https://git.magnolia-cms.com/projects/DEMOS/repos/minimal-headless-spa-demos/commits/e311e665f107922f16224860f4c93859c57d871b

Find a zip of the JARS you need attached to this ticket. 
Get a 6.2.13-snapshot webapp and replace jars as needed.

mgnl jumpstart -s -m 6.2.13

(I did DXCore with no demo... but It should work on CE in theory.)

Comment by Bartosz Staryga [ 13/Oct/21 ]

czimmermann & apchelintcev
I pushed updated state to branch:
https://git.magnolia-cms.com/projects/DEMOS/repos/minimal-headless-spa-demos/browse?at=refs%2Fheads%2Fnextjs

SSR
LM - nextjs-ssr-minimal-lm
SPA - nextjs-ssr-minimal
To run navigate to spa and run `npm run build && npm start`.
It will spin up Next.js with SSR.

SSG
LM - nextjs-ssg-minimal-lm
SPA - nextjs-ssg-minimal
To run navigate to spa and run `npm run build && npm start`.
It will spin up Next.js with API for preview iframe.
To build static sites run `npm run build && npm run export`.

A few more TO-DO's, but it's more wrapping up, for me:

  • add languages
  • add navigation
  • add readme
  • we should have some example of adding a webhook on publishing to trigger SSG
Comment by Bartosz Staryga [ 14/Oct/21 ]

Found a blocker: https://jira.magnolia-cms.com/browse/SPARE-3

Comment by Bartosz Staryga [ 26/Oct/21 ]

FYI czimmermann

  • add languages
  • add navigation
  • add readme

Scream when languages are available to be used/tested.

Comment by Bartosz Staryga [ 02/Nov/21 ]

mdrapela/czimmermann How can I test the latest version with language switcher? Could you guys provide me with the jars I need to use, please?
Once I have that I will finish and merge the examples in minimal examples repo and will let you know what things to look at in repos.

Comment by Bartosz Staryga [ 03/Nov/21 ]

rsiska/canh.nguyen question I have for lang switcher.
I can use:

routeTemplate: '/{{language}}/{{@path}}'
as well as:
routeTemplate: '/{language}/{{@path}}'

So for language, I can have 1 or 2 curly brackets, for @path not.
Why both works? Missing some consistency here

Comment by Aleksandr Pchelintcev [ 03/Nov/21 ]

bstaryga I suppose that's cause in case of path the slashes need to be escaped (the double brace semantics iiuc), am I right canh.nguyen?

Comment by Bartosz Staryga [ 03/Nov/21 ]

What do you say guys in example repo and in docs we would use double? To keep it consistent and not confuse people why do sometimes we have it one way or another?

Comment by Canh Nguyen [ 04/Nov/21 ]

The double braces will not encode the content. In case you need to use path as a parameter, or other parameters that have special characters like space, we need to escape the content.

For example, if you have a routeTemplate like:

'?title={{title}}' 

With title is "Hello World", the generated URL is like "http://foo.bar/?title=Hello World" so the URL is broken.

And if we configure routeTemplate: '?title={title}', the URL should be "http://foo.bar?title=Hello+World"

Comment by Bartosz Staryga [ 04/Nov/21 ]

canh.nguyen thanks for the clarification
mdrapela so if we had this clearly in docs what is one { for and what is two {{ for would be brilliant.
I will put this and the other info in the MGNLFE-111.

Anyway, I have added the language switching to demos and created PR.
czimmermann and canh.nguyen I guess this is for you:
https://git.magnolia-cms.com/projects/DEMOS/repos/minimal-headless-spa-demos/pull-requests/17/overview

I would appreciate a decent test on this.

Comment by Bartosz Staryga [ 04/Nov/21 ]

BTW What will be the pages app required to run this as this will not land in 6.2.13?
I'd like to put this as a note in README.md

Comment by Bartosz Staryga [ 04/Nov/21 ]

And another question can url and routeTemplate be set in site def (not as prototype)?

Comment by Christopher Zimmermann [ 17/Dec/21 ]

NextJS SSR and SSG have been demonstrated to work with Visual SPA Editor.

This is done in this demonstration project: https://git.magnolia-cms.com/projects/DEMOS/repos/minimal-headless-spa-demos/browse

See the new README sections for SSR and SSG.

Generated at Mon Feb 12 05:44:07 CET 2024 using Jira 9.4.2#940002-sha1:46d1a51de284217efdcb32434eab47a99af2938b.