具有多个工作区的 React 应用程序中的通用路径 - 如何做到这一点?

Cec*_*uez 13 javascript typescript reactjs react-native

所以我有一个基于此的 monorepo 尝试使用:

https://github.com/GeekyAnts/nativebase-templates/tree/master/solito-universal-app-template-nativebase-typescript

这个仓库有 4 个独立的地方,其中有一个 package.json(理论上是一个 tsconfig.json)——该应用程序部分是 TypeScript,部分是 Javascript(随着时间的推移,逐渐用 TypeScript 重写它)

基本上目录结构如下所示:

/ - root directory
/apps/expo - expo-related packages, configurations, functions, etc
/apps/next - next-related packages, configuration, functions, etc
/packages/app/ - general business logic, code, pages, etc
Run Code Online (Sandbox Code Playgroud)

无论我尝试做什么或尝试在何处设置路由,它都不起作用。

在我的根文件夹中的 tsconfig.json 中,我有这个(我也尝试将其放入各个文件夹的各个 tsconfig.json 文件中):

"paths": {
  "app/*": ["./packages/app/*"],
  "components/*": ["./packages/app/components"],
  "config/*": ["./packages/app/config"],
  "controllers/*": ["./packages/app/controllers"],
  "pages/*": ["./packages/app/pages"],
  "reducers/*": ["./packages/app/redux"],
  "resources/*": ["./packages/app/resources"],
  "revenuecat/*": ["./packages/app/revenuecat"],
  "routing/*": ["./packages/app/routing"],
  "utils/*": ["./packages/app/utils"],
  "interfaces/*": ["./packages/app/interfaces"],
  "root/*": ["./*"]
}
Run Code Online (Sandbox Code Playgroud)

但我的 Next 应用程序无法识别这些路径。

我尝试将 Expo 文件夹的 babel.config.js 放入我的插件中:

  [
    'module-resolver',
    {
      root: '../../packages',
      alias: {
        app: '../../packages/app',
        components: '../../packages/app/components',
        config: '../../packages/app/config',
        controllers: '../../packages/app/controllers',
        pages: '../../packages/app/pages',
        reducers: '../../packages/app/redux',
        resources: '../../packages/app/resources',
        revenuecat: '../../packages/app/revenuecat',
        routing: '../../packages/app/routing',
        utils: '../../packages/app/utils',
        interfaces: '../../packages/app/interfaces',
      },
    },
  ]
Run Code Online (Sandbox Code Playgroud)

我尝试将它们放在 Next 文件夹的 .babelrc 中,也在我的插件中:

[
  "module-resolver",
  {
    "root": "../../packages",
    "alias": {
      "app/*": "../../packages/app",
      "components": "../../packages/app/components",
      "config": "../../packages/app/config",
      "controllers": "../../packages/app/controllers",
      "pages": "../../packages/app/pages",
      "reducers": "../../packages/app/redux",
      "resources": "../../packages/app/resources",
      "revenuecat": "../../packages/app/revenuecat",
      "routing": "../../packages/app/routing",
      "utils": "../../packages/app/utils",
      "interfaces": "../../packages/app/interfaces"
    }
  }
]
Run Code Online (Sandbox Code Playgroud)

我尝试运行的代码是 _app.js,它调用 /packages/app/components/main 文件夹中的页脚文件。_app.js 工作正常,它到达我的 Footer.web.js 文件,但随后我得到:

error - ../../packages/app/components/main/Footer.web.js:4:0
Module not found: Can't resolve 'components/main/AppButtons'
  2 | import { FontAwesome } from '@expo/vector-icons';
  3 | import moment from 'moment';
> 4 | import AppButtonGroup from 'components/main/AppButtons';
  5 | import {
  6 |   Row,
  7 |   Column,
Run Code Online (Sandbox Code Playgroud)

现在 Appbuttons.tsx 与 Footer.web.js 位于同一文件夹中

我的猜测是我的 /packages/app 文件夹需要另一个 .babelrc 文件?或者是另一个错误?

我的工作区在我的根 package.json 中设置如下:

  "workspaces": [
    "apps/*",
    "packages/*"
  ],
Run Code Online (Sandbox Code Playgroud)

是什么导致这个不起作用?为什么我的路径在 /packages/app 文件夹中不起作用?

hac*_*ape 4

解决方案

  1. 将您的路径别名添加到工作区根目录中tsconfig.json,同时添加"baseURL": "./".
{
   "compilerOptions": {
+    "baseUrl": "./",
     "strictNullChecks": true,
     "noUncheckedIndexedAccess": true,
     "paths": {
       "app/*": ["./packages/app/*"],
+      "components/*": ["./packages/app/components/*"],
+      "config/*": ["./packages/app/config"],
       // ...
Run Code Online (Sandbox Code Playgroud)
  1. 配置next、安装tsconfig-paths-webpack-plugin、转到apps/next/next.config.js并应用此插件:
const path = require('node:path');
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
// ...

module.exports = withNativebase({
  // ...

  nextConfig: {
    webpack: (config, options) => {
      // ...

      config.resolve.plugins = [
        ...config.resolve.plugins,
        new TsconfigPathsPlugin({
          // Use the root `tsconfig.json`!
          configFile: path.resolve(__dirname, '../../tsconfig.json'),
        }),
      ]

      return config
    },
Run Code Online (Sandbox Code Playgroud)
  1. 配置expo,转到apps/expo/babel.config.js
const path = require('node:path');

// ...

    plugins: [
      'react-native-reanimated/plugin',
      [
        'module-resolver',
        {
          root: path.resolve(__dirname, '../../'),
          alias: {
            app: './packages/app',
            components: './packages/app/components',
            // ...
          },
        },
      ]
    ]
Run Code Online (Sandbox Code Playgroud)

解释

首先,让我说一下,我个人只会使用"app/components/*"别名,这样可以避免这种疯狂的配置。但既然你问了,这就是答案。请参阅上面的解决方案,下面是一些关于技术细节的书呆子解释。不在乎的话就跳过吧。

app/*伪别名的真相

如果没有上述配置,则只有app/*别名有效。但原因有点特殊:这不是真正的(用捆绑工具的术语)别名。它实际上是一个真正的文件系统符号链接<root>/node_modules/app -> <root>/packages/app

这个符号链接是由yarn/npm 的工作空间机制创建的。因为它位于 中<root>/node_modules,所以别名app/*路径实际上会被解析,就像它是一个真正的 npm 包一样。

不只是简单地使用别名

现在,如果您想添加自己的真实别名,则必须努力使用构建工具。

您使用的模板有两种工具设置:next适用于 Web、expo适用于本机。您需要单独解决它们。

在这种情况下,tsconfig.json->compilerOptions.paths主要用于IDE提示(例如vscode跳转到定义)。默认情况下,这两个工具都不使用它。因此,您仍然需要通过插件手动配置别名,就像我在解决方案部分中所示的那样。

是的,3 个工具的 3 个配置,太疯狂了。

重新审视伪别名

另一个解决方案是利用工作空间机制来创建伪别名,就像app/*. 例如,如果您想要components/*作为“别名”。你需要:

  1. 创建<root>/packages/components/package.json并给它一个"name": "components".

一个小变化:如果您"name": "duck"出于某种原因使用,您的伪别名将变成duck/*,即文件夹名称并不重要。只有包名称很重要。

  1. cd回到项目根目录,然后简单地运行yarn,您现在应该在 处看到一个符号链接<root>/node_modules/components

  2. (可选步骤)如果您想使用此“别名”,您应该添加到其他工作区包(例如)"dependencies": { "components": "*" }因为package.json它实际上是您依赖的另一个名为的包。将 dep 包添加到字段中是一个很好的做法。apps/next/package.jsoncomponents/*"components""dependencies"

我知道也很费力。但仍然是一个选择。