bazel-examples icon indicating copy to clipboard operation
bazel-examples copied to clipboard

NextJs monorepo: Error: > Couldn't find a `pages` directory. Please create one under the project root

Open jaskerv opened this issue 3 years ago • 8 comments

Newbie here, was trying to find a nextjs bazel example and found this. Kudos to your team!

I'm currently playing around with the NextJs example. However I want to set my project up as a monorepo, so that I can have multiple Nextjs applications.

My project dir is set up as such

node_modules/
.npmrc
.swcrc
BUILD.bazel
WORKSPACE.bazel
pnpm-lock.yaml
tsconfig.json
web/
  ecommerce/
    pages/
    public/
    styles/
    BUILD.bazel
    next-env.d.ts
    next.config.js

In my root BAZEL.build:

load("@aspect_bazel_lib//lib:copy_to_bin.bzl", "copy_to_bin")
load("@aspect_rules_ts//ts:defs.bzl", "ts_config")

npm_link_all_packages(name = "node_modules")

copy_to_bin(
    name = "swcrc",
    srcs = [".swcrc"],
    visibility = ["//visibility:public"],
)

ts_config(
    name = "tsconfig",
    src = "tsconfig.json",
    visibility = ["//visibility:public"],
)

In my ecommerce BAZEL.build:

load("@npm//:next/package_json.bzl", next_bin = "bin")
load("@aspect_rules_js//js:defs.bzl", "js_binary", "js_run_binary", "js_test")

# Source files passed to Next.js targets
filegroup(
    name = "srcs",
    srcs = [
        "//web/ecommerce/pages",
        "//web/ecommerce/public",
        "//web/ecommerce/styles",
    ],
)

# Config files passed to Next.js targets
filegroup(
    name = "config",
    srcs = [
        "next.config.js",
    ],
    visibility = ["//visibility:public"],
)

# `next dev` runs the application in development mode
# https://nextjs.org/docs/api-reference/cli#development
next_bin.next_binary(
    name = "dev",
    args = ["dev"],
    data = [
        ":config",
        "//:node_modules",
        ":srcs",
    ],
    # TODO: Next.js isn't able to detect when to pick update changes
    # when watching the runfiles. This prevents it from rebuilding & refreshing
    # when running under ibazel with `ibazel_notify_changes`
    # tags = ["ibazel_notify_changes"],
)

When I run bazel run //web/ecommerce:dev, it outputs this error:

❯ bazel run //web/ecommerce:dev
INFO: Analyzed target //web/ecommerce:dev (1 packages loaded, 5 targets configured).
INFO: Found 1 target...
Target //web/ecommerce:dev up-to-date:
  bazel-bin/web/ecommerce/dev.sh
INFO: Elapsed time: 0.248s, Critical Path: 0.00s
INFO: 1 process: 1 internal.
INFO: Build completed successfully, 1 total action
INFO: Build completed successfully, 1 total action
ready - started server on 0.0.0.0:3000, url: http://localhost:3000
Error: > Couldn't find a `pages` directory. Please create one under the project root
    at Object.findPagesDir (/home/jaskerv/.cache/bazel/_bazel_jaskerv/bd4b097237f91e06ed79cb1df45916f2/execroot/monorepo/bazel-out/k8-fastbuild/bin/web/ecommerce/dev.sh.runfiles/monorepo/node_modules/.aspect_rules_js/[email protected]_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/lib/find-pages-dir.js:42:19)
    at new DevServer (/home/jaskerv/.cache/bazel/_bazel_jaskerv/bd4b097237f91e06ed79cb1df45916f2/execroot/monorepo/bazel-out/k8-fastbuild/bin/web/ecommerce/dev.sh.runfiles/monorepo/node_modules/.aspect_rules_js/[email protected]_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/server/dev/next-dev-server.js:107:66)
    at NextServer.createServer (/home/jaskerv/.cache/bazel/_bazel_jaskerv/bd4b097237f91e06ed79cb1df45916f2/execroot/monorepo/bazel-out/k8-fastbuild/bin/web/ecommerce/dev.sh.runfiles/monorepo/node_modules/.aspect_rules_js/[email protected]_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/server/next.js:137:20)
    at /home/jaskerv/.cache/bazel/_bazel_jaskerv/bd4b097237f91e06ed79cb1df45916f2/execroot/monorepo/bazel-out/k8-fastbuild/bin/web/ecommerce/dev.sh.runfiles/monorepo/node_modules/.aspect_rules_js/[email protected]_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/server/next.js:149:42
    at async NextServer.prepare (/home/jaskerv/.cache/bazel/_bazel_jaskerv/bd4b097237f91e06ed79cb1df45916f2/execroot/monorepo/bazel-out/k8-fastbuild/bin/web/ecommerce/dev.sh.runfiles/monorepo/node_modules/.aspect_rules_js/[email protected]_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/server/next.js:127:24)
    at async /home/jaskerv/.cache/bazel/_bazel_jaskerv/bd4b097237f91e06ed79cb1df45916f2/execroot/monorepo/bazel-out/k8-fastbuild/bin/web/ecommerce/dev.sh.runfiles/monorepo/node_modules/.aspect_rules_js/[email protected]_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/cli/next-dev.js:142:9

I have a few questions around the nextjs example:

  • How would I get around this error? 🙏
  • What is the next_entry.js? Is this something manually defined?
  • How does the copy_to_bin swcrc work? I see it defined but not sure how its used.

jaskerv avatar Oct 21 '22 13:10 jaskerv

I'm working on improving and generalizing this example presently so you should see some updates next week including a working devserver for development mode.

The next_entry.js is an unfortunate work-around for running next build under bazel so that next & react don't get confused by finding themselves in both the runfiles and execroot node_modules trees. The code is sensitive to only being resolved to a single node_modules tree. Its required atm but the example does not make it very portable so I'll clean it up to abstract away some of the complexity and show how to use it in a monorepo.

gregmagolan avatar Oct 21 '22 22:10 gregmagolan

The copy_to_bin is a rule that copies a source file to the bazel output tree. rules_js and its derivate rules such as rules_ts always copy source files to the output tree so that node tools don't have to be taught to be aware of both the source tree and the output tree. We took this approach in rules_js since it is easier to adapt Bazel to current node tooling which writes its outputs to the same tree as sources then it is to fix all the node tooling to be aware of two different trees. Some more info on this in the rules_js README if you are curious: https://github.com/aspect-build/rules_js#running-nodejs-programs.

gregmagolan avatar Oct 21 '22 23:10 gregmagolan

Awesome, super excited to see how it works out 😄

jaskerv avatar Oct 24 '22 11:10 jaskerv

This is generalizing into a next() macro and adding a devserver that works with ibazel: https://github.com/aspect-build/bazel-examples/pull/121

gregmagolan avatar Oct 25 '22 08:10 gregmagolan

@Jaskerv did that PR solve this for you?

alexeagle avatar Nov 07 '22 19:11 alexeagle

@alexeagle Thankyou so much, that PR was a huge help 🚀🚀🚀

I've changed up how I am managing the monorepo. I made it so that each project is managing its own dependencies. This makes it easier managing dependencies.

For example

projectA
  BUILD.bazel
  package.json <--- next version 13
projectB
  BUILD.bazel
  package.json <--- next version 12
WORKSPACE.bazel

Since npm_translate_lock can only be defined in the WORKSPACE.bazel, this causes an issue when referencing npm modules defined in the each project.

Is there a way around this without manually defining npm_import for each project, or should I revert back to having all dependencies in the root package.json?

jaskerv avatar Nov 22 '22 12:11 jaskerv

You could use pnpm workspaces which rules_js support. We have a contrived example here: https://github.com/aspect-build/rules_js/tree/main/e2e/pnpm_workspace of how it is wired up with Bazel.

gregmagolan avatar Nov 22 '22 21:11 gregmagolan

The pnpm workspaces work well!!

However, I seem to have some trouble building my next project. I get the following sample error:

JsRunBinary web/project/.next failed: (Exit 1): next_js_binary.sh failed: error executing command bazel-out/k8-opt-exec-2B5CBBC6/bin/web/project/next_js_binary.sh build

> Build error occurred
[Error: EROFS: read-only file system, open '.../node_modules/next/dist/server/initialize-require-hook.js'] {
  errno: -30,
  code: 'EROFS',
  syscall: 'open',
  path: '.../bazel-out/k8-fastbuild/bin/node_modules/.aspect_rules_js/[email protected]_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/server/initialize-require-hook.js'
}

Any ideas? 😮

jaskerv avatar Dec 04 '22 11:12 jaskerv

Going to close this as I haven't touched this in a while. Thanks everyone :)

jaskerv avatar May 29 '23 11:05 jaskerv