Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

Importing Payload components causes SyntaxError on the front-end #45

Closed
imCorfitz opened this issue Jul 18, 2023 · 14 comments
Closed

Importing Payload components causes SyntaxError on the front-end #45

imCorfitz opened this issue Jul 18, 2023 · 14 comments

Comments

@imCorfitz
Copy link
Contributor

I have tried to add a color-picker field to a global in Payload, but the moment I call the useField hook or useFieldType hook, it seems that the front-end is having issues - outputting following in the terminal:

- error /my-app/node_modules/payload/dist/admin/components/forms/Label/index.scss:1
@import '../../../scss/styles.scss';
^

SyntaxError: Invalid or unexpected token
    at internalCompileFunction (node:internal/vm:73:18)
    at wrapSafe (node:internal/modules/cjs/loader:1176:20)
    at Module._compile (node:internal/modules/cjs/loader:1218:27)
    at Module._extensions..js (node:internal/modules/cjs/loader:1308:10)
    at Module.load (node:internal/modules/cjs/loader:1117:32)
    at Module._load (node:internal/modules/cjs/loader:958:12)
    at Module.require (node:internal/modules/cjs/loader:1141:19)
    at require (node:internal/modules/cjs/helpers:110:18)
    at Object.<anonymous> (/my-app/node_modules/payload/dist/admin/components/forms/Label/index.js:10:1)
    at Module._compile (node:internal/modules/cjs/loader:1254:14) {
  digest: undefined
}

How to replicate

  1. Spin up a new next installation.
  2. Follow the next-payload installation directions.
  3. Create a Field.tsx file in the payload directory with following:
import React from "react";
import { Label } from "payload/components/forms";
import { Props } from "payload/components/fields/Text";

const LabelField: React.FC<Props> = (props) => {
  const { path, required, label } = props;

  return (
    <div>
      <Label htmlFor={path} label={label} required={required} />
    </div>
  );
};

export default LabelField;
  1. Update payload.config.ts as follows:
import path from "path";
import { buildConfig } from "payload/config";
import Field from "./Field";

export default buildConfig({
  collections: [
    // Your collections here
  ],
  globals: [
    // Your globals here
    {
      slug: "header",
      fields: [
        {
          name: "custom",
          type: "text",
          admin: {
            components: {
              Field,
            },
          },
        },
      ],
    },
  ],
  typescript: {
    outputFile: path.resolve(__dirname, "../payload-types.ts"),
  },
});
  1. Finally call the getPayloadClient() function on the front-end e.g. by updating the default layout.tsx file like this:
import getPayloadClient from '@/payload/payloadClient'
import './globals.css'
import type { Metadata } from 'next'
import { Inter } from 'next/font/google'

const inter = Inter({ subsets: ['latin'] })

export const metadata: Metadata = {
  title: 'Create Next App',
  description: 'Generated by create next app',
}

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body className={inter.className}>{children}</body>
    </html>
  )
}

async function getSiteSettings() {
  const payload = await getPayloadClient();

  return {};
}

This will cause the error on the front-end. And if one goes in the the Field.tsx file and simply remove the imported <Label /> component from Payload, then no errors appear.

I have also tried not to use the Payload components, but when I call the useField() hook, it causes the same error.

@imCorfitz
Copy link
Contributor Author

I did some further research on the problems this morning, and it is quite clear it is Next.js that messes with it. Creating a clean Next.js with next-payload installation with following versions:

"dependencies": {
    "@payloadcms/next-payload": "^0.0.31",
    "@radix-ui/react-slot": "^1.0.2",
    "@types/node": "20.4.2",
    "@types/react": "^18.2.15",
    "@types/react-dom": "^18.2.7",
    "eslint": "8.45.0",
    "eslint-config-next": "13.4.10",
    "next": "13.4.10",
    "payload": "^1.11.2",
    "react": "18.2.0",
    "react-dom": "18.2.0",
    "typescript": "5.1.6"
  },

Then I installed the @payloadcms/plugin-seo and added the plugin to a clean payload.config.ts file:

 plugins: [
    seo({
      collections: [],
    }),
  ],

And it outputted the following errors:

- error /my-app/node_modules/payload/dist/admin/components/forms/Label/index.scss:1
@import '../../../scss/styles.scss';
^

SyntaxError: Invalid or unexpected token
    at internalCompileFunction (node:internal/vm:73:18)
    at wrapSafe (node:internal/modules/cjs/loader:1176:20)
    at Module._compile (node:internal/modules/cjs/loader:1218:27)
    at Module._extensions..js (node:internal/modules/cjs/loader:1308:10)
    at Module.load (node:internal/modules/cjs/loader:1117:32)
    at Module._load (node:internal/modules/cjs/loader:958:12)
    at Module.require (node:internal/modules/cjs/loader:1141:19)
    at require (node:internal/modules/cjs/helpers:110:18)
    at Object.<anonymous> (/my-app/node_modules/payload/dist/admin/components/forms/Label/index.js:10:1)
    at Module._compile (node:internal/modules/cjs/loader:1254:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1308:10)
    at Module.load (node:internal/modules/cjs/loader:1117:32)
    at Module._load (node:internal/modules/cjs/loader:958:12)
    at Module.require (node:internal/modules/cjs/loader:1141:19)
    at require (node:internal/modules/cjs/helpers:110:18)
    at Object.<anonymous> (/my-app/node_modules/payload/dist/admin/components/forms/field-types/Text/Input.js:8:33)
    at Module._compile (node:internal/modules/cjs/loader:1254:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1308:10)
    at Module.load (node:internal/modules/cjs/loader:1117:32)
    at Module._load (node:internal/modules/cjs/loader:958:12)
    at Module.require (node:internal/modules/cjs/loader:1141:19)
    at require (node:internal/modules/cjs/helpers:110:18)
    at Object.<anonymous> (/my-app/node_modules/payload/dist/admin/components/forms/field-types/Text/index.js:33:33)
    at Module._compile (node:internal/modules/cjs/loader:1254:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1308:10)
    at Module.load (node:internal/modules/cjs/loader:1117:32)
    at Module._load (node:internal/modules/cjs/loader:958:12)
    at Module.require (node:internal/modules/cjs/loader:1141:19)
    at require (node:internal/modules/cjs/helpers:110:18)
    at Object.<anonymous> (/my-app/node_modules/payload/components/forms.js:27:16)
    at Module._compile (node:internal/modules/cjs/loader:1254:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1308:10)
    at Module.load (node:internal/modules/cjs/loader:1117:32)
    at Module._load (node:internal/modules/cjs/loader:958:12)
    at Module.require (node:internal/modules/cjs/loader:1141:19)
    at require (node:internal/modules/cjs/helpers:110:18)
    at Object.<anonymous> (/my-app/node_modules/@payloadcms/plugin-seo/dist/fields/MetaDescription.js:79:15)
    at Module._compile (node:internal/modules/cjs/loader:1254:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1308:10)
    at Module.load (node:internal/modules/cjs/loader:1117:32)
    at Module._load (node:internal/modules/cjs/loader:958:12)
    at Module.require (node:internal/modules/cjs/loader:1141:19)
    at require (node:internal/modules/cjs/helpers:110:18)
    at Object.<anonymous> (/my-app/node_modules/@payloadcms/plugin-seo/dist/index.js:23:25)
    at Module._compile (node:internal/modules/cjs/loader:1254:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1308:10)
    at Module.load (node:internal/modules/cjs/loader:1117:32)
    at Module._load (node:internal/modules/cjs/loader:958:12)
    at Module.require (node:internal/modules/cjs/loader:1141:19)
    at require (node:internal/modules/cjs/helpers:110:18) {
  digest: undefined
}

@imCorfitz
Copy link
Contributor Author

So basically - If you are using Next.js version next@13.4.9 and DON'T use custom components that import resources from Payload - then it seems to be working fine. Also with SEO plugin.

@lmo-wt
Copy link

lmo-wt commented Jul 20, 2023

This might help you
#38 (comment)

@imCorfitz
Copy link
Contributor Author

You are absolutely on the spot mate!

Freaking spent an entire day trying to figure that out.

And then adding transpilePackages: ["@payloadcms/plugin-seo"], to next.config.js - otherwise that is gonna break as well.

Cheers!

@ToolReaz
Copy link

ToolReaz commented Aug 15, 2023

I still have this issue when importing payload's CodeField component when following the code described here (last comment).

This import is causing the problem:
import CodeField from "payload/dist/admin/components/forms/field-types/Code";

But the payload package is already added in the transpilePackages by the withPayload function.

@imCorfitz
Copy link
Contributor Author

@ToolReaz You'll likely have to add 'use client' to the top of that file.

@ToolReaz
Copy link

@ToolReaz You'll likely have to add 'use client' to the top of that file.

This is causing another error:

/home/toolreaz/dev/projects/myproject/node_modules/payload/dist/fields/config/sanitize.js:51
            field.blocks = field.blocks.map((block) => ({ ...block, fields: block.fields.concat(baseBlockFields_1.baseBlockFields) }));
                                                                                         ^

TypeError: Cannot read properties of undefined (reading 'concat')
    at /home/toolreaz/dev/projects/myproject/node_modules/payload/dist/fields/config/sanitize.js:51:90
    at Array.map (<anonymous>)
    at /home/toolreaz/dev/projects/myproject/node_modules/payload/dist/fields/config/sanitize.js:51:41
    at Array.map (<anonymous>)
    at sanitizeFields (/home/toolreaz/dev/projects/myproject/node_modules/payload/dist/fields/config/sanitize.js:16:19)
    at sanitizeCollection (/home/toolreaz/dev/projects/myproject/node_modules/payload/dist/collections/config/sanitize.js:126:47)
    at /home/toolreaz/dev/projects/myproject/node_modules/payload/dist/config/sanitize.js:44:106
    at Array.map (<anonymous>)
    at sanitizeConfig (/home/toolreaz/dev/projects/myproject/node_modules/payload/dist/config/sanitize.js:44:63)
    at buildConfig (/home/toolreaz/dev/projects/myproject/node_modules/payload/dist/config/build.js:19:42)

I'm using payload 1.13.4 and next-payload 0.0.35

@imCorfitz
Copy link
Contributor Author

That is likely because your file is ending with .ts instead of .tsx.

@IAmNatch
Copy link

IAmNatch commented Aug 15, 2023

Feels like we're so close to a solution here. Unfortunately, if I follow the above process, and use the Payload component inside of a collection field as an admin component, the page displays: "No matched field found for "MyFieldName".

Example

// export-reletionship-field.tsx
"use client"

import RelationshipField from "payload/dist/admin/components/forms/field-types/Relationship/index.js";
export { RelationshipField };

// my-field.ts
import { RelationshipField } from "./export-reletionship-field.tsx";

export const tenant: Field = {
  name: "tenant",
  type: "relationship",
  relationTo: "tenants",
  admin: {
    position: "sidebar",
    components: {
      Field: RelationshipField,
    },
  },

If instead I used a non payload component, everything works fine:

...
components: {
  Field: () => <div>Hello World</div>
} // Renders as expected on detail screen
...

It seems like this will be fixed automatically when payload exports all components as part of the bundle (payloadcms/payload#293), but its unclear when this will happen as it's been on the roadmap for quite a while.

@imCorfitz
Copy link
Contributor Author

I just tried to follow your code example - and it seems to work. Not sure why you get an error saying No matched field found for "MyFieldName" as none of these fields are named MyFieldName

recording.mp4

@IAmNatch
Copy link

Sorry, I was originally trying to generalize the field name, but in the example I ended up using the actual field. In my case, the error says : "No matched field found for Tenant".

I'll try and create a repro for you this evening.

@IAmNatch
Copy link

IAmNatch commented Aug 17, 2023

Here's minimal reproduction of the issue, using a page relation instead of a tenant relation for simplicity:

next-payload-repro--importing-from-dist.zip

And here's a video on my end:
https://github.com/payloadcms/next-payload/assets/15078788/a5145599-e7d3-4cd4-b477-9b41bcd46a12

Thanks for your interest in this issue!

@imCorfitz
Copy link
Contributor Author

imCorfitz commented Aug 18, 2023

@IAmNatch I'll agree with you that this is odd.. I did manage to get it to work - but the ways of doing so aren't logical 😵‍💫 Apparently I had to install the seo plugin, transpile it in next config and add the pages collection to the plugin. Then magically, your import of Payload fields is working as expected.. 😅

  1. yarn add @payloadcms/plugin-seo
  2. Update next.config.js with following:
const nextConfig = {
  transpilePackages: ["@payloadcms/plugin-seo"],
};
  1. Add to the payload config
import seo from "@payloadcms/plugin-seo";
...
plugins: [
    seo({
      collections: ["pages"],
    }),
  ],

@IAmNatch
Copy link

Weird! I tried this in the repro I shared earlier, but with no luck. I'm not seeing anything in the plugin-seo source code that would affect packaging like this (ie re-exporting of components, or webpack modifications), but perhaps I missed something. Let me know if you'd like another repro.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants