flex-plugin-builder
flex-plugin-builder copied to clipboard
Can't select correct environment during local development.
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?
any updates on this?
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 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
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!!!
@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.
Hi,
This is a long open item more than a year now, hence closing it. Feel free to reopen it if still required.