添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
  • my-library : npm包,需要在其它项目中作为依赖进行测试
  • 需要注意的是这里 my-library/package.json 中的 name 属性也是应该 my-library

  • my-application : package/my-application 需要进行测试的项目
  • 下面演示如何将 my-application 中的 my-library 链接到本地

    my-application 中执行 npm link my-library 安装到全局。这样才能让其它本地项目有办法链接到这个包。 npm link 的行为其实等同于 npm install --global

    $ cd ./my-library
    $ npm link
    

    my-application中执行npm link my-library去链接这个包

    $ cd ./my-application
    $ npm link my-library
    

    npm link <package-path>

    也可以直接执行npm link <package-path> 命令实现上述两步

    例子如下:

    $ cd ./my-application
    $ npm link ../my-library
    

    使用npm link <package-path>更加方便和不易出错,因为它是需要显式指定链接的包的路径

    4个使用npm link的缺点

  • 多个Node.js版本同时使用容易出错
  • 如果开发环境中使用类似nvm的版本管理工具安装多个Node.js版本的话,需要确保npm link的执行是在同一个node版本

    像上文所说,第一步执行npm link其实是将包安装全局。但是因为多个版本的Node.js的全局安装路径是互相独立的。如果在不同版本中使用,包查找会失败

    可以使用以下命令查看全局包的安装路径。如果Node.js的版本出现在打印的路径中,则全局包安装路径在不同Node.js版本下是独立的

    $ npm root -g
    ~/.nvm/versions/node/v14.16.1/lib/node_modules
    

    在不同的终端中处理多个包的时候很容易忽略不同终端下的Node.js版本是否一致。并且这个版本差异也很难发现,因为npm link在无法找到要链接的本地包时也不会报错

  • link失败不会报错并且会回退到直接从npm仓库进行安装
  • 如果尝试在一个包中执行npm link a ,就算这个包之前并没有注册为全局链接,这个命令执行也不会报错

    $ npm link a
    ~/my-package/node_modules/a -> ~/.nvm/versions/node/v14.16.1/lib/node_modules/a
    

    这是因为npm link的时候没有找到全局的包a,它就会从npm仓库上去全局安装这个包并创建一个软链接到这个包

    只有这个包在npm远端仓库上没有这个包,npm link这个包才会失败

    $ npm link non-existent-package
    npm ERR! code E404
    npm ERR! 404 Not Found - GET https://registry.npmjs.org/non-existent-package - Not found
    npm ERR! 404 
    npm ERR! 404  'non-existent-package@*' is not in this registry.
    npm ERR! 404 You should bug the author to publish it (or use the name yourself!)
    npm ERR! 404 
    npm ERR! 404 Note that you can also install from a
    npm ERR! 404 tarball, folder, http url, or git url.
    

    要判断链接是否真正成功,可以检查输出是否有打印两个->,注意上面的错误链接只有一个->。两个->说明创建了一个指向全局包软链接,然后链接向本地包

    # npm v6
    $ npm link my-linked-package
    ~/my-package/node_modules/my-linked-package -> ~/.nvm/versions/node/v14.16.1/lib/node_modules/my-linked-package -> ~/my-linked-package
    

    这种检查方法只能在npm v6版本中使用。从npm v7开始,链接路径不再被输出到终端了。从下面可以发现v7开始已经不可能确定是链接本地包成功还是、安装和链接了一个包

    # npm v7
    $ npm link a
    up to date, audited 3 packages in 671ms
    found 0 vulnerabilities
    

    也可以使用realpath命令验证一个包是否链接成功

    $ realpath node_modules/package-name
    ~/my-linked-package
    

    综上,由于缺少适当的报错,使用npm link带给我们不是很好的体验。特别是在多个 Node.js 版本的情况下

  • 会有预期之外的二进制可执行文件安装
  • npm link的第一步是将包安装到全局。这个命令是由两步实现

    npm install --global ...可用于使二进制文件作为系统范围的cli命令使用。如果包有bin 字段,通过npm link可以另这个bin中的命令可以直接通过终端执行命令

    考虑到npm link通常只是用来在开发中进行包的测试,全局二进制文件的安装可能会有额外的副作用。由于包可以声明具有任意名称的二进制执行文件,这种意外的副作用的影响可能非常严重

    下面的例子,在package.json中指定了binrandom-command

    "name": "my-package", "bin": { "random-command": "bin.js"

    执行npm link就也会全局安装可执行的random-command

    $ random-command
    zsh: command not found: random-command
    $ cd my-package && npm link
    added 1 package, and audited 3 packages in 548ms
    found 0 vulnerabilities
    $ random-command
    Suddenly works!
    

    全局安装也会覆盖已经存在的的全局可执行命令(取决于PATH配置--终端查找命令的环境变量)。如果使用nvm则可能会受到影响

    下面的例子,覆盖了标准的Unix命令cat

    $ type cat
    cat is /bin/cat
    $ cd my-package && npm link
    added 1 package, and audited 3 packages in 230ms
    found 0 vulnerabilities
    $ hash cash
    $ type cat
    cat is ~/.nvm/versions/node/v16.14.0/bin/cat
    

    在包安装方面,这些风险对于包管理很普遍,从安全角度来看,这些风险并不算太高

    npm link本身不是一个包安装工具。它是一个开发时进行软链接的工具。通过上文,我们了解到这种行为是会导致不少预期外的行为以及可能导致的一些错误

    顺便提下上面提到的运行npm link a,则二进制执行命令a已安装到系统中。可能会认为 npm unlink a可以卸载,但它只会删除本地的软链接,而不会删除全局安装的二进制文件

    卸载全局包和它的二进制执行文件需要使用:

    $ npm uninstall --global a
    
  • 不符合预期的软链接删除
  • 链接多个包时,将删除先前链接的包。这个行为是npm v7中引入的

    以下例子pkg-a已经被链接过并且存在于node_modules中了。但当链接了第二个包pkg-b后,pkg-a就不在node_modules中了

    $ npm link ../pkg-a
    added 1 package, and audited 5 packages in 684ms
    found 0 vulnerabilities
    $ ls node_modules 
    pkg-a
    $ npm link ../pkg-b
    added 1 package, removed 1 package, and audited 5 packages in 703ms
    found 0 vulnerabilities
    $ ls node_modules  
    pkg-b
    

    使用多个包进行链接时,npn link删除之前的链接包通常是不符合预期的。一般在链接第二个包之后,我们会继续运行代码并认为之前的软链接是应该不变的

    如果要链接多个包就必须将所有包路径一次传递给npm link

    $ npm link ../pkg-a ../pkg-b
    added 1 package, and audited 6 packages in 645ms
    found 0 vulnerabilities
    $ ls node_modules 
    pkg-a pkg-b
    

    虽然可行但这并不是一个很好的开发体验。在开发中,我们并不总是提前知道所有需要链接的包或以前链接过的包

    这种令人困惑的行为说明了npm link的可用性很差

    As with any popular package registry, npm has a diverse collection with no standard for quality.

    作为一个流行的包管理工具,npm有一个各种各样的包但却没有统一的质量标准

    这里列举了一些恶意包,但这里提到的风险不仅限于攻击。当不清楚是否安装了正确的软件包时是有可能发生意外的

    npm上的许多包是用来更改文件的,例如rimraf或代码linter工具。运行文件中被更改的代码可能是有可能有问题的

    npm install也有可能安装错误的包,但是了解到上面提到的npm link会有一些预料之外的行为时,npm link带来的风险会更高。如下:

    包名称可能会发生冲突。可能使用了一个npm仓库上已有的包名字去链接本地的包。在意识到名称已被占用之前,开发和测试新的或私有包可能会遇到

    本地链接失败不会报错。如果被链接的包无法在本地找到,将从npm仓库下中查找。如果找到相同名称的包,则可能会意外地安装到全局

    二进制可执行文件被安装。如果安装了错误的包,很难发现二进制执行文件也会被全局安装并且很难意识到需要全局卸载这个二进制执行文件。这就会留下这个不符合预期的可执行文件被可能被意外执行

    使用npm install作为替代

    npm link的一种替代方法是使用指定包路径的npm install

    $ npm install --no-save <package-path-a> <package-path-b> ...
    

    执行这个命令会创建一个指向包的软链接而不是全局安装。这种行为就和我们使用npm link进行测试包的初衷差不多了。 加上--no-save是为了防止包的路径保存在package.json

    但是npm install也是有缺点的。和npm link一样,执行npm install多次是会先移除之前的软链接。如果我们想一次链接多个包的话,必须一次将需要链接的多个包作为参数传入

    $ npm install --no-save <package-path-a> <package-path-b> ...
    

    npx link

    npx link,一个小工具用来替代npm link,并且能解决上面提到的npm link的缺点

    使用起来也很简单

    $ npx link <package-path>
    

    [npm link](https://github.com/privatenumber/link)不会全局安装链接的包或二进制执行文件,并且也不会删除以前的软链接,可以在不同版本的Node.js中使用。当不能解析包路径时,也会有一个执行失败报错

    如果需要执行链接包的二进制文件,执行通过npx命令或者通过package scripts

  • 三面面试官:运行 npm run xxx 的时候发生了什么?
  • 2018 年了,你还是只会 npm install 吗?
  • 字节的一个小问题 npm 和 yarn不一样吗?
  •