DomParfitt / graphviz-react

React component for displaying Graphviz graphs
MIT License
102 stars 21 forks source link

Trouble installing #15

Closed mttzr closed 3 years ago

mttzr commented 4 years ago

Hi there,

after installing from npm and importing into my react project I'm seeing the following error:

SyntaxError: Cannot use import statement outside a module

Have others reported this?

DomParfitt commented 4 years ago

Hi @mttzr, it sounds like this might be a problem with how you have your project set up rather than with this package. Do you have any snippets or a link you could post to help investigate?

DomParfitt commented 4 years ago

@mttzr were you able to solve your issue?

osequi commented 3 years ago

Hello @DomParfitt,

I've got the same error message.

/home/cs/osequi/coco/node_modules/graphviz-react/lib/Graphviz.js:1
import * as React from 'react';
^^^^^^

SyntaxError: Cannot use import statement outside a module
    at Object.compileFunction (node:vm:355:18)
    at wrapSafe (node:internal/modules/cjs/loader:1022:15)
    at Module._compile (node:internal/modules/cjs/loader:1056:27)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1121:10)
    at Module.load (node:internal/modules/cjs/loader:972:32)
    at Function.Module._load (node:internal/modules/cjs/loader:813:14)
    at Module.require (node:internal/modules/cjs/loader:996:19)
    at require (node:internal/modules/cjs/helpers:92:18)
    at eval (webpack-internal:///graphviz-react:1:18)
    at Object.graphviz-react (/home/cs/osequi/coco/.next/server/pages/index.js:1941:1)
    at __webpack_require__ (/home/cs/osequi/coco/.next/server/pages/index.js:23:31)
    at eval (webpack-internal:///./src/apps/studies/ds/Home/Home.tsx:13:72)
    at Module../src/apps/studies/ds/Home/Home.tsx (/home/cs/osequi/coco/.next/server/pages/index.js:530:1)
    at __webpack_require__ (/home/cs/osequi/coco/.next/server/pages/index.js:23:31)
    at eval (webpack-internal:///./src/apps/studies/ds/Home/index.ts:2:63)
    at Module../src/apps/studies/ds/Home/index.ts (/home/cs/osequi/coco/.next/server/pages/index.js:542:1)
osequi commented 3 years ago

And this is the call:

const dot = `graph {
    "1" [id="1",label=A]
    "2" [id="2",label=B]
    "1" -- "2" [source="1",target="2"]
  }`;

...

<Graphviz dot={dot} />

I've just cloned your repo, built the package, run the demo, and all's fine.

Perhaps my problem comes from Next.js.

DomParfitt commented 3 years ago

Hi @osequi.

Your problem most likely is caused by some configuration in your project rather than this package. Are you using NextJS with Typescript? The instructions in the README are for using the package with ES6-style imports, which is the standard way of performing imports in Typescript but if you are not using Typescript then you may need to use the older requires syntax.

Hope that helps.

osequi commented 3 years ago

Thanks @DomParfitt,

I've checked the tsconfig.json in your demo and it's very similar to my project's config:

{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": false,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "baseUrl": "./src",
    "paths": {
      "@apps/*": ["apps/*"],
      "@components": ["components"],
      "@tokens": ["tokens/"]
    },
    "downlevelIteration": true
  },
  "include": ["next-env.d.ts", "mdx.d.ts", "**/*.ts", "**/*.tsx"],
  "exclude": ["node_modules"]
}

This is your config:

{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "preserve"
  },
  "include": [
    "src"
  ]
}

The only difference was strict:false and "allowSyntheticDefaultImports": true. I've changed my config accordingly, and still the same error message ....

osequi commented 3 years ago

Another finding that might help.

I've created a new CRA/Typescript project, and added Graphviz. All works fine!. However when I run the tests, I'm getting the same error message:

Jest encountered an unexpected token

    This usually means that you are trying to import a file which Jest cannot parse, e.g. it's not plain JavaScript.

    By default, if Jest sees a Babel config, it will use that to transform your files, ignoring "node_modules".

    Here's what you can do:
     • If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/en/ecmascript-modules for how to enable it.
     • To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
     • If you need a custom transformation specify a "transform" option in your config.
     • If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.

    You'll find more details and examples of these config options in the docs:
    https://jestjs.io/docs/en/configuration.html

    Details:

    /home/cs/osequi/test-graphviz-cra/node_modules/graphviz-react/lib/Graphviz.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import * as React from 'react';
                                                                                             ^^^^^^

    SyntaxError: Cannot use import statement outside a module

      1 | import logo from "./logo.svg";
      2 | import "./App.css";
    > 3 | import { Graphviz } from "graphviz-react";
        | ^
      4 |
      5 | /* eslint-disable import/no-webpack-loader-syntax */
      6 | import Content from "!babel-loader!@mdx-js/loader!./App.mdx";

      at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1350:14)
      at Object.<anonymous> (src/App.tsx:3:1)

This tells me the package works in CRA, and gives the same error in other two environments like Next.js and Jest. However I might be wrong.

DomParfitt commented 3 years ago

@osequi what does your package.json look like?

osequi commented 3 years ago

For the Nextjs app:

{
  "name": "osequi",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "test": "jest",
    "docs": "typedoc src/**/*.ts"
  },
  "dependencies": {
    "@emotion/css": "^11.1.3",
    "@emotion/react": "^11.1.4",
    "@mdx-js/loader": "^1.6.22",
    "@next/mdx": "^10.0.5",
    "@react-aria/ssr": "^3.0.1",
    "@react-aria/utils": "^3.6.0",
    "graphviz-react": "^1.1.1",
    "jsdom": "^16.4.0",
    "lodash": "^4.17.20",
    "modularscale-js": "^3.0.1",
    "next": "^10.0.0",
    "next-seo": "^4.24.0",
    "normalize.css": "^8.0.1",
    "react": "17.0.1",
    "react-dom": "17.0.1",
    "react-svg": "^13.0.1",
    "slugify": "^1.5.0"
  },
  "devDependencies": {
    "@testing-library/jest-dom": "^5.11.9",
    "@testing-library/react": "^11.2.3",
    "@types/jest": "^26.0.20",
    "@types/lodash": "^4.14.168",
    "@types/marked": "^1.2.2",
    "@types/node": "^14.14.22",
    "@types/react": "^17.0.0",
    "jest": "^26.6.3",
    "jest-environment-jsdom-fifteen": "^1.0.2",
    "ts-jest": "^26.4.4",
    "typedoc": "^0.20.21",
    "typescript": "^4.1.3"
  }
}
DomParfitt commented 3 years ago

Thanks @osequi.

I've done a bit of digging and this is actually being caused by an interaction with NextJS that isn't particularly clear from the error message.

The TL;DR is that, by default, Next pre-renders every page but, unfortunately, graphviz-react relies on some client-side stuff which won't be available when Next tries to do its pre-rendering. The workaround for this is to have Next dynamically import graphviz-react so that it doesn't do this pre-rendering.

To do this, you will need to create a component file that simply re-exports graphviz-react as a default export:

components/Graphviz.tsx

import { Graphviz } from 'graphviz-react';

export default Graphviz;

This is because, unfortunately, Next is very opinionated about using default exports, but graphviz-react uses named exports.

Then in the page (or pages) you want to use the Graphviz component on you need to import it using Next's dynamic import, like so:

pages/graphviz

import dynamic from 'next/dynamic';

const Graphviz = dynamic(() => import('../components/Graphviz'), {ssr: false});

const GraphvizPage = () => {
  const dot = 'graph{a--b}';

  return <Graphviz dot={dot} />;
}

export default GraphvizPage;

This tells Next to import the re-exported component with server-side rendering disabled (because of the client-side requirement).

I'll add this to the README and will also update the graphviz-react to include a default export as well as the named exports, which will remove the need to do the re-export in components/Graphviz.tsx.

osequi commented 3 years ago

Thanks @DomParfitt,

I've tried to proceed as advised above ... and the same error message occurs.

Screenshot from 2021-05-01 17-21-03

It seems anytime the following line is present the error message is thrown:

import { Graphviz } from "graphviz-react";
DomParfitt commented 3 years ago

Hi @osequi, is your component that re-exports Graphviz under the pages directory in your project structure? If so you will need to move it (I think the usual structure for Next is to have a components directory in the root of the project). Next tries to pre-render everything that is in the pages directory, so the component that re-exports Next can't live in the pages directory.

I've got it working with a similar setup and am putting some changes in that should release soon to include a default export alongside the named exports, which will remove the need for the re-exporting component and allow you to just dynamically import Graphviz.

DomParfitt commented 3 years ago

@osequi I've just released a new version (1.2.0) that includes a default export for the Graphviz component. You should now be able to import the component in a NextJS page like so:

import dynamic from 'next/dynamic'

const Graphviz = dynamic(() => import('graphviz-react'), {ssr: false});

const GraphvizPage = () => {
  const dot = 'graph{a--b--c}';

  return <Graphviz dot={dot} />;
}

export default GraphvizPage;
osequi commented 3 years ago

@DomParfitt Thanks for the great help,

Now all works very fine :)

Keep up!

jake-goldsmith commented 1 year ago

@osequi @DomParfitt Did you manage to find a work around for the testing issue with CRA?

I've created a new CRA/Typescript project, and added Graphviz. All works fine!. However when I run the tests, I'm getting the same error message

I'm running into the same problem that the project builds fine, apart from when running the jest tests, but since I am using create-react-app rather than Next, I can't add in the import dynamically.

DomParfitt commented 1 year ago

@jake-goldsmith Can you open a new issue with some steps to reproduce. Thanks