Coder Social home page Coder Social logo

prismicio / prismic-next Goto Github PK

View Code? Open in Web Editor NEW
53.0 12.0 7.0 2.8 MB

Helpers to integrate Prismic into Next.js apps

Home Page: https://prismic.io/docs/technologies/nextjs

License: Apache License 2.0

JavaScript 1.68% TypeScript 98.32%
javascript typescript prismic react nextjs

prismic-next's Introduction

@prismicio/next

npm version npm downloads Github Actions CI Codecov Conventional Commits License

Helpers to integrate Prismic into Next.js apps.

  • 👁️  Easily set up Prismic Preview
  • 🖼️  Render optimized images using next/image and Prismic's built-in Imgix integration

Install

npm install @prismicio/next

Documentation

To discover what's new on this package check out the changelog. For full documentation, visit the official Prismic documentation.

Contributing

Whether you're helping us fix bugs, improve the docs, or spread the word, we'd love to have you as part of the Prismic developer community!

Asking a question: Open a new topic on our community forum explaining what you want to achieve / your question. Our support team will get back to you shortly.

Reporting a bug: Open an issue explaining your application's setup and the bug you're encountering.

Suggesting an improvement: Open an issue explaining your improvement or feature so we can discuss and learn more.

Submitting code changes: For small fixes, feel free to open a pull request with a description of your changes. For large changes, please first open an issue so we can discuss if and how the changes should be implemented.

For more clarity on this project and its structure you can also check out the detailed CONTRIBUTING.md document.

License

   Copyright 2013-2021 Prismic <[email protected]> (https://prismic.io)

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

prismic-next's People

Contributors

angeloashmore avatar bastienrobert avatar dayhaysoos avatar lihbr avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

prismic-next's Issues

Unicode characters not encoded in preview redirection URL

Versions

  • @prismicio/next: 0.1.9
  • next: 12.3.4
  • node: 16.18.1

Reproduction

  1. Setup a document type page, with an uid field and the following route resolver:
  {
    type: 'page',
    path: '/:uid',
  }
  1. Preview a page document with an uid containing unicode characters, like тест.

What is expected?

The тест page document is previewed.

What is actually happening?

An error page is displayed, and Next.js logs the following error:

TypeError [ERR_INVALID_CHAR]: Invalid character in header content ["Location"]
    at ServerResponse.setHeader (node:_http_outgoing:647:3)
    at ServerResponse._res.setHeader ([REDACTED]/node_modules/next/dist/server/base-server.js:127:24)
    at setHeadersFromObject ([REDACTED]/node_modules/next/dist/compiled/compression/index.js:46:680)
    at ServerResponse.setWriteHeadHeaders ([REDACTED]/node_modules/next/dist/compiled/compression/index.js:46:914)
    at ServerResponse.writeHead ([REDACTED]/node_modules/next/dist/compiled/compression/index.js:46:121)
    at Object.redirect ([REDACTED]/node_modules/next/dist/server/api-utils/index.js:35:9)
    at ServerResponse.apiRes.redirect ([REDACTED]/node_modules/next/dist/server/api-utils/node.js:351:59)
    at redirectToPreviewURL (webpack-internal:///(api)/../node_modules/@prismicio/next/dist/redirectToPreviewURL.js:18:16)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async preview (webpack-internal:///(api)/./src/pages/api/preview.ts:30:9) {
  code: 'ERR_INVALID_CHAR',
  page: '/api/preview'
}

After some research the error is located within redirectToPreviewURL, with the underlying res.redirect call. This function tries to send a response with the Location header set with the redirection URL, but it seems that Node doesn't allow raw unicode characters in HTTP headers.

Forcing each path segment in the to be URL encoded solves the issue, this is my workaround:

    const originalRedirect = res.redirect;
    await redirectToPreviewURL({
      req,
      res: {
        ...res,
        redirect: ((url: string) => {
          const encodedUrl = url.split('/').map(encodeURIComponent).join('/');
          return originalRedirect(encodedUrl);
        }) as NextApiResponse['redirect'],
      },
      client,
      basePath,
    });

Module not found: Can't resolve 'next/headers' - PrismicPreview

I have followed the official docs for installation and loading data, and in both scenarios I get a NextJS error saying Module not found: Can't resolve 'next/headers'. I have read through the docs in detail and have made sure all imports are coming from the correct files according to the docs.

I am getting the same error when both adding the preview component, as well as trying to fetch data. I specified more about the specific error and reproduction steps below. I have created a custom page and a slice via slicemachine and am able to preview that successfully in the slicemachine.

Versions

  • @prismicio/next: v^1.3.2
  • next: v12.2.5
  • node: v16.17.0

Steps to reproduce

Add either <PrismicPreview /> to _app.tsx or load data via creating a client in static props as specified in the docs.

What is expected?

I believe should be loading data/seeing previews, but I'm not positive because this is the first step in project setup.

What is actually happening?

I am getting the following error (replace _app.tsx with whichever file I am loading data from, but this is from adding <PrismicPreview /> to _app.tsx):

../../node_modules/@prismicio/next/dist/PrismicPreview.js:3:0
Module not found: Can't resolve 'next/headers'

Import trace for requested module:
../../node_modules/@prismicio/next/dist/index.js
./prismicio.ts
./pages/_app.tsx

https://nextjs.org/docs/messages/module-not-found

App router with Next 13.5.1 - Build error on preview routes

Hi!

Thanks for your amazing work on this module. I have a little build problem since I updated to Next 13.5.1.

Versions

  • @prismicio/next: 1.3.4
  • next: 13.5.1
  • node: 18.15

Reproduction

Following Prismic documentation for preview, add a /preview route handler in Next.Js App Router with the following content:

export async function GET(request: NextRequest) {
    const client = createClient();

    draftMode().enable();

    await redirectToPreviewURL({ client, request });
}

Steps to reproduce

Run a simple build with Next: npm run build

What is expected?

No build error.

What is actually happening?

Error on checking validity of types:

src/app/api/preview/route.ts
Type error: Route "src/app/api/preview/route.ts" has an invalid export:
  "Promise<void>" is not a valid GET return type:
    Expected "Response | Promise<Response>", got "Promise<void>".
      Expected "Promise<Response>", got "Promise<void>".
        Expected "Response", got "void".

The error appeared since Next.JS changed their expected return type for the route handlers. The redirectToPreviewURL() should have a return type of never to match the call to redirect() from next/navigation. The problem is also present for exitPreview() which should return Response instead of Response | void.

I get that those problems are due to @prismicio/next trying to support both Pages router and App router with the same functions. Maybe it could be interesting to have a parameter on those functions that provides a way to change the function return type conditionnally.

Add `fallback` prop to `<PrismicNextImage>`

Is your feature request related to a problem? Please describe.

Rendering a fallback component is a common pattern when a Prismic field is empty. This pattern allows a developer to specify, for example, a default background image while allowing a content manager to provide an override image in Prismic.

We already have a fallback prop for
@prismicio/react's <PrismicRichText> and <PrismicText> components, but we don't have it for <PrismicNextImage>.

Describe the solution you'd like

The fallback prop could act just like <PrismicRichText>'s fallback prop. Any ReactNode value could be given and rendered as a fallback, including next/image if desired.

import { PrismicNextImage } from '@prismicio/next'

<PrismicNextImage
  field={imageField}
  fallback={<p>No image</p>}
/>

If imageField is empty, as determined by @prismicio/helpers's isFilled.image() function, fallback will be rendered instead.

Describe alternatives you've considered

Rendering a fallback value can be accomplished today using @prismicio/helpers's isFilled.image() helper. Although this works, the solution is verbose and requires manually using an additional package.

import * as prismicH from '@prismicio/helpers'
import { PrismicNextImage } from '@prismicio/next'

{
  prismicH.isFilled.image(imageField) ? (
    <PrismicNextImage field={imageField} />
  ) : (
    <p>No image</p>
  )
}

Additional context

Requested by @a-trost

Don't require the full `context` object to use `enableAutoPreviews()`

In the example createClient() function, we ask users to pass the whole context object so we can pass it to enableAutoPreviews().

// In a page file

export const getStaticProps = (context) => {
  const client = createClient({ context })
}
// prismicio.js

export const createClient = ({ req, context } = {}) => {
  const client = prismic.createClient(endpoint)

  enableAutoPreviews({ client, req, context })

  return client
}

This causes an ergonomic issue when you need something from within context in getStaticProps or its sibling APIs.

For example, using params from context requires using context.params. This is non-idiomatic.

export const getStaticProps = async (context) => {
  const client = createClient({ context })

  const documents = await client.getByUID('page', context.params.uid)
}

It is more idiomatic to destructure params from context.

export const getStaticProps = async ({ params }) => {
  const client = createClient({ context })

  const documents = await client.getByUID('page', params.uid)
}

However, this means we can no longer pass the full context object to createClient (which is only passed directly to enableAutoPreviews()).

Proposal

Change enableAutoPreviews() to only require the data it needs. Rather than requiring the full context object, it can accept just the previewData property from within context.

This changes a page's getStaticProps() to this:

export const getStaticProps = async ({ params, previewData }) => {
  const client = createClient({ previewData })

  const documents = await client.getByUID('page', params.uid)
}

This improves on the current strategy in to ways:

  1. It allows for using params easily.
  2. It conveys intent; passing previewData to createClient shows that the client is "preview-capable."

The createClient() function would need to be updated appropriately:

// prismicio.js

export const createClient = ({ req, previewData } = {}) => {
  const client = prismic.createClient(endpoint)

  enableAutoPreviews({ client, req, previewData })

  return client
}

Thumbnail prop for `PrismicNextImage`

Hi!

I wanted to make a PR out of the blue, but let's first throw the feature on the table ┬─┬ノ( º _ ºノ)

Is your feature request related to a problem? Please describe.

Currently, the PrismicNextImage component expects you to choose your desired image size when initiating the component.

Ex <PrismicNextImage field={slice.primary.image} fallbackAlt='some fallback alt' />

When selecting a thumbnail, as it is called by Prismic, makes it possible to duplicate the component and select the required image size.

Ex <PrismicNextImage field={slice.primary.image['small']} fallbackAlt='some fallback alt' />

This can be ok in some use cases.
There is also a weird syntax where you wouldn't really expect it. Why is the first example without any specification and the second with? What does happen with the first example? Which image is selected? … (questions are rhetorical).

In my case, I use the image not as a thumbnail but as a better optimized size. Which means I have a few thumbnail options: main, small, large, …

With the current setup, this would be my code, which makes a long if statement of which to select.

Ex

<PrismicNextImage
    field={
      size >= 900
        ? slice.primary.image['large']
          : size <= 400
            ? slice.primary.image['small']
            : slice.primary.image
    }
    fallbackAlt='some fallback alt'
/>

Describe the solution you'd like

I would prefer there to be an extra prop added to the PrismicNextImage like thumbnail. This doesn't break anything and just gives extra functionality to the component where you can provide the thumbnail separately. The other functionality can perfectly still work.

Ex

<PrismicNextImage
    field={slice.primary.image}
    thumbnail={size >= 900 ? 'large' : size <= 400 ? 'small' : undefined}
    fallbackAlt='some fallback alt'
/>

Also look at this, how clean.
The weird syntax is also kind of resolved because you specify undefined as a thumbnail, so you don't want a thumbnail image selected. Although I would change the name of thumbnail to something more clear, in slice machine it is called responsive views. I currently can't think of something good.

Additional context

In CONTRIBUTING.md the branch name is still called master. ;)

Now let's flip the table and hope it lands somewhere in a future release! (╯°□°)╯︵ ┻━┻
Thanks!

  • Diemas

Next13 PrismicLink and PrismicRichText broken

Versions

  • @prismicio/next: 1.0.3
  • next: 13.2.1
  • node: 16.17.1

Reproduction

I am using Next13 and am running into a tricky issue with the library. When using PrismicLink or PrismicRichText if there is a link embedded, it breaks the whole app (see screenshot below). next/link moved from a child tag to not allowing this behavior so I think PrismicLink needs to be updated accordingly too.

https://jmp.sh/NRh7tnNr

To reproduce add a link within PrismicLink or PrismicRichText in a Next13 project

Updating to 0.1.2 adds the next/image chunk to my final bundle even if I don't use next/image

Versions

  • @prismicio/next: 0.1.3
  • next: 12.2.5
  • node: 14.19.3

Steps to reproduce

  • Run next/bundle-analyzer on v0.1.2 and the next/image chunk is not present .
  • Upgrade to v0.1.3 without changing anything else and the next/image chunk is now there.

image

What is expected?

I would expect the next/image chunk to not be included in my project if I don't use the next Image component

RFC: <PrismicImage /> component

Overview

This RFC is about introducing a <PrismicImage /> component to this package. This component is for users that wish to use Next.js' image component with Prismic. This component would be an abstraction over the current way of handling <NextImage />, making it easier to use.

Background information

As of right now, the current way of setting up Next Images could look simile to the code below:


const FullWidthImage = ({ slice }) => (
  <section className="bg-white py-12 md:py-16">
    <div className="mx-auto max-w-5xl">
      <Image
        src={slice.primary.image.url}
        alt={slice.primary.image.alt}
        width={slice.primary.image.dimensions.width}
        height={slice.primary.image.dimensions.height}
        layout="responsive"
      />
    </div>
  </section>
);```

This could be time consuming if you have many types of images you want to use. 

### Proposal
Provide a solution to the problems described in the previous section.
- Describe your ideas.
- Showing contrete examples of their useage can help reviewers understand how the ideas would be applied.
- 
The proposal would be to provide an image component, `<PrismicImage />` for example that abstracts out a lot of the things needed to display the Next Image component. We could also pass in some props for layout types that are in sync with Next

**Usage:**

### How it could be implemented

TODO

### How to provide feedback

TODO

Reconsider use of globalThis or use globalThis shim

Is your feature request related to a problem? Please describe.

Reconsider use of globalThis or use globalThis with a shim.

Currently, globalThis is only used within useEffect which only fire on the client so should not be necessary when access objects like document.

This is problematic since we have a decent amount of traffic still coming from Android 8.0/8.1 which uses Chrome 70 and unfortunately does not support globalThis.

Describe the solution you'd like

Either drop globalThis or use a globalThis shim that gracefully fallsback to self, window, etc.

Describe alternatives you've considered

I've tried polyfilling the API but there isn't an elegant approach, without downfalls, and so I decided against it.

Forwarded ref in `PrismicNextLink` breaks `basePath`

Pages router

Using PrismicNextLink with basePath throws the following hydration error:

Warning: Prop `href` did not match. Server: "/article/my-article" Client: "/home/article/my-article/"

Resulting in an issue where the link can be wrong displayed.
Looking into the issue, I copied the exact PrismicNextLink file from here and tried with that.
Removing the forwarded ref resolved the issue for basePath and the / at the end.

Versions

  • @prismicio/next: v1.5.0
  • next: v14.1.4
  • node: v20.11.1

Steps to reproduce

  • Create a clean Next.js Pages router project
  • Set up some basic routing with the routes in createClient.
  • Add a basePath to next.config.mjs
  • Check console.

What is expected?

The error should not be thrown with or without basePath.

What is actually happening?

An error is thrown, and the path is sometimes incorrect.

exitPreview() is not working

Packages version:

"@prismicio/client": "^6.7.1",
    "@prismicio/helpers": "^2.3.5",
    "@prismicio/next": "^0.1.5",
    "@prismicio/react": "^2.4.4",

api/exit-preview.js is as follows:

import { exitPreview } from "@prismicio/next"

export default async function exit(req, res) {
  await exitPreview({ res, req })
}

Steps to reproduce:

  • Preview a page
  • Open preview - preview works
  • click on exit preview in the toolbar
  • toolbar is gone but the preview data is still there!

Preview causing infinite reloading loop in Chrome and Firefox

Versions

  • package_name: v0.1.0
  • node: v16.13.1

Reproduction

Using preview in Chrome and Firefox causes infinite reloading loop. Works as expected in Safari.

Steps to reproduce

Create slicemachine Next.js project, and use this guide to set up Previews.

What is expected?

Preview to load once and not cause infinite reloading loop.

What is actually happening?

Preview is in infinite reloading loop.

PrismicToolbar not loading

Versions

  • package_name: "@prismicio/next": "^0.0.1"
  • node: v16.10.0

Reproduction

Seems that I'm just supposed to wrap it in _app.tsx but I can't seem to get it to show

<PrismicPreview repositoryName="wondervalley">
  <Component {...pageProps} />
</PrismicPreview>

NextRouter was not mounted error using PrismicPreview

Versions

  • @prismicio/next: v1.0.2
  • next: v13.1.1
  • node: v16.14.0

Reproduction

When I'm trying to add <PrismicPreview /> inside my page, I got an error from NextJS

Additional Details

Code used :

// ./app/layout.tsx

"use client";

import { PrismicProvider } from "@prismicio/react";
import Link from "next/link";
interface RootLayoutProps {
	children: React.ReactNode;
}

const RootLayout: React.FC<RootLayoutProps> = ({ children }) => {
	return (
		<html lang="fr">
			<head />

			<body>
				<PrismicProvider
					internalLinkComponent={(props) => <Link {...props} />}
				>
					<div>{children}</div>
				</PrismicProvider>
			</body>
		</html>
	);
};

export default RootLayout;
// ./app/page.tsx

"use client";

import { PrismicPreview } from "@prismicio/next";
import { repositoryName } from "../library/prismic";

const Page = () => {
	return (
		<PrismicPreview repositoryName={repositoryName}>
			<h1>Hello world!</h1>
		</PrismicPreview>
	);
};

export default Page;

What is actually happening?

Got an error from NextJS : Error: NextRouter was not mounted. https://nextjs.org/docs/messages/next-router-not-mounted.

Possible way to fix that

When I look to vercel/next.js#43585, It seems like replace next/router by next/navigation (used inside PrismicPreview.tsx on line :58 for useRouter) can solve this issue.

Invalid URL on redirectToPreviewURL()

Getting TypeError: Invalid URL on redirectToPreviewURL on the Next.js preview api route.

Screenshot 2024-01-05 at 3 39 01 PM

Versions

  • @prismicio/next: ^1.5.0
  • next: 13.1.6
  • node: 16.14.2

Reproduction

Just following the simplest Next.js documentation to enable previews:
On api/preview.ts:

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  const client = Client({ req });
  setPreviewData({ req, res });
  await redirectToPreviewURL({
    req,
    res,
    client,
    linkResolver: previewLinkResolver,
  });
}

Steps to reproduce

yarn dev then access any preview link. e.g. /api/preview?token=:token1&documentId=:id

What is expected?

redirectToPreviewURL shouldn't error. Afaik latest prismic-next version works fine with Next.js 13

What is actually happening?

Editing the document on Prismic and then clicking the "View" redirects just fine to my local preview route, but redirectToPreviewURL errors with 500 and unable to view anything.

Module not found: Can't resolve 'next/navigation'

I am just starting out installing dependencies as in the starter docs and as soon as I add the <PrismicPreview>...</PrismicPreview> part, I get the following error:

../../node_modules/@prismicio/next/dist/PrismicPreviewClient.js:5:0
Module not found: Can't resolve 'next/navigation'

Import trace for requested module:
../../node_modules/@prismicio/next/dist/PrismicPreview.js
../../node_modules/@prismicio/next/dist/index.js
./src/pages/_app.tsx

https://nextjs.org/docs/messages/module-not-found

After some digging in the @prismicio/next module, I found that the src/PrismicPreviewClient.tsx is using next/navigation which does not seem to be exported by next nor is it documented in their website. Removing that liner actually solves the problem.

Is this to support the new app router? Well in that case this breaks the existing pages router!

Versions

  • @prismicio/next: v1.1.0
  • next: v12.3.1
  • node: v16.19.0

Reproduction

Additional Details

In the pages/_app.tsx file I added the following:

import { PrismicProvider } from '@prismicio/react'
import { PrismicPreview } from '@prismicio/next'
import { repositoryName } from '../../prismicio'

<PrismicProvider>
   <PrismicPreview repositoryName={repositoryName}>
           ...
   </PrismicPreview>
</PrismicProvider>

Steps to reproduce

Please follow the steps at the setup Prismic docs

What is expected?

Expected the app to work normally with preview supported

What is actually happening?

The app breaks and shows the above error message.

Support Next.js Edge Runtime

Is your feature request related to a problem? Please describe.

Next.js supports a runtime called Edge Runtime built upon Web APIs, unlike the default Node.js-based runtime.

Some @prismicio/next APIs are incompatible with Edge Runtime, such as setPreviewData(). setPreviewData() reads an API Route request and sets a Prismic-specific Preview Data property, but the function does not currently support reading a Web API Request object as used in Edge Runtime.

Describe the solution you'd like

The existing @prismicio/next APIs could be made universal to run in both the default non-Edge Runtime and Edge Runtime environments. This can probably be done using duck typing to test the received data.

Describe alternatives you've considered

  • 🚫 Provide a different set of helpers specific to a runtime.
  • 🚫 Only support one runtime.

Additional context

None.

Opt out of SVG optimisation

The built-in loader for PrismicNextImage produces a srcset on the image tag for svg images. This behaviour seems to be redundant. Should you rather opt in to this much the same way as it works for the underlying Image component.

Doesn't works with React 18

Versions

  • package_name: 0.1.0
  • node: 16.14.2

Reproduction

When running npm install

Steps to reproduce

Run npm install with Next.js 12.1.2 and @prismicio/next 0.1.0

What is actually happening?

C:\Users\aaron.vandenberg\WebstormProjects\project-v2-react18>npm install
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR! 
npm ERR! While resolving: website@undefined
npm ERR! Found: [email protected]
npm ERR! node_modules/react
npm ERR!   react@"^18.0.0" from website@undefined
npm ERR!   apps/website
npm ERR!     website@undefined
npm ERR!     node_modules/website
npm ERR!       workspace apps\website from the root project  
npm ERR!   peer react@"^17.0.2 || ^18.0.0-0" from [email protected]
npm ERR!   node_modules/next
npm ERR!     next@"12.1.0" from website@undefined
npm ERR!     apps/website
npm ERR!       website@undefined
npm ERR!       node_modules/website
npm ERR!   @prismicio/next@"0.1.0" from website@undefined
npm ERR!   apps/website
npm ERR!     website@undefined
npm ERR!     node_modules/website
npm ERR!       workspace apps\website from the root project
npm ERR!
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR!

Remove the 404 page flash when previewing an unpublished document via share link

Is your feature request related to a problem? Please describe.

When using a shared preview link to preview an unpublished document, previewers will see the app's 404 page load and then immediately refresh to the previewed document. This flash of the 404 page is unexpected for most viewers and results in an unpolished viewing experience.

This is the current unpublished preview via share link experience:

  1. Previewer opens the share link.
  2. The link loads a prismic.io URL that sets the preview cookie in the person’s browser.
  3. The prismic.io page redirects to the URL where the share link was created.
  4. Note: it does not redirect to the preview resolver endpoint (/api/preview) where Next.js’s Preview Mode would be activated.
  5. Since the page is not published, the app lands on a 404 URL.
  6. The page sees that a Prismic preview cookie is present, but Next.js Preview Mode is not activated. It fetches the preview resolver endpoint (/api/preview) in the background to start Preview Mode. It then refreshes the page.
  7. Preview Mode is now active, so Next.js runs in SSR mode. It runs getStaticProps() using the preview ref which allows it to query the unpublished document.
  8. The preview is loaded.

Describe the solution you'd like

To remove the flash of the 404 page in this situation, the following flow could be implemented:

  1. Set up the 404 page using getServerSideProps(). This lets the page access the previewer's cookies on the server.
  2. If getServerSideProps() detects that a Prismic preview cookie is present, but Next.js's Preview Mode is not active, we know we need to hit /api/preview.
  3. Redirect to /api/preview with a reference to the current URL (i.e. the previewed page).
  4. Activate Preview Mode in /api/preview like normal.
  5. Redirect back to the previewed page.
  6. The preview is loaded.

Using this flow, the previewer should not see the 404 page. It should result in a quicker time-to-preview since this logic happens on the server. We do not need to wait for the browser to start the current client-side logic that handles this flow.

Describe alternatives you've considered

  • The 404 page could show a loading state when it detects a Prismic preview cookie and inactive Preview Mode. This is not ideal, but would be better than displaying the actual 404 page.

Additional context

Thanks to @chamois-d-or for surfacing this issue and suggesting solutions. 🙂

PrismicNextImage broken with Next 13.4.8

Versions

  • @prismicio/next: 1.3.2
  • next: 13.4.8
  • node: 18.13.0

Reproduction

Attempt to use PrismicNextImage with Next 13.4.8

What is actually happening?

next dev & next build both fail with the error:

Warning: React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: object. at PrismicNextImage (/Users/augie/dev/redacted/node_modules/.pnpm/@[email protected]_@[email protected][email protected][email protected]/node_modules/@prismicio/next/dist/PrismicNextImage.cjs:23:29)

Hydration error using `<PrismicLink/>`

Versions

"@prismicio/client": "^6.7.1",
"@prismicio/helpers": "^2.3.3",
"@prismicio/next": "^0.1.5",
"@prismicio/react": "^2.5.0",
"@prismicio/slice-simulator-react": "^0.2.2",
"next": "12.3.0",
"react": "18.2.0",

Reproduction

When using PrismicLink to render internal links it will create an a element inside an a element.

{menu.data?.links.map((menuLink, index) => ( <li key={menuLink.label}> <PrismicLink field={menuLink.link}> <span className="text-base font-medium text-gray-500 hover:text-gray-900"> test </span> </PrismicLink> </li> ))}

What is expected?

This gives a hydration error in React 18 since an a element cant be a child of another a element. I did follow the docs and guides and I have no clue why this bug did occur in my app.

Notify developers early if configuration is incorrect

Is your feature request related to a problem? Please describe.

@prismicio/next requires specific configuration to work properly. For example, <PrismicPreview> must be set up with a properly created preview endpoint, and enableAutoPreviews() requires valid Next.js preview data or an API req object.

Some of this configuration can be analyzed statically to provide in-code-editor errors via TypeScript, but not everyone is using TypeScript, and some configuration can only be analyzed at runtime.

Without notifying developers of misconfiguration in an obvious way, developers likely may not understand errors caused as a result.

Describe the solution you'd like

The most obvious way to signal misconfiguration is crashing the Next.js process. If the server cannot start or build, a developer is more likely to fix the issue.

Alternatively, we can throw errors in the browser, prompting the Next.js error overlay to appear.

We can provide helpful messages and links to guide developers to properly set up their project.

Describe alternatives you've considered

Some errors are logged to the browser console, but they are not obvious. In some cases, such as <PrismicPreview>'s logic to start shared preview links, the page may refresh so quickly that console messages cannot be read.

Additional context

Feature requested by @FuzzyReason

Use Next.js's `<Script>` component to load the Prismic Toolbar

Is your feature request related to a problem? Please describe.

The Prismic Toolbar is currently loaded using @prismicio/react's <PrismicToolbar> component. While this currently works, it results in an extra dependency and is likely less optimal than using Next.js's built-in <script> handling.

Describe the solution you'd like

<PrismicPreview> could replace it's <PrismicToolbar> usage using Next.js's <Script> component directly.

Describe alternatives you've considered

N/A

Additional context

https://nextjs.org/docs/basic-features/script

Storybook fails because @prismicio/next can't resolve 'next/router'

I'm not sure if this is solely caused by @prismicio/next, but I am getting this error since migrating our codebase to use it. Since the slice simulator is also broken for me (see prismicio/slice-machine#430), I still need Storybook.

The full error is:

ModuleNotFoundError: Module not found: Error: Can't resolve 'next/router' in '/Users/amosbastian/Development/lifex-website/node_modules/@prismicio/next/dist'
Did you mean 'router.js'?
BREAKING CHANGE: The request 'next/router' failed to resolve only because it was resolved as fully specified
(probably because the origin is strict EcmaScript Module, e. g. a module with javascript mimetype, a '*.mjs' file, or a '*.js' file where the package.json contains '"type": "module"').
The extension in the request is mandatory for it to be fully specified.
Add the extension to the request.
    at /Users/amosbastian/Development/lifex-website/node_modules/webpack/lib/Compilation.js:2015:28
    at /Users/amosbastian/Development/lifex-website/node_modules/webpack/lib/NormalModuleFactory.js:798:13
    at eval (eval at create (/Users/amosbastian/Development/lifex-website/node_modules/webpack/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:10:1)
    at /Users/amosbastian/Development/lifex-website/node_modules/webpack/lib/NormalModuleFactory.js:270:22
    at eval (eval at create (/Users/amosbastian/Development/lifex-website/node_modules/webpack/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:9:1)
    at /Users/amosbastian/Development/lifex-website/node_modules/webpack/lib/NormalModuleFactory.js:434:22
    at /Users/amosbastian/Development/lifex-website/node_modules/webpack/lib/NormalModuleFactory.js:116:11
    at /Users/amosbastian/Development/lifex-website/node_modules/webpack/lib/NormalModuleFactory.js:670:25
    at /Users/amosbastian/Development/lifex-website/node_modules/webpack/lib/NormalModuleFactory.js:855:8
    at /Users/amosbastian/Development/lifex-website/node_modules/webpack/lib/NormalModuleFactory.js:975:5
    at /Users/amosbastian/Development/lifex-website/node_modules/neo-async/async.js:6883:13
    at /Users/amosbastian/Development/lifex-website/node_modules/webpack/lib/NormalModuleFactory.js:958:45
    at finishWithoutResolve (/Users/amosbastian/Development/lifex-website/node_modules/webpack/node_modules/enhanced-resolve/lib/Resolver.js:312:11)
    at /Users/amosbastian/Development/lifex-website/node_modules/webpack/node_modules/enhanced-resolve/lib/Resolver.js:386:15
    at /Users/amosbastian/Development/lifex-website/node_modules/webpack/node_modules/enhanced-resolve/lib/Resolver.js:435:5
    at eval (eval at create (/Users/amosbastian/Development/lifex-website/node_modules/webpack/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:16:1)
resolve 'next/router' in '/Users/amosbastian/Development/lifex-website/node_modules/@prismicio/next/dist'
  Parsed request is a module
  using description file: /Users/amosbastian/Development/lifex-website/node_modules/@prismicio/next/package.json (relative path: ./dist)
    Field 'browser' doesn't contain a valid alias configuration
    resolve as module
      /Users/amosbastian/Development/lifex-website/node_modules/@prismicio/next/dist/node_modules doesn't exist or is not a directory
      looking for modules in /Users/amosbastian/Development/lifex-website/node_modules/@prismicio/next/node_modules
        /Users/amosbastian/Development/lifex-website/node_modules/@prismicio/next/node_modules/next doesn't exist
      /Users/amosbastian/Development/lifex-website/node_modules/@prismicio/node_modules doesn't exist or is not a directory
      /Users/amosbastian/Development/lifex-website/node_modules/node_modules doesn't exist or is not a directory
      looking for modules in /Users/amosbastian/Development/lifex-website/node_modules
        existing directory /Users/amosbastian/Development/lifex-website/node_modules/next
          using description file: /Users/amosbastian/Development/lifex-website/node_modules/next/package.json (relative path: .)
            using description file: /Users/amosbastian/Development/lifex-website/node_modules/next/package.json (relative path: ./router)
              Field 'browser' doesn't contain a valid alias configuration
              /Users/amosbastian/Development/lifex-website/node_modules/next/router doesn't exist
      /Users/amosbastian/Development/node_modules doesn't exist or is not a directory
      looking for modules in /Users/amosbastian/node_modules
        /Users/amosbastian/node_modules/next doesn't exist
      /Users/node_modules doesn't exist or is not a directory
      /node_modules doesn't exist or is not a directory

WARN Broken build, fix the error above.
WARN You may need to refresh the browser.

Versions

"@prismicio/client": "^6.4.1",
"@prismicio/next": "^0.1.0",
"@prismicio/react": "^2.1.2",
"@prismicio/slice-simulator-react": "^0.2.0",
"@storybook/addon-a11y": "^6.5.0-alpha.51",
"@storybook/addon-essentials": "^6.5.0-alpha.51",
"@storybook/builder-webpack5": "^6.5.0-alpha.51",
"@storybook/manager-webpack5": "^6.5.0-alpha.51",
"@storybook/react": "6.5.0-alpha.51",

Reproduction

Additional Details

Steps to reproduce

Run Storybook with Webpack 5 and @prismicio/next installed.

What is expected?

It should run.

What is actually happening?

It is giving an error about next/router.

PrismicNextImage -> height not using correct parameter when not used as explicit parameter

Versions

  • @prismicio/next: 1.0.2
  • next: ^13.1.0
  • node: 16.14.0

Reproduction

Steps to reproduce

Use the PrismicNextImage object with field={image} where Image is a Prismic image field.

When using an image with layout="responsive" images keep being out of aspect ratio.
In the component inspector I can see that height is equal to width. (My image for instance was 1000px x 200px)

If I use the width & height explicit from image.dimensions.[width/height] then the image scales correctly.

What is expected?

width & height should be equal to the actual width & height in Prismic when using layout="responsive"

What is actually happening?

In the component source I can see this code:

let resolvedWidth = castedWidth ?? field.dimensions.width;
let resolvedHeight = castedHeight ?? field.dimensions.width;

If I'm correct the second line should contain field.dimensions.height instead of the width parameter.

Version v0.1.5 is not working with Storybook v6.5.10

Versions

  • @prismicio/next: v0.1.5
  • next: v12.3.0
  • node: v18.7.0
  • storybook: v6.5.10

Reproduction

  • Install the latest version of "@prismicio/next": 0.1.5
  • Install the latest version of "storybook": 6.5.10
  • Create a story of a component that uses any Prismic Image
  • Try to run storybook
Additional Details

Package

{
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "test": "jest",
    "storybook": "start-storybook -p 6006",
    "build-storybook": "build-storybook",
    "chromatic": "npx chromatic",
    "slicemachine": "start-slicemachine",
    "e2e": "cypress open",
    "e2e:headless": "cypress run",
    "codegen": "prismic-ts-codegen"
  },
  "dependencies": {
    "@prismicio/client": "6.7.1",
    "@prismicio/helpers": "2.3.3",
    "@prismicio/next": "0.1.5",
    "@prismicio/react": "2.5.0",
    "@prismicio/slice-simulator-react": "0.2.2",
    "next": "12.3.0",
    "react": "18.2.0",
    "react-dom": "18.2.0",
    "recoil": "0.7.5",
    "styled-components": "5.3.5"
  },
  "devDependencies": {
    "@babel/core": "7.19.0",
    "@prismicio/types": "0.2.3",
    "@storybook/addon-a11y": "6.5.10",
    "@storybook/addon-actions": "6.5.10",
    "@storybook/addon-essentials": "6.5.10",
    "@storybook/addon-interactions": "6.5.10",
    "@storybook/addon-links": "6.5.10",
    "@storybook/addons": "6.5.10",
    "@storybook/react": "6.5.10",
    "@storybook/testing-library": "0.0.13",
    "@storybook/theming": "6.5.10",
    "@testing-library/jest-dom": "5.16.5",
    "@testing-library/react": "13.4.0",
    "@types/jest": "29.0.1",
    "@types/node": "18.7.16",
    "@types/react": "18.0.19",
    "@types/react-dom": "18.0.6",
    "@types/styled-components": "5.1.26",
    "@typescript-eslint/eslint-plugin": "5.36.2",
    "babel-loader": "8.2.5",
    "chromatic": "6.9.0",
    "cypress": "10.7.0",
    "eslint": "8.23.1",
    "eslint-config-next": "12.3.0",
    "eslint-plugin-jsx-a11y": "6.6.1",
    "eslint-plugin-react": "7.31.8",
    "eslint-plugin-storybook": "0.6.4",
    "eslint-plugin-styled-components-a11y": "1.0.0",
    "jest": "29.0.3",
    "jest-environment-jsdom": "29.0.3",
    "jest-styled-components": "7.1.1",
    "prismic-ts-codegen": "0.1.5",
    "slice-machine-ui": "0.4.2",
    "storybook-addon-designs": "6.3.1",
    "storybook-addon-next-router": "4.0.0",
    "storybook-addon-recoil-flow": "1.3.1",
    "tsconfig-paths-webpack-plugin": "4.0.0",
    "typescript": "4.8.3"
  }
}

Log

ERROR in ./node_modules/@prismicio/next/dist/PrismicPreview.mjs 77:30-38
Can't import the named export 'Fragment' from non EcmaScript module (only default export is available)
 @ ./node_modules/@prismicio/next/dist/index.mjs
 @ ./utils/prismic/index.ts
 @ ./components/quarks/RichText/RichText.tsx
 @ ./components/quarks/RichText/index.ts
 @ ./components/molecules/ShowcaseCard/ShowcaseCard.tsx
 @ ./components/molecules/ShowcaseCard/index.ts
 @ ./components/organisms/Showcase/Showcase.tsx
 @ ./components/organisms/Showcase/index.ts
 @ ./components/organisms/Showcase/Showcase.stories.tsx
 @ ./components sync ^\.(?:(?:^|\/|(?:(?:(?!(?:^|\/)\.).)*?)\/)(?!\.)(?=.)[^/]*?\.stories\.(js|jsx|ts|tsx))$
 @ ./generated-stories-entry.js
 @ multi ./node_modules/@storybook/core-client/dist/esm/globals/polyfills.js ./node_modules/@storybook/core-client/dist/esm/globals/globals.js (webpack)-hot-middleware/client.js?reload=true&quiet=false&noInfo=undefined ./storybook-init-framework-entry.js ./node_modules/@storybook/react/dist/esm/client/docs/config-generated-config-entry.js ./node_modules/@storybook/react/dist/esm/client/preview/config-generated-config-entry.js ./node_modules/@storybook/addon-links/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-docs/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-actions/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-backgrounds/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-measure/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-outline/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-interactions/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-a11y/preview.js-generated-config-entry.js ./node_modules/storybook-addon-next-router/dist/preset/addDecorator.js-generated-config-entry.js ./node_modules/storybook-addon-recoil-flow/dist/decorators.js-generated-config-entry.js ./.storybook/preview.js-generated-config-entry.js ./generated-stories-entry.js

ERROR in ./node_modules/@prismicio/next/dist/PrismicPreview.mjs 80:26-40
Can't import the named export 'PrismicToolbar' from non EcmaScript module (only default export is available)
 @ ./node_modules/@prismicio/next/dist/index.mjs
 @ ./utils/prismic/index.ts
 @ ./components/quarks/RichText/RichText.tsx
 @ ./components/quarks/RichText/index.ts
 @ ./components/molecules/ShowcaseCard/ShowcaseCard.tsx
 @ ./components/molecules/ShowcaseCard/index.ts
 @ ./components/organisms/Showcase/Showcase.tsx
 @ ./components/organisms/Showcase/index.ts
 @ ./components/organisms/Showcase/Showcase.stories.tsx
 @ ./components sync ^\.(?:(?:^|\/|(?:(?:(?!(?:^|\/)\.).)*?)\/)(?!\.)(?=.)[^/]*?\.stories\.(js|jsx|ts|tsx))$
 @ ./generated-stories-entry.js
 @ multi ./node_modules/@storybook/core-client/dist/esm/globals/polyfills.js ./node_modules/@storybook/core-client/dist/esm/globals/globals.js (webpack)-hot-middleware/client.js?reload=true&quiet=false&noInfo=undefined ./storybook-init-framework-entry.js ./node_modules/@storybook/react/dist/esm/client/docs/config-generated-config-entry.js ./node_modules/@storybook/react/dist/esm/client/preview/config-generated-config-entry.js ./node_modules/@storybook/addon-links/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-docs/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-actions/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-backgrounds/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-measure/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-outline/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-interactions/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-a11y/preview.js-generated-config-entry.js ./node_modules/storybook-addon-next-router/dist/preset/addDecorator.js-generated-config-entry.js ./node_modules/storybook-addon-recoil-flow/dist/decorators.js-generated-config-entry.js ./.storybook/preview.js-generated-config-entry.js ./generated-stories-entry.js

ERROR in ./node_modules/@prismicio/next/dist/setPreviewData.mjs 4:45-59
Can't import the named export 'cookie' from non EcmaScript module (only default export is available)
 @ ./node_modules/@prismicio/next/dist/index.mjs
 @ ./utils/prismic/index.ts
 @ ./components/quarks/RichText/RichText.tsx
 @ ./components/quarks/RichText/index.ts
 @ ./components/molecules/ShowcaseCard/ShowcaseCard.tsx
 @ ./components/molecules/ShowcaseCard/index.ts
 @ ./components/organisms/Showcase/Showcase.tsx
 @ ./components/organisms/Showcase/index.ts
 @ ./components/organisms/Showcase/Showcase.stories.tsx
 @ ./components sync ^\.(?:(?:^|\/|(?:(?:(?!(?:^|\/)\.).)*?)\/)(?!\.)(?=.)[^/]*?\.stories\.(js|jsx|ts|tsx))$
 @ ./generated-stories-entry.js
 @ multi ./node_modules/@storybook/core-client/dist/esm/globals/polyfills.js ./node_modules/@storybook/core-client/dist/esm/globals/globals.js (webpack)-hot-middleware/client.js?reload=true&quiet=false&noInfo=undefined ./storybook-init-framework-entry.js ./node_modules/@storybook/react/dist/esm/client/docs/config-generated-config-entry.js ./node_modules/@storybook/react/dist/esm/client/preview/config-generated-config-entry.js ./node_modules/@storybook/addon-links/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-docs/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-actions/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-backgrounds/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-measure/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-outline/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-interactions/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-a11y/preview.js-generated-config-entry.js ./node_modules/storybook-addon-next-router/dist/preset/addDecorator.js-generated-config-entry.js ./node_modules/storybook-addon-recoil-flow/dist/decorators.js-generated-config-entry.js ./.storybook/preview.js-generated-config-entry.js ./generated-stories-entry.js

ERROR in ./node_modules/@prismicio/next/dist/lib/getPrismicPreviewCookie.mjs 12:17-31
Can't import the named export 'cookie' from non EcmaScript module (only default export is available)
 @ ./node_modules/@prismicio/next/dist/PrismicPreview.mjs
 @ ./node_modules/@prismicio/next/dist/index.mjs
 @ ./utils/prismic/index.ts
 @ ./components/quarks/RichText/RichText.tsx
 @ ./components/quarks/RichText/index.ts
 @ ./components/molecules/ShowcaseCard/ShowcaseCard.tsx
 @ ./components/molecules/ShowcaseCard/index.ts
 @ ./components/organisms/Showcase/Showcase.tsx
 @ ./components/organisms/Showcase/index.ts
 @ ./components/organisms/Showcase/Showcase.stories.tsx
 @ ./components sync ^\.(?:(?:^|\/|(?:(?:(?!(?:^|\/)\.).)*?)\/)(?!\.)(?=.)[^/]*?\.stories\.(js|jsx|ts|tsx))$
 @ ./generated-stories-entry.js
 @ multi ./node_modules/@storybook/core-client/dist/esm/globals/polyfills.js ./node_modules/@storybook/core-client/dist/esm/globals/globals.js (webpack)-hot-middleware/client.js?reload=true&quiet=false&noInfo=undefined ./storybook-init-framework-entry.js ./node_modules/@storybook/react/dist/esm/client/docs/config-generated-config-entry.js ./node_modules/@storybook/react/dist/esm/client/preview/config-generated-config-entry.js ./node_modules/@storybook/addon-links/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-docs/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-actions/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-backgrounds/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-measure/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-outline/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-interactions/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-a11y/preview.js-generated-config-entry.js ./node_modules/storybook-addon-next-router/dist/preset/addDecorator.js-generated-config-entry.js ./node_modules/storybook-addon-recoil-flow/dist/decorators.js-generated-config-entry.js ./.storybook/preview.js-generated-config-entry.js ./generated-stories-entry.js

ERROR in ./node_modules/@prismicio/next/dist/PrismicPreview.mjs 80:22-25
Can't import the named export 'jsx' from non EcmaScript module (only default export is available)
 @ ./node_modules/@prismicio/next/dist/index.mjs
 @ ./utils/prismic/index.ts
 @ ./components/quarks/RichText/RichText.tsx
 @ ./components/quarks/RichText/index.ts
 @ ./components/molecules/ShowcaseCard/ShowcaseCard.tsx
 @ ./components/molecules/ShowcaseCard/index.ts
 @ ./components/organisms/Showcase/Showcase.tsx
 @ ./components/organisms/Showcase/index.ts
 @ ./components/organisms/Showcase/Showcase.stories.tsx
 @ ./components sync ^\.(?:(?:^|\/|(?:(?:(?!(?:^|\/)\.).)*?)\/)(?!\.)(?=.)[^/]*?\.stories\.(js|jsx|ts|tsx))$
 @ ./generated-stories-entry.js
 @ multi ./node_modules/@storybook/core-client/dist/esm/globals/polyfills.js ./node_modules/@storybook/core-client/dist/esm/globals/globals.js (webpack)-hot-middleware/client.js?reload=true&quiet=false&noInfo=undefined ./storybook-init-framework-entry.js ./node_modules/@storybook/react/dist/esm/client/docs/config-generated-config-entry.js ./node_modules/@storybook/react/dist/esm/client/preview/config-generated-config-entry.js ./node_modules/@storybook/addon-links/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-docs/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-actions/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-backgrounds/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-measure/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-outline/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-interactions/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-a11y/preview.js-generated-config-entry.js ./node_modules/storybook-addon-next-router/dist/preset/addDecorator.js-generated-config-entry.js ./node_modules/storybook-addon-recoil-flow/dist/decorators.js-generated-config-entry.js ./.storybook/preview.js-generated-config-entry.js ./generated-stories-entry.js

ERROR in ./node_modules/@prismicio/next/dist/PrismicPreview.mjs 77:25-29
Can't import the named export 'jsxs' from non EcmaScript module (only default export is available)
 @ ./node_modules/@prismicio/next/dist/index.mjs
 @ ./utils/prismic/index.ts
 @ ./components/quarks/RichText/RichText.tsx
 @ ./components/quarks/RichText/index.ts
 @ ./components/molecules/ShowcaseCard/ShowcaseCard.tsx
 @ ./components/molecules/ShowcaseCard/index.ts
 @ ./components/organisms/Showcase/Showcase.tsx
 @ ./components/organisms/Showcase/index.ts
 @ ./components/organisms/Showcase/Showcase.stories.tsx
 @ ./components sync ^\.(?:(?:^|\/|(?:(?:(?!(?:^|\/)\.).)*?)\/)(?!\.)(?=.)[^/]*?\.stories\.(js|jsx|ts|tsx))$
 @ ./generated-stories-entry.js
 @ multi ./node_modules/@storybook/core-client/dist/esm/globals/polyfills.js ./node_modules/@storybook/core-client/dist/esm/globals/globals.js (webpack)-hot-middleware/client.js?reload=true&quiet=false&noInfo=undefined ./storybook-init-framework-entry.js ./node_modules/@storybook/react/dist/esm/client/docs/config-generated-config-entry.js ./node_modules/@storybook/react/dist/esm/client/preview/config-generated-config-entry.js ./node_modules/@storybook/addon-links/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-docs/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-actions/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-backgrounds/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-measure/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-outline/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-interactions/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-a11y/preview.js-generated-config-entry.js ./node_modules/storybook-addon-next-router/dist/preset/addDecorator.js-generated-config-entry.js ./node_modules/storybook-addon-recoil-flow/dist/decorators.js-generated-config-entry.js ./.storybook/preview.js-generated-config-entry.js ./generated-stories-entry.js

ERROR in ./node_modules/@prismicio/next/dist/PrismicPreview.mjs 17:2-17
Can't import the named export 'useEffect' from non EcmaScript module (only default export is available)
 @ ./node_modules/@prismicio/next/dist/index.mjs
 @ ./utils/prismic/index.ts
 @ ./components/quarks/RichText/RichText.tsx
 @ ./components/quarks/RichText/index.ts
 @ ./components/molecules/ShowcaseCard/ShowcaseCard.tsx
 @ ./components/molecules/ShowcaseCard/index.ts
 @ ./components/organisms/Showcase/Showcase.tsx
 @ ./components/organisms/Showcase/index.ts
 @ ./components/organisms/Showcase/Showcase.stories.tsx
 @ ./components sync ^\.(?:(?:^|\/|(?:(?:(?!(?:^|\/)\.).)*?)\/)(?!\.)(?=.)[^/]*?\.stories\.(js|jsx|ts|tsx))$
 @ ./generated-stories-entry.js
 @ multi ./node_modules/@storybook/core-client/dist/esm/globals/polyfills.js ./node_modules/@storybook/core-client/dist/esm/globals/globals.js (webpack)-hot-middleware/client.js?reload=true&quiet=false&noInfo=undefined ./storybook-init-framework-entry.js ./node_modules/@storybook/react/dist/esm/client/docs/config-generated-config-entry.js ./node_modules/@storybook/react/dist/esm/client/preview/config-generated-config-entry.js ./node_modules/@storybook/addon-links/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-docs/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-actions/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-backgrounds/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-measure/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-outline/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-interactions/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-a11y/preview.js-generated-config-entry.js ./node_modules/storybook-addon-next-router/dist/preset/addDecorator.js-generated-config-entry.js ./node_modules/storybook-addon-recoil-flow/dist/decorators.js-generated-config-entry.js ./.storybook/preview.js-generated-config-entry.js ./generated-stories-entry.js

ERROR in ./node_modules/@prismicio/next/dist/PrismicPreview.mjs 14:17-26
Can't import the named export 'useRouter' from non EcmaScript module (only default export is available)
 @ ./node_modules/@prismicio/next/dist/index.mjs
 @ ./utils/prismic/index.ts
 @ ./components/quarks/RichText/RichText.tsx
 @ ./components/quarks/RichText/index.ts
 @ ./components/molecules/ShowcaseCard/ShowcaseCard.tsx
 @ ./components/molecules/ShowcaseCard/index.ts
 @ ./components/organisms/Showcase/Showcase.tsx
 @ ./components/organisms/Showcase/index.ts
 @ ./components/organisms/Showcase/Showcase.stories.tsx
 @ ./components sync ^\.(?:(?:^|\/|(?:(?:(?!(?:^|\/)\.).)*?)\/)(?!\.)(?=.)[^/]*?\.stories\.(js|jsx|ts|tsx))$
 @ ./generated-stories-entry.js
 @ multi ./node_modules/@storybook/core-client/dist/esm/globals/polyfills.js ./node_modules/@storybook/core-client/dist/esm/globals/globals.js (webpack)-hot-middleware/client.js?reload=true&quiet=false&noInfo=undefined ./storybook-init-framework-entry.js ./node_modules/@storybook/react/dist/esm/client/docs/config-generated-config-entry.js ./node_modules/@storybook/react/dist/esm/client/preview/config-generated-config-entry.js ./node_modules/@storybook/addon-links/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-docs/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-actions/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-backgrounds/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-measure/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-outline/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-interactions/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-a11y/preview.js-generated-config-entry.js ./node_modules/storybook-addon-next-router/dist/preset/addDecorator.js-generated-config-entry.js ./node_modules/storybook-addon-recoil-flow/dist/decorators.js-generated-config-entry.js ./.storybook/preview.js-generated-config-entry.js ./generated-stories-entry.js

ERROR in ./node_modules/@prismicio/next/dist/index.mjs 6:0-58
Can't reexport the named export 'PrismicNextImage' from non EcmaScript module (only default export is available)
 @ ./utils/prismic/index.ts
 @ ./components/quarks/RichText/RichText.tsx
 @ ./components/quarks/RichText/index.ts
 @ ./components/molecules/ShowcaseCard/ShowcaseCard.tsx
 @ ./components/molecules/ShowcaseCard/index.ts
 @ ./components/organisms/Showcase/Showcase.tsx
 @ ./components/organisms/Showcase/index.ts
 @ ./components/organisms/Showcase/Showcase.stories.tsx
 @ ./components sync ^\.(?:(?:^|\/|(?:(?:(?!(?:^|\/)\.).)*?)\/)(?!\.)(?=.)[^/]*?\.stories\.(js|jsx|ts|tsx))$
 @ ./generated-stories-entry.js
 @ multi ./node_modules/@storybook/core-client/dist/esm/globals/polyfills.js ./node_modules/@storybook/core-client/dist/esm/globals/globals.js (webpack)-hot-middleware/client.js?reload=true&quiet=false&noInfo=undefined ./storybook-init-framework-entry.js ./node_modules/@storybook/react/dist/esm/client/docs/config-generated-config-entry.js ./node_modules/@storybook/react/dist/esm/client/preview/config-generated-config-entry.js ./node_modules/@storybook/addon-links/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-docs/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-actions/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-backgrounds/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-measure/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-outline/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-interactions/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-a11y/preview.js-generated-config-entry.js ./node_modules/storybook-addon-next-router/dist/preset/addDecorator.js-generated-config-entry.js ./node_modules/storybook-addon-recoil-flow/dist/decorators.js-generated-config-entry.js ./.storybook/preview.js-generated-config-entry.js ./generated-stories-entry.js

ERROR in ./node_modules/@prismicio/next/dist/PrismicNextImage.mjs 50:16
Module parse failed: Unexpected token (50:16)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
|       width: layout === "fill" ? void 0 : field.dimensions.width,
|       height: layout === "fill" ? void 0 : field.dimensions.height,
>       alt: alt ?? (field.alt || fallbackAlt),
|       loader: imgixLoader,
|       layout,
 @ ./node_modules/@prismicio/next/dist/index.mjs 6:0-58 6:0-58
 @ ./utils/prismic/index.ts
 @ ./components/quarks/RichText/RichText.tsx
 @ ./components/quarks/RichText/index.ts
 @ ./components/molecules/ShowcaseCard/ShowcaseCard.tsx
 @ ./components/molecules/ShowcaseCard/index.ts
 @ ./components/organisms/Showcase/Showcase.tsx
 @ ./components/organisms/Showcase/index.ts
 @ ./components/organisms/Showcase/Showcase.stories.tsx
 @ ./components sync ^\.(?:(?:^|\/|(?:(?:(?!(?:^|\/)\.).)*?)\/)(?!\.)(?=.)[^/]*?\.stories\.(js|jsx|ts|tsx))$
 @ ./generated-stories-entry.js
 @ multi ./node_modules/@storybook/core-client/dist/esm/globals/polyfills.js ./node_modules/@storybook/core-client/dist/esm/globals/globals.js (webpack)-hot-middleware/client.js?reload=true&quiet=false&noInfo=undefined ./storybook-init-framework-entry.js ./node_modules/@storybook/react/dist/esm/client/docs/config-generated-config-entry.js ./node_modules/@storybook/react/dist/esm/client/preview/config-generated-config-entry.js ./node_modules/@storybook/addon-links/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-docs/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-actions/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-backgrounds/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-measure/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-outline/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-interactions/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-a11y/preview.js-generated-config-entry.js ./node_modules/storybook-addon-next-router/dist/preset/addDecorator.js-generated-config-entry.js ./node_modules/storybook-addon-recoil-flow/dist/decorators.js-generated-config-entry.js ./.storybook/preview.js-generated-config-entry.js ./generated-stories-entry.js

What is expected?

The Storybook runs, loading all the Prismic Images

What is actually happening?

The storybook run fails with the error described above

The types for Nextjs NextApiRequestLike definitions

Versions

  • @prismicio/next: 1.5.0
  • next: 14.0.4
  • node: 21.6.1

Reproduction

NextApiRequestLike types query does not match Next.js types. According to next.js types this value does not exist. I tried both app and pages. Same error.

TS2322: Type
IncomingMessage & {     cookies: Partial<{         [key: string]: string;     }>; }
is not assignable to type NextApiRequestLike | undefined
Property query is missing in type
IncomingMessage & {     cookies: Partial<{         [key: string]: string;     }>; }
but required in type NextApiRequestLike

the alt prop of the PrismicNextImage component has a type issue

Versions

  • @prismicio/next: 0.1.3
  • next: 12.3.0
  • node: 14.19.3

Reproduction

use prismicio-community/nextjs-starter-prismic-blog as sample project

Additional Details
package.json:
{
  "name": "test-next-theme",
  "version": "1.0.0",
  "license": "Apache-2.0",
  "scripts": {
    "dev": "concurrently \"npm:next:dev\" \"npm:slicemachine\" --names \"next,slicemachine\" --prefix-colors blue,magenta",
    "next:dev": "next",
    "build": "next build",
    "start": "next start",
    "test": "jest --watch",
    "test:ci": "jest --ci",
    "test:coverage": "jest --coverage",
    "lint": "next lint",
    "slicemachine": "start-slicemachine",
    "format": "prettier --write .",
    "gen": "prismic-ts-codegen",
    "prepare": "husky install"
  },
  "prettier": {
    "semi": false,
    "singleQuote": true,
    "printWidth": 80,
    "trailingComma": "none",
    "arrowParens": "avoid",
    "endOfLine": "auto"
  },
  "dependencies": {
    "@prismicio/client": "^6.7.1",
    "@prismicio/helpers": "^2.3.4",
    "@prismicio/next": "^0.1.3",
    "@prismicio/react": "^2.5.0",
    "@prismicio/slice-simulator-react": "^0.2.2",
    "clsx": "^1.2.1",
    "next": "12.3.0",
    "react": "18.2.0",
    "react-dom": "18.2.0"
  },
  "devDependencies": {
    "@commitlint/cli": "^8.0.0",
    "@commitlint/config-conventional": "^8.0.0",
    "@commitlint/prompt-cli": "^8.0.0",
    "@prismicio/types": "^0.2.3",
    "@tailwindcss/aspect-ratio": "^0.4.0",
    "@tailwindcss/typography": "^0.5.7",
    "@testing-library/jest-dom": "5.16.4",
    "@testing-library/react": "13.2.0",
    "@testing-library/user-event": "14.2.0",
    "@types/react": "18.0.20",
    "@typescript-eslint/eslint-plugin": "^5.21.0",
    "autoprefixer": "^10.4.11",
    "concurrently": "^7.3.0",
    "eslint": "8.22.0",
    "eslint-config-next": "12.2.5",
    "eslint-config-prettier": "^8.1.0",
    "eslint-plugin-import": "^2.26.0",
    "eslint-plugin-prettier": "^3.1.3",
    "jest": "28.1.0",
    "jest-environment-jsdom": "28.1.0",
    "husky": "^8.0.0",
    "postcss": "^8.4.16",
    "prettier": "^2.7.1",
    "prettier-plugin-tailwindcss": "^0.1.13",
    "prismic-ts-codegen": "^0.1.2",
    "slice-machine-ui": "^0.4.2",
    "tailwindcss": "^3.1.8"
  }
}

Steps to reproduce

cd your-project-name
npm i
npx @slicemachine/init

What is expected?

  • Add a non-empty string as the image alt prop

What is actually happening?

  • the PrismicNextImage only accepts the empty string ('') as the image alt prop

Screen Shot 2022-09-23 at 18 31 17

Possible fix

the alt and fallbackAlt of PrismicNextImageProps should be string type
Screen Shot 2022-09-23 at 18 38 51

Using old `useRouter` hook is breaking when using the `/app` directory on [email protected]

Versions

  • @prismicio/next: v1.0.2
  • next: v13.1.6
  • node: v16.19.0

Reproduction

Importing a function like enableAutoPreviews in a server component throws the following error:
image

Additional Details
{ "name": "marketing-site", "version": "0.1.0", "private": true, "scripts": { "dev:next": "pnpm clean && next dev", "test": "jest", "check-deadcode": "pnpm dlx unimported", "prismic-types": "pnpm dlx prismic-ts-codegen", "lint": "eslint --quiet --fix --ext ts,tsx,js,jsx ./", "lint:pkg": "npmPkgJsonLint .", "dev:slices": "pnpm storybook & pnpm slicemachine", "clean": "pnpm dlx rimraf out .next", "prebuild": "pnpm clean", "build": "NODE_ENV=production next build", "postbuild": "next-sitemap", "build:netlify": "pnpm build && next-sitemap", "build:analyze": "ANALYZE=true pnpm build", "start": "next start", "start:netlify": "netlify dev", "scripts:updateCarriersCSV": "node scripts/updateCarriersCSV.mjs", "storybook": "start-storybook -s ./public -p 8888", "build-storybook": "build-storybook -s ./public", "type-check": "tsc --noEmit", "slicemachine": "start-slicemachine --port 9999", "prepare": "husky install" }, "volta": { "node": "16.19.0", "pnpm": "7.26.2" }, "packageManager": "[email protected]", "lint-staged": { "*.{ts,js,tsx,jsx}": [ "eslint --fix", "prettier --write" ], "*.json": [ "prettier --write" ] }, "dependencies": { "@bugsnag/js": "7.20.0", "@bugsnag/plugin-react": "7.19.0", "@floating-ui/react": "0.16.0", "@getcircuit/colors": "1.3.1", "@getcircuit/electric-last-mile-calculator-commute": "0.1.2", "@getcircuit/electric-last-mile-calculator-delivery": "0.1.2", "@getcircuit/engine-client": "8.1.0", "@getcircuit/tailwind": "2.6.1", "@headlessui/react": "1.7.7", "@juggle/resize-observer": "3.4.0", "@prismicio/client": "6.7.3", "@prismicio/helpers": "2.3.5", "@prismicio/next": "1.0.2", "@prismicio/react": "2.5.0", "@prismicio/slice-simulator-react": "0.2.3", "@radix-ui/react-scroll-area": "0.1.3", "@radix-ui/react-tooltip": "1.0.0", "@tailwindcss/forms": "0.5.3", "@tailwindcss/typography": "0.5.9", "ariakit": "2.0.0-next.40", "axios": "1.3.1", "cheerio": "1.0.0-rc.12", "client-only": "^0.0.1", "clsx": "1.2.1", "flag-icons": "6.6.6", "follow-redirects": "1.15.2", "googleapis": "110.0.0", "http-status-codes": "2.2.0", "i18n-iso-countries": "7.5.0", "lodash.throttle": "4.1.1", "lottie-web": "5.10.2", "next": "13.1.6", "next-images": "1.8.4", "node-cache": "5.1.2", "react": "18.2.0", "react-device-detect": "2.2.2", "react-dom": "18.2.0", "react-intl": "6.2.7", "react-schemaorg": "2.0.0", "server-only": "^0.0.1", "slugify": "1.6.5" }, "devDependencies": { "@getcircuit/schema": "^0.8.88", "@getcircuit/web-utils": "1.11.6", "@kiwi/eslint-config": "2.0.4", "@kiwi/prettier-config": "2.0.4", "@netlify/plugin-nextjs": "4.30.3", "@next/eslint-plugin-next": "13.1.6", "@prismicio/types": "0.2.3", "@storybook/addon-actions": "6.5.16", "@storybook/addon-essentials": "6.5.16", "@storybook/addon-links": "6.5.16", "@storybook/addon-postcss": "2.0.0", "@storybook/react": "6.5.16", "@testing-library/dom": "8.20.0", "@testing-library/jest-dom": "5.16.5", "@testing-library/react": "13.4.0", "@testing-library/react-hooks": "8.0.1", "@testing-library/user-event": "14.4.3", "@types/intercom-web": "2.8.19", "@types/jest": "29.4.0", "@types/lodash.throttle": "4.1.7", "@types/node": "18.11.18", "@types/react": "18.0.27", "@types/react-dom": "18.0.10", "@typescript-eslint/parser": "5.50.0", "autoprefixer": "10.4.13", "eslint": "8.33.0", "eslint-config-next": "13.1.6", "eslint-plugin-storybook": "0.6.10", "git-repo-info": "2.1.1", "husky": "8.0.3", "jest": "29.4.1", "jest-environment-jsdom": "29.4.1", "jest-fetch-mock": "3.0.3", "lint-staged": "13.1.0", "netlify-cli": "12.10.0", "next-sitemap": "3.1.49", "npm-package-json-lint": "6.4.0", "postcss": "8.4.21", "prettier": "2.8.3", "prettier-plugin-tailwindcss": "0.2.2", "prismic-ts-codegen": "0.1.5", "schema-dts": "1.1.0", "slice-machine-ui": "0.5.1", "storybook-addon-next-router": "4.0.2", "tailwindcss": "3.2.4", "tsconfig-paths-webpack-plugin": "4.0.0", "typescript": "4.9.5", "webpack-bugsnag-plugins": "1.8.0", "webpack-bundle-analyzer": "4.7.0" } }

Steps to reproduce

  1. Create a server component
  2. Create a function createClient that imports and use enableAutoPreviews in this server component
  3. Use this function

What is expected?

That the app works with no problems

What is actually happening?

The app throws an error.

Warning in Next.js serverActions mod

Versions

  • @prismicio/next: 1.3.5
  • next: 13.5.3
  • node: 18.18.0

Reproduction

I just want to use the PrismicNextLink component as it is in the example. But it throws an error when I set the following in the next.config.js:

  experimental: {
    serverActions: true,
  },
<PrismicNextLink field={item.menu_item_link} >
  {item.menu_item}
</PrismicNextLink>

I would need the new serverActions mode.

Additional Details
Warning: An empty string ("") was passed to the href attribute. To fix this, either do not render the element at all or pass null to href instead of an empty string. at a at LinkComponent (webpack-internal:///(ssr)/./node_modules/next/dist/client/link.js:105:19) at PrismicNextLink2 (webpack-internal:///(ssr)/./node_modules/@prismicio/next/dist/PrismicNextLink.js:18:99)

Steps to reproduce

You need to set the serverActions parameter in the next.config.js.

What is expected?

What is actually happening?

RFC: @prismicio/next alpha feedback

Overview

@prismic/next is a new package designed for making Prismic easier to use with a NextJS project. The original RFC from @angeloashmore and provides more background:

#1

At the moment, the package is mostly focused around making it easier to to set up Prismic Previews with Next. As Next and/or Prismic itself release more updates, it's possible that this package could grow and adapt to whatever new features come out if necessary.

For this RFC, we'd like to gather feedback on the implementation from a developer experience perspective. Should we be doing more, should we be doing less? Could things be done in an easier, simpler way for the end user?

enableClientServerSupport

export const enableClientServerSupport = (
	config: EnableClientServerSupportConfig,
): void => {
	if ("context" in config && config.context) {
		const previewData = config.context.previewData;

		if (isPrismicNextPreviewData(previewData) && previewData.ref) {
			config.client.queryContentFromRef(previewData.ref);
		}
	} else if ("req" in config && config.req) {
		config.client.enableAutoPreviewsFromReq(config.req);
	}
};

enableClientServerSupport is a function that allows the end user to enable Previews with either PreviewData coming from NextJS context or a Prismic ref coming from the NextApiRequest. It's intended to be used in an end users createClient() function, like this:

import { enableClientServerSupport, CreateClientConfig } from 'prismic-next';

export const createClient = (config: CreateClientConfig) => {
  const client = Prismic.createClient(apiEndpoint);

  enableClientServerSupport({
    client,
    context: config.context,
    req: config.req,
  });

  return client;
};

One thing we've been wondering is whether or not @prismic/next should offer its own createClient function that would run enableClientServerSupport under the hood. On one hand, it'd be nice to not have to worry about creating your own client, however, the fear is that we might deal with feature creep as users might have more needs with creating client outside of what we provide.

Would love to get feedback on whether or not we might want to provide one on our own or leave it as is.

<PrismicPreview />

The PrismicPreview component is to be wrapped around the entire NextJS app. There are two reasons why we have this component:

  1. It's job is to add the PrismicToolbar to a NextJS app, there's a required param called repoName where you just pass it the name of your Prismic Repo and the correct URL for the toolbar is added in the necessary <script /> tag.

  2. There is a useEffect hook that adds event listeners that come from the Prismic Toolbar, so it can properly update when the Preview URL is triggered. It's listening for both prismicPreviewUpdate and prismicPreviewEnd.

By default, the updatePreviewURL is /api/preview and the exitPreviewURL is /api/exit-preview. The end user has an option to override both of those by passing their own URLs to the props. Here's what it looks like in usage:

import { PrismicPreview } from 'prismic-next';

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <PrismicPreview repoName='smashing-mag-nick-1'>
      <Component {...pageProps} />;
    </PrismicPreview>
  );
}

export default MyApp;

setPreviewData & redirectToPreviewURL

These are actually really straight forward, to be used when the prismicUpdatePreview event gets triggered from the toolbar. Usage:

import { linkResolver, createClient } from '../../prismic-config';
import * as prismicNext from 'prismic-next';
import { NextApiRequest, NextApiResponse } from 'next';

export default async (req: NextApiRequest, res: NextApiResponse) => {
  const client = createClient({ req });

  prismicNext.setPreviewData({ req, res });

  await prismicNext.redirectToPreviewURL({ res, client, linkResolver });
};

Here is how they look under the hood:

redirectToPreviewURL

import { NextApiResponse } from "next";
import { Client } from "@prismicio/client";
import { LinkResolverFunction } from "@prismicio/helpers";

export type PreviewConfig = {
	res: NextApiResponse;
	client: Client;
	linkResolver: LinkResolverFunction;
};

export async function redirectToPreviewURL({
	res,
	client,
	linkResolver,
}: PreviewConfig): Promise<void> {
	const previewUrl = await client.resolvePreviewURL({
		linkResolver,
		defaultURL: "/",
	});

	res.redirect(previewUrl);
}

setPreviewData

import { NextApiResponse, NextApiRequest } from "next";

export type PreviewConfig = {
	req: NextApiRequest;
	res: NextApiResponse;
};

export async function setPreviewData({
	req,
	res,
}: PreviewConfig): Promise<void> {
	const { token: ref } = req.query;

	res.setPreviewData({ ref });
}

exitPreview

This one is also pretty straight forward. Usage:

import { NextApiResponse } from 'next';
import { exitPreview } from 'prismic-next';

export default async function exit(_: any, res: NextApiResponse) {
  exitPreview(_, res);
}

Under the hood:

export async function exitPreview(_: any, res: NextApiResponse): Promise<void> {
	// Exit the current user from "Preview Mode". This function accepts no args.
	res.clearPreviewData();

	// Redirect the user back to the index page.
	res.writeHead(307, { Location: "/" });
	res.end();
}

Note

There is still some feedback left on these implementations that have yet to be applied, the intent of this RFC is to really focus on the end user usage, not collect feedback on the Pull Request itself. If you do want to give feedback about code quality, feel free to leave that feedback on the PR:

#3

Make Prismic Preview work with `next export`

Is your feature request related to a problem? Please describe.

When using the <PrismicPreview /> component in a NextJS application, the application can no longer be exported using next export. This is due to the usage of NextJS' <Image /> component inside the <PrismicPreview /> component. Next's image component is not compatible with exporting, see: https://nextjs.org/docs/messages/export-image-api

Describe the solution you'd like

Maybe a possible solution would be to allow passing a custom image loader to the PrismicPreview component, or even better just a simple boolean prop to opt-out of the image optimization.

Describe alternatives you've considered

  • Disabling the image optimization globally for the whole next application is not possible unfortunately.
  • Of course not exporting the application would be an option, but that would require us to change our hosting provider

Additional context

Versions used:

@prismicio/next@^0.1.3
next@^12.1.5

The error message of nextjs when exporting an application that uses <PrismicPreview />:

# next export
# ... build logs

Error: Image Optimization using Next.js' default loader is not compatible with `next export`.
  Possible solutions:
    - Use `next start` to run a server, which includes the Image Optimization API.
    - Use any provider which supports Image Optimization (like Vercel).
    - Configure a third-party loader in `next.config.js`.
    - Use the `loader` prop for `next/image`.
  Read more: https://nextjs.org/docs/messages/export-image-api
    at /Users/rvoellmy/nobank/frontend/node_modules/next/dist/export/index.js:156:23
    at async Span.traceAsyncFn (/Users/rvoellmy/nobank/frontend/node_modules/next/dist/trace/trace.js:79:20)

The recommended `/api/exit-preview` is cached on Vercel and only works on the first visit

Versions

  • @prismicio/next: v0.1.3
  • next: v12.2.4
  • node: v16.15.0

Reproduction

https://github.com/prismicio-community/nextjs-starter-prismic-blog

Steps to reproduce

Note: When testing, ensure that caching is enabled in the browser (i.e. the "Disable cache" setting is unchecked) and that the DevTools is closed.

  • Deploy site to Vercel
  • Edit a page and preview on production
  • Exit the preview and verify Preview Mode is no longer active
  • Start a new preview
  • Exit the preview and verify Preview Mode is still active

What is expected?

Previews exit as many times as needed.

What is actually happening?

It only exits the first time. Any subsequent attempt is not exited. However, the Prismic preview token is removed and the request to /api/exit-preview is successful.

This happens because the endpoint returns a 200 status code. Vercel caches 200 GET requests at the Edge. To prevent the endpoint from being cached, a non-200 status code must be sent, or a non-GET request must be used.

More details are available here: https://vercel.com/docs/concepts/functions/serverless-functions/edge-caching

File `libraries-state.json` not found inside '.slicemachine' folder

Versions

  • @prismicio/next: "^1.0.2"
  • next: "13.1.1"
  • node: v18.12.1

Reproduction

I followed the prismic documentation to install and configure Prismic in a Next.js project. Both nextjs as well as slicemachine ran without issues up to this point. But when I create a slice in slicemachine and try to simulate the newly created slice, simulator tab (in browser) shows;

image

And the tab running nextjs shows the following error;

image

If I add the file libraries-state.json, with an empty object, inside the .slicemachine folder manually there will be no such errors. But again, the file remains empty even while creating and updating slices in slicemachine, which I believe is not the expected behavior.

Updating library into latest version causes app to crash because of the "PrismicPreview" component.

Versions

  • @prismicio/next: 1.1.0
  • next: 13.4.3
  • node: v17.8.0

Reproduction

Was updating my current project libraries and had only problem when updating this library into latest version. Current package.json looks following (on my latest branch, not at master yet):

"dependencies": { "@apollo/client": "^3.7.14", "@prismicio/client": "^6.8.0", "@prismicio/helpers": "^2.3.9", "@prismicio/next": "^1.1.0", "@prismicio/react": "^2.6.1", "@prismicio/slice-simulator-react": "^0.2.3", "@types/node": "18.11.12", "@types/react": "18.0.26", "@types/react-dom": "18.0.9", "apollo-link": "^1.2.14", "apollo-link-http": "^1.5.17", "classnames": "^2.3.2", "eslint": "8.29.0", "eslint-config-next": "13.0.6", "graphql": "^15.8.0", "html-react-parser": "^3.0.16", "next": "^13.4.3", "react": "18.2.0", "react-dom": "18.2.0", "typescript": "4.9.4" }, "devDependencies": { "@graphql-codegen/cli": "^3.3.1", "@graphql-codegen/client-preset": "^3.0.1", "@graphql-codegen/fragment-matcher": "^4.0.1", "@prismicio/types": "^0.2.7", "@slicemachine/adapter-next": "^0.1.3", "@types/node-fetch": "^2.6.4", "autoprefixer": "^10.4.13", "dotenv": "^16.0.3", "node-fetch": "^2.6.11", "postcss": "^8.4.19", "slice-machine-ui": "^1.0.3", "tailwindcss": "^3.3.2", "ts-node": "^10.9.1" }

I have found the issue at on my _app.tsx file, which looks following:

Screenshot 2023-05-19 at 16 23 50

And the variable called prismicRepositoryName is equal to the following:

export const prismicRepositoryName = process.env.PRISMIC_REPOSITORY_NAME || '';

So if I either remove the PrismicPreview component or "hardcode" the variable into string e.g:

<PrismicPreview repositoryName={"myRepositoryName"}>

Then following error won't come:

Screenshot 2023-05-19 at 16 27 41

Steps to reproduce

  1. Make sure that PrismicPreview components "repositoryName" prop is using the env. variable
  2. Install first @prismicio/next version 1.0.3
  3. Then install latest version (1.1.0)
  4. App should crash and error regarding invalid repository name

What is expected?

Expecting that I could use env. variables with the PrismicPreview component, so that app won't crash on initial load.

What is actually happening?

App crashing on initial load.

Expose PrismicPreviewProps type

Versions

  • package_name: v0.0.4
  • node: v14.18.3

Reproduction

Using next dynamic import, the following function return a component typed React.ComponentType<{}>:

const PrismicPreview = dynamic(
  () => import('@prismicio/next').then((res) => res.PrismicPreview),
  { ssr: false },
)

Steps to reproduce

N/A

What is expected?

We should be able to pass PrismicPreviewProps to the next dynamic function generic (which actually exists).

What is actually happening?

PrismicPreviewProps is currently not exposed.

RFC: @prismicio/next

Overview

@prismicio/next is a new, yet to be written package designed to ease development when integrating Prismic with Next.js. It is both a library and a set of architecture recommendations for Next.js users.

It is targeted for users using Next.js directly, whether alongside other data sources, such as APIs and the file system, or exclusively with Prismic.

This package should make adoption of Prismic within Next.js a more pleasant experience, with most manual work automated through helpful functions.

This package and the surrounding concepts have the following goals:

  • Easily fetch Prismic content
  • Easily display Prismic content
  • Easily integrate with Preview Mode
  • Remain flexible and cognizant of users' own logic

"Easily" means easy to setup, but also easy to maintain and produce sustainable projects.

Background Information

Prismic's integration with Next.js is currently handled in two ways:

  1. A first-class Slice Machine integration composed of custom code generators, Slice Machine-specific functions, and React components.
  2. Starter projects with a suggested project organization to orchestrate fetching and displaying Prismic data.

This leaves a gap between the two approaches: developers who are familiar with Next.js with existing projects and developers who will be using Prismic outside of Slice Machine.

Developers in those groups are currently left to wire up solutions themselves. This can lead to error-prone code, additional maintenance burdens, and frustration.

Ultimately, this could drive users away from Prismic.

Proposal

Concepts from Slice Machine's integration with Next.js can be made more general. By making them less Slice Machine-specific, any user of Next.js—and, in some cases, React—can take advantage of the abstractions.

This is not a duplication of efforts. Instead, code generated and used by Slice Machine will come from @prismicio/next.

The following concepts and abstractions can be provided by the new package. Some come from Slice Machine, while others are new and unique to this approach.

Embrace Next.js' concepts

Users should use Next.js and its features as the Next.js team intends. By doing so, all documentation, examples, and best practices for Next.js will apply to these users' projects. As new Next.js features are introduced, they can be integrated into users' projects by the users themselves.

It should follow, then, that @prismicio/next works within the paradigms of Next.js. It should embrace the framework's core features, such as getStaticPaths and getStaticProps. It should provide solutions that are flexible and configurable, much like Next.js itself.

It should not try to hide Next.js features. It should not provide solutions that close off users from extending functionality.

Working to Next.js' strengths will also make the Prismic integration stronger.

Embrace Prismic core libraries

This proposal builds upon previous proposals and efforts to strengthen and simplify lower-level Prismic libraries. For example, by simplifying the core JavaScript client library, @prismicio/client, we have made data fetching in Next.js simpler as well.

These efforts should be embraced and used directly within Next.js.

For context, the opposite of this approach would involve hiding lower-level functionality behind single-task black boxes. This leads to technical debt as users can no longer extend that single task without updates to the library with fragmentation of usage.

Consider the following example for setting up getStaticPaths and getStaticProps:

import { useGetStaticProps, useGetStaticPaths } from "next-slicezone/hooks";

import { Client } from "../prismic-configuration";

export const getStaticProps = useGetStaticProps({
	client: Client(),
	uid: ({ params }) => params.uid,
});

export const getStaticPaths = useGetStaticPaths({
	client: Client(),
	type: "page",
	fallback: process.env.NODE_ENV === "development",
	formatPath: ({ uid }) => ({ params: { uid } }),
});

And the more flexible, albeit more verbose, counterpart:

import * as prismicNext from "@prismicio/next";
import * as prismicH from "@prismicio/helpers";

import { createClient, linkResolver } from "../prismic";

export const getStaticProps = async (context) => {
	const client = createClient();
	prismicNext.enableClientServerSupportFromContext(client, context);

	const uid = context.params.uid;
	const page = await client.getByUID("page", uid);

	return {
		props: { page },
	};
};

export const getStaticPaths = async () => {
	const client = createClient();
	const pages = await client.getAllByType("page");
	const paths = pages.map((page) => ({
		params: {
			uid: page.uid,
			pagePath: prismicH.documentAsLink(page, linkResolver).split("/"),
		},
	}));

	return { paths, fallback: true };
};

The first example showcases single-task black boxes to output data Next.js expects. It allows a user to configure its output through different string and function options. Someone familiar with Next.js, but unfamiliar with next-slicezone/hooks, may not understand what is happening or what the options affect.

The second example performs the same tasks as the first, but takes a more functional approach. Rather than providing single-task black boxes, @prismicio/next provides small functions to be used throughout a user's own logic. In this example, that logic includes using @prismicio/client directly to fetch documents, allowing the user to perform that work as they see fit. Someone familiar with Next.js, but unfamiliar with @prismicio/next, could read the code, have a general understanding of its effects, and know how to extend it.

Although neither example shows how TypeScript would be integrated, it should be clear how it can be added to the second example.

Provide small helper functions

The following helper functions abstract common tasks while allowing a user to use them as they see fit.

  • buildPreviewDataFromReq - Builds a Next.js Preview Mode data object from an API req object. This is used to automate some of the work needed to support previews.
  • getPreviewRefFromContext - Extracts a preview ref from a Next.js context object for use with Preview Mode. enableClientServerSupportFromContext uses this function internally.
  • enableClientServerSupportFromContext - Enables server support for a @prismicio/client from a Next.js context object. This can be used in any Next.js API that provides the request context, such as getStaticProps, getServerProps, and getInitialProps.

How could it be implemented

The library would consist of the above small helper functions. As such, implementations should be straightforward.

// enableClientServerSupportFromContext.ts

import * as nextT from "next/types";
import * as prismic from "@prismicio/client";

import { getPreviewRefFromContext } from "./getPreviewRefFromContext";

export const enableClientServerSupportFromContext = (
	client: prismic.Client,
	context: nextT.GetStaticPropsContext
): void => {
	const ref = getPreviewRefFromContext(context);

	if (ref) {
		client.queryContentFromRef(ref);
	}
};
// getPreviewRefFromContext.ts

import * as nextT from "next/types";

import { PrismicNextPreviewData } from "../types";

const isPrismicNextPreviewData = (
	previewData: nextT.PreviewData
): previewData is PrismicNextPreviewData =>
	typeof previewData === "object" && "ref" in previewData;

export const getPreviewRefFromContext = (
	context: nextT.GetStaticPropsContext
): string | undefined => {
	if (isPrismicNextPreviewData(context.previewData)) {
		return context.previewData.ref;
	}
};
// buildPreviewDataFromReq.ts

import * as nextT from "next/types";

import { PrismicNextPreviewData } from "../types";

export const buildPreviewDataFromReq = (
	req: nextT.NextApiRequest
): PrismicNextPreviewData => {
	if (Array.isArray(req.query.token)) {
		return {
			ref: req.query.token[0]
		};
	}

	return {
		ref: req.query.token
	};
};

From these functions, users can setup Preview Mode easily:

// pages/api/preview.ts

import * as nextT from "next/types";
import * as prismicNext from "@prismicio/next";

import { buildPreviewDataFromReq } from "../../lib/buildPreviewDataFromReq";
import { createClient, linkResolver } from "../../prismic";

export default async function handler(
	req: nextT.NextApiRequest,
	res: nextT.NextApiResponse
): Promise<void> {
	const client = createClient();
	client.enableServerSupportFromReq(req);

	const previewData = prismicNext.buildPreviewDataFromReq(req);
	const resolvedURL = await client.resolvePreviewURL({ linkResolver });

	res.setPreviewData(previewData);
	res.redirect(resolvedURL);
}
// pages/api/exit-preview.ts

import * as nextT from "next/types";

export default function handler(
	_req: nextT.NextApiRequest,
	res: nextT.NextApiResponse
): void {
	res.clearPreviewData();
}

The Preview Mode entry handler (pages/api/preview.ts) is recommended to be implemented within a project rather than via a helper method (e.g. createPrismicPreviewModeAPIHandler). This simplifies @prismicio/client instance management and allows a user to customize the handler.

If you have a good suggestion on how this could be more automated, please share!

How to provide feedback

Everything described above is open for feedback.

Do you think @prismicio/next should do more? Be more opinionated? Or less?

If you have comments, please share them here. ✌️

Transpiling package using NextJS transpilePackages config causes issues with "use client" directive

Versions

  • @prismicio/next: v1.3.4
  • next: v13.4.19
  • node: v16.17.0, v18.17.1

Reproduction

Additional Details
{
  "name": "prismic-test",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "slicemachine": "start-slicemachine"
  },
  "dependencies": {
    "@prismicio/client": "^7.2.0",
    "@prismicio/next": "^1.3.4",
    "@prismicio/react": "^2.7.1",
    "autoprefixer": "10.4.15",
    "eslint": "8.48.0",
    "eslint-config-next": "13.4.19",
    "next": "^13.4.19",
    "postcss": "8.4.29",
    "react": "18.2.0",
    "react-dom": "18.2.0",
    "tailwindcss": "3.3.3"
  }
}

Steps to reproduce

  1. Run npx create-next-app@latest and npx @slicemachine/init@latest with App Router enabled
  2. In the next.config.js file add the following to the nextConfig
const nextConfig = {
  transpilePackages: ["@prismicio/client", "@prismicio/next"]
}
  1. Create a component as follows
"use client"

import { PrismicNextLink } from "@prismicio/next"

export default function StyledLink() {
  return <PrismicNextLink />
}
  1. Import and render the new component into a page.js in your app directory
  2. Attempt to navigate to the page with component included and see a Server Component error

What is expected?

PrismicNextLink will render the same with or without the "use client" directive, as it does so when not transpiling the packages using NextJS configuration

What is actually happening?

The new component throws the following fatal error

ReactServerComponentsError:

You're importing a component that needs next/headers. That only works in a Server Component but one of its parents is marked with "use client", so it's a Client Component.
Learn more: https://nextjs.org/docs/getting-started/react-essentials

 1 | import { jsxs, Fragment, jsx } from "react/jsx-runtime";
 2 | import Script from "next/script";
 3 | import { draftMode } from "next/headers";
   : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 4 | import { PrismicPreviewClient } from "./PrismicPreviewClient.js";
 5 | import { getToolbarSrc } from './_node_modules/@prismicio/client/dist/getToolbarSrc.js';
 6 | function PrismicPreview({ repositoryName, children, ...props }) {
   `----

One of these is marked as a client entry with "use client":
  ./node_modules\@prismicio\next\dist\PrismicPreview.js
  ./node_modules\@prismicio\next\dist\index.js
  ./components\StyledLink.js

PreviewMenu is not displaying in Safari

Versions

  • @prismicio/next: v0.1.2
  • next: v12.1.0

What is expected?

The blue PreviewMenu to display in the bottom left corner of the screen when viewing the preview of a document.

What is actually happening?

PreviewMenu is not displaying on Safari version 15.4 where as it is displaying fine in Google Chrome and Firefox.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.