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

[BUG] NextJS: SyntaxError: Cannot use import statement outside a module #177

Closed
yjnnk opened this issue Nov 5, 2020 · 18 comments
Closed
Labels
area/library Related to all activities around Library package bug Something isn't working

Comments

@yjnnk
Copy link

yjnnk commented Nov 5, 2020

Description

I'm trying to render the AsyncApi react component in a NextJS app, but it crashes, displaying the error above:
Maybe there is a problem of compatibility between CommonJS modules and ESModules

import AsyncApi from './containers/AsyncApi/AsyncApi';
^^^^^^

SyntaxError: Cannot use import statement outside a module
    at compileFunction (<anonymous>)
    at Module._compile (internal/modules/cjs/loader.js:895:18)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:995:10)
    at Module.load (internal/modules/cjs/loader.js:815:32)
    at Function.Module._load (internal/modules/cjs/loader.js:727:14)
    at Module.require (internal/modules/cjs/loader.js:852:19)
    at require (internal/modules/cjs/helpers.js:74:18)
    at eval (webpack-internal:///@kyma-project/asyncapi-react:1:18)
    at Object.@kyma-project/asyncapi-react (/Users/ricardonakashima/Projetos/asyncapireact/.next/server/pages/index.js:150:1)
    at __webpack_require__ (/Users/naka/Projetos/asyncapireact/.next/server/pages/index.js:23:31)

Expected result

It should render the component

Steps to reproduce
you can easily reproduce the error by installing a simple next app:

  1. npx create-next-app
  2. installing the lib: npm install --save @kyma-project/asyncapi-react
  3. importing the component and rendering it in any page with any valid yml file.

Troubleshooting

I was able to compile the app by dynamically importing the component with ssr:false, but the component does not render.

import dynamic from 'next/dynamic'
const AsyncApiComponent = dynamic(() => import('@kyma-project/asyncapi-react'), { ssr:false})

@magicmatatjahu magicmatatjahu added area/library Related to all activities around Library package bug Something isn't working labels Nov 5, 2020
@magicmatatjahu
Copy link
Member

@YujiNNakashima Hi! Sorry for late response. I reproduced your problem by bootstrap nextjs app and yes, this is a problem with ESmodules. We are using TS in a component and have a module target set to esnext. I tried to change it to commonJS, but then if I use the component, then some internal shared components in library don't work, so we must add webpack/rollup and create several targets like umd, esm, cjs. Unfortunately, you cannot using pure React component in your project.

But don't worry, I tried to use our @asyncapi/web-component in nextJS app and it works in my env. So please install @asyncapi/web-component in your project:

npm i @asyncapi/web-component -s

and then import and use the component in this way:

export default function SomeYourComponent() {
  // lazy import for component
  React.useEffect(() => import("@asyncapi/web-component/lib/asyncapi-web-component"), []);

  return (
    <asyncapi-component schema={asyncapiSchema} cssImportPath="./asyncapi.css" />
  );
}

where asyncapiSchema is a schema, and cssImportPath is a path to css file. The easier way to have a css is copy this file https://codesandbox.io/s/asyncapi-web-component-in-action-l652x?file=/src/assets/asyncapi.css to ./public/asyncapi.css (please NOTE that cssImportPath prop has a ./asyncapi.css value, because NextJS read assets from public folder).

It works in dev and also in prod (after build) environments. Please try it and give the feedback. Of course, if you have any question, feel free to ask :)

@acelaya
Copy link

acelaya commented Nov 18, 2020

This is actually a problem with many modules when NextJS tries to do the server-side rendering and they are components that rely on being rendered in the browser.

There's a way around this documented in NextJS docs which consists on using a dynamic import disabling server-side rendering:

import dynamic from 'next/dynamic'

const AsyncApi = dynamic(import('@asyncapi/react-component'), { ssr: false }) // Async API cannot be server-side rendered

export const FooComponent = () => {
    return <AsyncApi {...} />
}

@github-actions
Copy link

This issue has been automatically marked as stale because it has not had recent activity 😴
It will be closed in 60 days if no further activity occurs. To unstale this issue, add a comment with detailed explanation.
Thank you for your contributions ❤️

@github-actions github-actions bot added the stale label Jan 18, 2021
@derberg
Copy link
Member

derberg commented Jan 18, 2021

Any suggestions where we should go with this issue, document a workaround, or any other ideas?

@derberg derberg removed the stale label Jan 18, 2021
@acelaya
Copy link

acelaya commented Jan 18, 2021

I haven't found a fully working approach in pure react/nextjs, but @magicmatatjahu suggested using the web component instead.

I haven't tried it though.

@SteveSonoa
Copy link

I believe this issue is beyond the scope of just next. I'm finding the same error message when running our Mocha test suite. When running from the browser, everything works as intended.

@SteveSonoa
Copy link

Also, I attempted to convert to the web-component and found the same error message.

@SteveSonoa
Copy link

Has there been any updates, movement, or visibility on this, please?

@derberg
Copy link
Member

derberg commented Mar 5, 2021

@SteveSonoa so far we just do not have an idea how to fix it and suggest web component. Since you say web component also causes issues we need to check, but for this, to move forward we need some sample project from your side, best on code sandbox, so we can see the problem in a reproducable environment

@nandorojo
Copy link

The only solution I've found is to use next-transpile-modules. But this is slow and feels unnecessary.

@dukeliberal
Copy link

dukeliberal commented Apr 26, 2021

Same issue found when I use react-monaco-editor@0.43.0 in nextjs@^10.1.3

@sstecnologiainformacao
Copy link

sstecnologiainformacao commented May 3, 2021

hey, folks.

The same problem when I use the react-pdf lib.

@glend1
Copy link

glend1 commented May 3, 2021

also an issue when using VexFlow

@magicmatatjahu
Copy link
Member

magicmatatjahu commented May 4, 2021

@YujiNNakashima @acelaya @SteveSonoa @nandorojo Huge sorry for waiting, but we didn't forget about this issue. We worked on unification react-component with our html-template. You can read more here.

We fixed mentioned problem in issue and also this issue in the 1.0.0-next.1 version of component. You can download it by:

npm i @asyncapi/react-component@next

Here is a list with changes (with some breaking changes, and by this we go with next version). Also here is a document how to exactly use "new" component in NextJS. Copied from docs:

// Import component using `dynamic` helper
import dynamic from 'next/dynamic';
import "@asyncapi/react-component/styles/default.min.css";

// Import component without SSR/SSG
const AsyncAPIComponent = dynamic(() => import('@asyncapi/react-component/browser'), { ssr: false });

export default function AsyncAPIPreview ({ schema, config }) {
  // Render on the browser only
  if (typeof navigator === 'undefined') return null;

  return schema && <AsyncAPIComponent schema={schema} config={config} />;
}

The main problem why we have browser bundle (which is umd bundle) is that our parser, which we use internally in component, have a lot of dependencies which aren't isomorphic (you can run this same code in browser and in node without problems), so we must have "browser" bundle and we also have plan to have bundled "node" version of component. NextJS (if has enabled SSG) first render page in server and then hydrate it in browser and by { ssr: false } we avoid unnecessary rendering (which will be broken btw).

The above solution isn't compatible with SSR and with SSG, because component is only rendered in browser.

To have fully support for SSR and SSG you must do following things:

  1. Install parser
npm i @asyncapi/parser
  1. Stringify parsed spec and use standalone component without parser (minimalistic version of component which only render spec without validation):
import { parse } from "@asyncapi/parser";
// version of component without parser, fully tree shakable
import { AsyncApiComponentWP } from "@asyncapi/react-component";

import '@asyncapi/react-component/styles/default.min.css';

export default function Home({ asyncapi }) {
  return (
    <div className="container">
      <AsyncApiComponentWP schema={asyncapi} />
    </div>
  )
}

// This function gets called at build time
export async function getStaticProps() {
  // example AsyncAPI spec written as string in YAML, you can e.g. fetch schema from db
  const doc = `
asyncapi: '2.0.0'
info:
  title: Example
  version: '0.1.0'
channels:
  example-channel:
    subscribe:
      message:
        payload:
          type: object
          properties:
            exampleField:
              type: string
            exampleNumber:
              type: number
            exampleDate:
              type: string
              format: date-time
`;

  // parse and stringify spec. NextJS writes the returned props from this function to separate `.json` file to use it in hydration on browser.
  const asyncapi = await parse(doc);
  // stringify doesn't work with circular references in spec. Please have it in mind.
  const stringified = JSON.stringify(asyncapi.json());

  return {
    props: {
      asyncapi: stringified,
    },
  }
}

We don't have currently documented above solution for SSR and SSG, because we have problems with circular references, you can read about it here. But "standalone" solution is faster and only includes about 150kb from package in final rendered page in opposite with "dynamic" component with about 800kb onboard.

Again, sorry for waiting and let us know if everything works, and of course, if you have any questions, feel free to ask :)

EDIT: Anticipating the questions. Probably we won't solve mentioned problem in issues related to NextJS in old version of component (in 0.X.Y versions), because we want focus on "new" component.

@magicmatatjahu
Copy link
Member

@dukeliberal @sstecnologiainformacao @glend1 Thanks for reporting issues, but it's not related to our component 😅 You can create issue for that in related repos. probably mentioned by you packages have only esm module in npm and NextJS needs cjs to render component in SSG. Also i think that your component is fully browser compatible (without compability with SSR), so you can use next/dynamic helper to skip rendering in server.

@acelaya
Copy link

acelaya commented May 8, 2021

Hey @magicmatatjahu, I'm testing the new version and overall, it looks amazing. I love the new look and feel.

Some feedback I can provide after starting to use it on my Next.JS app:

  • On TypeScript it complains about missing declaration for @asyncapi/react-component/browser. I have worked around it with @ts-expect-error for now.
  • Default stylesheet looks more like a page one than a component one, with a lot of resets, defaults, etc. It had some minor side effects over other styles in my page, but nothing critical. I guess this is related with the new tailwind-based styles and will be improved in the future.
  • When I export my Next.JS site to a static page, it does not include the stylesheet for some reason. I'm still investigating why does it skip only this specific one when I'm importing others in the same way. Probably not related specifically with this component, but more with the way Next.JS and webpack are plugged together.
    • EDIT: I have worked around this point by replacing the import of the stylesheet as a module from within a TypeScript file, and moved it as a CSS @import inside another one of my own CSS files. This way webpack detects it and includes it in the final bundle.

@magicmatatjahu
Copy link
Member

magicmatatjahu commented May 10, 2021

@acelaya Thanks for awesome feedback, I really appreciate that! 🤗

On TypeScript it complains about missing declaration for @asyncapi/react-component/browser. I have worked around it with @ts-expect-error for now.

Yes, we know about that, but there is a problem that TS at the moment doesn't support exports field in package.json. You can read more about it in this issue. It means that we cannot add redirect to appropriate types of given path (at the moment package.json supports only one types file/path). Only solution is adding this typings to types folder (new common folder in transpiled module) for this path manually before packing the package and publish in npm. I didn't check that and I'm not sure if it will work. I will try to do it and let you know :)

Default stylesheet looks more like a page one than a component one, with a lot of resets, defaults, etc. It had some minor side effects over other styles in my page, but nothing critical. I guess this is related with the new tailwind-based styles and will be improved in the future.

We also know about that but we we wanted to prerelease the component so people could give feedback and if founded bugs with logic and styles will be fixed then we will go to 1.0.0 (I don't know when this will happen). Of course 1.0.0 will also included custom theming etc. Sorry for reseting styles, I always tested new component on "fresh" projects, so I didn't notice this reseting. Most likely there is a flag in tailwind to disable reseting. Thanks for the information!

When I export my Next.JS site to a static page, it does not include the stylesheet for some reason. I'm still investigating why does it skip only this specific one when I'm importing others in the same way. Probably not related specifically with this component, but more with the way Next.JS and webpack are plugged together.

Awesome that you fixed problem. To be honest, I also tested component in NextJS (of course fresh project) and everything worked as expected, also build and serve this build. Maybe some bug in your version of NextJS?

Also related to stylesheet, you can try add our stylesheet as first stylesheet in page, the maybe another will "disable" the reseting :)

Thanks for feedback again!

@magicmatatjahu
Copy link
Member

I close issue, if any of the commenters here will have problems, please reopen or create a new issue. We will also remember about feedback :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/library Related to all activities around Library package bug Something isn't working
Projects
None yet
Development

No branches or pull requests

9 participants