Search code examples
javascriptnode.jswebpacknext.jsserver-side-rendering

Nextjs config for JSX file type


I have created an Next 13 application where i have installed an package @viral-loops/widgets

Once the package is installed and when i run the application i am getting the following error

error - ./node_modules/@viral-loops/widgets/dist/react/Widget.jsx
Module parse failed: Unexpected token (34:4)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| 
|   return (
>     <>
|       {props.ucid ? (
|         <form-widget ucid={props.ucid} popup={props.popup} />

Here is my next.config.js

module.exports = {
  webpack(config, { isServer }) {
    const prefix = config.assetPrefix ?? config.basePath ?? '';
    config.module.rules.push(
      {
        test: /\.svg$/,
        use: ['@svgr/webpack', 'url-loader'],
      },
      {
        test: /\.(png|jpe?g|gif)$/i,
        use: [
          {
            loader: 'url-loader',
          },
        ],
      },
      {
        test: /\.(mp4|webm|mov|ogg|swf|ogv)$/,
        use: [
          {
            loader: require.resolve('file-loader'),
            options: {
              publicPath: `${prefix}/_next/static/videos/`,
              outputPath: `${isServer ? '../' : ''}static/videos/`,
              name: '[name]-[hash].[ext]',
            },
          },
        ],
      },
    );
    return config;
  },
  images: {
    disableStaticImages: true,
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'images.ctfassets.net',
        pathname: '**',
      },
    ],
  },
  sassOptions: {
    includePaths: [
      path.join(__dirname, 'styles'),
      path.join(__dirname, 'styles/variables.scss'),
    ],
    prependData: '@import "./styles/variables.scss";',
  },
  compilerOptions: {
    baseUrl: '.',
    paths: {
      '@/components/*': ['components/*'],
    },
  },
};

I have tried setting up babel-loader like below in the next.config.js webpack

module.exports = {
  webpack(config, { isServer }) {
    const prefix = config.assetPrefix ?? config.basePath ?? '';
    config.module.rules.push(
      **{test: /\.(js|jsx)$/, use: 'babel-loader'}**,

Which returns a new error like below

Syntax error: Support for the experimental syntax 'jsx' isn't currently enabled (34:5):

  32 |
  33 |   return (
> 34 |     <>
     |     ^
  35 |       {props.ucid ? (
  36 |         <form-widget ucid={props.ucid} popup={props.popup} />
  37 |       ) : null}

Add @babel/preset-react (https://github.com/babel/babel/tree/main/packages/babel-preset-react) to the 'presets' section of your Babel config to enable transformation.

I am not sure where i have to add the @babel/preset-react in Nextjs application.


Solution

  • I have done the following to make the viral-loop widget to work in Next.js.

    To Integrate ViralLoop with Next.js application install the below package

    yarn add @viral-loops/widgets
    
    

    Install babel/preset-react

    Yarn add @babel/preset-react --save-dev
    
    

    Once the installation is complete go to Next.config.js and add the following snippet to transpile JSX

    {
           test: /\.(js|jsx)$/,
           use: {
             loader: 'babel-loader',
             options: {
               presets: ['@babel/preset-react'],
             },
           },
      },
    
    

    enter image description here

    Once the above steps are done the unexpected token issue was fixed but to import the widget i have to use the dynamic import like below

    import dynamic from 'next/dynamic';
    const ViralLoopsWidget: any = dynamic(() => import('@viral-loops/widgets/dist/react').then((mod) => mod.ViralLoopsWidget), {ssr: false});
    
    

    If the dynamic import is not needed then we can use the same inside an useEffect which will be called only on the client side render not on server side render

    useEffect(() => {
        const viralLoopInit = async () => {
          const viralLoop = await import('@viral-loops/widgets/dist/react');
          console.log('viralLoop is', viralLoop);
          console.log('viralLoop1 is', await viralLoop.getCampaign());
        }
        viralLoopInit();
      }, []);