Giter VIP home page Giter VIP logo

optimizely / javascript-sdk Goto Github PK

View Code? Open in Web Editor NEW
74.0 90.0 80.0 8.58 MB

JavaScript SDK for Optimizely Feature Experimentation and Optimizely Full Stack (legacy)

Home Page: https://www.optimizely.com/products/experiment/feature-experimentation/

License: Apache License 2.0

JavaScript 55.23% TypeScript 44.77%
optimizely-environment-prod optimizely-environment-public optimizely-owner-px

javascript-sdk's Introduction

Optimizely JavaScript SDK

npm npm GitHub Actions Coveralls license

This repository houses the JavaScript SDK for use with Optimizely Feature Experimentation and Optimizely Full Stack (legacy).

Optimizely Feature Experimentation is an A/B testing and feature management tool for product development teams that enables you to experiment at every step. Using Optimizely Feature Experimentation allows for every feature on your roadmap to be an opportunity to discover hidden insights. Learn more at Optimizely.com, or see the developer documentation.

Optimizely Rollouts is free feature flags for development teams. You can easily roll out and roll back features in any application without code deploys, mitigating risk for every feature on your roadmap.


Get Started

For Browser applications, refer to the JavaScript SDK's developer documentationβ€―for detailed instructions on getting started with using the SDK within client-side applications.

For Node.js applications, refer to the JavaScript (Node) variant of the developer documentation.

For Edge Functions, we provide starter kits that utilize the Optimizely JavaScript SDK for the following platforms:

Note: We recommend using the Lite version of the sdk for edge platforms. These starter kits also use the Lite variant of the JavaScript SDK which excludes the datafile manager and event processor packages.

Prerequisites

Ensure the SDK supports all of the platforms you're targeting. In particular, the SDK targets modern ES5-compliant JavaScript environment. We officially support:

  • Node.js >= 16.0.0. By extension, environments like AWS Lambda, Google Cloud Functions, and Auth0 Webtasks are supported as well. Older Node.js releases likely work too (try npm test to validate for yourself), but are not formally supported.
  • Modern Web Browsers, such as Microsoft Edge 84+, Firefox 91+, Safari 13+, and Chrome 102+, Opera 76+

In addition, other environments are likely compatible but are not formally supported including:

  • Progressive Web Apps, WebViews, and hybrid mobile apps like those built with React Native and Apache Cordova.
  • Cloudflare Workers and Fly, both of which are powered by recent releases of V8.
  • Anywhere else you can think of that might embed a JavaScript engine. The sky is the limit; experiment everywhere! πŸš€

Requirements

  • JavaScript (Browser): Modern web browser that is ES5-compliant.

  • JavaScript (Node): Node 16.0.0+

Install the SDK

Once you've validated that the SDK supports the platforms you're targeting, fetch the package from NPM:

Using npm:

npm install --save @optimizely/optimizely-sdk

Using yarn:

yarn add @optimizely/optimizely-sdk

Using pnpm:

pnpm add @optimizely/optimizely-sdk

Using deno (no installation required):

import optimizely from "npm:@optimizely/optimizely-sdk"

Use the JavaScript SDK (Browser)

See the Optimizely Feature Experimentation developer documentation for JavaScript (Browser) to learn how to set up your first JavaScript project and use the SDK for client-side applications.

Initialization (Browser)

The package has different entry points for different environments. The browser entry point is an ES module, which can be used with an appropriate bundler like Webpack or Rollup. Additionally, for ease of use during initial evaluations you can include a standalone umd bundle of the SDK in your web page by fetching it from unpkg:

<script src="https://unpkg.com/@optimizely/optimizely-sdk/dist/optimizely.browser.umd.min.js"></script>

<!-- You can also use the unminified version if necessary -->
<script src="https://unpkg.com/@optimizely/optimizely-sdk/dist/optimizely.browser.umd.js"></script>

When evaluated, that bundle assigns the SDK's exports to window.optimizelySdk. If you wish to use the asset locally (for example, if unpkg is down), you can find it in your local copy of the package at dist/optimizely.browser.umd.min.js. We do not recommend using this method in production settings as it introduces a third-party performance dependency.

As window.optimizelySdk should be a global variable at this point, you can continue to use it like so:

const optimizelyClient = window.optimizelySdk.createInstance({
  sdkKey: '<YOUR_SDK_KEY>',
  // datafile: window.optimizelyDatafile,
  // etc.
});

optimizelyClient.onReady().then(({ success, reason }) => {
  if (success) {
      // Create the Optimizely user context, make decisions, and more here!
  }
});

Regarding EventDispatchers: In Node.js and browser environments, the default EventDispatcher is powered by the http/s modules and by XMLHttpRequest, respectively. In all other environments, you must supply your own EventDispatcher.

Use the JavaScript SDK (Node)

See the Optimizely Feature Experimentation developer documentation for JavaScript (Node) to learn how to set up your first JavaScript project and use the SDK for server-side applications.

Initialization (Node)

The package has different entry points for different environments. The node entry point is CommonJS module.

const optimizelySdk = require('@optimizely/optimizely-sdk');

const optimizelyClient = optimizelySdk.createInstance({
  sdkKey: '<YOUR_SDK_KEY>',
  // datafile: window.optimizelyDatafile,
  // etc.
});

optimizelyClient.onReady().then(({ success, reason }) => {
  if (success) {
      // Create the Optimizely user context, make decisions, and more here!
  }
});

Regarding EventDispatchers: In Node.js environment, the default EventDispatcher is powered by the http/s module.

SDK Development

Unit Tests

There is a mix of testing paradigms used within the JavaScript SDK which include Mocha, Chai, Karma, and Jest, indicated by their respective *.tests.js and *.spec.ts filenames.

When contributing code to the SDK, aim to keep the percentage of code test coverage at the current level (Coveralls) or above.

To run unit tests on the primary JavaScript SDK package source code, you can take the following steps:

  1. On your command line or terminal, navigate to the ~/javascript-sdk/packages/optimizely-sdk directory.
  2. Ensure that you have run npm install to install all project dependencies.
  3. Run npm test to run all test files.
  4. (For cross-browser testing) Run npm run test-xbrowser to run tests in many browsers via BrowserStack.
  5. Resolve any tests that fail before continuing with your contribution.

This information is relevant only if you plan on contributing to the SDK itself.

# Prerequisite: Install dependencies.
npm install

# Run unit tests.
npm test

# Run unit tests in many browsers, currently via BrowserStack.
# For this to work, the following environment variables must be set:
#   - BROWSER_STACK_USERNAME
#   - BROWSER_STACK_PASSWORD
npm run test-xbrowser

/.github/workflows/javascript.yml contains the definitions for BROWSER_STACK_USERNAME and BROWSER_STACK_ACCESS_KEY used in the GitHub Actions CI pipeline. When developing locally, you must provide your own credentials in order to run npm run test-xbrowser. You can register for an account for free on the BrowserStack official website here.

Contributing

For more information regarding contributing to the Optimizely JavaScript SDK, please read Contributing.

Special Notes

Migrating from 4.x.x

This version represents a major version change and, as such, introduces some breaking changes. Please refer to the Changelog for more details.

Feature Management access

To access the Feature Management configuration in the Optimizely dashboard, please contact your Optimizely customer success manager.

Credits

@optimizely/optimizely-sdk is developed and maintained by Optimizely and many contributors. If you're interested in learning more about what Optimizely Feature Experimentation can do for your company you can visit the official Optimizely Feature Experimentation product page here to learn more.

First-party code (under packages/optimizely-sdk/lib/, packages/datafile-manager/lib, packages/datafile-manager/src, packages/datafile-manager/__test__, packages/event-processor/src, packages/event-processor/__tests__, packages/logging/src, packages/logging/__tests__, packages/utils/src, packages/utils/__tests__) is copyright Optimizely, Inc. and contributors, licensed under Apache 2.0.

Other Optimizely SDKs

javascript-sdk's People

Contributors

aliabbasrizvi avatar brandonhudavid avatar caitlinrubin-optimizely avatar delikat avatar dependabot[bot] avatar elliotykim avatar fayyazarshad avatar haleybash-optimizely avatar jaeopt avatar jasonkarns avatar jordangarcia avatar juancarlostong avatar mfahadahmed avatar mikechu-optimizely avatar mikeproeng37 avatar mjc1283 avatar mnoman09 avatar msohailhussain avatar nchilada avatar oakbani avatar onufryk avatar opti-jnguyen avatar ozayr-zaviar avatar rafinutshaw-optimizely avatar raju-opti avatar shaharyar123 avatar spencerwilson-optimizely avatar yasirfolio3 avatar yavorona avatar zashraf1985 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

javascript-sdk's Issues

Whitelisting and forced bucketing not working for feature tests inside exclusion groups

What I wanted to do

Develop and QA a feature test (which was part of an exclusion group).

What I expected to happen

Expected to be able to whitelist or force bucket a user id to force a variation to be shown.

Although technically the docs do not say that whitelisting takes precedence over exclusion group bucketing, they do say that "Forced bucketing variations will take precedence over ... the normal bucketed variation."
https://docs.developers.optimizely.com/full-stack/docs/set-forced-variation
https://developers.optimizely.com/x/solutions/sdks-v1/reference/index.html?language=node&platform=fullstack

What actually happened

  • Neither whitelisting nor forced bucketing worked as expected while the feature test was in the exclusion group.
  • When the feature test was removed from the group, whitelisting worked as expected again.

(This does not seem to be an issue with A/B tests inside or outside of exclusion groups. My iOS developer counterparts do not seem to have encountered this issue with the objective-c-sdk.)

Steps to reproduce

Link to repository that can reproduce the issue:

  1. Set up a feature test and whitelist a user id to a variation.
  2. Add the feature test to an exclusion group. In our case, the exclusion group contained other feature and a/b tests. Traffic allocation for this feature test was set at 0% or 50%.
  3. Changed our user id in the app and expected to see the feature variables set according to the expected variation.

Additional Info

I believe the root cause is here:

if (feature.hasOwnProperty('groupId')) {
var group = this.configObj.groupIdMap[feature.groupId];
if (group) {
experiment = this._getExperimentInGroup(group, userId);
if (experiment && feature.experimentIds.indexOf(experiment.id) !== -1) {
variationKey = this.getVariation(experiment.key, userId, attributes);
}
}

Because this test is in a group, the normal bucketing process happens first and determines that the user is not in the experiment (experiment is null). It looks like whitelisting and forced bucketing occurs in getVariation, which does not get called if experiment is null.

@optimizely/optimizely-sdk version: 3.0.1

Please let me know if I can provide more clarity or detail. Thank you!

Wrong lodash require path

After installing packages with yarn, client-sdk cant find 'optimizely-server-sdk/node_modules/lodash/core'

image

configObj on client gone in latest version?

I just upgraded the SDK from 3.1.0 to 3.2.1. I'm not super familiar with this code, however, we have a piece of code that started to fail after the upgrade in our optimizely utils (which in turn uses this SDK under the hood):

updateSegmentExperiments({experimentName, variationName, type} = {}) {
    if (_client) {
        const {
            configObj: {
                experimentKeyMap
            }
        } = _client;

        if (variationName !== 'a') {
            const variationObj = experimentKeyMap[experimentName].variationKeyMap[variationName];

            /* eslint-disable camelcase */
            _segmentExperiments.push({
                experiment_name: experimentName,
                experiment_id: experimentKeyMap[experimentName].id,
                variation_name: variationName,
                variation_id: variationObj.id,
                type
            });
            /* eslint-enable camelcase */
        }
    }
},

The error is TypeError: Cannot read property 'experimentKeyMap' of undefined and in my logging, I can confirm _client is set correctly but there is no configObj on it. Again, I'm not super familiar with this code as it was written by another developer, but what happened between the two versions that made this differ?

I appreciate any help you can offer.

Distributable is missing from npm package

The compiled distributable is missing from the npm package.

See: https://unpkg.com/[email protected]/

The entire dist dir is being ignored from npm because of .npmignore: https://github.com/optimizely/javascript-sdk/blob/master/.npmignore#L9

The .npmignore file ought to be removed (so that ignores are only listed in .gitignore in a single place, not duplicated in two files).

dist/ should be git-ignored (compiled assets are not supposed to be committed to version control)

And dist/ should be added to the package.json's files array so that the compiled distributable is actually included in the published npm package. (See npm-pack for inspecting the contents of the tarball that is published)

Imports its own lodash in a client build

We're loading this sdk in a client app via webpack. When we do our production build we get a bundle that contains two lodashes:

screen shot 2017-04-26 at 2 32 14 pm

It looks like this is coming from this require: https://github.com/optimizely/javascript-sdk/blob/master/index.js#L16

I see that you have custom lodash build there, but do we really need it for our client? Is there any way to avoid this so we bundle just one lodash for the browser?

I quickly tried adding:

      new webpack.NormalModuleReplacementPlugin(
        /node_modules\/optimizely-server-sdk\/node_modules\/lodash\/core\.js/,
        path.resolve(nodeModulesDir, 'lodash/core.js')
      ),

but no luck. Thanks for your help!

MaxListenersExceededWarning on [email protected]

Since [email protected], the test suite (npm run test-travis) has started emitting thousands of instances of:

(node:2877) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 2 error listeners added. Use emitter.setMaxListeners() to increase limit

I am not sure if this is indicative of a real regression in nodejs production usage, but it is definitely breaking the build (https://travis-ci.org/optimizely/javascript-sdk/jobs/381767712), and can be reproduced on my Mac using nvm install 10.1.

This wasn't/isn't an issue on [email protected] (https://travis-ci.org/optimizely/javascript-sdk/jobs/376595175)

Update UUID dependency for ESM

How would the enhancement work?

As of v8, uuid exposes ESM to support tree shaking.
https://github.com/uuidjs/uuid/blob/master/CHANGELOG.md#800-2020-04-29

Now we can import the v4 algorithm directly without pulling the entire library into our bundle.

#474 was initially opened to bump the UUID dep in optimizely-sdk. However, it was later discovered that the UUID dep is also imported by js-sdk-utils. To properly update the dep and to avoid duplicating the dep:

  1. optimizely-sdk should import the UUID function from js-sdk-utils
  2. optimizely-sdk should remove the UUID dependency from its package.json
  3. js-sdk-utils should update its UUID dep to latest (v8.0) and import via ESM

When would the enhancement be useful?

Minimize optimizely bundles by excluding portions of the UUID library that are unnecessary.

potential before

potential after

TypeError: crypto.randomBytes is not a function

When activating an experiment as follows:
optimizelyClient.activate('experiment', 'user123') returns null and the logger shows this error TypeError: crypto.randomBytes is not a function

Code:

optimizely.createInstance({ datafile: JSON.stringify(datafile),
  errorHandler: defaultErrorHandler,
  logger: defaultLogger.createLogger({
    logLevel: LOG_LEVEL.DEBUG
  }),
 })
const variation = optimizelyClient.activate('experiment', 'user123')

Further troubleshooting deduced that

optimizelyClient._sendImpressionEvent('experiment', variationKey, 'user123', {})

returns the error
TypeError: crypto.randomBytes is not a function

Publish non-minified bundle and/or sourcemaps.

With only the minified bundle published, it makes debugging the minified source rather difficult. I request that the published tarball include a non-minified bundle, such that we can debug a non-minified version of the library (or at least use our own minifier so that we can generate the corresponding source map).

At the very least, I would request that the sourcemap for the existing minified bundle be distributed alongside the bundle so we can at least debug with that. (preferably, both the sourcemap and non-minified bundle would be published so consumers can make their own choice.)

Audiences attributes only work with string values

optimizely.isFeatureFlag('flag-key', 'user-id', { isAdmin: true}) only get segmented in the isAdmin audience if the attribute has the type string "true" and doesn't actually work with booleans.

i.e optimizely.isFeatureFlag('flag-key', 'user-id', { isAdmin: true}) returns false
i.e optimizely.isFeatureFlag('flag-key', 'user-id', { isAdmin: "true"}) returns true

Installation triggers not-applicable peerDep warning

What I wanted to do

Install optimizely-sdk package

What I expected to happen

I expected to have no warnings or errors.

What actually happened

npm WARN @optimizely/[email protected] requires a peer of @react-native-community/async-storage@^1.2.0 but none is installed. You must install peer dependencies yourself.

This dependency is not applicable for projects that are not using react-native, so it should not be marked as a required peerDep. It should be optional.

Steps to reproduce

npm i @optimizely/[email protected]

@optimizely/optimizely-sdk version: 4.0.0

optimizely-sdk test suite is not cleaning up properly (requires dirty --exit flag for mocha)

The optimizely-sdk test suite requires the --exit flag to mocha. This means the test suite is not cleaning up after itself properly.

Mocha provides some details about the flag, why it is indicative of problems, and some ways to find/fix the root cause.

I ran the following to uncover which of the many test files is causing node to hang:

set -x; for f in lib/**/*.tests.js; do npx mocha -r esm "$f"; done

The problematic file is lib/optimizely/index.tests.js (luckily only one file is causing node to hang).

@optimizely/optimizely-sdk version:
tested at 764135b

DECISION notification listener

With the introduction of DECISION as a replacement of ACTIVATE it is impossible to distinguish between events from activate and getVariation. This makes things very hard for us as we only want to log events from activate to Google Analytics or other 3rd party integrations.

On the documentation is not mentioned that getVariation can trigger this event, but it does:

DECISION triggers a callback with the decision type, associated decision information, user ID, and attributes. DECISION listeners trigger when you call Activate, Get Enabled Features, Get Feature Variable, or Is Feature Enabled.

@optimizely/optimizely-sdk version: 3.1.x

optimizely-client-sdk imports optimizely-server-sdk

Hi there,
I'm using Optimizely to run AB test on several Single Page Applications and found that optimizely-client-sdk imports optimizely-server-sdk. This was sort of unexpected but more important the final bundle size is significantly larger (see stats below)
screen shot 2017-04-19 at 09 54 32

This is an extreme case but even in an average case the whole of our application code is around 64KB (I'm talking about our application code excluding external dependencies). If you compare it with the 77KB of optimizely-server-sdk you can easily understand that it might have a big impact on our mobile users even when we don't run experiments.

Is there any plan to fix this situation? Is there something we can do in the meantime to reduce the "optimizely" SDK size impact on our JS bundles?

CI: hang (sometimes) on lerna boostrap in travis-ci

Several recent builds (including on master) have been hanging during lerna boostrap. With the aid of verbose logging via #130 I can see that they are actually hanging after this:

> [email protected] postinstall /home/travis/build/optimizely/javascript-sdk
> lerna bootstrap && lerna run build
lerna verb rootPath /home/travis/build/optimizely/javascript-sdk
lerna info version 2.11.0
lerna info versioning independent
lerna info Bootstrapping 1 packages
lerna info lifecycle preinstall
lerna verb dependencyIsSatisfied bluebird false
lerna verb dependencyIsSatisfied chai false
lerna verb dependencyIsSatisfied coveralls false
lerna verb dependencyIsSatisfied eslint false
lerna verb dependencyIsSatisfied grunt false
lerna verb dependencyIsSatisfied grunt-karma false
lerna verb dependencyIsSatisfied istanbul false
lerna verb dependencyIsSatisfied json-loader false
lerna verb dependencyIsSatisfied karma false
lerna verb dependencyIsSatisfied karma-browserstack-launcher false
lerna verb dependencyIsSatisfied karma-chai false
lerna verb dependencyIsSatisfied karma-chrome-launcher false
lerna verb dependencyIsSatisfied karma-mocha false
lerna verb dependencyIsSatisfied karma-sinon false
lerna verb dependencyIsSatisfied karma-webpack false
lerna verb dependencyIsSatisfied load-grunt-tasks false
lerna verb dependencyIsSatisfied mathjs false
lerna verb dependencyIsSatisfied mocha false
lerna verb dependencyIsSatisfied mocha-lcov-reporter false
lerna verb dependencyIsSatisfied nock false
lerna verb dependencyIsSatisfied sinon false
lerna verb dependencyIsSatisfied webpack false
lerna verb dependencyIsSatisfied json-schema false
lerna verb dependencyIsSatisfied lodash false
lerna verb dependencyIsSatisfied murmurhash false
lerna verb dependencyIsSatisfied sprintf false
lerna verb dependencyIsSatisfied uuid false
lerna info Installing external dependencies
lerna verb actions 1 actions, concurrency 4

When successful the remaining lines are

lerna verb installed leaf @optimizely/optimizely-sdk
lerna info Symlinking packages and binaries
lerna info lifecycle postinstall
lerna info lifecycle prepublish
lerna info lifecycle prepare
lerna success Bootstrapped 1 packages
lerna verb rootPath /home/travis/build/optimizely/javascript-sdk
lerna info version 2.11.0
lerna info versioning independent

I guess we'll have to dig into lerna to figure out what that means.

Cloudflare Worker runtime use issues

What I wanted to do

I would like to use the optimizely-sdk in a cloudflare worker (have been emailing/talking to @asaschachar about this use-case). Specifically, need the ability to:

  1. Use either features flags (rollouts) or assign experiment variations
  2. Track conversions events from the worker
  3. Update the datafile using a webhook
  4. Use a datafile from cloudflare k/v storage (updated via the webhook in point 3)

What I expected to happen

Add imports to @optimizely/optimizely-sdk, bundle with webpack, able to use the sdk in cloudflare workers.

What actually happened

The sdk failed when using the node version, because it couldn't find the Buffer object.
The sdk failed when using the browser version, because it couldn't find "localStorage".

Steps to reproduce

  1. Approach 1: Attempted to use the "node" version of the library "lib/index.node.js".
    Ran into incompatibilities with the "Buffer" node builtin.

optimizely-sdk: v3.2.0
webpack.config.js

const path = require('path');
module.exports = {
  target: 'webworker',
  optimization: {
    minimize: false,
  },
  resolve: {
    // Resolve module first, before main and browser,
    // so import from optimizely doesn't bring in the browser version
    mainFields: ['module', 'main', 'browser'],
  },
  output: {
    filename: 'worker.js',
    path: path.resolve(__dirname, 'build/'),
  },
};
worker.js:1366 Uncaught TypeError: Cannot read property 'TYPED_ARRAY_SUPPORT' of undefined
    at Object.<anonymous> (VM5 worker.js:1366)
    at Object.<anonymous> (VM5 worker.js:3114)
    at __webpack_require__ (VM5 worker.js:114)
    at Object.<anonymous> (VM5 worker.js:13317)
    at __webpack_require__ (VM5 worker.js:114)
    at Object.<anonymous> (VM5 worker.js:3872)
    at Object.<anonymous> (VM5 worker.js:3957)
    at __webpack_require__ (VM5 worker.js:114)
    at Object.<anonymous> (VM5 worker.js:12931)
    at __webpack_require__ (VM5 worker.js:114)

Attempted various alias'es for the Buffer module, and a polyfill (npm install buffer), but it unfortunately doesn't work.

  1. Approach 2: attempted to use the browser version of the optimizely library
    optimizely-sdk: v3.2.0

webpack.config.js

const path = require('path');
module.exports = {
  target: 'webworker',
  optimization: {
    minimize: false,
  },
  output: {
    filename: 'worker.js',
    path: path.resolve(__dirname, 'build/'),
  },
};
  ReferenceError: localStorage is not defined
          at LocalStorageStore.getMap (evalmachine.<anonymous>:10702:24)
          at LocalStorageStore.values (evalmachine.<anonymous>:10669:49)
          at LocalStoragePendingEventsDispatcher.PendingEventsDispatcher.sendPendingEvents (evalmachine.<anonymous>:10586:40)
          at Object.createInstance (evalmachine.<anonymous>:5353:32)
          at Object.<anonymous> (evalmachine.<anonymous>:5229:27)
          at Generator.next (<anonymous>)
          at fulfilled (evalmachine.<anonymous>:5169:58)
          at process._tickCallback (internal/process/next_tick.js:68:7)

This version technically "works", as in, it'll assign a feature (haven't checked if the activate calls are going through to our custom dispatcher, I'd guess that they aren't going through, because this happens in sendPendingEvents).

  1. Approach 3: Current optimizely-sdk master
    The unconditional wrapping of a custom dispatcher in the localStorage wrapper was removed in (#289). I manually linked to this build of the library, and the localStorage errors were no longer present.

@optimizely/optimizely-sdk version:3.2.0

Browser and version: Cloudflare Workers Environment

node version: 10.15.3

webpack version: 4.29.6

promise-polyfill in sdk

Hey Optimizely team. First, thx for this great SDK ❀️

One thing we just found implementing it in my company is that you have the dependency to promise-polyfill. This adds up to the bundle size. IMHO adding polyfills should be the job of the application, not a library.

How would the enhancement work?

  • remove the polyfill, or
  • offer a version w/o polyfills

When would the enhancement be useful?

When the application already have a polyfill (e.g. polyfill.io)

Thx in advance!
Toni

Enhancement request: `.close()` should wait for in-flight requests to complete

How would the enhancement work?

Currently, the optimizely.close() Promise will send and wait for any pending events. However, it does not wait for the completion of events that are in the progress of being sent.

When would the enhancement be useful?

To avoid events half way through being sent getting cancelled before sending is complete.

@optimizely/optimizely-sdk version: 3.3.2

(nodejs) Failure to log "success" message when event dispatched

Since #98, the requestCallback never gets called with a second argument, because its role is a 'response' handler for HttpClientRequest:

The optional callback parameter will be added as a one-time listener for the 'response' event.
src: https://nodejs.org/api/http.html#http_http_request_options_callback

As a result, the callback defined in __dispatchEvent currently never gets called in nodejs, and as a result we don't log any messages for LOG_MESSAGES.ACTIVATE_USER or LOG_MESSAGES.TRACK_EVENT.

Add test for window.optimizelySdk usage

We should have a test that the built package exposes the right thing, since that only lives in the bundling config and could be messed up without affecting the unit tests. Probably would need to be some kind of "integration" test that uses the built files in dist.

Logging methods have no effect in v4 ESM bundle

What I wanted to do

Change the default log level

What I expected to happen

I expected info and debug level messages to start being written to the console
( the fetching of datafile, etc)

What actually happened

Nothing

Steps to reproduce

// foo.js
import sdk from '@optimizely/optimizely-sdk'

function createInstance() {
  sdk.setLogLevel('debug')
  return sdk.createInstance({sdkKey})
}

createInstance()

@optimizely/optimizely-sdk version: 4.0.0

Compiled using rollup:

{
  input: "foo.js",
  plugins: [
    resolve({mainFields: ['module', 'browser']}),
    common({
      namedExports: {
        '@optimizely/js-sdk-logging': [
          'ConsoleLogHandler',
          'getLogger',
          'setLogLevel',
          'LogLevel',
          'setLogHandler',
          'setErrorHandler',
          'getErrorHandler'
        ],
        '@optimizely/js-sdk-event-processor': [
          'LogTierV1EventProcessor',
          'LocalStoragePendingEventsDispatcher'
        ]
      }
    })
  ],
  ...
}

I further provided an invalid sdkKey to trigger ERROR level log messages. They did not log either. Nor did anything get logged when I made the sdk options argument entirely empty (sdk.createInstance({}))

My suspicion is that this isn't an issue with the logger at all, but more of an issue with the ESM bundle (which is new as of v4). I suspect that the logger plugin is not properly working with the js-sdk-logging external dep.

Distributed module file sizes for react-sdk and optimizely-sdk are large

The following modules are pretty large in filesize, and it'd be great to have them reduced:

@optimizely/[email protected]
132kB minified

[email protected]
114kB minified

This has a notable performance impact for consumers of the modules (like me), and their end users. 244k adds over 1 second of download time (3G) and delays user interactivity.
The file size is also high in comparison with other libraries used by web apps. For example redux = 7.2kB, all of lodash = 69.2kB, vue = 63.5kB, etc.

It'd be fantastic if the bundle sizes could be reduced dramatically, down to < 50k combined.

A couple clues I'd noticed that may be useful for optimizing the size:

  1. There was a large size increase for react-sdk from 0.2.0-beta1 (11kB) to 0.3.0-beta1 (132kB)
  2. The logging strings add a lot to the file size.

@optimizely/optimizely-sdk version: 3.2.1
@optimizely/[email protected] version: 0.3.0-beta1

Browser and version:

node version: 10.16.0
npm version: 6.9.0

Binary feature rollouts without user id always return false

optimizely.isFeatureEnabled('flagkey') always return false when a userId isn't provided.

Would be cool if the userId isn't required. Sometimes you don't care about rollout percentages and you just want it on or off for all users so passing a user-id would be meaningless.

Thoughts?

Whitelisting doesn't update the User Profile Service

What I wanted to do

When implementing a User Profile Service (UPS) I noticed that whitelisted users don't update the User Profile Service.

What I expected to happen

Based on the documentation User Profile Service is updated after returning a variation, the flow goes like this:

Return Variation -> Track -> Update UPS

866c238-sdk_flowchart_updated_bucketingID

But on the code, you can see that if the user is whitelisted __saveUserProfile is unreachable.

@optimizely/optimizely-sdk version:3.1.0

Make package more bundling-friendly

I've pulled @optimizely/optimizely-sdk into our client-side code, and according to the webpack visualizer tool, this delta occurs in the bundle size (it uses an estimate for actuals):

Raw: +307.2K
Actual: +77.2K

I've noticed that you're distributing this library as a webpack bundle. This is a bad idea because you're bundling in dependencies that may be in common with those of the consuming app. By me simply importing @optimizely/optimizely-sdk/lib/index.browser, this changes the delta significantly:

Raw: +102.4K
Actual: +53.5K

This is because we're also using lodash. We're also using uuid, though it's a different version, so making the dependency version looser on that, we could shave off a bit more (though that library is pretty tiny).

I'd recommend changing package.json such that the entry point is not a bundled build but rather is your library. That way webpack/browserify/rollup for the consuming app can make something much smaller.

Typescript build fails when using isolatedModules flag

What I wanted to do

I tried to build a project using this lib with typescript. I have the isolatedModules flag set to true due to the use of babel.

What I expected to happen

It to build correctly

What actually happened

I got the error:

../node_modules/@optimizely/optimizely-sdk/lib/core/event_processor/index.ts:25:10
Type error: Re-exporting a type when the '--isolatedModules' flag is provided requires using 'export type'.

  23 | }
  24 | 
> 25 | export { EventProcessor, LocalStoragePendingEventsDispatcher } from '@optimizely/js-sdk-event-processor';
     |          ^
  26 | 
  27 | export default { createEventProcessor, LocalStoragePendingEventsDispatcher };

Steps to reproduce

SDK version: 3.2.2
Node version: v12.18.0
NPM version: 6.14.4
Typescript version: 3.9.7

Use tsconfig with isolatedModules set to true
Run tsc
See error

Stop using lodash

Related: #47

Using version 3.0.1. See here: https://bundlephobia.com/result?p=@optimizely/[email protected]

  • Bundle is 83.7 kB minified, 22.4 kB gzipped
  • Nearly 40% of that size is lodash -- 33 kB of the bundle is lodash!
  • Without lodash your bundle would be closer to 50 kB minified, a huge savings.

We're seeing that it does indeed add lodash into our final bundle. We're using latest webpack/babel. We forked our configs from create-react-app. Removing lodash or changing how you depend on it will dramatically decrease your bundle size for all of your customers.

You aren't really using lodash that much: https://github.com/optimizely/javascript-sdk/search?q=%22require%28%27lodash%22&unscoped_q=%22require%28%27lodash%22

Options:

Fails to install on latest LTS node (12.16.1)

What I wanted to do

clone and npm-install javascript-sdk

What I expected to happen

successful npm install

What actually happened

node-gyp compilation errors for fs-events

make: *** [Release/obj.target/fse/fsevents.o] Error 1

[email protected] install /Users/jasonkarns/Projects/optimizely-javascript-sdk/packages/optimizely-sdk/node_modules/fsevents
node install

node-pre-gyp WARN Tried to download(404): https://fsevents-binaries.s3-us-west-2.amazonaws.com/v1.2.4/fse-v1.2.4-node-v72-darwin-x64.tar.gz
node-pre-gyp WARN Pre-built binaries not found for [email protected] and [email protected] (node-v72 ABI, unknown) (falling back to source compile with node-gyp)
SOLINK_MODULE(target) Release/.node
CXX(target) Release/obj.target/fse/fsevents.o
In file included from ../fsevents.cc:6:
In file included from ../../nan/nan.h:202:
In file included from ../../nan/nan_converters.h:67:
../../nan/nan_converters_43_inl.h:22:1: warning: 'ToBoolean' is deprecated: ToBoolean can never throw. Use Local version. [-Wdeprecated-declarations]
X(Boolean)
^
../../nan/nan_converters_43_inl.h:18:12: note: expanded from macro 'X'
val->To ## TYPE(isolate->GetCurrentContext())
^
:204:1: note: expanded from here
ToBoolean
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:2663:3: note: 'ToBoolean' has been explicitly marked deprecated here
V8_DEPRECATED("ToBoolean can never throw. Use Local version.",
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8config.h:328:29: note: expanded from macro 'V8_DEPRECATED'
declarator attribute((deprecated(message)))
^
In file included from ../fsevents.cc:6:
In file included from ../../nan/nan.h:202:
In file included from ../../nan/nan_converters.h:67:
../../nan/nan_converters_43_inl.h:40:1: warning: 'BooleanValue' is deprecated: BooleanValue can never throw. Use Isolate version. [-Wdeprecated-declarations]
X(bool, Boolean)
^
../../nan/nan_converters_43_inl.h:37:15: note: expanded from macro 'X'
return val->NAME ## Value(isolate->GetCurrentContext());
^
:211:1: note: expanded from here
BooleanValue
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:2701:3: note: 'BooleanValue' has been explicitly marked deprecated here
V8_DEPRECATED("BooleanValue can never throw. Use Isolate version.",
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8config.h:328:29: note: expanded from macro 'V8_DEPRECATED'
declarator attribute((deprecated(message)))
^
In file included from ../fsevents.cc:6:
In file included from ../../nan/nan.h:203:
In file included from ../../nan/nan_new.h:189:
../../nan/nan_implementation_12_inl.h:103:42: error: no viable conversion from 'v8::Isolate *' to 'Localv8::Context'
return scope.Escape(v8::Function::New( isolate
^~~~~~~
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:186:7: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'v8::Isolate *' to 'const v8::Localv8::Context &' for 1st argument
class Local {
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:186:7: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'v8::Isolate ' to 'v8::Localv8::Context &&' for 1st argument
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:190:13: note: candidate template ignored: could not match 'Local' against 'v8::Isolate '
V8_INLINE Local(Local<S> that)
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:4276:22: note: passing argument to parameter 'context' here
Local context, FunctionCallback callback,
^
In file included from ../fsevents.cc:6:
In file included from ../../nan/nan.h:203:
In file included from ../../nan/nan_new.h:189:
../../nan/nan_implementation_12_inl.h:337:37: error: too few arguments to function call, expected 2, have 1
return v8::StringObject::New(value).Asv8::StringObject();
~~~~~~~~~~~~~~~~~~~~~ ^
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:5531:3: note: 'New' declared here
static Local New(Isolate
isolate, Local value);
^
In file included from ../fsevents.cc:6:
../../nan/nan.h:1034:44: error: no matching member function for call to 'ToString'
v8::Localv8::String string = from->ToString();
~~~~~~^~~~~~~~
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:2668:44: note: candidate function not viable: requires single argument 'context', but no arguments were provided
V8_WARN_UNUSED_RESULT MaybeLocal ToString(
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:2684:31: note: candidate function not viable: requires single argument 'isolate', but no arguments were provided
Local ToString(Isolate
isolate) const);
^
In file included from ../fsevents.cc:6:
../../nan/nan.h:1044:37: error: cannot initialize a parameter of type 'v8::Isolate ' with an lvalue of type 'char '
length_ = string->WriteUtf8(str_, static_cast(len), 0, flags);
^~~~
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:2878:26: note: passing argument to parameter 'isolate' here
int WriteUtf8(Isolate
isolate, char
buffer, int length = -1,
^
In file included from ../fsevents.cc:6:
../../nan/nan.h:1818:28: warning: 'Set' is deprecated: Use maybe version [-Wdeprecated-declarations]
New(persistentHandle)->Set(New(key).ToLocalChecked(), value);
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:3498:3: note: 'Set' has been explicitly marked deprecated here
V8_DEPRECATED("Use maybe version",
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8config.h:328:29: note: expanded from macro 'V8_DEPRECATED'
declarator attribute((deprecated(message)))
^
In file included from ../fsevents.cc:6:
../../nan/nan.h:1824:28: warning: 'Set' is deprecated: Use maybe version [-Wdeprecated-declarations]
New(persistentHandle)->Set(key, value);
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:3498:3: note: 'Set' has been explicitly marked deprecated here
V8_DEPRECATED("Use maybe version",
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8config.h:328:29: note: expanded from macro 'V8_DEPRECATED'
declarator attribute((deprecated(message)))
^
In file included from ../fsevents.cc:6:
../../nan/nan.h:1830:28: warning: 'Set' is deprecated: Use maybe version [-Wdeprecated-declarations]
New(persistentHandle)->Set(index, value);
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:3507:3: note: 'Set' has been explicitly marked deprecated here
V8_DEPRECATED("Use maybe version",
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8config.h:328:29: note: expanded from macro 'V8_DEPRECATED'
declarator attribute((deprecated(message)))
^
In file included from ../fsevents.cc:6:
../../nan/nan.h:1836:32: warning: 'Get' is deprecated: Use maybe version [-Wdeprecated-declarations]
New(persistentHandle)->Get(New(key).ToLocalChecked()));
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:3553:3: note: 'Get' has been explicitly marked deprecated here
V8_DEPRECATED("Use maybe version", Local Get(Local key));
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8config.h:328:29: note: expanded from macro 'V8_DEPRECATED'
declarator attribute((deprecated(message)))
^
In file included from ../fsevents.cc:6:
../../nan/nan.h:1842:48: warning: 'Get' is deprecated: Use maybe version [-Wdeprecated-declarations]
return scope.Escape(New(persistentHandle)->Get(key));
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:3553:3: note: 'Get' has been explicitly marked deprecated here
V8_DEPRECATED("Use maybe version", Local Get(Local key));
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8config.h:328:29: note: expanded from macro 'V8_DEPRECATED'
declarator attribute((deprecated(message)))
^
In file included from ../fsevents.cc:6:
../../nan/nan.h:1847:48: warning: 'Get' is deprecated: Use maybe version [-Wdeprecated-declarations]
return scope.Escape(New(persistentHandle)->Get(index));
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:3557:3: note: 'Get' has been explicitly marked deprecated here
V8_DEPRECATED("Use maybe version", Local Get(uint32_t index));
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8config.h:328:29: note: expanded from macro 'V8_DEPRECATED'
declarator attribute((deprecated(message)))
^
In file included from ../fsevents.cc:6:
In file included from ../../nan/nan.h:2657:
../../nan/nan_object_wrap.h:24:25: error: no member named 'IsNearDeath' in 'Nan::Persistent<v8::Object, v8::NonCopyablePersistentTraitsv8::Object >'
assert(persistent().IsNearDeath());
~~~~~~~~~~~~ ^
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/assert.h:93:25: note: expanded from macro 'assert'
(__builtin_expect(!(e), 0) ? _assert_rtn(func, FILE, LINE, #e) : (void)0)
^
In file included from ../fsevents.cc:6:
In file included from ../../nan/nan.h:2657:
../../nan/nan_object_wrap.h:67:18: warning: 'MarkIndependent' is deprecated: Weak objects are always considered independent. Use TracedGlobal when trying to use EmbedderHeapTracer. Use a strong handle when trying to keep an object alive. [-Wdeprecated-declarations]
persistent().MarkIndependent();
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:566:3: note: 'MarkIndependent' has been explicitly marked deprecated here
V8_DEPRECATED(
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8config.h:328:29: note: expanded from macro 'V8_DEPRECATED'
declarator attribute((deprecated(message)))
^
In file included from ../fsevents.cc:6:
In file included from ../../nan/nan.h:2657:
../../nan/nan_object_wrap.h:124:26: error: no member named 'IsNearDeath' in 'Nan::Persistent<v8::Object, v8::NonCopyablePersistentTraitsv8::Object >'
assert(wrap->handle
.IsNearDeath());
~~~~~~~~~~~~~ ^
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/assert.h:93:25: note: expanded from macro 'assert'
(__builtin_expect(!(e), 0) ? __assert_rtn(func, FILE, LINE, #e) : (void)0)
^
../fsevents.cc:50:32: error: no template named 'Handle' in namespace 'v8'
static void Initialize(v8::Handlev8::Object exports);
~~~~^
../fsevents.cc:63:6: warning: field 'async_resource' will be initialized after field 'lockStarted' [-Wreorder]
: async_resource("fsevents:FSEvents"), lockStarted(false) {
^
In file included from ../fsevents.cc:82:
../src/constants.cc:89:11: warning: 'Set' is deprecated: Use maybe version [-Wdeprecated-declarations]
object->Set(Nan::Newv8::String("kFSEventStreamEventFlagNone").ToLocalChecked(), Nan::Newv8::Integer(kFSEventStreamEventFlagNone));
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:3498:3: note: 'Set' has been explicitly marked deprecated here
V8_DEPRECATED("Use maybe version",
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8config.h:328:29: note: expanded from macro 'V8_DEPRECATED'
declarator attribute((deprecated(message)))
^
In file included from ../fsevents.cc:82:
../src/constants.cc:90:11: warning: 'Set' is deprecated: Use maybe version [-Wdeprecated-declarations]
object->Set(Nan::Newv8::String("kFSEventStreamEventFlagMustScanSubDirs").ToLocalChecked(), Nan::Newv8::Integer(kFSEventStreamEventFlagMustScanSubDirs));
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:3498:3: note: 'Set' has been explicitly marked deprecated here
V8_DEPRECATED("Use maybe version",
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8config.h:328:29: note: expanded from macro 'V8_DEPRECATED'
declarator attribute((deprecated(message)))
^
In file included from ../fsevents.cc:82:
../src/constants.cc:91:11: warning: 'Set' is deprecated: Use maybe version [-Wdeprecated-declarations]
object->Set(Nan::Newv8::String("kFSEventStreamEventFlagUserDropped").ToLocalChecked(), Nan::Newv8::Integer(kFSEventStreamEventFlagUserDropped));
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:3498:3: note: 'Set' has been explicitly marked deprecated here
V8_DEPRECATED("Use maybe version",
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8config.h:328:29: note: expanded from macro 'V8_DEPRECATED'
declarator attribute((deprecated(message)))
^
In file included from ../fsevents.cc:82:
../src/constants.cc:92:11: warning: 'Set' is deprecated: Use maybe version [-Wdeprecated-declarations]
object->Set(Nan::Newv8::String("kFSEventStreamEventFlagKernelDropped").ToLocalChecked(), Nan::Newv8::Integer(kFSEventStreamEventFlagKernelDropped));
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:3498:3: note: 'Set' has been explicitly marked deprecated here
V8_DEPRECATED("Use maybe version",
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8config.h:328:29: note: expanded from macro 'V8_DEPRECATED'
declarator attribute((deprecated(message)))
^
In file included from ../fsevents.cc:82:
../src/constants.cc:93:11: warning: 'Set' is deprecated: Use maybe version [-Wdeprecated-declarations]
object->Set(Nan::Newv8::String("kFSEventStreamEventFlagEventIdsWrapped").ToLocalChecked(), Nan::Newv8::Integer(kFSEventStreamEventFlagEventIdsWrapped));
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:3498:3: note: 'Set' has been explicitly marked deprecated here
V8_DEPRECATED("Use maybe version",
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8config.h:328:29: note: expanded from macro 'V8_DEPRECATED'
declarator attribute((deprecated(message)))
^
In file included from ../fsevents.cc:82:
../src/constants.cc:94:11: warning: 'Set' is deprecated: Use maybe version [-Wdeprecated-declarations]
object->Set(Nan::Newv8::String("kFSEventStreamEventFlagHistoryDone").ToLocalChecked(), Nan::Newv8::Integer(kFSEventStreamEventFlagHistoryDone));
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:3498:3: note: 'Set' has been explicitly marked deprecated here
V8_DEPRECATED("Use maybe version",
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8config.h:328:29: note: expanded from macro 'V8_DEPRECATED'
declarator attribute((deprecated(message)))
^
In file included from ../fsevents.cc:82:
../src/constants.cc:95:11: warning: 'Set' is deprecated: Use maybe version [-Wdeprecated-declarations]
object->Set(Nan::Newv8::String("kFSEventStreamEventFlagRootChanged").ToLocalChecked(), Nan::Newv8::Integer(kFSEventStreamEventFlagRootChanged));
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:3498:3: note: 'Set' has been explicitly marked deprecated here
V8_DEPRECATED("Use maybe version",
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8config.h:328:29: note: expanded from macro 'V8_DEPRECATED'
declarator attribute((deprecated(message)))
^
In file included from ../fsevents.cc:82:
../src/constants.cc:96:11: warning: 'Set' is deprecated: Use maybe version [-Wdeprecated-declarations]
object->Set(Nan::Newv8::String("kFSEventStreamEventFlagMount").ToLocalChecked(), Nan::Newv8::Integer(kFSEventStreamEventFlagMount));
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:3498:3: note: 'Set' has been explicitly marked deprecated here
V8_DEPRECATED("Use maybe version",
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8config.h:328:29: note: expanded from macro 'V8_DEPRECATED'
declarator attribute((deprecated(message)))
^
In file included from ../fsevents.cc:82:
../src/constants.cc:97:11: warning: 'Set' is deprecated: Use maybe version [-Wdeprecated-declarations]
object->Set(Nan::Newv8::String("kFSEventStreamEventFlagUnmount").ToLocalChecked(), Nan::Newv8::Integer(kFSEventStreamEventFlagUnmount));
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:3498:3: note: 'Set' has been explicitly marked deprecated here
V8_DEPRECATED("Use maybe version",
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8config.h:328:29: note: expanded from macro 'V8_DEPRECATED'
declarator attribute((deprecated(message)))
^
In file included from ../fsevents.cc:82:
../src/constants.cc:98:11: warning: 'Set' is deprecated: Use maybe version [-Wdeprecated-declarations]
object->Set(Nan::Newv8::String("kFSEventStreamEventFlagItemCreated").ToLocalChecked(), Nan::Newv8::Integer(kFSEventStreamEventFlagItemCreated));
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:3498:3: note: 'Set' has been explicitly marked deprecated here
V8_DEPRECATED("Use maybe version",
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8config.h:328:29: note: expanded from macro 'V8_DEPRECATED'
declarator attribute((deprecated(message)))
^
In file included from ../fsevents.cc:82:
../src/constants.cc:99:11: warning: 'Set' is deprecated: Use maybe version [-Wdeprecated-declarations]
object->Set(Nan::Newv8::String("kFSEventStreamEventFlagItemRemoved").ToLocalChecked(), Nan::Newv8::Integer(kFSEventStreamEventFlagItemRemoved));
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:3498:3: note: 'Set' has been explicitly marked deprecated here
V8_DEPRECATED("Use maybe version",
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8config.h:328:29: note: expanded from macro 'V8_DEPRECATED'
declarator attribute((deprecated(message)))
^
In file included from ../fsevents.cc:82:
../src/constants.cc:100:11: warning: 'Set' is deprecated: Use maybe version [-Wdeprecated-declarations]
object->Set(Nan::Newv8::String("kFSEventStreamEventFlagItemInodeMetaMod").ToLocalChecked(), Nan::Newv8::Integer(kFSEventStreamEventFlagItemInodeMetaMod));
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:3498:3: note: 'Set' has been explicitly marked deprecated here
V8_DEPRECATED("Use maybe version",
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8config.h:328:29: note: expanded from macro 'V8_DEPRECATED'
declarator attribute((deprecated(message)))
^
In file included from ../fsevents.cc:82:
../src/constants.cc:101:11: warning: 'Set' is deprecated: Use maybe version [-Wdeprecated-declarations]
object->Set(Nan::Newv8::String("kFSEventStreamEventFlagItemRenamed").ToLocalChecked(), Nan::Newv8::Integer(kFSEventStreamEventFlagItemRenamed));
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:3498:3: note: 'Set' has been explicitly marked deprecated here
V8_DEPRECATED("Use maybe version",
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8config.h:328:29: note: expanded from macro 'V8_DEPRECATED'
declarator attribute((deprecated(message)))
^
In file included from ../fsevents.cc:82:
../src/constants.cc:102:11: warning: 'Set' is deprecated: Use maybe version [-Wdeprecated-declarations]
object->Set(Nan::Newv8::String("kFSEventStreamEventFlagItemModified").ToLocalChecked(), Nan::Newv8::Integer(kFSEventStreamEventFlagItemModified));
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:3498:3: note: 'Set' has been explicitly marked deprecated here
V8_DEPRECATED("Use maybe version",
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8config.h:328:29: note: expanded from macro 'V8_DEPRECATED'
declarator attribute((deprecated(message)))
^
In file included from ../fsevents.cc:82:
../src/constants.cc:103:11: warning: 'Set' is deprecated: Use maybe version [-Wdeprecated-declarations]
object->Set(Nan::Newv8::String("kFSEventStreamEventFlagItemFinderInfoMod").ToLocalChecked(), Nan::Newv8::Integer(kFSEventStreamEventFlagItemFinderInfoMod));
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:3498:3: note: 'Set' has been explicitly marked deprecated here
V8_DEPRECATED("Use maybe version",
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8config.h:328:29: note: expanded from macro 'V8_DEPRECATED'
declarator attribute((deprecated(message)))
^
In file included from ../fsevents.cc:82:
../src/constants.cc:104:11: warning: 'Set' is deprecated: Use maybe version [-Wdeprecated-declarations]
object->Set(Nan::Newv8::String("kFSEventStreamEventFlagItemChangeOwner").ToLocalChecked(), Nan::Newv8::Integer(kFSEventStreamEventFlagItemChangeOwner));
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:3498:3: note: 'Set' has been explicitly marked deprecated here
V8_DEPRECATED("Use maybe version",
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8config.h:328:29: note: expanded from macro 'V8_DEPRECATED'
declarator attribute((deprecated(message)))
^
In file included from ../fsevents.cc:82:
../src/constants.cc:105:11: warning: 'Set' is deprecated: Use maybe version [-Wdeprecated-declarations]
object->Set(Nan::Newv8::String("kFSEventStreamEventFlagItemXattrMod").ToLocalChecked(), Nan::Newv8::Integer(kFSEventStreamEventFlagItemXattrMod));
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:3498:3: note: 'Set' has been explicitly marked deprecated here
V8_DEPRECATED("Use maybe version",
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8config.h:328:29: note: expanded from macro 'V8_DEPRECATED'
declarator attribute((deprecated(message)))
^
In file included from ../fsevents.cc:82:
../src/constants.cc:106:11: warning: 'Set' is deprecated: Use maybe version [-Wdeprecated-declarations]
object->Set(Nan::Newv8::String("kFSEventStreamEventFlagItemIsFile").ToLocalChecked(), Nan::Newv8::Integer(kFSEventStreamEventFlagItemIsFile));
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:3498:3: note: 'Set' has been explicitly marked deprecated here
V8_DEPRECATED("Use maybe version",
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8config.h:328:29: note: expanded from macro 'V8_DEPRECATED'
declarator attribute((deprecated(message)))
^
In file included from ../fsevents.cc:82:
../src/constants.cc:107:11: warning: 'Set' is deprecated: Use maybe version [-Wdeprecated-declarations]
object->Set(Nan::Newv8::String("kFSEventStreamEventFlagItemIsDir").ToLocalChecked(), Nan::Newv8::Integer(kFSEventStreamEventFlagItemIsDir));
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:3498:3: note: 'Set' has been explicitly marked deprecated here
V8_DEPRECATED("Use maybe version",
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8config.h:328:29: note: expanded from macro 'V8_DEPRECATED'
declarator attribute((deprecated(message)))
^
In file included from ../fsevents.cc:82:
../src/constants.cc:108:11: warning: 'Set' is deprecated: Use maybe version [-Wdeprecated-declarations]
object->Set(Nan::Newv8::String("kFSEventStreamEventFlagItemIsSymlink").ToLocalChecked(), Nan::Newv8::Integer(kFSEventStreamEventFlagItemIsSymlink));
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8.h:3498:3: note: 'Set' has been explicitly marked deprecated here
V8_DEPRECATED("Use maybe version",
^
/usr/local/cache/node-gyp/12.16.1/include/node/v8config.h:328:29: note: expanded from macro 'V8_DEPRECATED'
declarator attribute((deprecated(message)))
^
../fsevents.cc:85:16: error: variable has incomplete type 'void'
void FSEvents::Initialize(v8::Handlev8::Object exports) {
^
../fsevents.cc:85:31: error: no member named 'Handle' in namespace 'v8'
void FSEvents::Initialize(v8::Handlev8::Object exports) {
~~~~^
../fsevents.cc:85:48: error: expected '(' for function-style cast or type construction
void FSEvents::Initialize(v8::Handlev8::Object exports) {
~~~~~~~~~~^
../fsevents.cc:85:50: error: use of undeclared identifier 'exports'
void FSEvents::Initialize(v8::Handlev8::Object exports) {
^
../fsevents.cc:85:58: error: expected ';' after top level declarator
void FSEvents::Initialize(v8::Handlev8::Object exports) {
^
;
30 warnings and 12 errors generated.
make: *** [Release/obj.target/fse/fsevents.o] Error 1
gyp ERR! build error
gyp ERR! stack Error: make failed with exit code: 2
gyp ERR! stack at ChildProcess.onExit (/usr/local/var/nodenv/versions/12.16.1/lib/node_modules/npm/node_modules/node-gyp/lib/build.js:194:23)
gyp ERR! stack at ChildProcess.emit (events.js:311:20)
gyp ERR! stack at Process.ChildProcess._handle.onexit (internal/child_process.js:275:12)
gyp ERR! System Darwin 19.3.0
gyp ERR! command "/usr/local/var/nodenv/versions/12.16.1/bin/node" "/usr/local/var/nodenv/versions/12.16.1/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "build" "--fallback-to-build" "--module=/Users/jasonkarns/Projects/optimizely-javascript-sdk/packages/optimizely-sdk/node_modules/fsevents/lib/binding/Release/node-v72-darwin-x64/fse.node" "--module_name=fse" "--module_path=/Users/jasonkarns/Projects/optimizely-javascript-sdk/packages/optimizely-sdk/node_modules/fsevents/lib/binding/Release/node-v72-darwin-x64" "--napi_version=5" "--node_abi_napi=napi"
gyp ERR! cwd /Users/jasonkarns/Projects/optimizely-javascript-sdk/packages/optimizely-sdk/node_modules/fsevents
gyp ERR! node -v v12.16.1
gyp ERR! node-gyp -v v5.0.5
gyp ERR! not ok
node-pre-gyp ERR! build error
node-pre-gyp ERR! stack Error: Failed to execute '/usr/local/var/nodenv/versions/12.16.1/bin/node /usr/local/var/nodenv/versions/12.16.1/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js build --fallback-to-build --module=/Users/jasonkarns/Projects/optimizely-javascript-sdk/packages/optimizely-sdk/node_modules/fsevents/lib/binding/Release/node-v72-darwin-x64/fse.node --module_name=fse --module_path=/Users/jasonkarns/Projects/optimizely-javascript-sdk/packages/optimizely-sdk/node_modules/fsevents/lib/binding/Release/node-v72-darwin-x64 --napi_version=5 --node_abi_napi=napi' (1)
node-pre-gyp ERR! stack at ChildProcess. (/Users/jasonkarns/Projects/optimizely-javascript-sdk/packages/optimizely-sdk/node_modules/fsevents/node_modules/node-pre-gyp/lib/util/compile.js:83:29)
node-pre-gyp ERR! stack at ChildProcess.emit (events.js:311:20)
node-pre-gyp ERR! stack at maybeClose (internal/child_process.js:1021:16)
node-pre-gyp ERR! stack at Process.ChildProcess._handle.onexit (internal/child_process.js:286:5)
node-pre-gyp ERR! System Darwin 19.3.0
node-pre-gyp ERR! command "/usr/local/var/nodenv/versions/12.16.1/bin/node" "/Users/jasonkarns/Projects/optimizely-javascript-sdk/packages/optimizely-sdk/node_modules/fsevents/node_modules/node-pre-gyp/bin/node-pre-gyp" "install" "--fallback-to-build"
node-pre-gyp ERR! cwd /Users/jasonkarns/Projects/optimizely-javascript-sdk/packages/optimizely-sdk/node_modules/fsevents
node-pre-gyp ERR! node -v v12.16.1
node-pre-gyp ERR! node-pre-gyp -v v0.10.0
node-pre-gyp ERR! not ok
Failed to execute '/usr/local/var/nodenv/versions/12.16.1/bin/node /usr/local/var/nodenv/versions/12.16.1/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js build --fallback-to-build --module=/Users/jasonkarns/Projects/optimizely-javascript-sdk/packages/optimizely-sdk/node_modules/fsevents/lib/binding/Release/node-v72-darwin-x64/fse.node --module_name=fse --module_path=/Users/jasonkarns/Projects/optimizely-javascript-sdk/packages/optimizely-sdk/node_modules/fsevents/lib/binding/Release/node-v72-darwin-x64 --napi_version=5 --node_abi_napi=napi' (1)
npm WARN [email protected] requires a peer of acorn@^6.0.0 || ^7.0.0 but none is installed. You must install peer dependencies yourself.
npm WARN [email protected] requires a peer of webpack@^2.0.0 || ^3.0.0 but none is installed. You must install peer dependencies yourself.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: [email protected] (node_modules/fsevents):
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: [email protected] install: node install
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: Exit status 1

up to date in 15.566s

2 packages are looking for funding
run npm fund for details

Steps to reproduce

  • git clone
  • cd packages/optimizely-sdk
  • npm i

@optimizely/optimizely-sdk version:
master

node version:
v12.16.1

npm version:
6.13.4

Versions of any other relevant tools (like module bundlers, transpilers, etc.):

optimizely-sdk test suite has cross-test-file pollution

While researching which file is causing the node process to hang during the test suite (#487 ), I ran each test file individually.

In doing so, I discovered that the lib/plugins/event_dispatcher/index.browser.tests.js test file does not pass successfully when run independently. That means it is dependent (accidentally) on some side effect that another test file is causing.

$ npx mocha -r esm -r lib/tests/exit_on_unhandled_rejection.js lib/plugins/event_dispatcher/index.browser.tests.js


  lib/plugins/event_dispatcher/browser
    APIs
      dispatchEvent
        1) should send a POST request with the specified params
        2) should execute the callback passed to event dispatcher with a post
        3) should execute the callback passed to event dispatcher with a get


  0 passing (10ms)
  3 failing

  1) lib/plugins/event_dispatcher/browser
       APIs
         dispatchEvent
           should send a POST request with the specified params:
     ReferenceError: XMLHttpRequest is not defined
      at dispatchEvent (lib/plugins/event_dispatcher/index.browser.js:31:5)
      at Context.<anonymous> (lib/plugins/event_dispatcher/index.browser.tests.js:50:9)
      at process.topLevelDomainCallback (domain.js:126:23)

  2) lib/plugins/event_dispatcher/browser
       APIs
         dispatchEvent
           should execute the callback passed to event dispatcher with a post:
     ReferenceError: XMLHttpRequest is not defined
      at dispatchEvent (lib/plugins/event_dispatcher/index.browser.js:31:5)
      at Context.<anonymous> (lib/plugins/event_dispatcher/index.browser.tests.js:69:9)
      at process.topLevelDomainCallback (domain.js:126:23)

  3) lib/plugins/event_dispatcher/browser
       APIs
         dispatchEvent
           should execute the callback passed to event dispatcher with a get:
     ReferenceError: XMLHttpRequest is not defined
      at dispatchEvent (lib/plugins/event_dispatcher/index.browser.js:51:5)
      at Context.<anonymous> (lib/plugins/event_dispatcher/index.browser.tests.js:86:9)
      at process.topLevelDomainCallback (domain.js:126:23)

@optimizely/optimizely-sdk version:

tested at 764135b

[Bug] Restore exported types defined in `shared_types`

What I wanted to do

Continue to use exported types defined in https://github.com/optimizely/javascript-sdk/blob/master/packages/optimizely-sdk/lib/shared_types.ts

These used to be exported from the package. We are maintaining libraries that depend on these types.

Please export them from index.d.ts

What I expected to happen

UserProfileService type should be useable as a named export.
OptimizelyConfig type should be useable as a named export.

What actually happened

These types may be able to be imported - but we have to do it much more indirectly. Please continue to just export them.

Expose usable method(s) to grab the user's variation for a feature test

How would the enhancement work?

This is an idea proposal for exposing a getVariationForFeature-like method (s) directly on the optimizelyClientInstance so developers can quickly figure out and directly reference the variation the user is bucketed in for a Optimizely Fullstack feature test. Currently we must use a hack of seeing whether a feature is enabled for a user (via .isFeatureEnabled()) and what feature variables we set to differentiate between multiple different feature test variants (via .getFeatureVariableBoolean or getFeatureVariableString).

Similar to how the sdk has already exposed a method we can use to grab an AB experiment's variation, there'll probably be 2 separate methods that will:

  1. trigger/log the impression back to Optimizely and also return the variation
  2. only return the variation (won't create an impression)

--
Side note: I noticed in this codebase line referencing optimizelyInstance.getVariationForFeature that there already is a way to grab the feature test but it's not exposed as a method we can directly call off the Optimizely client instance.

When would the enhancement be useful?

Next release if possible! We have more feature tests coming in where it would be helpful to be able to directly reference a feature test variant in code, rather than "guess" the variant with more complicated code.

@optimizely/optimizely-sdk version: 3.5.0 (pretty much all current versions)

global export

I see that the SDK compiles a browser distributable via webpack. However, I don't see what the globally exported variable name is for the distributable. Unfortunately none of the docs show usage other than require(... which isn't helpful.

More specifically, if webpack's configuration option output.library were set explicitly, this variable name would be abundantly clear.

Impression events don't respect HTTPS_PROXY

Since #98 removed the request library in favour of the stock Node HTTP implementation, the Optimizely SDK no longer supports HTTP(S) Proxies, as Node does not proxy by default (as documented here nodejs/node#15620).

We host our feature branches on a PAAS that requires outbound HTTP connections be proxied: As a result this bug currently causes our application to crash with the error below when calling optimizely.activate

   2018-06-21T16:49:56.60+0100 [APP/PROC/WEB/0] ERR events.js:183
   2018-06-21T16:49:56.60+0100 [APP/PROC/WEB/0] ERR       throw er; // Unhandled 'error' event
   2018-06-21T16:49:56.60+0100 [APP/PROC/WEB/0] ERR       ^
   2018-06-21T16:49:56.60+0100 [APP/PROC/WEB/0] ERR Error: connect ECONNREFUSED 34.228.76.60:443
   2018-06-21T16:49:56.60+0100 [APP/PROC/WEB/0] ERR     at Object._errnoException (util.js:1022:11)
   2018-06-21T16:49:56.60+0100 [APP/PROC/WEB/0] ERR     at _exceptionWithHostPort (util.js:1044:20)
   2018-06-21T16:49:56.60+0100 [APP/PROC/WEB/0] ERR     at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1198:14)

This error can't be caught, because it occurs asynchronously to the main control flow of the application, and thus causes the entire application server to crash.

Users are able to be bucketed into multiple variants

When changing allocations between variations in my Optimizely dashboard, my users were able to be bucketed into multiple variants. I assumed that once a user gets bucketed into a variation, they stay in that bucket (this works as expected in the web app when using Optimizely X FullStack project with ruby). But with the React Native app, which uses this library (which points to the same project), this is seeming to not be the case.

Is this expected? Am I doing something wrong?

In my js app, I'm calling the activate method on optimizelyClientInstance.

Code:

Create Optimizely Client using project datafile that's been fetched

optimizelyClientInstance = optimizely.createInstance({
  datafile: newDatafile,
});

Later, I'm checking variations my 3 users are assigned to.

const variation = optimizelyClientInstance.activate(
  experimentName,
  9255,
  attributes,
);

const var2 = optimizelyClientInstance.activate(
  experimentName,
  'aa',
  attributes,
);

const var3 = optimizelyClientInstance.activate(
  experimentName,
  'bb',
  attributes,
);

Screenshots of variants per user when I was changing allocations: https://screencast.com/t/0rOfarGaC

try/catch for localStorage calls

Hey Optimizely team πŸ‘‹

A small thing I encountered having Optimizely running in prod for some weeks now. I see a fair amount of these errors shown in our error logging service:

[OPTIMIZELY] - ERROR ${dateTime} EventProcessor: Failed to read the 'localStorage' property from 'Window': Access is denied for this document.

This is due to the fact that Google Chrome users can actively deny access to localStorage (see this https://bit.ly/2H0SMJ7).

How would the enhancement work?

This is something nobody can prevent, so I would recommend to put localStorage calls inside a try/catch block.

I don't know if these users are able to attend tests at all. If not, you could prevent them from being bucketed in the first place.

When would the enhancement be useful?

Would be nice to not see this error because no one can do anything about it.

how to build

Hello, how can I build the javascript sdk into a bundled file?

[OPTIMIZELY] - ERROR 2020-01-17T22:20:33.483Z fns.assignIn is not a function

How would the enhancement work?

When would the enhancement be useful?

What I wanted to do

What I expected to happen

What actually happened

This happens only after the build process using webpack. without the webpack build, it works as expected.

I get the following error.
image

This is where it seems the error coming. the lodash function used
image

Check this gist https://gist.github.com/pgdesigning/9e64ccbef9ce455430d00935228145ea
it has the webpack generated optimizely output and the source map

Steps to reproduce

Link to repository that can reproduce the issue:

@optimizely/optimizely-sdk version:
"@optimizely/optimizely-sdk": "^3.3.2",

Browser and version:

node version:
v10.15.3
npm version:
6.4.1
Versions of any other relevant tools (like module bundlers, transpilers, etc.):
"webpack": "4.6.0",
"webpack-auto-inject-version": "1.0.0",
"webpack-bundle-analyzer": "2.9.2",
"webpack-chunk-hash": "0.5.0",
"webpack-cli": "2.0.14",
"webpack-dev-middleware": "3.1.2",
"webpack-hot-middleware": "2.22.1"
"chunk-manifest-webpack-plugin": "1.1.2",
"@types/html-webpack-plugin": "2.30.1",
"add-asset-html-webpack-plugin": "2.1.3",

ESM and other enhancements

How would the enhancement work?

Optimizations to make a smaller dependency bundle. The alpha release which eliminates the lodash dependency is fantastic! There is other low-hanging fruit to make a much smaller bundle:

  1. Expose an ESM entrypoing in package.json as module
    This would allow tree-shaking and module de-duping for consumers are already have this tooling in place.
  2. Provide a way to omit (or pass-in) the datafile manager. The datafile manager is virtually unnecessary when the datafile is fetched manually or side-loaded into the page. (js-sdk-datafile-manager: 25.39KB)
  3. Provide a way to opt-out of the logging dependency. This dependency provides little to no value in the browser when it is either disabled in production or a simple facade around console.log in development (js-sdk-logging: 15.24KB)
  4. uuid and murmurhash may already be present in consumers' bundles
  5. Omit the project config schema for production builds when validation is not desirable: (project_config_schema.js 6.58KB)
  6. Allow opting out of the utils package.
    13kb (uncompressed) of error messages and another 14kb (uncompressed) of validations? These assertions are quite useful during development, but do not make up for their bundle-cost in production.

(File-sizes estimates generates using rollup-plugin-visualizer from optimizely-sdk at recent master

When would the enhancement be useful?

For consumers who already have module bundler infrastructure in place (webpack, rollup, etc) and could take advantage of tree-shaking and de-duping of dependencies.

@optimizely/optimizely-sdk version:
HEAD@645ea8a81656cc6b63bfc13f1a8de53a892b2b84

getEnabledFeatures attributes usage?

Let's say we have a feature called 'PDP_video_player' and another one called 'PDP_image_carousel'. Each of them have audiences, so we'll be passing attributes to .isFeatureEnabled. You'll only have a chance of getting the 'PDP_video_player' if 'Experience_Has_Video' is true and you'll only have a chance of getting the 'PDP_image_carousel' if 'Experience_Has_Video' is false.

In other words, when we call .isFeatureEnabled for different features, we'll be passing different sets of attributes because our features have different audiences.

We go to use the undocumented getEnabledFeatures method:

image

And get unexpected results because getEnabledFeatures accepts an attributes parameter, loops through all the features, and then passes that same attributes set to each feature:

image

Should it rather rather accept a map of attributes keyed off feature name and then pluck the right set out each time and pass those along?

image

programatic access to a full list of feature flags?

Forgive me if this exists already, but I wasn't able to find anything in the documentation.

Is there a way to get programatic access to a full list of the feature flags? If not, could that be an enhancement?

(for further context, I'm using the react-sdk)

How would the enhancement work?

Expose an api that would probably be something as simple as getAllFeatureFlags(). Even if it's just the name of the flags, I can then use optimizely.isFeatureEnabled() to get the status of the flag

When would the enhancement be useful?

I've built a developer+PM focused tool that allows devs/PMs to see, in our app, all the toggles and their status. I am using

optimizely?.client?.projectConfigManager?.datafileManager?.currentDatafile?.featureFlags

to get that list, which admittedly is reaching into the internals and also now appears to not work anymore.

So instead of me searching through the internals again for that list, I thought it would be better to propose a formal API for this instead 😊

UUID dependency issue with Angular 6 apps

Hey Guys,

We're working on upgrading our Angular app to v6, and ran into an issue with the optimizely sdk:

Uncaught ReferenceError: global is not defined
    at Object../node_modules/uuid/lib/rng-browser.js (vendor.js:162311)
    at __webpack_require__ (runtime.js:83)
    at Object../node_modules/uuid/v1.js (vendor.js:162352)
    at __webpack_require__ (runtime.js:83)
    at Object../node_modules/uuid/index.js (vendor.js:162252)
    at __webpack_require__ (runtime.js:83)
    at Object../node_modules/optimizely-server-sdk/lib/utils/fns/index.js (vendor.js:131747)
    at __webpack_require__ (runtime.js:83)
    at Object../node_modules/optimizely-client-sdk/index.js (vendor.js:128792)
    at __webpack_require__ (runtime.js:83)

As a temporary workaround we had to add the following polyfill:

window.global = window;

Can you look into this? Perhaps you guys need to bump the uuid library version?

typescript error in the build process

After I updated the optimizley-sdk to version 4.4.0 my build process started to fail
I am using typescript(4.0.5) and I started to get the following errors after the upgrade:
node_modules/@optimizely/optimizely-sdk/lib/optimizely/index.ts:150:11 - error TS2322: Type 'UserProfileService' is not assignable to type 'null'.

150 userProfileService = config.userProfileService;
~~~~~~~~~~~~~~~~~~

node_modules/@optimizely/optimizely-sdk/lib/optimizely/index.ts:335:7 - error TS2322: Type 'string' is not assignable to type 'null'.

335 variationId = projectConfig.getVariationIdFromExperimentAndVariationKey(configObj, experimentKey, variationKey);
~~~~~~~~~~~

node_modules/@optimizely/optimizely-sdk/lib/optimizely/index.ts:336:7 - error TS2322: Type 'string' is not assignable to type 'null'.

336 experimentId = projectConfig.getExperimentId(configObj, experimentKey);
~~~~~~~~~~~~
I have downgraded the SDK to version 4.3.4 and everything works as expected.

@optimizely/optimizely-sdk version: 4.4.0

node version: 12.17

npm version: 6.14.4

Suppress NO_DATAFILE_SPECIFIED error when sdkKey is present

What I wanted to do

Create instance of Optimizely with sdkKey (function createInstance) and without a datafile

What I expected to happen

As it says in the docs, the param datafile is not necessary if sdkKey is present (and vice versa)

What actually happened

The enums.ERROR_MESSAGES.NO_DATAFILE_SPECIFIED ("No datafile specified. Cannot start optimizely.") is thrown. Even though this doesn't cause the creation to break, it throws an error to the console (that my company has suppressed using a combination of a custom logger and custom error handling).

Steps to reproduce

optimizelyClientInstance = optimizely.createInstance({
  sdkKey: <optimizelySdkKey>,
});
  
const result = await optimizelyClientInstance.onReady({ timeout: 10000 });

@optimizely/optimizely-sdk version: 4.3.1

Browser and version: Chrome

node version: 14.6.0

npm version: 6.14.7

Package is not shrinkwrapped

Developers and CI enjoy working off the reproducible dependency tree via the checked-in package-lock.json, but projects using @optimizely/optimizely-sdk as a dependency have no such reproducibility guarantee; their package managers are free to strategically dedupe dependencies as they see fit. For example, say the SDK depends on lodash@^4.0.0 (but for devs and CI is pinned to 4.17.10), and another dependency depends on [email protected] and is also not shrinkwrapped. Package managers are free to dedupe the dependency and fetch the latest [email protected].

Do we want to shrinkwrap the SDK? It precludes downstream deduping, but with the benefit that the SDK's dependencies, from the perspective of SDK consumers, are now pinned.

For what it's worth, NPM advises not to do this:

It's strongly discouraged for library authors to publish this file, since that would prevent end users from having control over transitive dependency updates.

Create way to import React-Native's Optimizely version

How would the enhancement work?

To take advantage of the optimizely-sdk/lib/index.react-native.js file that was added by a recent commit, it'd be useful if we can add a way for React-Native folks to directly import it for use by adding this line at the top of the file import { OptimizelyReactNativeClient } from '@optimizely/optimizely-sdk'

Why?

Right now, folks working with React-Native by default must hunt for the specific file path from the commit and specify that longer file path for the React Native index file as something like import optimizely from '@optimizely/optimizely-sdk/lib/index.react-native.js'. If they want to clean up the imported filepath, they currently have to patch and edit Optimizely's package.json so that the browser key points at index.react-native.js instead

When would the enhancement be useful?

This enhancement would be useful for the next major release. My team is currently going to use a patched version for now

UMD tests not passing for Node 10 and above

Currently, we have to run the umdbrowser tests on Node 8.

Running on Node 10 yields this error:

`> @optimizely/[email protected] test-xbrowser /home/travis/build/optimizely/javascript-sdk/packages/optimizely-sdk

karma start karma.bs.conf.js --single-run
14 02 2019 18:53:27.791:ERROR [config]: Invalid config file!
ReferenceError: internalBinding is not defined
at internal/util/inspect.js:31:15
at req_ (/home/travis/build/optimizely/javascript-sdk/packages/optimizely-sdk/node_modules/natives/index.js:137:5)
at require (/home/travis/build/optimizely/javascript-sdk/packages/optimizely-sdk/node_modules/natives/index.js:110:12)
at util.js:25:21
at req_ (/home/travis/build/optimizely/javascript-sdk/packages/optimizely-sdk/node_modules/natives/index.js:137:5)
at require (/home/travis/build/optimizely/javascript-sdk/packages/optimizely-sdk/node_modules/natives/index.js:110:12)
at fs.js:42:21
at req_ (/home/travis/build/optimizely/javascript-sdk/packages/optimizely-sdk/node_modules/natives/index.js:137:5)
at Object.req [as require] (/home/travis/build/optimizely/javascript-sdk/packages/optimizely-sdk/node_modules/natives/index.js:54:10)
at Object. (/home/travis/build/optimizely/javascript-sdk/packages/optimizely-sdk/node_modules/fstream/node_modules/graceful-fs/fs.js:1:99)
at Module._compile (internal/modules/cjs/loader.js:689:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
at Module.load (internal/modules/cjs/loader.js:599:32)
at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
at Function.Module._load (internal/modules/cjs/loader.js:530:3)
at Module.require (internal/modules/cjs/loader.js:637:17)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! @optimizely/[email protected] test-xbrowser: karma start karma.bs.conf.js --single-run
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the @optimizely/[email protected] test-xbrowser script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
npm ERR! /home/travis/.npm/_logs/2019-02-14T18_53_27_811Z-debug.log
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! @optimizely/[email protected] test-ci: npm run test-xbrowser && npm run test-umdbrowser
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the @optimizely/[email protected] test-ci script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
npm ERR! /home/travis/.npm/_logs/2019-02-14T18_53_27_831Z-debug.log`

Error importing ESM bundle due to CJS logging dependency

What I wanted to do

Trying to import the ESM bundle from optimizely-sdk

What I expected to happen

Expected it to import successfully.

What actually happened

When using rollup on a bundle that imports optimizely-sdk's ESM bundle:

[!] Error: 'ConsoleLogHandler' is not exported by ../optimizely-javascript-sdk/packages/optimizely-sdk/node_modules/@optimizely/js-sdk-logging/lib/index.js
https://rollupjs.org/guide/en/#error-name-is-not-exported-by-module
../optimizely-javascript-sdk/packages/optimizely-sdk/dist/optimizely.browser.es.min.js (1:7)

Steps to reproduce

The root cause is an issue with the commonjs wrapping of some of the optimizely deps. Because these are declared as external in the ESM bundle, this error does not manifest during optimizely's build. However, a trivial way to repro the issue:

  1. insert external: [] above:
  2. run npm run build

Doing this will force rollup to attempt to embed the logging dependency directly, rather than ignore it. This exposes the same problem that consumers will have when they attempt to import the main sdk ESM bundle (at which point, rollup will need to import the logging dep)

It appears that this was worked around for the UMD build by adding namedExports to the commonjs plugin. However, this option is no longer available with recent versions of the commonjs plugin. rollup/plugins#149

I believe this will be fixed implicitly by converting the logging dependency to ESM.

@optimizely/optimizely-sdk version:
4.0

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.