├── .gitignore ├── .editorconfig ├── .github ├── workflows │ ├── release.yml │ ├── test.yml │ └── sync-default-branch.yml └── dependabot.yml ├── bin └── npm-cli.js ├── package.json ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /package*/ 3 | /tmp 4 | 5 | /nodenv-jetbrains-npm-*.tgz 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # https://EditorConfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | insert_final_newline = true 8 | indent_size = 2 9 | indent_style = space 10 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | push: { tags: "v[0-9]+.[0-9]+.[0-9]+*" } 4 | 5 | permissions: {} 6 | jobs: 7 | release: 8 | permissions: { contents: write, id-token: write } 9 | uses: nodenv/.github/.github/workflows/release.yml@v7 10 | secrets: 11 | BOT_TOKEN: ${{ secrets.BOT_TOKEN }} 12 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | on: 3 | push: 4 | pull_request: 5 | schedule: [{ cron: "0 0 10 * *" }] # monthly https://crontab.guru/#0_0_10_*_* 6 | workflow_dispatch: 7 | 8 | permissions: {} 9 | jobs: 10 | test: 11 | uses: nodenv/.github/.github/workflows/test.yml@v6 12 | with: { npm: false } 13 | permissions: 14 | contents: read 15 | packages: read 16 | id-token: write 17 | security-events: write 18 | statuses: write 19 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Please see the documentation for all configuration options: 2 | # https://docs.github.com/en/code-security/dependabot/working-with-dependabot/dependabot-options-reference 3 | 4 | version: 2 5 | updates: 6 | - package-ecosystem: npm 7 | directory: "/" 8 | schedule: { interval: weekly } 9 | cooldown: { default-days: 15 } 10 | 11 | - package-ecosystem: github-actions 12 | directory: "/" 13 | schedule: { interval: weekly } 14 | cooldown: { default-days: 15 } 15 | -------------------------------------------------------------------------------- /.github/workflows/sync-default-branch.yml: -------------------------------------------------------------------------------- 1 | name: Sync Default Branch 2 | on: 3 | push: { branches: main } 4 | workflow_dispatch: 5 | permissions: {} 6 | 7 | jobs: 8 | sync: 9 | permissions: { contents: write } 10 | uses: nodenv/.github/.github/workflows/sync-default-branch.yml@v6 11 | # One-time commands for users to switch-over: 12 | # 13 | # ```console 14 | # git branch -m master main 15 | # git fetch origin 16 | # git branch -u origin/main main 17 | # git remote set-head origin -a 18 | # ``` 19 | -------------------------------------------------------------------------------- /bin/npm-cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var child_process = require("child_process"); 4 | var fs = require("fs"); 5 | var path = require("path"); 6 | 7 | child_process.exec("nodenv root", function (err, stdout) { 8 | var npm; 9 | 10 | // get shim path from `nodenv root` (respects $NODENV_ROOT) 11 | if (!err && stdout) { 12 | npm = npmShim(stdout.replace(/\n/g, "")); 13 | } 14 | 15 | // infer shim path if installed as nodenv plugin 16 | if (!npm && path.basename(path.resolve(__dirname + "/../..")) === "plugins") { 17 | npm = npmShim(path.resolve(__dirname + "/../../..")); 18 | } 19 | 20 | // fallback to npm from PATH if not found thus far 21 | child_process 22 | .spawn(npm || "npm", process.argv.slice(2), { stdio: "inherit" }) 23 | .on("close", process.exit); 24 | }); 25 | 26 | function npmShim(nodenvRoot) { 27 | var npmShim = nodenvRoot + "/shims/npm"; 28 | if (fs.existsSync(npmShim)) return npmShim; 29 | } 30 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nodenv/jetbrains-npm", 3 | "version": "1.0.3", 4 | "description": "Fix IntelliJ/WebStorm's npm integration under nodenv.", 5 | "homepage": "https://github.com/nodenv/jetbrains-npm", 6 | "license": "MIT", 7 | "author": "Jason Karns (http://jason.karns.name/)", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/nodenv/jetbrains-npm.git" 11 | }, 12 | "bugs": { 13 | "url": "https://github.com/nodenv/jetbrains-npm/issues" 14 | }, 15 | "publishConfig": { 16 | "access": "public" 17 | }, 18 | "files": [ 19 | "bin" 20 | ], 21 | "scripts": { 22 | "start": "bin/npm-cli.js", 23 | "test": "bats ${CI:+--tap} test", 24 | "posttest": "npm run lint", 25 | "lint": "prettier --check .", 26 | "postversion": "git push --follow-tags" 27 | }, 28 | "devDependencies": { 29 | "prettier": "3" 30 | }, 31 | "keywords": [ 32 | "nodenv", 33 | "jetbrains", 34 | "npm" 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Sergey Simonchik, Jason Karns 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jetbrains-npm proxy 2 | 3 | Fix IntelliJ/WebStorm's npm integration under nodenv. 4 | 5 | [![Tests](https://img.shields.io/github/actions/workflow/status/nodenv/jetbrains-npm/test.yml?label=tests&logo=github)](https://github.com/nodenv/jetbrains-npm/actions/workflows/test.yml) 6 | [![Latest GitHub Release](https://img.shields.io/github/v/release/nodenv/jetbrains-npm?label=github&logo=github&sort=semver)](https://github.com/nodenv/jetbrains-npm/releases/latest) 7 | [![Latest Homebrew Release]()](https://github.com/nodenv/homebrew-nodenv/blob/main/Formula/jetbrains-npm.rb) 8 | [![Latest npm Release](https://img.shields.io/npm/v/@nodenv/jetbrains-npm?logo=npm&logoColor=white)](https://www.npmjs.com/package/@nodenv/jetbrains-npm/v/latest) 9 | 10 | 11 | 12 | - [Pre-requisites](#pre-requisites) 13 | - [Installation](#installation) 14 | - [nodenv plugin](#nodenv-plugin) 15 | - [JetBrains-aware Git clone](#jetbrains-aware-git-clone) 16 | - [standalone clone](#standalone-clone) 17 | - [Homebrew](#homebrew) 18 | - [global npm or Yarn package](#global-npm-or-yarn-package) 19 | - [Configuration](#configuration) 20 | - [Package Manager](#package-manager) 21 | - [Nodenv Root](#nodenv-root) 22 | - [Why is this necessary?](#why-is-this-necessary) 23 | - [How it works](#how-it-works) 24 | 25 | 26 | 27 | ## Pre-requisites 28 | 29 | This proxy assumes you have already selected nodenv's shim as your node runtime within your IDE's preferences: 30 | 31 | ![image](https://user-images.githubusercontent.com/119972/50924357-5984e700-141d-11e9-90bc-8d63dcb26287.png) 32 | 33 | ## Installation 34 | 35 | ### nodenv plugin 36 | 37 | **(recommended if you have a custom nodenv root)** 38 | 39 | This installation method allows the proxy to find nodenv root automatically; 40 | the trade-off being that IntelliJ/WebStorm must be explicitly configured with the proxy's location. 41 | 42 | ```sh 43 | git clone https://github.com/nodenv/jetbrains-npm "$(nodenv root)"/plugins/jetbrains-npm 44 | ``` 45 | 46 | After installation, set the [Package Manager path](#package-manager) to the output of: 47 | 48 | ```sh 49 | echo "$(nodenv root)"/plugins/jetbrains-npm 50 | ``` 51 | 52 | ### JetBrains-aware Git clone 53 | 54 | **(recommended if your nodenv root is the default ~/.nodenv)** 55 | 56 | This installation method enables JetBrains to find the npm proxy automatically, as it is relative to the node executable: `../lib/node_modules/npm/bin/npm-cli.js`; (relative to `shims/node`) 57 | the trade-off requires ensuring the proxy can find your nodenv-root. 58 | 59 | ```sh 60 | mkdir -p "$(nodenv root)/lib/node_modules" 61 | git clone https://github.com/nodenv/jetbrains-npm "$(nodenv root)"/lib/node_modules/npm 62 | ``` 63 | 64 | After installation, the IDE should automatically find the proxy and include it in the list of available [package managers](#package-manager); just select it! (In fact, if the package manager field is empty before cloning, then a restart of WebStorm should select it automatically.) 65 | 66 | ### standalone clone 67 | 68 | You may also choose to clone the proxy to any location on disk that you like. 69 | 70 | ```sh 71 | # in whatever directory you like: 72 | git clone https://github.com/nodenv/jetbrains-npm 73 | ``` 74 | 75 | After installation: 76 | 77 | 1. set your [Package Manager path](#package-manager) as the path to your clone 78 | 2. ensure [`NODENV_ROOT`](#nodenv-root) is set in your IDE environment 79 | 80 | ### Homebrew 81 | 82 | ```sh 83 | brew tap nodenv/nodenv 84 | brew install jetbrains-npm 85 | ``` 86 | 87 | After installation, set the [Package Manager path](#package-manager) to the output of: 88 | 89 | ```sh 90 | brew --prefix jetbrains-npm 91 | ``` 92 | 93 | And finally, ensure [`NODENV_ROOT`](#nodenv-root) is set in your IDE environment. 94 | 95 | ### global npm or Yarn package 96 | 97 | ```sh 98 | npm -g install @nodenv/jetbrains-npm 99 | ``` 100 | 101 | or 102 | 103 | ```sh 104 | yarn global add @nodenv/jetbrains-npm 105 | ``` 106 | 107 | After installation, set the [Package Manager path](#package-manager) to the output of: 108 | 109 | ```sh 110 | echo $(npm -g prefix)/lib/node_modules/@nodenv/jetbrains-npm 111 | ``` 112 | 113 | or 114 | 115 | ```sh 116 | echo $(yarn global dir)/node_modules/@nodenv/jetbrains-npm 117 | ``` 118 | 119 | And finally, ensure [`NODENV_ROOT`](#nodenv-root) is set in your IDE environment. 120 | 121 | _**NOTE:**_ 122 | Be aware which node is active when you install this package. 123 | Remember that global npm installs are still contained within the node version itself. (`$(nodenv prefix)/lib/node_modules/`) 124 | This means the package will be removed if you `nodenv uninstall` the particular node version. 125 | Therefore, it's recommended to install this package globally using a _system_ node, such that this package will live outside nodenv versions. 126 | Yarn, in contrast, defaults to installing global packages to a single shared global directory; outside the node version. 127 | 128 | ## Configuration 129 | 130 | ### Package Manager 131 | 132 | Regardless of your installation method, you will need to explicitly configure your package manager within IntelliJ/WebStorm. 133 | It may be detected by the IDE automatically, in which case you merely need to select it. 134 | Or you may need to paste in the full path manually. 135 | 136 | The package manager setting is found under: `Languages & Frameworks -> Node.js and NPM -> Package manager`. 137 | It should be set to the path where this proxy was installed. (ie, the directory that _contains_ this proxy's package.json file) 138 | 139 | ![50924463-9f41af80-141d-11e9-8322-0456278c9bfd](https://user-images.githubusercontent.com/119972/50924683-47577880-141e-11e9-9438-e01bac8ad118.png) 140 | 141 | ### Nodenv Root 142 | 143 | If you use the default path of `~/.nodenv` as your nodenv root, you're all set; 144 | the proxy should be able to derive your nodenv root location automatically. 145 | 146 | If you use a custom location for nodenv root, you must ensure `NODENV_ROOT` is set accordingly and exported in IntelliJ/WebStorm's environment in one of the following ways: 147 | 148 | - set and export it in `~/.profile` or `~/.bash_profile` 149 | - or source `~/.bashrc` from `~/.profile` or `~/.bash_profile` 150 | - or always launch IntelliJ/WebStorm from a terminal 151 | - or modify the IDE desktop launcher to launch Bash interactively 152 | 153 | (see [JetBrains issue](https://youtrack.jetbrains.com/issue/IDEABKL-7589) for 154 | more details about JetBrains and environment variables) 155 | 156 | ## Why is this necessary? 157 | 158 | IntelliJ/WebStorm, for its own reasons, does not directly execute the npm or Yarn executable found in `PATH`. 159 | Instead, it attempts to find the npm/Yarn _package directory_, and invoke node with the `bin/npm-cli.js` or `bin/yarn.js` script. 160 | ([resolution logic](https://github.com/nodenv/nodenv/pull/129#discussion_r246391978)) 161 | Of course, nodenv only resolves the true location of the node (or npm/Yarn) executable at invocation time. 162 | This means JetBrains will never find the npm-cli.js or yarn.js scripts, since they do not exist relative to nodenv's node shim. (nor can they be found relative to nodenv's npm/Yarn shims) 163 | 164 | ## How it works 165 | 166 | This proxy conforms to the directory structure that JetBrains is hardcoded to find: the npm shim is at `bin/npm-cli.js`. 167 | Thus, IntelliJ/WebStorm can be configured to treat this proxy as the "package manager". 168 | The various installation options either support JetBrains' own lookup mechanisms such that JetBrains can find the proxy automatically, or allow the proxy to find nodenv-root automatically. 169 | 170 | When the proxy is invoked, it derives the nodenv-root (either by the proxy's own file location, or by the `nodenv root` command which relies on `NODENV_ROOT` and defaults to `~/.nodenv`). 171 | Then it proxies the invocation to nodenv's shim (found at `$(nodenv root)/shims/npm`); wherein nodenv can ensure the correct version of node+npm is activated according to `.node-version`, etc. 172 | --------------------------------------------------------------------------------