mupdf.js icon indicating copy to clipboard operation
mupdf.js copied to clipboard

Add a example mupdf.js with Sveltekit

Open jet10000 opened this issue 10 months ago • 4 comments

Add a example mupdf.js with Sveltekit

jet10000 avatar Feb 17 '25 09:02 jet10000

Hey, after some tinkering I got it to work:


1st step: add mupdf to the dependencies npm i mupdf

2nd step: change module resolution in tsconfig.json

tsconfig.json

{
        // ....
	"compilerOptions": {
                // ....
		"moduleResolution": "nodenext",
                "module": "nodenext"
	}
        // ....
}

3rd step: mupdf will try to fetch the wasm binary from node_modules/.vite/dist/mupdf_wasm.wasm. This is however by default not the place where the binary is located. That's why I used the vite-plugin-static-copy to mitigate this: npm i vite-plugin-static-copy

vite.config.ts

import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
import { viteStaticCopy } from 'vite-plugin-static-copy';

export default defineConfig({
	optimizeDeps: {
		esbuildOptions: {
			target: 'esnext'
		}
	},
	build: {
		target: 'esnext'
	},
	plugins: [
		viteStaticCopy({
			targets: [
				{
					src: 'node_modules/mupdf/dist/mupdf-wasm.wasm',
					dest: 'node_modules/.vite/deps',
				}
			]
		}),
		sveltekit()
	]
});

hope this helps!

lbirkert avatar Mar 08 '25 18:03 lbirkert

This is my approach:

  • bun add mupdf
  • vite.config.ts
import { sveltekit } from "@sveltejs/kit/vite";
import { defineConfig } from "vite";
import tailwindcss from "@tailwindcss/vite";

export default defineConfig({
	optimizeDeps: {
		exclude: ["mupdf"],
		esbuildOptions: {
			target: "esnext", //esnext is subject to change, es2022 should work too (untested)
		},
	},
	build: {
		target: "esnext", //same
	},
	plugins: [sveltekit(), tailwindcss()],
});

And here is an example:

  • +page.server.ts
import type { PageServerLoad } from "./$types";
import { read } from "$app/server";
import myImportedPDF from "$lib/myDocument.pdf";

export const load = (async () => {
	return {
		myReturnedPDF: await read(myImportedPDF).arrayBuffer(),
	};
}) satisfies PageServerLoad;
  • +page.svelte
<script lang="ts">
	import * as mupdfjs from "mupdf/mupdfjs";
	import type { PageProps } from "./$types";

	let { data }: PageProps = $props();
	let pdf = mupdfjs.PDFDocument.openDocument(data.myReturnedPDF, "application/pdf");
</script>

<!--Simple HTML preview of the first page, not a 1:1 with the PDF -->
<div class="w-fit bg-white">
	{@html pdf
		.loadPage(0)
		.toStructuredText("preserve-whitespace,preserve-images,preserve-spans")
		.asHTML(0)
		.replace(/<p style="([^"]*)">/g, '<p style="$1; position: absolute;">')}
</div>

my tsconfig.json uses the default "moduleResolution": "bundler" I have yet to test an actual deployment, but in local development everything seems to work fine

MrVoshel avatar Mar 08 '25 20:03 MrVoshel

Seems more idiomatic. Good job!

lbirkert avatar Mar 09 '25 16:03 lbirkert

You should probably clarify if you want an example using server side rendering, client side rendering, or both!

ccxvii avatar Mar 21 '25 15:03 ccxvii