Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

monorepo 如何解决别名问题 #95

Open
bosens-China opened this issue Jan 5, 2023 · 0 comments
Open

monorepo 如何解决别名问题 #95

bosens-China opened this issue Jan 5, 2023 · 0 comments
Labels
工具相关 工程化相关的东西

Comments

@bosens-China
Copy link
Owner

得益于 pnpm 软链接实现现在 monorepo 项目已经十分成熟了,不过在写项目时候还是遇到很多痛点,例如:

  1. 如果我有多个 packages 项目并且使用 TypeScript,那么我肯定希望是写的都是 ts,在需要调用的时候通过工具来完成这一过程的转译,不过在实际开发中可能使用了 vite 这样的工具,导致遇到问题只能通过其它方式来绕过去;
  2. 如果写一个后端项目,那么数据库定义的模型描述肯定希望在 web 项目也可以复用,不过在多入口中可能还需要通过 @new-house/src/xxxx.ts 来引用,这个 src/xxx 也太不简洁了。

所以这篇文章重点就是解决问题 2 ,问题 1 如果有机会再单独开一个篇幅来说,在正式讲解之前需要介绍一下 exports 这个属性

exports

这个属性添加于 v12.7.0,最简单的使用方式如下

{
  // package.json
  "exports": "./index.js"
}

它的优先级高于 main,除此之外更多是作为不同环境导入文件来使用,例如开发了一个 utils 的包希望它可以在 node 的 cjs 和 ems 环境下工作,那么它就可以发挥作用了。

{
  "exports": {
    ".": {
      "import": "./feature-node.mjs",
      "require": "./feature-node.cjs"
    },
  }
}

除此之外还可以解决目录别名问题,这也是为什么介绍它的原因

{
  "name": "my-package",
  "exports": {
    ".": "./lib/index.js",
    "./lib": "./lib/index.js",
    "./lib/*": "./lib/*.js",
    "./lib/*.js": "./lib/*.js",
    "./feature": "./feature/index.js",
    "./feature/*": "./feature/*.js",
    "./feature/*.js": "./feature/*.js",
    "./package.json": "./package.json"
  }
}

上面的 "./feature/*": "./feature/*.js", 以及 "./feature/*.js": "./feature/*.js", 等都可以通过 my-package/feature/xxx.js 来完成调用

exports 就介绍到这里,了解到它可以适配不同环境以及用于解决目录别名,下面就是项目实战。

TypeScript 下使用

为了方便,这里我已经搭建好了一个 pnpm monorepo 项目,它的文件结构如下

test
├─ node_modules
├─ package.json
├─ packages
│    ├─ utils
│    │    ├─ package.json
│    │    ├─ src
│    │    │    ├─ addition.ts
│    │    │    └─ subtraction.ts
│    │    └─ tsconfig.json
│    └─ web
│           ├─ babel.config.js
│           ├─ dist
│           │    └─ index.js
│           ├─ node_modules
│           ├─ package.json
│           ├─ src
│           │    └─ index.ts
│           ├─ tsconfig.json
│           └─ webpack.config.js
├─ pnpm-lock.yaml
├─ pnpm-workspace.yaml
└─ tsconfig.json

utils 这个项目用于给 web 项目使用,它的 package.json 内容如下

{
  "name": "@test/utils",
  "version": "1.0.0",
  "exports": {
    "./*": "./src/*.ts"
  }
}

这里设置 "./*" 是提示这个为一个子目录别名,同理你也可以设置 "test/*" 表示以 test 为开头,因为 utils 这个项目都是 ts 我并不想花时间每次都 build 一遍成 js 所以只能写成 ./src/*.ts

这里提示一下,如果是 ts 项目必须这个结尾,否则会提示找不到类型文件

第二步就是在 web 项目中引用

// web/src/index.ts
import addition from '@test/utils/addition';
import subtraction from '@test/utils/subtraction';

console.log(addition(1, 1));
console.log(subtraction(1, 1));

如果 TypeScript 提示说不到模块之类的错误,那么你需要调整一下 tsconfig.json 的配置

{
  "compilerOptions": {
    "moduleResolution": "NodeNext" // node 16也可以
  }
}

这样就消除了闹心的 src 目录

其它问题

TypeScript 使用别名如何定义类型文件

这个可以参考官方文档的实现

// package.json
{
  "name": "my-package",
  "type": "module",
  "exports": {
    ".": {
      // Entry-point for TypeScript resolution - must occur first!
      "types": "./types/index.d.ts",
      // Entry-point for `import "my-package"` in ESM
      "import": "./esm/index.js",
      // Entry-point for `require("my-package") in CJS
      "require": "./commonjs/index.cjs"
    }
  },
  // CJS fall-back for older versions of Node.js
  "main": "./commonjs/index.cjs",
  // Fall-back for older versions of TypeScript
  "types": "./types/index.d.ts"
}

额外在 exports 中添加 types 属性,相关讨论链接 microsoft/TypeScript#33079 (comment)

设置了 moduleResolution 导致导入其它模块必须以.js 结尾

以.js 结尾是规范的规定,如果你使用 webpack5 来打包项目可以在配置文件中添加以下内容

{
  resolve: {
    extensionAlias: {
      ".js": [".ts", ".js"],
      ".cjs": [".cts", ".cjs"],
      ".mjs": [".mts", ".mjs"],
    }
    // ...
  }
  // ...
}

相关问题链接 Support TypeScript module resolution node16 · Issue #12625 · facebook/create-react-app (github.com)

参考链接

@bosens-China bosens-China added the 工具相关 工程化相关的东西 label Jan 5, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
工具相关 工程化相关的东西
Projects
None yet
Development

No branches or pull requests

1 participant