edp icon indicating copy to clipboard operation
edp copied to clipboard

[package]edp-package流程整理

Open otakustay opened this issue 9 years ago • 17 comments

@leeight 因为现在的edp-package在使用过程中还是有不少细节有问题的,这些细节很难说清楚,所以我整理了一个我认为合理的流程,看看是否能采纳到现在的功能中

第一次写完发现自己想的不对,又重写了一下……其实importupdate就是同一个过程,只有一些细枝末节上是不同的,所以我整理成一个流程了

效果

  1. 被使用者明确指定的包是不用让使用者确认的,都明确输入指令要引入/更新一个包了,再问它“是否要引入/更新XXX”是多余的
  2. 如果一个包在本地是没有的,但edp判断这个包是需要的(被依赖),也不用问用户要不要引入,不引入就完蛋了
  3. importupdate过程中,是可能涉及已经存在的包的update的,此时是需要询问用户的,要按照下面说的的流程进行
  4. 开发者指定import一个已经存在的包不应该被允许,应该提示“请使用edp update”。同样update一个不存在的包也是不行的
  5. importupdate过程不应该把未指定的包(如被依赖的包)加入到package.json中,比如我edp import er,你不能在package.jsondep中加上eoo这一项
  6. 任何时候不要依赖dep下有多少目录,这个逻辑肯定是不对的,package.jsonmodule.conf才是入口

使用方法

  1. edp import/update package用来拉取1个指定的包,区别就在上面说的,已经存在的包不能import,不存在的包不能update
  2. edp import/update package package ...用来拉取n个指定的包,此过程是对过程1的n次重复,这N交是串行的(并行会让你在处理依赖的时候头疼),任意一次失败都不应该影响其它的拉取,完成后提示“xxx包拉取失败”,以便使用者补救
  3. edp import/update没有参数时根据package.json来拉取所有需要的依赖,此过程是从package.json中读取包列表并执行过程2,注意这里看package.json就行,如果一个包不在package.json中,且不会在其它包更新过程中因为依赖问题一起更新的话,说明这个包根本没用了,没删掉它已经很客气了还更新啥
  4. edp import/update url根据URL来拉取1个指定的包,这个过程是第1步的子集,具体对照下文的流程应该比较容易理解

拉取单个包的流程

针对过程1,其实际执行应该是这样的:

  1. 从registry查找对应的meta信息
  2. 根据meta信息找符合指定版本要求(从package.json来或者@xxx指定的)的最新版本
  3. 根据第2步拿到的版本,去registry拿这个版本对应的package.json【注1】
  4. 根据package.json找到所有的依赖
  5. 对每个依赖,重复1-4的过程,把整个依赖树建起来
  6. 把这个树合并成一个数组,合并时注意根据包名去重,数组中每一项是{packageName, version},一个包在数组中应该只出现一次【注2】
  7. 根据第6步得出的数组,查看每一项,按以下分支走
    1. 如果本地有了,并且我们需要的版本比本地存在的更新(版本更新通过本地的package.json里的version比较),则询问用户“是否把xxx从1.0更新至2.0”,用户选Yes则下载更新,选No则跳过。下载更新是简单粗暴地“删除本地再下载安装”的过程(后续会加MD5比对之类的需求,所以不要和下面第3步的直接安装混在一起)
    2. 如果本地有了,且本地的版本比我们要的还新,直接跳过
    3. 本地没有这个包,则直接下载安装,不用问用户
  8. 全搞完后更新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. 找符合一个包的要求的最新的,则因为1.7.2符合1.x,所以使用1.7.2
  2. 找符合所有包的要求最新的,则用1.5.6

另外,有可能foobar依赖的版本根本是冲突的,比如1.5.x1.7.x,那么也要考虑上面2个原则用哪个,反正edp是不支持多版本共存和map的自动配置了,要玩开发者自己去玩儿去

我建议采用选新的方式,上面的案例我们用1.7.2

总结和关键点

  1. importupdate的流程是高度相同的
  2. 拉取package.json这事似乎是做不到的,要拉取整个包再解压找package.json,但后续下载安装又会用到这个包,所以这里设个缓存避免多次的下载
  3. 全程我们只看项目及各个包的package.json,不要有其它的信息来干扰
  4. 询问最少原则,只在本地有这个包且版本比较旧时才触发询问,一个包也只应该被询问一次(这就是建立依赖树再打平成数组的目的)
  5. 要考虑v1v2的两种layout

其它功能

  1. edp import应该增加--save参数来指定要不要更新package.json
  2. 最好有个edp dep来查看整个依赖树关系
  3. 【非常未来】考虑到通过配置require.config多版本并存、包改名等情况,事实上整个过程是需要结合module.conf里的信息的,比如edp update er但可能因为require.config里的packges里把er配成了mvc,那么比对版本的时候就要看dep/mvc这个目录。但现在没有去实现它的必要

otakustay avatar Jun 03 '15 07:06 otakustay

@leeight 现在有人做不,没有的话7月我看一下算了?

otakustay avatar Jul 07 '15 06:07 otakustay

好,交给你了

leeight avatar Jul 07 '15 07:07 leeight

有一个问题,上面的方案认为module.conf用于存储项目当前引入包的源信息。但是包改名、多版本并存之类的事情就没法支持了。是不是应该有个新的隐藏文件,用于存储当前引入包的源信息,而module.conf经过这个文件生成。

其实,最初设计的时候,module.conf仅仅是用于生成require.config的

errorrik avatar Oct 21 '15 05:10 errorrik

另外,原先有部分依赖包信息是存在.edpproj文件里的,是继续保留,还是废掉这个逻辑,必须存package.json?

我个人建议是废掉

errorrik avatar Oct 21 '15 05:10 errorrik

另外, @beenlee 从package.json里读dependencies的逻辑是这样的:

先看存不存在edp.dependencies,再看存不存在efe.dependencies,再看存不存在dependencies

errorrik avatar Oct 21 '15 05:10 errorrik

@errorrik edp.dependencies, efe.dependencies, dependencies这三个是什么区别,在import时是按什么规则写入的? 现在的逻辑好像是将依赖写入到package.json的edp.dependencies,如果没有这个文件,就尝试去找.edpproj下的metadata写到metadata的dependencies里 那个efe.dependencies是什么情况下写入的呢。

daaaabeen avatar Oct 22 '15 03:10 daaaabeen

先说dependenciesedp.dependencies

在通常情况下看来,一个package的依赖,应该写在dependencies里,这很好理解。但是有一种特殊的情况:这个package是一个浏览器端和browser端都能跑的package,甚至这就是一个node写的业务项目

在上面的情况下,node package的依赖与browser的依赖很可能不同。所以我们需要两个:

  • dependencies node 依赖
  • edp.dependencies browser 依赖

但是,大部分情况下,我们的包是纯粹的(就是个browser package或者node package)。如果我是单纯的browser package,但是我非要写edp.dependencies,又会觉得很sb。直接写dependencies就好了。

edp-package是管理browser package的。综上,处理逻辑就会变成:

  • 如果有edp.dependencies,就认它
  • 如果没有,就认dependencies

那么在最后,efe.dependencies是个什么鬼货色呢?其实丫啥也不是,现在没有任何地方实现它。因为efe代表的是技术体系,edp代表的是开发平台,所以我个人觉得可能efe.dependencies会更好些。但是想了想,没必要搞这么多名字出来。考虑dependenciesedp.dependencies就好了。如果想要扩展性好点,可以留出配置口。

errorrik avatar Oct 26 '15 11:10 errorrik

看到在说这个区别,我补一下,请顺便把main的问题解决了,对edp来说main: 'foo'会想找src/foo.js,而node并不会,这个需要区别对待

我们是否应该期待所有的配置都在edp下可以被override呢

otakustay avatar Oct 26 '15 12:10 otakustay

我们是否应该期待所有的配置都在edp下可以被override呢

我觉得可以,再想想除了main好像也没别的了。devDependencies?

errorrik avatar Oct 27 '15 05:10 errorrik

比如oo我们其实就想叫oo的,但是在npm上显然这名字已经占用了,所以最后改叫eoo

不过name要这么做的话,得 @leeight 那边的registry有支持

otakustay avatar Oct 27 '15 06:10 otakustay

我觉得可以,再想想除了main好像也没别的了。devDependencies?

或者改成 edp:main / efe:main / amd:main 之类的?

我们是否应该期待所有的配置都在edp下可以被override呢

override的目的就是为了少写点儿配置?

leeight avatar Oct 27 '15 07:10 leeight

我觉得可以,再想想除了main好像也没别的了。devDependencies?

实用角度看有着四个:name, main, dependencies, devDependencies 但也有其他字段需覆盖的场景,比如发版时指定各自的 files、private 等,比较少见

或者改成 edp:main / efe:main / amd:main 之类的?

从好记出发,已经有个 edp 对象了,放里面更方便点儿?

firede avatar Oct 27 '15 08:10 firede

那我大概整理下,主要有以下几个需要做的事~

  1. 项目的信息全部使用package.json保存,废掉.edpproj中的metadata,module.conf除了用于更新require.config信息之外,我们还能通过他来找到包的源信息
  2. package.json中使用edp.dependencies(或者直接dependencies)字段来保存且只保存直接依赖的包,而所有的包应该是在module.conf中能查到的这样两者的差也就是间接依赖的包了。这样就可以获得整个的依赖树了
  3. main的话,在edp下在加一个main,外层的main的路径相对与工程根目录,里面的相对于src目录,这样的话node在用的时候用外层的,edp用的时候,如果里边有就用里面的,如果没有就用外面的在加个src
  4. 拉取包的整个过程,就是 @otakustay 整理的那些

daaaabeen avatar Oct 30 '15 07:10 daaaabeen

正好最近打算把一些基础包同时发到npm和edp,需要这里提到的edp.main的支持,来问一下进度如何

otakustay avatar Dec 21 '15 08:12 otakustay

@otakustay 流程整理的这个,已经做完了,unimport也加上了,已发pr,edp.main的这个,现在的edp-project里module.js好像已经对npm和edp的包入口做了处理,可以在第一层的main指定为node的入口,edp下指定main 为edp的入口就可以了

daaaabeen avatar Jan 03 '16 18:01 daaaabeen

@leeight 你这边有空review吗

otakustay avatar Jan 06 '16 10:01 otakustay

可以

leeight avatar Jan 06 '16 10:01 leeight