[package]edp-package流程整理
@leeight 因为现在的edp-package在使用过程中还是有不少细节有问题的,这些细节很难说清楚,所以我整理了一个我认为合理的流程,看看是否能采纳到现在的功能中
第一次写完发现自己想的不对,又重写了一下……其实import和update就是同一个过程,只有一些细枝末节上是不同的,所以我整理成一个流程了
效果
- 被使用者明确指定的包是不用让使用者确认的,都明确输入指令要引入/更新一个包了,再问它“是否要引入/更新XXX”是多余的
- 如果一个包在本地是没有的,但edp判断这个包是需要的(被依赖),也不用问用户要不要引入,不引入就完蛋了
- 在
import或update过程中,是可能涉及已经存在的包的update的,此时是需要询问用户的,要按照下面说的的流程进行 - 开发者指定
import一个已经存在的包不应该被允许,应该提示“请使用edp update”。同样update一个不存在的包也是不行的 import或update过程不应该把未指定的包(如被依赖的包)加入到package.json中,比如我edp import er,你不能在package.json的dep中加上eoo这一项- 任何时候不要依赖
dep下有多少目录,这个逻辑肯定是不对的,package.json和module.conf才是入口
使用方法
edp import/update package用来拉取1个指定的包,区别就在上面说的,已经存在的包不能import,不存在的包不能updateedp import/update package package ...用来拉取n个指定的包,此过程是对过程1的n次重复,这N交是串行的(并行会让你在处理依赖的时候头疼),任意一次失败都不应该影响其它的拉取,完成后提示“xxx包拉取失败”,以便使用者补救edp import/update没有参数时根据package.json来拉取所有需要的依赖,此过程是从package.json中读取包列表并执行过程2,注意这里看package.json就行,如果一个包不在package.json中,且不会在其它包更新过程中因为依赖问题一起更新的话,说明这个包根本没用了,没删掉它已经很客气了还更新啥edp import/update url根据URL来拉取1个指定的包,这个过程是第1步的子集,具体对照下文的流程应该比较容易理解
拉取单个包的流程
针对过程1,其实际执行应该是这样的:
- 从registry查找对应的meta信息
- 根据meta信息找符合指定版本要求(从
package.json来或者@xxx指定的)的最新版本 - 根据第2步拿到的版本,去registry拿这个版本对应的package.json【注1】
- 根据
package.json找到所有的依赖 - 对每个依赖,重复1-4的过程,把整个依赖树建起来
- 把这个树合并成一个数组,合并时注意根据包名去重,数组中每一项是
{packageName, version},一个包在数组中应该只出现一次【注2】 - 根据第6步得出的数组,查看每一项,按以下分支走
- 如果本地有了,并且我们需要的版本比本地存在的更新(版本更新通过本地的
package.json里的version比较),则询问用户“是否把xxx从1.0更新至2.0”,用户选Yes则下载更新,选No则跳过。下载更新是简单粗暴地“删除本地再下载安装”的过程(后续会加MD5比对之类的需求,所以不要和下面第3步的直接安装混在一起) - 如果本地有了,且本地的版本比我们要的还新,直接跳过
- 本地没有这个包,则直接下载安装,不用问用户
- 如果本地有了,并且我们需要的版本比本地存在的更新(版本更新通过本地的
- 全搞完后更新
module.conf
以上步骤中有任何一步出错,整个过程回滚,打印错误信息,应该就像什么都没发生过一样,不能有残留的文件变更出现
【注1】如果用的是edp import/update url拉某个URL的话,此时没有registry,所以是直接拉下来进第4步就行
注意这种直接从URL拉过来的东西,不要在package.json里留下dependencies项,不然会影响以后的edp update更新所有包(会在registry上找不到这个包),这种包以后更新也肯定是edp update url更新的,在package.json中出现没有用
【注2】这里涉及到多个包依赖同一个包且版本要求不同时的原则,比如foo依赖[email protected],bar依赖[email protected],而当前的underscore版本是1.7.2:
- 找符合一个包的要求的最新的,则因为
1.7.2符合1.x,所以使用1.7.2 - 找符合所有包的要求最新的,则用
1.5.6
另外,有可能foo和bar依赖的版本根本是冲突的,比如1.5.x和1.7.x,那么也要考虑上面2个原则用哪个,反正edp是不支持多版本共存和map的自动配置了,要玩开发者自己去玩儿去
我建议采用选新的方式,上面的案例我们用1.7.2的
总结和关键点
import和update的流程是高度相同的- 拉取
package.json这事似乎是做不到的,要拉取整个包再解压找package.json,但后续下载安装又会用到这个包,所以这里设个缓存避免多次的下载 - 全程我们只看项目及各个包的
package.json,不要有其它的信息来干扰 - 询问最少原则,只在本地有这个包且版本比较旧时才触发询问,一个包也只应该被询问一次(这就是建立依赖树再打平成数组的目的)
- 要考虑
v1和v2的两种layout
其它功能
edp import应该增加--save参数来指定要不要更新package.json- 最好有个
edp dep来查看整个依赖树关系 - 【非常未来】考虑到通过配置
require.config多版本并存、包改名等情况,事实上整个过程是需要结合module.conf里的信息的,比如edp update er但可能因为require.config里的packges里把er配成了mvc,那么比对版本的时候就要看dep/mvc这个目录。但现在没有去实现它的必要
@leeight 现在有人做不,没有的话7月我看一下算了?
好,交给你了
有一个问题,上面的方案认为module.conf用于存储项目当前引入包的源信息。但是包改名、多版本并存之类的事情就没法支持了。是不是应该有个新的隐藏文件,用于存储当前引入包的源信息,而module.conf经过这个文件生成。
其实,最初设计的时候,module.conf仅仅是用于生成require.config的
另外,原先有部分依赖包信息是存在.edpproj文件里的,是继续保留,还是废掉这个逻辑,必须存package.json?
我个人建议是废掉
另外, @beenlee 从package.json里读dependencies的逻辑是这样的:
先看存不存在edp.dependencies,再看存不存在efe.dependencies,再看存不存在dependencies
@errorrik edp.dependencies, efe.dependencies, dependencies这三个是什么区别,在import时是按什么规则写入的? 现在的逻辑好像是将依赖写入到package.json的edp.dependencies,如果没有这个文件,就尝试去找.edpproj下的metadata写到metadata的dependencies里 那个efe.dependencies是什么情况下写入的呢。
先说dependencies和edp.dependencies。
在通常情况下看来,一个package的依赖,应该写在dependencies里,这很好理解。但是有一种特殊的情况:这个package是一个浏览器端和browser端都能跑的package,甚至这就是一个node写的业务项目。
在上面的情况下,node package的依赖与browser的依赖很可能不同。所以我们需要两个:
dependenciesnode 依赖edp.dependenciesbrowser 依赖
但是,大部分情况下,我们的包是纯粹的(就是个browser package或者node package)。如果我是单纯的browser package,但是我非要写edp.dependencies,又会觉得很sb。直接写dependencies就好了。
edp-package是管理browser package的。综上,处理逻辑就会变成:
- 如果有
edp.dependencies,就认它 - 如果没有,就认
dependencies
那么在最后,efe.dependencies是个什么鬼货色呢?其实丫啥也不是,现在没有任何地方实现它。因为efe代表的是技术体系,edp代表的是开发平台,所以我个人觉得可能efe.dependencies会更好些。但是想了想,没必要搞这么多名字出来。考虑dependencies和edp.dependencies就好了。如果想要扩展性好点,可以留出配置口。
看到在说这个区别,我补一下,请顺便把main的问题解决了,对edp来说main: 'foo'会想找src/foo.js,而node并不会,这个需要区别对待
我们是否应该期待所有的配置都在edp下可以被override呢
我们是否应该期待所有的配置都在edp下可以被override呢
我觉得可以,再想想除了main好像也没别的了。devDependencies?
比如oo我们其实就想叫oo的,但是在npm上显然这名字已经占用了,所以最后改叫eoo了
不过name要这么做的话,得 @leeight 那边的registry有支持
我觉得可以,再想想除了main好像也没别的了。devDependencies?
或者改成 edp:main / efe:main / amd:main 之类的?
我们是否应该期待所有的配置都在edp下可以被override呢
override的目的就是为了少写点儿配置?
我觉得可以,再想想除了main好像也没别的了。devDependencies?
实用角度看有着四个:name, main, dependencies, devDependencies 但也有其他字段需覆盖的场景,比如发版时指定各自的 files、private 等,比较少见
或者改成 edp:main / efe:main / amd:main 之类的?
从好记出发,已经有个 edp 对象了,放里面更方便点儿?
那我大概整理下,主要有以下几个需要做的事~
- 项目的信息全部使用package.json保存,废掉.edpproj中的metadata,module.conf除了用于更新require.config信息之外,我们还能通过他来找到包的源信息
- package.json中使用edp.dependencies(或者直接dependencies)字段来保存且只保存直接依赖的包,而所有的包应该是在module.conf中能查到的这样两者的差也就是间接依赖的包了。这样就可以获得整个的依赖树了
- main的话,在edp下在加一个main,外层的main的路径相对与工程根目录,里面的相对于src目录,这样的话node在用的时候用外层的,edp用的时候,如果里边有就用里面的,如果没有就用外面的在加个src
- 拉取包的整个过程,就是 @otakustay 整理的那些
正好最近打算把一些基础包同时发到npm和edp,需要这里提到的edp.main的支持,来问一下进度如何
@otakustay 流程整理的这个,已经做完了,unimport也加上了,已发pr,edp.main的这个,现在的edp-project里module.js好像已经对npm和edp的包入口做了处理,可以在第一层的main指定为node的入口,edp下指定main 为edp的入口就可以了
@leeight 你这边有空review吗
可以