amplify-hosting icon indicating copy to clipboard operation
amplify-hosting copied to clipboard

Next.js Preview mode doesn't work on Amplify?

Open skrg-kotani opened this issue 3 years ago • 7 comments

Please describe which feature you have a question about?

Do I have to set the Next.js version to a specific value(version) to implement the Next.js preview mode?

I trying to implement the Next.js Preview mode. Next.js Preview mode is refer to: https://nextjs.org/docs/advanced-features/preview-mode

But Next.js Preview mode doesn't work on Amplify. ( I checked Preview mode is correct working on Vercel or local.) Next.js version of my app is 11.1.3. And Next.js version of Amplify (Build image settings) is 11. And webpack5.

Working point

  • I checked Next.js API Rpute is working because Cookie was set in the header.
  • I checkedgetStaticProps is working because logic in the getStaticProps was called when request came.

Not working point

  • context.preview is undefined in the getStaticProps

Related issues:https://github.com/aws-amplify/amplify-console/issues/2532

Provide additional details none

What AWS Services are you utilizing? Amplify Console, Amplify CLI

Provide additional details e.g. code snippets I'm trying with the code below, but the browser shows "none none".

preview page (pages/preview.js)

export default function Preview({ message, timestamp }) {
  return message + " " + timestamp;
}

export async function getStaticProps(context) {
  // If you request this page with the preview mode cookies set:
  //
  // - context.preview will be true
  // - context.previewData will be the same as
  //   the argument used for `setPreviewData`.
  return {
    props: {
      message: context.preview ? context.previewData.message : "none",
      timestamp: context.preview ? context.previewData.timestamp : "none",
    },
  };
}

preview api (api/preview.js)

// A simple example for testing it manually from your browser.
// If this is located at pages/api/preview.js, then
// open /api/preview from your browser.
export default function handler(req, res) {
  res.setPreviewData({
    message: "Hey, this is a preview",
    timestamp: new Date().toISOString(),
  });
  res.redirect("/preview");
}

skrg-kotani avatar Jan 31 '22 07:01 skrg-kotani

Hi! I understand the cause. The cause seemed to be cookies(of preview mode) were not allowed in the origin request on CloudFront by default. CloudFront_Settings

So I have a question.

  • How should I set CloudFront to control cookies (add / delete cookies) from Next.js API Route? I think I probably have to disable the cookies(of preview mode) cache and send it to the origin.
  • Is there any reason why Amplify set CloudFront to "Legacy cache settings" than "Cache policy and origin request policy (recommended)" by default?

please give me some advice or new information!

skrg-kotani avatar Feb 01 '22 08:02 skrg-kotani

Did you manage to find a solution to this @skrg-kotani ? I tried going with Cache policy and origin request policy (recommended) option, and then selecting Amplify option for Cache Policy for all paths except _next/static/* and static/*, which seemed to fix the problem.

But unfortunately the settings seem to re-set on every new build. I'm on Next.js 11.1.2.

biiishal avatar Feb 22 '22 07:02 biiishal

I have the same problem. I hope this issue will be solved.

swanmatch avatar Apr 22 '22 04:04 swanmatch

I have the same problem. Any recommendation or workaround?

ecasanova avatar May 20 '22 23:05 ecasanova

スクリーンショット 2022-05-30 0 33 30

@biiishal

Thanks for your advice! For me, By adding just two cookies to all paths except _next/static/* and static/*, which seemed to fix the problem.

itsuki-n22 avatar May 29 '22 15:05 itsuki-n22

Automated workaround.... use SNS on build success to trigger a lambda that updates the distribution behaviors so the preview cookies work.

  1. Create SNS notification for builds

Easiest way to do this is add email notifications through the Amplify console and snag the ARN for the SNS topic that triggers those emails.

  1. Create a lambda function that updates the cloudfront distribution after the build

I added this lambda to an existing serverless framework project but you can create an ad-hoc lambda function, too. If you go the ad-hoc route then add a Layer that has @aws-sdk/client-cloudfront installed and use that in the function.

IAM

{
        Effect: "Allow",
        Action: ["cloudfront:GetDistribution", "cloudfront:UpdateDistribution"],
        Resource: ["<ARN FOR YOUR DISTRIBUTION>"],
      }

serverless.ts function definition

wwwBuildEvent: {
      handler: "src/sns-events/www-build-events/handler.handler",
      events: [
        {
          sns: "<ARN FOR SNS TOPIC>",
        },
      ],
    },

Handler

import {
  CloudFrontClient,
  UpdateDistributionCommand,
  GetDistributionCommand,
  GetDistributionCommandInput,
  UpdateDistributionCommandInput,
  CacheBehavior,
} from "@aws-sdk/client-cloudfront";

const updateDistributionForNextPreview = async (distributionId: string) => {
  const client = new CloudFrontClient({});
  const input: GetDistributionCommandInput = {
    Id: distributionId,
  };
  const getDistCmdStr = new GetDistributionCommand(input);
  const getDistResp = await client.send(getDistCmdStr);
  // https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-managed-cache-policies.html
  const amplifyCachePolicyId = "2e54312d-136d-493c-8eb9-b001f22f67d2";
  const updateInput: UpdateDistributionCommandInput = {
    DistributionConfig: {
      ...getDistResp.Distribution.DistributionConfig,
      DefaultCacheBehavior: {
        ...getDistResp.Distribution.DistributionConfig.DefaultCacheBehavior,
        MinTTL: undefined,
        ForwardedValues: undefined,
        MaxTTL: undefined,
        DefaultTTL: undefined,
        CachePolicyId: amplifyCachePolicyId,
      },
      CacheBehaviors: {
        Quantity:
          getDistResp.Distribution.DistributionConfig.CacheBehaviors.Quantity,
        Items:
          getDistResp.Distribution.DistributionConfig.CacheBehaviors.Items.map(
            (cacheBehavior): CacheBehavior => {
              if (
                cacheBehavior.PathPattern === "_next/static/*" ||
                cacheBehavior.PathPattern === "static/*"
              ) {
                return cacheBehavior;
              }
              return {
                ...cacheBehavior,
                MinTTL: undefined,
                ForwardedValues: undefined,
                MaxTTL: undefined,
                DefaultTTL: undefined,
                CachePolicyId: amplifyCachePolicyId,
              };
            }
          ),
      },
    },
    Id: getDistResp.Distribution.Id,
    IfMatch: getDistResp.ETag!,
  };
  const updateDistCmdStr = new UpdateDistributionCommand(updateInput);
  const updateDistResp = await client.send(updateDistCmdStr);
  return updateDistResp;
};

exports.handler = async (event, context) => {
  const sns = event.Records[0].Sns.Message;
  if (!sns.includes("build status is SUCCEED")) {
    return sns;
  }
  // update cloudfront distribution so that next preview works
  const distributionId = "<YOUR DISTRIBUTION ID>";
  await updateDistributionForNextPreview(distributionId);

  return sns;
};

We also had issues with the environment variables not working. We tried checking process.env.IS_PREVIEW but the amplify env variable overrides do not work yet with Next.

After following the steps in this issue https://github.com/aws-amplify/amplify-hosting/issues/1987 to expose the variables and remove our dependency on the overrides by checking AWS_BRANCH instead AND the above automation our previews are working great.

HarrisonJackson avatar Jun 05 '22 04:06 HarrisonJackson

Just in case anyone else arrives on this issue the same way we did, and saves them an hour.

If you're finding the previews aren't working in Chrome (Incognito), it's because Incognito blocks 3rd party cookies by default. If you head into Preferences and Allow All Cookies (!) then it works.

Funnily enough MS Edge does not have the same behaviour and allows the cookie.

mxkxf avatar Sep 21 '22 13:09 mxkxf

My NextJS 13 SSR app is setting cookies on my local machine properly but the response headers are not returning with set cookie for __next_preview_data when i deploy on amplify. does anyone have any idea why this is happening?

Amplify SSR

image

Local System

image

ashish7adlakha avatar Nov 24 '22 08:11 ashish7adlakha

Hi all. I have successfully tested Next.js Preview Mode today with the contentful example so this issue can be closed.

Note the build config I used to ensure the server-side runtime has access to the environment variables.

version: 1
frontend:
  phases:
    preBuild:
      commands:
        - npm ci
    build:
      commands:
        - env | grep -e CONTENTFUL_SPACE_ID -e CONTENTFUL_ACCESS_TOKEN -e CONTENTFUL_PREVIEW_ACCESS_TOKEN -e CONTENTFUL_PREVIEW_SECRET -e CONTENTFUL_REVALIDATE_SECRET >> .env.production
        - npm run build
  artifacts:
    baseDirectory: .next
    files:
      - '**/*'
  cache:
    paths:
      - node_modules/**/*

michrome avatar Dec 15 '22 16:12 michrome

⚠️COMMENT VISIBILITY WARNING⚠️

Comments on closed issues are hard for our team to see. If you need more assistance, please either tag a team member or open a new issue that references this one. If you wish to keep having a conversation with other community members under this issue feel free to do so.

github-actions[bot] avatar Dec 15 '22 16:12 github-actions[bot]

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

github-actions[bot] avatar Dec 15 '22 17:12 github-actions[bot]