we have a rendered PDF!
TODOS: * actually apply styles to PDF * better error handling on client side
This commit is contained in:
parent
369f7e8946
commit
a90b3c888e
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -4,12 +4,15 @@
|
||||
"doctypes",
|
||||
"esbenp",
|
||||
"iconify",
|
||||
"pandoc",
|
||||
"pdoc",
|
||||
"rehype",
|
||||
"resumarkdown",
|
||||
"résumé",
|
||||
"spacebar",
|
||||
"tablist",
|
||||
"testid",
|
||||
"texlive",
|
||||
"textbox"
|
||||
],
|
||||
"editor.formatOnSave": true,
|
||||
|
@ -1,11 +1,16 @@
|
||||
FROM node:22.11.0-alpine AS builder
|
||||
FROM node:22.11.0-bookworm-slim AS builder
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
RUN npm install && npm run build
|
||||
|
||||
FROM node:22.11.0-alpine AS runner
|
||||
FROM node:22.11.0-bookworm-slim AS runner
|
||||
LABEL maintainer="Nicola Clark <nicola@slottedspoon.dev>"
|
||||
EXPOSE 3000
|
||||
ENV LANG=C.UTF-8
|
||||
RUN apt-get update && \
|
||||
apt-get install -y pandoc texlive && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
RUN useradd -u 9999 pdoc
|
||||
WORKDIR /app
|
||||
COPY package.json package-lock.json ./
|
||||
COPY --from=builder /app/build ./build
|
||||
|
18
package-lock.json
generated
18
package-lock.json
generated
@ -23,6 +23,7 @@
|
||||
"@sveltejs/adapter-node": "^5.2.9",
|
||||
"@sveltejs/kit": "^2.5.27",
|
||||
"@sveltejs/vite-plugin-svelte": "^4.0.0-next.0",
|
||||
"@types/node": "^22.9.0",
|
||||
"@types/ua-parser-js": "^0.7.39",
|
||||
"@types/user-agents": "^1.0.4",
|
||||
"less": "^4.2.0",
|
||||
@ -1017,6 +1018,16 @@
|
||||
"integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.0.tgz",
|
||||
"integrity": "sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.19.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/resolve": {
|
||||
"version": "1.20.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz",
|
||||
@ -3194,6 +3205,13 @@
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "6.19.8",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
|
||||
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/unified": {
|
||||
"version": "11.0.5",
|
||||
"resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz",
|
||||
|
@ -30,6 +30,7 @@
|
||||
"@sveltejs/adapter-node": "^5.2.9",
|
||||
"@sveltejs/kit": "^2.5.27",
|
||||
"@sveltejs/vite-plugin-svelte": "^4.0.0-next.0",
|
||||
"@types/node": "^22.9.0",
|
||||
"@types/ua-parser-js": "^0.7.39",
|
||||
"@types/user-agents": "^1.0.4",
|
||||
"less": "^4.2.0",
|
||||
|
@ -18,13 +18,18 @@
|
||||
|
||||
async function performRender(event: MouseEvent) {
|
||||
event.preventDefault();
|
||||
console.log(
|
||||
await fetch('/render', {
|
||||
const renderResponse = await fetch('/render', {
|
||||
method: 'POST',
|
||||
body: await output,
|
||||
headers: { 'content-type': 'text/html' },
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
if (!renderResponse.ok) {
|
||||
return;
|
||||
}
|
||||
|
||||
const docURL = URL.createObjectURL(await renderResponse.blob());
|
||||
window.open(docURL, '_blank');
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
import { error, json, type RequestEvent } from '@sveltejs/kit';
|
||||
import child_process from 'node:child_process';
|
||||
|
||||
import { error, type RequestEvent } from '@sveltejs/kit';
|
||||
|
||||
export async function POST({ request }: RequestEvent) {
|
||||
if (!(request.headers.get('Content-Type') ?? 'bad').includes('text/html')) {
|
||||
@ -10,7 +12,21 @@ export async function POST({ request }: RequestEvent) {
|
||||
}
|
||||
|
||||
const input = await request.text();
|
||||
console.log('received input: ', input);
|
||||
|
||||
return json({ msg: 'to be implemented' });
|
||||
const {
|
||||
status: exitCode,
|
||||
stderr: err,
|
||||
stdout: output,
|
||||
} = child_process.spawnSync('pandoc', ['--sandbox', '-f', 'html', '-t', 'pdf'], {
|
||||
input,
|
||||
timeout: 5000,
|
||||
uid: 9999,
|
||||
});
|
||||
|
||||
if (exitCode !== 0) {
|
||||
console.error('pandoc errored: ', err.toString());
|
||||
error(500, 'pandoc returned error response in server');
|
||||
}
|
||||
|
||||
return new Response(output, { headers: { 'content-type': 'application/pdf' } });
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user