mupdf not working with Next.js RouteHandler
Hi there,
I also posted this on Discord and the member suggested me to create the issue here :) I'm currently trying to use mupdf with Next.js RouteHandler, but I'm facing difficulties making it work. I would appreciate any help.
Overview
I am attempting to use mupdf within Next.js RouteHandler.
The test is very simple: fetch a PDF and convert it to PNG for the response.
I've tried both runtime = edge and runtime = nodejs, but both result in errors.
(I prefer to use edge runtime because my project is related to LLM work).
Next.js: 14.2.3(I tried 13.5.6, but the result was same)
mupdf: 0.2.2
Target file
The api is very simple. Just getting pdf file from /public directory, and load and convert it to png by using mupdf, and return it to client.
import { NextRequest, NextResponse } from "next/server";
import * as mupdf from "mupdf";
export const runtime = "edge";
export async function GET(req: NextRequest) {
const res = await fetch("http://localhost:3000/dummy.pdf");
const document = mupdf.Document.openDocument(
await res.arrayBuffer(),
"application/pdf"
);
const page = document.loadPage(0);
const pixmap = page.toPixmap(
mupdf.Matrix.scale(2, 2),
mupdf.ColorSpace.DeviceRGB,
false,
true
);
const pngImage = pixmap.asPNG();
return new NextResponse(pngImage, {
headers: { "Content-Type": "image/png" },
});
}
Errors
-
runtime=edge
pnpm dev
> [email protected] dev /Users/arwtyxouymz/work/sandbox/mupdf-edge-test
> next dev
▲ Next.js 14.2.3
- Local: http://localhost:3000
✓ Starting...
✓ Ready in 2.7s
○ Compiling /_not-found ...
✓ Compiled /_not-found in 2.9s (464 modules)
GET /sample.pdf 404 in 3007ms
✓ Compiled in 107ms (236 modules)
✓ Compiled in 133ms (236 modules)
⨯ ./node_modules/.pnpm/[email protected]/node_modules/mupdf/dist/mupdf-wasm.js:100:27
Module not found: Can't resolve 'module'
https://nextjs.org/docs/messages/module-not-found
Import trace for requested module:
./node_modules/.pnpm/[email protected]/node_modules/mupdf/dist/mupdf.js
./app/api/mupdf/route.ts
./node_modules/.pnpm/[email protected][email protected][email protected]/node_modules/next/dist/build/webpack/loaders/next-edge-app-route-loader/index.js?absolutePagePath=%2FUsers%2Farwtyxouymz%2Fwork%2Fsandbox%2Fmupdf-edge-test%2Fapp%2Fapi%2Fmupdf%2Froute.ts&page=%2Fapi%2Fmupdf%2Froute&appDirLoader=bmV4dC1hcHAtbG9hZGVyP25hbWU9YXBwJTJGYXBpJTJGbXVwZGYlMkZyb3V0ZSZwYWdlPSUyRmFwaSUyRm11cGRmJTJGcm91dGUmYXBwUGF0aHM9JnBhZ2VQYXRoPXByaXZhdGUtbmV4dC1hcHAtZGlyJTJGYXBpJTJGbXVwZGYlMkZyb3V0ZS50cyZhcHBEaXI9JTJGVXNlcnMlMkZhcnd0eXhvdXlteiUyRndvcmslMkZzYW5kYm94JTJGbXVwZGYtZWRnZS10ZXN0JTJGYXBwJnBhZ2VFeHRlbnNpb25zPXRzeCZwYWdlRXh0ZW5zaW9ucz10cyZwYWdlRXh0ZW5zaW9ucz1qc3gmcGFnZUV4dGVuc2lvbnM9anMmcm9vdERpcj0lMkZVc2VycyUyRmFyd3R5eG91eW16JTJGd29yayUyRnNhbmRib3glMkZtdXBkZi1lZGdlLXRlc3QmaXNEZXY9dHJ1ZSZ0c2NvbmZpZ1BhdGg9dHNjb25maWcuanNvbiZiYXNlUGF0aD0mYXNzZXRQcmVmaXg9Jm5leHRDb25maWdPdXRwdXQ9JnByZWZlcnJlZFJlZ2lvbj0mbWlkZGxld2FyZUNvbmZpZz1lMzAlM0Qh&nextConfigOutput=&preferredRegion=&middlewareConfig=e30%3D!
○ Compiling /api/mupdf ...
⚠ ./node_modules/.pnpm/[email protected]/node_modules/mupdf/dist/mupdf.js
The generated code contains 'async/await' because this module is using "topLevelAwait".
However, your target environment does not appear to support 'async/await'.
As a result, the code may not run as expected or may cause runtime errors.
Import trace for requested module:
./node_modules/.pnpm/[email protected]/node_modules/mupdf/dist/mupdf.js
./app/api/mupdf/route.ts
./node_modules/.pnpm/[email protected][email protected][email protected]/node_modules/next/dist/build/webpack/loaders/next-app-loader.js?name=app%2Fapi%2Fmupdf%2Froute&page=%2Fapi%2Fmupdf%2Froute&appPaths=&pagePath=private-next-app-dir%2Fapi%2Fmupdf%2Froute.ts&appDir=%2FUsers%2Farwtyxouymz%2Fwork%2Fsandbox%2Fmupdf-edge-test%2Fapp&pageExtensions=tsx&pageExtensions=ts&pageExtensions=jsx&pageExtensions=js&rootDir=%2FUsers%2Farwtyxouymz%2Fwork%2Fsandbox%2Fmupdf-edge-test&isDev=true&tsconfigPath=tsconfig.json&basePath=&assetPrefix=&nextConfigOutput=&preferredRegion=&middlewareConfig=e30%3D!./app/api/mupdf/route.ts?__next_edge_ssr_entry__
GET /api/mupdf 500 in 1835ms
✓ Compiled /_error in 148ms (419 modules)
-
runtime=nodejs
pnpm dev
> [email protected] dev /Users/arwtyxouymz/work/sandbox/mupdf-edge-test
> next dev
▲ Next.js 14.2.3
- Local: http://localhost:3000
✓ Starting...
✓ Ready in 1546ms
⨯ ./node_modules/.pnpm/[email protected]/node_modules/mupdf/dist/mupdf-wasm.js:114:1
Module not found: Can't resolve './'
https://nextjs.org/docs/messages/module-not-found
Import trace for requested module:
./node_modules/.pnpm/[email protected]/node_modules/mupdf/dist/mupdf.js
./app/api/mupdf/route.ts
○ Compiling /_not-found ...
⨯ ./node_modules/.pnpm/[email protected]/node_modules/mupdf/dist/mupdf-wasm.js:114:1
Module not found: Can't resolve './'
https://nextjs.org/docs/messages/module-not-found
Import trace for requested module:
./node_modules/.pnpm/[email protected]/node_modules/mupdf/dist/mupdf.js
./app/api/mupdf/route.ts
✓ Compiled /_not-found in 100ms (236 modules)
○ Compiling /_error ...
⨯ ./node_modules/.pnpm/[email protected]/node_modules/mupdf/dist/mupdf-wasm.js:114:1
Module not found: Can't resolve './'
https://nextjs.org/docs/messages/module-not-found
Import trace for requested module:
./node_modules/.pnpm/[email protected]/node_modules/mupdf/dist/mupdf.js
./app/api/mupdf/route.ts
GET /api/mupdf 500 in 2651m
How to reproduce
I create the minimum reproduce repo. https://github.com/arwtyxouymz/mupdf-edge-test You can try it just like this.
Updated: 06/11 I updated my repo to be able to test easily.
$ pnpm dev
# In another session
# Route Handler
## => Not work
$ curl http://localhost:3000/api/mupdf/edge
## => Not work
$ curl http://localhost:3000/api/mupdf/nodejs
# API Routes
## => Not work
$ curl http://localhost:3000/api/pages/mupdf/edge
## => WORK!!
$ curl http://localhost:3000/api/pages/mupdf/nodejs
Thank you for your help and for maintaining this great project!
Okay - this is not related to using Next.js or the RouteHandler - we had a previous issue here: https://github.com/ArtifexSoftware/mupdf.js/issues/12 - you can also checkout the react-example branch to validate the same errors you are seeing ( see examples/mupdf-react after checking out that branch ) .
We have mupdf.js working in the browser with the node modules, but more with vanilla JS - see examples/annotations-test for how that is done. I don't know if this helps you with your environment though!
We need to figure out how to resolve this "module not found" issue, to be honest I don't comprehend the complexities around it. I will assign some engineers to this Issue who might understand this better.
@jamie-lemon Thank you for the response and providing examples. I found it works with next.js API Routes with nodejs runtime. I don't understand why API routes with nodejs runtime works even though it doesn't work Route Handler with nodejs runtime.
I updated the https://github.com/arwtyxouymz/mupdf-edge-test and you can try it by:
$ pnpm dev
# This causes error (using Route Handler)
$ curl http://localhost:3000/api/mupdf
# This works (using API Routes with nodejs runtime)
$ curl http://localhost:3000/api/pages/mupdf
I hope this helps your investigation. Thanks.
@arwtyxouymz @jamie-lemon I solved it by explicitly adding the mupdf wasm files in Next.js config
https://github.com/mfts/papermark/blob/main/next.config.mjs#L14
Maybe that solves your issue
@mfts
Actually, I read your article and tried your solution before creating the issue. But it didn't work with app router. (You use pages router) And your mupdf version is v0.1.* but i use v0.2.*. I tried your repo code with mupdf v0.2 and app router, it didn't work.
That's a good point. I'll try it with 0.2 and work with it
@arwtyxouymz Thanks for the feedback - I can confirm that I can also see it working with your API Routes with nodejs runtime solution. "I don't understand why API routes with nodejs runtime works even though it doesn't work Route Handler with nodejs runtime."
I also don't understand this :) . All I know is that the library works fine under the node js environment, which explains why the "API routes with nodejs runtime" would work in this case. I have asked @mipo1357 to look into this issue further and hopefully he might have some ideas ( he is more of a React programmer than I am ;) )
Thanks for pointing out the problem. I am attempting to investigate here but am unable to provide a solution. Please give me some more time.
@mipo1357 @jamie-lemon
I could make mupdf work with runtime=nodejs in Route Handler by just adding mupdf to serverComponentsExternalPackages
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
serverComponentsExternalPackages: ['mupdf'],
},
};
export default nextConfig;
Thanks @arwtyxouymz for your example repo
I successfully updated mupdf from v0.1.3 to v0.2.2.
I made the following changes:
-
next.config.js: change to/dist/from/lib/experimental: { outputFileTracingIncludes: { "/api/mupdf/*": ["./node_modules/mupdf/dist/*.wasm"], }, -
pages/api/mupdf.ts: import statementimport * as mupdf from "mupdf"; -
tsconfig.json: change tobundler"moduleResolution": "bundler",
next.js 14.2.4 node 20.8.0 typescript 5.5.3
Thanks for the info. I will check these actions!
I'm running into this now, same settings as what @mfts has shared but still getting the following error on build:
Failed to compile.
./node_modules/mupdf/dist/mupdf-wasm.js
Module not found: Can't resolve 'module'
https://nextjs.org/docs/messages/module-not-found
Import trace for requested module:
./node_modules/mupdf/dist/mupdf.js
./src/screens/pitch/usePitchScreen.ts
./src/screens/pitch/PitchScreen.tsx
./src/screens/pitch/PitchScreenModal.tsx
./src/screens/profile/ProfileScreen.tsx
@Southclaws bundler, next.config is set like mine above? And you're on mupdf@^0.2.2 ?
I did get this working eventually on 0.2.2 inside a route handler (not a page handler) - though now we've switched to doing this in our Go backend using https://github.com/klippa-app/go-pdfium
It seems in my installation with next.js invoking mupdfjs on the server side was causing trouble with this line: I'm not very familiar with the internals of mupdfjs, and not sure why one needs the './' prefix here. Seems it should not be necessary.
L116: ./node_modules/.pnpm/[email protected]/node_modules/mupdf/dist/mupdf-wasm.js
- scriptDirectory = require('url').fileURLToPath(new URL('./', import.meta.url));
+ scriptDirectory = require('url').fileURLToPath(new URL(import.meta.url));
It seems in my installation with next.js invoking mupdfjs on the server side was causing trouble with this line: I'm not very familiar with the internals of mupdfjs, and not sure why one needs the './' prefix here. Seems it should not be necessary.
L116: ./node_modules/.pnpm/[email protected]/node_modules/mupdf/dist/mupdf-wasm.js
- scriptDirectory = require('url').fileURLToPath(new URL('./', import.meta.url));
- scriptDirectory = require('url').fileURLToPath(new URL(import.meta.url));
The "./" prefix is added by the Emscripten compiler -- it is not specific to the MuPDF.js project.
@Southclaws did you solve this?
Module not found: Can't resolve 'module'
i'm getting the same error.