flex-plugin-builder icon indicating copy to clipboard operation
flex-plugin-builder copied to clipboard

Can't select correct environment during local development.

Open gi-joe-moto opened this issue 6 years ago • 5 comments

Our organization has two Flex instances one prod and one test (test doesn't have SSO configured). When I'm doing local development and run 'npm start' the page comes up but it always default to our prod environment where I have no tasks. In addition the environment selector that appears at the top of the screen when I access the hosted version of the app is not available so I can't switch the environment. My plugin is configured to target the Test environment in the appConfig.js but this configuration seems to be ignored.

The only way I'm able to get around the issue is by clearing my browser cache and launching with a fresh session. This is, however, impractical to do on a regular basis because I constantly need to log into the Twilo Console to upload new assets and test the other environments. Is there ANY way you could add the environment selector to the local dev version of TF used by the plugin builder?

gi-joe-moto avatar Feb 18 '19 17:02 gi-joe-moto

any updates on this?

Stas-Buzunko avatar Apr 08 '20 21:04 Stas-Buzunko

Hi, You can deploy your plugins across multiple account sids by using https://www.twilio.com/docs/flex/plugins#using-multiple-accountsids . The question above refers to an older version of the Plugin Builder where you need to manually drag and drop your plugins as an asset. I would recommend using the latest version which provides the capability of deploying the plugin from the command line. Let me know if this helps with your case.

rnairtwilio avatar Apr 08 '20 21:04 rnairtwilio

@rnairtwilio question was about local development so that i can run

npm run dev - and get dev twilio project running npm run prod - get production twilio project running locally

I'm using craco plugin and was able to pick up correct env file by using NODE_ENV=production / NODE_ENV=development

but accountSid is ignored and is taken somewhere i have no idea where

Stas-Buzunko avatar Apr 08 '20 22:04 Stas-Buzunko

This is going to be somewhat long, but this is what we did: (This is a simplified version of our code obviously) Something similar to the following works for both the webchat-ui project and the flex-ui project...

src/Components/RootContainer/RootContainerFlexPlugin.tsx

import { FlexPlugin } from "flex-plugin";
import * as React from "react";
import RootContainer from "./RootContainer";
import * as Flex from "@twilio/flex-ui";
import { Manager } from '@twilio/flex-ui';
import rootReducer from '../../reducers';
import { isProduction } from '../../environments/environment';
import { updateConfig } from '../../core/updateConfig';
import throttle from 'lodash/throttle';
import { RdFlexState } from "core/rdFlexState";
import { saveState } from "core/localStorage";

declare global {
  interface Window {
    devToolsExtension: () => any
  }
}

interface Props { }

interface State {

}

export class RootContainerFlexPlugin extends FlexPlugin {
  state: State = {
    // Form fields

  };

  constructor(props: Readonly<Props>) {
    super("RootContainerFlexPlugin");
    /* Notice this isProduction() function */
    console.log('IS_PRODUCTION', isProduction());
  }

  init(flex, manager: Manager) {
    this.updateConfiguration(manager);
    this.replaceReducer(manager);
    this.registerPlugins(manager);
  }

  protected registerPlugins(manager: Manager) {
    Flex.RootContainer.Content.add(
        <RootContainer key="demo-component" store={manager.store} manager={manager} />,
      {
        sortOrder: -1
      }
    );
  }

  protected replaceReducer(manager: Manager) {
    manager.store.replaceReducer(rootReducer);
  }

  protected updateConfiguration(manager: Manager) {
    /* THIS is the KEY here */
    manager.updateConfig(updateConfig({}));
  }
}

src/core/updateConfig.ts


import { Manager } from '@twilio/flex-ui';
import { getAppConfig } from '../appConfig';
import { isProduction } from '../environments/environment';

/* The appConfig is UPDATED on the fly at runtime, based on our ENV variable */
export function updateConfig(newContext?: any) {
  var dev = {
    accountSid: "YYY",
    sso: { accountSid: "YYY" },
    serviceBaseUrl: "something-ocelot-yyyy.twil.io"
  }

  var prod = {
    accountSid: "XXX",
    sso: { accountSid: "XXX" },
    serviceBaseUrl: "something-olm-xxxx.twil.io"
  }
  /* This is how we can overwrite the config dynamically on the fly within a plugin!! */
  return Object.assign({}, getAppConfig(), {
    logLevel: isProduction() ? "SILENT" : "DEBUG",
    context: Object.assign({}, getAppConfig().context || {}, newContext)
  }, isProduction() ? prod : dev);
}

src/appConfig.ts

export function getAppConfig() {
    /* We will be overriding the default /public/appConfig.js */
    return window.appConfig;
}

src/environments/environment.ts

export const environment = {
    // Webpack will do a find and replace on the following expression at build-time based on our env variable
    production: process.env['RD_PROD_ENV']
}

export function isProduction() {
    return environment.production;
}

export function isHostedByTwilio() {
    return window.location.host === 'flex.twilio.com';
}

export function isLocalhost() {
    return window.location.hostname === 'localhost';
}

config/webpack-override-craco-plugin.js

// https://github.com/gsoft-inc/craco/tree/master/packages/craco#develop-a-plugin
const { getLoader, getLoaders, removeLoaders, loaderByName, throwUnexpectedConfigError,
    addAfterLoader, addBeforeLoader, loader } = require("@craco/craco");
const { when, whenDev, whenProd, whenTest, ESLINT_MODES, POSTCSS_MODES, createWebpackProdConfig,
    createWebpackDevConfig } = require("@craco/craco");
const webpack = require('webpack');
const CompressionPlugin = require('compression-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');

module.exports = {
    overrideWebpackConfig: ({ webpackConfig, cracoConfig, pluginOptions, context: { env, paths } }) => {
        if (pluginOptions.preText) {
            console.log(pluginOptions.preText);
        }
        webpackConfig = Object.assign({}, webpackConfig);

...

// Set our RD_PROV_ENV JavaScript variable to the RD_PROD_ENV ENVIRONMENT variable at build-time
        const interpolateHtmlPlugin = webpackConfig.plugins.find((plugin) => { return 'InterpolateHtmlPlugin' === plugin.constructor.name });
        const definePlugin = webpackConfig.plugins.find((plugin) => { return 'DefinePlugin' === plugin.constructor.name });

        if (interpolateHtmlPlugin && interpolateHtmlPlugin.replacements && process.env) {
            interpolateHtmlPlugin.replacements["RD_PROD_ENV"] = process.env['RD_PROD_ENV'];
        }

        if (definePlugin && definePlugin.definitions && definePlugin.definitions["process.env"] && process.env) {
            definePlugin.definitions["process.env"]["RD_PROD_ENV"] = process.env['RD_PROD_ENV'];
        }

        // Always return the config object.
        return webpackConfig;
    }
};

.circleci/config.yml

...
# deploy dev to dev
RD_PROD_ENV=false TWILIO_ACCOUNT_SID=$DEV_TWILIO_ACCOUNT_SID TWILIO_AUTH_TOKEN=$DEV_TWILIO_AUTH_TOKEN npm run deploy
...
# deploy prod to prod
RD_PROD_ENV=true TWILIO_ACCOUNT_SID=$PROD_TWILIO_ACCOUNT_SID TWILIO_AUTH_TOKEN=$PROD_TWILIO_AUTH_TOKEN npm run deploy
...

shell

# serve prod locally
RD_PROD_ENV=true npm start

Or:

# serve dev locally
RD_PROD_ENV=false npm start

Or simply:

# serve dev locally
npm start

After you do all this make sure you try it out in an incognito window and clear your cache because otherwise it might try and hold onto your old session. In our code, we use the isProduction() call everywhere to determine both which twilio runtime to hit as well as which of our backend apis to hit. (dev or prod)

Hope this helps!!!

chase2981 avatar Apr 13 '20 22:04 chase2981

@Stas-Buzunko @gi-joe-moto See my comment above and let me know if something like that works for you. You could also simply replace the public/appConfig.js each build based on your environment variable using something like the CopyWebpackPlugin, along with a public/appConfigProd.js and a public/appConfigDev.js.

chase2981 avatar Apr 14 '20 04:04 chase2981

Hi,

This is a long open item more than a year now, hence closing it. Feel free to reopen it if still required.

anjha91 avatar Oct 04 '23 08:10 anjha91