美文网首页
Npm 多模块依赖解决方案

Npm 多模块依赖解决方案

作者: dkvirus | 来源:发表于2018-08-18 18:35 被阅读0次

    一、问题

    以电商后管系统为例,有三个项目:

    • 商品项目:mail-goods
    • 订单项目:mail-order
    • 集成项目:mail-integration

    其中:mail-integration 项目依赖 mail-goods 和 mail-order。我们称 mail-integration 为 集成项目,mail-goods 和 mail-order 为 底层依赖项目

    如果商品项目(mail-goods)的代码有改动,需要经过以下几个步骤才能在集成项目(mail-integration)中看到效果:

    • mail-goods 原本版本号为 1.0.0,修改 mail-goods 的代码;
    • 修改 mail-goods 版本号为 1.1.0,发布最新包:npm publish
    • 切换到 mail-integration 目录下,更新高版本的 mail-goods:npm install mail-goods@1.1.0
    • 重新运行 mail-integration,才可以看到 mail-goods 中修改的代码效果。

    这样做有几个问题:

    • 即便底层依赖包 mail-goods 只是修改了一个字符,也要经过 publish、install 操作,过程繁琐;
    • Npm 公共仓库 publish 不能发布同版本的包,也就是说每次 publish 都必须升级底层依赖包的版本号,不利于版本的管理。

    为了解决上面的问题,经过调研,有三个方案可以解决问题,下面一一介绍。

    二、方案一:lerna

    很多开源项目都用到了 lerna 做多模块依赖管理,如:dva、umi。如果第一次接触 lerna,可以动手操作一下下面的步骤感受一下 lerna 是如何优雅的解决多模块依赖问题。

    1)安装全局包 lerna

    $ npm install lerna -g
    

    2)初始化 lerna 项目

    $ mkdir test-lerna 
    $ cd test-lerna
    $ lerna init
    

    会生成如下目录:

    |-- test-lerna
      |-- packages/
      |-- lerna.json
      |-- package.json
    

    所有子包都放到 packages/ 目录下面统一管理。

    3)补充目录结构

    在 test-lerna/packages 目录下新建 test1 和 test2 两个子模块,分别创建 package.json 文件。

    目录结构

    修改 test2 子模块的 package.json,添加配置依赖 test1 子模块。

    {
      "name": "test2",
      "version": "1.0.0",
      // ....
      "dependencies": {
        "test1": "^1.0.0"
      },
      "keywords": [],
      "author": "",
      "license": "ISC"
    }
    

    在 /test-lerna 目录下执行 $ lerna bootstrap 安装依赖包,注意这里不是 $ npm install,因为 test2 依赖了 test1,去 test2 目录下可以看到出现了 node_modules 目录,可以看到 test1 目录被加载进来了(这里的 test1 其实相当于是个快捷方式而已),但到目前为止我们压根没有将 test1 提交到 npm 远程仓库。

    4)添加文件内容

    test-lerna/packages/test1/index.js

    function sum (a, b) {
        return Number(a) + Number(b);
    }
    
    module.exports = sum;
    

    test-lerna/packages/test1/test.js,运行该脚本确保 test1 内容是正确的。

    var sum = require('./index');
    
    console.log(sum(1, 2));
    

    test-lerna/packages/test2/index.js,引入 test1 包并调用它的方法,测试运行完全 ok。

    var sum = require('test1');
    
    console.log(sum(1, 2));
    

    5)修改 test1 包

    修改 test-lerna/packages/test1/index.js 文件,添加一段打印信息。

    function sum (a, b) {
        console.log('xixihaha');
        return Number(a) + Number(b);
    }
    
    module.exports = sum;
    

    重新执行 test2 包下的 index.js,发现也能打印出 xixihaha,都不需要发布 test1 包,test1 修改,及时生效。

    6)总结

    使用 lerna,不需要频繁的提交底层依赖包,就可看到底层依赖包的修改效果,其机制是创建底层依赖包的快捷方式(linux中叫做软链接)放到集成项目的 node_modules 目录下,由于是快捷方式,当底层依赖包有修改时,快捷方式内的内容也会相应修改。

    当然,lerna 要求有依赖关系的包都必须放到 pacakges 目录下,如果受不了这种强制要求,可以跳转方案三。

    三、方案二:npm 私有仓库

    Npm 公共仓库对于同一个包的同一个版本是不允许重复发布的,这是出于安全方面考虑。

    dk 用 react 1.0.0 包运行的程序目前跑的很稳定,如果 Npm 公共仓库能上传相同版本的包,指不定 react 哪个马虎的工作人员提交了个有 bug 的代码,并同时 publish 了 react 1.0.0 这个包,dk 这边的程序就会报错,又无从查起,命名包的版本都一样,为什么昨天晚上跑的还正常,今天跑起来就会报错呢?

    有的公司会搭建供内部使用的 Npm 私有仓库,常用的开源软件是 Nexus,感兴趣的可以自行学习一波。私有仓库通过设置可以允许上传同版本的 npm 包。

    mail-goods 版本为 1.0.0,现在修改了代码,可以重复 publish mail-goods 1.0.0 这个包,mail-integration 只需要强制更新(包的版本不变,包内容变化)一下 mail-goods 包的内容即可 npm install mail-goods -f

    这样做可以解决底层依赖包版本更新太快的问题,但没法解决每次修改底层包都要 publish > install 的繁琐操作。

    四、方案三:npm install <folder>

    npm install <folder> 这里的 folder 是底层依赖包的绝对路径,也就是有盘符的路径,如:'D://work/test1' 这种。

    这种方案底层机制和方案一 lerna 很像,也是创建快捷方式(linux中叫做软链接)放到集成项目的 node_modules 下,较 lerna 灵活的一点是不必按照 lerna 要求有依赖关系的包必须放到 pacakges 目录下,而是可以是任意目录。

    dk 实际使用 npm install <folder> 发现有几个需要注意的事项,列举如下:

    • 底层依赖包和继承项目包可能有共同的依赖,如都用到了 react,此时可能会报一个 react 的错误,错误原因是检查有多个版本的 react 包,解决方法为定义别名指定使用集成项目下的 react 依赖(webpack 和 roadhog 构建工具可以设置别名,其它构建工具不清楚)
    alias: {
        // ....
        react: path.join(__dirname, 'node_modules', 'react')
    },
    
    • npm install <folder> --no-save,加上 --no-save 不会修改 package.json 和 package-lock.json 文件,你可以分别测试一下不加参数和加参数安装之后 package.json 和 package-lock.json 里的区别。

    相关文章

      网友评论

          本文标题:Npm 多模块依赖解决方案

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