2013-07-18 14 views
7

Ich versuche, Mixpanel Event-Tracking in einer einzigen Seite basierend auf Backbone.js und require.js zu verwenden.Mixpanel 2.2 innerhalb einer AMD strukturierten Web-App - z. require.js

am snippet suchen, das für Ausschneiden und Einfügen in eine reguläre Webseite bieten Mixpanel, kann ich sagen, dass sie ihren eigenen Asynchron-Lademechanismus gerollt haben, die in den aktuellen Mixpanel API von einer eigenständigen Ressource zieht, einige zusätzliche Arbeit Richten Sie "people" und andere Attribute ein, und legen Sie schließlich das "mixpanel" -Objekt über den globalen Namespace offen.

Ich habe versucht, Shim-Config-Einträge für das Snippet oder die Standalone-API hinzuzufügen, aber beide funktionieren nicht gut.

Durch meine Forschung fand ich eine project on github, die genau das tut, was ich will, aber es ist ein paar Jahre alt und basiert auf der "alten" Mixpanel-API. In der neuen Version hat Mixpanel einige nicht-triviale Änderungen am Snippet und API vorgenommen, die ich einfach nicht verstehen kann.

Ich hoffe, jemand versteht das Mixpanel-Snippet und/oder AMD und require.js und kann mich durch diese gehen.

Antwort

13

Es gibt zwei lustige Dinge, die dieses eine ungerade Problem macht zu lösen:

  1. Die mixpanel lib erfordert, dass Sie window.mixpanel definiert haben, bevor Sie es laden.
  2. Die Mixpanel-Bibliothek definiert window.mixpanel als Teil ihres Init-Prozesses neu.

Aus dem Kasten, die Schnipsel mixpanel nicht get_distinct_id (und jeden Anruf, der per Definition ist, synchron) unterstützen, bis die lib geladen, aber nicht andere Verfahren Stub (wie Spur), bevor die Lade mixpanel lib um der Warteschlange willen. Deshalb haben wir zwei Möglichkeiten:

Option 1. Tropfen Asynchron-Unterstützung und warten, bis die lib geladen wird - Gist

Diese Methode funktioniert durch eine Pre-init-Modul zur Einrichtung der Erstellung der window.mixpanel deps benötigt durch die mixpanel lib und dann das als eine Abhängigkeit zu der lib selbst angeben. Dann wird "mixpanel" benötigt, bis die lib vollständig geladen ist. 2.

<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> 

Option Geben Sie einen "geladen" Rückruf des Moduls Eigenschaften zu aktualisieren. -

Wenn Sie wirklich async Unterstützung möchten, müssen Sie die Methoden Ihres Stubs aktualisieren, sobald die Mixpanel-Bibliothek geladen ist. Ich empfehle das nicht, weil es (neben anderen Gründen) window.mixpanel! == mixpanel nach der Kopie ergibt. Dies bedeutet auch, dass Sie sich bei synchronen Aufrufen wie get_distinct_id() gegen Race Conditions schützen müssen. Wenn die lib noch nicht geladen wurde, ist sie nicht definiert. Hinweis: Ich empfehle, wenn Sie Async-Unterstützung haben müssen, sollten Sie einfach durch window.mixpanel anstelle all dieser Verrücktheit aufrufen.

<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> 
+0

Dies (der erste Ansatz) funktioniert für mich - danke eine Tonne. –

+0

Wir verwendeten einen sehr ähnlichen Ansatz zur zweiten Methode, mit dem Zusatz eines Versprechens, das sich löst, wenn das Mischpanel unseren "geladenen" Rückruf aufruft. Danke für die Hilfe! – liquidki

+0

Option 1. funktionierte gut für mich, bis ich meinen Code durch den RequireJS-Optimierer lief. Die optimierte Ausgabe enthält den Mixpanel-Lib-Code mit einer angehängten Shim-Modul-Definition: define ("mixpanel", ["mixpanelPreInit"], (Funktion (global) {....} (this))); Leider wird der Mixpanel-Lib-Code immer noch ausgewertet, noch bevor die Moduldefinition ist. Wenn es ausgewertet wird, erwartet es, dass der Initialisierungscode bereits ausgeführt wurde. – tnunamak

5

Nach Lösung arbeitet für mixpanel api 2.2

hinzufügen mixpanel mit folgenden Shim -

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

shim : { 
    'mixpanel' : { 
     exports : 'mixpanel' 
    }, 
} 

und Verwendung folgende requirejs Modul anstelle des Snippet von mixpanel gegeben -

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; 
}); 

I einfach das Snippet aus dem Mixpanel genommen, die Async Mixpanel Load entfernt und in eine requirejs Moduldefinition verpackt.

Ändern Sie "YOUR TOKEN" an der Unterseite des Moduls.

Beispiel für die Verwendung mit einem Aufruf erfordern -

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

EDIT: Das zweite ist die richtige Antwort nach einer kleinen Änderung. Die Art, wie das Mixpanel-Skript funktioniert, erfordert, dass der Init-Aufruf im Snippet vor dem eigentlichen Mixpanel-Laden erfolgt. der Trick ist mixpanel nach der init call.i bearbeitet hat, die zweite Antwort und entfernt, um die ersten und here's the gist

EDIT zu verlangen: Antwort von @johanandren Requirejs folgt AMD Prinzip und die Reihenfolge, in der Skripte ist lädt zu Kommentar nicht behoben. Für den Fall, dass Sie den Mixpanel laden müssen, bevor Sie das Mixpanel-Snippet verwenden, kann der folgende Hack verwendet werden.

//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; 

** es verstößt gegen die Async Last Features von AMD, zwingt das Skript zu blockieren und sogar in vanila mixpanel Snippet die Last async und Verfügbarkeit für die anfängliche api Anrufe nicht

garantiert
+0

ich beide Wege ausprobiert habe und Ich erhalte eine js Fehler. Der # 2 Vorschlag ergibt ''Mixpanel Fehler:' Mixpanel 'Objekt nicht initialisiert. Stellen Sie sicher, dass Sie die neueste Version der Mixpanel JS Library zusammen mit dem von uns bereitgestellten Snippet benutzen. '' Uncaught TypeError: Kann die Eigenschaft '__SV' von undefined nicht '' [Hier ist ein Geiste] (https: //gist.github. com/dwightgunning/6088c0b0056838c0eb47) mit meinem Versuch, die zweite Alternative zu verwenden. –

+0

Entschuldigung für die späte Antwort. Ich war im Urlaub. Ich habe das Problem gelöst und die Antwort aktualisiert. Die Mixpanel-API geht davon aus, dass die Synchronisierungslast nicht vor dem passieren wird Aufruf an die init-Methode und damit das Problem, das vorherige Snippet geladen Mixpanel vor dem Snippet.Dies kann mit einem einfachen Require Call Post die Snippet-Init korrigiert werden.Ich habe auch eine neue öffentliche erstellt [Gist] (https: // gist .github.com/mohitmayank/6162576) – Mohit

+0

versucht, diese Lösung, aber es funktioniert nicht für uns, die Skripts abhängig von Mixpanel-Snippet wird ausgeführt, bevor Mixpanel vollständig geladen oder initialisiert wurde, so wird es einige Methoden zu haben scheinen .track zum Beispiel wird nichts tun, und wird überhaupt keine anderen Methoden haben, wie get_distinct_id – johanandren

0

Das ist für mich gearbeitet . Platzieren Sie Ihr Mixpanel-Snippet in Ihrem js/lib-Verzeichnis mit dem Namen "mixpanel-snippet.js".

Fügen Sie in Ihrer app.js das folgende Shim hinzu, das erforderlich ist.config:

'mixpanel-snippet': { 
    exports: 'mixpanel' 
} 

In Ihrer erfordern Funktion Add 'mixpanel-Snippet' auf die gewünschte Array und initialisieren mixpanel:

require(['jquery', 'backbone', 'app/router', 'mixpanel'], function ($, Backbone, Router) { 
    var router = new Router(); 
    Backbone.history.start(); 
    mixpanel.init(key); 
    mixpanel.track("Landed on Start up Page"); 
}); 

Ich kann ein volles app.js Beispiel geben, wenn es helfen würde, aber dies sollte fang an zu beginnen. Lass mich wissen, ob das funktioniert.

+0

Thx wird es in Kürze überprüfen. –

+0

Ich könnte das falsch interpretieren, aber verwendet das nicht einfach das globale 'window.mixpanel'-Objekt, so dass Sie wirklich nichts von dem Laden von AMD bekommen? –

0

Ab mixpanel der 2.7.x-Release, die sie unterstützen jetzt mehrere AMD/UMD-Versionen kompatibel mit requirejs, können Sie es auf ihre Github Seite greifen: https://github.com/mixpanel/mixpanel-js

requirejs(['./mixpanel.amd'], function(mixpanel) { 

    mixpanel.init("FAKE_TOKEN", { 
     debug: true, 
     loaded: function() { 
      mixpanel.track('loaded() callback works but is unnecessary'); 
      alert("Mixpanel loaded successfully via RequireJS/AMD"); 
     } 
    }); 

    mixpanel.track('Tracking after mixpanel.init'); 

});