英文:
Unable to use Mongoose 7 with NextJS 13
问题
我正在使用 Nextjs 13.4.7 与 mongoose 7,并已根据 [mongoose 文档](https://mongoosejs.com/docs/nextjs.html) 在我的 next.config.js 中进行了必要的配置,如下所示:
```js
/** @type {import('next').NextConfig} */
module.exports = {
webpack(config) {
config.module.rules.push({
test: /\.svg$/i,
issuer: /\.(j|t)sx?$/,
use: ['@svgr/webpack'],
});
config.experiments = { ...config.experiments, topLevelAwait: true };
return config
},
experimental: {
serverComponentsExternalPackages: ["mongoose"],
appDir: true
},
}
然而,它仍然出现了很多模块导入错误,如下所示:
找不到模块: 无法解析 '/home/krush/portfolioblog/blog/node_modules/mongodb/lib' 中的 'kerberos'
请求模块的导入跟踪:
./node_modules/mongodb/lib/deps.js
./node_modules/mongodb/lib/index.js
./node_modules/mongoose/lib/index.js
./node_modules/mongoose/index.js
./lib/dbConnect.js
./app/posts/[postId]/page.js
./node_modules/mongodb/lib/deps.js
找不到模块: 无法解析 '/home/krush/portfolioblog/blog/node_modules/mongodb/lib' 中的 '@mongodb-js/zstd'
请求模块的导入跟踪:
./node_modules/mongodb/lib/deps.js
./node_modules/mongodb/lib/index.js
./node_modules/mongoose/lib/index.js
./node_modules/mongoose/index.js
./lib/dbConnect.js
./app/posts/[postId]/page.js
./node_modules/mongodb/lib/deps.js
找不到模块: 无法解析 '/home/krush/portfolioblog/blog/node_modules/mongodb/lib' 中的 'aws4'
请求模块的导入跟踪:
./node_modules/mongodb/lib/deps.js
./node_modules/mongodb/lib/index.js
./node_modules/mongoose/lib/index.js
./node_modules/mongoose/index.js
./lib/dbConnect.js
./app/posts/[postId]/page.js
如何解决这个问题?有人能提供解决此错误的正确配置吗?
附注:这个错误是由于 NextJS 规则造成的,我们不能在服务器组件中使用客户端组件('use client' 指令)。
<details>
<summary>英文:</summary>
I am using Nextjs 13.4.7 with mongoose 7 and have made necessary configurations to my next.config.js as give by [mongoose](https://mongoosejs.com/docs/nextjs.html) as shown:
```js
/** @type {import('next').NextConfig} */
module.exports = {
webpack(config) {
config.module.rules.push({
test: /\.svg$/i,
issuer: /\.[jt]sx?$/,
use: ['@svgr/webpack'],
});
config.experiments = { ...config.experiments, topLevelAwait: true };
return config
},
experimental: {
serverComponentsExternalPackages: ["mongoose"],
appDir: true
},
}
However it still gives lot module import errors as follows:
Module not found: Can't resolve 'kerberos' in '/home/krush/portfolioblog/blog/node_modules/mongodb/lib'
Import trace for requested module:
./node_modules/mongodb/lib/deps.js
./node_modules/mongodb/lib/index.js
./node_modules/mongoose/lib/index.js
./node_modules/mongoose/index.js
./lib/dbConnect.js
./app/posts/[postId]/page.js
./node_modules/mongodb/lib/deps.js
Module not found: Can't resolve '@mongodb-js/zstd' in '/home/krush/portfolioblog/blog/node_modules/mongodb/lib'
Import trace for requested module:
./node_modules/mongodb/lib/deps.js
./node_modules/mongodb/lib/index.js
./node_modules/mongoose/lib/index.js
./node_modules/mongoose/index.js
./lib/dbConnect.js
./app/posts/[postId]/page.js
./node_modules/mongodb/lib/deps.js
Module not found: Can't resolve 'aws4' in '/home/krush/portfolioblog/blog/node_modules/mongodb/lib'
Import trace for requested module:
./node_modules/mongodb/lib/deps.js
./node_modules/mongodb/lib/index.js
./node_modules/mongoose/lib/index.js
./node_modules/mongoose/index.js
./lib/dbConnect.js
./app/posts/[postId]/page.js
How do I fix this? Can someone provide the proper configuration that would resolve this error?
PS. This error was because of the NextJS rule that we cannot use client components ('use client' directive) with server components.
答案1
得分: 0
在客户端组件中无法使用mongoose(使用“use client”)进行数据获取,因为它涉及到mongoose需要mongodb连接URI环境变量,而这在客户端组件中无法访问。以下是我解决这个问题的方法:
错误的方法
- app/
- posts/
- [postId]
- page.js
我的page.js组件的代码,使用了mongoose查询,它是一个客户端组件,用于使用React状态等。
'use client';
import Posts from '@/models/post';
import dbConnect from '@/lib/dbConnect';
async function fetchPost(postId) {
// MONGODB_URI被dbConnect()访问,这是不可能的
await dbConnect();
const postData = await Posts.findById(postId);
return postData;
}
export default async function Component({params: {postId}}) {
const postData = await fetchPost();
return <div>{postData.title}</div>;
}
修复的方法
新的目录结构。
- page.js成为一个服务器组件,将数据传递给子组件
作为props - PostComponent处理客户端功能,现在可以访问Reach功能,如状态。
- app/
- posts/
- [postId]
- page.js
- PostComponent.js
我的page.js组件使用mongoose查询的结构
import Posts from '@/models/post';
import dbConnect from '@/lib/dbConnect';
import PostComponent from './PostComponent';
async function fetchPost(postId) {
// MONGODB_URI被dbConnect()访问,这是不可能的
await dbConnect();
const postData = await Posts.findById(postId);
return postData;
}
export default async function Component({params: {postId}}) {
const postData = await fetchPost();
return <div><PostComponent postData={postData} /></div>;
}
附注:我还遇到一个问题,无法在没有“NEXT_APP_”前缀的情况下使用环境变量。这个答案也解决了这些问题。
英文:
Turns out you can't use mongoose in client component(having "use client") data fetching as it involves mongoose requiring mongodb connection URI env variable which cannot be accessed within client component. This is how I solved it:
Erroneous method
- app/
- posts/
- [postId]
- page.js
Code of my page.js component using mongoose queries that is a client component to use React state etc.
'use client';
import Posts from '@/models/post';
import dbConnect from '@/lib/dbConnect';
async function fetchPost(postId) {
// MONGODB_URI is being accessed by dbConnect() which is not possible
await dbConnect();
const postData = await Posts.findById(postId);
return postData;
}
export default async function Component({params: {postId}}) {
const postData = await fetchPost();
return <div>{postData.title}</div>
}
Fixed method
New directory structure.
- page.js becomes a server component with data passed on to child component <PostComponent /> as props
- PostComponent handles the client functionalities and now can access Reach functionalities like states.
- app/
- posts/
- [postId]
- page.js
- PostComponent.js
Structure of my page.js component using mongoose queries
import Posts from '@/models/post';
import dbConnect from '@/lib/dbConnect';
import PostComponent from './PostComponent';
async function fetchPost(postId) {
// MONGODB_URI is being accessed by dbConnect() which is not possible
await dbConnect();
const postData = await Posts.findById(postId);
return postData;
}
export default async function Component({params: {postId}}) {
const postData = await fetchPost();
return <div><PostComponent postData={postData} /></div>
}
PS. I also had an issue where I was unable to use env variables without NEXT_APP_
prefix. This answer also solves those issues.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论