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
相关产品推荐
相关产品推荐

