Next.JS v13在Docker中不遵循路径别名,但在本地工作。

huangapple go评论89阅读模式
英文:

Next.JS v13 in Docker does not respect path alias but works locally

问题

以下是要翻译的部分:

错误:

> [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 - 警告:您已启用了next.config.js中的实验性功能(instrumentationHook)。
#25 0.941 - 警告:实验性功能不受semver支持,可能导致意外或破坏的应用程序行为。自行承担风险使用。
#25 0.941
#25 1.010 - 信息 正在创建优化的生产构建...
#25 10.94 编译失败。
#25 10.94
#25 10.95 ./src/app/layout.tsx
#25 10.95 模块未找到:无法解析'~/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 模块未找到:无法解析'~/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 > 构建失败,因为webpack错误
#25 11.09  ELIFECYCLE  命令以退出码1失败。

你可以看到文件存在且命名正确的部分在这里:

Next.JS v13在Docker中不遵循路径别名,但在本地工作。

Dockerfile:

ARG ALPINE_VERSION=3.17

FROM node:20-alpine AS base

# 仅在需要时安装依赖项
FROM base AS deps
# 查看https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine 以了解为什么可能需要libc6-compat。
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

# 仅在需要时重新构建源代码
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# Panda在“prepare”命令中构建,在“install”后运行,因此我们在这里将其复制过来以进行构建
# COPY --from=deps /app/src/styles/ ./src/styles/

RUN ["chmod", "+x", "./docker-entrypoint.sh"]

# Next.js会收集关于一般用法的完全匿名的遥测数据。
# 了解更多信息:https://nextjs.org/telemetry
# 在构建过程中禁用遥测时,请取消下面一行的注释。
ENV NEXT_TELEMETRY_DISABLED 1

RUN npm i -g pnpm
RUN pnpm run build

# 生产镜像,复制所有文件并运行next
FROM alpine:${ALPINE_VERSION} AS runner

WORKDIR /app

# 在运行时禁用遥测时,请取消下面一行的注释。
ENV NEXT_TELEMETRY_DISABLED 1

RUN apk add --no-cache --update nodejs
# 使用Go二进制文件获取AWS SSM参数,减小镜像大小
# 注意:如果不使用USER nextjs,则可能会出现“8: not found”错误,与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

# 自动利用输出跟踪以减小镜像大小
# 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"]
# 用于调试,保持容器处于活动状态
# CMD ["tail", "-f", "/dev/null"]

请注意,Dockerfile和错误消息中可能包含的HTML字符实体已被保留,因为它们是代码的一部分。

英文:

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:

Next.JS v13在Docker中不遵循路径别名,但在本地工作。

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"]

答案1

得分: 2

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.

解决方案是更新 next.config.js 来在 webpack 中设置路径别名。这应该与你的 tsconfig.json 相同。

const nextConfig = {
  output: 'standalone',
  webpack: (config, { isServer }) => {
    config.resolve.alias['~'] = path.join(__dirname, 'src');
    return config;
  },
};

这是我的假设:在 Next.js 13 中,他们转向了 turbopack,但仍然使用 Webpack 作为打包工具。Webpack 运行的阶段与 TS 编译阶段不同,因此它不会考虑 tsconfig.json

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.

这是我的假设:在 Next.js 13 中,他们转向了 turbopack,但仍然使用 Webpack 作为打包工具。Webpack 运行的阶段与 TS 编译阶段不同,因此它不会考虑 tsconfig.json

英文:

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.

huangapple
  • 本文由 发表于 2023年7月13日 14:21:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/76676456.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定