Mixpanel 2.2在AMD结构化网络应用程序中 - 例如require.js

Dwi*_*ing 7 amd requirejs mixpanel

我试图在基于Backbone.js和require.js的单页面站点中使用Mixpanel事件跟踪.

看看Mixpanel为常规网页提供剪切和粘贴的片段,我可以告诉他们已经推出了自己的异步加载机制,从独立的资源中提取实际的Mixpanel API,做一些额外的工作来设置'人员'和其他属性,最后通过全局命名空间公开'mixpanel'对象.

我试图为片段或独立API添加shim配置条目,但都不能正常工作.

通过我的研究,我在github上找到了一个完全符合我想要的项目,但它已经存在了几年,并且基于"旧的"mixpanel API.在新版本中,Mixpanel对代码片段和API进行了一些非平凡的更改,我无法理解.

我希望有人理解Mixpanel片段和/或AMD和require.js,并且可以引导我完成这个.

Jos*_*mer 13

有两个有趣的事情使这个问题成为一个奇怪的问题:

  1. mixpanel lib要求您在加载之前定义window.mixpanel.
  2. mixpanel lib将window.mixpanel重新定义为其init进程的一部分.

开箱即用,mixpanel片段不支持get_distinct_id(以及任何调用,根据定义,同步),直到加载lib但是在加载mixpanel lib之前确实存在其他方法(例如track)排队.因此我们有两种选择:

选项1.删除异步支持并等待加载lib - Gist

此方法的工作原理是创建一个pre-init模块来设置mixpanel lib所需的window.mixpanel deps,然后将其指定为lib本身的依赖项.然后要求"mixpanel"将阻塞,直到lib完全加载.

<html>
    <head>
        <title>Mixpanel AMD Example - Sync</title>
        <script type="text/javascript" src="http://requirejs.org/docs/release/2.1.8/minified/require.js"></script>
        <script type="text/javascript">
            requirejs.config({
                paths : { 'mixpanel': "//cdn.mxpnl.com/libs/mixpanel-2.2.min" },
                shim: {
                    'mixpanel': {
                        deps: ['mixpanel-preinit'],
                        exports: 'mixpanel'
                    }
                }
            });
            define("mixpanel-preinit", function(require) {
                // this is a stripped down version of the mixpanel snippet that removes the loading of the lib via external script tag and the stubs for queuing calls
                var b=window.mixpanel=window.mixpanel||[];var i,g;b._i=[];b.init=function(a,e,d){function f(b,h){var a=h.split(".");2==a.length&&(b=b[a[0]],h=a[1]);b[h]=function(){b.push([h].concat(Array.prototype.slice.call(arguments,0)))}}"undefined"!==typeof d?c=b[d]=[]:d="mixpanel";b._i.push([a,e,d])};b.__SV=1.2;
                b.init("YOUR TOKEN");
            });
        </script>
    </head>
    <body>
        <script type="text/javascript">
            require(['mixpanel'], function(mixpanel) {
                mixpanel.track("my event", {prop1: "val1"}); 
                console.log(mixpanel.get_distinct_id()); 
            });
        </script>
    </body>
</html>
Run Code Online (Sandbox Code Playgroud)

选项2.提供"已加载"回调以更新模块的属性.- 要点

如果您真的需要异步支持,则需要在加载mixpanel lib后更新存根的方法.我不建议这样做,因为(除其他原因外)它会在复制后产生window.mixpanel!== mixpanel.这也意味着您必须防止同步调用(例如get_distinct_id())上的竞争条件.如果尚未加载lib,则它将是未定义的.注意:我建议如果您必须具有异步支持,则应该通过window.mixpanel调用而不是所有这些疯狂.

<html>
    <head>
        <title>Mixpanel AMD Example - Async</title>
        <script type="text/javascript" src="http://requirejs.org/docs/release/2.1.8/minified/require.js"></script>
        <script type="text/javascript">
            requirejs.config({
                paths : { 'mixpanel-lib': "//cdn.mxpnl.com/libs/mixpanel-2.2.min" }
            });

            define("mixpanel", function(require) {
                var b = window.mixpanel || [];
                if (!b.__SV) { var i, g; window.mixpanel = b; b._i = []; b.init = function (a, e, d) { function f(b, h) { var a = h.split("."); 2 == a.length && (b = b[a[0]], h = a[1]); b[h] = function () { b.push([h].concat(Array.prototype.slice.call(arguments, 0))) } } var c = b; "undefined" !== typeof d ? c = b[d] = [] : d = "mixpanel"; c.people = c.people || []; c.toString = function (b) { var a = "mixpanel"; "mixpanel" !== d && (a += "." + d); b || (a += " (stub)"); return a }; c.people.toString = function () { return c.toString(1) + ".people (stub)" }; i = "disable track track_pageview track_links track_forms register register_once alias unregister identify name_tag set_config people.set people.set_once people.increment people.append people.track_charge people.clear_charges people.delete_user".split(" "); for (g = 0; g < i.length; g++) f(c, i[g]); b._i.push([a, e, d]) }; b.__SV = 1.2 }

                // go ahead and start loading the mixpanel-lib
                require(['mixpanel-lib']);

                b.init("YOUR TOKEN", {loaded: function() { 
                    // now that we know mixpanel is loaded, copy the prop references to our module def
                    for(var prop in window.mixpanel) {
                        b[prop] = window.mixpanel[prop];
                    }
                }}); 
                return b;
            });
        </script>
    </head>
    <body>
        <script type="text/javascript">
            require(['mixpanel'], function(mixpanel) {
                mixpanel.track("my event", {prop1: "val1"}); 
                console.log(mixpanel.get_distinct_id()); // probably undefined
            });
        </script>
    </body>
</html>
Run Code Online (Sandbox Code Playgroud)


Moh*_*hit 5

以下解决方案适用于mixpanel api 2.2

使用以下垫片添加mixpanel -

path : {
    'mixpanel' : '//cdn.mxpnl.com/libs/mixpanel-2.2.min'
}

shim : {
    'mixpanel' : {
        exports : 'mixpanel'
    },
}
Run Code Online (Sandbox Code Playgroud)

并使用以下requirejs模块而不是mixpanel给出的片段 -

define('mixpanel-snippet', [], function(){
    var b = window.mixpanel || [];
    if (!b.__SV) {
        var i, g;
        window.mixpanel = b;
        b._i = [];
        b.init = function (a, e, d) {
            function f(b, h) {
                var a = h.split(".");
                2 == a.length && (b = b[a[0]], h = a[1]);
                b[h] = function () {
                    b.push([h].concat(Array.prototype.slice.call(arguments, 0)))
                }
            }
            var c = b;
            "undefined" !==
            typeof d ? c = b[d] = [] : d = "mixpanel";
            c.people = c.people || [];
            c.toString = function (b) {
                var a = "mixpanel";
                "mixpanel" !== d && (a += "." + d);
                b || (a += " (stub)");
                return a
            };
            c.people.toString = function () {
                return c.toString(1) + ".people (stub)"
            };
            i = "disable track track_pageview track_links track_forms register register_once alias unregister identify name_tag set_config people.set people.set_once people.increment people.append people.track_charge people.clear_charges people.delete_user".split(" ");
            for (g = 0; g < i.length; g++)
                f(c, i[g]);
            b._i.push([a, e, d])
        };
        b.__SV = 1.2
    }
    b.init("YOUR TOKEN");
    require(['mixpanel'], function(mixpanel){});

    return b;
});
Run Code Online (Sandbox Code Playgroud)

我只是从mixpanel中获取了片段,删除了异步mixpanel加载并将其包装在requirejs模块定义中.

更改模块底部的"您的令牌".

使用需求调用的示例 -

require([
    'mixpanel-snippet',
], function (mixpanel) {
        mixpanel.track("Landing Page with AMD SHIM");
});
Run Code Online (Sandbox Code Playgroud)

编辑:第二个是经过一点修改后的正确答案.mixpanel脚本的工作方式是它需要片段中的init调用在实际mixpanel加载之前发生.诀窍是在init调用后要求mixpanel.i编辑了第二个答案并删除了第一个答案,这里是要点

编辑:回答来自@johanandren的评论Requirejs遵循AMD原则,并且脚本将加载的顺序不固定.如果您需要在使用mixpanel-snippet之前加载mixpanel,可以使用以下hack.

//at the end of mixpanel-snippet code mentioned above force the script to block until mixpanel is loaded

b.init("YOUR TOKEN");
var wait = true;
require(['mixpanel'], function(mixpanel){wait = false;});
while(wait){}
return b;
Run Code Online (Sandbox Code Playgroud)

**它违反了AMD的Async加载功能,强制脚本加阻,即使在vanila mixpanel片段中,加载也是异步的,初始api调用的可用性无法保证