2

I am trying to use WebViewer imported from "@pdftron/webviewer", code below marked as number 1 is code that I use in React.js app and it works fine, while code number 2 is code that I use in Next.js app that throws this error:

Unhandled Runtime Error TypeError: WebViewer is not a function

Code number 1 (used in React.js app):

import { useEffect, useRef } from "react";
import WebViewer from "@pdftron/webviewer";
import "./App.css";

export default function App() {
  const viewerDiv = useRef<HTMLDivElement>(null);
  useEffect(() => {
    WebViewer({ path: "./lib", initialDoc: "./sample.doc" }, viewerDiv.current as HTMLDivElement);
  }, []);
  return (
    <div>
      <div className="webviewer" ref={viewerDiv}></div>
    </div>
  );
}

Code number 2 (used in Next.js app):

import dynamic from "next/dynamic";
const WebViewer = dynamic(() => import("@pdftron/webviewer"), { ssr: false });
import { useEffect, useRef } from "react";

export default function Editor() {
  const viewerDiv = useRef(null);
  useEffect(() => {
    WebViewer(
      {
        path: "webviewer",
        initialDoc: "http://www.africau.edu/images/default/sample.pdf",
      },
      viewerDiv.current
    );
  }, []);
  return (
    <div>
      <div className={"webviewer"} ref={viewerDiv}></div>
    </div>
  );
}

Can somebody explain me why am I getting this error within Next.js app and how to fix it?

UPDATE: I went from js to ts in Next.js app also and got this warnings:

Argument of type '() => Promise<typeof import("/home/petar/Workspace/next-ts-editor/node_modules/@pdftron/webviewer/types")>' is not assignable to parameter of type 'DynamicOptions | Loader'. Type '() => Promise<typeof import("/home/petar/Workspace/next-ts-editor/node_modules/@pdftron/webviewer/types")>' is not assignable to type '() => LoaderComponent'. Type 'Promise<typeof import("/home/petar/Workspace/next-ts-editor/node_modules/@pdftron/webviewer/types")>' is not assignable to type 'LoaderComponent'. Type 'typeof import("/home/petar/Workspace/next-ts-editor/node_modules/@pdftron/webviewer/types")' is not assignable to type 'ComponentType | { default: ComponentType; }'. Type 'typeof import("/home/petar/Workspace/next-ts-editor/node_modules/@pdftron/webviewer/types")' is not assignable to type '{ default: ComponentType; }'. Types of property 'default' are incompatible. Type '(options: WebViewerOptions, viewerElement: HTMLElement) => Promise' is not assignable to type 'ComponentType'. Type '(options: WebViewerOptions, viewerElement: HTMLElement) => Promise' is not assignable to type 'FunctionComponent'. Type 'Promise' is missing the following properties from type 'ReactElement<any, any>': type, props, key

This expression is not callable. Not all constituents of type 'ComponentType' are callable. Type 'ComponentClass<WebViewerOptions, any>' has no call signatures.

  • 1
    `next/dynamic` is used to dynamically import _React_ _components_. To dynamically import a regular JavaScript library you can look into a solution like suggested in [Why am I getting ReferenceError: self is not defined in Next.js when I try to import a client-side library?](https://stackoverflow.com/a/66100185/1870780). – juliomalves Aug 18 '21 at 10:09

1 Answers1

2

I have managed to find a solution for this problem. This is a code snippet that works for me, please let me know if there is a better way.

import { useEffect, useRef } from "react";

export default function Editor() {
  const viewerDiv = useRef<HTMLDivElement>(null);
  const loadViewer = async () => {
    const WebViewer = (await import("@pdftron/webviewer")).default;
    WebViewer(
      {
        path: "lib",
        initialDoc: "./sample.pdf",
      },
      viewerDiv.current as HTMLDivElement
    );
  };
  useEffect(() => {
    loadViewer();
  }, []);
  return (
    <div>
      <div className={"webviewer"} ref={viewerDiv}></div>
    </div>
  );
}