I had a working docker build and when I put in absolute paths with a path alias, it suddenly started complaining module not found, can't resolve 'ComponentName'
It will fail at the pnpm run build
step, but when I run it locally, it works fine.
tsconfig.json
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"baseUrl": ".",
"paths": {
"~/*": [
"./src/*"
]
}
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts"
],
"exclude": [
"node_modules"
]
}
The file causing the error:
import { Providers } from './providers';
import NavBar from '~/components/NavBar';
import { css } from '~/styles/css';
import './global.css';
export const metadata = {
title: 'p-stack-fs',
description: 'A boilerplate for TypeScript, Next.js, and PostgreSQL',
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
<Providers>
<div className={css({ minH: '100vh' })}>
<NavBar />
{children}
</div>
</Providers>
</body>
</html>
);
Error:
> [builder 6/6] RUN pnpm run build:
#25 0.534
#25 0.534 > p-stack-fs@0.1.0 build /app
#25 0.534 > next build
#25 0.534
#25 0.940 - warn You have enabled experimental feature (instrumentationHook) in next.config.js.
#25 0.941 - warn Experimental features are not covered by semver, and may cause unexpected or broken application behavior. Use at your own risk.
#25 0.941
#25 1.010 - info Creating an optimized production build...
#25 10.94 Failed to compile.
#25 10.94
#25 10.95 ./src/app/layout.tsx
#25 10.95 Module not found: Can't resolve '~/components/NavBar'
#25 10.95
#25 10.95 https://nextjs.org/docs/messages/module-not-found
#25 10.95
#25 10.95 ./src/app/layout.tsx
#25 10.95 Module not found: Can't resolve '~/styles/css'
#25 10.95
#25 10.95 https://nextjs.org/docs/messages/module-not-found
#25 10.95
#25 10.95
#25 10.95 > Build failed because of webpack errors
#25 11.09 ELIFECYCLE Command failed with exit code 1.
------
executor failed running [/bin/sh -c pnpm run build]: exit code: 1
You can see the files exist and are named properly here:
FWIW, here's my Dockerfile
ARG ALPINE_VERSION=3.17
FROM node:20-alpine AS base
# Install dependencies only when needed
FROM base AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
COPY panda.config.ts ./
RUN npm i -g pnpm && pnpm i --prod --frozen-lockfile
# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# Panda is built in the `prepare` command, which runs after
# `install`, so we copy it over here for building
# COPY --from=deps /app/src/styles/ ./src/styles/
RUN ["chmod", "+x", "./docker-entrypoint.sh"]
# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry during the build.
ENV NEXT_TELEMETRY_DISABLED 1
RUN npm i -g pnpm
RUN pnpm run build
# Production image, copy all the files and run next
FROM alpine:${ALPINE_VERSION} AS runner
WORKDIR /app
# Uncomment the following line in case you want to disable telemetry during runtime.
ENV NEXT_TELEMETRY_DISABLED 1
RUN apk add --no-cache --update nodejs
# Get AWS SSM Params using a Go binary, reduces image size
# Note: this might get a "8: not found" error if not using the USER nextjs, has
# to do with something with the ca-certificates
RUN apk update && apk add --no-cache ca-certificates && update-ca-certificates
RUN wget https://github.com/pthieu/go-aws-get-parameter/raw/master/ssm_get_parameter
RUN ["chmod", "+x", "./ssm_get_parameter"]
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/static ./.next/static
# COPY --from=builder /app/src/db/migrations ./migrations
COPY --from=builder --chown=nextjs:nodejs /app/docker-entrypoint.sh ./
USER nextjs
EXPOSE 80
ENV PORT 80
ENTRYPOINT [ "sh", "docker-entrypoint.sh" ]
CMD ["node", "server.js"]
# For debugging, keeps container alive
# CMD ["tail", "-f", "/dev/null"]
Found the issue.
The solution was to update next.config.js
to set the path alias in webpack. This should be the same as your tsconfig.json
.
const nextConfig = {
output: 'standalone',
webpack: (config, { isServer }) => {
config.resolve.alias['~'] = path.join(__dirname, 'src');
return config;
},
};
Here's my hypothesis: in Next.js 13, they moved to turbopack but still use Webpack as a bundler. Webpack runs at a different phase than the TS compilation phase, so it doesn't take into account tsconfig.json
.