Skip to content
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

"Uncaught TypeError: root is undefined" when importing from package #2804

Closed
RST-J opened this issue Dec 10, 2020 · 16 comments
Closed

"Uncaught TypeError: root is undefined" when importing from package #2804

RST-J opened this issue Dec 10, 2020 · 16 comments

Comments

@RST-J
Copy link

RST-J commented Dec 10, 2020

I am a bit heavily lost in the quest for a solution to my problem, so apologies if this is not the right place for my question. It appeared the least wrong one to start with and I happily take recommendations where to go with it otherwise.

I want to setup pdf.js in our Rails app and followed the recommendation for webpack users which basically says to simply use import pdfjsLib from 'pdfjs-dist/webpack'; which takes care of setting up the worker. With this code in my JavaScript I get the following error in my browser console when I access a page that triggers this code:

Uncaught TypeError: root is undefined
    webpackUniversalModuleDefinition pdf.js:77
    js                               pdf.js:78

I cannot find the respective code in the pdf.js repository, I assume it is generated by some build/release pipeline. But here is what the respective file in node_modules/pdfjs-dist/build/pdf.js looks like. It starts with something that appears to me like something webpack specific:

(function webpackUniversalModuleDefinition(root, factory) {
	if(typeof exports === 'object' && typeof module === 'object')
		module.exports = factory();
	else if(typeof define === 'function' && define.amd)
		define("pdfjs-dist/build/pdf", [], factory);
	else if(typeof exports === 'object')
		exports["pdfjs-dist/build/pdf"] = factory();
	else
		root["pdfjs-dist/build/pdf"] = root.pdfjsLib = factory();
})(this, function() {
// all the code
});

The flagged lines belong to the body of a function defined like this:

// define __esModule on exports
__w_pdfjs_require__.r = function(exports) {
  if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {                  // <-- Line 77
    Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); // <-- Line 78
  }
  Object.defineProperty(exports, '__esModule', { value: true });
};

A gist with the complete pdf.js from the pdfjs-dist package can be viewed here

That is my situation and I am lost between webpacker, webpack and pdf.js. My intuition was that I probably need to tell webpack(er?) that it should inject something for the root value. However, this is a formal parameter of the module definition as far as I see it. So what value for what keyword would I have to inject exactly and where? I was down to the imports-loader for webpack but either did not figure out how to correctly embed its rules in the webpack config in config/webpack/environment.js. I try & only-errored for some time and gave up.

On the other hand I think/hope/assume that it should be possible to somehow only do what the README for pdf.js says: Import the thing via webpack.js. After all it is advertised as the zero-configuration method for Webpack users and I would like to be one of that happy users. Maybe I am only missing something very simple that is painfully obvious if you know it ... but I just don't know and couldn't figure out in three days so far. So, anyone a hint or maybe even the solution? 😃

@RST-J RST-J changed the title "Uncaught TypeError: root is undefined" when importing package "Uncaught TypeError: root is undefined" when importing from package Dec 10, 2020
@rossta
Copy link
Member

rossta commented Dec 27, 2020

This is either a bug or missing documentation in the pdf.js library. I don’t believe there’s anything Webpacker can do specifically to address the behavior you’re seeing. Could you open an issue there and close this one?

@RST-J
Copy link
Author

RST-J commented Dec 28, 2020

Thanks for the reply. I was at the pdf.js repo already and started writing my issue there when I thought, I probably should start from the top of the stack of tools I use. So I am now (more) confident to go over there and actually post it. 👍

@Genkilabs
Copy link

@RST-J Did you ever figure this out? I have spent hours trying to make Rails 6.1 play nice with pdf.js to no avail. I have tried using the ES5, commonjs and UMD flavors of the library and nothing works.

The response from your posting on the pdf.js library repo basically bounced it back here:

Did you try the Webpack example standalone, i.e., outside of Webpacker/Rails? If that works, and it should, then it's related to the integration with Webpacker/Rails and that's unfortunately something we don't know anything about and can't provide meaningful assistance for.

Meaning, they believe the issue is in fact a Rails/webpacker thing...

@RST-J
Copy link
Author

RST-J commented Feb 18, 2021

@Genkilabs No, I unfortunately I didn't yet. I did some more trial and error without success and then decided to postpone that. It is not urgent yet. We will get back at this some time soon and if we cannot get it running we probably will just copy the latest release into our own sources which then hopefully works out somehow. Of course that means updating is not just a yarn away.

I didn't try out the standalone Webpack example either. Because I don't have a real clue what it even is yet. We don't use heavy client side JavaScript and before Webpacker we had Gems for libraries. So that is stuff we have to get a grip on first. And that is the problem, I have no idea what that root parameter means and where it is expected to come from and where Webpacker should make sure it is provided and why it doesn't do it and which loader/preprocessor I had to configure at what exact place with which config to make it happen ...

Did you run into the same error or something else?

@rossta I am reopening this for now because they rather think it is an Webpacker issue, see mozilla/pdf.js#12786. It seems that a few others also had this or similar problems. I cannot really judge anything here but I suspect, if pdfjs would not work with standalone Webpack that would have caused a big echo in the pdfjs repo.

@RST-J RST-J reopened this Feb 18, 2021
@Genkilabs
Copy link

Genkilabs commented Feb 18, 2021

@RST-J

Did you run into the same error or something else?

Yes. Same issue, different nuance. Running on Rails 6.1 Ruby 3.0. We use Yarn and exclusively "pack" tags for both our JS and SCSS. Since we don't run the "classic" asset pipeline I can't just side-load the ES5 flavor, and frankly, running a legacy pipeline for just a single JS file seems like doing-it-wrong.

The text of the error I get is Uncaught TypeError: Cannot set property 'pdfjsLib' of undefined which comes from the same line (after compilation pdf.js:77), specifically the chained assignment root["pdfjs-dist/build/pdf"] = root.pdfjsLib = factory(); which can be seen in the UMD flavor here https://github.com/mozilla/pdfjs-dist/blob/master/build/pdf.js#L31

Using the browser debugger I stepped in and verified that at this point in the execution the local var 'root' is indeed "undefined". Since the standard example use of the UMD definition looks like this:

  if(typeof exports === 'object' && typeof module === 'object')
    module.exports = factory();
  else if(typeof define === 'function' && define.amd)
    define("library", [], factory);
  else if(typeof exports === 'object')
    exports["library"] = factory();
  else
    root["library"] = factory();
})

it leads me to believe that the issue may be a combination of webpacker not managing root correctly and/or one of the projects not including correct typeof data from config to make that switch work? IDK tho...

Unfortunately, this came along with upgrading our entire stack from Rails 5 where we used this lib as a globally-scoped variable; so this really needs a solution for us. For the moment, I think I'll make a stand alone script tag pointing at a static, minified pdf.js sitting on S3 or something, and revisit this later. <_<

@Genkilabs
Copy link

@RST-J I have a WORKAROUND for running pdf.js on Rails 6.1 Ruby 3.0 with webpacker. This Gist is not as good as if pdf.js exported correctly, but it will get you through the day.

https://gist.github.com/Genkilabs/a5285020ca548f589b9c46497afca941

NOTE: I did NOT do anything like require('pdfjs-dist/es5/build/pdf') in my application.js and I did not import it in my module, because its a globally-scoped kludgearound!

@RST-J
Copy link
Author

RST-J commented Feb 19, 2021

Thanks a lot for sharing @Genkilabs, looks like we can get around shipping our custom copy of pdfjs which is a big gain already 😃

I'll report here if we get it working without the workaround. Although I'm not too optimistic about that.

@rossta
Copy link
Member

rossta commented Feb 19, 2021

I have a working demo of integrating Webpacker 6.0.0.beta.5 with PDF.js: https://github.com/rossta/webpacker-6.0.0.beta-pdfjs-demo

The main issue I ran into is that the main 'pdfjs-dist' package does not appear to work as an ES module, so import pdfjs from 'pdfjs-dist/webpack' results in an undefined import. However, const pdfjs = require('pdfjs-dist/webpack') does work as expected.

There is a mirror site which packages 'pdfjs-dist' as an ES module; I would expect normal ES import syntax would work for you if you choose this distribution.

Hope that's helpful.

@RST-J
Copy link
Author

RST-J commented Feb 23, 2021

@rossta I will try whether that works out in our project. I hope there is no other stuff that doesn't work with that version.

To be clear: Webpacker 5.2.1 does not work? I changed the version in your dummy and rebuilt with hopefully no remaining artifacts using rm -r tmp/cache/* && bundle install && rails webpacker:clobber && rails s
That led to a blank page in the browser. However, it didn't show me the same error in the console. (Maybe because error output has to be configured?)

No surprise though if 5.2.1 doesn't work. I actually ask because I got the same result using the same steps when I set Webpacker to 6.0.0.pre.2. Could you confirm that this later version does not work (anymore)? Or have I messed something up when switching the version?

@rossta
Copy link
Member

rossta commented Feb 24, 2021

@RST-J I think I found out what's going on. I've got pdf.js working for Webpacker 5 in the demo/webpacker-5 branch. Could you test my fix described below?

There was a problem with the Webpacker 5 config after all (it's fixed in Webpacker 6). To fix in your project on Webpacker 5, you'll want to disable the default Webpacker loader rule for processing node_modules. To do so, your config should look something like the following:

// config/webpack/environment.js

const { environment } = require('@rails/webpacker')

environment.loaders.delete('nodeModules') // <== deletes Webpacker loader rule for node_modules

module.exports = environment

Webpacker 5 is configured to run Babel transpilation on your node_modules libraries—turns out this caused a lot of unexpected bugs. You can read more about the history in this PR.

Apologies, this should have occurred to me earlier. Let me know if this works for you.

@RST-J
Copy link
Author

RST-J commented Feb 24, 2021

@rossta you are my personal hero of (at least) the day. Just tried it in our project, it works. 😄👍

And apology rejected. 😉 It would have taken me ages (or a lucky guess on the right search terms) to find that out.

@RST-J RST-J closed this as completed Feb 24, 2021
@Genkilabs
Copy link

@RST-J Thank you for solving this. It seems much more elegant than my amateur kludge. I wonder, though, will deleting that loader cause trouble for other libraries? I could always try and find out in our next sprint I suppose...
Anyways, I'll get moved over to Webpacker 6 asap, and thanks again.

@RST-J
Copy link
Author

RST-J commented Feb 24, 2021

@Genkilabs all kudos is due to @rossta

I have not observed any issues with that removed loader in my development environment so far. Don't know how much this tells but we at least require from @material/material-components-web, jquery, trix and @rails/actiontext in node_modules.

I expect this will not be any different in production then. But when in doubt that is something Murphy has to decide upon.

@rossta
Copy link
Member

rossta commented Feb 24, 2021

@Genkilabs I don't know your stack so I'm making assumptions, but I doubt you'll have issues with this change as it's not likely for libraries to require you to run babel transpilation on their contents to be used.

@Genkilabs
Copy link

@Genkilabs I don't know your stack so I'm making assumptions, but I doubt you'll have issues with this change as it's not likely for libraries to require you to run babel transpilation on their contents to be used.

Perfect! Indeed we do not use Babel for that. Thanks again.

@sbilharz
Copy link

We indeed had issues with deleting the loader altogether, namely IE compatibility of some packages we use. After all, this is what babel is there for, so we shouldn't be too surprised about that. Depending on what libraries you include and which modern JS features they use, you could face similar problems even with current browsers that might be hard to detect. We defused the fix for the original issue to be more specific and only exclude the pdfjs package from transpilation:

// config/webpack/environment.js
const { environment } = require('@rails/webpacker')
let nodeModules = environment.loaders.find(loader => loader.key === 'nodeModules')
nodeModules.value.exclude = new RegExp(nodeModules.value.exclude.source + "|pdf")
module.exports = environment

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants