microsoft-graph-toolkit
microsoft-graph-toolkit copied to clipboard
Enable Server Side Rendering
Enable components to be rendered on the backend while retaining functionality when running on the front end
I just tried enabling mgt-react with Next.js. They have the experimental flag for "esmExternals: true": https://github.com/vercel/next.js/discussions/35217
There are two points that currently prevent loading of mgt-react and its dependencies:
- Enabling esmExternals will emit "import(...)" instead of "require(...)" for modules that have "type: module" in ther package.json.
- In turn, node in esm mode requires all imports to end in ".js", ".cjs" or ".mjs".
When monkey-patching those manually in the installed files, then you can import more and more of mgt-react.
edit: I just tried using the "next-transpile-modules": const withTM = require("next-transpile-modules")(["@microsoft/mgt-react", "@microsoft/mgt-components", "wc-react"])
This makes the page load, but causes an unhandledRejection "window is not defined" during SSR. Now I see, why it isn't that straight-forward to fix.
This is quite interesting! Can you share the scenarios on why you are looking at SSR? I'm hearing from what you are saying that we would probably need a cjs module to support SSR today, right?
Technically, we don't require SSR for our application, because most pages depend on dynamic user content. However, Next.JS makes it easy for us to share types between database, backend and frontend.
We currently have two problems that prevent using this module without changes:
- node-style imports.
- lit-html and lit-element need access to the "window" object while executing during SSR (also mentioned in the earlier linked issues).
As for supporting the graph toolkit, one of the following is enough for resolving the imports:
- Transpile your npm packages to cjs.
- Transpile on the fly (e.g. using "next-transpile-modules"). This is also what all bundlers are currently doing.
- Add "type: module" to the npm package.json, and convert your node-style imports (without file extensions) to standard compliant esm-imports by appending ".js".
As for adapting lit-html. I haven't had a look at their source, yet. Intuitively, one should only access the "window" object in the hook callbacks of "useEffect" and "useLayoutEffect". If I recall correctly, Next.JS only executes those when the code is loaded by the browser. It should also be possible, to probe "window" and only run the initialization code when it is defined.
This is related to #2957
Maybe its enough (for the beginning) to make it possible to render the components still in the frontend, but remove errors that are generated when depending on "document" in the backend. Probably this is the same for all frameworks, ie Angular Universal or also Next.js
@web265p3 thanks for that feedback.
Unfortunately, that's not going to be trivially feasible in the immediate term due to our current dependency on @azure/msal-browser
in the @microsoft/mgt-msal2-provider
.
As to the other usages of document, there are number of theming/animation/placement usages that need to use document, and I'm not clear on how we should protect those code paths during SSR.
If you have any expertise or guidance you can share on those aspects of server side rendering of client side components I'd greatly appreciate it.