I have a lerna monorepo containing lots of packages.
I'm trying to achieve the following:
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'.
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',
My (lerna) monorepo is structured as standard, for example here is a 'components' package that is published as @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
Note that each component is represented by a directory so that it can contain other components if necessary. In this example, packages/components/index
exports Button
as a named export. Files are transpiled to the package's /es/
directory.
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 Button
for example, will autosuggest all of the following import paths:
packages/components/src/index.js
packages/components/src/Button/index.js
packages/components/src/Button/Button.js
packages/components/es/index.js
packages/components/es/Button/index.js
packages/components/es/Button/Button.js
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:
import { Button } from '@namespace/components'
Adding excludes to the project's jsconfig.json
has no effect on the suggested paths, and doesn't even remove the suggestions at /es/*
:
{
"compilerOptions": {
"target": "es6",
},
"exclude": [
"**/dist/*",
"**/coverage/*",
"**/lib/*",
"**/public/*",
"**/es/*"
]
}
Explicitly adding paths using the "compilerOptions" also fails to set up the correct relationship between the files:
{
"compilerOptions": {
"target": "es6",
"baseUrl": ".",
"paths": {
"@namespace/components/*": [
"./packages/namespace-components/src/*.js"
]
}
},
}
At present Cmd/Clicking on an import from a different package fails to open anything (no definition is found).
How should I configure VSCode so that:
As requested, I have a single babel config in the root:
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
Which extends:
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
Introduction. Lerna is a tool for managing JavaScript projects with multiple packages. Lerna manages monorepos, which can hold projects containing multiple packages within itself. Monorepos can be challenging to manage because sequential builds and publishing individual packages take a long time.
To start to use lerna you need install the package in mode global or use npx, when you decide what you need to do. Before to continue I suggest you create a branch and call it lerna-init, it will be used in the future. After that we need to init our lerna project, lerna has two modes: fixed/locked and independent.
Why Should Developers Use Lerna? Lerna makes things easier for developers by managing tasks like versioning, deployment of code, dependency management between projects, and much more. It is mostly used in bigger projects, where it becomes hard to maintain all these tasks manually over time.
In your case, I would make use of lerna in combination with yarn workspaces.
When running yarn install
, all your packages are linked under your @namespace
in a global node_modules
folder. With that, you get IntelliSense.
I've set up an example repository here: https://github.com/flolude/stackoverflow-lerna-monorepo-vscode-intellisense
You just need to add "useWorkspaces": "true"
to your lerna.json
lerna.json
{
"packages": ["packages/*"],
"version": "0.0.0",
"useWorkspaces": "true"
}
And the rest is just propper naming:
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"
}
// ...
}
Then you can do the following:
import { Component1 } from '@namespace/components';
// your logic
@namespace
Unfortunately, I couldn't find a way to make this work in VSCode with a Javascript Monorepo. But there are some things you can do:
import {} from '@namespace/components'
to the top of your file
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With