title: How Should VSCode Be Configured To Support A Lerna Monorepo?
body: <p>I have a <a href="https://github.com/lerna/lerna" rel="noreferrer">lerna</a> monorepo containing lots of packages.</p>
  
  <p>I'm trying to achieve the following:</p>
  
  <ol>
  <li>Ensure that VSCode provides the correct import suggestions (based on package names, not on relative paths) from one package to another.</li>
  <li>Ensure that I can 'Open Definition' of one of these imports and be taken to the src of that file.</li>
  </ol>
  
  <p>For 1. I mean that if I am navigating code within package-a and I start to type a function exported by package-b, I get a suggestion that will trigger the adding of an import: `import { example } from 'package-b'.</p>
  
  <p>For 2. I mean that if I alt/click on the name of a function exported by 'package-b' while navigating the file from a different package that has imported it, I am taken to '/packages/namespace/package/b/src/file-that-contains-function.js',</p>
  
  <p>My (lerna) monorepo is structured as standard, for example here is a 'components' package that is published as <code>@namespace/components</code>.</p>
  
  <pre><code>- packages
      - components
         - package.json
         - node_modules
         - src
           - index.js
           - components
             - Button
               - index.js
               - Button.js
         - es
           - index.js
           - components
             - Button
               - index.js
               - Button.js
  </code></pre>
  
  <p>Note that each component is represented by a directory so that it can contain other components if necessary. In this example, <code>packages/components/index</code> exports <code>Button</code> as a named export. Files are transpiled to the package's <code>/es/</code> directory.</p>
  
  <p>By default, VSCode provides autosuggestions for imports, but it is confused by this structure and, for if a different package in the monorepo needs to use <code>Button</code> for example, will autosuggest all of the following import paths:</p>
  
  <ul>
  <li><code>packages/components/src/index.js</code></li>
  <li><code>packages/components/src/Button/index.js</code></li>
  <li><code>packages/components/src/Button/Button.js</code></li>
  <li><code>packages/components/es/index.js</code></li>
  <li><code>packages/components/es/Button/index.js</code></li>
  <li><code>packages/components/es/Button/Button.js</code></li>
  </ul>
  
  <p>However none of these are the appropriate, because they will be rendered as relative paths from the importing file to the imported file. In this case, the following import is the correct import:</p>
  
  <pre><code>import { Button } from '@namespace/components'
  </code></pre>
  
  <p>Adding excludes to the project's <code>jsconfig.json</code> has no effect on the suggested paths, and doesn't even remove the suggestions at <code>/es/*</code>:</p>
  
  <pre><code>{
    "compilerOptions": {
      "target": "es6",
    },
    "exclude": [
      "**/dist/*",
      "**/coverage/*",
      "**/lib/*",
      "**/public/*",
      "**/es/*"
    ]
  }
  </code></pre>
  
  <p>Explicitly adding paths using the "compilerOptions" also fails to set up the correct relationship between the files:</p>
  
  <pre><code>{
    "compilerOptions": {
      "target": "es6",
      "baseUrl": ".",
      "paths": {
        "@namespace/components/*": [
          "./packages/namespace-components/src/*.js"
        ]
      }
    },
  }
  </code></pre>
  
  <p>At present Cmd/Clicking on an import from a different package fails to open anything (no definition is found).</p>
  
  <p><strong>How should I configure VSCode so that:</strong></p>
  
  <ol>
  <li><strong>VSCode autosuggests imports from other packages in the monorepo using the namespaced package as the import value.</strong></li>
  <li><strong>Using 'Open Definition' takes me to the src of that file.</strong></li>
  </ol>
  
  <p>As requested, I have a single babel config in the root:</p>
  
  <pre><code>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
  </code></pre>
  
  <p>Which extends:</p>
  
  <pre><code>const presets = [
    [
      `@babel/preset-env`,
      {
        loose: true,
        modules: false,
        useBuiltIns: `entry`,
        shippedProposals: true,
        targets: {
          browsers: [`&gt;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
  </code></pre>