使用 create-react-app 时在后端和前端之间共享模型

IT技术 reactjs model-view-controller
2021-05-13 14:26:21

我使用create-react-app创建了一个项目前端在./src文件夹内描述我有一个以server.js项目根目录命名的文件此文件使用express描述 API

我想要一个文件夹,其中包含将在前端(下./src)和后端(下之间共享的模型./server.js

我想分享的其中一个课程的示例:

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

如果我把这个类放在 下./src/models/DataModel.js,我可以./src通过 using在里面使用它import DataModel from '../models/DataModel';但我不能在里面使用它,./server.js因为它给了我以下错误:

意外的令牌导出

而且我不能将类直接放在我的项目的根目录下,因为 create-react-app 不接受从./src文件夹外部导入,并且会给我以下错误:

未找到module:您试图导入位于项目 src/ 目录之外的 ../../DataModel。不支持 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;
}

但我仍然有同样的问题:

未找到module:您试图导入位于项目 src/ 目录之外的 ../../DataModel。不支持 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:babel-plugin-named-asset-import@0.2.3:babel-preset-react-app@6.1.0:react-dev-utils@6.1.1:react-scripts@2.1.1",
              "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:babel-plugin-named-asset-import@0.2.3:babel-preset-react-app@6.1.0:react-dev-utils@6.1.1:react-scripts@2.1.1",
              "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操作之前记录它,我们可以看到它们是 no ModuleScopePlugin那么为什么它仍然失败呢?

欢迎任何帮助。

谢谢。

1个回答

共享代码是module的用途。理想情况下,您将模型打包到一个module中并安装/导入到每个代码库中。为了保持开发简单,您可能希望使用使用 Lerna 和 Yarn(或类似替代品)的 monorepo 格式。

如果这超出了您的项目范围,那么我认为您应该能够在您的模型代码中使用 CommonJS 导出(如先前建议的那样),您将其保存在 React 应用程序 src 中并从您的服务器代码中要求。

./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 module伏都教。

我上面建议的代码适用于 codeandbox,但不适用于本地。

我尝试将 react-scripts 和 react 版本与 codeandbox 中的那些匹配,但没有成功。我只能假设 codeandbox 有自己的应对机制来缓解这个问题。

一旦使用 commonjs 导出在module中定义了类,事情就会变得很奇怪

module.exports = { DataModel };import {DataModel}给予Attempted import error: 'DataModel' is not exported from '../models/DataModel'.

module.exports = { DataModel };requireTypeError: Cannot assign to read only property 'exports' of object '#<Object>'

exports.DataModel = DataModel;requireReferenceError: exports is not defined

换掉class一个老式的“class”,以及require我们应用程序中的module,一切都按预期工作。

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

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

module.exports = { DataModel };

这似乎与 webpack/babel/et al 执行的所有魔法有关,以处理浮动的不同module格式,但我真的无法确定。

有那么一瞬间我以为这会解释它,但是..它没有.. https://medium.com/webpack/webpack-4-import-and-commonjs-d619d626b655