Next.js 中间件模块未找到:无法解析“fs”

问题描述 投票:0回答:5

当我尝试初始化 Firebase admin V9 时,在 Next.js

_middleware
文件中收到此错误。有谁知道如何解决这个问题吗?

./node_modules/@google-cloud/storage/build/src/bucket.js:22:0
Module not found: Can't resolve 'fs'

../../firebase/auth-admin

import * as admin from "firebase-admin";

if (!admin.apps.length) {
  admin.initializeApp({
    credential: admin.credential.cert({
      projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
      clientEmail: process.env.FIREBASE_CLIENT_EMAIL,
      privateKey: process.env.FIREBASE_ADMIN_PRIVATE_KEY,
    }),
  });
}

const firestore = admin.firestore();

const auth = admin.auth();

export { firestore, auth };

在我的

_middleware

中调用它
import { NextFetchEvent, NextRequest, NextResponse } from "next/server";
import { auth } from "../../firebase/auth-admin";

export default async function authenticate(
  req: NextRequest,
  ev: NextFetchEvent
) {
  const token = req.headers.get("token");
  console.log("auth = ", auth);
  //   const decodeToken = await auth.verifyIdToken(token);
  return NextResponse.next();
}

我在here看到了一个通过自定义 webpack 的解决方案,但这并不能解决问题。

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  webpack: (config, { isServer, node }) => {
    node = {
      ...node,
      fs: "empty",
      child_process: "empty",
      net: "empty",
      tls: "empty",
    };
    return config;
  },
};

module.exports = nextConfig;
javascript next.js firebase-admin
5个回答
12
投票

Next.js 中间件使用的 Edge Runtime 不支持 Node.js 原生 API。

来自 Edge Runtime 文档:

Edge Runtime 有一些限制,包括:

  • 不支持原生 Node.js API 。例如,您无法读取或写入文件系统
  • Node 模块
  • 可以使用,只要它们实现 ES 模块并且不使用任何原生 Node.js API
您无法在 Next.js 中间件中使用使用

fs

 的 Node.js 库。尝试使用客户端库。


4
投票
我浪费了很多时间来让它发挥作用。奇怪的是,这在 api 本身中可以工作。

因此,不要在

_middleware

 文件中调用 firebase-admin 操作。在 api 本身中调用它,如下所示:

import type { NextApiRequest, NextApiResponse } from 'next' import { auth } from "../../firebase/auth-admin"; export default async function handler(req: NextApiRequest, res: NextApiResponse) { const authorization = req.headers.authorization console.log(`Handler auth header: ${authorization}`) if (!authorization) { return res.status(401).json({ message: 'Authorisation header not found.' }) } const token = authorization.split(' ')[1] if (!token) { return res.status(401).json({ message: 'Bearer token not found.' }) } console.log(`Token: ${token}`) try { const {uid} = await auth.verifyIdToken("sd" + token) console.log(`User uid: ${uid}`) res.status(200).json({ userId: uid }) } catch (error) { console.log(`verifyIdToken error: ${error}`) res.status(401).json({ message: `Error while verifying token. Error: ${error}` }) } }
使其可重用的解决方法是创建一个包装函数。

如果有人知道如何在

_middleware

文件中完成这项工作,我将非常感激。

编辑:包装中间件功能的要点:

https://gist.github.com/jvgrootveld/ed1863f0beddc1cc2bf2d3593dedb6da


0
投票
确保您没有在客户端中调用 firebase-admin

import * as admin from "firebase-admin";
    

0
投票
我最近发布了一个旨在解决该问题的库:

https://github.com/ensite-in/next-firebase-auth-edge

它允许在 Next.js 中间件和 Next.js 13 服务器组件内创建和验证令牌。完全基于 Web Crypto API 构建。

请注意,它确实依赖于 Next.js ^13.0.5 实验性的“appDir”和“allowMiddlewareResponseBody”功能。


0
投票
将中间件视为客户端代码。您必须做一些

/api/

 路由工作并在中间件中获取该端点。

这是我的示例

middleware.ts

,其想法是将博客文章的路由从 
id
 重定向到它的 
slug

顺便说一句,我正在使用 Next 14 和应用程序路由器

// cred - https://www.youtube.com/watch?v=xrvul-JrKFI // other tips - https://borstch.com/blog/development/middleware-usage-in-nextjs-14 import { Post } from '@ks/types'; import { NextResponse } from 'next/server' import type { NextRequest } from 'next/server' export async function middleware(request: NextRequest) { //todo set user chosen theme here? from cookies if (request.nextUrl.pathname.startsWith('/blog/id')) { try { const url = new URL(request.url) const postId = url.pathname.split('/blog/id/')[1] const res = await fetch( url.origin + `/api/gql/noauth`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ query: ` query Post($where: PostWhereUniqueInput!) { post(where: $where) { slug } } `, variables: { where: { id: postId } } }), }) const {post} = await res.json() as {post: Post} if(!post.slug) return console.log('no post:slug found'); return NextResponse.redirect(new URL(`/blog/${post?.slug}`, request.url)) } catch (error) { return new Response('Error processing request', { status: 500 }); } } } // See "Matching Paths" https://nextjs.org/docs/app/building-your-application/routing/middleware#matching-paths export const config = { matcher:[ '/blog/id/:id*'], }
    
© www.soinside.com 2019 - 2024. All rights reserved.