{"action":"created","issue":{"url":"https://api.github.com/repos/ecomfe/edp/issues/332","labels_url":"https://api.github.com/repos/ecomfe/edp/issues/332/labels{/name}","comments_url":"https://api.github.com/repos/ecomfe/edp/issues/332/comments","events_url":"https://api.github.com/repos/ecomfe/edp/issues/332/events","html_url":"https://github.com/ecomfe/edp/issues/332","id":84401821,"number":332,"title":"[package]edp-package流程整理","user":{"login":"otakustay","id":639549,"avatar_url":"https://avatars.githubusercontent.com/u/639549?v=3","gravatar_id":"","url":"https://api.github.com/users/otakustay","html_url":"https://github.com/otakustay","followers_url":"https://api.github.com/users/otakustay/followers","following_url":"https://api.github.com/users/otakustay/following{/other_user}","gists_url":"https://api.github.com/users/otakustay/gists{/gist_id}","starred_url":"https://api.github.com/users/otakustay/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/otakustay/subscriptions","organizations_url":"https://api.github.com/users/otakustay/orgs","repos_url":"https://api.github.com/users/otakustay/repos","events_url":"https://api.github.com/users/otakustay/events{/privacy}","received_events_url":"https://api.github.com/users/otakustay/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":0,"created_at":"2015-06-03T07:04:19Z","updated_at":"2015-07-07T06:13:19Z","closed_at":null,"body":"@leeight 因为现在的`edp-package`在使用过程中还是有不少细节有问题的，这些细节很难说清楚，所以我整理了一个我认为合理的流程，看看是否能采纳到现在的功能中\r\n\r\n第一次写完发现自己想的不对，又重写了一下……其实`import`和`update`就是同一个过程，只有一些细枝末节上是不同的，所以我整理成一个流程了\r\n\r\n## 效果\r\n\r\n1. 被使用者明确指定的包是不用让使用者确认的，都明确输入指令要引入/更新一个包了，再问它“是否要引入/更新XXX”是多余的\r\n2. 如果一个包在本地是没有的，但edp判断这个包是需要的（被依赖），也不用问用户要不要引入，不引入就完蛋了\r\n3. 在`import`或`update`过程中，是可能涉及已经存在的包的`update`的，此时是需要询问用户的，要按照下面说的的流程进行\r\n3. 开发者指定`import`一个已经存在的包不应该被允许，应该提示“请使用`edp update`”。同样`update`一个不存在的包也是不行的\r\n4. `import`或`update`过程不应该把未指定的包（如被依赖的包）加入到`package.json`中，比如我`edp import er`，你不能在`package.json`的`dep`中加上`eoo`这一项\r\n5. 任何时候不要依赖`dep`下有多少目录，这个逻辑肯定是不对的，`package.json`和`module.conf`才是入口\r\n\r\n## 使用方法\r\n\r\n1. `edp import/update package`用来拉取1个指定的包，区别就在上面说的，已经存在的包不能`import`，不存在的包不能`update`\r\n2. `edp import/update package package ...`用来拉取n个指定的包，此过程是对过程1的n次重复，这N交是串行的（并行会让你在处理依赖的时候头疼），任意一次失败都不应该影响其它的拉取，完成后提示“xxx包拉取失败”，以便使用者补救\r\n3. `edp import/update`没有参数时根据`package.json`来拉取所有需要的依赖，此过程是从`package.json`中读取包列表并执行过程2，注意这里看`package.json`就行，如果一个包不在`package.json`中，且不会在其它包更新过程中因为依赖问题一起更新的话，说明这个包根本没用了，没删掉它已经很客气了还更新啥\r\n4. `edp import/update url`根据URL来拉取1个指定的包，这个过程是第1步的子集，具体对照下文的流程应该比较容易理解\r\n\r\n## 拉取单个包的流程\r\n\r\n针对过程1，其实际执行应该是这样的：\r\n\r\n1. 从registry查找对应的meta信息\r\n2. 根据meta信息找符合指定版本要求（从`package.json`来或者`@xxx`指定的）的最新版本\r\n3. 根据第2步拿到的版本，去registry拿这个版本对应的package.json【注1】\r\n4. 根据`package.json`找到所有的依赖\r\n5. 对每个依赖，重复1-4的过程，把整个依赖树建起来\r\n6. 把这个树合并成一个数组，合并时注意根据包名去重，数组中每一项是`{packageName, version}`，一个包在数组中应该只出现一次【注2】\r\n7. 根据第6步得出的数组，查看每一项，按以下分支走\r\n    1. 如果本地有了，并且我们需要的版本比本地存在的更新（版本更新通过本地的`package.json`里的`version`比较），则询问用户“是否把xxx从1.0更新至2.0”，用户选Yes则下载更新，选No则跳过。下载更新是简单粗暴地“删除本地再下载安装”的过程（后续会加MD5比对之类的需求，所以不要和下面第3步的直接安装混在一起）\r\n    2. 如果本地有了，且本地的版本比我们要的还新，直接跳过\r\n    3. 本地没有这个包，则直接下载安装，不用问用户\r\n8. 全搞完后更新`module.conf`\r\n\r\n以上步骤中有任何一步出错，整个过程回滚，打印错误信息，应该就像什么都没发生过一样，不能有残留的文件变更出现\r\n\r\n【注1】如果用的是`edp import/update url`拉某个URL的话，此时没有registry，所以是直接拉下来进第4步就行\r\n\r\n注意这种直接从URL拉过来的东西，不要在`package.json`里留下`dependencies`项，不然会影响以后的`edp update`更新所有包（会在registry上找不到这个包），这种包以后更新也肯定是`edp update url`更新的，在`package.json`中出现没有用\r\n\r\n【注2】这里涉及到多个包依赖同一个包且版本要求不同时的原则，比如`foo`依赖`underscore@1.5.x`，`bar`依赖`underscore@1.x`，而当前的`underscore`版本是`1.7.2`：\r\n\r\n1. 找符合一个包的要求的最新的，则因为`1.7.2`符合`1.x`，所以使用`1.7.2`\r\n2. 找符合所有包的要求最新的，则用`1.5.6`\r\n\r\n另外，有可能`foo`和`bar`依赖的版本根本是冲突的，比如`1.5.x`和`1.7.x`，那么也要考虑上面2个原则用哪个，反正edp是不支持多版本共存和`map`的自动配置了，要玩开发者自己去玩儿去\r\n\r\n我建议采用选新的方式，上面的案例我们用`1.7.2`的\r\n\r\n## 总结和关键点\r\n\r\n1. `import`和`update`的流程是高度相同的\r\n2. 拉取`package.json`这事似乎是做不到的，要拉取整个包再解压找`package.json`，但后续下载安装又会用到这个包，所以这里设个缓存避免多次的下载\r\n3. 全程我们只看项目及各个包的`package.json`，不要有其它的信息来干扰\r\n4. 询问最少原则，只在本地有这个包且版本比较旧时才触发询问，一个包也只应该被询问一次（这就是建立依赖树再打平成数组的目的）\r\n5. 要考虑`v1`和`v2`的两种layout\r\n\r\n## 其它功能\r\n\r\n1. `edp import`应该增加`--save`参数来指定要不要更新`package.json`\r\n2. 最好有个`edp dep`来查看整个依赖树关系\r\n3. 【非常未来】考虑到通过配置`require.config`多版本并存、包改名等情况，事实上整个过程是需要结合`module.conf`里的信息的，比如`edp update er`但可能因为`require.config`里的`packges`里把`er`配成了`mvc`，那么比对版本的时候就要看`dep/mvc`这个目录。但现在没有去实现它的必要"},"comment":{"url":"https://api.github.com/repos/ecomfe/edp/issues/comments/119083415","html_url":"https://github.com/ecomfe/edp/issues/332#issuecomment-119083415","issue_url":"https://api.github.com/repos/ecomfe/edp/issues/332","id":119083415,"user":{"login":"otakustay","id":639549,"avatar_url":"https://avatars.githubusercontent.com/u/639549?v=3","gravatar_id":"","url":"https://api.github.com/users/otakustay","html_url":"https://github.com/otakustay","followers_url":"https://api.github.com/users/otakustay/followers","following_url":"https://api.github.com/users/otakustay/following{/other_user}","gists_url":"https://api.github.com/users/otakustay/gists{/gist_id}","starred_url":"https://api.github.com/users/otakustay/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/otakustay/subscriptions","organizations_url":"https://api.github.com/users/otakustay/orgs","repos_url":"https://api.github.com/users/otakustay/repos","events_url":"https://api.github.com/users/otakustay/events{/privacy}","received_events_url":"https://api.github.com/users/otakustay/received_events","type":"User","site_admin":false},"created_at":"2015-07-07T06:13:18Z","updated_at":"2015-07-07T06:13:18Z","body":"@leeight 现在有人做不，没有的话7月我看一下算了？"}}