React + Docker: Не удалось разрешить импорт
Я бьюсь головой о стену, пытаясь решить эту проблему, но я продолжаю получать следующую ошибку, которую не могу решить, когда пытаюсь добавить что-то в пряжу и затем использовать это:
PM [vite] Внутренняя ошибка сервера: Failed to resolve import "@mui/x-data-grid" from "src/components/formSubmit.tsx". Файл существует?
Может быть, я каким-то образом испортил свои node_modules? Я думаю, что мой сценарий докера правильный, и я проверил, что он существует в node_modules на образе, но, похоже, я все еще получаю эту проблему.
Моя структура папок такова:
--Myapp
|--frontend
-node_modules
-package.json
-index.html
- public
- src
- App.tsx
- index.tsx
- components
- formsubmit.tsx
- tsconfig.json
- vite.config.js
- vite-env.d.ts
|--compose
|--local
|--react
|--django
|--djangobackend
Docker-compose:
version: '3'
volumes:
myapp_local_postgres_data: {}
myapp_local_postgres_data_backups: {}
services:
django:
build:
context: .
dockerfile: ./compose/local/django/Dockerfile
image: myapp_local_django
container_name: myapp_local_django
depends_on:
- postgres
volumes:
- .:/app:z
env_file:
- ./.envs/.local/.django
- ./.envs/.local/.postgres
ports:
- '28000:8000'
command: /start
react:
build:
context: .
dockerfile: ./compose/local/react/Dockerfile
image: myapp_react
container_name: myapp_react
depends_on:
- postgres
- django
volumes:
- ./frontend:/app
- /app/node_modules/
ports:
- 28001:3000
environment:
- NODE_ENV=development
command: yarn start
Frontend dockerfile:
ARG BUILD_ENVIRONMENT=local
FROM node:lts-bookworm-slim
WORKDIR /app
COPY ./frontend/package.json .
#COPY ./frontend/yarn.lock .
COPY ./frontend/src .
COPY ./frontend/public .
COPY ./frontend/vite.config.ts .
COPY ./frontend/vite-env.d.ts .
COPY ./frontend/tsconfig.json .
COPY ./frontend/index.html .
RUN yarn
EXPOSE 3000
CMD yarn dev
tsconfig.json:
{
"compilerOptions": {
"target": "ESNext",
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"types": ["vite/client"],
"allowJs": true,
"skipLibCheck": false,
"esModuleInterop": false,
"allowSyntheticDefaultImports": true,
"strict": false,
"noImplicitAny": false,
"noImplicitThis": false,
"noUnusedLocals": false,
"noUnusedParameters": false,
"moduleResolution": "node",
"resolveJsonModule": true,
"forceConsistentCasingInFileNames": true,
"module": "ESNext",
"isolatedModules": true,
"noEmit": true,
"jsx": "react"
},
"include": ["src"]
vite.config.js:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import viteTsconfigPaths from 'vite-tsconfig-paths'
import { resolve, dirname } from "node:path";
export default defineConfig({
// depending on your application, base can also be "/"
base: '',
plugins: [react(), viteTsconfigPaths(), ],
server: {
// this ensures that the browser opens upon server start
open: false,
// this sets a default port to 3000
port: 3000,
host: true,
strictPort: true,
watch: {
usePolling: true,
},
fs: {
cachedChecks: false
},
},
package.json:
{
"name": "frontend",
"version": "0.1.0",
"private": true,
"dependencies": {
"@emotion/react": "^11.11.3",
"@emotion/styled": "^11.11.0",
"@mui/icons-material": "^5.15.10",
"@mui/lab": "^5.0.0-alpha.165",
"@mui/material": "^5.15.10",
"@mui/system": "^5.15.9",
"@mui/x-data-grid": "^6.19.4",
"@testing-library/dom": "^9.3.4",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"@tinymce/tinymce-react": "^4.3.2",
"@types/jest": "^29.5.12",
"@types/node": "^20.11.19",
"@types/react": "^18.2.55",
"@types/react-dom": "^18.2.19",
"@vitejs/plugin-react": "^4.2.1",
"axios": "^1.6.7",
"jodit": "^4.0.6",
"jodit-react-ts": "^0.9.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"typescript": "^3.9.10",
"vite": "^5.1.3",
"vite-tsconfig-paths": "^4.3.1",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "vite",
"build": "tsc & vite build",
"preview": "vite preview"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
А потом я просто пытаюсь сделать:
import { DataGrid, GridRowsProp, GridColDef } from '@mui/x-data-grid';
Ваш docker-compose.yml
определяет объем для node_modules
, который может переопределять установленные модули с локальным пустым каталогом. Это может привести к проблемам, когда зависимости не будут найдены внутри контейнера Docker.
, в то formSubmit.tsx
время как ваша файловая система имеет formsubmit.tsx
. Linux, включая контейнеры Docker, чувствителен к регистру, в отличие от Windows. Убедитесь, что имена файлов точно совпадают, включая регистр.
Ваш текущий Dockerfile копирует отдельные файлы, а затем запускает yarn
без предварительного копирования yarn.lock
. Это может привести к расхождениям между локальным окружением и окружением Docker.
Вместо этого:
FROM node:lts-bookworm-slim
WORKDIR /app
# Copy package.json and yarn.lock
COPY ./frontend/package.json ./frontend/yarn.lock ./
# Install dependencies
RUN yarn install
# Copy the rest of your frontend application
COPY ./frontend .
EXPOSE 3000
CMD ["yarn", "dev"]
Это обеспечит установку ваших зависимостей на основе заблокированных версий из yarn.lock
, обеспечивая более согласованную сборку между локальными и Docker-окружениями.
Поскольку вы используете vite-tsconfig-paths
, убедитесь, что ваши tsconfig.json
пути правильно настроены, чтобы разрешить пути модулей, как ожидалось.
Работает, когда я удаляю и добавляю его обратно в docker-compose.
Если удаление блока volumes:
приведет к работоспособной установке, это сильный признак того, что основной проблемой может быть сопоставление томов для node_modules
. Это связано с тем, что тома Docker сохраняют данные при перестройке контейнеров, что может случайно привести к повторному использованию устаревшего или поврежденного каталога node_modules
, что приведет к возникновению ошибок, с которыми вы столкнулись.
Удаление, а затем повторное добавление тома node_modules
в docker-compose.yml
временно решает проблему, поскольку заставляет Docker использовать свежеустановленный node_modules
из контейнера, а не потенциально поврежденную или несовместимую версию из тома.
Но... переустановка зависимостей при каждой сборке образа Docker может увеличить время сборки, особенно для больших проектов. А если вы активно развиваетесь и вам нужно добавлять или обновлять зависимости, отсутствие привязки node_modules
к хосту может сделать управление этими изменениями несколько более сложным.
Для разработки: Рассмотрите возможность использования именованного тома для
node_modules
или непосредственной установки зависимостей внутри контейнера без их отображения на хост. Это позволит вам использовать механизмы кэширования Docker и избежать переустановки зависимостей, еслиpackage.json
илиyarn.lock
не изменится.services: react: volumes: - ./frontend:/app - myapp_frontend_node_modules:/app/node_modules
И объявите именованный том в нижней части вашего
docker-compose.yml
:volumes: myapp_frontend_node_modules:
Для Production: Обычно лучше всего опустить
node_modules
том полностью. Зависимости должны быть запечены в образ в процессе сборки, чтобы убедиться, что контейнер запускается именно с теми зависимостями, с которыми он был протестирован.