infodocviewdoc
v3.0.4
Published
`infodocviewdoc` es una librería Angular para previsualizar documentos en microfrontends (shell + Native Federation u orquestador similar).
Downloads
670
Readme
MFE Document Viewer Integration Guide
infodocviewdoc es una librería Angular para previsualizar documentos en microfrontends (shell + Native Federation u orquestador similar).
1) Instalacion del paquete
npm i [email protected]Para probar cambios locales sin publicar:
npm install <ruta>/sgdea-component-library/dist/ui-components
2) Dependencias requeridas en el host (package.json)
El MFE debe tener exactamente (o al menos) la misma major/minor de PDF viewer que el paquete:
{
"dependencies": {
"infodocviewdoc": "^3.0.4",
"@handsontable/angular": "^16.2.0",
"handsontable": "^16.2.0",
"jspdf": "^4.1.0",
"ngx-extended-pdf-viewer": "^25.6.4",
"xlsx": "^0.18.5"
}
}Critico entre microfronts
Si otro MFE usa otra version de ngx-extended-pdf-viewer (p. ej. 22.x / worker 5.1.xxx) y el usuario navega sin F5, el shell deja scripts globales conflictivos y el canvas puede quedar en blanco (toolbar si, documento no).
Regla: todos los MFE que abran PDFs deben alinear ngx-extended-pdf-viewer@^25.6.4 (PDF.js build 5.4.1105).
Ejemplo completo (MFE nuevo)
{
"dependencies": {
"@angular/animations": "19.2.4",
"@angular/common": "19.2.4",
"@angular/core": "19.2.4",
"@angular/forms": "19.2.4",
"@angular/platform-browser": "19.2.4",
"@angular/platform-browser-dynamic": "19.2.4",
"@angular/router": "19.2.4",
"rxjs": "~7.8.0",
"tslib": "2.3.0",
"zone.js": "~0.15.0",
"infodocviewdoc": "^3.0.4",
"@handsontable/angular": "^16.2.0",
"handsontable": "^16.2.0",
"jspdf": "^4.1.0",
"ngx-extended-pdf-viewer": "^25.6.4",
"xlsx": "^0.18.5"
}
}npm install3) Assets PDF en angular.json (recomendado)
Copia los assets al build (o usa CDN / pdfAssetsBaseUrl):
{
"glob": "**/*",
"input": "node_modules/ngx-extended-pdf-viewer/assets",
"output": "/assets/"
}- Si no hay
/assets/local, el paquete usa fallback CDN:https://cdn.jsdelivr.net/npm/[email protected]/assets - Sin assets ni CDN → 404 en
viewer-*.mjsy PDF en blanco aunque el download del archivo sea 200.
Assets en otra ruta
<sgdea-document-viewer
[pdfAssetsBaseUrl]="'https://mi-dominio.com/assets'"
...
></sgdea-document-viewer>4) Import y uso basico
import { PdfViewerComponent } from 'infodocviewdoc';
@Component({
standalone: true,
imports: [PdfViewerComponent],
})
export class PdfPreviewModalComponent {}<sgdea-document-viewer
[fileBlob]="blob"
[fileBlobName]="fileName"
[url]="apiUrl"
[token]="token"
[pdfAssetsBaseUrl]="pdfAssetsBaseUrl">
</sgdea-document-viewer>5) Inputs
| Input | Uso |
|-------|-----|
| fileBlob | File \| Blob ya descargado por el host (requerido para render). |
| fileBlobName | Nombre con extension (recomendado). |
| url / token | Solo para conversion Office → PDF. |
| pdfAssetsBaseUrl | Base de assets PDF.js (CDN o host). |
Formatos: .pdf, .txt, imagenes, .xlsx/.xls, .docx/.doc, .pptx/.ppt (Office via conversion).
6) Integracion anti-fallo entre MFEs (obligatoria si navegas sin F5)
Sintoma tipico
- Abriste un PDF en otro MFE.
- Entras a este MFE sin recargar.
- Modal del visor: toolbar OK, canvas blanco.
- Con F5 a veces “arregla”. Eso es estado global de PDF.js, no falta de
fileBlob.
El paquete mitiga esto así (interno, no necesitas setearlo en tu template):
[forceFullReloadOfJavaScriptCode]="true"(re-ejecuta scripts de PDF.js al montar).- Remount diferido (~200 ms) +
pdfMountKey. - Reaplica
assetsFolder+workerSrc(5.4.1105) en cada apertura. - PDF como
Uint8Array(mas estable que reusar unBlobcruzando MFEs). - No borra
localStorage['pdfjs.history']ni fuerzadisableHistory = true.
6.1) Utilidad de preload en el MFE (copia esto)
Crea src/app/shared/utils/pdf-viewer-preload.util.ts:
const NGX_EXTENDED_PDF_VIEWER_ASSETS_VERSION = '25.6.4';
const PDF_JS_BUILD = '5.4.1105';
/** CDN alineado a la peerDependency del paquete. */
export const PDF_ASSETS_BASE_URL =
`https://cdn.jsdelivr.net/npm/ngx-extended-pdf-viewer@${NGX_EXTENDED_PDF_VIEWER_ASSETS_VERSION}/assets`;
let preloadPromise: Promise<void> | null = null;
/**
* Precarga assets/worker. NO borrar pdfjs.history ni poner disableHistory=true:
* eso no carga el PDF y puede empeorar el estado entre MFEs.
*/
function applyPdfJsAssets(mod: typeof import('ngx-extended-pdf-viewer')): void {
const base = PDF_ASSETS_BASE_URL.replace(/\/$/, '');
mod.pdfDefaultOptions.assetsFolder = base;
mod.pdfDefaultOptions.disableHistory = false;
mod.pdfDefaultOptions.historyUpdateUrl = false;
(mod.pdfDefaultOptions as { workerSrc: string | (() => string) }).workerSrc = () =>
`${base}/pdf.worker-${PDF_JS_BUILD}.mjs`;
}
export function preloadPdfViewerAssets(): Promise<void> {
if (!preloadPromise) {
preloadPromise = (async () => {
const mod = await import('ngx-extended-pdf-viewer');
applyPdfJsAssets(mod);
await Promise.all(
[
fetch(`${PDF_ASSETS_BASE_URL}/viewer-${PDF_JS_BUILD}.min.mjs`, {
mode: 'cors',
cache: 'force-cache',
}),
fetch(`${PDF_ASSETS_BASE_URL}/pdf.worker-${PDF_JS_BUILD}.mjs`, {
mode: 'cors',
cache: 'force-cache',
}),
].map((request) => request.catch(() => undefined)),
);
})().catch((error) => {
preloadPromise = null;
throw error;
});
}
return preloadPromise;
}6.2) Precargar al entrar al MFE
import { Component, OnInit } from '@angular/core';
import { preloadPdfViewerAssets } from '@shared/utils/pdf-viewer-preload.util';
@Component({ /* ... */ })
export class AppComponent implements OnInit {
ngOnInit(): void {
void preloadPdfViewerAssets();
}
}6.3) Descargar el archivo ANTES de abrir el modal
No abras el dialog solo con storagePath esperando que el visor “se arregle solo”.
- Loading.
- En paralelo:
preloadPdfViewerAssets()+ download (ArrayBuffer/Blob). - Abrir modal con
[fileBlob]+[fileBlobName](+[pdfAssetsBaseUrl]).
import { firstValueFrom } from 'rxjs';
import { preloadPdfViewerAssets, PDF_ASSETS_BASE_URL } from '@shared/utils/pdf-viewer-preload.util';
openDocumentViewer(bucket: string, objectName: string, fileName: string): void {
void Promise.all([
preloadPdfViewerAssets().catch(() => undefined),
firstValueFrom(this.fileService.getFileToView(bucket, objectName)),
])
.then(([, arrayBuffer]) => {
const blob = new Blob([arrayBuffer], { type: 'application/pdf' });
this.dialog.open(DocumentViewComponent, {
width: '95vw',
height: '90vh',
data: {
fileName,
blob,
pdfAssetsBaseUrl: PDF_ASSETS_BASE_URL,
},
});
})
.catch(() => {
/* error de descarga */
});
}6.4) Montar el visor cuando el dialog ya tiene tamaño
En MatDialog:
- Espera
afterOpened(). - Usa
*ngIf/@ifpara montarsgdea-document-viewersolo cuando el contenedor tenga tamaño (clientWidth/Height >= 48) o tras un delay corto (~150 ms). - Opcional:
@forcon key nueva para forzar remount al reabrir.
@if (infodocViewerVisible) {
@for (shellKey of [viewerShellKey]; track shellKey) {
<sgdea-document-viewer
[fileBlob]="previewBlob"
[fileBlobName]="documentName"
[url]="apiUrl"
[token]="token"
[pdfAssetsBaseUrl]="pdfAssetsBaseUrl">
</sgdea-document-viewer>
}
}Altura del wrap (evitar canvas con 0 px):
.infodoc-wrap sgdea-document-viewer {
display: block;
width: 100%;
height: 100%;
min-height: 70vh;
}6.5) Checklist MFE federado
[email protected]+ngx-extended-pdf-viewer@^25.6.4(misma familia en todos los MFE).- Util
preloadPdfViewerAssetssinremoveItem('pdfjs.history')nidisableHistory = true. - Precarga en
AppComponent(o al entrar al feature). - Blob listo antes del modal; pasar
fileBlob+fileBlobName+pdfAssetsBaseUrl. - Contenedor con altura real; montaje diferido / remount.
- Probar sin F5: otro MFE (PDF) → este MFE → Anexo/visor.
- Network:
viewer-5.4.1105*.mjsypdf.worker-5.4.1105.mjsen 200.
6.6) Que NO hacer en el host
| Anti-patron | Por que falla |
|-------------|---------------|
| localStorage.removeItem('pdfjs.history') al entrar | No alimenta el PDF; confunde el debug y pelea con el paquete. |
| pdfDefaultOptions.disableHistory = true en preload | No soluciona el blank entre MFEs. |
| Abrir modal solo con ruta y sin fileBlob | Carrera con cold-start de PDF.js. |
| Mezclar versiones distintas de ngx-extended-pdf-viewer entre MFE | Worker/viewer incorrectos → toolbar OK, canvas blanco. |
| Depender de F5 / “recargar pagina” | No es aceptable en shell federado. |
7) Diagnostico rapido
| Observacion | Interpretacion |
|-------------|----------------|
| Download 200 + blobs desde pdf-viewer + toolbar + canvas blanco | Estado PDF.js entre MFEs / scripts no re-ejecutados. Revisar seccion 6 + versiones. |
| 404 viewer-*.mjs / worker | Assets mal configurados o CDN bloqueado. |
| create-audit 400 | Ruido; no bloquea el render del PDF. |
| Falta pdfjs.history | Irrelevante para cargar bytes; el PDF va por fileBlob. |
8) Cambios del paquete (comportamiento actual 3.0.4 local / a publicar)
Contrato publico sin breaking changes:
- Inputs:
fileBlob,fileBlobName,url,token,pdfAssetsBaseUrl
| Area | Comportamiento |
|------|----------------|
| Reload MFE | forceFullReloadOfJavaScriptCode + delay de montaje. |
| Assets | Reaplica assetsFolder + workerSrc (CDN/pdfAssetsBaseUrl) en cada apertura. |
| Src PDF | Prefiere Uint8Array desde el blob. |
| Historial | No limpia pdfjs.history; deja disableHistory = false. |
| Remount | pdfMountKey fuerza nueva instancia de ngx-extended-pdf-viewer. |
Si tu README o util de host aun recomienda borrar
pdfjs.history/disableHistory = true, actualiza el host al patron de la seccion 6.
9) Instalacion local (desarrollo sin publicar)
# En la libreria
npm run build:lib
# En el MFE
npm install "C:/Users/aguio/Repos/Front/Package/component-library/sgdea-component-library/dist/ui-components"Reinicia ng serve del MFE despues de reinstalar/rebuild.
10) Public API
public-api.ts exporta:
PdfViewerComponent(selector: sgdea-document-viewer)
11) Publicar (mantenedores)
cd C:/Users/aguio/Repos/Front/Package/component-library/sgdea-component-library
npm run publish:lib
cd dist/ui-components
npm login
npm publish --access publicnpm view infodocviewdoc version
npm i [email protected]Resumen de adopcion en otro microfront
- Instalar deps alineadas (
infodocviewdoc+[email protected]). - Copiar preload de la seccion 6.1 (sin borrar history).
- Descargar blob → abrir modal →
<sgdea-document-viewer>. - Validar flujo shell → otro MFE → este MFE → PDF sin F5.
