Skip to content

Commit 8e6ba04

Browse files
chore: env refactor + android emulator connection bug
1 parent 6fb85ce commit 8e6ba04

File tree

6 files changed

+59
-115
lines changed

6 files changed

+59
-115
lines changed

.env.development

Lines changed: 0 additions & 14 deletions
This file was deleted.

.env.production

Lines changed: 0 additions & 6 deletions
This file was deleted.

app.config.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { ConfigContext, ExpoConfig } from '@expo/config';
22

3-
import { ClientEnv, Env } from './env';
3+
import { Env } from './env';
44

55
export default ({ config }: ConfigContext): ExpoConfig => ({
66
...config,
@@ -74,7 +74,7 @@ export default ({ config }: ConfigContext): ExpoConfig => ({
7474
],
7575
],
7676
extra: {
77-
...ClientEnv,
77+
...Env,
7878
eas: {
7979
projectId: Env.EAS_PROJECT_ID,
8080
},

env.js

Lines changed: 35 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,19 @@
22
/*
33
* Env file to load and validate env variables
44
* Be cautious; this file should not be imported into your source folder.
5-
* We split the env variables into two parts:
6-
* 1. Client variables: These variables are used in the client-side code (src folder).
7-
* 2. Build-time variables: These variables are used in the build process (app.config.ts file).
85
* Import this file into the `app.config.ts` file to use environment variables during the build process. The client variables can then be passed to the client-side using the extra field in the `app.config.ts` file.
96
* To access the client environment variables in your `src` folder, you can import them from `@env`. For example: `import Env from '@env'`.
107
*/
118
/**
129
* 1st part: Import packages and Load your env variables
13-
* we use dotenv to load the correct variables from the .env file based on the APP_ENV variable (default is development)
1410
* APP_ENV is passed as an inline variable while executing the command, for example: APP_ENV=staging pnpm build:android
1511
*/
1612
const z = require('zod');
1713

1814
const packageJSON = require('./package.json');
1915
const path = require('path');
2016
const APP_ENV = process.env.APP_ENV ?? 'development';
21-
const envPath = path.resolve(__dirname, `.env.${APP_ENV}`);
17+
const envPath = path.resolve(__dirname, `.env`);
2218

2319
require('dotenv').config({
2420
path: envPath,
@@ -32,124 +28,87 @@ require('dotenv').config({
3228
* for example: if the APP_ENV is staging, the bundle id will be com.habitstogether.staging
3329
*/
3430

35-
// TODO: Replace these values with your own
36-
31+
const NAME = 'HabitsTogetherApp'; // app name
32+
const SCHEME = 'habitstogetherApp'; // app scheme
3733
const BUNDLE_ID = 'com.habitstogether'; // ios bundle id
3834
const PACKAGE = 'com.habitstogether'; // android package name
39-
const NAME = 'HabitsTogetherApp'; // app name
4035
const EXPO_ACCOUNT_OWNER = 'habitstogether'; // expo account owner
4136
const EAS_PROJECT_ID = 'c3e1075b-6fe7-4686-aa49-35b46a229044'; // eas project id
42-
const SCHEME = 'habitstogetherApp'; // app scheme
43-
44-
/**
45-
* We declare a function withEnvSuffix that will add a suffix to the variable name based on the APP_ENV
46-
* Add a suffix to variable env based on APP_ENV
47-
* @param {string} name
48-
* @returns {string}
49-
*/
50-
51-
const withEnvSuffix = (name) => {
52-
return APP_ENV === 'production' ? name : `${name}.${APP_ENV}`;
53-
};
5437

5538
/**
5639
* 2nd part: Define your env variables schema
5740
* we use zod to define our env variables schema
5841
*
59-
* we split the env variables into two parts:
60-
* 1. client: These variables are used in the client-side code (`src` folder).
61-
* 2. buildTime: These variables are used in the build process (app.config.ts file). You can think of them as server-side variables.
62-
*
63-
* Main rules:
64-
* 1. If you need your variable on the client-side, you should add it to the client schema; otherwise, you should add it to the buildTime schema.
65-
* 2. Whenever you want to add a new variable, you should add it to the correct schema based on the previous rule, then you should add it to the corresponding object (_clientEnv or _buildTimeEnv).
66-
*
6742
* Note: `z.string()` means that the variable exists and can be an empty string, but not `undefined`.
6843
* If you want to make the variable required, you should use `z.string().min(1)` instead.
6944
* Read more about zod here: https://zod.dev/?id=strings
7045
*
7146
*/
7247

73-
const client = z.object({
48+
const envSchema = z.object({
7449
APP_ENV: z.enum(['development', 'staging', 'production']),
7550
NAME: z.string(),
7651
SCHEME: z.string(),
7752
BUNDLE_ID: z.string(),
7853
PACKAGE: z.string(),
7954
VERSION: z.string(),
80-
81-
// ADD YOUR CLIENT ENV VARS HERE
82-
API_URL: z.string(),
83-
VAR_NUMBER: z.number(),
84-
VAR_BOOL: z.boolean(),
85-
});
86-
87-
const buildTime = z.object({
8855
EXPO_ACCOUNT_OWNER: z.string(),
8956
EAS_PROJECT_ID: z.string(),
90-
// ADD YOUR BUILD TIME ENV VARS HERE
91-
SECRET_KEY: z.string(),
57+
// firebase
58+
EXPO_PUBLIC_FIREBASE_API_KEY: z.string().min(1),
59+
EXPO_PUBLIC_FIREBASE_AUTH_DOMAIN: z.string().min(1),
60+
EXPO_PUBLIC_FIREBASE_PROJECT_ID: z.string().min(1),
61+
EXPO_PUBLIC_FIREBASE_STORAGE_BUCKET: z.string().min(1),
62+
EXPO_PUBLIC_FIREBASE_MESSAGING_SENDER_ID: z.string().min(1),
63+
EXPO_PUBLIC_FIREBASE_APP_ID: z.string().min(1),
64+
EXPO_PUBLIC_FIREBASE_MEASUREMENT_ID: z.string().min(1),
9265
});
9366

9467
/**
95-
* @type {Record<keyof z.infer<typeof client> , unknown>}
68+
* Load environment variables
69+
* @type {Record<keyof z.infer<typeof envSchema> , unknown>}
9670
*/
97-
const _clientEnv = {
71+
const _env = {
9872
APP_ENV,
99-
NAME: NAME,
100-
SCHEME: SCHEME,
101-
BUNDLE_ID: withEnvSuffix(BUNDLE_ID),
102-
PACKAGE: withEnvSuffix(PACKAGE),
73+
NAME,
74+
SCHEME,
75+
BUNDLE_ID,
76+
PACKAGE,
10377
VERSION: packageJSON.version,
104-
105-
// ADD YOUR ENV VARS HERE TOO
106-
API_URL: process.env.API_URL,
107-
VAR_NUMBER: Number(process.env.VAR_NUMBER),
108-
VAR_BOOL: process.env.VAR_BOOL === 'true',
109-
};
110-
111-
/**
112-
* @type {Record<keyof z.infer<typeof buildTime> , unknown>}
113-
*/
114-
const _buildTimeEnv = {
11578
EXPO_ACCOUNT_OWNER,
11679
EAS_PROJECT_ID,
117-
// ADD YOUR ENV VARS HERE TOO
118-
SECRET_KEY: process.env.SECRET_KEY,
80+
// firebase
81+
EXPO_PUBLIC_FIREBASE_API_KEY: process.env.EXPO_PUBLIC_FIREBASE_API_KEY,
82+
EXPO_PUBLIC_FIREBASE_AUTH_DOMAIN:
83+
process.env.EXPO_PUBLIC_FIREBASE_AUTH_DOMAIN,
84+
EXPO_PUBLIC_FIREBASE_PROJECT_ID: process.env.EXPO_PUBLIC_FIREBASE_PROJECT_ID,
85+
EXPO_PUBLIC_FIREBASE_STORAGE_BUCKET:
86+
process.env.EXPO_PUBLIC_FIREBASE_STORAGE_BUCKET,
87+
EXPO_PUBLIC_FIREBASE_MESSAGING_SENDER_ID:
88+
process.env.EXPO_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
89+
EXPO_PUBLIC_FIREBASE_APP_ID: process.env.EXPO_PUBLIC_FIREBASE_APP_ID,
90+
EXPO_PUBLIC_FIREBASE_MEASUREMENT_ID:
91+
process.env.EXPO_PUBLIC_FIREBASE_MEASUREMENT_ID,
11992
};
12093

12194
/**
12295
* 3rd part: Merge and Validate your env variables
12396
* We use zod to validate our env variables based on the schema we defined above
12497
* If the validation fails we throw an error and log the error to the console with a detailed message about missed variables
125-
* If the validation passes we export the merged and parsed env variables to be used in the app.config.ts file as well as a ClientEnv object to be used in the client-side code
98+
* If the validation passes we export the merged and parsed env variables to be used in the app.config.ts file (look at under extra)
12699
**/
127-
const _env = {
128-
..._clientEnv,
129-
..._buildTimeEnv,
130-
};
131100

132-
const merged = buildTime.merge(client);
133-
const parsed = merged.safeParse(_env);
134-
135-
if (parsed.success === false) {
101+
const parsed = envSchema.safeParse(_env);
102+
if (!parsed.success) {
136103
console.error(
137104
'❌ Invalid environment variables:',
138105
parsed.error.flatten().fieldErrors,
139-
140-
`\n❌ Missing variables in .env.${APP_ENV} file, Make sure all required variables are defined in the .env.${APP_ENV} file.`,
141-
`\n💡 Tip: If you recently updated the .env.${APP_ENV} file and the error still persists, try restarting the server with the -c flag to clear the cache.`,
142-
);
143-
throw new Error(
144-
'Invalid environment variables, Check terminal for more details ',
145106
);
107+
throw new Error('Invalid environment variables. Check your .env file.');
146108
}
147109

148110
const Env = parsed.data;
149-
const ClientEnv = client.parse(_clientEnv);
150111

151112
module.exports = {
152113
Env,
153-
ClientEnv,
154-
withEnvSuffix,
155114
};

src/api/common/firebase.ts

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,32 @@
1+
import { Env } from '@env';
12
import { initializeApp } from 'firebase/app';
2-
import { connectFirestoreEmulator, getFirestore } from 'firebase/firestore';
3+
import {
4+
connectFirestoreEmulator,
5+
initializeFirestore,
6+
} from 'firebase/firestore';
37
import { connectFunctionsEmulator, getFunctions } from 'firebase/functions';
8+
import { Platform } from 'react-native';
49

510
const firebaseConfig = {
6-
apiKey: process.env.EXPO_PUBLIC_FIREBASE_API_KEY,
7-
authDomain: process.env.EXPO_PUBLIC_FIREBASE_AUTH_DOMAIN,
8-
projectId: process.env.EXPO_PUBLIC_FIREBASE_PROJECT_ID,
9-
storageBucket: process.env.EXPO_PUBLIC_FIREBASE_STORAGE_BUCKET,
10-
messagingSenderId: process.env.EXPO_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
11-
appId: process.env.EXPO_PUBLIC_FIREBASE_APP_ID,
11+
apiKey: Env.EXPO_PUBLIC_FIREBASE_API_KEY,
12+
authDomain: Env.EXPO_PUBLIC_FIREBASE_AUTH_DOMAIN,
13+
projectId: Env.EXPO_PUBLIC_FIREBASE_PROJECT_ID,
14+
storageBucket: Env.EXPO_PUBLIC_FIREBASE_STORAGE_BUCKET,
15+
messagingSenderId: Env.EXPO_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
16+
appId: Env.EXPO_PUBLIC_FIREBASE_APP_ID,
1217
};
1318

1419
// Initialize Firebase
1520
export const app = initializeApp(firebaseConfig);
16-
export const db = getFirestore(app);
21+
export const db = initializeFirestore(app, {
22+
experimentalForceLongPolling: true,
23+
});
24+
const functions = getFunctions(app);
1725

18-
// Connect to emulator in development
19-
if (__DEV__) {
20-
connectFirestoreEmulator(db, '127.0.0.1', 8080);
21-
}
22-
23-
// Connect to Functions emulator
24-
const functions = getFunctions();
26+
// Connect to emulator
27+
// 10.0.2.2 is a special IP address to connect to the 'localhost' of the host computer from an Android emulator
28+
const emulatorHost = Platform.OS === 'ios' ? '127.0.0.1' : '10.0.2.2';
2529
if (process.env.NODE_ENV === 'development') {
26-
connectFunctionsEmulator(functions, '127.0.0.1', 5001);
30+
connectFirestoreEmulator(db, emulatorHost, 8080);
31+
connectFunctionsEmulator(functions, emulatorHost, 5001);
2732
}

src/core/env.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
import Constants from 'expo-constants';
99
/**
10-
* @type {typeof import('../../env.js').ClientEnv}
10+
* @type {typeof import('../../env.js').Env}
1111
*/
1212
//@ts-ignore // Don't worry about TypeScript here; we know we're passing the correct environment variables to `extra` in `app.config.ts`.
1313
export const Env = Constants.expoConfig?.extra ?? {};

0 commit comments

Comments
 (0)