tfrere HF Staff commited on
Commit
8d245e0
·
1 Parent(s): 77b813e

fix: enable PDF generation by adding playwright dependency

Browse files

- Add playwright as a production dependency in backend
- Set PLAYWRIGHT_BROWSERS_PATH in Dockerfile for reliable browser discovery
- Remove silent fallback on playwright install to surface errors
- Remove non-functional PDF button from editor hero (only relevant in published output)
- Respect showPdf frontmatter flag in publisher pipeline

Made-with: Cursor

Dockerfile CHANGED
@@ -50,8 +50,9 @@ COPY backend/package.json backend/package-lock.json* ./
50
  RUN npm install --omit=dev
51
  COPY --from=backend-build /app/dist ./dist
52
 
53
- # Install Playwright Chromium
54
- RUN npx playwright install chromium || echo "Playwright install skipped"
 
55
 
56
  # Copy frontend build
57
  COPY --from=frontend-build /app/frontend/dist ./frontend-dist
 
50
  RUN npm install --omit=dev
51
  COPY --from=backend-build /app/dist ./dist
52
 
53
+ # Install Playwright Chromium browser binaries
54
+ ENV PLAYWRIGHT_BROWSERS_PATH=/app/browsers
55
+ RUN npx playwright install chromium
56
 
57
  # Copy frontend build
58
  COPY --from=frontend-build /app/frontend/dist ./frontend-dist
backend/package-lock.json CHANGED
@@ -36,6 +36,7 @@
36
  "express": "^4.21.0",
37
  "lowlight": "^3.3.0",
38
  "multer": "^2.1.1",
 
39
  "ws": "^8.20.0",
40
  "yjs": "^13.6.0",
41
  "zod": "^4.3.6"
@@ -3405,6 +3406,50 @@
3405
  "url": "https://github.com/sponsors/jonschlinkert"
3406
  }
3407
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3408
  "node_modules/postcss": {
3409
  "version": "8.5.9",
3410
  "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.9.tgz",
 
36
  "express": "^4.21.0",
37
  "lowlight": "^3.3.0",
38
  "multer": "^2.1.1",
39
+ "playwright": "^1.59.1",
40
  "ws": "^8.20.0",
41
  "yjs": "^13.6.0",
42
  "zod": "^4.3.6"
 
3406
  "url": "https://github.com/sponsors/jonschlinkert"
3407
  }
3408
  },
3409
+ "node_modules/playwright": {
3410
+ "version": "1.59.1",
3411
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.59.1.tgz",
3412
+ "integrity": "sha512-C8oWjPR3F81yljW9o5OxcWzfh6avkVwDD2VYdwIGqTkl+OGFISgypqzfu7dOe4QNLL2aqcWBmI3PMtLIK233lw==",
3413
+ "license": "Apache-2.0",
3414
+ "dependencies": {
3415
+ "playwright-core": "1.59.1"
3416
+ },
3417
+ "bin": {
3418
+ "playwright": "cli.js"
3419
+ },
3420
+ "engines": {
3421
+ "node": ">=18"
3422
+ },
3423
+ "optionalDependencies": {
3424
+ "fsevents": "2.3.2"
3425
+ }
3426
+ },
3427
+ "node_modules/playwright-core": {
3428
+ "version": "1.59.1",
3429
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.59.1.tgz",
3430
+ "integrity": "sha512-HBV/RJg81z5BiiZ9yPzIiClYV/QMsDCKUyogwH9p3MCP6IYjUFu/MActgYAvK0oWyV9NlwM3GLBjADyWgydVyg==",
3431
+ "license": "Apache-2.0",
3432
+ "bin": {
3433
+ "playwright-core": "cli.js"
3434
+ },
3435
+ "engines": {
3436
+ "node": ">=18"
3437
+ }
3438
+ },
3439
+ "node_modules/playwright/node_modules/fsevents": {
3440
+ "version": "2.3.2",
3441
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
3442
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
3443
+ "hasInstallScript": true,
3444
+ "license": "MIT",
3445
+ "optional": true,
3446
+ "os": [
3447
+ "darwin"
3448
+ ],
3449
+ "engines": {
3450
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
3451
+ }
3452
+ },
3453
  "node_modules/postcss": {
3454
  "version": "8.5.9",
3455
  "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.9.tgz",
backend/package.json CHANGED
@@ -39,6 +39,7 @@
39
  "express": "^4.21.0",
40
  "lowlight": "^3.3.0",
41
  "multer": "^2.1.1",
 
42
  "ws": "^8.20.0",
43
  "yjs": "^13.6.0",
44
  "zod": "^4.3.6"
 
39
  "express": "^4.21.0",
40
  "lowlight": "^3.3.0",
41
  "multer": "^2.1.1",
42
+ "playwright": "^1.59.1",
43
  "ws": "^8.20.0",
44
  "yjs": "^13.6.0",
45
  "zod": "^4.3.6"
backend/src/publisher/index.ts CHANGED
@@ -232,8 +232,9 @@ export async function publishDocument(docName: string, token?: string): Promise<
232
  };
233
 
234
  // Pre-compute public URLs so og:image and PDF link are embedded in HTML
 
235
  const useHf = isHfStorageEnabled();
236
- if (useHf && isPdfEnabled()) {
237
  meta.ogImage = getPublishedAssetUrl(docName, "thumb.jpg");
238
  meta.pdfUrl = getPublishedAssetUrl(docName, "article.pdf");
239
  }
@@ -250,7 +251,7 @@ export async function publishDocument(docName: string, token?: string): Promise<
250
  let pdf: Buffer | null = null;
251
  let thumbnail: Buffer | null = null;
252
 
253
- if (isPdfEnabled()) {
254
  try {
255
  const assets = await generatePdfAndThumbnail(html);
256
  pdf = assets.pdf;
 
232
  };
233
 
234
  // Pre-compute public URLs so og:image and PDF link are embedded in HTML
235
+ const wantPdf = frontmatter.showPdf !== false;
236
  const useHf = isHfStorageEnabled();
237
+ if (wantPdf && useHf && isPdfEnabled()) {
238
  meta.ogImage = getPublishedAssetUrl(docName, "thumb.jpg");
239
  meta.pdfUrl = getPublishedAssetUrl(docName, "article.pdf");
240
  }
 
251
  let pdf: Buffer | null = null;
252
  let thumbnail: Buffer | null = null;
253
 
254
+ if (wantPdf && isPdfEnabled()) {
255
  try {
256
  const assets = await generatePdfAndThumbnail(html);
257
  pdf = assets.pdf;
frontend/src/editor/frontmatter/FrontmatterHero.tsx CHANGED
@@ -28,7 +28,7 @@ export function FrontmatterHero({ store }: FrontmatterHeroProps) {
28
  const hasAuthors = data.authors.length > 0;
29
  const hasAffiliations = data.affiliations.length > 0;
30
  const multipleAffiliations = data.affiliations.length > 1;
31
- const hasMeta = hasAuthors || data.published || data.doi || data.showPdf;
32
 
33
  return (
34
  <div>
@@ -146,17 +146,6 @@ export function FrontmatterHero({ store }: FrontmatterHeroProps) {
146
  />
147
  </div>
148
 
149
- {/* PDF cell */}
150
- {data.showPdf && (
151
- <div className="meta-container-cell meta-container-cell--pdf">
152
- <h3>PDF</h3>
153
- <p style={{ margin: 0, lineHeight: 1 }}>
154
- <a className="button" href="#" onClick={(e) => e.preventDefault()}>
155
- Download PDF
156
- </a>
157
- </p>
158
- </div>
159
- )}
160
  </div>
161
  </header>
162
  )}
 
28
  const hasAuthors = data.authors.length > 0;
29
  const hasAffiliations = data.affiliations.length > 0;
30
  const multipleAffiliations = data.affiliations.length > 1;
31
+ const hasMeta = hasAuthors || data.published || data.doi;
32
 
33
  return (
34
  <div>
 
146
  />
147
  </div>
148
 
 
 
 
 
 
 
 
 
 
 
 
149
  </div>
150
  </header>
151
  )}