Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: modify delayLoad functionality #17

Merged
merged 22 commits into from Nov 29, 2022
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 3 additions & 2 deletions .babelrc
@@ -1,4 +1,5 @@
{
"presets": ["env", "react"],
"presets": ["@babel/preset-env", "@babel/preset-react"],
"plugins": ["@babel/plugin-proposal-object-rest-spread"],
"comments": false
}
}
32 changes: 20 additions & 12 deletions README.md
Expand Up @@ -40,7 +40,7 @@ plugins: [
// required; non-empty string
//NOTE: Do not commit this to git. Process from env.
prodKey: `RUDDERSTACK_PRODUCTION_WRITE_KEY`,

// if you have a development env for your rudderstack account, paste that key here
// when process.env.NODE_ENV === 'development'
// optional; non-empty string
Expand All @@ -58,32 +58,32 @@ plugins: [

// If you need to proxy events through a custom data plane,
// add a `dataPlaneUrl` property (defaults to https://hosted.rudderlabs.com )
// RudderStack docs:
// - https://docs.rudderstack.com/rudderstack-sdk-integration-guides/rudderstack-javascript-sdk#3-1-load
// Rudderstack docs:
saikumarrs marked this conversation as resolved.
Show resolved Hide resolved
// - https://rudderstack.com/docs/sources/event-streams/sdks/rudderstack-javascript-sdk/#31-load
dataPlaneUrl: `https://override-rudderstack-endpoint`,

// Add a `controlPlaneUrl` property if you are self-hosting the Control Plane
// RudderStack docs:
// - https://docs.rudderstack.com/rudderstack-sdk-integration-guides/rudderstack-javascript-sdk#3-1-1-self-hosted-control-plane
// Rudderstack docs:
// - https://rudderstack.com/docs/sources/event-streams/sdks/rudderstack-javascript-sdk/#311-self-hosted-control-plane
controlPlaneUrl: `https://override-control-plane-url`,

// boolean (defaults to false); whether to delay load RudderStack
// boolean (defaults to false); whether to delay loading(Download SDK and call load API) of RudderStack JS SDK.
MoumitaM marked this conversation as resolved.
Show resolved Hide resolved
// ADVANCED FEATURE: only use if you leverage client-side routing (ie, Gatsby <Link>)
// This feature will force RudderStack to load _after_ either a page routing change
// or user scroll, or after `delayLoadTime` elapses, whichever comes first. This feature is used to help improve your website's
// This feature will force Rudderstack to load _after_ either a page routing change
// or user scroll, whichever comes first. This delay time is controlled by
// `delayLoadTime` setting. This feature is used to help improve your website's
// TTI (for SEO, UX, etc). See links below for more info.
// NOTE: But if you are using server-side routing and enable this feature,
// RudderStack will never load (because although client-side routing does not do
// a full page refresh, server-side routing does, thereby preventing RudderStack
// Rudderstack will never load (because although client-side routing does not do
// a full page refresh, server-side routing does, thereby preventing Rudderstack
// from ever loading).
// See here for more context:
// GIF: https://github.com/benjaminhoffman/gatsby-plugin-segment/pull/19#issuecomment-559569483
// TTI: https://github.com/GoogleChrome/lighthouse/blob/master/docs/scoring.md#performance
// Problem/solution: https://marketingexamples.com/seo/performance
delayLoad: false,

// number (default to 1000); time to wait after the page loads
// to load the RudderStack SDK
// number (default to 1000); time to wait after scroll or route change
// To be used when `delayLoad` is set to `true`
delayLoadTime: 1000,

Expand All @@ -95,6 +95,12 @@ plugins: [
// *Another use case is if you want to add callbacks to the methods at load time.
manualLoad: false,

// Can be used to override the location of the JavaScript library. This is useful
// if you want to add a proxy between the location and the RudderStack source so ad-blockers won't block
// fetching the JavaScript sdk.
// By default plugin will use the latest JS SDK: https://cdn.rudderlabs.com/v1.1/rudder-analytics.min.js
sdkURL: `https://subdomain.yourdomain.com/v1.1/rudder-analytics.min.js`,

MoumitaM marked this conversation as resolved.
Show resolved Hide resolved
// string ('async' or 'defer'); whether to load the RudderStack SDK async or defer. Anything else
// will load normally.
// 'async' will load the SDK as <script async></script>
Expand All @@ -103,6 +109,8 @@ plugins: [

// Options to the `load` API
// Note: The above `controlPlaneUrl` overrides the `configUrl` field in this object
// Here you can find all the loadOptions available for JS SDK -
// https://www.rudderstack.com/docs/sources/event-streams/sdks/rudderstack-javascript-sdk/load-js-sdk/#loading-options
MoumitaM marked this conversation as resolved.
Show resolved Hide resolved
loadOptions: {
...
}
Expand Down
27 changes: 5 additions & 22 deletions gatsby-browser.js
Expand Up @@ -3,51 +3,34 @@
exports.onRouteUpdate = function (_ref, _ref2) {
var prevLocation = _ref.prevLocation;
var trackPage = _ref2.trackPage,
_ref2$trackPageDelay = _ref2.trackPageDelay,
trackPageDelay = _ref2$trackPageDelay === undefined ? 50 : _ref2$trackPageDelay;

_ref2$trackPageDelay = _ref2.trackPageDelay,
trackPageDelay = _ref2$trackPageDelay === void 0 ? 50 : _ref2$trackPageDelay;
function trackRudderStackPage() {
if (trackPage) {
// Adding a delay (defaults to 50ms when not provided by plugin option `trackPageDelay`)
// ensure that the RudderStack route tracking is in sync with the actual Gatsby route
// (otherwise you can end up in a state where the RudderStack page tracking reports
// the previous page on route change).
var delay = Math.max(0, trackPageDelay);

window.setTimeout(function () {
window.rudderanalytics && window.rudderanalytics.page(document.title);
}, delay);
}
}

// IMPORTANT: If you are cloning the contents of this file,
// we recommend to keep this section of the code intact and
// just change the tracking logic in `trackRudderStackPage` method.
if (window.rudderSnippetLoaded === false) {
if (window.rudderSnippetLoading === true) {
// As the loading is in progress, set the alternate callback function
// to track page
window.rudderSnippetLoadedCallback = function () {
trackRudderStackPage();
};
} else {
// if it is not the first page
if (prevLocation) {
// Trigger the script loader and set the callback function
// to track page
window.rudderSnippetLoadedCallback = undefined;
window.rudderSnippetLoader(function () {
trackRudderStackPage();
});
} else {
// As this is the first page, set the alternate callback function
// to track page and wait for the scroll event to occur (for SDK to get loaded)
} else {
window.rudderSnippetLoadedCallback = function () {
trackRudderStackPage();
}
};
}
}
} else {
trackRudderStackPage();
}
};
};
151 changes: 34 additions & 117 deletions gatsby-ssr.js
@@ -1,139 +1,56 @@
"use strict";

var _react = require("react");

var _react2 = _interopRequireDefault(_react);

function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : { default: obj };
}

var _react = _interopRequireDefault(require("react"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
exports.onRenderBody = function (_ref, pluginOptions) {
var setHeadComponents = _ref.setHeadComponents;
var trackPage = pluginOptions.trackPage,
prodKey = pluginOptions.prodKey,
var prodKey = pluginOptions.prodKey,
devKey = pluginOptions.devKey,
_pluginOptions$dataPl = pluginOptions.dataPlaneUrl,
dataPlaneUrl =
_pluginOptions$dataPl === undefined
? "https://hosted.rudderlabs.com"
: _pluginOptions$dataPl,
dataPlaneUrl = _pluginOptions$dataPl === void 0 ? "https://hosted.rudderlabs.com" : _pluginOptions$dataPl,
controlPlaneUrl = pluginOptions.controlPlaneUrl,
delayLoad = pluginOptions.delayLoad,
delayLoadTime = pluginOptions.delayLoadTime,
manualLoad = pluginOptions.manualLoad,
loadType = pluginOptions.loadType,
useNewSDK = pluginOptions.useNewSDK,
useBetaSDK = pluginOptions.useBetaSDK,
loadOptions = pluginOptions.loadOptions,
sdkURL = pluginOptions.sdkURL;
_pluginOptions$sdkURL = pluginOptions.sdkURL,
sdkURL = _pluginOptions$sdkURL === void 0 ? "https://cdn.rudderlabs.com/v1.1/rudder-analytics.min.js" : _pluginOptions$sdkURL,
_pluginOptions$loadOp = pluginOptions.loadOptions,
loadOptions = _pluginOptions$loadOp === void 0 ? {} : _pluginOptions$loadOp;

var sdkSrc = "https://cdn.rudderlabs.com/v1/rudder-analytics.min.js";
if (sdkURL) sdkSrc = sdkURL;
else if (useBetaSDK) {
sdkSrc = "https://cdn.rudderlabs.com/v1.1/beta/rudder-analytics.min.js";
} else if (useNewSDK) {
sdkSrc = "https://cdn.rudderlabs.com/v1.1/rudder-analytics.min.js";
}
if (!prodKey || prodKey.length < 10) console.error("Your RudderStack prodKey must be at least 10 char in length.");

if (!prodKey || prodKey.length < 10)
console.error(
"Your RudderStack prodKey must be at least 10 char in length."
);

if (devKey && devKey.length < 10)
console.error(
"If present, your RudderStack devKey must be at least 10 char in length."
);
if (devKey && devKey.length < 10) console.error("If present, your RudderStack devKey must be at least 10 char in length.");

var writeKey = process.env.NODE_ENV === "production" ? prodKey : devKey;

var loadConfig = "'" + writeKey + "', '" + dataPlaneUrl + "'";

if (loadOptions) {
// Override config URL if provided separately
loadOptions.configUrl = controlPlaneUrl || loadOptions.configUrl;
loadConfig += ", " + JSON.stringify(loadOptions);
var finalLoadOptions = _objectSpread(_objectSpread({}, loadOptions), {}, {
configUrl: controlPlaneUrl || loadOptions.configUrl
});
var loadConfig = "'".concat(writeKey, "', '").concat(dataPlaneUrl, "', ").concat(JSON.stringify(finalLoadOptions));
var scriptTagStr = "var s = document.createElement(\"script\");\n s.type = \"text/javascript\";\n s.src = \"".concat(sdkURL, "\";");
if (loadType === "async") {
scriptTagStr += "s.async = true;";
} else if (loadType === "defer") {
scriptTagStr += "s.defer = true;";
}
scriptTagStr += "document.head.appendChild(s);";
var snippet = "rudderanalytics=window.rudderanalytics=[];for(var methods=[\"load\",\"page\",\"track\",\"identify\",\"alias\",\"group\",\"ready\",\"reset\",\"getAnonymousId\",\"setAnonymousId\"],i=0;i<methods.length;i++){var method=methods[i];rudderanalytics[method]=function(a){return function(){rudderanalytics.push([a].concat(Array.prototype.slice.call(arguments)))}}(method)}\n ".concat(scriptTagStr, "\n");
var instantLoader = "".concat(snippet).concat(manualLoad ? "" : "rudderanalytics.load(".concat(loadConfig, ")"), ";");
var delayedLoader = "\n window.rudderSnippetLoaded = false;\n window.rudderSnippetLoading = false;\n window.rudderSnippetLoadedCallback = undefined;\n window.rudderSnippetLoader = function (callback) {\n if (!window.rudderSnippetLoaded && !window.rudderSnippetLoading) {\n window.rudderSnippetLoading = true;\n function loader() {\n ".concat(snippet, "\n window.rudderanalytics.load(").concat(loadConfig, ");\n window.rudderSnippetLoading = false;\n window.rudderSnippetLoaded = true;\n if (callback) { callback(); }\n if (window.rudderSnippetLoadedCallback) {\n window.rudderSnippetLoadedCallback();\n window.rudderSnippetLoadedCallback = undefined;\n }\n };\n\n \"requestIdleCallback\" in window\n ? requestIdleCallback(function () { loader(); })\n : loader();\n }\n }\n window.addEventListener('scroll',function () {window.rudderSnippetLoader()}, { once: true });\n setTimeout(\n function () {\n \"requestIdleCallback\" in window\n ? requestIdleCallback(function () { window.rudderSnippetLoader(); })\n : window.rudderSnippetLoader();\n },\n ").concat(delayLoadTime, " || 1000\n );\n ");

var snippet =
'rudderanalytics=window.rudderanalytics=[];for(var methods=["load","page","track","identify","alias","group","ready","reset","getAnonymousId","setAnonymousId"],i=0;i<methods.length;i++){var method=methods[i];rudderanalytics[method]=function(a){return function(){rudderanalytics.push([a].concat(Array.prototype.slice.call(arguments)))}}(method)}\n ' +
(delayLoad || manualLoad
? ""
: "rudderanalytics.load(" + loadConfig + ")") +
";\n";

const delayedLoader = `
window.rudderSnippetLoaded = false;
window.rudderSnippetLoading = false;
window.rudderSnippetLoadedCallback = undefined;
window.rudderSnippetLoader = function (callback) {
if (!window.rudderSnippetLoaded && !window.rudderSnippetLoading) {
window.rudderSnippetLoading = true;
function loader() {
window.rudderanalytics.load(${loadConfig});
window.rudderSnippetLoading = false;
window.rudderSnippetLoaded = true;
if (callback) { callback(); }
if (window.rudderSnippetLoadedCallback) {
window.rudderSnippetLoadedCallback();
window.rudderSnippetLoadedCallback = undefined;
}
};

"requestIdleCallback" in window
? requestIdleCallback(function () { loader(); })
: loader();
}
}
window.addEventListener('scroll',function () {window.rudderSnippetLoader()}, { once: true });
setTimeout(
function () {
"requestIdleCallback" in window
? requestIdleCallback(function () { window.rudderSnippetLoader(); })
: window.rudderSnippetLoader();
},
${delayLoadTime} || 1000
);
`;

var snippetToUse =
"\n " +
(delayLoad && !manualLoad ? delayedLoader : "") +
"\n " +
snippet +
"\n ";
var snippetToUse = "".concat(delayLoad && !manualLoad ? delayedLoader : instantLoader);

if (writeKey) {
var tags = [
_react2.default.createElement("script", {
key: "plugin-rudderstack",
dangerouslySetInnerHTML: { __html: snippetToUse },
}),
];

var tag = void 0;

if (loadType == "async") {
tag = _react2.default.createElement("script", {
async: true,
key: "rudderstack-cdn",
src: sdkSrc,
});
} else if (loadType == "defer") {
tag = _react2.default.createElement("script", {
defer: true,
key: "rudderstack-cdn",
src: sdkSrc,
});
} else {
tag = _react2.default.createElement("script", {
key: "rudderstack-cdn",
src: sdkSrc,
});
}

tags.push(tag);
var tags = [_react["default"].createElement("script", {
key: "plugin-rudderstack",
dangerouslySetInnerHTML: {
__html: snippetToUse
}
})];
setHeadComponents(tags);
}
};
};