Next-Slicezone 'module parse failed' when using with Prismic.io

372 Views Asked by At

I'm not sure what I'm doing wrong, and the documentation is pretty spotty and nobody on Prismic's Community board is very responsive. I'm hoping somebody can help me here:

I'm trying to use slicezone for nextjs, and I'm following along with the documentation and I'm 'missing a loader' for slicezone.

The error:

./node_modules/next-slicezone/index.js
Module parse failed: Unexpected token (6:2)
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
| 
| const PageInfo = ({ title, description }) => (
>   <div
|     style={{
|       height: '80vh',

My page:

import { client } from '../../../prismic-configuration'
import Prismic from '@prismicio/client'
import { SliceZone } from 'next-slicezone'
import { useGetStaticProps, useGetStaticPaths} from 'next-slicezone/hooks'
import resolver from '../../../sm-resolver'

const CategoryProduct = ({slices}) => {
  return(
    <div>

    </div>
  )
}

export async function getStaticProps(props) {
  const { params: { uid, category }} = props
  console.log(uid, category)
  const products = await client.query([
    Prismic.Predicates.at('', 'product'),
  ])
  const prods = {
    props: {
      products
    }
  }

  return prods
}

export async function getStaticPaths() {
  const results = {
    paths: [
      {
        params: {
          uid: 'handmade-film-transitions',
          category: 'transitions'
        }
      }
    ], fallback: false
  }
  return results
}

I should note that when I remove next-slicezone and just leave the prismic query, everything works just fine. I've looked at my configuration files, and everything seems to be in order.

Here's the sm-resolver.js that it auto-installed for me (which I think may be the culprit). Not sure where to go:

module.exports = {
  apiEndpoint: 'https://edit-elements.cdn.prismic.io/api/v2',
  repoName: "edit-elements",
  linkResolver: function(doc) {
      if (doc.isBroken) {
          return '/404';
      }
      if (doc.type === 'home') {
          return '/';
      }
      if (doc.type === 'page') {
          return '/page/' + doc.uid
      }
      if (doc.type === 'shop') {
          return `/shop/${doc.uid}`
      }
      return '/'
  }
}

I'm sure I'm doing something wrong because the docs are pretty nebulous (especially having to integrate with an already-setup repo), so any help would be greatly appreciated. :)

1

There are 1 best solutions below

0
On

The issue was the version (as I and others) have set up doesn't work out of the box. You have to use next-transpile-modules (in its current state). sm-resolver is just for link-building (from Prismic support).

Here is the solution:

next.config.js:

const withPlugins = require('next-compose-plugins')
const withSvgr = require('next-svgr')
const withTM = require('next-transpile-modules')(['next-slicezone'])

module.exports = withPlugins([
  withTM,
  withSvgr],
  {
    future: 
    {
      webpack5: true
    },
    modules: true,
  },
)

package.json:

{
  "name": "edit-elements",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "storybook": "start-storybook -p 8888",
    "build-storybook": "build-storybook",
    "slicemachine": "start-slicemachine --port 9999"
  },
  "dependencies": {
    "@emotion/react": "^11.4.0",
    "@emotion/styled": "^11.3.0",
    "@material-ui/core": "^5.0.0-alpha.31",
    "@material-ui/icons": "^4.11.2",
    "@material-ui/lab": "^4.0.0-alpha.58",
    "@prismicio/client": "^4.0.0",
    "@storybook/react": "^6.2.9",
    "clsx": "^1.1.1",
    "essential-slices": "^1.0.4",
    "firebase": "^8.2.1",
    "firebase-admin": "^9.4.2",
    "firebaseui": "^4.7.1",
    "framer-motion": "^3.1.1",
    "jose": "^3.12.3",
    "next": "^10.2.1",
    "next-compose-plugins": "^2.2.1",
    "next-slicezone": "0.1.0-alpha.0",
    "next-svgr": "^0.0.2",
    "next-transpile-modules": "^6.4.1",
    "prismic-dom": "^2.2.5",
    "prismic-reactjs": "^1.3.3",
    "react": "17.0.1",
    "react-dom": "17.0.1",
    "react-paypal-button-v2": "^2.6.3",
    "react-player": "^2.9.0",
    "react-resize-detector": "^6.7.2",
    "sass": "^1.32.4",
    "slice-machine-ui": "^0.0.46",
    "storybook": "^6.2.9",
    "styled-components": "^5.2.1",
    "theme-ui": "^0.7.3"
  },
  "devDependencies": {
    "babel-plugin-react-require": "^3.1.3"
  }
}

An example of a working dynamic page [category]/[uid]:

import { client } from '../../../prismic-configuration'
import Prismic from '@prismicio/client'
import { Divider, Grid, Typography, makeStyles } from '@material-ui/core'
import SliceZone from 'next-slicezone'
import { useGetStaticPaths, useGetStaticProps } from 'next-slicezone/hooks'
import SliceResolver from '../../../sm-resolver'
import AddToCartButton from '../../../components/AddToCartButton'
import { SignJWT } from 'jose/jwt/sign'
import { useEffect, useRef, useState } from 'react'

const theme = makeStyles({
  'section': {
    margin: '3rem auto'
  },
  outer: {
    padding: '1rem .5rem'
  },
  container: {
    margin: 'auto',
  },
  slim: {
    margin: 'auto',
    maxWidth: '1200px',
  },
  productImg: {
    width: '100%',
    height: 'auto',
    maxWidth: '500px'
  },
  productTitle: {
    marginTop: '3rem'
  },
  justifyText: {
    textAlign: 'justify'
  },
  wideDivide: {
    margin: '3em auto'
  },
  strike: {
    textDecoration: 'line-through',
    fontSize: '1.5rem',
    color: '#999999'
  }
})

const CategoryProduct = (props) => {
  const [ currentProduct, setCurrentProduct ] = useState(null)

  useEffect(() => {
    const { product } = props
    console.log('useEffect props', product)
    setCurrentProduct(prevState => product)
    console.log('loaded product', currentProduct)
  }, [currentProduct])

  const product = props.product
  const slices = product.data.body
  const { featured_image, price, on_sale, sale_price, title, short_description } = product.data
  const styles = theme()
  return(
    <Grid container direction="column" mt={6} className={styles.outer}>
      <Grid container style={{marginBottom: '6rem'}} className={styles.slim} justifyContent="center">
        <Grid item xs={4} md={6}>
          <img className={styles.productImg} src={featured_image.medium.url} />
        </Grid>
        <Grid item xs={8} md={6} sx={{textAlign: 'right'}}>
          <Typography className={styles.productTitle} variant="h1">{title[0].text}</Typography>
          <Typography mb={2} variant="h4">{on_sale && sale_price ? <div><span className={styles.strike}>${price}</span>&nbsp;${sale_price}</div> : `$${price}`}</Typography>
          <AddToCartButton product={product} />
          <Divider className={styles.wideDivide} />
          <Typography className={styles.justifyText}>{short_description[0].text}</Typography>
        </Grid>
      </Grid>
      <Grid container direction="column" className={[styles.slices, styles.slim].join(' ')}>
        <SliceZone resolver={SliceResolver} slices={slices} />
      </Grid>
    </Grid>
  )
}

export const getStaticProps = async ({params}) => {
  const product = await client.getByUID('product', params.uid)
  const { price, sale_price } = product.data
  // Where we return the specific product's data
  return {
    props: {
      product
    }
  }
}

export const getStaticPaths = useGetStaticPaths({
  client: client,
  type: 'product',
  formatPath: (doc) => {
    // Where we return paths for /category/uid for static pages
    return {
      params: {
        category: doc.data.category.uid,
        uid: doc.uid 
      }
    }
  }
})
export default CategoryProduct