reactjs 将使用typescript(next.js)创建的Web应用程序部署到vercel时,我收到一个构建错误,无法部署

5ktev3wc  于 2023-03-29  发布在  React
关注(0)|答案(1)|浏览(95)

▼环境(取自packege.json)
“@prisma/client”:“^4.11.0”
“@supabase/supabase-js”:“^2.12.1”
“next”:“^12.2.5”,.
“next-auth”:“^4.20.1”,.
“react”:“17.0.2”,“next”.
“ typescript ”:“第4.5.5条”
框架是NextJS
数据库是supabase
图像存储是数据库存储
ORM是Prisma
形式为反作用钩形
使用了typescript。
我可以在本地开发期间使用npm run dev注册,更新和检索图像,而不会出现任何问题。
如果我在本地运行npm run build而不是vercel,我可以毫无问题地构建,npm run start也没有任何问题。
要存储在DB中的图像的列类型是字符串。
我认为错误是因为next.js中定义的类型与prisma中保存时的类型不匹配,但我经验不足,很难确定原因并解决问题。
www.DeepL.com/Translator翻译(免费版)
下面的错误消息仅在使用vercel构建时输出,我无法构建。

// Error output in vercel log
./pages/api/user/index.tsx:19:9
Type error: Type '{ name: any; email: any; password: any; image: any; }' is not assignable to type '(Without<UserCreateInput, UserUncheckedCreateInput> & UserUncheckedCreateInput) | (Without<...> & UserCreateInput)'.
  Object literal may only specify known properties, and 'image' does not exist in type '(Without<UserCreateInput, UserUncheckedCreateInput> & UserUncheckedCreateInput) | (Without<...> & UserCreateInput)'.

错误API

  • pages/API/user/index.tsx
import prisma from "../../../lib/prisma";
import type { NextApiRequest, NextApiResponse } from "next";
import { hash } from "bcrypt";

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  if (req.method === "POST") {
    const { name, email, password, image } = req.body;
    console.log(req.body);

    const hash_password = await hash(password, 10);
    const data = await prisma.user.create({
      data: {
        name: name,
        email: email,
        password: hash_password,
        image: image,
      },
    });
    return res.status(200).json(data);
  } else if (req.method === "GET") {
    const data = await prisma.user.findMany({});
    return res.status(200).json(data);
  }
}

调用上述API的组件

  • pages/user/index.tsx
// pages/user/index.tsx
import { useForm } from "react-hook-form";
import { useRouter } from "next/router";
import Link from "next/link";
import { signIn } from "next-auth/react";
import Image, { StaticImageData } from "next/image";
import { useState, useRef } from "react";
import { supabase } from "../../lib/supabase";
// ユーザのデフォルト画像
const defaultImg = process.env.NEXT_PUBLIC_DEFAULT_IMG;
interface UserInput {
  name: string;
  email: string;
  password: string;
  image?: string | StaticImageData;
}

type uploadImageUrl = string;

export default function UserForm() {
  const [uploadImageUrl, setUploadImageUrl] = useState<uploadImageUrl>();
  const [uploadImageFile, setUploadImageFile] = useState<File>();
  const router = useRouter();
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<UserInput>({
    defaultValues: {
      name: "",
      email: "",
      password: "",
      image: defaultImg,
    },
  });

  // const inputRef = useRef<HTMLInputElement>();
  // 画像が選択されたら、プレビュー
  const onChangeFile = (e: React.ChangeEvent<HTMLInputElement>) => {
    const { files } = e.target;
    setUploadImageUrl(URL.createObjectURL(files[0]));
    setUploadImageFile(files[0]);
  };

  const submitUserRegister = async (input: UserInput) => {
    //supabaseに画像をアップロード
    const { data, error } = await supabase.storage
      .from("photos")
      .upload("user/" + uploadImageFile.name, uploadImageFile);

    //supabaseから画像のURLをDL
    const url = await supabase.storage
      .from("photos")
      .getPublicUrl(JSON.stringify(data));
    const { publicUrl } = url.data;

    // DLしたURLをimageに格納
    const formData = {
      name: input.name,
      email: input.email,
      password: input.password,
      image: publicUrl,
    };

    try {
      const res = await fetch("/api/user", {
        method: "POST",
        body: JSON.stringify(formData),
        headers: {
          "Content-Type": "application/json",
        },
      });
      // json形式で返す
      const data = await res.json();
      const email = data.email;
      //登録済みのデータを使用するとhash化したpasswordを利用してしまうため、formに入力されたpasswordを使用
      const password = formData.password;
      //sign In()でそのままログイン

      await signIn("credentials", {
        email,
        password,
        callbackUrl: "/",
        redirect: true,
      });
    } catch (error) {
      console.error("Error registering user:", error);
    }
  };

  return (
    <div>
      <h3>ユーザー登録</h3>

      <form
        onSubmit={handleSubmit(submitUserRegister)}
        className="w-full max-w-sm"
      >
---
不要部分の為省略
---
        <Image
          src={uploadImageUrl ? uploadImageUrl : defaultImg}
          width={100}
          height={100}
        ></Image>
        <label className="block mb-2 text-sm font-medium text-gray-900 dark:text-white">
          Upload file
        </label>
        <input
          className="block w-full text-sm text-gray-900 border border-gray-300 rounded-lg cursor-pointer bg-gray-50 dark:text-gray-400 focus:outline-none dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400"
          id="file_input"
          type="file"
          onChange={onChangeFile}
        />

        <div className="md:flex md:items-center">
          <div className="md:w-2/3">
            <button className="shadow bg-blue-500 hover:bg-blue-400 focus:shadow-outline focus:outline-none text-white font-bold py-2 px-4 rounded">
              <Link href={`/`}>Home</Link>
            </button>
          </div>
          <div className="md:w-2/3">
            <button
              className="shadow bg-blue-500 hover:bg-blue-400 focus:shadow-outline focus:outline-none text-white font-bold py-2 px-4 rounded"
              type="submit"
            >
              Sign Up
            </button>
          </div>
        </div>
      </form>
    </div>
  );
}

schema.prisma

model User {
  id            String       @default(cuid()) @id
  name          String?
  email         String?   @unique
  emailVerified DateTime?
  image         String?
  password      String
  createdAt     DateTime  @default(now()) @map(name: "created_at")
  updatedAt     DateTime  @updatedAt @map(name: "updated_at")
  posts         Post[]
  @@map(name: "users")
}

如果您需要任何其他信息,请让我们知道。提前感谢您。

uelo1irk

uelo1irk1#

错误说图像字段不知道。也许你需要更新模型。尝试“prisma db push”。如果你在生产中,你需要使用prisma migrate来更新模型。如果你使用mondoDB,你也需要使用push,因为驱动程序不支持迁移。

相关问题