Closed pixelass closed 3 years ago
Hey @pixelass,
I never built a Contentful extension using next.js but I can explain the mechanics behind init
that might help you to solve the issue.
When importing contentful-ui-extensions-sdk
, the SDK waits for a connection from the Contentful web app. This connection is attempted by the web app as soon as the iframe finished loading. init
can be called later, but we also recommend calling it immediately while the page is loading.
I assume that your code fails because the second line is removed by the compiler as it is only a type import. Therefore, your extension only starts listening to the connection of the Contentful web app after dynamically importing the SDK using await import("contentful-ui-extensions-sdk")
. Depending on the timings, the web app already tried to connect at that point and failed. The web app does not retry to connect to an extension.
The callback passed as an argument to init
is only called when the web app was able to connect to your extension.
I hope this explanation helps you to solve your issue.
@andipaetzold thank you for that comment. It's basically what I thought might happen. we played around with several things but what's irritating is that we never see the issue once our extension is deployed and not called from localhost.
We cannot import contentful-ui-extensions-sdk
outside the React.useEffect
since the package references window
and is therefore not compatible with SSR without some kind of lazy loading.
Okay, this seems to be a general issue with SSR rendering and our SDK then.
What could work is importing the SDK via a script tag in your html head.
<script src="https://unpkg.com/contentful-ui-extensions-sdk@3"></script>
That way, no JavaScript is executed on the server but the SDK is still loaded immediately on page load. You can then access the init
function via window.contentfulExtension.init
. This is not a perfect solution as you will probably lose type safety or have to add some custom typings - but it should allow you to build a Contentful extension using SSR.
@andipaetzold That sounds like a valid workaround. Thank you I'll give it a try and report back.
We made these changes and they seem to work as expected:
While this could be fixed in this library (to support SSR out of the box) we'll consider it as fixed and close this issue. Feel free to comment if you need help setting this up.
import React from "react";
import Head from "next/head";
import "@contentful/forma-36-react-components/dist/styles.css";
import "../styles/index.css";
// @ts-ignore
const App = ({ Component, pageProps }) => {
return (
<>
<Head>
<title>Contentful Extensions</title>
<script src="https://unpkg.com/contentful-ui-extensions-sdk@3" />
</Head>
<Component {...pageProps} />
</>
);
};
export default App;
import React from "react";
import { FieldExtensionSDK } from "contentful-ui-extensions-sdk";
declare global {
interface Window {
contentfulExtension: any;
}
}
export const useContentfulSdk = () => {
const [contentfulSdk, setContentfulSdk] = React.useState<null | FieldExtensionSDK>(null);
React.useEffect(() => {
(async () => {
window.contentfulExtension.init((sdk: FieldExtensionSDK) => {
setContentfulSdk(sdk);
});
})();
}, []);
return contentfulSdk;
};
We use a react-hook to get access to the SDK in our contentful-extension.
Since our extensions are running in next.js, we use this mechanism to allow server side rendering. When deployed this works as expected but if we host this extension on localhost the chance of the callback being called seems to be 1:100. (see logs in the code-sample below)
We are using this extension in Contentful (not looking at the localhost itself as we are aware that it won't work outside app.contentful.com)
Here's a screenshot of what we see in contentful: (we show a loader until SDK has been loaded)
Here's the actual code that we use: