最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Next.js middleware Module not found: Can't resolve 'fs' - Stack Overflow

programmeradmin1浏览0评论

Getting this error in Next.js _middleware file when I try to initialize Firebase admin V9. Anyone know how to solve this issue?

./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 };

Calling it in my _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();
}

I saw a solution here by customizing webpack but this does not fix it.

/** @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;

Getting this error in Next.js _middleware file when I try to initialize Firebase admin V9. Anyone know how to solve this issue?

./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 };

Calling it in my _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();
}

I saw a solution here by customizing webpack but this does not fix it.

/** @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;
Share Improve this question edited Feb 15, 2022 at 19:32 juliomalves 50.3k23 gold badges176 silver badges167 bronze badges asked Feb 14, 2022 at 3:08 me-meme-me 5,80914 gold badges61 silver badges112 bronze badges
Add a comment  | 

5 Answers 5

Reset to default 12

The Edge Runtime, which is used by Next.js Middleware, does not support Node.js native APIs.

From the Edge Runtime documentation:

The Edge Runtime has some restrictions including:

  • Native Node.js APIs are not supported. For example, you can't read or write to the filesystem
  • Node Modules can be used, as long as they implement ES Modules and do not use any native Node.js APIs

You can't use Node.js libraries that use fs in Next.js Middleware. Try using a client-side library instead.

I wasted a lot of time tying to get this to work. The weird thing is that this will work in the api itself.

So instead of calling firebase-admin action in the _middleware file. Call it in the api itself like:

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}` })
  }
}

A workaround to make this reusable is to create a wrapper function.

If anyone knows how to make this work in a _middleware file, I would be really grateful.

Edit: Gist for the wrapper middleware function: https://gist.github.com/jvgrootveld/ed1863f0beddc1cc2bf2d3593dedb6da

make sure you're not calling firebase-admin in the client

import * as admin from "firebase-admin";

I've recently released a library that aims to solve the problem: https://github.com/ensite-in/next-firebase-auth-edge

It allows to create and verify tokens inside Next.js middleware and Next.js 13 server components. Built entirely upon Web Crypto API.

Please note it does rely on Next.js ^13.0.5 experimental "appDir" and "allowMiddlewareResponseBody" features.

think of the middleware as client side code. You'll have to do some /api/ route work around and fetch that endpoint in the middleware.

Here is my example middleware.ts with the idea of redirecting a route to a blog post from it's id to it's slug

btw I'm using Next 14 with app router

// 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*'],
}
发布评论

评论列表(0)

  1. 暂无评论