(pdf.js) Build Error (Bundler) webpack returned errors to ember-auto-import

Hi there, I’ve been trying to import the PDF.js library and by extenstion pdfjs-dist into my ember app however I receive this error:

ERROR in ./node_modules/pdfjs-dist/build/pdf.js 1361:17
Module parse failed: Unexpected character '#' (1361:17)
File was processed with these loaders:
 * ./node_modules/babel-loader/lib/index.js
You may need an additional loader to handle the result of these loaders.
| 
|         class PDFDocumentLoadingTask {
>           static #docId = 0;
| 
|           constructor() {
 @ /tmp/broccoli-18121rh8YKoSzZQDd/cache-334-bundler/staging/app.js 19:44-123
Build Error (Bundler)

webpack returned errors to ember-auto-import


Stack Trace and Error Report: /tmp/error.dump.8d142691655ddaa06585780d1a612a8f.log

Dependancies:

{
  "name": "super-rentals",
  "version": "0.0.0",
  "private": true,
  "description": "Small description for super-rentals goes here",
  "repository": "",
  "license": "MIT",
  "author": "",
  "directories": {
    "doc": "doc",
    "test": "tests"
  },
  "scripts": {
    "build": "ember build --environment=production",
    "lint": "npm-run-all --aggregate-output --continue-on-error --parallel \"lint:!(fix)\"",
    "lint:fix": "npm-run-all --aggregate-output --continue-on-error --parallel lint:*:fix",
    "lint:hbs": "ember-template-lint .",
    "lint:hbs:fix": "ember-template-lint . --fix",
    "lint:js": "eslint . --cache",
    "lint:js:fix": "eslint . --fix",
    "start": "ember serve",
    "test": "npm-run-all lint test:*",
    "test:ember": "ember test"
  },
  "devDependencies": {
    "@ember/optional-features": "^2.0.0",
    "@ember/render-modifiers": "^2.0.4",
    "@ember/test-helpers": "^2.4.2",
    "@glimmer/component": "^1.0.4",
    "@glimmer/tracking": "^1.0.4",
    "babel-eslint": "^10.1.0",
    "broccoli-asset-rev": "^3.0.0",
    "ember-auto-import": "^1.11.3",
    "ember-cli": "~3.28.3",
    "ember-cli-app-version": "^5.0.0",
    "ember-cli-babel": "^7.26.6",
    "ember-cli-dependency-checker": "^3.2.0",
    "ember-cli-htmlbars": "^5.7.1",
    "ember-cli-inject-live-reload": "^2.1.0",
    "ember-cli-sri": "^2.1.1",
    "ember-cli-terser": "^4.0.2",
    "ember-data": "~3.28.0",
    "ember-export-application-global": "^2.0.1",
    "ember-fetch": "^8.1.1",
    "ember-load-initializers": "^2.1.2",
    "ember-maybe-import-regenerator": "^0.1.6",
    "ember-page-title": "^6.2.2",
    "ember-qunit": "^5.1.4",
    "ember-resolver": "^8.0.2",
    "ember-source": "~3.28.0",
    "ember-template-lint": "^3.6.0",
    "ember-wavesurfer": "0.0.5",
    "ember-welcome-page": "^4.0.0",
    "eslint": "^7.32.0",
    "eslint-config-prettier": "^8.3.0",
    "eslint-plugin-ember": "^10.5.4",
    "eslint-plugin-node": "^11.1.0",
    "eslint-plugin-prettier": "^3.4.1",
    "eslint-plugin-qunit": "^6.2.0",
    "loader.js": "^4.7.0",
    "npm-run-all": "^4.1.5",
    "pdfjs": "^2.4.7",
    "pdfjs-dist": "^3.1.81",
    "prettier": "^2.3.2",
    "qunit": "^2.16.0",
    "qunit-dom": "^1.6.0"
  },
  "engines": {
    "node": "12.* || 14.* || >= 16"
  },
  "ember": {
    "edition": "octane"
  },
  "dependencies": {
    "webpack": "^5.75.0",
    "webpack-cli": "^5.0.1"
  }
}

Component:

import Component from '@glimmer/component';
import PDFJS from 'pdfjs-dist';
// import pdfjsLib from 'pdfjs-dist/webpack';


import EmberObject from '@ember/object';

export default class PDFPreviewComponent extends Component {

}
'use strict';

const EmberApp = require('ember-cli/lib/broccoli/ember-app');

module.exports = function (defaults) {
  let app = new EmberApp(defaults, {
    // Add options here
    autoImport: {
      webpack: {
        entry: {
            "pdf.worker":  "pdfjs-dist/build/pdf.worker.entry",
        }
      }
    }
  });

  // Use `app.import` to add additional libraries to the generated
  // output files.
  //
  // If you need to use different assets in different
  // environments, specify an object as the first parameter. That
  // object's keys should be the environment name and the values
  // should be the asset to use in that environment.
  //
  // If the library that you are including contains AMD or ES6
  // modules that you would like to import into your application
  // please specify an object with the list of modules as keys
  // along with the exports of each module as its value.

  return app.toTree();
};

Any help will be much appreciated, I’ve been trying to figure this out for too long haha

It’s complaining about this line:

>           static #docId = 0;

Specifically the # which denotes a private class field, which is a relatively new Javascript feature (ES2022 i think?).

My guess is that you need some babel config or plugins or updates so that it properly transpiles this code. Off the top of my head I can’t recall what exactly you need to change but basically you want to be sure ember-auto-import and/or the rest of your build pipeline will support these new ES features.

This looks like the relevant plugin, I think: "@babel/plugin-proposal-private-methods"

Also it looks like there are other solutions described here including using the legacy version or downgrading the package version.

1 Like

As @dknutsen said you have to use legacy build , here is a working example where i have used pdfjs it may help you of how using it , because i have found issues in the beginning to make it work especially with an error related to pdf.worker.entry and enumerable Array _super property …

import { modifier } from 'ember-modifier';
import { tracked } from '@glimmer/tracking';
import { task } from 'ember-concurrency';
import fetch from 'fetch';

import pdfjsLib from 'pdfjs-dist/build/pdf';
import pdfjsWorker from 'pdfjs-dist/build/pdf.worker.entry';

export default modifier(function pdfparser(element /*, params, hash*/) {
  var section = element.querySelectorAll('.content');

  document.getElementById('loadpdf').addEventListener('change', (event) => {
    console.log('event', event);
    const path = (window.URL || window.webkitURL).createObjectURL(
      event.target.files[0]
    );

    pdfParser(path);
  });

  function pdfParser(file) {
    Object.defineProperty(Array.prototype, '_super', {
      enumerable: false,
    });

    pdfjsLib.GlobalWorkerOptions.workerSrc = pdfjsWorker;

    const PDFJS = pdfjsLib,
      pdfMime = 'application/pdf';
    // ad = ABOUtils.DOM,
    // [$, $$] = ad.selectors();

    const state = {
      mime: pdfMime,
      docs: [],
    };

    function parsePage(page, pageInfo) {
      return new Promise((resolve, reject) => {
        page.getOperatorList().then(function (ops) {
          const fns = ops.fnArray,
            args = ops.argsArray;

          let imgsFound = 0;
          args.forEach((arg, i) => {
            //Not a JPEG resource:
            if (fns[i] !== PDFJS.OPS.paintJpegXObject) {
              return;
            }

            console.log('loading', arg);
            imgsFound++;

            const imgKey = arg[0],
              imgInfo = {
                name: pageInfo.name + '-' + imgsFound + '.jpg',
                url: '',
              };
            pageInfo.images.push(imgInfo);

            page.objs.get(imgKey, (img) => {
              imgInfo.url = img.src;
            });
          });
        });

        //Full SVG:

        // Get viewport (dimensions)
        const scale = 1.5;
        const viewport = page.getViewport({ scale });

        pageInfo.svg = {
          w: viewport.width,
          h: viewport.height,
          doc: '',
        };

        // SVG rendering by PDF.js
        page
          .getOperatorList()
          .then((opList) => {
            var svgGfx = new PDFJS.SVGGraphics(page.commonObjs, page.objs);
            return svgGfx.getSVG(opList, viewport);
          })
          .then((svg) => {
            pageInfo.svg.doc = svg;
            resolve(pageInfo);
          });
      });
    }

    function handleFiles(filePath, docName) {
      console.log('files', filePath);
      const d = {
        name: filePath,
        pages: [],
      };

      PDFJS.getDocument(filePath)
        .promise.then(function (doc) {
          return new Promise((resolve, reject) => {
            const ppp = [];
            for (let i = doc.numPages; i > 0; i--) ppp.push(i);
            for (const p of ppp) {
              const pageInfo = {
                number: p,
                name: docName + '-' + p,
                images: [],
                svg: {},
              };

              doc.getPage(p).then(async (page) => {
                const pi = await parsePage(page, pageInfo);

                // section.insertChildAtIndex(pi.svg.doc,pageInfo.number);
                // let section =  [document.createElement('div'), document.createElement('div')];//document.body.querySelectorAll('.content');
                console.log('section ', section);
                section[pageInfo.number - 1].appendChild(pi.svg.doc);

                console.log('pageInfo.number........ ', pageInfo.number);
                if (pi && pageInfo.number == 1) {
                  resolve(pi);
                }
              });
            }
          });
        })
        .then((result) => {
          console.log('finish.......... ', result);

          const images = Array.prototype.slice.call(
            document.body.querySelectorAll('image')
          );
          const texts = Array.prototype.slice.call(
            document.body.querySelectorAll('text')
          );

          const players = Array(images.length + 1);

          for (const imgIndex in images) {
            players[imgIndex] = {};
            players[imgIndex].image = images[imgIndex];
          }

          players.shift();
          texts.shift();
          for (const textIndex in texts) {
            players[parseInt(textIndex / 10)].informations = [];
          }

          for (const textIndex in players) {
            let k = 9;
            for (let i = 0; i < k; i++) {
              players[textIndex].informations.push(
                texts[textIndex * k + i].textContent
              );
            }
          }
          console.log('players', players);

          for (const pp in players) {
            var player = players[pp];
            var form = document.createElement('FORM');
            form.setAttribute('method', 'post');
            form.setAttribute('action', "'/'");

            var fileInput = document.createElement('INPUT');
            fileInput.setAttribute('type', 'file');

            console.log('players', player.image.href.baseVal);

            fileInput.setAttribute('value', player.image.href.baseVal);

            form.appendChild(fileInput);

            fetch(player.image.href.baseVal, {
              method: 'GET',
              headers: {
                'Content-Type': 'application/json',
              },
            })
              .then((response) => response.blob())
              .then((blob) => {
                console.log('player', player);

                const body = new FormData();
                body.append('file', blob);
                const sportif = {
                  license: player.informations[1].split(' ')[1],
                  category: player.informations[1].split(' ')[3],
                };
                const generalites = {
                  name: `${player.informations[2].split('-')[0]} ${
                    player.informations[2].split('-')[1]
                  }`,
                  birthDate: player.informations[4].split('-')[0],
                  id: player.informations[5].split('-')[0],
                  club: player.informations[5].split('-')[1],
                  inscriptionDate: player.informations[3].split('-')[1],
                  inscriptionNumber: player.informations[3].split('-')[0],
                  genre: player.informations[4].split('-')[1],
                  nationalite: player.informations[4].split('-')[2],
                };

                body.append('sportif', JSON.stringify(sportif));
                body.append('generalites', JSON.stringify(generalites));

                fetch('http://localhost:8000/upload', {
                  // HTTP request type
                  method: 'POST',

                  // Sending our blob with our request
                  body: body,
                })
                  .then(async (response) => {
                    console.log('response ', response);
                  })
                  .catch((err) => alert(err));
              });
          }
        })
        .catch(function (error) {
          console.log(error);
          throw error;
        });
    }

    handleFiles(file, file);
  }
});

Thanks for the responses guys