从 NextJs 11 开始,有一个名为 externalDir 的新实验选项运行良好,并且不需要使用 next-transpile-modules。
为了清楚起见,让我们一步一步地做,它可能看起来很长,但是一旦你掌握了它,它就很容易(实际上是 3 个步骤)
1。纱线 V3(可选)
为了改善体验,我建议升级yarn to v3+ (yarn set version 3.0.2 && yarn plugin import workspace-tools) 并编辑生成的配置.yarnrc.yml,类似于此:
# Yarn 2+ supports pnp or regular node_modules installs. Use node-modules one.
nodeLinker: node-modules
nmMode: hardlinks-local
plugins:
- path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs
spec: "@yarnpkg/plugin-workspace-tools"
yarnPath: .yarn/releases/yarn-3.0.2.cjs
PS:您可能也想将此添加到.gitignore
.yarn/*
!.yarn/patches
!.yarn/releases
!.yarn/plugins
!.yarn/sdks
!.yarn/versions
.pnp.*
为什么?因为您可以使用workspace: alias protocol。 (也可以在 pnpm 中使用)
2。严格的工作区拓扑(可选)
我建议严格限制软件包所依赖的内容(有明确的界限)。这不是绝对要求,而是一种可以避免难以调试情况的良好做法。
为了帮助包管理器,我建议正确声明每个应用程序/包的依赖项及其边界。
换句话说,每个包/应用程序都有自己的 package.json,您可以在其中显式添加他们需要的 deps(不在根 package.json 中)
按照你的例子,
apps/
packages
/app
package.json (app depend on ui-kit through yarn workspace: alias)
tsconfig.json (we will add typescript path aliases there too)
next.config.js
/ui-kit
package.json
package.json (do not put nextjs as dep here, only in app)
rootpackage.json 的示例
{
"name": "monorepo",
"private": true,
"workspaces": [
"packages/*" // Enable package discovery in packages/* directory.
],
"devDependencies": {
"husky": "7.0.2", // Only what's needed for monorepo management
}
packages/app/package.json 的示例
{
"name": "my-app",
"devDependencies": {
"@types/node": "16.10.1",
"@types/react": "17.0.29",
"@types/react-dom": "17.0.9",
"typescript": "4.4.4"
},
"dependencies": {
// Assuming the name of packages/ui-kit is ui-kit,
// we explicitly declare the dependency on it through
// workspace: alias (package-manager perspective)
"ui-kit": "workspace:*",
"next": "11.1.2",
"react": "17.0.2",
"react-dom": "17.0.2",
}
}
为什么?这样你就不会陷入与部门冲突的奇怪问题。
3。打字稿别名
即使您不使用 typescript,NextJs 也会读取 tsconfig.json 并查找 typescript path mapping 配置。如果您不知道它是什么......它只是一个您声明(再一次)您的部门的配置。 Nextjs 会将它们转换为它在后台编译 deps 时使用的内容(即:babel-plugin-module-resolver 和可能稍后的 swc)。
按照您的示例,只需以这种方式编辑./packages/app/tsconfig.json
{
"compilerOptions": {
// here baseUrl is set at ./src (good practive), can
// be set to '.'
"baseUrl": "./src",
"paths": {
// Declare deps here (keep them in sync with what
// you defined in the package.json)
// PS: path are relative to baseUrl
"ui-kit/*": ["../../ui-kit/src/*"],
// if you have a barrel in ui-lib
"ui-kit": ["../../ui-kit/src/index"],
}
},
}
为什么?更多工具之间的限制(包管理器和路径有不同的视角)
4。 Nextjs 配置
在packages/app/nextjs.config.js 中,启用externalDir 配置(目前处于实验阶段,但效果很好,feedback thread here)
const nextConfig = {
experimental: {
// this will allow nextjs to resolve files (js, ts, css)
// outside packages/app directory.
externalDir: true,
},
};
export default nextConfig;
PS:对于较旧的 nextjs 版本,完全可以通过自定义 webpack 配置来做同样的事情。询问您是否需要示例。
你会得到什么
在您的应用中,您应该能够像这样导入您的 ui-kit:
import { Button } from 'ui-kit';
// or
import Avatar from 'ui-kit/components/Avatar'
它的美妙之处在于快速刷新可以开箱即用(无需构建)。它很快,你不需要 NX(+ 昂贵的 nx.cloud)、rush 或任何东西......
Nextjs 将简单地导入文件,按需构建它们,甚至将它们缓存在它自己的优化缓存中(尤其是在 webpack 5 中速度很快,并且也可以在 CI 上启用)...
如果您想了解更多信息,我会维护一个示例存储库,该存储库将在此存储库上提供完整的生命周期视角(ci、github 操作、linter、部署...):https://github.com/belgattitude/nextjs-monorepo-example。
PS:也关注 yarn 3+ 开发和版本here,他们现在做得很好。