'NextJs build fail for webpack | Monaco editor

Description of the bug

1.Monaco editor running properly in dev server, but I have to import it dynamicly to turn ssr off; but Its emmiting a warning, But its running in dev despite of that error. error - unhandledRejection: SyntaxError: Cannot use import statement outside a module

2.Second when I run npm run build its showing conflict webpack error.

Failed to compile.

Conflict: Multiple assets emit different content to the same filename ../main.js.nft.json

Conflict: Multiple assets emit different content to the same filename ../main.js.nft.json

Conflict: Multiple assets emit different content to the same filename ../main.js.nft.json

Conflict: Multiple assets emit different content to the same filename ../main.js.nft.json


> Build failed because of webpack errors


My next.config.js file:

const MonacoWebpackPlugin = require("monaco-editor-webpack-plugin");
const withTM = require("next-transpile-modules")([
  // `monaco-editor` isn't published to npm correctly: it includes both CSS
  // imports and non-Node friendly syntax, so it needs to be compiled.
  "monaco-editor",
]);

module.exports = withTM({
  webpack: (config) => {
    const rule = config.module.rules
      .find((rule) => rule.oneOf)
      .oneOf.find(
        (r) =>
          // Find the global CSS loader
          r.issuer && r.issuer.include && r.issuer.include.includes("_app")
      );
    if (rule) {
      rule.issuer.include = [
        rule.issuer.include,
        // Allow `monaco-editor` to import global CSS:
        /[\\/]node_modules[\\/]monaco-editor[\\/]/,
      ];
    }

    config.plugins.push(
      new MonacoWebpackPlugin({
        languages: [
          "json",
          "markdown",
          "css",
          "typescript",
          "javascript",
          "html",
          "graphql",
          "python",
          "scss",
          "yaml",
        ],
        filename: "static/[name].worker.js",
      })
    );
    return config;
  },
});


This is my editor.js page in nextjs

import React, { useEffect } from "react";
import dynamic from "next/dynamic";
const MonacoEditor = dynamic(import("react-monaco-editor"), { ssr: false });
import DrawerWrapper from "../components/wrapperRoutes/DrawerWrapper";
import RestrictedForMobile from "../components/restricted/forMobile";
const App = () => {
  const [iframeSrc, setIframeSrc] = React.useState("");
  const [html, setHtml] = React.useState('');
  const [css, setCss] = React.useState('');
  const [js, setJs] = React.useState('');

//useEffect to render iframe output in every 600ms

  useEffect(() => {
    const timeout = setTimeout(() => {
      setIframeSrc(`
        <head><link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet">
        </head>
        <body>${html}</body>
        <style>${css}</style>
        <script>${js}</script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.24.0/axios.min.js"></script>
        `);
    }, 600);
    return () => clearTimeout(timeout);
  }, [html, css, js]);

  

  return (
    <>
      <DrawerWrapper>
        <div className="block lg:hidden">
          <RestrictedForMobile />
        </div>

        <div className="hidden lg:block">
          <div className=" w-full bg-coolGray-900 flex justify-between align-center items-center  overflow-visible   ">
            <div className="ml-3">
              <p className="bg-secondary mt-1 text-center text-gray-50 rounded-t-lg">
                HTML
              </p>

              <MonacoEditor
                width="32vw"
                height="400"
                language="html"
                theme="hc-black"
                value={html}
                options={{
                  minimap: {
                    enabled: false,
                  },
                }}
                onChange={setHtml}
              />

            </div>
            <div className=" flex-shrink-0">
              <p className="bg-secondary mt-1 text-center text-gray-50 rounded-t-lg">
                CSS
              </p>

              <MonacoEditor
                width="32vw"
                height="400"
                className="shadow-md"
                language="css"
                theme="hc-black"
                value={css}
                options={{
                  minimap: {
                    enabled: false,
                  },
                }}
                onChange={setCss}
              />

            </div>

            <div className="mr-3 flex-shrink-0">
              <p className="bg-secondary mt-1 text-center text-gray-50 rounded-t-lg">
                JS
              </p>

              <MonacoEditor
                width="32vw"
                height="400"
                language="javascript"
                theme="hc-black"
                value={js}
                options={{
                  minimap: {
                    enabled: false,
                  },
                }}
                onChange={setJs}
              />

            </div>
          </div>
          {/* <div className="text-gray-400 divider">Output [screen : 100vh]</div> */}

          <iframe
            srcDoc={iframeSrc}
            frameBorder="0"
            sandbox="allow-scripts allow-forms"
            className="overflow-scroll h-screen border-t-4 border-b-4 -mb-6 border-secondary"
            width="100%"
            height="100%"
          />
        </div>
      </DrawerWrapper>
    </>
  );
};

export default App;



Environment:

  • OS: Apple Macbook Air M1, Monterey
  • Browser: Chrome

Please Help . Thank You ❤️



Solution 1:[1]

In addition to excluding the server from the dynamic import (which you've done with { ssr: false }), you'll also need to exclude it when the MonacoWebpackPlugin is created. The webpack function in next.config.js will get called twice -- once for server-side compilation, once more for client-side compilation. When running next build, the error you're seeing happens during server-side compilation, so limit the MonacoWebpackPlugin to the client side:

// next.config.js

// ...

module.exports = withTM({
  webpack: (config, options) => { // add `options` parameter

    // ...

    if (!options.isServer) { // run only for client side
      config.plugins.push(
        new MonacoWebpackPlugin({

          // ...

        })
      );
    }
    return config;
  },
});

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1