Arhn - архитектура программирования

Совместное использование модели между серверной частью и интерфейсом при использовании приложения create-response-app

Я создал проект с помощью create-react-app. Интерфейс описан в папке ./src. У меня есть файл с именем server.js в корне проекта. Этот файл описывает API с использованием express.

Я хотел бы иметь папку с моделями, которые будут совместно использоваться во внешнем интерфейсе (под ./src) и сервером (под ./server.js).

Пример одного из классов, которым я хотел бы поделиться:

export default class DataModel {
    constructor(name) {
        this.name = name;
    }
}

Если я помещу этот класс в ./src/models/DataModel.js, я могу использовать его внутри ./src, используя import DataModel from '../models/DataModel';, но я не могу использовать его внутри ./server.js, так как он дает мне следующую ошибку:

Неожиданный экспорт токена

И я не могу поместить класс непосредственно в корень моего проекта, поскольку приложение create-response-app не принимает импорт из-за пределов папки ./src и выдаст мне следующую ошибку:

Модуль не найден: вы попытались импортировать ../../DataModel, который находится за пределами каталога src / проекта. Относительный импорт вне src / не поддерживается.


Обновлять

Я пробовал использовать react-app-rewired, но безуспешно.

Мой package.json обновлен:

{
    //...
    "scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test",
    "eject": "react-scripts eject"
  },
    "devDependencies": {
    "react-app-rewired": "^2.1.0"
  }
}

И я добавил файл config-overrides.js в корень моего проекта (на том же уровне, что и package.json и мой класс DataModel).

/* config-overrides.js */

module.exports = function override(config, env) {
  delete config.resolve.plugins.ModuleScopePlugin;
  return config;
}

Но у меня все еще та же проблема:

Модуль не найден: вы попытались импортировать ../../DataModel, который находится за пределами каталога src / проекта. Относительный импорт вне src / не поддерживается.

Обновление # 2

Я зарегистрировал config, который был передан через функцию override, и вот что у меня получилось:

{
  "mode": "development",
  "devtool": "cheap-module-source-map",
  "entry": [
    "C:\\Users\\me\\Documents\\nodejs\\MY_PROJECT\\node_modules\\react-dev-utils\\webpackHotDevClient.js",
    "C:\\Users\\me\\Documents\\nodejs\\MY_PROJECT\\src\\index.js"
  ],
  "output": {
    "pathinfo": true,
    "filename": "static/js/bundle.js",
    "chunkFilename": "static/js/[name].chunk.js",
    "publicPath": "/"
  },
  "optimization": {
    "splitChunks": {
      "chunks": "all",
      "name": false
    },
    "runtimeChunk": true
  },
  "resolve": {
    "modules": [
      "node_modules"
    ],
    "extensions": [
      ".web.mjs",
      ".mjs",
      ".web.js",
      ".js",
      ".json",
      ".web.jsx",
      ".jsx"
    ],
    "alias": {
      "react-native": "react-native-web"
    },
    "plugins": [
      {
        "topLevelLoader": {}
      },
      {
        "appSrcs": [
          "C:\\Users\\me\\Documents\\nodejs\\MY_PROJECT\\src"
        ],
        "allowedFiles": {}
      }
    ]
  },
  "resolveLoader": {
    "plugins": [
      {}
    ]
  },
  "module": {
    "strictExportPresence": true,
    "rules": [
      {
        "parser": {
          "requireEnsure": false
        }
      },
      {
        "test": {},
        "enforce": "pre",
        "use": [
          {
            "options": {
              "formatter": "C:\\Users\\me\\Documents\\nodejs\\MY_PROJECT\\node_modules\\react-dev-utils\\eslintFormatter.js",
              "eslintPath": "C:\\Users\\me\\Documents\\nodejs\\MY_PROJECT\\node_modules\\eslint\\lib\\api.js",
              "baseConfig": {
                "extends": [
                  "C:\\Users\\me\\Documents\\nodejs\\MY_PROJECT\\node_modules\\eslint-config-react-app\\index.js"
                ],
                "settings": {
                  "react": {
                    "version": "999.999.999"
                  }
                }
              },
              "ignore": false,
              "useEslintrc": false
            },
            "loader": "C:\\Users\\me\\Documents\\nodejs\\MY_PROJECT\\node_modules\\eslint-loader\\index.js"
          }
        ],
        "include": "C:\\Users\\me\\Documents\\nodejs\\MY_PROJECT\\src"
      },
      {
        "oneOf": [
          {
            "test": [
              {},
              {},
              {},
              {}
            ],
            "loader": "C:\\Users\\me\\Documents\\nodejs\\MY_PROJECT\\node_modules\\url-loader\\dist\\cjs.js",
            "options": {
              "limit": 10000,
              "name": "static/media/[name].[hash:8].[ext]"
            }
          },
          {
            "test": {},
            "include": "C:\\Users\\me\\Documents\\nodejs\\MY_PROJECT\\src",
            "loader": "C:\\Users\\me\\Documents\\nodejs\\MY_PROJECT\\node_modules\\babel-loader\\lib\\index.js",
            "options": {
              "customize": "C:\\Users\\me\\Documents\\nodejs\\MY_PROJECT\\node_modules\\babel-preset-react-app\\webpack-overrides.js",
              "babelrc": false,
              "configFile": false,
              "presets": [
                "C:\\Users\\me\\Documents\\nodejs\\MY_PROJECT\\node_modules\\babel-preset-react-app\\index.js"
              ],
              "cacheIdentifier": "development:[email protected]:[email protected]:[email protected]:[email protected]",
              "plugins": [
                [
                  "C:\\Users\\me\\Documents\\nodejs\\MY_PROJECT\\node_modules\\babel-plugin-named-asset-import\\index.js",
                  {
                    "loaderMap": {
                      "svg": {
                        "ReactComponent": "@svgr/webpack?-prettier,-svgo![path]"
                      }
                    }
                  }
                ]
              ],
              "cacheDirectory": true,
              "cacheCompression": false
            }
          },
          {
            "test": {},
            "exclude": {},
            "loader": "C:\\Users\\me\\Documents\\nodejs\\MY_PROJECT\\node_modules\\babel-loader\\lib\\index.js",
            "options": {
              "babelrc": false,
              "configFile": false,
              "compact": false,
              "presets": [
                [
                  "C:\\Users\\me\\Documents\\nodejs\\MY_PROJECT\\node_modules\\babel-preset-react-app\\dependencies.js",
                  {
                    "helpers": true
                  }
                ]
              ],
              "cacheDirectory": true,
              "cacheCompression": false,
              "cacheIdentifier": "development:[email protected]:[email protected]:[email protected]:[email protected]",
              "sourceMaps": false
            }
          },
          {
            "test": {},
            "exclude": {},
            "use": [
              "C:\\Users\\me\\Documents\\nodejs\\MY_PROJECT\\node_modules\\style-loader\\index.js",
              {
                "loader": "C:\\Users\\me\\Documents\\nodejs\\MY_PROJECT\\node_modules\\css-loader\\index.js",
                "options": {
                  "importLoaders": 1
                }
              },
              {
                "loader": "C:\\Users\\me\\Documents\\nodejs\\MY_PROJECT\\node_modules\\postcss-loader\\src\\index.js",
                "options": {
                  "ident": "postcss"
                }
              }
            ]
          },
          {
            "test": {},
            "use": [
              "C:\\Users\\me\\Documents\\nodejs\\MY_PROJECT\\node_modules\\style-loader\\index.js",
              {
                "loader": "C:\\Users\\me\\Documents\\nodejs\\MY_PROJECT\\node_modules\\css-loader\\index.js",
                "options": {
                  "importLoaders": 1,
                  "modules": true
                }
              },
              {
                "loader": "C:\\Users\\me\\Documents\\nodejs\\MY_PROJECT\\node_modules\\postcss-loader\\src\\index.js",
                "options": {
                  "ident": "postcss"
                }
              }
            ]
          },
          {
            "test": {},
            "exclude": {},
            "use": [
              "C:\\Users\\me\\Documents\\nodejs\\MY_PROJECT\\node_modules\\style-loader\\index.js",
              {
                "loader": "C:\\Users\\me\\Documents\\nodejs\\MY_PROJECT\\node_modules\\css-loader\\index.js",
                "options": {
                  "importLoaders": 2
                }
              },
              {
                "loader": "C:\\Users\\me\\Documents\\nodejs\\MY_PROJECT\\node_modules\\postcss-loader\\src\\index.js",
                "options": {
                  "ident": "postcss"
                }
              },
              "C:\\Users\\me\\Documents\\nodejs\\MY_PROJECT\\node_modules\\sass-loader\\lib\\loader.js"
            ]
          },
          {
            "test": {},
            "use": [
              "C:\\Users\\me\\Documents\\nodejs\\MY_PROJECT\\node_modules\\style-loader\\index.js",
              {
                "loader": "C:\\Users\\me\\Documents\\nodejs\\MY_PROJECT\\node_modules\\css-loader\\index.js",
                "options": {
                  "importLoaders": 2,
                  "modules": true
                }
              },
              {
                "loader": "C:\\Users\\me\\Documents\\nodejs\\MY_PROJECT\\node_modules\\postcss-loader\\src\\index.js",
                "options": {
                  "ident": "postcss"
                }
              },
              "C:\\Users\\me\\Documents\\nodejs\\MY_PROJECT\\node_modules\\sass-loader\\lib\\loader.js"
            ]
          },
          {
            "exclude": [
              {},
              {},
              {}
            ],
            "loader": "C:\\Users\\me\\Documents\\nodejs\\MY_PROJECT\\node_modules\\file-loader\\dist\\cjs.js",
            "options": {
              "name": "static/media/[name].[hash:8].[ext]"
            }
          }
        ]
      }
    ]
  },
  "plugins": [
    {
      "options": {
        "template": "C:\\Users\\me\\Documents\\nodejs\\MY_PROJECT\\public\\index.html",
        "templateContent": false,
        "filename": "index.html",
        "hash": false,
        "inject": true,
        "compile": true,
        "favicon": false,
        "minify": false,
        "cache": true,
        "showErrors": true,
        "chunks": "all",
        "excludeChunks": [],
        "chunksSortMode": "auto",
        "meta": {},
        "title": "Webpack App",
        "xhtml": false
      },
      "version": 4
    },
    {
      "replacements": {
        "NODE_ENV": "development",
        "PUBLIC_URL": "",
        "REACT_APP_DEFAULT_LANGUAGE": "fr"
      }
    },
    {
      "appPath": "C:\\Users\\me\\Documents\\nodejs\\MY_PROJECT"
    },
    {
      "definitions": {
        "process.env": {
          "NODE_ENV": "\"development\"",
          "PUBLIC_URL": "\"\"",
          "REACT_APP_DEFAULT_LANGUAGE": "\"fr\""
        }
      }
    },
    {
      "options": {},
      "fullBuildTimeout": 200,
      "requestTimeout": 10000
    },
    {
      "options": {},
      "pathCache": {},
      "fsOperations": 0,
      "primed": false
    },
    {
      "nodeModulesPath": "C:\\Users\\me\\Documents\\nodejs\\MY_PROJECT\\node_modules"
    },
    {
      "options": {
        "resourceRegExp": {},
        "contextRegExp": {}
      }
    },
    {
      "opts": {
        "publicPath": "/",
        "basePath": "",
        "fileName": "asset-manifest.json",
        "transformExtensions": {},
        "writeToFileEmit": false,
        "seed": null,
        "filter": null,
        "map": null,
        "generate": null,
        "sort": null
      }
    }
  ],
  "node": {
    "dgram": "empty",
    "fs": "empty",
    "net": "empty",
    "tls": "empty",
    "child_process": "empty"
  },
  "performance": false
}

Я регистрирую это перед вызовом операции delete, и, как мы видим, их нет ModuleScopePlugin. Так почему он все еще не работает?

Любая помощь приветствуется.

Спасибо.


  • stackoverflow.com/questions/44114436/. И используйте экспорт CommonJS вместо модулей ES. 27.02.2019
  • Но для этого нужно сделать eject. Что делать, если я не хочу выгружать свое приложение? 27.02.2019
  • Вы можете использовать react-app-rewired. Либо то, либо другое. Более общий способ - сделать частный common пакет и использовать его в обоих. 27.02.2019
  • Я не знал о react-app-rewired (я новичок в реакции). Скоро попробую, спасибо. 27.02.2019
  • Я пробовал react-app-rewired, но похоже, что это не работает. Есть идеи, что я делаю неправильно? 08.03.2019

Ответы:


1

Совместное использование кода - вот для чего нужны модули. В идеале вы должны упаковать свои модели в модуль и установить / импортировать в каждую базу кода. Чтобы упростить разработку, вы, вероятно, захотите использовать формат monorepo, используя Lerna и Yarn (или аналогичные альтернативы).

Если это выходит за рамки вашего проекта, я думаю, вы сможете обойтись без использования экспорта CommonJS в коде модели (как предлагалось ранее), который вы храните в src приложения React и требуете от кода вашего сервера.

./src/models/DataModel.js:

class DataModel {
  constructor(name) {
    this.name = name;
  }
}
module.exports = { DataModel };

из приложения React

import { DataModel } from "./models/DataModel";

с сервера

const { DataModel } = require("./src/models/DataModel");

=========================================================================

Обновлять

Итак, насколько я могу судить, здесь мы сталкиваемся с некоторым глубоким вуду с js-модулями.

Код, который я предложил выше, работает вcodeandbox, но не локально.

Я безуспешно пытался сопоставить сценарии реакции и версии реакции с теми, которые находятся в codeandbox. Я могу только предположить, что у codeandbox есть собственные механизмы решения проблемы.

Как только класс определен в модуле с использованием экспорта commonjs, все становится странно с

module.exports = { DataModel }; и import {DataModel} дают Attempted import error: 'DataModel' is not exported from '../models/DataModel'.

module.exports = { DataModel }; и require дает TypeError: Cannot assign to read only property 'exports' of object '#<Object>'

а также

exports.DataModel = DataModel; и require дает ReferenceError: exports is not defined

Замените class на "класс" старой школы и require модуль из нашего приложения, и все будет работать, как ожидалось.

function DataModel(name) {
  this.name = name;
}

DataModel.prototype.logName = function () {
  console.log(this.name);
}

module.exports = { DataModel };

Похоже, это связано со всей магией, которую выполняет webpack / babel / et al, чтобы справиться с различными форматами модулей, плавающими вокруг, но я действительно не мог этого решить.

На секунду я подумал, что это объяснит это, но… это не… https://medium.com/webpack/webpack-4-import-and-commonjs-d619d626b655

09.03.2019
  • Фактически, совместное использование кода, вероятно, является лучшим решением в большинстве случаев, но это не то, что мы собираемся делать по внутренним причинам (+ проект небольшой, и его не нужно разделять). Решение со смешиванием import и require в порядке, но у меня все еще есть проблема: я не могу использовать свой конструктор внутри приложения React. Если я попробую new DataModel('my model');, я получу следующую ошибку: Ошибка попытки импорта: DataModel не экспортируется из ./models/DataModel. 11.03.2019
  • Вы использовали именованный формат импорта, т.е. import { DataModel }, а не формат импорта по умолчанию, import DataModel? 12.03.2019
  • Я использовал именованный формат импорта (как в примере) 12.03.2019
  • Тогда я не уверен, что случилось. Может быть, что-то в вашем конфиге webpack? Я не понимаю, почему это не сработает, но у меня это работает .. codesandbox.io/s/ 8l17wn84x0 12.03.2019
  • Моя конфигурация веб-пакета - это конфигурация по умолчанию, заданная приложением create-response-app. Но в любом случае спасибо за ваше время, я буду продолжать поиск решения этой проблемы. 12.03.2019
  • И если я не использую именованный формат импорта, я получаю сообщение об ошибке, что это не экспорт по умолчанию для DataModel. 12.03.2019
  • не стоит беспокоиться. Можете ли вы вообще воспроизвести это в codeandbox? может это поможет. 12.03.2019
  • Позвольте нам продолжить это обсуждение в чате. 12.03.2019
  • Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..