Monday, June 12, 2023

Experience Edge and using template reference in targetItem.

 I recently ran into an issue with Experience Edge where I had a datasource item droptree field pointing to a template field. I was using graphQL to retrieve the targetItem and then it's id.


fragment taxonomyTermFields on Item {
  ... on TaxonomyTerm {
    description {
      value
      jsonValue
    }
    termName {
      value
      jsonValue
    }
  }
}

query ProductCategoryList($datasource: String!, $language: String!) {
  # Datasource query
  # $datasource will always be set to the ID of the rendering's datasource item
  # (as long as the GraphQLData helper is used)
  datasource: item(path: $datasource, language: $language) {
    id
    name
    ... on ProductCategoryListing {
      templateFilter {
        targetItem {
          id
        }
      }
      root {
        targetItem {
          id
        }
      }
      filters {
        targetItem {
          name
          displayName
          children {
            results {
              id
              ...taxonomyTermFields
            }
          }
          ... on TaxonomyFolder {
            title {
              value
              jsonValue
            }
          }
        }
      }
      linkSectionTitle {
        value
        jsonValue
      }
      links {
        value
        jsonValue
      }
    }
  }

It turns out that this graphQL will always return null for targetFilter.targetItem.id because none of the templates are being published to Experience Edge (except for the template folders). To make it work with Experience Edge graphQL had to be changed as follows:


fragment taxonomyTermFields on Item {
  ... on TaxonomyTerm {
    description {
      value
      jsonValue
    }
    termName {
      value
      jsonValue
    }
  }
}

query ProductCategoryList($datasource: String!, $language: String!) {
  # Datasource query
  # $datasource will always be set to the ID of the rendering's datasource item
  # (as long as the GraphQLData helper is used)
  datasource: item(path: $datasource, language: $language) {
    id
    name
    ... on ProductCategoryListing {
      templateFilter {
        value
      }
      root {
        value
      }
      filters {
        targetItem {
          name
          displayName
          children {
            results {
              id
              ...taxonomyTermFields
            }
          }
          ... on TaxonomyFolder {
            title {
              value
              jsonValue
            }
          }
        }
      }
      linkSectionTitle {
        value
        jsonValue
      }
      links {
        value
        jsonValue
      }
    }
  }

Tuesday, September 20, 2022

Deploying of Sitecore JSS (Next.js) application to Vercel from on-prem Gitlab

 I just went through implementing of on-prem Gitlab CI/CD pipeline for deploying of a Next.js Sitecore JSS application to Vercel. At first everything looked straight forward, but there a few hiccups down the road sharing of which I thought would be beneficial to others.

Building and deploying of Next.js Sitecore JSS application

Vercel team referred us to the following documentation to help use configure on-prem Gitlab CI/CD pipeline to deploy the application to Vercel:

I followed the instructions and configured the CI/CD pipeline script to run the following commands:

- npm install --global vercel 
- vercel pull --yes --environment=preview --token=$VERCEL_TOKEN 
- vercel build --token=$VERCEL_TOKEN 
- vercel deploy --prebuilt --token=$VERCEL_TOKEN

I also added five environment variables to the Vercel project:
Vercel environment variables

When I ran the pipeline and Vercel CLI commands finished executing, I saw the following output in the deployment screen capture. The cause of this broken output was the broken references to JS and CSS files. The host name in these references are pointing to a local instance. If I added PUBLIC_URL to the environment variables for all environments, then the references would be correct and the application would load properly. However, if different environments are expected to have different PUBLIC_URL this solution wouldn't work.



After digging a little deeper into Sitecore JSS code and debugging the deployment script that Vercel CLI produced I realized that VERCEL_URL is always empty when you run the build "locally" (not in Vercel deployment). Going through documentation didn't help much.

By pure accident I ran a command to switch scopes:

vercel --scope $VERCEL_SCOPE ${VERCEL_PARAMS} --token=${VERCEL_TOKEN} 

And all of a sudden I see a traditional build starting in Vercel. It goes through the usual build, checks and deployment and I see JS and CSS references getting proper hostname in references.

I filed a support ticket with Vercel asking to explain the behavior and advise on the way forward. After three weeks of back and forth they finally explained why changing of scope triggered a build. 

Apparently any run of vercel command triggers a build and deployment, and if you run this CLI command from your local "rendering" application, it will trigger a build using your local application. 

The bottom line is that for Sitecore JSS applications and for any applications that expect using VERCEL_URL during build you can't use pull/build/deploy. You have to use vercel command. A

Deployment URL


If you need to get a value of your Vercel deployment each time you run CLI build and deployment command, you need to use the following format:

    - DEPLOYMENT_URL=$(vercel --scope $VERCEL_SCOPE ${VERCEL_PARAMS} --token=${VERCEL_TOKEN} --prod)
    - echo $DEPLOYMENT_URL

However, if you are trying to assign an alias to a preview or development deployment don't expect it to work. Alias assignment only works for production deployments.

Final Script

After all troubles I ended up creating a separate Vercel project for each environment. Each branch from our on-prem Gitlab was configured to deploy to a separate Vercel project into production environment. We can still deploy to preview from branches, but the main environment branch was configured to always deploy to production. That allowed us to have specific domain names for each environment branch. If we were using cloud version of Gitlab, we probably wouldn't have to do that, but since we are working with on-prem version, there was no other choice.

So the final Vercel portion of the script looks like this:

    - npm install --global vercel
    - DEPLOYMENT_URL=$(VERCEL_ORG_ID=$VERCEL_ORG_ID VERCEL_PROJECT_ID=$VERCEL_DEV_PROJECT_ID vercel --scope $VERCEL_SCOPE ${VERCEL_PARAMS} --token=${VERCEL_TOKEN} --prod)
    - echo $DEPLOYMENT_URL
 

Other considerations

If you are working with on-prem source control and have to use Vercel CLI, make sure that you are running the build on linux/amd64 machine. The system must match Vercel platform Build Image (https://vercel.com/docs/build-output-api/v3#introduction/known-limitations)