Repository navigation
refactor: declare env variables once with envField helpers - #163
Open
devs-rootstrap wants to merge 5 commits into
Open
devs-rootstrap wants to merge 5 commits into
devs-rootstrap wants to merge 5 commits into
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
Hardcoded app-name assertions fail in generated projects because setup replaces the name in env.js but leaves the test expectations unchanged.
1 open issue
What changed in this PR
Overall Review: ai:serious
This PR centralizes environment-variable declarations in typed envField helpers, simplifying the template’s shared build and runtime configuration.
Changes:
- Adds string, number, and boolean builders with optional values, defaults, and stricter parsing.
- Refactors environment loading to read schema keys automatically while preserving static-value precedence.
- Adds helper and integration tests and updates configuration documentation.
| File | Description |
|---|---|
env.js |
Adopts schema-driven loading and separates static values. |
env-fields.js |
Adds typed field builders and environment parsing helpers. |
docs/src/content/docs/recipes/sentry-setup.mdx |
Migrates Sentry configuration examples to envField. |
docs/src/content/docs/getting-started/environment-vars-config.mdx |
Documents single declarations, options, and parsing behavior. |
__tests__/env.test.ts |
Tests loading, validation modes, and static-value precedence. |
__tests__/env-fields.test.ts |
Tests builders, defaults, optional values, and parsing helpers. |
Review effort: Balanced
Comment on lines
+49
to
+58
| NAME: 'RootstrapApp', | ||
| }); | ||
| expect(ClientEnv.VAR_NUMBER).toBe(10); | ||
| expect(ClientEnv).not.toHaveProperty('SECRET_KEY'); | ||
| }); | ||
|
|
||
| it('keeps the static values over the ones in process.env', () => { | ||
| const { Env } = loadEnv({ ...VALID_ENV, NAME: 'OtherName' }, RUN_SCRIPT); | ||
|
|
||
| expect(Env.NAME).toBe('RootstrapApp'); |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Jira board reference:
What does this do?
Adds a small
envFieldinterface to declare environment variables once, with their type, instead of declaring them twice (zod schema + parsed value in_clientEnv/_buildTimeEnv).env-fields.jsmodule (CommonJS, next toenv.js) exposingenvField.string(),envField.number()andenvField.boolean(). Each builder returns a zod schema that receives the rawprocess.envstring, converts it to the declared type and validates it.optionalanddefaultoptions. Without options the variable is required, and an empty value (e.g.API_URL=) is treated as missing.env.jsnow declares each.envvariable only inclientEnvSchema/buildTimeEnvSchema. Values are read fromprocess.envfor every key declared in the schema (readEnv), and the static values defined inenv.js(NAME,BUNDLE_ID,EXPO_ACCOUNT_OWNER, ...) are kept inclientStaticValues/buildTimeStaticValuesand take precedence.parseString/parseNumber/parseBooleancalls and the hand-built_clientEnv/_buildTimeEnventries are removed. Exports (Env,ClientEnv,withEnvSuffix), when validation runs and the error output are the same as before.__tests__/env-fields.test.ts), plus tests that loadenv.jswith a mockedprocess.envin both validation modes (__tests__/env.test.ts).envField.Example:
Why did you do this?
Adding a variable meant writing its zod type in the schema and also remembering to add it to
_clientEnv/_buildTimeEnvwith the rightparseXcall. That repeated logic was easy to get out of sync. WithenvField, the schema is the only place to declare a variable, and the type conversion comes from the declared type.Who/what does this impact?
env.js(used byapp.config.tsand, throughextra, byEnvfrom@/lib/envinsrc). The variables and the exported types stay the same.envField.*instead ofz.*plus a_clientEnv/_buildTimeEnventry.Layer 2: Risk Classification
Author applies a risk label when opening the PR. When in doubt, escalate.
risk:lowrisk:mediumrisk:highLabel applied:
risk:medium(refactor of the shared env loading used by every build and run).How did you test this?
Verification
pnpm lintpnpm type-checkpnpm lint:translationspnpm testenv.jswith Node, with and without the variables setEnv/ClientEnvbuilt as expected;VAR_NUMBERandVAR_BOOLconverted to number / booleanNot verified on a device.
How to test locally
pnpm installpnpm test __tests__/env-fields.test.ts __tests__/env.test.ts.env.sampleto.env.development, fill it in and runpnpm start. The app should start as before.VAR_BOOL=yesorVAR_NUMBER=abc(or removeAPI_URL) and runpnpm startagain. It should fail with the usualInvalid environment variablesmessage listing the variable.Notes:
optionalanddefault, as described in the card's Tasks. The card'scontextidea (build time vs app) is already covered by the existing split betweenclientEnvSchemaandbuildTimeEnvSchema.accessoption (public / secret), similar to Astro'senvField..env.sample.trueandfalseare accepted. Before, any other value (e.g.TRUE,1,yes) was silently converted tofalse; now it fails validation.42,-3.5). Before, whitespace-only values became0and forms likeInfinity,0x10or1e3were accepted; now they fail validation.undefinedinstead of the raw or converted value.env.js(e.g.NAME) take precedence over a variable with the same name in the.envfile, as before.Screenshots / Previews
N/A, no UI changes.