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 том полностью. Зависимости должны быть запечены в образ в процессе сборки, чтобы убедиться, что контейнер запускается именно с теми зависимостями, с которыми он был протестирован.

Вернуться на верх