Preview isn't working in Production

I've set up preview for my nuxt front-end. The app runs in Universal Mode and is hosted on Digital Ocean. When I preview a document on my live site, the preview doesn't work and I see a 404 page.

On my local machine, the previews work with no issues. I can run npm run build && npm run start, and the preview is displayed as expected.

This is what my preview URLs look like.

I'm sending the request /api/preview. In Nuxt this is a serverMiddleware that parses the token and document ID and then generates the URL using my link resolver.

The file looks like this:

import Prismic from "@prismicio/client";
import express from "express";
import linkResolver from "../prismic/linkResolver";

const app = express();

app.use(express.json());
app.use(express.urlencoded({ extended: true }));

app.get("/preview", async (req, res) => {
  const api = await Prismic.client("http://caliray.cdn.prismic.io/api/v2");

  const { token, documentId } = req.query;

  const redirectUrl = await api
    .getPreviewResolver(token, documentId)
    .resolve(linkResolver, "/");

  res.redirect(redirectUrl);
});

module.exports = app;

I register this serverMiddleware in nuxt.config.js like so:

serverMiddleware: [{ path: "/api", handler: "~/api/index.js" }],

What I expect to happen is that I can preview unpublished documents or changes to published documents on my live production site.

What happens that when I hit the preview button, the browser goes to this URL:

That route doesn't exist in my nuxt router so i'm redirected to a 404 page.

Any reasons why the preview isn't working as expected? I've spent most of this week trying to get it working on production.

Thanks!

Hi Kristen,

Thanks for reaching out.

Well, in Nuxt.js, using the @nuxt/prismic module, almost everything is configured for you. You'll just need to configure previews in your repo.

So, In fact, you would not need to have this middleware as you are most probably is using an old Nuxt.js version.

To learn more about setting up previews using the @nuxt/prismic module, please follow this document.

Please let us know if you need any other help,
Fares

hey @Fares, Thanks for the reply.

I've made the change to use the @nuxt/prismic module. That has worked well. The preview is working as expected. There is just one small issue now.

When I make changes to a published document, and then try to preview it in Production, the Preview page does not show the latest changes. However, when I preview it on my local machine, the changes do appear.

Is there any trick to previewing changes to a published document?

Thanks!

1 Like

Hello @kristen

I am taking this over as Fares is out of the office.

We have already discussed the same issue in the following thread. It might be helpful for you:
https://community.prismic.io/t/nuxt-prismic-preview-not-working-on-production-server/7713/7

Let me know if it still doesn't solve your issue. I'd love to dig it more.

Thanks,
Priyanka

Hi @Priyanka, thanks for your reply.

I have seen this issue before, unfortunately I don't think it will help. This is not a Static Site, and I am not using the nuxt generate command before deploying. We're using Nuxt to handle our server side rendering.

Similarly, I don't have the modules that Phil recommends removing. @/modules/static, and @/modules/crawler, are not present in my nuxt.config.js. Likewise, I do not have the modern config included in my project object.

Can you also try to clear the cookies to see if it solves the issue? If it doesn't solve your issue I need the following:

  1. paste your package.json file
  2. paste nuxt.config.json file code
  3. Better if you can share your repo and source code with me (You can send me a private message though)

Thanks,
Priyanka

Thanks Priyanka, Clearing the cookies did not fix the issue. Attached below are the files requested. I will get you the source code shortly.

Our package.json:

{
  "name": "caliray",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "dev": "nuxt",
    "build": "nuxt build",
    "start": "nuxt start",
    "test": "jest",
    "generate": "NODE_ENV=development nuxt generate",
    "analyze": "nuxt build --analyze",
    "slicemachine": "start-slicemachine --port 9999",
    "build-fragment": "node ./fetchFragmentTypes.js"
  },
  "dependencies": {
    "@nuxtjs/apollo": "^4.0.1-rc.5",
    "@nuxtjs/axios": "^5.13.1",
    "@nuxtjs/google-gtag": "^1.0.4",
    "@nuxtjs/prismic": "^1.4.0",
    "@nuxtjs/redirect-module": "^0.3.1",
    "@nuxtjs/sitemap": "^2.4.0",
    "@prismicio/vue": "^2.1.0",
    "apollo-cache-inmemory": "^1.6.6",
    "apollo-link-http": "^1.5.17",
    "apollo-link-prismic": "^1.0.8",
    "cookie-parser": "^1.4.6",
    "core-js": "^3.20.0",
    "faunadb": "^4.4.1",
    "fibers": "^5.0.0",
    "graphql": "^15.8.0",
    "graphql-tag": "^2.12.6",
    "js-cookie": "^2.2.1",
    "klaviyo-subscribe": "^1.0.0",
    "lozad": "^1.16.0",
    "netlify-lambda": "^2.0.3",
    "nuxt": "^2.14.12",
    "nuxt-jsonld": "^1.5.3",
    "nuxt-sm": "0.0.6",
    "nuxt-svg-sprite-module": "^1.0.7",
    "nuxt-vuex-router-sync": "0.0.3",
    "prismic-javascript": "^3.0.2",
    "vue-country-region-select": "^2.0.14",
    "vue-debounce": "^2.6.0",
    "vue-disqus": "^4.0.1",
    "vue-gtag": "^1.16.1",
    "vue-instagram-embed": "^1.0.0",
    "vue-marquee-text-component": "^1.2.0",
    "vue-server-renderer": "^2.6.14",
    "vue-slicezone": "0.0.30",
    "vue-slick-carousel": "^1.0.6",
    "vue-slide-up-down": "^2.0.1",
    "vue2-smooth-scroll": "^1.5.0",
    "vuelidate": "^0.7.7"
  },
  "devDependencies": {
    "@babel/core": "^7.16.5",
    "@babel/plugin-syntax-dynamic-import": "^7.8.3",
    "@babel/preset-env": "^7.16.5",
    "@nuxtjs/google-analytics": "^2.4.0",
    "@nuxtjs/router": "^1.7.0",
    "@vue/test-utils": "^1.3.0",
    "babel-core": "^7.0.0-bridge.0",
    "babel-jest": "^26.6.3",
    "babel-loader": "^8.2.3",
    "jest": "^26.6.3",
    "mock-apollo-client": "^1.2.0",
    "node-sass": "^6.0.1",
    "regenerator-runtime": "^0.13.7",
    "sass": "^1.45.0",
    "sass-loader": "^10.2.0",
    "slice-machine-ui": "0.0.44",
    "vue-jest": "^3.0.7"
  },
  "jest": {
    "moduleFileExtensions": [
      "js",
      "json",
      "vue"
    ],
    "transform": {
      "^.+\\.js$": "babel-jest",
      ".*\\.(vue)$": "vue-jest"
    },
    "moduleNameMapper": {
      "@/(.*)": "<rootDir>/$1"
    }
  }
}

and our nuxt.config.js

import Prismic from "prismic-javascript";
import linkResolver from "./prismic/linkResolver";

export default {
  // Global page headers: https://go.nuxtjs.dev/config-head
  vue: {
    config: {
      productionTip: false,
      devtools: true
    }
  },

  head: {
    title: process.env.NUXT_ENV_SITE_NAME,
    htmlAttrs: {
      lang: "en"
    },
    meta: [
      {
        charset: "utf-8"
      },
      {
        name: "viewport",
        content: "width=device-width, initial-scale=1, maximum-scale=1"
      },
      {
        name: "p:domain_verify",
        content: "9ba28e885ea2e1ee41591ad98d6dbbc4"
      },
      {
        name: "facebook-domain-verification",
        content: "pio6phwusddehzaxzkcma46cfkp1js"
      }
    ],
    script: [
      {
        src:
          "https://polyfill.io/v3/polyfill.min.js?features=IntersectionObserver",
        body: true
      },
      {
        src: "https://www.instagram.com/embed.js",
        body: true,
        async: true
      }
      // {
      //   src: "//static.cdn.prismic.io/prismic.js?repo=caliray&new=true",
      //   async: true
      // }
    ]
  },

  publicRuntimeConfig: {
    siteName: process.env.NUXT_ENV_SITE_NAME,
    siteId: process.env.NUXT_ENV_SITE_ID,
    siteUrl: process.env.NUXT_ENV_SITE_URL,
    shopifyUrl: `${process.env.NUXT_ENV_SHOPIFY_REPO_ID}.myshopify.com`,
    disqusShortname: "caliraybeauty"
  },

  loaders: {
    vue: {
      prettify: false
    }
  },

  loading: {
    color: "#003B4A"
  },

  // Global CSS: https://go.nuxtjs.dev/config-css
  css: ["~/assets/scss/styles.scss", "~/assets/scss/non_sass_edits.css"],

  // Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
  plugins: [
    { src: "~/plugins/cms.plugin.js" },
    { src: "~/plugins/filters.js" },
    { src: "~/plugins/helpers.js" },
    { src: "~/plugins/vuelidate.js" },
    { src: "~/plugins/vue-debounce.js" },
    { src: "~/plugins/jsonld.js" },
    { src: "~/plugins/prismic-link.js", mode: "client" },
    { src: "~/plugins/vue2-smooth-scroll.js", mode: "client" },
    { src: "~/plugins/vue-country-region-select.js", mode: "client" },
    { src: "~/plugins/vue-marquee-text-component.js", mode: "client" },
    { src: "~/plugins/client-init.js", mode: "client" },
    { src: "~/plugins/klaviyo.js", mode: "client" },
    { src: "~/plugins/facebook.plugin.js", mode: "client" },
    { src: "~/plugins/faunadb.js", mode: "client" },
    { src: "~/plugins/google-analytics.js", mode: "client" }
  ],

  // Auto import components: https://go.nuxtjs.dev/config-components
  components: false,

  // Modules for dev and build (recommended): https://go.nuxtjs.dev/config-modules
  buildModules: ["@nuxtjs/router"],

  // Modules: https://go.nuxtjs.dev/config-modules
  modules: [
    "@nuxtjs/axios", // https://go.nuxtjs.dev/axios
    "@nuxtjs/apollo",
    [
      "nuxt-svg-sprite-module",
      {
        directory: "~/assets/img/svg/raw",
        templateLocation: "app.html"
      }
    ],
    "@nuxtjs/prismic",
    "@nuxtjs/redirect-module",
    "nuxt-vuex-router-sync",
    "nuxt-sm",
    "@nuxtjs/sitemap"
  ],

  // Axios module configuration: https://go.nuxtjs.dev/config-axios
  axios: {},

  apollo: {
    clientConfigs: {
      default: "@/plugins/apollo/prismic.js",
      shopify: "@/plugins/apollo/shopify.js"
    }
  },

  prismic: {
    endpoint: `https://${process.env.NUXT_ENV_PRISMIC_REPO_ID}.cdn.prismic.io/api/v2`,
    linkResolver: "~/prismic/linkResolver",
    htmlSerializer: "~/prismic/htmlSerializer",
    preview: "/preview"
  },

  // https://www.npmjs.com/package/@nuxtjs/redirect-module
  redirect: [
    { from: "^/account/login", to: "/login" },
    { from: "^/products/(.*)$", to: "/shop/product/$1" }
  ],

  sitemap: {
    hostname: process.env.NUXT_ENV_SITE_URL,
    routes: async () => {
      const api = await Prismic.getApi(
        `https://${process.env.NUXT_ENV_PRISMIC_REPO_ID}.cdn.prismic.io/api/v2`
      );
      const response = await api.query("", { pageSize: 10000 });
      return response.results.map(linkResolver);
    }
  },

  // Build Configuration: https://go.nuxtjs.dev/config-build
  build: {
    terser: false,
    devtools: true,
    parallel: true,
    transpile: ["vue-slicezone", "nuxt-sm"],
    extend(config, ctx) {
      if (process.env.NODE_ENV !== "production") {
        config.devtool = "#source-map";
      }

      if (
        config.optimization.splitChunks &&
        typeof config.optimization.splitChunks === "object"
      ) {
        config.optimization.splitChunks.maxSize = 500000;
      }
    }
  },

  server: {
    port: 3000, // default: 3000
    host: "0.0.0.0" // default: localhost
  }
};

EDIT:

One thing that jumps out at me in the nuxt.config.js, is the prismic toolbar is commented out in the head.meta.script array. My understanding was this was not needed if we use the Prismic Module's built-in preview system. Is that correct?

Hello @kristen

If you add the preview route as /preview, you need to only set up the preview environment inside your repository. You don't need to add it in the nuxt.config.js file. Can you remove it from this file and try again? Can you also update prismic vue to the latest version 2.1.2? Also, try to add in nuxt.config.js file in prismic object:
modern: process.env.NODE_ENV === 'production'

Thanks,
Priyanka

Hey @Priyanka, yes I believe this is working now. I removed preview: /preview from my prismic config, and added modern: process.env.NODE_ENV === 'production'. I also updated the prismic/vue package to 2.1.2.

Thanks so much for your help in figuring this out. I really appreciate it.

I am glad to help you, @kristen. Feel free to reach out to us if you have any questions.