optimizely/javascript-sdk

issue: Incorrect client engine detected

jasonrowsell opened this issue · 4 comments

Is there an existing issue for this?

  • I have searched the existing issues

SDK Version

4.3.2

Current Behavior

I'm currently using Optimizely SDK in a lambda function with a node runtime. Every time the function is invoked it logs the following errors

ERROR	[OPTIMIZELY] - ERROR EventProcessor: window is not defined
ERROR	[OPTIMIZELY] - ERROR INDEX_BROWSER: unable to bind optimizely.close() to page unload event: "window is not defined"

This error seems to be coming from the createInstance function in index.browser.ts. However, I would have expected the createInstance function in index.node.ts to have been invoked instead. Somehow the clientEngine isn't correct. Any idea why that may be?

optimizelySDK.setLogLevel("warn");
optimizelySDK.setLogger(optimizelySDK.logging.createLogger());

export default class OptimizelyFeatureToggler implements FeatureToggler {
  private static singletonInstance?: OptimizelyFeatureToggler = undefined;

  private user = "example-user";
  private client: Client;

  public static async instance() {
    if (OptimizelyFeatureToggler.singletonInstance === undefined) {
      OptimizelyFeatureToggler.singletonInstance = new OptimizelyFeatureToggler();
      await OptimizelyFeatureToggler.singletonInstance.initialize();
    }
    return OptimizelyFeatureToggler.singletonInstance;
  }

  public isFeatureEnabled(featureToggle: string): boolean {
    return this.client.isFeatureEnabled(featureToggle, this.user);
  }

  public getFeatureVariable(featureToggle: string, featureVariable: string): unknown {
    return this.client.getFeatureVariable(featureToggle, featureVariable, this.user);
  }

  private async initialize(): Promise<void> {
    const token = await this.getOptimizelyToken();
    const datafileUrl = `https://cdn.optimizely.com/datafiles/${token}.json`;
    const datafile = await fetch(datafileUrl).then(response => response.json());
    const datafileOptions = { autoUpdate: true, updateInterval: 1000 };
    this.client = optimizelySDK.createInstance({ datafile, datafileOptions });
  }

  private getOptimizelyToken = async () => {
    const secret = await secretRetriever.retrieve(process.env.OPTIMIZELY_TOKEN || "");
    return secret.token;
  };
}

Expected Behavior

I expect no error messages to be logged and for the createInstance function in index.node.ts to be invoked rather than in index.browser.ts

Steps To Reproduce

Invoke lambda, observe logged errors

SDK Type

Node

Node Version

16.20.1

Browsers impacted

No response

Link

No response

Logs

No response

Severity

No response

Workaround/Solution

No response

Recent Change

No response

Conflicts

No response

Hi. Thanks for reporting the issue. We are looking into it.

A question:
Are you using any bundler? In that case, are you bundling for proper target? For example: setting target: 'node' for webpack?

Hi @raju-opti, webpack is used for the bundler and the target is set to node

module.exports = {
  mode: serverlessWebpack.lib.webpack.isLocal ? "development" : "production",
  entry: serverlessWebpack.lib.entries,
  resolve: {
    extensions: [".js", ".ts"]
  },
  optimization: {
    minimize: false
  },
  output: {
    libraryTarget: "commonjs2",
    path: path.join(__dirname, ".webpack"),
    filename: "[name].js"
  },
  externals: {
    "aws-sdk": "aws-sdk"
  },
  target: "node",
  module: {
    rules: [{ test: /\.ts/, loader: "ts-loader" }]
  },
}

Hi @jasonrowsell , optimizely-sdk specifies three entry points in the package.json

"module": "dist/optimizely.browser.es.min.js",
"main": "dist/optimizely.node.min.js",
"browser": "dist/optimizely.browser.min.js",

As you can see, module and browser fields point to browser entrypoints, and the main field points to node entrypoint.
Looks like we need to add

module.exports = {
  //...
  resolve: {
    mainFields: ['main', 'module'],
  },
};

to the webpack config.

According to webpack documentation, if we use node target, then the default value for resolve.mainFields is ['module', 'main'], which will resolve to the browser entrypoint for optimizely-sdk. Adding the above config should make webpack resolve to the node entrypoint instead.

Worked like a charm, no more errors logged. Thank you very much for your help and such a quick response :)