Client routing for internal `content` links

OPENING POST


Description

Right now an internal link found in content.rendered triggers a new SSR. It should be captured in Frontity and switched to a client route.

User Stories

As a Frontity developer
I want to use Frontityā€™s router for all the internal links found in content.rendered
so that when readers click, the route change is done in the client

Possible solution

We have to add a processor for this.


SUMMARY


:warning: Please, bear in mind that this section wasnā€™t part of the opening post. It has been added afterwards and its purpose is to keep a quick summary with the most relevant information about this FD at the top of the thread.

Relevant links

Also, as noted by @mmczaplinski, we should check for absolute links and change them to relative links.

For example, in a site www.mydomain.com with a WordPress URL wp.mydomain.com we need to do this change:

<a href="https://wp.mydomain.com/some-post">

<a href="/some-post">

@luisherranz now that we have a <Link /> we could simply add a processor to replace all anchor tags with our <Link /> component. It already checks for external links. We would only need to add a check for internal absolute links and convert to relative links.

Absolutely. Great idea.

The only thing missing here is that the WordPress bakend URL is only on state.source.api now, and it may (or may not) contain a prefix, usually /wp-json.

We have seen lately that many packages need to know the ā€œWordPress URLā€, not only for the wp-source package.

Iā€™m not 100% sure yet how that should be handled. One idea is to move it to state.frontity, similar to url:

export default {
  state: {
    frontity: {
      url: "https://mars.frontity.org",
      title: "Test Frontity Blog",
      description: "Useful content for Frontity development",
      backend: "https://test.frontity.org",
    },
  },
  packages: [
    {
      name: "@frontity/wp-source",
      state: {
        source: {
          prefix: "/wp-json", // This will be the default.
          prefix: false, // This could be use to use `?rest_route=`.
          isWpCom: true, // To support the WP.com API.
        },
      },
    },
  ],
};

For example the @frontity/head-tags plugin is extracting the backend URL from state.source.api using this function: https://github.com/frontity/frontity/blob/dev/packages/head-tags/src/utils/index.ts#L29-L38

Iā€™ll open a new FD to discuss this.

This is the new FD: Make the backend URL a global setting

Letā€™s move the conversation there :slightly_smiling_face:

Iā€™ve started working on this here: https://github.com/frontity/frontity/pull/520

@luisherranz Do you think itā€™s worth relying on state.source.api for now and change it later?

Iā€™m not sure weā€™re at a point where Make the backend URL a global setting can be implemented.

Hey, sorry for the delay in my answer @nicholasio.oliveira (Iā€™m on holiday although I try to stay up to date).

To be honest, Iā€™d prefer to try to do it now, becauseā€¦ well, the sooner the better for this type of change. If we keep delaying it itā€™s going to be more difficult.

And I think we can make it 100% backward compatible using derived state: Make the backend URL a global setting

I just finished my PR for this: https://github.com/frontity/frontity/pull/520 the new source url made things much easier!

2 Likes

Released in @frontity/components@1.6.0 and @frontity/html2react@1.5.0:

Thanks @nicholasio.oliveira!! :tada::smile:

1 Like

We have encountered an issue in our web, frontity.org with the link processor (I think). We have two different sites in the same project. In the frontity.settings.js file, we defined that, for all the urls that starts with /blog we are using the twentytwenty-theme, and for the others we are using our custom theme frontity-org-theme.

The problem is that both of them use the same frontity.url. In some blog posts, we are linking to pages in the frontity-org-theme, like the About Us page for example. I assume that, as it matches frontity.url, it does CSR. And it renders the About Us page in CSR with the twentytwenty-theme, which isnā€™t correct. It should SSR the page with frontity-org-theme, as it is a url not covered by the match property of the blog.

We have found a workaround, and adding target="_blank" to the link itā€™s okay, as it is loading a new tab. But I feel it should work without that property.

Is there something we should change in the frontity.settings.js file or is this a bug? Would it be possible to check if the link matches the match and, if not, do SSR?

This feels like a bug to me and agree the easiest way is checking if the link matches the match property. I wonder though if itā€™s possible to do CSR between different sites/themes.

This should fix it: https://github.com/frontity/frontity/pull/625

Didnā€™t test with multiple sites but added tests that covers the edge case here. @SantosGuillamot Can you check if this fixes the issue for you?

Great :slightly_smiling_face: Thanks for the quick PR!

I have tried to test it in the frontity.org repo but I wasnā€™t able to make it work. Not sure if thereā€™s something I am missing. I have left my feedback in the Pull Request. We can keep the conversation there.

I see, I was assuming the match property was being exposed through the useConnect

Iā€™ll take a look at getSettings and see if thereā€™s a way to access the match property from a component.

There is an issue using the match property. In most cases, there will be a default site where you donā€™t have to use the match, so we couldnā€™t rely on the match property in all the cases. @mmczaplinski, any ideas about which could be the best approach here?

I think that the approach outlined by @nicholasio.oliveira is in the PR is correct. We can expose the match property in the state.frontity. I donā€™t really see another way to solve this at the moment.

I think that it the in case when there is no match property (e.g. on a ā€œdefaultā€ site with no match attribute in the settings) we can check the link against state.source.url. That is:

if (link.startsWith(state.source.url)) {
  // The link could also start with http:// or https:// so should account for that.
  return link;
}

(this is not tested) :slight_smile:

From an SEO perspective, I believe using absolute is the easiest to maintain.

There are arguments for both, and John Mueller (Google Search Guru at Google) says both works ā€œif done correctly.ā€

However, if you donā€™t have the time or resources to focus on SEO, itā€™s easier to just make it all absolute for a set-it-and-leave-it point of view. That way you donā€™t need to worry about SEO and duplicate content etc.

Would it make sense to write a processor to look for your current URL (localhost or real domain etc.) and string replace the href but also truncate it become a relative link so it can be handled internally?

Possibly having two settings to choose between absolute or relative will be interesting.

Sources:

1 Like

Sure. It should be easy to do a processor for that. Something like this:

const relativeToAbsoluteLinks = {
  test: ({ node }) =>
    node.component === "a" &&
    node.props?.href.startsWith("/")
  processor: ({ state, node }) => {
    // Add `state.frontity.url` in front of all relative links.
    node.props.href = state.frontity.url + node.props.href
    return node;
  },
};
1 Like