El servicio de diagnóstico de accesibilidad de Liberogic proporcionaba certificados e informes en formato HTML, pero en respuesta a las solicitudes de certificados en formato PDF,Certificados e informes en formato PDF¡Ya puedes emitirlo!
Certificado de inspección de accesibilidad web en formato PDF
Informe de conformidad de accesibilidad de PDF (VPAT/ACR)
Para solucionar este problema, creamos un sistema que genera automáticamente un archivo PDF al mismo tiempo que genera el archivo HTML durante el proceso de compilación.
🛠️ Infraestructura para la creación de PDF: Construcción de Puppeteer y del entorno
Puede utilizar el navegador Chromium sin interfaz gráfica como herramienta de generación de PDF.PuppeteerDado que HTML se construyó originalmente con Astro, la introducción de Puppeteer fue relativamente sencilla.
1. Proteger un entorno de renderizado utilizando un servidor local
Puppeteer utiliza la funcionalidad de impresión de Chromium, pero no admite archivos HTML locales (file://) directamente,El diseño está rotoSurgirán problemas.
Para evitar esto, creamos el siguiente entorno:
- Servidor web temporal:Después de la construcción
distUn servidor web local temporal para alojar el directorio (http-server) como un proceso hijo de Node.js. - Entorno estable:Titiritero a través del servidor (
http://localhost:8080) para garantizar un entorno de renderizado estable idéntico al de un navegador.
Configuración del entorno y código de inicio del servidor (fragmento)
// プロジェクト定数からドメインを取得し、未設定なら localhost:8080 を使用
const HOST_DOMAIN = SITE_URL || `http://localhost:${PORT}`;
const BUILD_ROOT = path.join(__dirname, 'dist');
const PORT = 8080;
// --- サーバーの起動ロジック ---
let serverProcess = exec(`npx http-server ${BUILD_ROOT} -p ${PORT} -s --silent`);
// サーバーが起動するまで待機
await new Promise((resolve) => setTimeout(resolve, 2000));
// --- Puppeteerのページアクセス ---
// Puppeteerは localhost:8080 にアクセスし、レンダリングを開始します
const serverUrl = `http://localhost:${PORT}/${REPORT_DIR}/${urlPath}`;
await page.goto(serverUrl, { waitUntil: 'networkidle0' });
2. Aplicación de fuentes japonesas
Dado que el entorno del servidor local donde se genera el PDF no dispone de fuentes japonesas, las fuentes incrustadas en el PDF serán incorrectas.
- Solución alternativa para la fuente:En el script, la referencia a la fuente web y el estilo aplicado se insertan dinámicamente en el DOM justo antes de generar el PDF. Esto permite generar PDFs con fuentes japonesas. Dado que el HTML prioriza la velocidad y no utiliza fuentes web, esta inserción dinámica se aplica únicamente al PDF.
Código de inserción de fuentes dinámicas (fragmento)
// Webフォントの動的挿入ロジック (page.evaluateでブラウザ側で実行)
await page.evaluate((fontUrl) => {
// <link>タグを生成してDOMに挿入
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = fontUrl;
document.head.appendChild(link);
// @media print スタイルを強制的に挿入し、フォントを適用
const printStyle = document.createElement('style');
printStyle.textContent = `
@media print {
html, body {
font-family: 'Noto Sans JP', sans-serif !important;
}
}
`;
document.head.appendChild(printStyle);
}, WEBFONTS_URL);
🚨 Problema principal: Problemas con las referencias URL en los enlaces PDF
Lo más difícil fueEnlace entre archivos PDFEl enlace integrado en el PDF todavía apunta a la URL del entorno de desarrollo local (http://localhost:8080Esto ocurre porque Chromium mantiene la URI base al cargar el HTML como base del enlace PDF.
Forzar rutas absolutas para los enlaces
Para resolver este problema, forzamos la reescritura del enlace a una ruta absoluta completa después de la implementación siguiendo estos pasos:
- Utilice el dominio de destino:Constantes del proyecto (
SITE_URL) al dominio en el que se está implementando (por ejemplo,https://example.com) se obtiene. - Construcción y sustitución de URL absolutas:Obtener contenido HTML en Node.js y devolver el enlace original (
/accessibility_report/top/)de,Dominio adquiridoLa URL completa que comienza con (por ejemplo,https://example.com/accessibility_report/pdf/acr-top.pdf) - Volver a aplicar al DOM:Vuelva a aplicar el HTML reescrito a Chromium (
page.setContent()) para insertar enlaces en el PDF.El dominio después del despliegue previstoestaba firmemente sujeto a la
Código de reescritura de enlaces (fragmento)
// 1. 無効化したいリンク(.link-ignore-pdf)を物理的に削除
const ignoreLinkRegex = new RegExp(`(<a\\\\s+[^>]*class=["'][^"']*${ignoreClass}[^"']*["'][^>]*>)(.*?)(<\\/a\\\\s*>)`, 'gi');
content = content.replace(ignoreLinkRegex, '$2'); // <a>タグ全体を中身のテキストに置換
// 2. 詳細ページへのリンクを絶対URLに書き換え
const detailLinkRegex = new RegExp(`href="${reportDirRootLink}([^/]+)\\/"`, 'g');
const detailPdfUrl = `${pdfAbsoluteUrl}/acr-top.pdf`; // 例
content = content.replace(detailLinkRegex, (match, slug) => {
// リンクを <http://localhost>... ではなく、<https://example.com/>... に強制置換
return `href="${pdfAbsoluteUrl}/acr-${slug}.pdf"`;
});
// 3. 最終的なコンテンツをブラウザに再適用し、PDF出力へ
await page.setContent(content, {
waitUntil: 'domcontentloaded',
baseURL: baseUrlForContent
});
🎉 Resumen
Esta vez tuvimos algunas dificultades debido al requisito, un tanto inusual, de enlazar archivos PDF, pero la introducción de Puppeteer en sí fue bastante fluida. La compilación es rápida y me pareció una herramienta muy útil.
Los puntos clave de esta respuesta son los siguientes:
- La renderización a través de un servidor local garantiza la estabilidad.
- Inyección dinámica de fuentes web para compatibilidad con el idioma japonés
- Enlaces entre archivos PDF mediante rutas absolutas
La compatibilidad con PDF ha mejorado enormemente la comodidad de nuestro servicio. ¡Seguiremos esforzándonos por brindar servicios de evaluación de accesibilidad de alta calidad que sean valiosos para nuestros clientes!
Pasó de la maquetación al mundo web y rápidamente se convirtió en un maestro de la artesanía, con un dominio del marcado, el diseño front-end, la dirección y la accesibilidad. Ha estado activo en diversos campos desde la fundación de Liberogic y ahora es un diccionario viviente dentro de la empresa. Recientemente, se ha obsesionado con explorar mejoras de eficiencia mediante indicaciones, preguntándose: "¿Podemos confiar más en la IA para la accesibilidad?". Su tecnología y su pensamiento siguen evolucionando.
Futa
Especialista certificado en accesibilidad web (WAS) de IAAP / Ingeniero de marcado / Ingeniero de interfaz / Director web