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

Support for Static Site Generators #194

Closed
cgrail opened this issue Oct 18, 2019 · 15 comments
Closed

Support for Static Site Generators #194

cgrail opened this issue Oct 18, 2019 · 15 comments
Labels
contribution welcome Open for contributions feature-request New feature or request

Comments

@cgrail
Copy link
Member

cgrail commented Oct 18, 2019

I really like UI5 WebComponents for React. I wanted to use it in combination with a static site generator like Next.js or Gatsby.js, but it didn't work. I don't think Server Side Rendering is supported currently. Would be great if you could support that to improve the speed of the initial page loading.

@MarcusNotheis
Copy link
Contributor

Hi @cgrail

thanks for your issue.
As far as I know, there are a couple of issues when trying to SSR HTML Custom Elements.
Maybe @petermuessig has any idea on how to solve this? I think I remember we that we talked about that some time ago...

@MarcusNotheis MarcusNotheis added contribution welcome Open for contributions feature-request New feature or request labels Oct 25, 2019
@petermuessig
Copy link

Hi @cgrail
as of today, the Web Components do not support SSR. We made some experiments to use the renderers at server-side to render an initial content for the Web Components and on client-side doing some progressive enhancement but it is not more than a POC so far. But I am wondering a bit, why the Web Components don't work with Next.js or Gatsby.js - they could just simply render the custom HTML tag and then the Web Component renders at client-side. But I have to admit that I am not in the details of Next.js or Gatsby.js to judge on this.
Cheers,
Peter

@ericsolberg
Copy link

Just as an FYI - I've heard that Stencil.js is a good tool for compiling design systems into standard web component libraries that support, among other things, SSR. https://stenciljs.com/

@ThomasSwolfs
Copy link

ThomasSwolfs commented Aug 19, 2020

Hi @petermuessig ,

When using the react web components in NextJS the way it is described in the documentation, I get the following error:

import { ThemeProvider } from '@ui5/webcomponents-react/lib/ThemeProvider';
image

I didn't get into the technical details yet, but there is something going wrong on the SSR side.
Though, you can bypass this by using dynamic imports by NextJS:

const ThemeProvider = dynamic(() => import('@ui5/webcomponents-react/lib/ThemeProvider').then((mod) => mod.ThemeProvider), { ssr: false }) const Button = dynamic(() => import('@ui5/webcomponents-react/lib/Button').then((mod) => mod.Button), { ssr: false } )
image

https://nextjs.org/docs/advanced-features/dynamic-import

This way I managed to use the components with NextJS.

I think it wouldn't be a bad idea to consider diving into this issue since NextJS is a popular goto framework to develop React applications.

Kr,
Thomas

@petermuessig
Copy link

HI @ThomasSwolfs ,

thanks for the feedback. I need to understand how this module is used in Next.js. It seems to be a more general issue which means that you are trying to use an ES6 module import outside an ES6 module. Where did you use this? In a naked Next.js boilerplate code? How is the module loaded which imports the Theme Provider? From what I see here is that the ThemeProvider is required (CommonJS) but an ES6 module cannot be required. Maybe I also misunderstand the issue here - then please forgive me... 😄

The dynamic import is doing the trick that ES6 modules can be imported in the non-ES6 module code, right?

Maybe also @MarcusNotheis can take a look into this.

Best regards,
Peter

@ThomasSwolfs
Copy link

Hi @petermuessig ,

I think that you are right about the ES6 modules. I'm using a naked Next.js boilerplate indeed.

I found a package https://www.npmjs.com/package/next-transpile-modules which tackles this issue and transpiles modules using ES6 modules.
I gave this a quick try and (I think) I managed to get through the import statements errors.

Now the next error is a quite logical one. Document is only available in a browser. So when Next.js tries to access the web components library, on the server side the code will crash.

ReferenceError: document is not defined
image

@MarcusNotheis
Copy link
Contributor

Hey @ThomasSwolfs,
yes, you are absolutely right. I'll look into that and we try to get rid of all those document/window access which would crash on server side. We'll keep you updated on that topic.

@ThomasSwolfs
Copy link

Hi Marcus, that's good news!
Just for my own understandings; would you recommend using the next-transpile-modules package I mentioned above? Or would you suggest to find another way?

@MarcusNotheis
Copy link
Contributor

Hey Thomas,
I'm not an expert for Next.js (just took the getting started path again 😄), but in my opinion this package looks promising.
As of now, I have identified a couple of areas where we need to invest so I'm just posting our TODO list here:

  • lazy loading of Web Components when doing SSR
    we can't just import '@ui5/webcomponents/dist/Button'; but have to move that import into an effect (like useEffect(() => {import('@ui5/webcomponents/dist/Button');}, []);
    TODO: This would have an negative impact on performance for the classical approach without SSR
  • base package optimizations:
    e.g. the Device is heavily relying on window and document - can we lazy-load it when doing SSR?

@ThomasSwolfs
Copy link

Hey Marcus,

Is lazy loading the right way to go here? In my understanding, that's what next/dynamic is doing.
In my first response above I have an example where I used the ui5 components with the dynamic package.

Wouldn't this just be the same kind of workaround?

image

I'm just spilling some uncertain thoughts here, so please correct me if I'm wrong. :-)

@MarcusNotheis
Copy link
Contributor

I'm not sure to be honest. I think the approach you shared is the best way to do it in a next.js environment. On the other hand, we have the issue in UI5 Web Components React that we don't want to limit ourselves to Next.js. Let me try go a bit more into detail by digging into the Button Component. This is the current source of the button:

import { ButtonDesign } from '@ui5/webcomponents-react/lib/ButtonDesign';
import { withWebComponent } from '@ui5/webcomponents-react/lib/withWebComponent';
import '@ui5/webcomponents/dist/Button';

/**
 * <a href="https://sap.github.io/ui5-webcomponents/playground/components/Button" target="_blank">UI5 Web Components Playground</a>
 */
var Button = withWebComponent('ui5-button', ['design', 'icon'], ['disabled', 'iconEnd', 'submits'], [], ['click']);
Button.displayName = 'Button';
Button.defaultProps = {
  design: ButtonDesign.Default,
  disabled: false,
  iconEnd: false,
  submits: false
};

export { Button };
//# sourceMappingURL=Button.js.map

Currently, line 3 (import '@ui5/webcomponents/dist/Button';) is crashing Next.js because it is extending HTMLElement. So, when running only in Next.js, replacing this line with your proposal would work perfectly fine - but this would limit us to only use next.js. So I think the most generic solution would be lazy-loading everything from @ui5/webcomponents/dist/XYZ by using React.useEffect. Does this sound reasonable?

@ThomasSwolfs
Copy link

Good point, I understand what you are saying. It will be a more generic solution indeed.
I'm just thinking that this would mean that the webcomponents are not really being generated on the server-side?

I did a little research and found this repository:
https://github.com/skatejs/skatejs
Here they are using a kind of minimalistic DOM so that the components can be rendered truly on the server-side:
https://medium.com/@treshugart/%C3%A5server-side-rendering-web-components-e5df705f3f48

Maybe this option is overkill? I'm not really sure about the differences between both options in terms of performance etc..

@MarcusNotheis
Copy link
Contributor

Hey @ThomasSwolfs,

I played around with SSR and Next.js and was able to achieve first results. We are now e.g. able to render a Button with Next.js which will then be hydrated on the client. Unfortunately, there are still many other open topics which are accessing "client only" objects like window or document - also in the underlying UI5 Web Components library. I've open another issue in SAP/ui5-webcomponents#2240 to investigate further.

Best regards,
Marcus

@MarcusNotheis
Copy link
Contributor

Hey all,

I was finally able to build a working Next.js app with the help of a custom babel plugin: https://github.com/MarcusNotheis/babel-plugin-ui5-webcomponents-react-nextjs

Although you can build and run a Next.js app with that plugin, this doesn't really support Server Side Rendering because it will just transform all imports from webcomponents react into dynamic, client only imports.

Having said that, I'll close this issue for now as I don't see any chance to get real SSR with Web Components - but we might come back to it later as soon as there is a general concept for rendering web components on server side available.

Best regards,
Marcus

@cgrail
Copy link
Member Author

cgrail commented Jun 1, 2021

Thanks a lot for trying.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
contribution welcome Open for contributions feature-request New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants