-
Notifications
You must be signed in to change notification settings - Fork 49
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
POC: printing with react-pdf #1924
Conversation
Cool, react ist schon geil. Und Web Components kommen auch immer mehr, toll dass es teilweise interop zwischen den Frameworks ermöglicht. |
Ich habe react + angular + storybook schon zusammen verwendet. Das klappt mehrheitlich. |
Ich habe hier zum ersten Mal etwas "echtes" mit React und mit Web Components gemacht. Kombiniert sowieso zum ersten Mal. Habe auch nicht die ganze Komplexität von React verwendet denke ich, aber ging mit Vorwissen von Vue recht schnell. Und JSX ist cooler als ich gedacht hätte als ich mich mal drauf eingelassen habe. |
036e150
to
457973c
Compare
15a6f3f
to
b8545ee
Compare
Meeting Discussion
|
639d5ea
to
aab62e4
Compare
8145a3e
to
1b1c253
Compare
a50a1be
to
2b10c46
Compare
676a63c
to
17daa28
Compare
PR ist grundsätzlich ready zum reviewen und mergen. Ich räume über die nächsten Tage noch weiter auf, solange es noch nicht gemerged ist. Aber zurückhalten müsst ihr euch trotzdem nicht, ist nicht gerade klein zu rebasen ;) Wenn gemerged eröffne ich dann einen neuen PR mit weiteren Verbesserungen. Aktuell ist die Print Preview auf dem Print-Tab implementiert, sowie der "Generate PDF" Button auf dem Grobprogramm. Beides läuft in einem Web Worker, kann aber für Entwicklung via Boolean in LocalPrintPreview.vue und LocalPDFDownloadButton.vue zurück auf Main Thread geschaltet werden. @usu ein Tipp: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Output ist bei mir im Moment aber nur "Hello world! I was rendered in a background worker...". By purpose oder noch was schief?
@@ -6,6 +6,7 @@ | |||
group="contentNodes" | |||
class="draggable-area d-flex flex-column pb-10" | |||
:class="{ 'min-height': layoutMode }" | |||
:invert-swap="true" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hab die Docu gelesen und verstehe immer noch nicht, was das macht? 😅
Was macht das genau?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bei mir hats auch erst bei dieser Erklärung mit Animation geklickt: https://github.com/SortableJS/Sortable/wiki/Swap-Thresholds-and-Direction
Beispiel das mich zu dieser Änderung bewegt hat: Sagen wir ich habe ein zweispaltiges ColumnLayout, in der linken Spalte ist ein grosses SiKo und die rechte Spalte ist leer. Unter dem ColumnLayout ist ein grosses Storyboard. Sowohl ColumnLayout wie auch Storyboard sind alleine schon höher als der Screen. Wenn ich das Storyboard in die rechte Spalte des ColumnLayouts draggen will, dann geht das nur mit invert-swap
.
Ohne invert-swap
ist die Drop Zone für "über dem ColumnLayout" bereits am unteren Rand des ColumnLayouts. Also noch bevor ich das Storyboard bis zur leeren Spalte gezogen habe, würde das Storyboard bereits komplett über dem ColumnLayout platziert.
Mit invert-swap
ist die Drop Zone für "über dem ColumnLayout" am oberen Rand des ColumnLayouts. So kann ich das Storyboard problemlos in die verschachtelte Drop Zone für die rechte Spalte ziehen, ohne dass es vorschnell ganz über das ColumnLayout platziert wird.
Standardmässig ist die Drop Zone 50% der Höhe des Elements, also wenn ich vorhin "am oberen Rand" gesagt habe bedeutet es eigentlich "in der oberen Hälfte". Die Höhe der Drop Zone kann man mit swap-threshold
einstellen, Standardwert ist 0.5
(50%). Das können wir dann in Zukunft mal noch optimieren.
Only works in Chromium-based browsers, not in Firefox. For Firefox support, we need to add https://www.npmjs.com/package/vite-plugin-worker Currently, i18n and hal-json-vuex don't work, because the worker thread does not have access to the memory and objects of the main thread. So we need to pass the translations and vuex store contents to the worker thread and construct instances of vue-i18n and hal-json-vuex there.
Also reimplements the pdf download button and pdf preview components in Vue. This means we do not have to "mix" and translate between Vue and React anymore. React is now purely used for PDF rendering, never HTML. Also prepares for easily switching between web worker and main thread in development.
We don't need this dependency anymore, now that we don't use React for HTML rendering anymore.
By avoiding all n+1 queries, we can improve the loading time from F5 until finished pdf preview in a full-fledged weekend camp from ~35 to ~18 seconds.
Ich habe jetzt noch Dummy-Implementationen für Vue-i18n und hal-json-vuex im Web Worker eingefügt, und somit kann wieder das volle PDF gerendert werden. Bei hal-json-vuex habe ich nur die read-only Features ohne Loading Handling etc. in 120 Zeilen re-implementiert. Für vue-i18n mache ich aktuell einfach ein @BacLuc bezüglich Performance, bei mir auf dem Laptop dauert das reine generieren des PDFs mit Web Worker 5-6 Sekunden, und das bei beiden Beispiel-Lagern der Dev-Daten. Vorher müssen aber natürlich viele Daten aus der API geladen werden. Ich habe da noch etwas optimiert, und von F5 bis fertige PDF-Preview (ohne dass Vite oder API Platform etwas neu kompilieren müssen) dauerts bei mir normalerweise um die 18 Sekunden für ein ca. 11-seitiges PDF, davon ca. 6 bis sich die Seite aufgebaut hat (Vuetify), 6-7 bis alle Daten aus der API geladen sind und eben 5-6 Sekunden fürs rendern des PDFs im Web Worker. Ich habe noch gelesen dass die Startup-Zeit von Web Workers auf Android recht schlecht ist, das müssen wir sicher noch im Auge behalten sobald das mal deployed ist. Ich habe noch diverse technische Schulden und Problemchen aufgeschrieben, und werde die dann noch in #1241 festhalten um sie zu tracken. |
7a7073d
to
491c52c
Compare
In Firefox gibt es noch warnings, aber die beeinträchtigen die Funktionalität nicht:
|
@@ -29,18 +29,23 @@ | |||
:title="result.title" | |||
class="mt-2" /> | |||
</div> | |||
<local-print-preview :config="config" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Als hint für die, die das auch ausprobieren.
Das PDF Rendern wird automatisch gestartet, sobald man die Seite öffnet.
Im Firefox ist das Feedback für "PDF ist fertig gerendert" nicht so offensichtlich.
Im chrome sieht man dann das preview (aber nicht in den downloads), in firefox sieht man das pdf es nicht im preview, aber in den downloads
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bin nicht ganz sicher was du meinst. Die preview wird bei mir in firefox wie auch chromium im iframe angezeigt, wenn auch mit unterschiedlichen pdf viewers.
Ich glaube auf mobile hatte es das preview pdf bei mir auch mal heruntergeladen statt angezeigt, meinst du so etwas?
frontend/src/components/print/scheduleEntry/contentNode/ColumnLayout.jsx
Outdated
Show resolved
Hide resolved
Ja, habe ich in #1241 auch so festgehalten. Müssten wir möglicherweise noch shimmen oder so. Die funktionen werden nicht gebraucht in unserem fall, aber React überprüft sofort beim Laden ob sie verfügbar sind. |
Können wir mergen? |
Refs #1241
Fixes #2023
Ich bin bei der tausendsten Suche nach custom PDF renderers für Vue 3 auf react-pdf gestossen. Das ist quasi ein Modul für React-Apps, das es erlaubt einen Komponentenbaum mit PDF als Zielformat statt HTML zu rendern. Leider gibt es für Vue bisher kein auch nur ansatzweise ähnlich ausgereiftes Package, wohl unter anderem weil Custom Renderers erst seit Vue 3 möglich sind.
Eine separate React-App analog unserem Nuxt Print Preview Service wäre natürlich denkbar. Aber ich wollte mal sehen wie weit ich komme wenn ich eine inline Vorschau möchte (#microfrontends 😆).
Um react-pdf in unserem Frontend nutzbar zu machen habe ich hier eine solche React-Komponente in eine Web Component verpackt. Web Components ist ein eher neuer Web-Standard. Es ist ein Komponentensystem (wie Vue-Komponenten oder React-Komponenten) das aber direkt nativ von Browsern untersützt wird. Web Components erlauben es, Custom HTML Elemente zu definieren und zu nutzen. Wenn die PDF-Preview-React-Komponente erst mal als solches Custom HTML Element verfügbar ist, kann man sie in Vue ganz normal nutzen, wie jedes andere HTML-Element:<ecamp3-print-preview />
Um react-pdf in unserem Frontend nutzbar zu machen, habe ich eine solche React-Komponente in eine Vue-Komponente gewrappt, welche die "Übersetzung" macht. Das war gar nicht mal so schwierig, abgeschaut habe ich bei https://github.com/alkin/vue-react/blob/master/src/vue-react.jsUm react-pdf in unserem Frontend nutzbar zu machen habe ich zwei simple Vue-Komponenten für Print Preview und Print Download Button geschrieben, die dann React verwenden um ein PDF zu rendern. React wird nie verwendet um HTML zu rendern, nur PDF. Ausserdem kann man in diesen beiden Komponenten separat via Boolean umschalten, ob das PDF im Main Thread generiert werden soll (gut für Debugging) oder in einem separaten Thread in einem Web Worker (gut für mittlere bis grosse PDFs und für Produktion).
Das Ganze funktioniert meiner Meinung nach erstaunlich gut. Inline PDF Preview und PDF Download Link kommen beides mit react-pdf mit, die habe ich einfach nach Vue portiert und noch etwas vereinfacht. Alle Anforderungen die wir in #479 (comment) festgehalten haben werden abgedeckt (CSS Grid Layout ist nicht unterstützt, aber für Tabellen gibts eine Erweiterung, und den Picasso habe ich mit Flexboxen und Absolute Positioning gemacht, welche beide sehr gut unterstützt sind).
react-pdf.mp4
Pros
Cons
Web Components, React), weitere Technologien zu lernen für Einsteiger. Wäre bei Weasy und ein Stück weit bei paged.js aber auch sohier sollten wir denke ich unbedingt mit asynchron nachgeladenen Chunks arbeitender Web Worker wird bereits erst on demand geladenLive reloading während der Entwicklung funktioniert nicht, muss jeweils mit F5 neu laden. Machts aber bei vielen Arten von Änderungen schon automatisch.