使用 create-react-app 时在后端和前端之间共享模型 [英] Share model between backend and frontend when using create-react-app

查看:52
本文介绍了使用 create-react-app 时在后端和前端之间共享模型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I created a project using create-react-app. The front-end is described inside the ./src folder. I have a file named server.js on the root of the project. This file is describing the API using express.

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

I would like to have a folder with models that would be shared between the front-end (under ./src) and the back-end (under ./server.js).

我想分享的一个类的例子:

An example of a one of the classes that I would like to share:

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

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

If I put this class under ./src/models/DataModel.js, I can use it inside ./src by using import DataModel from '../models/DataModel'; but I can't use it inside ./server.js as it gives me the following error:

意外的令牌导出

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

And I can't put the class directly under to the root of my project as create-react-app do not accept import from outside the ./src folder and will give me the following error:

未找到模块:您试图导入位于项目 src/目录之外的 ../../DataModel.不支持 src/之外的相对导入.

Module not found: You attempted to import ../../DataModel which falls outside of the project src/ directory. Relative imports outside of src/ are not supported.

<小时>

更新

我尝试使用 react-app-rewired 但没有成功.

我的 package.json 已更新:

My package.json has been updated:

{
    //...
    "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 类处于同一级别).

And I added the file config-overrides.js on the root of my project (same level as package.json and my DataModel class).

/* config-overrides.js */

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

但我仍然有同样的问题:

But I still have the same issue:

未找到模块:您试图导入位于项目 src/目录之外的 ../../DataModel.不支持 src/之外的相对导入.

Module not found: You attempted to import ../../DataModel which falls outside of the project src/ directory. Relative imports outside of src/ are not supported.

更新 #2

我记录了通过 override 函数传递的 config,这是我得到的:

Update #2

I logged the config that is passed through the override function and here is what I got:

{
  "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 操作之前记录它,我们可以看到它们不是 ModuleScopePlugin.那么为什么它仍然失败?

I log it before calling the delete operation and as we can see their is no ModuleScopePlugin. So why does it still failing?

欢迎任何帮助.

谢谢.

推荐答案

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

Sharing code is what modules are for. Ideally you would package up you models into a module and install/import into each codebase. To keep development simple you would probably want to utilise a monorepo format using Lerna and Yarn (or similar alternatives).

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

If that's beyond the scope of your project then I think you should be able to get away with using CommonJS exports in your model code (as previously suggested) which you keep in the React app src and require from your server code.

./src/models/DataModel.js:

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

来自 React 应用

from React app

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

来自服务器

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

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

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

据我所知,我们在这里遇到了一些深入的 js 模块伏都教.

So as far as I can tell we're hitting some deep js-module voodoo here.

我上面建议的代码在 codeandbox 中有效,但在本地无效.

The code I suggested above works in codesandbox, but not locally.

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

I have tried matching the react-scripts and react versions with those in codesandbox with no success. I can only assume that codesandbox has it's own coping mechanisms which alleviate the problem.

一旦使用 commonjs 导出在模块中定义了类,

As soon as the class is defined in the module using the commonjs export, things get weird with

module.exports = { DataModel };import {DataModel} 给出 尝试导入错误:'DataModel' 未从 '../models 导出/DataModel'.

module.exports = { DataModel };require 给出 TypeError:无法分配给对象#"的只读属性exports"'

exports.DataModel = DataModel;require 给出 ReferenceError:exports is not defined

class 换成老式的类",并require 应用程序中的模块,一切都按预期进行.

Swap out the class for an old-school "class" though, and require the module from our app, and everything works as expected.

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

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

module.exports = { DataModel };

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

It seems it's to do with all the magic being performed by webpack/babel/et al to deal with the different module formats floating around, but I really couldn't nail it down.

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

For a second I thought this was going to explain it, but.. it didn't.. https://medium.com/webpack/webpack-4-import-and-commonjs-d619d626b655

这篇关于使用 create-react-app 时在后端和前端之间共享模型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆