Start using Next.XP in existing project

Enonic version: 7.14.3
OS: macos

Hi everyone,

so I tried the Enonic nextjs tutorial, and it works great! We now want to look at using nextjs in our existing project. How would we do this? It seems like once we add the Next.XP app all rendering is done with nextjs. Is that correct? Is it possible to use nextjs to render only certain pages? Our site is huge and it would be a huge undertaking to implement everything in nextjs at once, it would be easier to start only with some pages.

Hi @Markus !

Generally speaking we set it up that all requests are forwarded to the next.js on purpose, but there is a way to override that if you really know what you’re doing !

To do that, you’ll need to update this mapping to only forward needed paths to Next.XP, rebuild the app and make sure it is added to your site.

N.B. But that wasn’t tested and may produce unwanted side effects though :upside_down_face:

But you can always copy the site and work on migrating the copy, while still having old version for comparison if the above doesn’t work.

Is this something you need for development purposes? We are working on a new feature in CS that will allow you to toggle previews more easily, but until then Pavels suggestion is the way to go.

Thanks for the replies :slight_smile: Pavels suggestion seems to work!
First of all we want to experiment with this. So for development. If we decide to go the next way however it would be nice to be able to do the same in production. We then could gradually convert our site to nextjs.

Hi again, I have been playing around with @pmi solution, and it seems to work fine. Now we have another use case as well. Can only some components on the page be rendered with nextjs? For example could I render the header with the main menu the old way, and the content, for example an article, in nextjs?

Next.js is a whole different server/frontend compared to xp. Next.js has a ton of specific requirements in order to work. You can’t really mix things this way.

ok, thanks for the reply!

Hi again,

we have tested this for some time now. We have changed the mapping in site.xml (see below) to let Next.xp only render pages on certain paths. This works fine. There is one issue though. It seems that everytime a part is changed in ContentStudio it tries to render it with the Next.xp. We get the following error message in the ContentStudio preview: “Nextjs server did not return preview token: Forbidden”. See also screenshot attached. This is on a page with a URL that according to the mapping below should not be rendered with Next.XP. Actually this seems to happen on all pages. Do you have any tips?

our mapping:

<mappings>
    <mapping controller="/lib/nextxp/proxy.js" order="11">
      <pattern>/nextxp/.*</pattern>
    </mapping>
    <mapping controller="/lib/nextxp/proxy.js" order="11">
      <pattern>/_next/.*</pattern>
    </mapping>
    <mapping controller="/lib/nextxp/proxy.js" order="10">
      <service>component</service>
    </mapping>
  </mappings>

Hi @Markus,

Yes, that makes perfect sense, because the component controller takes care of single component reloads here:

<mapping controller="/lib/nextxp/proxy.js" order="10">
  <service>component</service>
</mapping>

You have 2 options here:

  1. Remove it to let XP render it at all times
  2. Use custom filter for component rendering and inside it use the function from lib/nextxp/proxy.js only for paths you want to be rendered by Next.XP:
<mapping filter="/your/custom/proxy-filter.js">
  <service>component</pattern>
</mapping>

Docs about mappings and filters

1 Like

Thanks for the quick reply @pmi . What I do not understand is how I should identify the paths the filter should use lib/nextxp/proxy.js. I have created a folder called nextxp. All in this folder should be rendered with nextxp. However in this case the requeset is only for one component and the path is somehting linke this:

/admin/site/edit/storebrand/draft/3363e423-b441-4fd6-b507-006f308fb618/_/component/main/8/first/0

I have logged the request and do not see any props on it that tell me it is on a nextxp page :thinking:

Markus, AFAIK there is no way to deal with this easily the way stuff works right now. I assume you only need this for your own development purposes? Did you consider just copying the dataset, so you could have one site running with xp rendering, and the other one using Next.js - at the same time?

Actually we where thinking of doing this not only for devleopment. We wanted to test the Next.xp way on a new feature/page we currently are working on. We want to release this to production. The rest of the site should still be rendered the old way. Based on the experience with this new feature in Next we want to evaluate and then decide if we should move more features/pages or do all of the site.

Is it somehow possible to set some header fields that we can check for in the filter? Either if we are on a next.xp page or not?

I guess you will have to make your own version of the component mapping filter then, as Pavel mentions. This is only used by Content Studio - so it won’t affect your live front-end at least. We didn’t really think about your use-case when we built the Next.js integration.

In upcoming releases - the editors will be able to choose which view to use, and Site engine and Next.js will be two different views… So I guess that may address it?

thanks for the reply @tsi I guess that would fix it. When will the new version be released?

About the custom filter I am a bit unsure on how to do it. Because the request is only for a component. And I am not sure how to figure out if the component is on a page that is to be rendered with Next.

You’re almost there @Markus !

My idea was that in your filter you have access to Request object, that have the path (not url) property, that you could compare to /nextxp.

But if it looks the way you said, then you probably need to extract content id from it and use:

const content = contentLib.get({
    key: '/path/to/content' or 'contentId'
});

You have next under /nextxp and /_next , so filter could just check for those paths and invoke next.xp’s /lib/nextxp/proxy.js , otherwise return return next(req); to move to the next in chain.

Thanks @pmi. Now we got it to work. For other readers this is what worked for us:

var nextXpProxy = require('/lib/nextxp/proxy.js');
var contentLib = require('/lib/xp/content');

exports.filter = function (req, next) {
    req.requestLogging = true;
    const matches = /\/draft\/(.{8}-.{4}-.{4}-.{4}-.{12})\/_\//gm.exec(req.path);
    if (matches.length < 2) {
        return next(req);
    }

    const contentId = matches[1];
    const content = contentLib.get({
        key: contentId
    });
    if (content && content._path.indexOf("nextxp") > -1) {
        return nextXpProxy.get(req, next);
    }

    return next(req);
};
4 Likes