Npm 多模块依赖解决方案

一、问题

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

  • 商品项目: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 里的区别。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,423评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,339评论 1 289
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,241评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,503评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,824评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,262评论 1 207
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,615评论 2 309
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,337评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,989评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,300评论 2 240
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,829评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,193评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,753评论 3 230
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,970评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,708评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,295评论 2 267
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,207评论 2 258

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,083评论 18 139
  • 一、Python简介和环境搭建以及pip的安装 4课时实验课主要内容 【Python简介】: Python 是一个...
    _小老虎_阅读 5,618评论 0 10
  • Node的包管理器 JavaScript缺少包结构的定义,而CommonJS定义了一系列的规范。而NPM的出现则是...
    IT老马阅读 2,780评论 0 5
  • 描述 npm从以下来源获取配置值,按优先级排序: 命令行标记 在命令行上放置--foo bar设置foo配置参数为...
    竹天亮阅读 43,451评论 0 8
  • 都认为帮朋友忙,朋友会回报你会记住你对他的好吗?我的回答是不!不!不! 据调查统计百分之七十的朋友觉得好朋友帮...
    王小绅阅读 259评论 0 0