browser-script-canary
TypeScript icon, indicating that this package has built-in type declarations

1.0.0 • Public • Published

Browser Script Canary

An easy way to do a user based Canary Deployment of your Javascript script!

Really useful for SDK deployments.

What this module does:

  • Rolls out if the current end-user should load the Canary version of your script.
  • Seamlessly load the Canary version of your script.

Simple example

In Typescript:

import {ICanaryConfig, Canary} from "browser-script-canary";
 
(async function main() {
    const canary = new Canary({
        probability: 50, // percentage
        canaryScriptUrl: '/mySdk.js?version=canary'
    } as ICanaryConfig);
    
    const wasCanaryLoaded = await canary.bootstrap();
    
    if (!wasCanaryLoaded) {
        // initialize the current sdk:
        window.mySdk = {
            isReady: () => true,
        };
    }
})();

Inner Flow

  • Script loads.
  • Participating in the Canary:
    • If the end-user never rolled its participation in the Canary
      • Roll the canary participation according to the probability.
    • If the end-user participates in Canary
      • Loading of Canary Script:
        • According to configuration

ICanaryConfig

export interface ICanaryConfig {
    // Participating in Canary:
    probability: number,
    version?: string,
    cookiesNames?: {
            isCanary?: string,
            version?: string
    },
    
    // Loading of Canary Script:
    canaryScriptUrl?: string,
    loadAsync?: boolean,
    supportCORs?: boolean,
    
    // Helpers:
    globalCanaryIndicationName?: string
}

Participating in the Canary

probability : number

Required in range: 0 <= probability <= 100.

The higher the probability, the more likely an end-user will receive the Canary version.

version?: string

Optional.

Changing the version will cause reset of all participating Canary end-users.

cookiesNames?: Object

Optional.

isCanary: string - the end-user's Canary indication cookie name.

version: string - the end-user's Canary version cookie name. If no version parameter, it won't be set.

Loading of Canary Script

canaryScriptUrl?: string

Optional.

The URL the Canary version script will be loaded from.

The default is the URL of the current script (document.currentScript) with the query string parameter: version=canary. To change this - check the 'Advanced Customization' section.

loadAsync?: boolean

Optional. The Default is false.

If true, will load the Canary script in an async matter by appending a script tag to the document.head's children. This could be problematic in the following case:

<html>
    <head>
        <script>
            const canary = new Canary({
                probability: 100,
                canaryScriptUrl: '/mySdk.js?version=canary',
                loadAsync: true
            });        
            canary.bootstrap();
        </script> 
        <script>
           mySdk.doAction();
           // because in `head`, scripts are loaded in a sync matter,
           //  this will run before the above finished bootstrapping - so it'll throw.
        </script> 
    </head>
</html>

supportCORs?: boolean

Optional. The default is false. Relevant only if loadAsync !== true.

If true the canary script URL will be loaded by a sync XHR request - so it must support CORs.

Else it'll be loaded via document.write of a the relevant script tag (which works fine if the script is in head).

Helpers

globalCanaryIndicationName?: string

Optional. The default is '___canary'.

The property name on window that the indication for the Canary bootstrapping will be stored.

More about changing this in the 'Advanced Customization' section.

Example

Inside the repo there's an example that can walk you through the usage and value of most of the above parameters. After cloning the repo:

  • In its directory run: npm i && npm run example
  • Add to your hosts file: 127.0.0.1 example.com
  • Using a modern browser, navigate to http://example.com:8080/example/index.html

Advanced Customization

When creating an instance of the Canary class, except for the ICanaryConfig Object you can provide other alternate implementations of different depedendencies:

export class Canary {
    constructor(config: ICanaryConfig,
                cookieProvider = new CookieProvider(),
                scriptLoader = new ScriptLoader(),
                randomFactory = () => Math.random() * 100,
                defaultScriptFactory = () =>
                    (!document || !document.currentScript)
                        ? undefined 
                        : (document.currentScript as HTMLScriptElement).src,
                globalCanaryIndication = {
                    get: () => window[config.globalCanaryIndicationName],
                    set: (val) => window[config.globalCanaryIndicationName] = val
                }) {}
}

CookieProvider

export interface ICookieProvider {
    get: (key: string) => string | null;
    put: (key: string, val: string) => void;
    remove: (key: string) => void;
}

How cookies are read, set and deleted.

ScriptLoader

export interface IScriptLoader {
    load(url: string, isAsync?: boolean, supportCORs?: boolean): Promise<any>;
}

How the Canary script will be loaded according to configuration.

randomFactory

() => number

How to generate a random number.

defaultScriptFactory

() => string|undefined

How to get the default script url (when canaryScriptUrl is not provided).

globalCanaryIndication

export interface IGlobalCanaryIndication {
    get: () => boolean,
    set: (val: boolean) => void
}

How to get and set the global indication of loading Canary.

Package Sidebar

Install

npm i browser-script-canary

Weekly Downloads

0

Version

1.0.0

License

MIT

Unpacked Size

35.2 kB

Total Files

13

Last publish

Collaborators

  • baryo