Open YaromichSergey opened 1 month ago
pdf.js is removed from memory when you destroy the Angular component. Instead, you can simply hide the <ngx-extended-pdf-viewer>
component. You just have to make sure the component is visible before modifying the [src]
attribute. Maybe you need to add a timeout like so:
this.showPDF = true;
setTimeout(() => this.src="/assets/my-favorite-pdf-file.pdf", 0);
<ngx-extended-pdf-viewer [style.hidden]="!showPDF" [src]="src">
Note that this is pseudo-code - I didn't try it. If it works, please tell me, so I can fix the errors of my pseudo-code for the benefit of other users.
It's not what we are looking for. We need something global in case of saving viewer. I'm trying to initialize it with ComponentFactoryResolver to save instance of library but it still re-launch(pdf-worker) and others and it's a bit harder to use. Main problem to avoid load library(from source from cache what ever) and avoid executing JS each time it need. Best behavior: load library(all source what needs), cache them and each time we invoke it be ready to show document as it waits for them. We need to understand if it possible. By our investigating it looks like not, at least with how we using library.
There are checks preventing loading the viewer-*.js
and the pdf-*.js
twice. The check regarding pdf-*.js
seems to be broken, but at least the viewer shouldn't be loaded twice. However, when I tested it, none of these file were loaded twice. Can you confirm that?
Remains the worker. That's probably the most annoying file because it's so huge. After reading the api.js
file I believe it's possible to cache the worker, but I didn't manage to wrap my head around it yet.
How urgent is your issue? Are you ready to dive into the source code yourself? At the moment, I'm trying to catch up after my vacations, so I appreciate every help I can get!
We are really interesting in it. Unfortunately I can't help with it. I tested again and can see that viewer-*.js and pdf-.js loads only first time. We are waiting for caching workers(pdf.worker-) and all you can do as soon as you can implement it. If you can mention in some way with ready state of this it will be great. Thank you in advance
Issue #2329 is doing the exact opposite: they noticed I've implemented a memory leak, so the garbage collector can't remove the JavaScript resources. I'll tackle #2329 first. It might make your issue worse.
Here's something you can try: you can load the JavaScript files yourself. Actually you can even load the worker file yourself, but that means the worker is executed in the main thread, so it reduces the rendering performance. It depends on the use-case which tradeoff is worse.
private loadViewer(): void {
globalThis['ngxZone'] = this.ngZone;
this.ngZone.runOutsideAngular(() => {
this.needsES5().then((needsES5) => {
const viewerPath = this.getPdfJsPath('viewer', needsES5);
const script = this.createScriptElement(viewerPath);
document.getElementsByTagName('head')[0].appendChild(script);
});
});
}
private loadPdfJs() {
globalThis['ngxZone'] = this.ngZone;
this.ngZone.runOutsideAngular(() => {
if (!globalThis['pdfjs-dist/build/pdf']) {
this.needsES5().then((needsES5) => {
if (needsES5) {
if (!pdfDefaultOptions.needsES5) {
console.log(
"If you see the error message \"expected expression, got '='\" above: you can safely ignore it as long as you know what you're doing. It means your browser is out-of-date. Please update your browser to benefit from the latest security updates and to enjoy a faster PDF viewer."
);
}
pdfDefaultOptions.needsES5 = true;
console.log('Using the ES5 version of the PDF viewer. Your PDF files show faster if you update your browser.');
}
if (this.minifiedJSLibraries && !needsES5) {
if (!pdfDefaultOptions.workerSrc().endsWith('.min.mjs')) {
const src = pdfDefaultOptions.workerSrc();
pdfDefaultOptions.workerSrc = () => src.replace('.mjs', '.min.mjs');
}
}
const pdfJsPath = this.getPdfJsPath('pdf', needsES5);
if (pdfJsPath.endsWith('.mjs')) {
const src = pdfDefaultOptions.workerSrc();
if (src.endsWith('.js')) {
pdfDefaultOptions.workerSrc = () => src.substring(0, src.length - 3) + '.mjs';
}
}
const script = this.createScriptElement(pdfJsPath);
script.onload = () => {
if (!(globalThis as any).webViewerLoad) {
this.loadViewer();
}
};
document.getElementsByTagName('head')[0].appendChild(script);
});
} else if (!(globalThis as any).webViewerLoad) {
this.loadViewer();
}
});
}
private createScriptElement(sourcePath: string): HTMLScriptElement {
const script = document.createElement('script');
script.async = true;
script.type = sourcePath.endsWith('.mjs') ? 'module' : 'text/javascript';
this.pdfCspPolicyService.addTrustedJavaScript(script, sourcePath);
return script;
}
In your application, you can simplify the code a lot. You don't need all the options a general-purpose library needs.
I've got an idea how to improve performance in version 21. If everything goes according to plan, I'm going to move the code loading and managing the base library into a service, so it doesn't have to be loaded every time you navigate from page to page.
It will be great. Looking forward for your news. Thanks for replying here. As for the error with old version of chrome with new version. Do you have a plan to fix it? Or just throw error with event?. Unfortunately we still have old users with old browsers and need to support them. For now we have workaround with window.onerror but we understand that it's not the best idea. Could you share you thoughts?
Which bug are you referring to? Maybe Promise.withResolvers
? I think you might be able to polyfill it - but to my surprise, I haven't found a polyfill yet.
Yes, about this bug. I tried to polyfill it and it's isn't working. I tried to add to angular code something like
function promiseWithResolvers() {
let resolve;
let reject;
const promise = new Promise(
(res, rej) => {
// Executed synchronously!
resolve = res;
reject = rej;
});
return {promise, resolve, reject};
}
But it didn't work as expected(nothing changed). Don't know is it read code and can work(you can test it)
That's pretty much the approach I'd use, just slightly different - maybe that's why it's not working?
I'd add these lines to the module file or to the constructor of the component using <ngx-extended-pdf-viewer>
:
Promise.promiseWithResolvers() = function() {
let resolve;
let reject;
const promise = new Promise(
(res, rej) => {
// Executed synchronously!
resolve = res;
reject = rej;
});
return {promise, resolve, reject};
}
BTW, if everything fails, there's always the option to add the attribute [forceUsingLegacyES5]="true"
.
Have a look at version 21.0.0-alpha.0. I'd be very surprised if it's not full of bugs - but it works surprisingly good, and jumping between the demos of the showcase seems to be considerably faster.
I have already tested it and have this moments:
As for loading process, it's hard to say that it loads faster, need to re-test it again after your fixes. Thanks in advance
I have a question-request. How to cache/optimize library sources and loads. We use pdf library to view pdf. We have component which re-initialize a lot of times during user session. And every time we need to load js files. How to optimize this process? Is it possible to load only first time? We understand that js files caching and next time it's load from browser cache. But we still need time to process js. What is your recommendation for best optimization, reusabillity component? Thanks in advance