diegomura / react-pdf

📄 Create PDF files using React
https://react-pdf.org
MIT License
14.95k stars 1.18k forks source link

Can't get it to work with Meteor #317

Closed serkyen closed 6 years ago

serkyen commented 6 years ago

OS: macOs 10.13.4

React-pdf version: "@react-pdf/renderer": "^1.0.0-alpha.17",

Description: I am just trying to set up a simple functioning download PDF button using the from the example provided in the 'Advanced' section of the docs.

Here is my code I am using...


import { PDFDownloadLink, Document, Page } from '@react-pdf/renderer';

class PDFButton extends React.Component {
    render() {
        const MyDoc = (
          <Document>
            <Page>
              // My document data
            </Page>
          </Document>
        );

        return (
            <div>
                <PDFDownloadLink document={MyDoc} fileName="somename.pdf">
                   {({ blob, url, loading, error }) => (
                     loading ? 'Loading document...' : 'Download now!'
                    )}
                </PDFDownloadLink>
            </div>
        )
    }
}

Receiving the following error...

Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

package.json...

"dependencies": {
    "@fortawesome/fontawesome": "^1.1.5",
    "@fortawesome/fontawesome-free-solid": "^5.0.10",
    "@fortawesome/react-fontawesome": "0.0.18",
    "@react-pdf/renderer": "^1.0.0-alpha.17",
    "antd": "^2.10.4",
    "bcrypt": "^1.0.3",
    "fabric": "^2.2.1",
    "griddle-react": "^1.13.1",
    "image-compressor.js": "^1.1.3",
    "jquery": "^3.1.1",
    "moment": "^2.22.2",
    "prop-types": "^15.6.2",
    "react": "^16.5.2",
    "react-collapse": "^4.0.3",
    "react-color": "^2.13.8",
    "react-dom": "^16.5.2",
    "react-icons": "^2.2.7",
    "react-router": "^3.0.0",
    "react-sortable-hoc": "^0.6.8",
    "rgba-convert": "^0.3.0"
  },
  "engines": {
    "node": "4.8.1"
  },
  "devDependencies": {
    "babel-plugin-transform-class-properties": "^6.24.1",
    "enzyme": "^2.7.1",
    "expect": "^1.20.2"
  },
  "babel": {
    "plugins": [
      "transform-class-properties"
    ]
  }

What am I doing wrong here? Thanks

How to replicate issue including code snippet (if applies):

You can make use of react-pdf REPL to share the snippet

nihakue commented 6 years ago

Hey serkyen,

I don't work on react-pdf, but I suspect your problem has to do with this section:

<Document>
  <Page>
    // My document data
  </Page>
</Document>

Page is expecting some children (see the quick-start guide). I suppose the docs could be more explicit about this, but this is more a general React thing. You can't have a component which renders 'undefined'. null is OK, but the Page component just renders its children.

So add some content to MyDoc and that example should work.

For example, you could replace it with:

  <Document>
    <Page>
      <View>
        <Text>Section #1</Text>
      </View>
      <View>
        <Text>Section #2</Text>
      </View>
    </Page>
  </Document>
serkyen commented 6 years ago

@nihakue, thanks for the response.

I tried that, but still the same error.

The funny thing is that when I made that change and refreshed, naturally, the error changed to 'View' is not defined, so I added 'View' into the import...

import { PDFDownloadLink, Document, Page, View} from '@react-pdf/renderer';

Then it went back to the same original error, even though 'Text' was still missing from the import.

Also, to shed some more light, when I collapse the error in the console, I see this...

warningWithoutStack | @ | modules.js?hash=7cae…6a8280d5cb835:22004
warning | @ | modules.js?hash=7cae…6a8280d5cb835:22423
createElementWithValidation | @ | modules.js?hash=7cae…6a8280d5cb835:23373
render | @ | OrderForm.js:1169
...

Line 1169 on OrderForm.js points to this line...

<PDFDownloadLink document={MyDoc} fileName="somename.pdf">

serkyen commented 6 years ago

Just to try it another way, if I hook up a button to this...

handlePrint = () => {

    const MyDoc = (
      <Document>
        <Page>
          <View>
            <Text>Section #1</Text>
          </View>
          <View>
            <Text>Section #2</Text>
          </View>
        </Page>
      </Document>
    );

    ReactPDF.render(<MyDoc />, `${__dirname}/example.pdf`);
  }

Upon clicking the button, I get this error...

Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: <DOCUMENT />. Did you accidentally export a JSX literal instead of a component?

and this...

Uncaught Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
    at invariant (modules.js?hash=7cae2fe62e95b598133c39163bc6a8280d5cb835:529007)
    at getFiberTagFromObjectType (modules.js?hash=7cae2fe62e95b598133c39163bc6a8280d5cb835:521583)
    at createFiberFromElement (modules.js?hash=7cae2fe62e95b598133c39163bc6a8280d5cb835:521543)
    at reconcileSingleElement (modules.js?hash=7cae2fe62e95b598133c39163bc6a8280d5cb835:524611)
    at reconcileChildFibers (modules.js?hash=7cae2fe62e95b598133c39163bc6a8280d5cb835:524668)
    at reconcileChildrenAtExpirationTime (modules.js?hash=7cae2fe62e95b598133c39163bc6a8280d5cb835:525047)
    at reconcileChildren (modules.js?hash=7cae2fe62e95b598133c39163bc6a8280d5cb835:525030)
    at updateHostRoot (modules.js?hash=7cae2fe62e95b598133c39163bc6a8280d5cb835:525301)
    at beginWork (modules.js?hash=7cae2fe62e95b598133c39163bc6a8280d5cb835:525850)
    at performUnitOfWork (modules.js?hash=7cae2fe62e95b598133c39163bc6a8280d5cb835:527887)
diegomura commented 6 years ago

Hey! Some things to mention:

serkyen commented 6 years ago

@diegomura

Ok so just to be clear, none of this code in the docs should be running on the client, only on the server?

Point 1 If I simply try to move the import lines...

import { Page, Text, View, Document, StyleSheet } from '@react-pdf/renderer';
import ReactPDF from '@react-pdf/renderer';

...to a file in the server, I get the following error...

packages/modules.js:5199
    const [encoded, positions] = this.src.encode(str);
          ^

SyntaxError: Unexpected token [
    at Object.exports.runInThisContext (vm.js:53:16)
    at /Users/MacBookPro/Desktop/myapp/.meteor/local/build/programs/server/boot.js:332:30
    at Array.forEach (native)
    at Function._.each._.forEach (/Users/MacBookPro/.meteor/packages/meteor-tool/.1.5.4_1.17v9aqi++os.osx.x86_64+web.browser+web.cordova/mt-os.osx.x86_64/dev_bundle/server-lib/node_modules/underscore/underscore.js:79:11)
    at /Users/MacBookPro/Desktop/myapp/.meteor/local/build/programs/server/boot.js:158:5
    at /Users/MacBookPro/Desktop/myapp/.meteor/local/build/programs/server/boot.js:388:5
    at Function.run (/Users/MacBookPro/Desktop/myapp/.meteor/local/build/programs/server/profile.js:510:12)
    at /Users/MacBookPro/Desktop/myapp/.meteor/local/build/programs/server/boot.js:387:11
Exited with code: 1
Your application is crashing. Waiting for file change.

I also tried changing the lines as follows...

import { PDFDownloadLink, Document, Page, View, Text } from '@react-pdf/renderer/dist/react-pdf.browser.js';
import ReactPDF from '@react-pdf/renderer/dist/react-pdf.browser.js';

Then I get...

Error: Cannot find module '@react-pdf/renderer/dist/react-pdf.browser.js'

So I had a look at the node-modules/@react-pdf directory and that file is actually not there...

image

I also tried changing it to...

import { PDFDownloadLink, Document, Page, View, Text } from '@react-pdf/renderer/dist/react-pdf.browser.es.js';
import ReactPDF from '@react-pdf/renderer/dist/react-pdf.browser.es.js';

Then I get...

packages/modules.js:5132
import _classCallCheck from 'babel-runtime/helpers/classCallCheck';
^^^^^^

SyntaxError: Unexpected reserved word
...

I don't really mind if it is server or client side. I just need a way to be able to create PDF's with values from the DB, for users to download and I would much prefer to do it with HTML templates rather than using PDFkit.

diegomura commented 6 years ago

Ok so just to be clear, none of this code in the docs should be running on the client, only on the server?

No. Doc examples are for both node and browser.

Let me rewind a bit first: this library is both to generate PDF document client or server-side (aka. node or web). The way you define the documents in both scenarios is exactly the same, using Document, Page, View and so on. However, because these environments are very different, each react-pdf build has some specific features regarding the env. For example, when using react-pdf in a web environment, you have PDFDownloadLink (which does not make sense in node). Or if you are using react-pdf on a node project, you have ReactPDF.render to save the doc into the file system (which of course does not make sense in the web).

How does react-pdf know if it's running in a node or browser environment? Because of the main and browser entry points in the package.json file. Bundlers such as webpack checks for the presence of browser, and if any, loads the module from there. What I think is going on is that meteor is not loading from these browser entry points, so PDFDownloadLink is undefined.

So when you say that "I don't really mind if it is server or client side", I think it's crucial for you to know that, because regarding this fact you will have access to some parts of the API instead of others.

Sorry'@react-pdf/renderer/dist/react-pdf.browser.js' didn't exists. I forgot to write the type of build. The error you're having when loading from react-pdf.browser.es.js is because this is the ES6 build and you're not transpiling modules. Try loading the lib from the CommonJS build (react-pdf.browser.cjs.js` instead.

Hope this explained a bit why is necessary to know where docs are going to be rendered. Sorry if I was a bit redundant.

serkyen commented 6 years ago

@diegomura Thank you for the detailed explanation.

So after changing the import line to load from react-pdf.browser.cjs.js on the client side, I managed to get the PDFDownloadLink to work successfully with meteor. Thanks! 👍

Now, if I wanted to do this server side (instead of using PDFDownloadLink), using...

import { Page, Text, View, Document, StyleSheet } from '@react-pdf/renderer/dist/react-pdf.browser.cjs.js';
import ReactPDF from '@react-pdf/renderer/dist/react-pdf.browser.cjs.js';

results in this error...

Error: Module version mismatch. Expected 46, got 48.
    at Error (native)
    at Object.Module._extensions..node (module.js:434:18)
    at Module.load (module.js:343:32)
    at Function.Module._load (module.js:300:12)
    at Module.require (module.js:353:17)
    at require (internal/module.js:12:17)
    at initNode (/Users/MacBookPro/Desktop/myapp/node_modules/nbind/dist/nbind.js:141:15)
    at /Users/MacBookPro/Desktop/myapp/node_modules/nbind/dist/nbind.js:115:13
    at findCompiledModule (/Users/MacBookPro/Desktop/myapp/node_modules/nbind/dist/nbind.js:79:13)
    at find (/Users/MacBookPro/Desktop/myapp/node_modules/nbind/dist/nbind.js:93:13)
    at Object.init (/Users/MacBookPro/Desktop/myapp/node_modules/nbind/dist/nbind.js:104:5)
    at Object.<anonymous> (/Users/MacBookPro/Desktop/myapp/node_modules/yoga-layout/dist/entry-node.js:18:25)
    at Module._compile (module.js:409:26)
    at Object.Module._extensions..js (module.js:416:10)
    at Module.load (module.js:343:32)
    at Function.Module._load (module.js:300:12)
Exited with code: 1
Your application is crashing. Waiting for file change.

And using...

import { Page, Text, View, Document, StyleSheet } from '@react-pdf/renderer/dist/react-pdf.cjs.js';
import ReactPDF from '@react-pdf/renderer/dist/react-pdf.cjs.js';

I get this error:

packages/modules.js:5185
    const [encoded, positions] = this.src.encode(str);
          ^

SyntaxError: Unexpected token [
    at Object.exports.runInThisContext (vm.js:53:16)
    at /Users/MacBookPro/Desktop/myapp/.meteor/local/build/programs/server/boot.js:332:30
    at Array.forEach (native)
    at Function._.each._.forEach (/Users/MacBookPro/.meteor/packages/meteor-tool/.1.5.4_1.17v9aqi++os.osx.x86_64+web.browser+web.cordova/mt-os.osx.x86_64/dev_bundle/server-lib/node_modules/underscore/underscore.js:79:11)
    at /Users/MacBookPro/Desktop/myapp/.meteor/local/build/programs/server/boot.js:158:5
    at /Users/MacBookPro/Desktop/myapp/.meteor/local/build/programs/server/boot.js:388:5
    at Function.run (/Users/MacBookPro/Desktop/myapp/.meteor/local/build/programs/server/profile.js:510:12)
    at /Users/MacBookPro/Desktop/myapp/.meteor/local/build/programs/server/boot.js:387:11
Exited with code: 1
Your application is crashing. Waiting for file change.

Is there anyway around this? Really appreciate your help

diegomura commented 6 years ago

Error: Module version mismatch. Expected 46, got 48.

This happens when you installed react-pdf (and in the process building Yoga) with one particular Node version, and running it with other. However, you shouldn't use react-pdf.browser.cjs.js if you want to generate docs server-side.

SyntaxError: Unexpected token [

This is beyond Meteor. Seems like there's a dependency using some JS features that your Node version does not support (destructuring in this case). What Node version are you using? The only fix here is upgrading Node unless to 8.12.0 which is the LTS version, if possible to version 10. Isn't bad idea to do it either way 😄

serkyen commented 6 years ago

@diegomura

This happens when you installed react-pdf (and in the process building Yoga) with one particular Node version, and running it with other. However, you shouldn't use react-pdf.browser.cjs.js if you want to generate docs server-side.

Can you please elaborate on this. I just upgraded nodejs to 10.10.0, uninstalled @react-pdf and reinstalled it (to rebuild Yoga), then the error changed to... Error: Module version mismatch. Expected 46, got 64.

And simply using import ReactPDF from '@react-pdf/renderer'; also results in the SyntaxError: Unexpected token [ error.

This is beyond Meteor. Seems like there's a dependency using some JS features that your Node version does not support (destructuring in this case). What Node version are you using? The only fix here is upgrading Node unless to 8.12.0 which is the LTS version, if possible to version 10. Isn't bad idea to do it either way 😄

As mentioned, I just upgraded node to 10.10.0 and I am still getting the same error unfortunately.