From f0075a4ac76b2bc5124b54b4a6243063f95d44fa Mon Sep 17 00:00:00 2001 From: Brent Vatne Date: Wed, 29 May 2024 13:24:51 +0200 Subject: [PATCH] [expo-constants] Source env when creating app config (#29099) # Why Let's say you have a **.env** with the following config: ``` HELLO_WORLD=123 ``` Then you add that to your `extra` in **app.config.js** ```js { ... "extra": { "helloWorld": process.env.HELLO_WORLD ?? 'ENV VAR NOT DEFINED' } } ``` Then in your app you read the value: ```js export default function App() { return ( process.env.HELLO_WORLD: {Constants.expoConfig.extra.helloWorld} ); } ``` Then you run a build in Expo Go, you will see the value 123. Similarly, if you load it in a dev build, it show the same result. But if you run `npx expo run:android --variant release`, then you will see "ENV VAR NOT DEFINED". Similarly, if you committed that **.env** file to your app (or loaded it in a pre-install hook) on EAS Build, then you will see "ENV VAR NOT DEFINED". This happens because we do not load `@expo/env` in our **getAppConfig.js** script in `expo-constants`. # How Load the env before calling `getConfig(..)` from **getAppConfig.js**. # Test Plan - Applied patch with patch-package - Ran `npx expo run:ios --configuration Release`, `npx expo run:android --variant release`, `eas build -p all --profile preview` - verified in each case that the env is loaded as expected. --- .gitattributes | 1 + packages/expo-constants/CHANGELOG.md | 2 + packages/expo-constants/package.json | 3 +- .../scripts/__tests__/getAppConfig-test.ts | 51 +++++++++++++++++++ .../scripts/build/getAppConfig.d.ts | 1 + .../scripts/build/getAppConfig.js | 29 +++++++++++ .../expo-constants/scripts/getAppConfig.js | 23 +-------- .../expo-constants/scripts/jest.config.js | 1 + .../scripts/src/getAppConfig.ts | 28 ++++++++++ packages/expo-constants/scripts/tsconfig.json | 9 ++++ packages/expo-module-scripts/CHANGELOG.md | 2 + .../babel.config.scripts.js | 1 + .../expo-module-scripts/bin/expo-module-build | 20 +++++--- .../expo-module-scripts/bin/expo-module-lint | 2 +- .../bin/expo-module-prepare | 2 +- .../expo-module-scripts/bin/expo-module-test | 2 +- .../jest-preset-scripts.js | 2 + 17 files changed, 146 insertions(+), 33 deletions(-) create mode 100644 packages/expo-constants/scripts/__tests__/getAppConfig-test.ts create mode 100644 packages/expo-constants/scripts/build/getAppConfig.d.ts create mode 100644 packages/expo-constants/scripts/build/getAppConfig.js create mode 100644 packages/expo-constants/scripts/jest.config.js create mode 100644 packages/expo-constants/scripts/src/getAppConfig.ts create mode 100644 packages/expo-constants/scripts/tsconfig.json create mode 100644 packages/expo-module-scripts/babel.config.scripts.js create mode 100644 packages/expo-module-scripts/jest-preset-scripts.js diff --git a/.gitattributes b/.gitattributes index 792295fe5fec0..0d7a91a3de9e3 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,6 +3,7 @@ packages/*/build/** -diff linguist-generated packages/*/plugin/build/** -diff linguist-generated packages/*/cli/build/** -diff linguist-generated packages/*/utils/build/** -diff linguist-generated +packages/*/scripts/build/** -diff linguist-generated packages/@*/*/build/** -diff linguist-generated ios/vendored/** linguist-vendored diff --git a/packages/expo-constants/CHANGELOG.md b/packages/expo-constants/CHANGELOG.md index 66d8b170200ca..791b2a3ede58d 100644 --- a/packages/expo-constants/CHANGELOG.md +++ b/packages/expo-constants/CHANGELOG.md @@ -8,6 +8,8 @@ ### 🐛 Bug fixes +- Source env when creating app config. ([#29099](https://github.com/expo/expo/pull/29099) by [@brentvatne](https://github.com/brentvatne)) + ### 💡 Others ## 16.0.1 — 2024-04-23 diff --git a/packages/expo-constants/package.json b/packages/expo-constants/package.json index a4c56a9f3523e..fc11b432f5da0 100644 --- a/packages/expo-constants/package.json +++ b/packages/expo-constants/package.json @@ -34,7 +34,8 @@ "preset": "expo-module-scripts" }, "dependencies": { - "@expo/config": "~9.0.0" + "@expo/config": "~9.0.0", + "@expo/env": "~0.3.0" }, "devDependencies": { "expo-module-scripts": "^3.0.0" diff --git a/packages/expo-constants/scripts/__tests__/getAppConfig-test.ts b/packages/expo-constants/scripts/__tests__/getAppConfig-test.ts new file mode 100644 index 0000000000000..e3087ecfc1197 --- /dev/null +++ b/packages/expo-constants/scripts/__tests__/getAppConfig-test.ts @@ -0,0 +1,51 @@ +const { getConfig } = require('@expo/config'); +const fs = require('fs'); +const path = require('path'); +const { load } = require('@expo/env'); + +jest.mock('fs'); +jest.mock('path'); +jest.mock('@expo/config'); +jest.mock('@expo/env', () => ({ + load: jest.fn(), +})); + +const possibleProjectRoot = '/path/to/project'; +const destinationDir = '/path/to/destination'; +const mockExpConfig = { some: 'config' }; + +describe('getAppConfig', () => { + beforeAll(() => { + jest.resetAllMocks(); + // Mock the arguments + process.argv[2] = possibleProjectRoot; + process.argv[3] = destinationDir; + + fs.existsSync.mockImplementation((filePath) => { + if (filePath === path.join(possibleProjectRoot, 'package.json')) { + return true; + } + return false; + }); + + path.join.mockImplementation((...args) => args.join('/')); + path.resolve.mockImplementation((...args) => args.join('/')); + jest.spyOn(process, 'chdir').mockImplementation(() => {}); + getConfig.mockReturnValue({ exp: mockExpConfig }); + + // Import the script (this runs the script) + require('../build/getAppConfig'); + }); + + it('should call writeFileSync with the correct parameters', () => { + // Verify writeFileSync was called with the expected arguments + expect(fs.writeFileSync).toHaveBeenCalledWith( + path.join(destinationDir, 'app.config'), + JSON.stringify(mockExpConfig) + ); + }); + + it('should load from @expo/env', () => { + expect(load).toHaveBeenCalledWith(possibleProjectRoot); + }) +}); diff --git a/packages/expo-constants/scripts/build/getAppConfig.d.ts b/packages/expo-constants/scripts/build/getAppConfig.d.ts new file mode 100644 index 0000000000000..cb0ff5c3b541f --- /dev/null +++ b/packages/expo-constants/scripts/build/getAppConfig.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/packages/expo-constants/scripts/build/getAppConfig.js b/packages/expo-constants/scripts/build/getAppConfig.js new file mode 100644 index 0000000000000..924d2e31e4a11 --- /dev/null +++ b/packages/expo-constants/scripts/build/getAppConfig.js @@ -0,0 +1,29 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const config_1 = require("@expo/config"); +const fs_1 = __importDefault(require("fs")); +const path_1 = __importDefault(require("path")); +const possibleProjectRoot = process.argv[2]; +const destinationDir = process.argv[3]; +// TODO: Verify we can remove projectRoot validation, now that we no longer +// support React Native <= 62 +let projectRoot; +if (fs_1.default.existsSync(path_1.default.join(possibleProjectRoot, 'package.json'))) { + projectRoot = possibleProjectRoot; +} +else if (fs_1.default.existsSync(path_1.default.join(possibleProjectRoot, '..', 'package.json'))) { + projectRoot = path_1.default.resolve(possibleProjectRoot, '..'); +} +else { + throw new Error(`Unable to locate project (no package.json found) at path: ${possibleProjectRoot}`); +} +require('@expo/env').load(projectRoot); +process.chdir(projectRoot); +const { exp } = (0, config_1.getConfig)(projectRoot, { + isPublicConfig: true, + skipSDKVersionRequirement: true, +}); +fs_1.default.writeFileSync(path_1.default.join(destinationDir, 'app.config'), JSON.stringify(exp)); diff --git a/packages/expo-constants/scripts/getAppConfig.js b/packages/expo-constants/scripts/getAppConfig.js index 4b294540f1b08..409d5f55db1ca 100644 --- a/packages/expo-constants/scripts/getAppConfig.js +++ b/packages/expo-constants/scripts/getAppConfig.js @@ -1,22 +1 @@ -const { getConfig } = require('@expo/config'); -const fs = require('fs'); -const path = require('path'); - -const possibleProjectRoot = process.argv[2]; -const destinationDir = process.argv[3]; - -// Remove projectRoot validation when we no longer support React Native <= 62 -let projectRoot; -if (fs.existsSync(path.join(possibleProjectRoot, 'package.json'))) { - projectRoot = possibleProjectRoot; -} else if (fs.existsSync(path.join(possibleProjectRoot, '..', 'package.json'))) { - projectRoot = path.resolve(possibleProjectRoot, '..'); -} - -process.chdir(projectRoot); - -const { exp } = getConfig(projectRoot, { - isPublicConfig: true, - skipSDKVersionRequirement: true, -}); -fs.writeFileSync(path.join(destinationDir, 'app.config'), JSON.stringify(exp)); +require('./build/getAppConfig'); \ No newline at end of file diff --git a/packages/expo-constants/scripts/jest.config.js b/packages/expo-constants/scripts/jest.config.js new file mode 100644 index 0000000000000..a67b34cd0beb2 --- /dev/null +++ b/packages/expo-constants/scripts/jest.config.js @@ -0,0 +1 @@ +module.exports = require('expo-module-scripts/jest-preset-scripts'); diff --git a/packages/expo-constants/scripts/src/getAppConfig.ts b/packages/expo-constants/scripts/src/getAppConfig.ts new file mode 100644 index 0000000000000..607309e30206a --- /dev/null +++ b/packages/expo-constants/scripts/src/getAppConfig.ts @@ -0,0 +1,28 @@ +import { getConfig } from '@expo/config'; +import fs from 'fs'; +import path from 'path'; + +const possibleProjectRoot = process.argv[2]; +const destinationDir = process.argv[3]; + +// TODO: Verify we can remove projectRoot validation, now that we no longer +// support React Native <= 62 +let projectRoot; +if (fs.existsSync(path.join(possibleProjectRoot, 'package.json'))) { + projectRoot = possibleProjectRoot; +} else if (fs.existsSync(path.join(possibleProjectRoot, '..', 'package.json'))) { + projectRoot = path.resolve(possibleProjectRoot, '..'); +} else { + throw new Error( + `Unable to locate project (no package.json found) at path: ${possibleProjectRoot}` + ); +} + +require('@expo/env').load(projectRoot); +process.chdir(projectRoot); + +const { exp } = getConfig(projectRoot, { + isPublicConfig: true, + skipSDKVersionRequirement: true, +}); +fs.writeFileSync(path.join(destinationDir, 'app.config'), JSON.stringify(exp)); diff --git a/packages/expo-constants/scripts/tsconfig.json b/packages/expo-constants/scripts/tsconfig.json new file mode 100644 index 0000000000000..354bddb4336eb --- /dev/null +++ b/packages/expo-constants/scripts/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "expo-module-scripts/tsconfig.plugin", + "compilerOptions": { + "outDir": "build", + "rootDir": "src" + }, + "include": ["./src"], + "exclude": ["**/__mocks__/*", "**/__tests__/*"] +} diff --git a/packages/expo-module-scripts/CHANGELOG.md b/packages/expo-module-scripts/CHANGELOG.md index 0caf2ec49f67e..c9307ff3971d3 100644 --- a/packages/expo-module-scripts/CHANGELOG.md +++ b/packages/expo-module-scripts/CHANGELOG.md @@ -6,6 +6,8 @@ ### 🎉 New features +- Add support for building scripts directory (similar to cli, utils, and plugins). ([#29099](https://github.com/expo/expo/pull/29099) by [@brentvatne](https://github.com/brentvatne)) + ### 🐛 Bug fixes ### 💡 Others diff --git a/packages/expo-module-scripts/babel.config.scripts.js b/packages/expo-module-scripts/babel.config.scripts.js new file mode 100644 index 0000000000000..4bbab44d8026d --- /dev/null +++ b/packages/expo-module-scripts/babel.config.scripts.js @@ -0,0 +1 @@ +module.exports = require('./babel.config.cli'); diff --git a/packages/expo-module-scripts/bin/expo-module-build b/packages/expo-module-scripts/bin/expo-module-build index 845a146464db4..7c556d528ecb9 100755 --- a/packages/expo-module-scripts/bin/expo-module-build +++ b/packages/expo-module-scripts/bin/expo-module-build @@ -8,16 +8,22 @@ args=("$@") # If the command is used like `yarn build plugin`, set the --build option to point to # plugin/tsconfig.json -extra_module_build_types=("plugin" "cli" "utils") +extra_module_build_types=("plugin" "cli" "utils" "scripts") for i in "${extra_module_build_types[@]}" do if [ "$1" == "$i" ]; then - # `--build` must be the first argument, so reset the array - args=() - args+=("--build") - args+=("$(pwd)/$i") - # Push the rest of the arguments minus the `plugin` arg - args+=("${@:2}") + # Check if tsconfig.json exists in the directory + if [ -f "$(pwd)/$i/tsconfig.json" ]; then + # `--build` must be the first argument, so reset the array + args=() + args+=("--build") + args+=("$(pwd)/$i") + # Push the rest of the arguments minus the `plugin` arg + args+=("${@:2}") + else + echo "tsconfig.json not found in $@, skipping build for $@/" + exit + fi fi done diff --git a/packages/expo-module-scripts/bin/expo-module-lint b/packages/expo-module-scripts/bin/expo-module-lint index d388c4975a3eb..689c4c18641e3 100755 --- a/packages/expo-module-scripts/bin/expo-module-lint +++ b/packages/expo-module-scripts/bin/expo-module-lint @@ -7,7 +7,7 @@ script_dir="$(dirname "$0")" args=() # If the command is used like `yarn lint plugin` then set the target to `plugin/src` -extra_module_build_types=("plugin" "cli" "utils") +extra_module_build_types=("plugin" "cli" "utils" "scripts") found_target="" for i in "${extra_module_build_types[@]}" do diff --git a/packages/expo-module-scripts/bin/expo-module-prepare b/packages/expo-module-scripts/bin/expo-module-prepare index 0efd1c67fab61..26484488c9dbf 100755 --- a/packages/expo-module-scripts/bin/expo-module-prepare +++ b/packages/expo-module-scripts/bin/expo-module-prepare @@ -11,7 +11,7 @@ echo "Configuring module" "$script_dir/expo-module-configure" "$script_dir/expo-module-build" -extra_module_build_types=("plugin" "cli" "utils") +extra_module_build_types=("plugin" "cli" "utils" "scripts") for i in "${extra_module_build_types[@]}" do if [[ -d "$i" ]]; then diff --git a/packages/expo-module-scripts/bin/expo-module-test b/packages/expo-module-scripts/bin/expo-module-test index 7faf1f1fa0678..3c9835249195c 100755 --- a/packages/expo-module-scripts/bin/expo-module-test +++ b/packages/expo-module-scripts/bin/expo-module-test @@ -7,7 +7,7 @@ script_dir="$(dirname "$0")" args=("$@") # If the command is used like `yarn test plugin`, set the --rootDir option to the `plugin` directory -extra_module_build_types=("plugin" "cli" "utils") +extra_module_build_types=("plugin" "cli" "utils" "scripts") for i in "${extra_module_build_types[@]}" do if [ "$1" == "$i" ]; then diff --git a/packages/expo-module-scripts/jest-preset-scripts.js b/packages/expo-module-scripts/jest-preset-scripts.js new file mode 100644 index 0000000000000..276e1a01a37be --- /dev/null +++ b/packages/expo-module-scripts/jest-preset-scripts.js @@ -0,0 +1,2 @@ +/** @type {import('jest').Config} */ +module.exports = require('./jest-preset-cli');