Forum Discussion

JohnCooper-be3c's avatar
JohnCooper-be3c
Community Member
7 months ago
Solved

Tighter security settings in browsers can impact dynamically loaded JavaScript libraries.

If you're encountering this issue, here's a heads-up. We noticed some challenges with a couple of Storyline courses that utilised unpkg.com's open-source JavaScript libraries dynamically. Specificall...
  • JohnCooper-be3c's avatar
    7 months ago

    CORS Errors with pdf-lib and Storyline — Why You Should Switch from unpkg.com to jsDelivr to dynamically load code

    I promised a fuller explanation - and here it is. Over the years I have posted several examples here (and seen my code appearing in other posts) where I suggested using the JavaScript library pdf-lib to create downloadable notes or certificates. 

    If your Storyline project has used any of my code (or other code derived from it) and it suddenly starts throwing CORS errors when generating PDFs, here’s what’s likely happening — and how to fix it.

    The Problem: CORS errors from unpkg.com

    In the original code, I used dynamic import() calls to load external JavaScript libraries like this:

    await import("https://unpkg.com/pdf-lib@1.17.1/dist/pdf-lib.js");

    This worked fine, but now browsers are enforcing stricter CORS (Cross-Origin Resource Sharing) rules, especially for JavaScript module imports.

    That unpkg.com link doesn't return the proper Access-Control-Allow-Origin header, which causes this error:

    Access to script at 'https://unpkg.com/...' from origin '...' has been blocked by CORS policy...

    This will prevent your Storyline course from loading the library at runtime, causing PDF generation to fail.

    ✅ The Solution: Switch to jsDelivr

    To resolve this, you simply need to load the library from a CDN that does send the correct CORS headers — like jsDelivr.

    Replace this:

    await import("https://unpkg.com/pdf-lib@1.17.1/dist/pdf-lib.js");

    With this:

    PDFLib = await import("https://cdn.jsdelivr.net/npm/pdf-lib@1.17.1/dist/pdf-lib.esm.min.js");

    (Don’t forget to declare let PDFLib; at the top of your script to make it available globally - I hadn't done that in my original examples and, it worked but was risky!)

    If you’re also using tiny-save-as to download the generated PDF, you’ll need to do the same in this section of code:

    await import("https://cdn.jsdelivr.net/npm/tiny-save-as@1.0.1/dist/tiny-save-as.esm.min.js")

    .then(({ default: saveAs }) => { saveAs(new Blob([pdfBytes]), filename); });

    Why This Matters

    • unpkg.com doesn’t always send CORS headers for ESM imports
    • jsDelivr is fully CORS-compliant and supports modern module usage
    • This fix makes your Storyline + PDF solution reliable across all modern browsers and LMS platforms