资讯专栏INFORMATION COLUMN

kmdjs集成uglifyjs2打造极致的编程体验

Pink / 2576人阅读

摘要:怎样才算更好不用依赖注入不用写,自动匹配依赖如下所示这就要借助能力,把的字符串替换成带有就可以实现上面的效果。再也不用区分循环依赖和非循环依赖了上面的所有代码可以上找到

回顾

上篇文章大概展示了kmdjs0.1.x时期的编程范式:
如下面所示,可以直接依赖注入到function里,

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

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

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

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

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

不用依赖注入function

不用写full namespace,自动匹配依赖

如下所示:

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

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

uglifyjs依赖分析和代码重构
function fixDeps(fn,deps) {
    var U2 = UglifyJS;
    //uglify2不支持匿名转ast
    var code = fn.toString().replace("function","function ___kmdjs_temp");
    var ast = U2.parse(code);
    ast.figure_out_scope();
    var nodes = [];


    ast.walk(new U2.TreeWalker(function (node) {

        if (node instanceof U2.AST_New) {
            var ex = node.expression;
            var name = ex.name;
            isInWindow(name) || isInArray(nodes, node) || isInScopeChainVariables(ex.scope, name) || nodes.push({name:name,node:node});
        }

        if (node instanceof U2.AST_Dot) {
            var ex = node.expression;
            var name = ex.name;
            var scope = ex.scope;
            if (scope) {
                isInWindow(name) || isInArray(nodes, node) || isInScopeChainVariables(ex.scope, name) || nodes.push({name:name,node:node});
            }
        }

        if (node instanceof U2.AST_SymbolRef) {
            var name = node.name;
            isInWindow(name) || isInArray(nodes, node) || isInScopeChainVariables(node.scope, name) || nodes.push({name:name,node:node});
        }
    }));

    var cloneNodes = [].concat(nodes);
    //过滤new nodes 中的symbo nodes
    for (var i = 0, len = nodes.length; i < len; i++) {
        var nodeA = nodes[i].node;
        for (var j = 0, cLen = cloneNodes.length; j < cLen; j++) {
            var nodeB = cloneNodes[j].node;
            if (nodeB.expression === nodeA) {
                nodes.splice(i, 1);
                i--;
                len--;
            }
        }
    }

    for (var i = nodes.length; --i >= 0;) {
        var item = nodes[i],
            node=item.node,
            name=item.name;
        var fullName=getFullName(deps,name);
        var replacement;
        if (node instanceof  U2.AST_New) {
            replacement = new U2.AST_New({
                expression: new U2.AST_SymbolRef({
                    name:fullName
                }),
                args: node.args
            });
        } else if (node instanceof  U2.AST_Dot) {
            replacement = new U2.AST_Dot({
                expression: new U2.AST_SymbolRef({
                    name: fullName
                }),
                property: node.property
            });
        }else if(node instanceof U2.AST_SymbolRef){
            replacement = new U2.AST_SymbolRef({
                    name: fullName
            });
        }

        var start_pos = node.start.pos;
        var end_pos = node.end.endpos;

        code = splice_string(code, start_pos, end_pos, replacement.print_to_string({
            beautify: true
        }));
    }
    return code.replace("function ___kmdjs_temp","function");
}

function getFullName(deps,name){
    var i= 0,
        len=deps.length,
            matchCount= 0,
            result=[];

    for(;i1){
        throw "the same name conflict: "+result.join(" and ");
    } else if(matchCount===1){
        return result[0];
    }else{
        throw " can not find module ["+name+"]";
    }
}

function splice_string(str, begin, end, replacement) {
    return str.substr(0, begin) + replacement + str.substr(end);
}

function isInScopeChainVariables(scope, name) {
    var vars = scope.variables._values;
    if (Object.prototype.hasOwnProperty.call(vars, "$" + name)) {
        return true;
    }

    if (scope.parent_scope) {
        return isInScopeChainVariables(scope.parent_scope, name);
    }

    return false;
}

function isInArray(arr,name){
    var i= 0,len=arr.length;
    for(;i

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

 console.log(fixDeps(function (A) {
        var eee = m;
        var b = new A();
        var b = new B();
        var c = new C();
        var d = G.a;
    },["c.B","AAA.G","SFSF.C","AAAA.m"] ))

输出:

function (A) {
        var eee = AAAA.m;
        var b = new A();
        var b = new c.B();
        var c = new SFSF.C();
        var d = AAA.G.a;
}

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

function buildBundler(){
    var topNsStr = "";
    each(kmdjs.factories, function (item) {
        nsToCode(item[0]);
    });
    topNsStr+=  kmdjs.nsList.join("
") +"

";
    each(kmdjs.factories, function (item) {
        topNsStr+=item[0]+" = ("+ fixDeps(item[2],item[1])+")();

" ;
    });
    if(kmdjs.buildEnd) kmdjs.buildEnd(topNsStr);
    return topNsStr;
}

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

Github

上面的所有代码可以Github上找到:
https://github.com/kmdjs/kmdjs

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/79667.html

相关文章

  • 隐形巨头华三通信:多年耕耘 打造云计算“大同世界”

    摘要:华三通信云计算产品线总裁吴健这样说到。虽然低调如斯,但这丝毫没有影响华三通信在云计算领域内的江湖地位。相比起来,华三通信发布的超融合系统产品则更加广为人知。  从引力波到AlphaGo,从虚拟现实到新能源,从电子政务到云课堂,云计算早已不再是高高在上的概念,而是已经渗透到了科技、工作、生活的每一个角落。  云计算的大行其道,不但改变了科技行业原有的技术路线,更是改变了既有的产业格局,创新、融...

    ivyzhang 评论0 收藏0
  • kmdjs和循环依赖

    摘要:从很早的版本就开始,是支持循环依赖的。比如下面的代码会被编译成要支持循环依赖其实有个要求,就是。不是的循环依赖是无解的循环依赖。所以在初始化阶段,这样的循环依赖是被允许的,因为都是。 循环依赖 循环依赖是非常必要的,有的程序写着写着就循环依赖了,可以提取出一个对象来共同依赖解决循环依赖,但是有时会破坏程序的逻辑自封闭和高内聚。所以没解决好循环依赖的模块化库、框架、编译器都不是一个好库、...

    AlienZHOU 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<