簡體   English   中英

將 next.js 與紗線工作區結合使用

[英]Using next.js with yarn workspaces

今天遇到了這樣的項目結構的復雜問題

packages
  /app
    pages/
    package.json
  /ui-kit
    pages/
    package.json
  /shared
.babelrc
package.json

root lvl package json 定義了workspaces: [packages/*]其中appui-kit都是 nextjs 應用程序。

我在 root lvl package.json 中有以下腳本

"dev:app": "next packages/app",
"dev:ui-kit": "next packages/ui-kit"

在我引入shared文件夾之前,這兩個都運行良好, shared文件夾本質上包含一些功能/組件等......在包之間重復使用。 一旦我將它包含到appui-kit我就會收到這樣的錯誤

在 ./packages/shared/index.js

模塊解析失敗:意外標記 (4:21) 您可能需要一個合適的加載程序來處理此文件類型。 | 從“反應”導入反應 | | export default () => 你好,共享! |

所以看起來 nextjs 沒有將任何加載器應用於它指向的文件夾之外的任何東西。 有沒有辦法以某種方式解決這個問題? 即從根文件夾開始,但根據不同的腳本命令以某種方式將其指向不同的入口文件?

問題是下一個文件夾之外的代碼沒有被 Babel 轉譯。 這是因為.babelrc文件沒有被考慮在內,即使它位於代碼的根目錄。

但是,如果您改為使用babel.config.js文件(從 Babel 版本 7 開始推薦)並將其放在代碼的根目錄(有效替換.babelrc文件),您可以使用此插件:

https://github.com/josephluck/next-plugin-custom-babel-config

我已經做到了,而且效果很好!

對於 Next.js 9.2+, 這個其他答案對我不起作用。 我不得不使用一個名為next-transpile-modules的分叉包。

你真正需要做的就是yarn add next-transpile-modules到每個包中,然后添加/編輯next.config.js ,如下所示:

// next.config.js
const withTM = require('next-transpile-modules')(['somemodule', 'and-another']); // pass the modules you would like to see transpiled

module.exports = withTM();

如果您想使用 Next.js 默認值,您甚至可能不再需要將babel.config.js放入根目錄。

包的工作方式是通過實現自定義 Webpack 配置, 如官方文檔中所述,告訴 webpack 監視您在上面的next.config.js定義的模塊的目錄。

嘗試將其添加到 next.config.js 以啟用下一個根文件夾之外的編譯打字稿文件:

module.exports = {
  // ... other settings
  experimental: {
    externalDir: true,
  },
}

歸功於: https : //github.com/belgattitude/nextjs-monorepo-example#step-33-next-config

NextJs 11 開始,有一個名為externalDir的新實驗選項,它運行良好並且不需要使用 next-transpile-modules。

為了清楚起見,讓我們一步一步地說明,這可能看起來是一個漫長的過程,但是一旦你掌握了它,它就非常簡單(實際上 3 個步驟)


1.紗線V3(可選)

為了改善體驗,我建議將yarn升級到 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.*

為什么 ? 因為您將有可能使用工作區:別名協議 (也可在 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)

package.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",
  }
}

為什么 ? 這樣你就不會陷入與 deps 沖突的奇怪問題。


3. 打字稿別名

即使你沒有使用 typescript,NextJs 也會讀取tsconfig.json並尋找tsconfig.json 路徑映射配置。 如果您不知道它是什么......它只是一種配置,您可以在其中聲明(再一次)您的 deps。 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配置(目前處於實驗階段但效果很好,反饋線程在這里

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)、匆忙或任何東西......

Nextjs 將簡單地導入文件,按需構建它們,甚至將它們緩存在它自己優化的緩存中(尤其是在 webpack 5 中速度更快,也可以在 CI 上啟用)...

如果您想了解更多信息,我會在此存儲庫上維護一個示例存儲庫,該存儲庫將提供完整的生命周期透視圖(ci、github 操作、linters、部署...): https : //github.com/belgattitude/nextjs-monorepo-example

PS:在這里也關注 yarn 3+ 的開發和版本,他們現在做得很好。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM