VSCode 应该如何配置以支持 Lerna Monorepo?

How Should VSCode Be Configured To Support A Lerna Monorepo?

我有一个 lerna 包含很多包的 monorepo。

我正在努力实现以下目标:

  1. 确保 VSCode 提供从一个包到另一个包的正确导入建议(基于包名称,而不是相对路径)。
  2. 确保我可以 'Open Definition' 这些导入之一并被带到该文件的 src。

对于 1. 我的意思是,如果我在 package-a 中导航代码并开始键入 package-b 导出的函数,我会得到一个建议,该建议将触发添加导入:`import { example } 来自 'package-b'.

对于 2。我的意思是,如果我 alt/click 在 'package-b' 导出的函数的名称上,同时从导入它的不同包中导航文件,我将被带到 '/packages/namespace/package/b/src/file-that-contains-function.js',

我的 (lerna) monorepo 结构是标准的,例如这里有一个 'components' 包,发布为 @namespace/components.

- packages
    - components
       - package.json
       - node_modules
       - src
         - index.js
         - components
           - Button
             - index.js
             - Button.js
       - es
         - index.js
         - components
           - Button
             - index.js
             - Button.js

请注意,每个组件都由一个目录表示,以便它可以在必要时包含其他组件。在此示例中,packages/components/indexButton 导出为命名导出。文件被转译到包的 /es/ 目录。

默认情况下,VSCode 为导入提供自动建议,但它被这种结构混淆了,例如,如果 monorepo 中的不同包需要使用 Button,则会自动建议所有以下导入路径:

然而,其中 none 是合适的,因为它们将呈现为从导入文件到导入文件的相对路径。在这种情况下,以下导入是正确的导入:

import { Button } from '@namespace/components'

向项目的 jsconfig.json 添加排除项对建议路径没有影响,甚至不会删除 /es/*:

中的建议
{
  "compilerOptions": {
    "target": "es6",
  },
  "exclude": [
    "**/dist/*",
    "**/coverage/*",
    "**/lib/*",
    "**/public/*",
    "**/es/*"
  ]
}

使用 "compilerOptions" 显式添加路径也无法在文件之间建立正确的关系:

{
  "compilerOptions": {
    "target": "es6",
    "baseUrl": ".",
    "paths": {
      "@namespace/components/*": [
        "./packages/namespace-components/src/*.js"
      ]
    }
  },
}

目前 Cmd/Clicking 从不同的包导入时无法打开任何内容(未找到定义)。

我应该如何配置 VSCode 以便:

  1. VSCode 使用命名空间包作为导入值自动建议从 monorepo 中的其他包导入。
  2. 使用 'Open Definition' 将我带到该文件的 src。

根据要求,我在根目录中有一个 babel 配置:

const { extendBabelConfig } = require(`./packages/example/src`)

const config = extendBabelConfig({
  // Allow local .babelrc.js files to be loaded first as overrides
  babelrcRoots: [`packages/*`],
})

module.exports = config

延伸:

const presets = [
  [
    `@babel/preset-env`,
    {
      loose: true,
      modules: false,
      useBuiltIns: `entry`,
      shippedProposals: true,
      targets: {
        browsers: [`>0.25%`, `not dead`],
      },
    },
  ],
  [
    `@babel/preset-react`,
    {
      useBuiltIns: true,
      modules: false,
      pragma: `React.createElement`,
    },
  ],
]

const plugins = [
  `@babel/plugin-transform-object-assign`,
  [
    `babel-plugin-styled-components`,
    {
      displayName: true,
    },
  ],
  [
    `@babel/plugin-proposal-class-properties`,
    {
      loose: true,
    },
  ],
  `@babel/plugin-syntax-dynamic-import`,
  [
    `@babel/plugin-transform-runtime`,
    {
      helpers: true,
      regenerator: true,
    },
  ],
]

// By default we build without transpiling modules so that Webpack can perform
// tree shaking. However Jest cannot handle ES6 imports becuase it runs on
// babel, so we need to transpile imports when running with jest.
if (process.env.UNDER_TEST === `1`) {
  // eslint-disable-next-line no-console
  console.log(`Running under test, so transpiling imports`)
  plugins.push(`@babel/plugin-transform-modules-commonjs`)
}

const config = {
  presets,
  plugins,
}

module.exports = config

在你的情况下,我会使用 lerna in combination with yarn workspaces。 当 运行 yarn install 时,您的所有包都链接到全局 node_modules 文件夹中的 @namespace 下。这样,您就可以获得 IntelliSense。

我在这里设置了一个示例存储库:https://github.com/flolude/Whosebug-lerna-monorepo-vscode-intellisense

您只需将 "useWorkspaces": "true" 添加到您的 lerna.json

lerna.json

{
  "packages": ["packages/*"],
  "version": "0.0.0",
  "useWorkspaces": "true"
}

剩下的只是恰当的命名:

global package.json

{
  "name": "namespace",
  // ...
}
package.json of your component package

{
  "name": "@namespace/components",
  "main": "src/index.js",
  // ...
}
package.json of the package that imports the components

{
  "name": "@namespace/components",
  "main": "src/index.js",
  "dependencies": {
     "@namespace/components":"0.0.0"
  }
  // ...
}

然后您可以进行以下操作:

import { Component1 } from '@namespace/components';

// your logic

自动从 @namespace

导入

不幸的是,我找不到使用 Javascript Monorepo 在 VSCode 中完成这项工作的方法。但是您可以做一些事情:

  1. 使用打字稿(tutorial, other tutorial
  2. 使用module-alias
  3. import {} from '@namespace/components' 添加到文件顶部
  4. 使用 Auto Import 扩展

编辑:VSCode 的最新版本已损坏。

我终于设法让它可靠地工作了。您需要为 monorepo 中的每个包创建一个单独的 jsconfig.js,例如:

  • {monorepo root}/packages/some-package/jsconfig.json:
{
  "compilerOptions": {
    "target": "es6",
    "jsx": "preserve",
    "module": "commonjs"
  },
  "include": ["src/**/*.js"],
  "exclude": ["src/index.js"]
}

请注意,我已经排除了 src/index.js 文件,因此它不会作为导入建议从该包中提供。

此设置似乎实现了:

  • Intellisense 从包而不是使用相对路径导入建议。
  • 转到 monorepo 中其他包源的定义。

VSCode 最近有点不稳定,但它似乎在起作用。

请注意,这适用于 JavaScript-only monorepo(不是 Typescript)。