回顾

上篇文章大概展示了kmdjs0.1.x时期的编程范式:

如下面所示,可以直接依赖注入到function里,

  1. kmdjs.define('main',['util.bom','app.Ball','util.dom.test'], function(bom,Ball,test) {
  2. var ball = new Ball(0, 0, 28, 1, -2, 'kmdjs');
  3. var vp = bom.getViewport();
  4. });

也可以直接在代码里把full namespace加上来调用,如:

  1. kmdjs.define('main',['util.bom','app.Ball','util.dom.test'], function() {
  2. var ball = new app.Ball(0, 0, 28, 1, -2, 'kmdjs');
  3. var vp = util.bom.getViewport();
  4. });

而且,在循环依赖的场景,因为执行顺序的问题,会导致第一种方式注入undefined,所以循环依赖的情况下只能用full namespace的方式来调用。

这种编程体验虽然已经足够好,但是可以更好。怎样才算更好?

  1. 不用依赖注入function
  2. 不用写full namespace,自动匹配依赖

如下所示:

  1. kmdjs.define('main',['util.bom','app.Ball','util.dom.test'], function() {
  2. var ball = new Ball(0, 0, 28, 1, -2, 'kmdjs');
  3. var vp = bom.getViewport();
  4. });

这就要借助uglifyjs能力,把function的字符串替换成带有namespace就可以实现上面的效果。

uglifyjs依赖分析和代码重构

  1. function fixDeps(fn,deps) {
  2. var U2 = UglifyJS;
  3. //uglify2不支持匿名转ast
  4. var code = fn.toString().replace('function','function ___kmdjs_temp');
  5. var ast = U2.parse(code);
  6. ast.figure_out_scope();
  7. var nodes = [];
  8. ast.walk(new U2.TreeWalker(function (node) {
  9. if (node instanceof U2.AST_New) {
  10. var ex = node.expression;
  11. var name = ex.name;
  12. isInWindow(name) || isInArray(nodes, node) || isInScopeChainVariables(ex.scope, name) || nodes.push({name:name,node:node});
  13. }
  14. if (node instanceof U2.AST_Dot) {
  15. var ex = node.expression;
  16. var name = ex.name;
  17. var scope = ex.scope;
  18. if (scope) {
  19. isInWindow(name) || isInArray(nodes, node) || isInScopeChainVariables(ex.scope, name) || nodes.push({name:name,node:node});
  20. }
  21. }
  22. if (node instanceof U2.AST_SymbolRef) {
  23. var name = node.name;
  24. isInWindow(name) || isInArray(nodes, node) || isInScopeChainVariables(node.scope, name) || nodes.push({name:name,node:node});
  25. }
  26. }));
  27. var cloneNodes = [].concat(nodes);
  28. //过滤new nodes 中的symbo nodes
  29. for (var i = 0, len = nodes.length; i < len; i++) {
  30. var nodeA = nodes[i].node;
  31. for (var j = 0, cLen = cloneNodes.length; j < cLen; j++) {
  32. var nodeB = cloneNodes[j].node;
  33. if (nodeB.expression === nodeA) {
  34. nodes.splice(i, 1);
  35. i--;
  36. len--;
  37. }
  38. }
  39. }
  40. for (var i = nodes.length; --i >= 0;) {
  41. var item = nodes[i],
  42. node=item.node,
  43. name=item.name;
  44. var fullName=getFullName(deps,name);
  45. var replacement;
  46. if (node instanceof U2.AST_New) {
  47. replacement = new U2.AST_New({
  48. expression: new U2.AST_SymbolRef({
  49. name:fullName
  50. }),
  51. args: node.args
  52. });
  53. } else if (node instanceof U2.AST_Dot) {
  54. replacement = new U2.AST_Dot({
  55. expression: new U2.AST_SymbolRef({
  56. name: fullName
  57. }),
  58. property: node.property
  59. });
  60. }else if(node instanceof U2.AST_SymbolRef){
  61. replacement = new U2.AST_SymbolRef({
  62. name: fullName
  63. });
  64. }
  65. var start_pos = node.start.pos;
  66. var end_pos = node.end.endpos;
  67. code = splice_string(code, start_pos, end_pos, replacement.print_to_string({
  68. beautify: true
  69. }));
  70. }
  71. return code.replace('function ___kmdjs_temp','function');
  72. }
  73. function getFullName(deps,name){
  74. var i= 0,
  75. len=deps.length,
  76. matchCount= 0,
  77. result=[];
  78. for(;i<len;i++) {
  79. var fullName = deps[i];
  80. if (fullName.split('.').pop() === name) {
  81. matchCount++;
  82. if (!isInArray(result, fullName)) result.push(fullName);
  83. }
  84. }
  85. if(matchCount>1){
  86. throw "the same name conflict: "+result.join(" and ");
  87. } else if(matchCount===1){
  88. return result[0];
  89. }else{
  90. throw ' can not find module ['+name+']';
  91. }
  92. }
  93. function splice_string(str, begin, end, replacement) {
  94. return str.substr(0, begin) + replacement + str.substr(end);
  95. }
  96. function isInScopeChainVariables(scope, name) {
  97. var vars = scope.variables._values;
  98. if (Object.prototype.hasOwnProperty.call(vars, "$" + name)) {
  99. return true;
  100. }
  101. if (scope.parent_scope) {
  102. return isInScopeChainVariables(scope.parent_scope, name);
  103. }
  104. return false;
  105. }
  106. function isInArray(arr,name){
  107. var i= 0,len=arr.length;
  108. for(;i<len;i++){
  109. if(arr[i]===name){
  110. return true;
  111. }
  112. }
  113. return false;
  114. }
  115. function isInWindow(name){
  116. if(name==='this')return true;
  117. return name in window;
  118. }

通过上面的fixDeps,可以对代码就行变换。如:

  1. console.log(fixDeps(function (A) {
  2. var eee = m;
  3. var b = new A();
  4. var b = new B();
  5. var c = new C();
  6. var d = G.a;
  7. },['c.B','AAA.G','SFSF.C','AAAA.m'] ))

输出:

  1. function (A) {
  2. var eee = AAAA.m;
  3. var b = new A();
  4. var b = new c.B();
  5. var c = new SFSF.C();
  6. var d = AAA.G.a;
  7. }

这样,kmdjs在执行模块function的时候,只需要fixDeps加上full namespace就行:

  1. function buildBundler(){
  2. var topNsStr = "";
  3. each(kmdjs.factories, function (item) {
  4. nsToCode(item[0]);
  5. });
  6. topNsStr+= kmdjs.nsList.join('\n') +"\n\n";
  7. each(kmdjs.factories, function (item) {
  8. topNsStr+=item[0]+' = ('+ fixDeps(item[2],item[1])+')();\n\n' ;
  9. });
  10. if(kmdjs.buildEnd) kmdjs.buildEnd(topNsStr);
  11. return topNsStr;
  12. }

build出来的包,当然全都加上了namespace。再也不用区分循环依赖和非循环依赖了~~~

Github

上面的所有代码可以Github上找到:

https://github.com/kmdjs/kmdjs

kmdjs集成uglifyjs2打造极致的编程体验的更多相关文章

  1. EDM数据营销之电商篇| 六大事务性邮件,环环相扣打造极致用户体验!

    “以用户为中心”的时代,电商们致力于打造极致的用户体验,想尽各式新颖营销办法,但难免还是会出现营销断层,以至于和用户间无法达到完整的交互. 本次Focussend以邮件营销为例,聚焦用户从浏览到支付等 ...

  2. Dora.Interception,为.NET Core度身打造的AOP框架 [1]:更加简练的编程体验

    很久之前开发了一个名为Dora.Interception的开源AOP框架(github地址:https://github.com/jiangjinnan/Dora,如果你觉得这个这框架还有那么一点价值 ...

  3. observejs改善组件编程体验

    传送门 observejs:https://github.com/kmdjs/observejs 本文演示:http://kmdjs.github.io/observejs/list/ 本文代码:ht ...

  4. 依赖注入[6]: .NET Core DI框架[编程体验]

    毫不夸张地说,整个ASP.NET Core框架是建立在一个依赖注入框架之上的,它在应用启动时构建请求处理管道过程中,以及利用该管道处理每个请求过程中使用到的服务对象均来源于DI容器.该DI容器不仅为A ...

  5. iOS-Socket编程体验

    CHENYILONG Blog Socket编程体验 Socket编程体验  技术博客http://www.cnblogs.com/ChenYilong/新浪微博http://weibo.com/lu ...

  6. AOP框架Dora.Interception 3.0 [1]: 编程体验

    .NET Core正式发布之后,我为.NET Core度身定制的AOP框架Dora.Interception也升级到3.0.这个版本除了升级底层类库(.NET Standard 2.1)之外,我还对它 ...

  7. 全新升级的AOP框架Dora.Interception[1]: 编程体验

    多年之前利用IL Emit写了一个名为Dora.Interception(github地址,觉得不错不妨给一颗星)的AOP框架.前几天利用Roslyn的Source Generator对自己为公司写的 ...

  8. .NET CORE学习笔记系列(2)——依赖注入[6]: .NET Core DI框架[编程体验]

    原文https://www.cnblogs.com/artech/p/net-core-di-06.html 毫不夸张地说,整个ASP.NET Core框架是建立在一个依赖注入框架之上的,它在应用启动 ...

  9. AMD and CMD are dead之KMDjs集成Blob一键下载全部build包

    更新 不zuo,[A/C]MD就不会死,所以kmdjs赢来来其伟大的版本0.0.6,该版本主要的更新有: 移除去了kmdjs.get(..).then的支持,只支持kmdjs.get(-,functi ...

随机推荐

  1. MongoDB学习笔记二—Shell操作

    数据类型 MongoDB在保留JSON基本键/值对特性的基础上,添加了其他一些数据类型. null null用于表示空值或者不存在的字段:{“x”:null} 布尔型 布尔类型有两个值true和fal ...

  2. 大数据之Yarn——Capacity调度器概念以及配置

    试想一下,你现在所在的公司有一个hadoop的集群.但是A项目组经常做一些定时的BI报表,B项目组则经常使用一些软件做一些临时需求.那么他们肯定会遇到同时提交任务的场景,这个时候到底如何分配资源满足这 ...

  3. Lesson 21 Mad or not?

    Text Aeroplanes are slowly driving me mad. I live near an airport and passing planes can be heard ni ...

  4. JS模块化开发:使用SeaJs高效构建页面

    一.扯淡部分 很久很久以前,也就是刚开始接触前端的那会儿,脑袋里压根没有什么架构.重构.性能这些概念,天真地以为前端===好看的页面,甚至把js都划分到除了用来写一些美美的特效别无它用的阴暗角落里,就 ...

  5. Glide源码导读

    最近比较无聊,为了找点事干,就花了两天时间把Glide的源码大概看了一下.刚开始看Glide的源码头脑还是比较乱的,因为作者引入了几个概念,又大量用了泛型,如果不了解这些概念读起代码来就比较痛苦,我也 ...

  6. 达夫设备(Duff's Device)

    达夫设备设备是一段非常巧妙,看起来非常诡异的c代码,它可以很大的提高程序执行的效率(本文将试验),达夫设备的来源我就不说了,我们来分析一下. 达夫设备是考虑到我们一般用for或者while循环的时候, ...

  7. 将一句话里的单词进行倒置,标点符号不倒换。比如将“I come from Shanghai.”倒换后变为“Shanghai. from come I”

    string str = "I come from Shanghai."; //根据空格切割 string[] strS = str.Split(' '); string temp ...

  8. 对百度的UEditor多图片上传的一些补充

    我已经写了一篇文章关于百度的UEditor提取多图片上传模块.如果还没有看过,请点击以下链接查看 http://www.cnblogs.com/luke1006/p/3719029.html 出差了两 ...

  9. fir.im Weekly - APP 性能监测优化 二三事

    每一个成功的 App,都拥有强大的性能体验.本期 fir.im Weekly 整理了微信读书.美团外卖. 天猫.美团点评技术团队的关于性能监测优化方面策略和工具的分享,一起来看看. 微信读书 iOS ...

  10. 透视 HTML子元素的margin-top样式会应用在父元素上的原由

    情况说明 当对页面中元素设置margin-top样式时,如果该元素有父元素,则margin-top会应用与父元素,子元素的top与父元素的top重叠.举例说明 <style>body{ma ...