读懂package.json -- 依赖管理

作者: CodeLoam | 来源:发表于2017-06-26 09:55 被阅读0次

    npm做为Javascript项目的包管理工具,由于其与Node.js的紧密配合(npm和Node.js出自一人之手),目前已经基本没有竞争对手。

    包管理工具要解决的主要问题就是依赖包的安装,在Javascript项目中,包的依赖关系是由package.json给出的,这篇文件将介绍package.json中描述的依赖信息。

    依赖管理

    在package.json中,有如下几项涉及到依赖包的描述:

    • dependencies
      项目中使用到的包,但不包括测试所使用的包

    • devDependencies

      主要是在测试时使用的包,也包括一些代码编译的包,比如将coffee-script编译为javascript。也就是说在仅仅使用该项目的时候(而不进行测试等环节),不需要安装的包可以放在devDependencies中

    • peerDependencies

      如果改项目需要指明一些有协作关系的包的版本时,使用peerDependencies。这里使用了协作,而不是依赖,是我个人的理解。peerDependencies并不是必须安装的包,但如果一旦要安装,就要符合要求。比如react-dom的package.json中有如下的描述:

      "peerDependencies": {
          "react": "^15.6.1"
       },
      

      peerDependencies至少打消了一些顾虑,比如react生态中用到的一些包在升级的时候会不会不匹配?

    • optionalDependencies

      如果有一些依赖包即使安装失败,项目仍然能够运行或者希望npm继续运行,就可以使用optionalDependencies。另外optionalDependencies会覆盖dependencies中的同名依赖包,所以不要在两个地方都写。

    • bundledDependencies/bundleDependencies

      如果在打包发布的使用希望一些依赖包也出现在最终的包里,那么可以将包的名字放在bundledDependencies,bundledDependencies的值是一个字符串数组,如:

      "name": "awesome-web-framework",
      "version": "1.0.0",
      "bundledDependencies": [
          'renderized', 'super-streams'
       ]
      

      npm pack会将renderizedsuper-streams放入生成的包awesome-web-framework-1.0.0.tgz中,并且在npm install awesome-web-framework-1.0.0.tgz时,renderizedsuper-streams也会被一同安装。

    这些项的内容形式都是一样的(除了bundledDependencies),只是作用不同,如:

      "dependencies": {
        "base62": "~0.1.1",
        "commoner": "~0.7.0",
        "esprima": "https://github.com/facebook/esprima/tarball/ca28795124d45968e62a7b4b336d23a053ac3a84",
        "recast": "~0.4.8",
        "source-map": "~0.1.22"
      }
    

    key就是项目的名词,而value可以有多种形式

    • version,遵循semver
    • 一个tarball的url
    • 一个git url
    • 本地路径

    关于semver会在另一篇文章中介绍(先挖个坑)。

    依赖树

    不同于很多语言的依赖管理,npm使用的是依赖树。也就是说每个依赖包会有一套自己指定的(在package.json中说明的)依赖包,而不会和其他包共享。
    例如,mod-a依赖mod-b@1.0.0,mod-c依赖mod-b@2.0.0,而现在有一个项目依赖mod-a和mod-c,那么最终安装的依赖包如下:

    ├─┬ node_modules
    │ ├─┬ mod-a
    │ │ ├── mod-b@1.0.0
    │ ├─┬ mod-c
    │ │ ├── mod-b@2.0.0
    

    而Node.js在加载依赖包的时候会处理这个问题。之所以文章最开始说npm和Node.js的紧密合作也是这个原因。

    使用依赖树来管理包带来了一个明显的好处,不用处理依赖冲突的问题。这个问题在早期的Java项目中比较常见,而在使用了Maven和Gradle之后,情况有所缓解,但只能减轻同一个包多个版本被放入发布的包中这种情况,仍然无法解决依赖冲突这个根本问题。

    依赖树也有一些缺点:

    • 代码量增加。由于不能共享相同的包(在npm v3中,尝试着共享相同版本的库,但还是比较弱),导致最终打包的时候有同一个库的多个版本的代码出现在最终包中。
    • 潜在的运行时冲突。以上面的例子为例,可能有些时候,mod-b的两个版本无法同时运行,而这只有在运行或者测试的时候才能被发现。

    希望以上的介绍能够帮助你更好的理解npm的依赖管理。

    相关文章

      网友评论

        本文标题:读懂package.json -- 依赖管理

        本文链接:https://www.haomeiwen.com/subject/ukpdcxtx.html