Creating a Next.js specific ecosystem in a monorepo

67 views Asked by At

I'm working on a sort of internal ecosystem-frameowork thing that will run on Next.js. I'm very familiar with Next and all of it's features, but I'm equally unfamiliar with bundling my own packages, especially in a monorepo. I'm currently running into issues with the monaco-editor. It runs and loads perfectly fine when it's either part of a single, massive Next project, or in another single, standalone, Next.js sandbox sort of app, but when adding it to the monorepo and trying to import it into another package, I am running into this error:

editor.worker.bundle.js:1 Uncaught SyntaxError: Unexpected token '<' (at editor.worker.bundle.js:1:1)

Which in turn is just pointing to the fact that Next is returning html in an error page. That source is:

 <!--$!-->
        <template data-dgst="BAILOUT_TO_CLIENT_SIDE_RENDERING" data-msg="Bail out to client-side rendering: next/dynamic" data-stck="
    at BailoutToCSR (webpack-internal:///(ssr)/../../node_modules/next/dist/shared/lib/lazy-dynamic/dynamic-bailout-to-csr.js:13:11)
    at Suspense
    at LoadableComponent
    at CodeEditorPage (webpack-internal:///(ssr)/./app/editor/[uniqueContentId]/page.tsx:25:200)
    at StaticGenerationSearchParamsBailoutProvider (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/static-generation-searchparams-bailout-provider.js:16:11)
    at Lazy
    at InnerLayoutRouter (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/layout-router.js:241:11)
    at RedirectErrorBoundary (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/redirect-boundary.js:72:9)
    at RedirectBoundary (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/redirect-boundary.js:80:11)
    at NotFoundBoundary (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/not-found-boundary.js:84:11)
    at LoadingBoundary (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/layout-router.js:338:11)
    at ErrorBoundary (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/error-boundary.js:159:11)
    at InnerScrollAndFocusHandler (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/layout-router.js:152:9)
    at ScrollAndFocusHandler (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/layout-router.js:227:11)
    at RenderFromTemplateContext (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/render-from-template-context.js:16:44)
    at Lazy
    at OuterLayoutRouter (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/layout-router.js:356:11)
    at Lazy
    at InnerLayoutRouter (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/layout-router.js:241:11)
    at RedirectErrorBoundary (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/redirect-boundary.js:72:9)
    at RedirectBoundary (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/redirect-boundary.js:80:11)
    at NotFoundBoundary (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/not-found-boundary.js:84:11)
    at LoadingBoundary (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/layout-router.js:338:11)
    at ErrorBoundary (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/error-boundary.js:159:11)
    at InnerScrollAndFocusHandler (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/layout-router.js:152:9)
    at ScrollAndFocusHandler (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/layout-router.js:227:11)
    at RenderFromTemplateContext (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/render-from-template-context.js:16:44)
    at Lazy
    at OuterLayoutRouter (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/layout-router.js:356:11)
    at Lazy
    at InnerLayoutRouter (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/layout-router.js:241:11)
    at RedirectErrorBoundary (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/redirect-boundary.js:72:9)
    at RedirectBoundary (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/redirect-boundary.js:80:11)
    at NotFoundErrorBoundary (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/not-found-boundary.js:76:9)
    at NotFoundBoundary (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/not-found-boundary.js:84:11)
    at LoadingBoundary (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/layout-router.js:338:11)
    at ErrorBoundary (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/error-boundary.js:159:11)
    at InnerScrollAndFocusHandler (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/layout-router.js:152:9)
    at ScrollAndFocusHandler (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/layout-router.js:227:11)
    at RenderFromTemplateContext (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/render-from-template-context.js:16:44)
    at Lazy
    at OuterLayoutRouter (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/layout-router.js:356:11)
    at Lazy
    at body
    at html
    at RedirectErrorBoundary (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/redirect-boundary.js:72:9)
    at RedirectBoundary (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/redirect-boundary.js:80:11)
    at ReactDevOverlay (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/react-dev-overlay/internal/ReactDevOverlay.js:84:9)
    at HotReload (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/react-dev-overlay/hot-reloader-client.js:308:11)
    at Router (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/app-router.js:177:11)
    at ErrorBoundaryHandler (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/error-boundary.js:113:9)
    at ErrorBoundary (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/error-boundary.js:159:11)
    at AppRouter (webpack-internal:///(ssr)/../../node_modules/next/dist/client/components/app-router.js:517:13)
    at Lazy
    at Lazy
    at rw (/Users/bigsexy/Desktop/currentProjects/ulld/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:39:15737)
    at rw (/Users/bigsexy/Desktop/currentProjects/ulld/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:39:15737)
    at ServerInsertedHTMLProvider (/Users/bigsexy/Desktop/currentProjects/ulld/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:39:21384)"></template>
        <!--/$-->
        <div role="region" aria-label="Notifications (F8)" tabindex="-1" style="pointer-events:none">
            <ol tabindex="-1" class="fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]"></ol>
        </div>
        <script src="/_next/static/chunks/webpack.js?v=1710692966071" async=""></script>
        <script>
            (self.__next_f = self.__next_f || []).push([0]);
            self.__next_f.push([2, null])
        </script>
        <script>
            self.__next_f.push([1, "1:HL[\"/_next/static/media/1ad50b89ab7c557e-s.p.ttf\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/ttf\"}]\n2:HL[\"/_next/static/media/266c1538bae4d3be-s.p.ttf\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/ttf\"}]\n3:HL[\"/_next/static/media/7f28fc0765fccab4-s.p.ttf\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/ttf\"}]\n4:HL[\"/_next/static/media/9204c2aa0a88c808-s.p.ttf\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/ttf\"}]\n5:HL[\"/_next/static/media/93679a4f0d810027-s.p.ttf\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/ttf\"}]\n6:HL[\"/_next/static/media/a"])
        </script>
        <script>
            self.__next_f.push([1, "0eb13619368af8d-s.p.ttf\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/ttf\"}]\n7:HL[\"/_next/static/media/adb2344dba116b3b-s.p.ttf\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/ttf\"}]\n8:HL[\"/_next/static/media/bfeb6e8b20c639f3-s.p.ttf\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/ttf\"}]\n9:HL[\"/_next/static/media/c36a3fe042b96dc3-s.p.ttf\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/ttf\"}]\na:HL[\"/_next/static/media/d0bc87a819730d23-s.p.ttf\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/ttf\"}]\nb:HL[\"/_next/static/css/app/layout.css?v=1710692966071"])
        </script>
        <script>
            self.__next_f.push([1, "\",\"style\"]\n0:\"$Lc\"\n"])
        </script>
        <script>
            self.__next_f.push([1, "d:HL[\"/_next/static/css/app/editor/[uniqueContentId]/page.css?v=1710692966071\",\"style\"]\n"])
        </script>
        <script>
            self.__next_f.push([1, "e:I[\"(app-pages-browser)/../../node_modules/next/dist/client/components/app-router.js\",[\"app-pages-internals\",\"static/chunks/app-pages-internals.js\"],\"\"]\n10:I[\"(app-pages-browser)/../../node_modules/next/dist/client/components/static-generation-searchparams-bailout-provider.js\",[\"app-pages-internals\",\"static/chunks/app-pages-internals.js\"],\"\"]\n11:I[\"(app-pages-browser)/./app/editor/[uniqueContentId]/page.tsx\",[\"app/editor/[uniqueContentId]/page\",\"static/chunks/app/editor/%5BuniqueContentId%5D/page.js\"],\"\"]\n"])
        </script>
        <script>
            self.__next_f.push([1, "12:I[\"(app-pages-browser)/../../node_modules/next/dist/client/components/layout-router.js\",[\"app-pages-internals\",\"static/chunks/app-pages-internals.js\"],\"\"]\n14:I[\"(app-pages-browser)/../../node_modules/next/dist/client/components/render-from-template-context.js\",[\"app-pages-internals\",\"static/chunks/app-pages-internals.js\"],\"\"]\n17:I[\"(app-pages-browser)/../../node_modules/next/dist/client/components/error-boundary.js\",[\"app-pages-internals\",\"static/chunks/app-pages-internals.js\"],\"\"]\n13:[\"uniqueContentId\","])
        </script>
...
</html>

My main question is around the use of Next.js specific features... the dynamic loading feature in this case, from within a package that will be used in a Next app elsewhere.

My next.config.mjs looks like this:

import nextPwa from "@ducanh2912/next-pwa"
import MonacoEditorWebpackPlugin from "monaco-editor-webpack-plugin";

const isDevelopment = process.env.NODE_ENV === "development"

const monacoRules = [
    {
        test: /\.ttf$/,
        type: 'asset/resource'
    }
]

const withPWA = nextPwa({
    dest: "public",
    ...(process.env.PRODUCTION_LOCAL && {
        workboxOptions: {
            mode: "production"
        }
    }),
});

const regexEqual = (x, y) => {
    return (
        x instanceof RegExp &&
        y instanceof RegExp &&
        x.source === y.source &&
        x.global === y.global &&
        x.ignoreCase === y.ignoreCase &&
        x.multiline === y.multiline
    )
}



/** @type {import('next').NextConfig} */
export default withPWA({
    reactStrictMode: false,
    transpilePackages: [
        'three',
        'react-three-fiber',
        'drei',
        'glsify',
        'monaco-editor',
        'theAppWithMonaco'
    ],
    experimental: {
        typedRoutes: true,
        esmExternals: "loose",
        optimizePackageImports: [
            "lucide-react",
            "katex"
        ]
        // mdxRs: true,
    },
    onDemandEntries: {
        maxInactiveAge: 10 * 1000,
        pagesBufferLength: isDevelopment ? 2 : undefined,
    },
    poweredByHeader: false,
    webpack: (config, ctx) => {
        config.cache = false
        if (!ctx.isServer) { // run only for client side
            config.plugins.push(
                new MonacoEditorWebpackPlugin({
                    // available options are documented at https://github.com/microsoft/monaco-editor/blob/main/webpack-plugin/README.md#options
                    // languages: [
                    //     'json',
                    //     'typescript',
                    //     'html',
                    //     'css',
                    //     'python',
                    //     'markdown',
                    //     'yaml'
                    // ],
                    filename: "static/[name].worker.js",
                })
            )
            config.module.rules.push(...monacoRules)
        }
        config.externals.push({
            'utf-8-validate': 'commonjs utf-8-validate',
            'bufferutil': 'commonjs bufferutil',
        })
        if (!ctx.isServer) {
            // config.resolve.modules.push(path.resolve("node_modules/monaco-editor"));
            config.resolve = {
                ...config.resolve,
                fallback: {
                    net: false,
                    dns: false,
                    tls: false,
                    fs: false,
                    request: false,
                    child_process: false,
                    perf_hooks: false
                },
                // alias: {
                //     "styled-components": path.resolve(process.cwd(), "node_modules", "styled-components"),
                // }
            };
        }
        config.module.rules.push({
            test: /canvas\.node|\.csl|\.pdf|\.glb|\.gltf|\.whl/,
            use: 'raw-loader',
        })
        config.module.rules.push({
            test: /\.ttf$/,
            use: ['file-loader']
        })
        config.module.rules.push({
            test: /\.bib/,
            use: [
                // {
                //     loader: 'file-loader'
                // },
                {
                    loader: 'raw-loader'
                }
            ]
        })
        return config
    },
})```



This config is identical to the config that is used in sandbox I mentioned above, that I created just to test things out without the rest of the massive load on the main Next dev server, and it works fine in that app. 

A few points to mention:
1. I've tried both transpiling and not transpiling the monorepo package that now contains the editor from within the `Next.config` of the main app, and failed to an equal degree with both.
2. I do not have a `nextJs.config` in the app that is exporting the monaco-editor. I can't imagine that would come in to play, but I could be wrong.
3. The editor app is collecting things from the public folder. That public folder exists in the main app that is using the editor, not within the editor package itself. Again, I'm under the impression that those file-structure-ish features won't be relevant when it's being exported, but I could be wrong.
4. I've also tried dynamically importing the editor from the editor package, again... to no avail.

And help would be very much appreciated, whether it regards this situation in particular or just using Next features from within a package, I'd greatly appreciate it.

Thanks!
0

There are 0 answers