Cannot access '__WEBPACK_DEFAULT_EXPORT__' before initialization
brianlovin opened this issue · comments
Hey team! I'm working through adding next-connect
to all of my API pages in a Next.js project. I'm using the factory pattern that I've seen outlined in other issues:
import nc from 'next-connect';
export default function nextConnectHandler() {
return nc<NextApiRequest, NextApiResponse>({
onError(error: Error, req: NextApiRequest, res: NextApiResponse) {
console.log({ error });
res.status(501).json({ error: `${error.message}` });
},
onNoMatch(req: NextApiRequest, res: NextApiResponse) {
res.status(405).json({ error: `Method '${req.method}' Not Allowed` });
},
});
}
Then, from an API route, I can call it like this:
// /api/foo.ts
import nextConnectHandler from 'utils/nextConnectHandler';
const apiRoute = nextConnectHandler();
apiRoute.get(async (req, res) => {
// some logic
});
export default apiRoute;
On the client, results are sporadic. Sometimes my API requests resolve just fine, but other times I'm getting waves of this error:
error - (api)/utils/nextConnectHandler.ts (23:44) @ nextConnectHandler
TypeError: (0 , next_connect__WEBPACK_IMPORTED_MODULE_1__.default) is not a function
Have you encountered something like this before? Googling and issue search on this repo didn't turn up anything quite like it.
I have also tried:
rm -rf node_modules yarn.lock && yarn
to make sure I'm using latest package- delete
.next
directory and restart the app withvercel dev
to recompile
Interestingly, I can get some of my pages to load and fetch data (correctly!) when server rendered. But as soon as the page renders and the React hydrates, I have some swr
calls to my API that are failing with the above error.
Here are my versions:
"next-connect": "^0.12.2",
"next": "^12.1.6",
So this is the CJS export of next-connect: https://unpkg.com/next-connect@0.12.2/dist/index.cjs
This is the ESM version: https://unpkg.com/next-connect@0.12.2/dist/index.js
It seems that webpack is trying to pull the CJS version which has the export written as:
module.exports = function
(So no .default
- which is technically inaccurate according to ESM spec). When we write import nc from "next-connect"
and transpile that, it would become const nc = require("next-connect").default;
which undefined considering the module.exports
above.
Normally, you would enable esModuleInterop
so that TS will transform the import code (import nc from "next-connect"
) to something like:
__importDefault(require("next-connect")); // automatically handle the discrepency
and it would work.
However, if it actually pulls the ESM version, it should not be a problem, so I am not sure why this is not the case.
I will look into this asap.
Hey @brianlovin, could you please give me some more info on your usage?
- where do you use it? In API Routes, in GetServerSideProps? Could you post a snippet of where you call that factory function.
- Your Next.js version, TSConfig, Webpack Config (if applicable)
I definitely saw the issue above (not in next-connect but other packages with default export and in CommonJS) so my guess in the previous comment could be the case.
However, I just spin up a Next.js project but could not reproduce it. (I believe it's valid though, just want a way to reproduce to come up w a solution)
Thanks!
Thanks for investigating this @hoangvvo —
I was using this at the root level of each of my API pages. Here's loosely what I did:
1. I started with a nextConnect
instance per file:
import type { NextApiRequest, NextApiResponse } from 'next';
import Cors from 'cors';
import { prisma } from '~/web/lib/prisma';
import nextConnect from 'next-connect';
import { User } from '@prisma/client';
import { getToken } from 'next-auth/jwt';
async function getUser(email: string): Promise<User | null> {
return await prisma.user.findUnique({
where: { email },
});
}
const apiRoute = nextConnect<NextApiRequest, NextApiResponse>({
onError(error, req, res) {
res.status(501).json({ error: `Error while validating Figma token: ${error.message}` });
},
onNoMatch(req, res) {
res.status(405).json({ error: `Method '${req.method}' Not Allowed` });
},
});
apiRoute.use(Cors());
apiRoute.get(async (req, res) => {
const token = await getToken({ req });
const data = await getUser(token.email)
return res.status(200).json({ status: 'ok', data });
});
export default apiRoute;
2. I abstracted out the apiRoute
constructor to a new file
import nextConnect from 'next-connect'
export default function createApiRoute() {
return nextConnect<NextApiRequest, NextApiResponse>({
onError(error, req, res) {
res.status(501).json({ error: `Error while validating Figma token: ${error.message}` });
},
onNoMatch(req, res) {
res.status(405).json({ error: `Method '${req.method}' Not Allowed` });
},
});
}
3. Then I imported that factory for apiRoutes
into each of my API pages.
// ...
import nc from 'helpers/createNextConnect'
async function getUser(email: string): Promise<User | null> {
return await prisma.user.findUnique({
where: { email },
});
}
const apiRoute = nc()
apiRoute.use(Cors());
apiRoute.get(async (req, res) => {
const token = await getToken({ req });
const data = await getUser(token.email)
return res.status(200).json({ status: 'ok', data });
});
export default apiRoute;
That's where the errors above started happening. Hope this makes sense.
Thanks for investigating this @hoangvvo —
I was using this at the root level of each of my API pages. Here's loosely what I did:
1. I started with a
nextConnect
instance per file:import type { NextApiRequest, NextApiResponse } from 'next'; import Cors from 'cors'; import { prisma } from '~/web/lib/prisma'; import nextConnect from 'next-connect'; import { User } from '@prisma/client'; import { getToken } from 'next-auth/jwt'; async function getUser(email: string): Promise<User | null> { return await prisma.user.findUnique({ where: { email }, }); } const apiRoute = nextConnect<NextApiRequest, NextApiResponse>({ onError(error, req, res) { res.status(501).json({ error: `Error while validating Figma token: ${error.message}` }); }, onNoMatch(req, res) { res.status(405).json({ error: `Method '${req.method}' Not Allowed` }); }, }); apiRoute.use(Cors()); apiRoute.get(async (req, res) => { const token = await getToken({ req }); const data = await getUser(token.email) return res.status(200).json({ status: 'ok', data }); }); export default apiRoute;2. I abstracted out the
apiRoute
constructor to a new fileimport nextConnect from 'next-connect' export default function createApiRoute() { return nextConnect<NextApiRequest, NextApiResponse>({ onError(error, req, res) { res.status(501).json({ error: `Error while validating Figma token: ${error.message}` }); }, onNoMatch(req, res) { res.status(405).json({ error: `Method '${req.method}' Not Allowed` }); }, }); }3. Then I imported that factory for
apiRoutes
into each of my API pages.That's where the errors above started happening. Hope this makes sense.
Thanks @brianlovin! Could you also include your TypeScript Config? I feel like it might have something to do with esModuleInterop
option. Also with your (just saw it in your first issue)next
version too would be great!
Sure! This is mostly the Next.js default:
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"baseUrl": ".",
"paths": {
"~/*": ["../*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "prisma/seed.js", "prisma/seedData.js"],
"exclude": ["node_modules"]
}