You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker Compose环境下Yarn包无法被esbuild解析的问题

Docker容器中esbuild无法解析依赖包的问题

本地使用bin/dev命令启动服务时,esbuild可正常编译所有文件;但通过docker-compose up启动容器时,esbuild出现无法解析@hotwired/stimulus、react、react-dom/client等依赖包的错误。所有文件中的包名大小写均正确,已尝试多种方法均未解决问题。


本地启动脚本(bin/dev)

if gem list --no-installed --exact --silent foreman; then
  echo "Installing foreman..."
  gem install foreman
fi

# Default to port 3000 if not specified
export PORT="${PORT:-3000}"

exec foreman start -f Procfile.dev "$@"

容器启动错误日志

app-1       | 10:54:38 web.1  | started with pid 9
app-1       | 10:54:38 js.1   | started with pid 10
app-1       | 10:54:38 js.1   | yarn run v1.22.17
app-1       | 10:54:38 js.1   | $ esbuild app/javascript/*.* --bundle --sourcemap --format=esm --outdir=app/assets/builds --public-path=/assets --loader:.js=jsx --watch=forever
app-1       | 10:54:39 js.1   | ✘ [ERROR] Could not resolve "@hotwired/stimulus"
app-1       | 10:54:39 js.1   | 
app-1       | 10:54:39 js.1   |     app/javascript/controllers/application.js:1:28:
app-1       | 10:54:39 js.1   |       1 │ import { Application } from "@hotwired/stimulus"
app-1       | 10:54:39 js.1   |         ╵                             ~~~~~~~~~~~~~~~~~~~~
app-1       | 10:54:39 js.1   | 
app-1       | 10:54:39 js.1   |   You can mark the path "@hotwired/stimulus" as external to exclude it from the bundle, which will remove this error and leave the unresolved path in the bundle.
app-1       | 10:54:39 js.1   | 
app-1       | 10:54:39 js.1   | ✘ [ERROR] Could not resolve "@hotwired/stimulus"
app-1       | 10:54:39 js.1   | 
app-1       | 10:54:39 js.1   |     app/javascript/controllers/hello_controller.js:1:27:
app-1       | 10:54:39 js.1   |       1 │ import { Controller } from "@hotwired/stimulus"
app-1       | 10:54:39 js.1   |         ╵                            ~~~~~~~~~~~~~~~~~~~~
app-1       | 10:54:39 js.1   | 
app-1       | 10:54:39 js.1   |   You can mark the path "@hotwired/stimulus" as external to exclude it from the bundle, which will remove this error and leave the unresolved path in the bundle.
app-1       | 10:54:39 js.1   | 
app-1       | 10:54:39 js.1   | ✘ [ERROR] Could not resolve "@hotwired/stimulus"
app-1       | 10:54:39 js.1   | 
app-1       | 10:54:39 js.1   |     app/javascript/controllers/react_controller.js:1:27:
app-1       | 10:54:39 js.1   |       1 │ import { Controller } from "@hotwired/stimulus"
app-1       | 10:54:39 js.1   |         ╵                            ~~~~~~~~~~~~~~~~~~~~
app-1       | 10:54:39 js.1   | 
app-1       | 10:54:39 js.1   |   You can mark the path "@hotwired/stimulus" as external to exclude it from the bundle, which will remove this error and leave the unresolved path in the bundle.
app-1       | 10:54:39 js.1   | 
app-1       | 10:54:39 js.1   | ✘ [ERROR] Could not resolve "react"
app-1       | 10:54:39 js.1   | 
app-1       | 10:54:39 js.1   |     app/javascript/controllers/react_controller.js:2:18:
app-1       | 10:54:39 js.1   |       2 │ import React from "react";
app-1       | 10:54:39 js.1   |         ╵                   ~~~~~~~
app-1       | 10:54:39 js.1   | 
app-1       | 10:54:39 js.1   |   You can mark the path "react" as external to exclude it from the bundle, which will remove this error and leave the unresolved path in the bundle.
app-1       | 10:54:39 js.1   | 
app-1       | 10:54:39 js.1   | ✘ [ERROR] Could not resolve "react-dom/client"
app-1       | 10:54:39 js.1   | 
app-1       | 10:54:39 js.1   |     app/javascript/controllers/react_controller.js:3:27:
app-1       | 10:54:39 js.1   |       3 │ import { createRoot } from 'react-dom/client';
app-1       | 10:54:39 js.1   |         ╵                            ~~~~~~~~~~~~~~~~~~
app-1       | 10:54:39 js.1   | 
app-1       | 10:54:39 js.1   |   You can mark the path "react-dom/client" as external to exclude it from the bundle, which will remove this error and leave the unresolved path in the bundle.
app-1       | 10:54:39 js.1   | 
app-1       | 10:54:39 js.1   | ✘ [ERROR] Could not resolve "react"
app-1       | 10:54:39 js.1   | 
app-1       | 10:54:39 js.1   |     app/javascript/components/App.jsx:1:18:
app-1       | 10:54:39 js.1   |       1 │ import React from "react";
app-1       | 10:54:39 js.1   |         ╵                   ~~~~~~~
app-1       | 10:54:39 js.1   | 
app-1       | 10:54:39 js.1   |   You can mark the path "react" as external to exclude it from the bundle, which will remove this error and leave the unresolved path in the bundle.
app-1       | 10:54:39 js.1   | 
app-1       | 10:54:39 js.1   | 6 errors
app-1       | 10:54:39 js.1   | [watch] build finished, watching for changes...

相关配置文件

Dockerfile

# /path/to/app/Dockerfile
FROM ruby:2.7.5-alpine

ENV BUNDLER_VERSION=2.1.4

RUN apk add --update --no-cache \
      binutils-gold \
      build-base \
      curl \
      file \
      g++ \
      gcc \
      git \
      less \
      libstdc++ \
      libffi-dev \
      libc-dev \
      linux-headers \
      libxml2-dev \
      libxslt-dev \
      libgcrypt-dev \
      make \
      netcat-openbsd \
      nodejs \
      openssl \
      pkgconfig \
      postgresql-dev \
      tzdata \
      yarn

RUN gem install bundler -v $BUNDLER_VERSION

ENV BUNDLE_PATH /bundle
ENV BUNDLE_BIN /bundle/bin
ENV GEM_HOME /bundle
ENV PATH $GEM_HOME/bin:$BUNDLE_BIN:$PATH

WORKDIR /app

COPY Gemfile Gemfile.lock ./

RUN bundle config build.nokogiri --use-system-libraries

RUN apk update && bundle check || bundle install

COPY package.json yarn.lock ./

RUN yarn install --check-files

RUN yarn global add esbuild

COPY . ./

ENTRYPOINT ["./entrypoints/docker-entrypoint.sh"]

docker-entrypoint.sh

#!/bin/sh

set -e

if [ -f tmp/pids/server.pid ]; then
  rm tmp/pids/server.pid
fi

bundle exec bin/dev

docker-compose.yml

version: '2.24.1'

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    depends_on:
      - database
    ports:
      - "3000:3000"
    volumes:
      - .:/app
      - gem_cache:/usr/local/bundle/gems
      - node_modules:/app/node_modules
    env_file: .env
    environment:
      RAILS_ENV: development
  database:
    image: postgres:12.1
    volumes:
      - db_data:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql

volumes:
  gem_cache:
  db_data:
  node_modules:

package.json

{
  "license": "MIT",
  "dependencies": {
    "@hotwired/stimulus": "3.2.2",
    "esbuild": "0.19.11",
    "react": "18.2.0",
    "react-dom": "18.2.0"
  },
  "scripts": {
    "build": "esbuild app/javascript/*.* --bundle --sourcemap --format=esm --outdir=app/assets/builds --public-path=/assets --loader:.js=jsx"
  }
}

已尝试的无效方案

  • 在package.json中添加esbuild外部依赖配置:
    "esbuild": {
        "external": [
          "@hotwired/stimulus",
          "react",
          "react-dom/client"
        ]
      }
    
  • 全局安装相关依赖包
  • 更新bundler版本
  • 在package.json中明确指定包版本

内容的提问来源于stack exchange,提问作者Keliorw

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 22:30:54