build: add env utils (#4304)

* build: add env utils

* test: env utils
This commit is contained in:
Zach Pomerantz 2022-08-08 18:38:37 +02:00 committed by GitHub
parent 77c4e74fc6
commit 9b9d6aff78
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 70 additions and 9 deletions

@ -1,4 +1,5 @@
import { Identify, identify, init, track } from '@amplitude/analytics-browser'
import { isDevelopmentEnv } from 'utils/env'
/**
* Initializes Amplitude with API key for project.
@ -6,8 +7,8 @@ import { Identify, identify, init, track } from '@amplitude/analytics-browser'
* Uniswap has two Amplitude projects: test and production. You must be a
* member of the organization on Amplitude to view details.
*/
export function initializeAnalytics(isDevEnvironment = process.env.NODE_ENV === 'development') {
if (isDevEnvironment) return
export function initializeAnalytics() {
if (isDevelopmentEnv()) return
const API_KEY = process.env.REACT_APP_AMPLITUDE_KEY
if (typeof API_KEY === 'undefined') {
@ -36,7 +37,7 @@ export function initializeAnalytics(isDevEnvironment = process.env.NODE_ENV ===
/** Sends an event to Amplitude. */
export function sendAnalyticsEvent(eventName: string, eventProperties?: Record<string, unknown>) {
if (process.env.NODE_ENV === 'development') {
if (isDevelopmentEnv()) {
console.log(`[amplitude(${eventName})]: ${JSON.stringify(eventProperties)}`)
return
}
@ -54,14 +55,12 @@ type Value = string | number | boolean | string[] | number[]
* for details.
*/
class UserModel {
constructor(private isDevEnvironment = process.env.NODE_ENV === 'development') {}
private log(method: string, ...parameters: unknown[]) {
console.debug(`[amplitude(Identify)]: ${method}(${parameters})`)
}
private call(mutate: (event: Identify) => Identify) {
if (this.isDevEnvironment) {
if (isDevelopmentEnv()) {
const log = (_: Identify, method: string) => this.log.bind(this, method)
mutate(new Proxy(new Identify(), { get: log }))
return

@ -24,6 +24,7 @@ import {
import { Link } from 'react-router-dom'
import { useDarkModeManager } from 'state/user/hooks'
import styled, { css } from 'styled-components/macro'
import { isDevelopmentEnv, isStagingEnv } from 'utils/env'
import { ReactComponent as MenuIcon } from '../../assets/images/menu.svg'
import { useOnClickOutside } from '../../hooks/useOnClickOutside'
@ -301,7 +302,7 @@ export default function Menu() {
<Trans>Claim UNI</Trans>
</UNIbutton>
)}
{['development', 'test'].includes(process.env.NODE_ENV) && (
{(isDevelopmentEnv() || isStagingEnv()) && (
<ToggleMenuItem onClick={openFeatureFlagsModal}>Feature Flags</ToggleMenuItem>
)}
</MenuFlyout>

@ -1,6 +1,8 @@
// This optional code is used to register a service worker.
// register() is not called by default.
import { isProductionEnv, isStagingEnv } from 'utils/env'
// This lets the app load faster on subsequent visits in production, and gives
// it offline capabilities. However, it also means that developers (and users)
// will only see deployed updates on subsequent visits to a page, after all the
@ -93,7 +95,7 @@ function checkValidServiceWorker(swUrl: string, config?: Config) {
}
export function register(config?: Config) {
if (['production', 'staging'].includes(process.env.NODE_ENV) && 'serviceWorker' in navigator) {
if ((isProductionEnv() || isStagingEnv()) && 'serviceWorker' in navigator) {
// The URL constructor is available in all browsers that support SW.
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href)
if (publicUrl.origin !== window.location.origin) {

@ -2,6 +2,7 @@ import { configureStore } from '@reduxjs/toolkit'
import { setupListeners } from '@reduxjs/toolkit/query/react'
import multicall from 'lib/state/multicall'
import { load, save } from 'redux-localstorage-simple'
import { isTestEnv } from 'utils/env'
import application from './application/reducer'
import burn from './burn/reducer'
@ -44,7 +45,7 @@ const store = configureStore({
.concat(dataApi.middleware)
.concat(routingApi.middleware)
.concat(save({ states: PERSISTED_KEYS, debounce: 1000 })),
preloadedState: load({ states: PERSISTED_KEYS, disableWarnings: process.env.NODE_ENV === 'test' }),
preloadedState: load({ states: PERSISTED_KEYS, disableWarnings: isTestEnv() }),
})
store.dispatch(updateVersion())

43
src/utils/env.test.ts Normal file

@ -0,0 +1,43 @@
import { isDevelopmentEnv, isProductionEnv, isStagingEnv, isTestEnv } from './env'
describe('env', () => {
const ENV = process.env
afterEach(() => {
process.env = ENV
})
function setEnv(env: Record<string, unknown>) {
process.env = {
PUBLIC_URL: 'http://example.com',
NODE_ENV: 'development',
...env,
}
}
it('isDevelopmentEnv is true if NODE_ENV=development', () => {
setEnv({ NODE_ENV: 'development' })
expect(isDevelopmentEnv()).toBe(true)
})
it('isTestEnv is true if NODE_ENV=test', () => {
setEnv({ NODE_ENV: 'test' })
expect(isTestEnv()).toBe(true)
})
it('isStagingEnv is true REACT_APP_STAGING=1', () => {
setEnv({ REACT_APP_STAGING: 1 })
expect(isStagingEnv()).toBe(true)
})
describe('isProductionEnv', () => {
it('is true if NODE_ENV=production', () => {
setEnv({ NODE_ENV: 'production' })
expect(isProductionEnv()).toBe(true)
})
it('is false if NODE_ENV=production and REACT_APP_STAGING=1', () => {
setEnv({ NODE_ENV: 'production', REACT_APP_STAGING: 1 })
expect(isProductionEnv()).toBe(false)
})
})
})

15
src/utils/env.ts Normal file

@ -0,0 +1,15 @@
export function isDevelopmentEnv(): boolean {
return process.env.NODE_ENV === 'development'
}
export function isTestEnv(): boolean {
return process.env.NODE_ENV === 'test'
}
export function isStagingEnv(): boolean {
return Boolean(process.env.REACT_APP_STAGING)
}
export function isProductionEnv(): boolean {
return process.env.NODE_ENV === 'production' && !isStagingEnv()
}