├── .circleci └── config.yml ├── .editorconfig ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ └── bug_report.md ├── dependabot.yml ├── pull_request_template.md ├── stale.yml └── workflows │ ├── dependabot.yml │ └── issuehunt.yml ├── .gitignore ├── .vscode └── launch.json ├── .yarnrc.yml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SECURITY.md ├── __tests__ ├── __fixtures__ │ ├── allowlist │ │ ├── .babelrc │ │ ├── .env │ │ └── source.js │ ├── app-env-development │ │ ├── .babelrc │ │ ├── .env │ │ ├── .env.development │ │ └── source.js │ ├── app-env-production │ │ ├── .babelrc │ │ ├── .env │ │ ├── .env.production │ │ └── source.js │ ├── app-env │ │ ├── .babelrc │ │ ├── .env │ │ ├── .env.cli │ │ └── source.js │ ├── as-alias │ │ ├── .babelrc │ │ ├── .env │ │ └── source.js │ ├── blacklist │ │ ├── .babelrc │ │ ├── .env │ │ └── source.js │ ├── blocklist │ │ ├── .babelrc │ │ ├── .env │ │ └── source.js │ ├── custom-module │ │ ├── .babelrc │ │ ├── .env │ │ └── source.js │ ├── default-import │ │ ├── .babelrc │ │ └── source.js │ ├── default-safe │ │ ├── .babelrc │ │ ├── .env │ │ └── source.js │ ├── default │ │ ├── .babelrc │ │ ├── .env │ │ └── source.js │ ├── env-name │ │ ├── .babelrc │ │ ├── .env │ │ ├── .env.cli │ │ └── source.js │ ├── filename │ │ ├── .babelrc │ │ ├── .env │ │ ├── .env.build │ │ └── source.js │ ├── from-env │ │ ├── .babelrc │ │ └── source.js │ ├── local-env │ │ ├── .babelrc │ │ ├── .env │ │ ├── .env.test │ │ ├── .env.test.local │ │ └── source.js │ ├── module-name │ │ ├── .babelrc │ │ ├── .env │ │ └── source.js │ ├── multi-env │ │ ├── .babelrc │ │ ├── .env │ │ ├── .env.test │ │ └── source.js │ ├── process-env-propagate │ │ ├── .babelrc │ │ ├── .env │ │ └── source.js │ ├── process-env-undefined │ │ ├── .babelrc │ │ ├── .env │ │ └── source.js │ ├── process-env │ │ ├── .babelrc │ │ ├── .env │ │ └── source.js │ ├── require-import │ │ ├── .babelrc │ │ ├── .env │ │ └── source.js │ ├── safe-error │ │ ├── .babelrc │ │ ├── .env │ │ └── source.js │ ├── safe-no-dotenv │ │ ├── .babelrc │ │ └── source.js │ ├── safe-success │ │ ├── .babelrc │ │ ├── .env │ │ └── source.js │ ├── undefined │ │ ├── .babelrc │ │ └── source.js │ ├── unused │ │ ├── .babelrc │ │ ├── .env │ │ └── source.js │ ├── variable-not-exist │ │ ├── .babelrc │ │ └── source.js │ ├── verbose │ │ ├── .babelrc │ │ ├── .env │ │ └── source.js │ ├── whitelist │ │ ├── .babelrc │ │ ├── .env │ │ └── source.js │ └── wildcard-import │ │ ├── .babelrc │ │ └── source.js └── index.test.js ├── index.js ├── package.json ├── tea.yaml └── yarn.lock /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | defaults: 4 | workspace_root: &workspace_root 5 | ~/react-native-dotenv 6 | 7 | nodejs_container: &nodejs_container 8 | working_directory: *workspace_root 9 | docker: 10 | - image: cimg/node:lts 11 | 12 | filters: &default_filters 13 | tags: 14 | only: '/v[0-9]+(\.[0-9]+)*/' 15 | 16 | attach_workspace: &attach_workspace 17 | attach_workspace: 18 | at: *workspace_root 19 | 20 | restore_node_modules: &restore_node_modules 21 | restore_cache: 22 | name: Restore node_modules cache 23 | keys: 24 | - v3-react-native-dotenv-node-{{ .Branch }}-{{ checksum "yarn.lock" }} 25 | - v3-react-native-dotenv-node-main-{{ checksum "yarn.lock" }} 26 | - v3-react-native-dotenv-node-main- 27 | 28 | jobs: 29 | checkout: 30 | <<: *nodejs_container 31 | steps: 32 | - checkout 33 | 34 | - persist_to_workspace: 35 | root: *workspace_root 36 | paths: 37 | - ./ 38 | 39 | install: 40 | <<: *nodejs_container 41 | steps: 42 | - *attach_workspace 43 | - *restore_node_modules 44 | 45 | - restore_cache: 46 | name: Restore yarn cache 47 | keys: 48 | - v3-react-native-dotenv-yarn-{{ checksum "yarn.lock" }} 49 | - v3-react-native-dotenv-yarn- 50 | 51 | - run: 52 | name: Install dependencies 53 | command: yarn --frozen-lockfile 54 | 55 | - save_cache: 56 | name: Save yarn cache 57 | key: v3-react-native-dotenv-yarn-{{ checksum "yarn.lock" }} 58 | paths: 59 | - ~/.cache/yarn/ 60 | 61 | - save_cache: 62 | name: Save node_modules cache 63 | key: v3-react-native-dotenv-node-{{ .Branch }}-{{ checksum "yarn.lock" }} 64 | paths: 65 | - node_modules/ 66 | 67 | lint: 68 | <<: *nodejs_container 69 | steps: 70 | - *attach_workspace 71 | - *restore_node_modules 72 | 73 | - run: 74 | name: Lint JavaScript 75 | command: yarn xo 76 | 77 | test: 78 | <<: *nodejs_container 79 | steps: 80 | - *attach_workspace 81 | - *restore_node_modules 82 | 83 | - run: 84 | name: Run tests 85 | command: yarn test 86 | 87 | - store_test_results: 88 | path: reports/tests/ 89 | 90 | - run: 91 | name: Upload code coverage to codecov 92 | command: yarn codecov 93 | 94 | workflows: 95 | version: 2 96 | 97 | push: 98 | jobs: 99 | - checkout: 100 | filters: *default_filters 101 | 102 | - install: 103 | requires: 104 | - checkout 105 | filters: *default_filters 106 | 107 | - lint: 108 | requires: 109 | - install 110 | filters: *default_filters 111 | 112 | - test: 113 | requires: 114 | - install 115 | filters: *default_filters 116 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [goatandsheep] 4 | patreon: goatandsheep 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: goatandsheep 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: goatandsheep 7 | 8 | --- 9 | 10 | - [ ] Asked question in discussions 11 | - [ ] Tried the troubleshooting Wiki 12 | - [ ] Followed the migration Wiki 13 | - [ ] Installed library as devDependency not production dependency 14 | 15 | **Describe the bug** 16 | A clear and concise description of what the bug is. 17 | 18 | **To Reproduce** 19 | Steps to reproduce the behavior: 20 | 1. Go to '...' 21 | 2. Click on '....' 22 | 3. Scroll down to '....' 23 | 4. See error 24 | 25 | **Expected behavior** 26 | A clear and concise description of what you expected to happen. 27 | 28 | **Screenshots** 29 | If applicable, add screenshots to help explain your problem. 30 | 31 | **Desktop (please complete the following information):** 32 | - OS: [e.g. iOS] 33 | - Browser [e.g. chrome, safari] 34 | - Version [e.g. 22] 35 | 36 | **Smartphone (please complete the following information):** 37 | - Device: [e.g. iPhone6] 38 | - OS: [e.g. iOS8.1] 39 | - Browser [e.g. stock browser, safari] 40 | - Version [e.g. 22] 41 | 42 | **Additional context** 43 | Add any other context about the problem here. 44 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "10:00" 8 | open-pull-requests-limit: 10 9 | versioning-strategy: increase 10 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Link to issue ## 2 | 3 | 4 | 5 | ## Description of changes being made ## 6 | 7 | * What was the solution to the problem? 8 | * Did you set option `verbose: true` in your babel config? If so, what was the output? 9 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 60 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 7 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - pinned 8 | - security 9 | # Label to use when marking an issue as stale 10 | staleLabel: wontfix 11 | # Comment to post when marking an issue as stale. Set to `false` to disable 12 | markComment: > 13 | This issue has been automatically marked as stale because it has not had 14 | recent activity. It will be closed if no further activity occurs. Thank you 15 | for your contributions. 16 | # Comment to post when closing a stale issue. Set to `false` to disable 17 | closeComment: false -------------------------------------------------------------------------------- /.github/workflows/dependabot.yml: -------------------------------------------------------------------------------- 1 | name: CreateDependabotIssue 2 | on: 3 | workflow_dispatch: 4 | pull_request: 5 | types: [opened, reopened] 6 | 7 | jobs: 8 | issue: 9 | runs-on: ubuntu-latest 10 | env: 11 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 12 | steps: 13 | - name: Checks if Dependabot PR 14 | if: ${{github.event_name != 'pull_request'}} 15 | run: echo "no dependabot" 16 | - uses: actions/checkout@v2 17 | if: ${{github.event.pull_request.user.login == 'dependabot[bot]' || github.event.pull_request.user.login == 'app/dependabot'}} 18 | 19 | - name: Open issue if Dependabot PR 20 | if: ${{github.event.pull_request.user.login == 'dependabot[bot]' || github.event.pull_request.user.login == 'app/dependabot'}} 21 | env: 22 | pr_title: ${{github.event.pull_request.title}} 23 | pr_number: ${{github.event.pull_request.number}} 24 | pr_url: ${{github.event.pull_request.url}} 25 | run: | 26 | title="Dependabot PR $pr_title opened" 27 | body="Dependabot has opened PR #$pr_number 28 | Link: $pr_url" 29 | gh issue create --title "$title" --body "$body" 30 | -------------------------------------------------------------------------------- /.github/workflows/issuehunt.yml: -------------------------------------------------------------------------------- 1 | name: Auto message for Issues 2 | on: 3 | issues: 4 | types: [opened, reopened] 5 | jobs: 6 | comment: 7 | name: Hello new contributor 8 | runs-on: ubuntu-latest 9 | env: 10 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 11 | steps: 12 | - uses: actions/checkout@v2 13 | - name: Posts comment 14 | env: 15 | issue_num: ${{github.event.issue.number}} 16 | comment_message: "Hey, thank you for opening this issue! 🙂 To boost priority on this issue and support open source please tip the team at https://issuehunt.io/r/${{github.repository}}/issues/${{github.event.issue.number }}" 17 | run: gh issue comment $issue_num --body "$comment_message" 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | reports 4 | 5 | .nyc_output 6 | 7 | .vs 8 | .idea 9 | 10 | .yarn/* 11 | !.yarn/patches 12 | !.yarn/releases 13 | !.yarn/plugins 14 | !.yarn/sdks 15 | !.yarn/versions 16 | .pnp.* 17 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "command": "npm run test", 5 | "name": "Run npm run test", 6 | "request": "launch", 7 | "type": "node-terminal" 8 | } 9 | ] 10 | } -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | 2 | ​#​ ​Contributor Covenant Code of Conduct 3 | 4 | ​##​ ​Our Pledge 5 | 6 | ​We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. 7 | 8 | ​We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. 9 | 10 | ​##​ ​Our Standards 11 | 12 | ​Examples of behavior that contributes to a positive environment for our community include: 13 | 14 | ​*​ Demonstrating empathy and kindness toward other people 15 | ​*​ Being respectful of differing opinions, viewpoints, and experiences 16 | ​*​ Giving and gracefully accepting constructive feedback 17 | ​*​ Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience 18 | ​*​ Focusing on what is best not just for us as individuals, but for the overall community 19 | 20 | ​Examples of unacceptable behavior include: 21 | 22 | ​*​ The use of sexualized language or imagery, and sexual attention or 23 | ​  advances of any kind 24 | ​*​ Trolling, insulting or derogatory comments, and personal or political attacks 25 | ​*​ Public or private harassment 26 | ​*​ Publishing others' private information, such as a physical or email 27 | ​  address, without their explicit permission 28 | ​*​ Other conduct which could reasonably be considered inappropriate in a 29 | ​  professional setting 30 | 31 | ​##​ ​Enforcement Responsibilities 32 | 33 | ​Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. 34 | 35 | ​Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. 36 | 37 | ​##​ ​Scope 38 | 39 | ​This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. 40 | 41 | ​##​ ​Enforcement 42 | 43 | ​Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement. All complaints will be reviewed and investigated promptly and fairly. 44 | 45 | ​All community leaders are obligated to respect the privacy and security of the reporter of any incident. 46 | 47 | ​##​ ​Enforcement Guidelines 48 | 49 | ​Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: 50 | 51 | ​###​ ​1. Correction 52 | 53 | ​**Community Impact**​: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. 54 | 55 | ​**Consequence**​: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. 56 | 57 | ​###​ ​2. Warning 58 | 59 | ​**Community Impact**​: A violation through a single incident or series of actions. 60 | 61 | ​**Consequence**​: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. 62 | 63 | ​###​ ​3. Temporary Ban 64 | 65 | ​**Community Impact**​: A serious violation of community standards, including sustained inappropriate behavior. 66 | 67 | ​**Consequence**​: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. 68 | 69 | ​###​ ​4. Permanent Ban 70 | 71 | ​**Community Impact**​: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior,  harassment of an individual, or aggression toward or disparagement of classes of individuals. 72 | 73 | ​**Consequence**​: A permanent ban from any sort of public interaction within the project community. 74 | 75 | ​##​ ​Attribution 76 | 77 | ​This Code of Conduct is adapted from the [​Contributor Covenant​][homepage], version 2.0, 78 | ​available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 79 | 80 | ​Community Impact Guidelines were inspired by [​Mozilla's code of conduct enforcement ladder​](https://github.com/mozilla/diversity). 81 | 82 | ​For answers to common questions about this code of conduct, see the FAQ at 83 | ​https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations. -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute 2 | 3 | ​I'm really glad you're reading this, because we need volunteer developers to help this project come to fruition. 4 | 5 | ​If you haven't already, come find us in discussions tab on GitHub. 6 | We want you working on things you're excited about. 7 | 8 | ## ​Testing 9 | 10 | ​We have a handful of tests. Please write tests for new code you create. 11 | ## ​Submitting changes 12 | 13 | ​Please send a GitHub Pull Request with a clear list of what you've done (read more about [​pull requests​](http://help.github.com/pull-requests/)). 14 | When you send a pull request, we will love you forever if you include tests.We can always use more test coverage. Please follow our coding conventions (below) and make sure all of your commits are atomic (one feature per commit). 15 | 16 | ​Always write a clear log message for your commits. One-line messages are fine for small changes but bigger changes should look like this: 17 | 18 | $ git commit -m "A brief summary of the commit 19 | ​>​  20 | ​>​ A paragraph describing what changed and its impact." 21 | 22 | ## ​Coding conventions 23 | 24 | Start reading our code and you'll get the hang of it. We optimize for readability: 25 | 26 | - We indent using two spaces (soft tab) 27 | - This is open source software. Consider the people who will read your code, and make it look nice for them. 28 | 29 |  It's sort of like driving a car: Perhaps you love doing donuts when you're alone, but with passengers the goal is to make the ride as smooth as possible. 30 | 31 | ​Thanks, 32 | ​Kemal Ahmed 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Bertrand Marron 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-native-dotenv [![CircleCI](https://circleci.com/gh/goatandsheep/react-native-dotenv.svg?style=svg)](https://circleci.com/gh/goatandsheep/react-native-dotenv) 2 | 3 | > Load environment variables using `import` statements. 4 | 5 | [![npm version](https://badgen.net/npm/v/react-native-dotenv)](https://www.npmjs.com/package/react-native-dotenv) 6 | [![dependencies Status](https://img.shields.io/librariesio/release/npm/react-native-dotenv)](https://img.shields.io/librariesio/release/npm/react-native-dotenv) 7 | [![codecov](https://badgen.net/codecov/c/github/goatandsheep/react-native-dotenv)](https://codecov.io/gh/goatandsheep/react-native-dotenv) 8 | [![XO code style](https://badgen.net/badge/code%20style/XO/cyan)](https://github.com/xojs/xo) 9 | [![npm downloads](https://img.shields.io/npm/dt/react-native-dotenv.svg?style=flat-square)](https://www.npmjs.com/package/react-native-dotenv) 10 | [![works with dotenv-vault](https://badge.dotenv.org/works-with.svg?r=1)](https://www.dotenv.org/r/github.com/dotenv-org/dotenv-vault?r=1) 11 | 12 | ## Installation 13 | 14 | ```sh 15 | $ npm install -D react-native-dotenv 16 | ``` 17 | 18 | If you are using Yarn: 19 | 20 | ```sh 21 | $ yarn add -D react-native-dotenv 22 | ``` 23 | 24 | **Breaking changes**: moving from `v0.x` to `v2.x` changes both the setup and usage of this package. Please see the [migration guide](https://github.com/goatandsheep/react-native-dotenv/wiki/Migration-Guide). 25 | 26 | Many have been asking about the reasons behind recent changes in this repo. Please see the [story wiki page](https://github.com/goatandsheep/react-native-dotenv/wiki/Story-of-this-repo). 27 | 28 | ## Introduction 29 | 30 | This babel plugin lets you inject your environment variables into your Javascript environment using dotenv for multiple environments. It is best suited for use with react native and works with all flavors including web. 31 | 32 | ## Usage 33 | 34 | > Also preview [the expo test app](https://github.com/goatandsheep/react-native-dotenv-expo-test). 35 | 36 | **babel.config.js** 37 | 38 | Basic setup: 39 | 40 | ```javascript 41 | api.cache(false) 42 | module.exports = { 43 | plugins: [ 44 | ['module:react-native-dotenv'] 45 | ] 46 | }; 47 | ``` 48 | 49 | If the defaults do not cut it for your project, this outlines the available options for your Babel configuration and their respective default values, but you do not need to add them if you are using the default settings. 50 | 51 | ```javascript 52 | api.cache(false) 53 | module.exports = { 54 | plugins: [ 55 | [ 56 | 'module:react-native-dotenv', 57 | { 58 | envName: 'APP_ENV', 59 | moduleName: '@env', 60 | path: '.env', 61 | blocklist: null, 62 | allowlist: null, 63 | blacklist: null, // DEPRECATED 64 | whitelist: null, // DEPRECATED 65 | safe: false, 66 | allowUndefined: true, 67 | verbose: false, 68 | }, 69 | ], 70 | ], 71 | }; 72 | 73 | ``` 74 | 75 | > Note: for safe mode, it's highly recommended to set `allowUndefined` to `false`. 76 | 77 | > Note: Expo now has [built-in environment variable support](https://docs.expo.dev/guides/environment-variables/). Evaluate if you need 78 | 79 | **.env** 80 | 81 | ```dosini 82 | API_URL=https://api.example.org 83 | API_TOKEN=abc123 84 | ``` 85 | 86 | ### process.env technique 87 | 88 | In **users.js** 89 | 90 | ```js 91 | fetch(`${process.env.API_URL}/users`, { 92 | headers: { 93 | 'Authorization': `Bearer ${process.env.API_TOKEN}` 94 | } 95 | }) 96 | ``` 97 | 98 | ### Import technique 99 | 100 | > The import technique, which is the initial functionality of the library, is to have an import statement at the top that turns into an object because of Babel 101 | 102 | In **users.js** 103 | 104 | ```js 105 | import {API_URL, API_TOKEN} from "@env" 106 | 107 | fetch(`${API_URL}/users`, { 108 | headers: { 109 | 'Authorization': `Bearer ${API_TOKEN}` 110 | } 111 | }) 112 | ``` 113 | 114 | ## [DEPRECATED] White and black lists 115 | 116 | Moving forward to a more inclusive language, terms like `white` and `black` are being moved away. Future versions will just use `allowlist` and `blocklist` while `whitelist`/`blacklist` are still supported. 117 | 118 | ## Allow and Block lists 119 | 120 | It is possible to limit the scope of env variables that will be imported by specifying a `allowlist` and/or a `blocklist` as an array of strings. 121 | 122 | ```json 123 | { 124 | "plugins": [ 125 | ["module:react-native-dotenv", { 126 | "blocklist": [ 127 | "GITHUB_TOKEN" 128 | ] 129 | }] 130 | ] 131 | } 132 | ``` 133 | 134 | ```json 135 | { 136 | "plugins": [ 137 | ["module:react-native-dotenv", { 138 | "allowlist": [ 139 | "API_URL", 140 | "API_TOKEN" 141 | ] 142 | }] 143 | ] 144 | } 145 | ``` 146 | 147 | ## Safe mode 148 | 149 | Enable safe mode to only allow environment variables defined in the `.env` file. This will completely ignore everything that is already defined in the environment. 150 | 151 | The `.env` file has to exist. 152 | 153 | ```json 154 | { 155 | "plugins": [ 156 | ["module:react-native-dotenv", { 157 | "safe": true 158 | }] 159 | ] 160 | } 161 | ``` 162 | 163 | ## Allow undefined 164 | 165 | Allow importing undefined variables, their value will be `undefined`. 166 | 167 | ```json 168 | { 169 | "plugins": [ 170 | ["module:react-native-dotenv", { 171 | "allowUndefined": true 172 | }] 173 | ] 174 | } 175 | ``` 176 | 177 | ```js 178 | import {UNDEFINED_VAR} from '@env' 179 | 180 | console.log(UNDEFINED_VAR === undefined) // true 181 | ``` 182 | 183 | When set to `false`, an error will be thrown. **This is no longer default behavior**. 184 | 185 | ## Override `envName` 186 | 187 | One thing that we've noticed is that metro overwrites the test environment variable even if you specify a config, so we've added a way to fix this. By default, defining the `APP_ENV` variable can be used to set your preferred environment, separate from `NODE_ENV`. 188 | 189 | ```json 190 | // package.json 191 | { 192 | "scripts": { 193 | "start:staging": "APP_ENV=staging npx react-native start", 194 | } 195 | } 196 | ``` 197 | The above example would use the `.env.staging` file. The standard word is `test`, but go nuts. 198 | 199 | To use your own defined name as the environment override, you can define it using `envName`: 200 | 201 | ```json 202 | { 203 | "plugins": [ 204 | ["module:react-native-dotenv", { 205 | "envName": "MY_ENV" 206 | }] 207 | ] 208 | } 209 | ``` 210 | 211 | Now you can define `MY_ENV`: 212 | 213 | ```json 214 | // package.json 215 | { 216 | "scripts": { 217 | "start:staging": "MY_ENV=staging npx react-native start", 218 | } 219 | } 220 | ``` 221 | 222 | Note: if you're using `APP_ENV` (or `envName`), you cannot use `development` nor `production` as values, and you should avoid having a `.env.development` or `.env.production`. This is a Babel and Node thing that I have little control over unfortunately and is consistent with many other platforms that have an override option, like [Gatsby](https://www.gatsbyjs.com/docs/how-to/local-development/environment-variables/#additional-environments-staging-test-etc). If you want to use `development` and `production`, you should not use `APP_ENV` (or `envName`), but rather the built-in `NODE_ENV=development` or `NODE_ENV=production`. 223 | 224 | 225 | ## Multi-env 226 | 227 | This package now supports environment specific variables. This means you may now import environment variables from multiple files, i.e. `.env`, `.env.development`, `.env.production`, and `.env.test`. This is based on [dotenv-flow](https://www.npmjs.com/package/dotenv-flow). 228 | 229 | Note: it is not recommended that you commit any sensitive information in `.env` file to code in case your git repo is exposed. The best practice is to put a `.env.template` or `.env.development.template` that contains dummy values so other developers know what to configure. Then add your `.env` and `.env.development` to `.gitignore`. You can also keep sensitive keys in a separate `.env.local` (and respective `.env.local.template`) in `.gitignore` and you can use your other `.env` files for non-sensitive config. 230 | 231 | If you are publishing your apps on an auto-publishing platform like EAS (Expo Application Services), make sure to put your secrets on the platform dashboard directly. If you are wondering what environment the platforms choose it is likely `.env.production` (not `.env.prod`) and there is likely no way to change this. 232 | 233 | The base set of variables will be `.env` and the environment-specific variables will overwrite them. 234 | 235 | The variables will automatically be pulled from the appropriate environment and `development` is the default. The choice of environment is based on your Babel environment first and if that value is not set, your NPM environment, which should actually be the same, but this makes it more robust. 236 | 237 | In general, **Release** is `production` and **Debug** is `development`. 238 | 239 | To choose, setup your scripts with `NODE_ENV` for each environment 240 | 241 | ```json 242 | // package.json 243 | { 244 | "scripts": { 245 | "start:development": "NODE_ENV=development npx react-native start", 246 | "start:production": "NODE_ENV=production npx react-native start", 247 | } 248 | } 249 | ``` 250 | 251 | ## TypeScript 252 | 253 | For the library to work with TypeScript, you must manually specify the types for the module. 254 | 255 | - Create a `types` folder in your project 256 | - Inside that folder, create a `*.d.ts`file, say, `env.d.ts` 257 | - in that file, declare a module as the following format: 258 | 259 | ```ts 260 | declare module '@env' { 261 | export const API_BASE: string; 262 | } 263 | ``` 264 | 265 | Add all of your .env variables inside this module. 266 | 267 | - Finally, add this folder into the `typeRoots` field in your `tsconfig.json` file: 268 | 269 | ```json 270 | { 271 | ... 272 | "compilerOptions": { 273 | ... 274 | "typeRoots": ["./types"], 275 | ... 276 | } 277 | ... 278 | } 279 | ``` 280 | 281 | ## Reference Material 282 | 283 | If you are not familiar with how dotenv or Babel work, make sure to read the following reference materials: 284 | 285 | * [babel environments](https://babeljs.io/docs/en/6.26.3/babelrc#env-option) 286 | * [dotenv documentation](https://www.npmjs.com/package/dotenv) 287 | * [See the wiki for more troubleshooting tips](https://github.com/goatandsheep/react-native-dotenv/wiki/Multi-env-troubleshooting) 288 | 289 | ### How this works 290 | 291 | This Babel plugin processes your `.env` files and your environment variables and replaces the references to the environment variables in your code before it runs. This is because the environment variables will no longer be accessible once the React Native engine generates the app outputs. 292 | 293 | ## Cacheing 294 | 295 | When using with [`babel-loader`](https://github.com/babel/babel-loader) with caching enabled you will run into issues where environment changes won’t be picked up. 296 | This is due to the fact that `babel-loader` computes a `cacheIdentifier` that does not take your `.env` file(s) into account. The good news is that a recent update has fixed this problem as long as you're using a new version of Babel. Many react native libraries have not updated their Babel version yet so to force the version, add in your `package.json`: 297 | 298 | ```json 299 | "resolutions": { 300 | "@babel/core": "^7.20.2", 301 | "babel-loader": "^8.3.0" 302 | } 303 | ``` 304 | 305 | If this does not work, you should set `api.cache(false)` in your babel config 306 | 307 | metro.config.js`resetCache: true` 308 | 309 | You can easily clear the cache: 310 | 311 | ```shell 312 | rm -rf node_modules/.cache/babel-loader/* 313 | ``` 314 | 315 | or 316 | 317 | `npm start -- --reset-cache` 318 | 319 | or 320 | 321 | `yarn start --reset-cache` 322 | 323 | or 324 | 325 | `yarn start --clear` 326 | 327 | or 328 | 329 | `jest --no-cache` 330 | 331 | or 332 | 333 | `expo r -c` 334 | 335 | and 336 | 337 | `expo start --clear` 338 | 339 | or 340 | 341 | `rm -rf .expo/web/cache` 342 | 343 | or 344 | 345 | [react-native-clean-project](https://www.npmjs.com/package/react-native-clean-project) 346 | 347 | Maybe a solution for updating package.json scripts: 348 | 349 | > "cc": "rimraf node_modules/.cache/babel-loader/*,", 350 | > "android": "npm run cc && react-native run-android", 351 | > "ios": "npm run cc && react-native run-ios", 352 | 353 | Or you can override the default `cacheIdentifier` to include some of your environment variables. 354 | 355 | The tests that use `require('@env')` are also not passing. 356 | 357 | For nextjs, you _must_ set `moduleName` to `react-native-dotenv`. 358 | 359 | ## Credits 360 | 361 | * Based on [David Chang](https://github.com/zetachang)’s works on [babel-plugin-dotenv](https://github.com/zetachang/react-native-dotenv/tree/master/babel-plugin-dotenv). 362 | * Also based on [Bertrand Marron](https://github.com/tusbar)'s works on [babel-plugin-dotenv-import](https://github.com/tusbar/babel-plugin-dotenv-import). 363 | 364 | If you'd like to become an active contributor, please send us a message. 365 | 366 | ## Miscellaneous 367 | 368 | ``` 369 | ╚⊙ ⊙╝ 370 | ╚═(███)═╝ 371 | ╚═(███)═╝ 372 | ╚═(███)═╝ 373 | ╚═(███)═╝ 374 | ╚═(███)═╝ 375 | ╚═(███)═╝ 376 | ``` 377 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Use this section to tell people about which versions of your project are 6 | currently being supported with security updates. 7 | 8 | | Version | Supported | 9 | | ------- | ------------------ | 10 | | 5.1.x | :white_check_mark: | 11 | | 5.0.x | :x: | 12 | | 4.0.x | :white_check_mark: | 13 | | < 4.0 | :x: | 14 | 15 | ## Reporting a Vulnerability 16 | 17 | Use this section to tell people how to report a vulnerability. 18 | 19 | Tell them where to go, how often they can expect to get an update on a 20 | reported vulnerability, what to expect if the vulnerability is accepted or 21 | declined, etc. 22 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/allowlist/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | ["../../../", { 4 | "path": "__tests__/__fixtures__/allowlist/.env", 5 | "allowlist": [ 6 | "ALLOWLISTED" 7 | ] 8 | }] 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/allowlist/.env: -------------------------------------------------------------------------------- 1 | ALLOWLISTED=1 2 | NOT_ALLOWLISTED=1 3 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/allowlist/source.js: -------------------------------------------------------------------------------- 1 | import {NOT_ALLOWLISTED} from '@env' 2 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/app-env-development/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | ["../../../", { 4 | "path": "__tests__/__fixtures__/app-env/.env", 5 | "verbose": true 6 | }] 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/app-env-development/.env: -------------------------------------------------------------------------------- 1 | API_KEY=never 2 | DEV_USERNAME=this-should-not-appear 3 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/app-env-development/.env.development: -------------------------------------------------------------------------------- 1 | API_KEY=abc123456 2 | DEV_USERNAME=username123456 3 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/app-env-development/source.js: -------------------------------------------------------------------------------- 1 | import {API_KEY, DEV_USERNAME} from '@env' 2 | 3 | console.log(API_KEY) 4 | console.log(DEV_USERNAME) 5 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/app-env-production/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | ["../../../", { 4 | "path": "__tests__/__fixtures__/app-env/.env", 5 | "verbose": true 6 | }] 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/app-env-production/.env: -------------------------------------------------------------------------------- 1 | API_KEY=never 2 | DEV_USERNAME=this-should-not-appear 3 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/app-env-production/.env.production: -------------------------------------------------------------------------------- 1 | API_KEY=abc123456 2 | DEV_USERNAME=username123456 3 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/app-env-production/source.js: -------------------------------------------------------------------------------- 1 | import {API_KEY, DEV_USERNAME} from '@env' 2 | 3 | console.log(API_KEY) 4 | console.log(DEV_USERNAME) 5 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/app-env/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | ["../../../", { 4 | "path": "__tests__/__fixtures__/app-env/.env" 5 | }] 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/app-env/.env: -------------------------------------------------------------------------------- 1 | API_KEY=never 2 | DEV_USERNAME=this-should-not-appear 3 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/app-env/.env.cli: -------------------------------------------------------------------------------- 1 | API_KEY=abc123456 2 | DEV_USERNAME=username123456 3 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/app-env/source.js: -------------------------------------------------------------------------------- 1 | import {API_KEY, DEV_USERNAME} from '@env' 2 | 3 | console.log(API_KEY) 4 | console.log(DEV_USERNAME) 5 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/as-alias/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | ["../../../", { 4 | "path": "__tests__/__fixtures__/as-alias/.env" 5 | }] 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/as-alias/.env: -------------------------------------------------------------------------------- 1 | API_KEY=abc123 2 | DEV_USERNAME=username 3 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/as-alias/source.js: -------------------------------------------------------------------------------- 1 | import {API_KEY as key, DEV_USERNAME as username} from '@env' 2 | 3 | const a = key 4 | const b = username 5 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/blacklist/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | ["../../../", { 4 | "path": "__tests__/__fixtures__/blacklist/.env", 5 | "blacklist": [ 6 | "BLACKLISTED" 7 | ] 8 | }] 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/blacklist/.env: -------------------------------------------------------------------------------- 1 | BLACKLISTED=1 2 | NOT_BLACKLISTED=1 3 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/blacklist/source.js: -------------------------------------------------------------------------------- 1 | import {BLACKLISTED} from '@env' 2 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/blocklist/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | ["../../../", { 4 | "path": "__tests__/__fixtures__/blocklist/.env", 5 | "blocklist": [ 6 | "BLOCKLISTED" 7 | ] 8 | }] 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/blocklist/.env: -------------------------------------------------------------------------------- 1 | BLOCKLISTED=1 2 | NOT_BLOCKLISTED=1 3 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/blocklist/source.js: -------------------------------------------------------------------------------- 1 | import {BLOCKLISTED} from '@env' 2 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/custom-module/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | ["../../../", { 4 | "path": "__tests__/__fixtures__/custom-module/.env", 5 | "moduleName": "foo" 6 | }] 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/custom-module/.env: -------------------------------------------------------------------------------- 1 | API_KEY=abc123 2 | DEV_USERNAME=username 3 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/custom-module/source.js: -------------------------------------------------------------------------------- 1 | import {API_KEY, DEV_USERNAME} from 'foo' 2 | 3 | console.log(API_KEY) 4 | console.log(DEV_USERNAME) 5 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/default-import/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "../../../" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/default-import/source.js: -------------------------------------------------------------------------------- 1 | import config from '@env' 2 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/default-safe/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | ["../../../", { 4 | "path": "__tests__/__fixtures__/default-safe/.env", 5 | "safe": true 6 | }] 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/default-safe/.env: -------------------------------------------------------------------------------- 1 | API_KEY=abc123 2 | DEV_USERNAME=username 3 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/default-safe/source.js: -------------------------------------------------------------------------------- 1 | import {API_KEY, DEV_USERNAME} from '@env' 2 | 3 | console.log(API_KEY) 4 | console.log(DEV_USERNAME) 5 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/default/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | ["../../../", { 4 | "path": "__tests__/__fixtures__/default/.env" 5 | }] 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/default/.env: -------------------------------------------------------------------------------- 1 | API_KEY=abc123 2 | DEV_USERNAME=username 3 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/default/source.js: -------------------------------------------------------------------------------- 1 | import {API_KEY, DEV_USERNAME} from '@env' 2 | 3 | console.log(API_KEY) 4 | console.log(DEV_USERNAME) 5 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/env-name/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | ["../../../", { 4 | "envName": "MY_ENV", 5 | "path": "__tests__/__fixtures__/env-name/.env" 6 | }] 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/env-name/.env: -------------------------------------------------------------------------------- 1 | API_KEY=never 2 | DEV_USERNAME=this-should-not-appear 3 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/env-name/.env.cli: -------------------------------------------------------------------------------- 1 | API_KEY=abc123456 2 | DEV_USERNAME=username123456 3 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/env-name/source.js: -------------------------------------------------------------------------------- 1 | import {API_KEY, DEV_USERNAME} from '@env' 2 | 3 | console.log(API_KEY) 4 | console.log(DEV_USERNAME) 5 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/filename/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | ["../../../", { 4 | "path": "__tests__/__fixtures__/filename/.env.build" 5 | }] 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/filename/.env: -------------------------------------------------------------------------------- 1 | API_KEY=never 2 | DEV_USERNAME=this-should-not-appear 3 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/filename/.env.build: -------------------------------------------------------------------------------- 1 | API_KEY=abc123456 2 | DEV_USERNAME=username123456 3 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/filename/source.js: -------------------------------------------------------------------------------- 1 | import {API_KEY, DEV_USERNAME} from '@env' 2 | 3 | console.log(API_KEY) 4 | console.log(DEV_USERNAME) 5 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/from-env/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "../../../" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/from-env/source.js: -------------------------------------------------------------------------------- 1 | import {FROM_ENV} from '@env' 2 | 3 | console.log(FROM_ENV) 4 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/local-env/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | ["../../../", { 4 | "path": "__tests__/__fixtures__/local-env/.env" 5 | }] 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/local-env/.env: -------------------------------------------------------------------------------- 1 | API_KEY=never 2 | DEV_USERNAME=default 3 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/local-env/.env.test: -------------------------------------------------------------------------------- 1 | API_KEY=username123456 2 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/local-env/.env.test.local: -------------------------------------------------------------------------------- 1 | API_KEY=username123456 2 | DEV_USERNAME=local-key 3 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/local-env/source.js: -------------------------------------------------------------------------------- 1 | import {API_KEY, DEV_USERNAME} from '@env' 2 | 3 | console.log(API_KEY) 4 | console.log(DEV_USERNAME) 5 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/module-name/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | ["../../../", { 4 | "path": "__tests__/__fixtures__/module-name/.env", 5 | "moduleName": "react-native-dotenv" 6 | }] 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/module-name/.env: -------------------------------------------------------------------------------- 1 | API_KEY=abc123 2 | DEV_USERNAME=username 3 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/module-name/source.js: -------------------------------------------------------------------------------- 1 | import {API_KEY, DEV_USERNAME} from 'react-native-dotenv' 2 | 3 | console.log(API_KEY) 4 | console.log(DEV_USERNAME) 5 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/multi-env/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | ["../../../", { 4 | "path": "__tests__/__fixtures__/multi-env/.env" 5 | }] 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/multi-env/.env: -------------------------------------------------------------------------------- 1 | API_KEY=never 2 | DEV_USERNAME=username123456 3 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/multi-env/.env.test: -------------------------------------------------------------------------------- 1 | API_KEY=abc123456 2 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/multi-env/source.js: -------------------------------------------------------------------------------- 1 | import {API_KEY, DEV_USERNAME} from '@env' 2 | 3 | console.log(API_KEY) 4 | console.log(DEV_USERNAME) 5 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/process-env-propagate/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | ["../../../", { 4 | "path": "__tests__/__fixtures__/process-env-propagate/.env", 5 | "moduleName": "process.env" 6 | }] 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/process-env-propagate/.env: -------------------------------------------------------------------------------- 1 | # empty on purpose 2 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/process-env-propagate/source.js: -------------------------------------------------------------------------------- 1 | console.log(process.env.NODE_ENV) 2 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/process-env-undefined/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | ["../../../", { 4 | "path": "__tests__/__fixtures__/process-env-undefined/.env", 5 | "moduleName": "process.env" 6 | }] 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/process-env-undefined/.env: -------------------------------------------------------------------------------- 1 | # empty on purpose 2 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/process-env-undefined/source.js: -------------------------------------------------------------------------------- 1 | console.log(process.env.UNDEFINED_VAR) 2 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/process-env/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | ["../../../", { 4 | "path": "__tests__/__fixtures__/process-env/.env", 5 | "moduleName": "process.env" 6 | }] 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/process-env/.env: -------------------------------------------------------------------------------- 1 | API_KEY=abc123 2 | DEV_USERNAME=username 3 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/process-env/source.js: -------------------------------------------------------------------------------- 1 | console.log(process.env.API_KEY) 2 | console.log(process.env.DEV_USERNAME) 3 | console.log(process.env.NODE_ENV) 4 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/require-import/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | ["../../../", { 4 | "path": "__tests__/__fixtures__/require-import/.env" 5 | }] 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/require-import/.env: -------------------------------------------------------------------------------- 1 | API_KEY=abc123 2 | DEV_USERNAME=username 3 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/require-import/source.js: -------------------------------------------------------------------------------- 1 | const API_KEY = require('@env').API_KEY 2 | 3 | console.log(API_KEY) 4 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/safe-error/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | ["../../../", { 4 | "path": "__tests__/__fixtures__/safe-error/.env", 5 | "safe": true, 6 | "allowUndefined": false 7 | }] 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/safe-error/.env: -------------------------------------------------------------------------------- 1 | HELLO=1 2 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/safe-error/source.js: -------------------------------------------------------------------------------- 1 | import {FROM_ENV} from '@env' 2 | 3 | console.log(FROM_ENV) 4 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/safe-no-dotenv/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | ["../../../", { 4 | "path": "__tests__/__fixtures__/safe-no-dotenv/.env", 5 | "safe": true, 6 | "allowUndefined": true 7 | }] 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/safe-no-dotenv/source.js: -------------------------------------------------------------------------------- 1 | import {FROM_ENV} from '@env' 2 | 3 | console.log(FROM_ENV) 4 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/safe-success/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | ["../../../", { 4 | "path": "__tests__/__fixtures__/safe-success/.env", 5 | "safe": true 6 | }] 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/safe-success/.env: -------------------------------------------------------------------------------- 1 | HELLO=1 2 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/safe-success/source.js: -------------------------------------------------------------------------------- 1 | import {HELLO, NODE_ENV} from '@env' 2 | 3 | console.log(HELLO) 4 | console.log(NODE_ENV) 5 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/undefined/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | ["../../../", { 4 | "allowUndefined": true 5 | }] 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/undefined/source.js: -------------------------------------------------------------------------------- 1 | import {API_KEY} from '@env' 2 | 3 | console.log(API_KEY) 4 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/unused/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | ["../../../", { 4 | "path": "__tests__/__fixtures__/unused/.env" 5 | }] 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/unused/.env: -------------------------------------------------------------------------------- 1 | API_KEY=abc123 2 | DEV_USERNAME=username 3 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/unused/source.js: -------------------------------------------------------------------------------- 1 | import {join} from 'node:path' // eslint-disable-line import/no-unresolved 2 | 3 | console.log(join) 4 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/variable-not-exist/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | ["../../../", { 4 | "allowUndefined": false 5 | }] 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/variable-not-exist/source.js: -------------------------------------------------------------------------------- 1 | import {foo} from '@env' 2 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/verbose/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | ["../../../", { 4 | "path": "__tests__/__fixtures__/default/.env", 5 | "verbose": true 6 | }] 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/verbose/.env: -------------------------------------------------------------------------------- 1 | API_KEY=abc123 2 | DEV_USERNAME=username 3 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/verbose/source.js: -------------------------------------------------------------------------------- 1 | import {API_KEY, DEV_USERNAME} from '@env' 2 | 3 | console.log(API_KEY) 4 | console.log(DEV_USERNAME) 5 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/whitelist/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | ["../../../", { 4 | "path": "__tests__/__fixtures__/whitelist/.env", 5 | "whitelist": [ 6 | "WHITELISTED" 7 | ] 8 | }] 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/whitelist/.env: -------------------------------------------------------------------------------- 1 | WHITELISTED=1 2 | NOT_WHITELISTED=1 3 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/whitelist/source.js: -------------------------------------------------------------------------------- 1 | import {NOT_WHITELISTED} from '@env' 2 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/wildcard-import/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "../../../" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /__tests__/__fixtures__/wildcard-import/source.js: -------------------------------------------------------------------------------- 1 | import * as env from '@env' 2 | -------------------------------------------------------------------------------- /__tests__/index.test.js: -------------------------------------------------------------------------------- 1 | const {transformFileSync} = require('@babel/core') 2 | 3 | const FIXTURES = '__tests__/__fixtures__/' 4 | 5 | describe('react-native-dotenv', () => { 6 | if (process.env.NODE_ENV === undefined) { 7 | process.env.NODE_ENV = test 8 | } 9 | 10 | const OLD_ENV = process.env 11 | afterEach(() => { 12 | jest.resetModules() 13 | process.env = {...OLD_ENV} 14 | }) 15 | 16 | it('should throw if the variable does not exist', () => { 17 | expect( 18 | () => transformFileSync(FIXTURES + 'variable-not-exist/source.js'), 19 | ).toThrow('"foo" is not defined in .env') 20 | }) 21 | 22 | it('should throw if default is imported', () => { 23 | expect( 24 | () => transformFileSync(FIXTURES + 'default-import/source.js'), 25 | ).toThrow('Default import is not supported') 26 | }) 27 | 28 | it('should throw if wildcard is imported', () => { 29 | expect( 30 | () => transformFileSync(FIXTURES + 'wildcard-import/source.js'), 31 | ).toThrow('Wildcard import is not supported') 32 | }) 33 | 34 | it('should load environment variables from .env', () => { 35 | const {code} = transformFileSync(FIXTURES + 'default/source.js') 36 | expect(code).toBe('console.log("abc123");\nconsole.log("username");') 37 | }) 38 | 39 | it('should print the environment if setting to verbose', () => { 40 | console.log = jest.fn() 41 | const {code} = transformFileSync(FIXTURES + 'verbose/source.js') 42 | expect(code).toBe('console.log("abc123");\nconsole.log("username");') 43 | expect(console.log.mock.calls[0][1]).toBe('test') 44 | }) 45 | 46 | it('should allow importing variables already defined in the environment', () => { 47 | process.env.FROM_ENV = 'hello' 48 | 49 | const {code} = transformFileSync(FIXTURES + 'from-env/source.js') 50 | expect(code).toBe('console.log("hello");') 51 | }) 52 | 53 | /* 54 | // removed because babel caches process.env if multiple tests using the same fixtures 55 | it('should prioritize environment variables over variables defined in .env', () => { 56 | process.env.API_KEY = 'i win' 57 | const {code} = transformFileSync(FIXTURES + 'default/source.js') 58 | expect(code).toBe('console.log("i win");\nconsole.log("username");') 59 | }) 60 | */ 61 | 62 | it('should prioritize environment variables over variables defined in .env even when safe', () => { 63 | process.env.API_KEY = 'i win again' 64 | 65 | const {code} = transformFileSync(FIXTURES + 'default-safe/source.js') 66 | expect(code).toBe('console.log("i win again");\nconsole.log("username");') 67 | }) 68 | 69 | it('should load custom env file', () => { 70 | const {code} = transformFileSync(FIXTURES + 'filename/source.js') 71 | expect(code).toBe('console.log("abc123456");\nconsole.log("username123456");') 72 | }) 73 | 74 | it('should load multiple env files', () => { 75 | const {code} = transformFileSync(FIXTURES + 'multi-env/source.js') 76 | expect(code).toBe('console.log("abc123456");\nconsole.log("username123456");') 77 | }) 78 | 79 | it('should load local env files', () => { 80 | const {code} = transformFileSync(FIXTURES + 'local-env/source.js') 81 | expect(code).toBe('console.log("username123456");\nconsole.log("local-key");') 82 | }) 83 | 84 | it('should support `as alias` import syntax', () => { 85 | const {code} = transformFileSync(FIXTURES + 'as-alias/source.js') 86 | expect(code).toBe('const a = "abc123";\nconst b = "username";') 87 | }) 88 | 89 | it('should allow specifying a custom module name', () => { 90 | const {code} = transformFileSync(FIXTURES + 'custom-module/source.js') 91 | expect(code).toBe('console.log("abc123");\nconsole.log("username");') 92 | }) 93 | 94 | it('should allow specifying process.env', () => { 95 | const {code} = transformFileSync(FIXTURES + 'process-env/source.js') 96 | expect(code).toBe('console.log("abc123");\nconsole.log("username");\nconsole.log("test");') 97 | }) 98 | 99 | it('should not change undefined process.env variables', () => { 100 | const {code} = transformFileSync(FIXTURES + 'process-env-undefined/source.js') 101 | expect(code).toBe('console.log(process.env.UNDEFINED_VAR);') 102 | }) 103 | 104 | it('should propagate process.env variables from node process', () => { 105 | const customEnv = 'my-custom-env' 106 | const backupNodeEnv = process.env.NODE_ENV 107 | process.env.NODE_ENV = customEnv 108 | const {code} = transformFileSync(FIXTURES + 'process-env-propagate/source.js') 109 | expect(code).toBe(`console.log("${customEnv}");`) 110 | process.env.NODE_ENV = backupNodeEnv 111 | }) 112 | 113 | it('should allow specifying the package module name', () => { 114 | const {code} = transformFileSync(FIXTURES + 'module-name/source.js') 115 | expect(code).toBe('console.log("abc123");\nconsole.log("username");') 116 | }) 117 | 118 | it('should leave other imports untouched', () => { 119 | const {code} = transformFileSync(FIXTURES + 'unused/source.js') 120 | expect(code).toBe('import { join } from \'node:path\'; // eslint-disable-line import/no-unresolved\n\nconsole.log(join);') 121 | }) 122 | 123 | it('should throw when using non-allowlisted env variables', () => { 124 | expect( 125 | () => transformFileSync(FIXTURES + 'allowlist/source.js'), 126 | ).toThrow('"NOT_ALLOWLISTED" was not present in allowlist') 127 | }) 128 | 129 | it('should throw when using blocklisted env variables', () => { 130 | expect( 131 | () => transformFileSync(FIXTURES + 'blocklist/source.js'), 132 | ).toThrow('"BLOCKLISTED" was not present in blocklist') 133 | }) 134 | 135 | it('should throw when using non-whitelisted env variables', () => { 136 | expect( 137 | () => transformFileSync(FIXTURES + 'whitelist/source.js'), 138 | ).toThrow('"NOT_WHITELISTED" was not whitelisted') 139 | }) 140 | 141 | it('should throw when using blacklisted env variables', () => { 142 | expect( 143 | () => transformFileSync(FIXTURES + 'blacklist/source.js'), 144 | ).toThrow('"BLACKLISTED" was blacklisted') 145 | }) 146 | 147 | it('should throw when trying to use a variable not defined in .env in safe mode', () => { 148 | process.env.FROM_ENV = 'here' 149 | 150 | expect( 151 | () => transformFileSync(FIXTURES + 'safe-error/source.js'), 152 | ).toThrow('"FROM_ENV" is not defined') 153 | }) 154 | 155 | it('should load environment variables from .env in safe mode', () => { 156 | const {code} = transformFileSync(FIXTURES + 'safe-success/source.js') 157 | expect(code).toBe('console.log("1");\nconsole.log("test");') 158 | }) 159 | 160 | it('should import undefined variables', () => { 161 | const {code} = transformFileSync(FIXTURES + 'undefined/source.js') 162 | expect(code).toBe('console.log(undefined);') 163 | }) 164 | 165 | it('should not throw if .env exists in safe mode', () => { 166 | const {code} = transformFileSync(FIXTURES + 'safe-no-dotenv/source.js') 167 | expect(code).toBe('console.log(undefined);') 168 | }) 169 | 170 | it('should load APP_ENV specific env file', () => { 171 | process.env.APP_ENV = 'cli' 172 | 173 | const {code} = transformFileSync(FIXTURES + 'app-env/source.js') 174 | expect(code).toBe('console.log("abc123456");\nconsole.log("username123456");') 175 | }) 176 | 177 | it('should fail to load APP_ENV development', () => { 178 | console.error = jest.fn() 179 | process.env.APP_ENV = 'development' 180 | 181 | const {code} = transformFileSync(FIXTURES + 'app-env-development/source.js') 182 | expect(code).toBe('console.log("never");\nconsole.log("this-should-not-appear");') 183 | expect(console.error.mock.calls[0][0]).toBe('APP_ENV error') 184 | }) 185 | 186 | it('should fail to load APP_ENV production', () => { 187 | console.error = jest.fn() 188 | process.env.APP_ENV = 'production' 189 | 190 | const {code} = transformFileSync(FIXTURES + 'app-env-production/source.js') 191 | expect(code).toBe('console.log("never");\nconsole.log("this-should-not-appear");') 192 | expect(console.error.mock.calls[0][0]).toBe('APP_ENV error') 193 | }) 194 | 195 | it('should load MY_ENV specific env file', () => { 196 | process.env.MY_ENV = 'cli' 197 | 198 | const {code} = transformFileSync(FIXTURES + 'env-name/source.js') 199 | expect(code).toBe('console.log("abc123456");\nconsole.log("username123456");') 200 | }) 201 | }) 202 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const dotenv = require('dotenv') 4 | 5 | function parseDotenvFile(path, verbose = false) { 6 | let content 7 | 8 | try { 9 | content = fs.readFileSync(path) 10 | } catch (error) { 11 | // The env file does not exist. 12 | if (verbose) { 13 | console.error('react-native-dotenv', error) 14 | } 15 | 16 | return {} 17 | } 18 | 19 | return dotenv.parse(content) 20 | } 21 | 22 | function undefObjectAssign(targetObject, sourceObject) { 23 | const keys = Object.keys(sourceObject) 24 | for (let i = 0, length = keys.length; i < length; i++) { 25 | if (sourceObject[keys[i]]) { 26 | targetObject[keys[i]] = sourceObject[keys[i]] 27 | } 28 | } 29 | 30 | return targetObject 31 | } 32 | 33 | function safeObjectAssign(targetObject, sourceObject, exceptions = []) { 34 | const keys = Object.keys(targetObject) 35 | for (let i = 0, length = keys.length; i < length; i++) { 36 | if (targetObject[keys[i]] && sourceObject[keys[i]]) { 37 | targetObject[keys[i]] = sourceObject[keys[i]] 38 | } 39 | } 40 | 41 | for (let index = 0, length = exceptions.length; index < length; index++) { 42 | if (sourceObject[exceptions[index]]) { 43 | targetObject[exceptions[index]] = sourceObject[exceptions[index]] 44 | } 45 | } 46 | 47 | return targetObject 48 | } 49 | 50 | function mtime(filePath) { 51 | try { 52 | return fs.statSync(filePath).mtimeMs 53 | } catch { 54 | return null 55 | } 56 | } 57 | 58 | module.exports = (api, options) => { 59 | const t = api.types 60 | let env = {} 61 | options = { 62 | envName: 'APP_ENV', 63 | moduleName: '@env', 64 | path: '.env', 65 | whitelist: null, 66 | blacklist: null, 67 | allowlist: null, 68 | blocklist: null, 69 | safe: false, 70 | allowUndefined: true, 71 | verbose: false, 72 | ...options, 73 | } 74 | const babelMode = process.env[options.envName] || (process.env.BABEL_ENV && process.env.BABEL_ENV !== 'undefined' && process.env.BABEL_ENV !== 'development' && process.env.BABEL_ENV) || process.env.NODE_ENV || 'development' 75 | const localFilePath = options.path + '.local' 76 | const modeFilePath = options.path + '.' + babelMode 77 | const modeLocalFilePath = options.path + '.' + babelMode + '.local' 78 | 79 | if (options.verbose) { 80 | console.log('dotenvMode', babelMode) 81 | if (process.env[options.envName] === 'production' || process.env[options.envName] === 'development') { 82 | console.error('APP_ENV error', 'cannot use APP_ENV=development or APP_ENV=production') 83 | } 84 | } 85 | 86 | api.cache.using(() => mtime(options.path)) 87 | api.cache.using(() => mtime(modeFilePath)) 88 | api.cache.using(() => mtime(localFilePath)) 89 | api.cache.using(() => mtime(modeLocalFilePath)) 90 | 91 | const dotenvTemporary = undefObjectAssign({}, process.env) 92 | const parsed = parseDotenvFile(options.path, options.verbose) 93 | const localParsed = parseDotenvFile(localFilePath, options.verbose) 94 | const modeParsed = parseDotenvFile(modeFilePath, options.verbose) 95 | const modeLocalParsed = parseDotenvFile(modeLocalFilePath, options.verbose) 96 | env = (options.safe) ? safeObjectAssign(undefObjectAssign(undefObjectAssign(undefObjectAssign(parsed, modeParsed), localParsed), modeLocalParsed), dotenvTemporary, ['NODE_ENV', 'BABEL_ENV', options.envName]) 97 | : undefObjectAssign(undefObjectAssign(undefObjectAssign(undefObjectAssign(parsed, modeParsed), localParsed), modeLocalParsed), dotenvTemporary) 98 | 99 | api.addExternalDependency(path.resolve(options.path)) 100 | api.addExternalDependency(path.resolve(modeFilePath)) 101 | api.addExternalDependency(path.resolve(localFilePath)) 102 | api.addExternalDependency(path.resolve(modeLocalFilePath)) 103 | 104 | return ({ 105 | name: 'dotenv-import', 106 | visitor: { 107 | ImportDeclaration(path) { 108 | if (path.node.source.value === options.moduleName) { 109 | for (const [index, specifier] of path.node.specifiers.entries()) { 110 | if (specifier.type === 'ImportDefaultSpecifier') { 111 | throw path.get('specifiers')[index].buildCodeFrameError('Default import is not supported') 112 | } 113 | 114 | if (specifier.type === 'ImportNamespaceSpecifier') { 115 | throw path.get('specifiers')[index].buildCodeFrameError('Wildcard import is not supported') 116 | } 117 | 118 | if (specifier.imported && specifier.local) { 119 | const importedId = specifier.imported.name 120 | const localId = specifier.local.name 121 | 122 | if (Array.isArray(options.allowlist) && !options.allowlist.includes(importedId)) { 123 | throw path.get('specifiers')[index].buildCodeFrameError(`"${importedId}" was not present in allowlist`) 124 | } else if (Array.isArray(options.whitelist) && !options.whitelist.includes(importedId)) { 125 | console.warn('[DEPRECATION WARNING] This option is will be deprecated soon. Use allowlist instead') 126 | throw path.get('specifiers')[index].buildCodeFrameError(`"${importedId}" was not whitelisted`) 127 | } 128 | 129 | if (Array.isArray(options.blocklist) && options.blocklist.includes(importedId)) { 130 | throw path.get('specifiers')[index].buildCodeFrameError(`"${importedId}" was not present in blocklist`) 131 | } else if (Array.isArray(options.blacklist) && options.blacklist.includes(importedId)) { 132 | console.warn('[DEPRECATION WARNING] This option is will be deprecated soon. Use blocklist instead') 133 | throw path.get('specifiers')[index].buildCodeFrameError(`"${importedId}" was blacklisted`) 134 | } 135 | 136 | if (!options.allowUndefined && !Object.hasOwn(env, importedId)) { 137 | throw path.get('specifiers')[index].buildCodeFrameError(`"${importedId}" is not defined in ${options.path}`) 138 | } 139 | 140 | const binding = path.scope.getBinding(localId) 141 | for (const referencePath of binding.referencePaths) { 142 | referencePath.replaceWith(t.valueToNode(env[importedId])) 143 | } 144 | } 145 | } 146 | 147 | path.remove() 148 | } 149 | }, 150 | MemberExpression(path) { 151 | if (path.get('object').matchesPattern('process.env')) { 152 | const key = path.toComputedKey() 153 | if (t.isStringLiteral(key)) { 154 | const importedId = key.value 155 | const value = (env && importedId in env) ? env[importedId] : process.env[importedId] 156 | if (value !== undefined) { 157 | path.replaceWith(t.valueToNode(value)) 158 | } 159 | } 160 | } 161 | }, 162 | }, 163 | }) 164 | } 165 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-dotenv", 3 | "version": "3.4.11", 4 | "description": "Load environment variables using import statements.", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/goatandsheep/react-native-dotenv.git" 8 | }, 9 | "homepage": "https://github.com/goatandsheep/react-native-dotenv", 10 | "bugs": "https://github.com/goatandsheep/react-native-dotenv/issues", 11 | "main": "index.js", 12 | "scripts": { 13 | "lint": "xo", 14 | "lint:fix": "xo --fix", 15 | "test": "jest" 16 | }, 17 | "keywords": [ 18 | "dotenv", 19 | "babel-plugin", 20 | "babel", 21 | "dotenv-flow", 22 | "react", 23 | "react-native", 24 | "config", 25 | "env", 26 | "12factor" 27 | ], 28 | "dependencies": { 29 | "dotenv": "^16.4.5" 30 | }, 31 | "devDependencies": { 32 | "@babel/core": "^7.23.9", 33 | "codecov": "^3.8.3", 34 | "jest": "29.7.0", 35 | "jest-junit": "^16.0.0", 36 | "xo": "^0.57.0" 37 | }, 38 | "author": "Kemal Ahmed", 39 | "license": "MIT", 40 | "files": [ 41 | "index.js" 42 | ], 43 | "jest": { 44 | "testEnvironment": "node", 45 | "testPathIgnorePatterns": [ 46 | "/node_modules/", 47 | "/__fixtures__/" 48 | ], 49 | "reporters": [ 50 | "default", 51 | [ 52 | "jest-junit", 53 | { 54 | "outputDirectory": "reports/tests" 55 | } 56 | ] 57 | ], 58 | "collectCoverage": true, 59 | "collectCoverageFrom": [ 60 | "index.js" 61 | ], 62 | "coverageReporters": [ 63 | "lcov", 64 | "text-summary" 65 | ] 66 | }, 67 | "peerDependencies": { 68 | "@babel/runtime": "^7.20.6" 69 | }, 70 | "resolutions": { 71 | "@babel/core": "^7.20.5", 72 | "@babel/runtime": "^7.20.6" 73 | }, 74 | "xo": { 75 | "semicolon": false, 76 | "space": 2, 77 | "overrides": [ 78 | { 79 | "files": "**/*", 80 | "rules": { 81 | "unicorn/prefer-module": "off", 82 | "unicorn/prefer-node-protocol": "off", 83 | "node/prefer-global/process": "off", 84 | "n/prefer-global/process": "off", 85 | "prefer-destructuring": "off" 86 | } 87 | }, 88 | { 89 | "files": "__tests__/**/*.js", 90 | "env": [ 91 | "jest" 92 | ] 93 | }, 94 | { 95 | "files": "__tests__/__fixtures__/**/*.js", 96 | "rules": { 97 | "import/no-unresolved": [ 98 | "error", 99 | { 100 | "ignore": [ 101 | "@env", 102 | "foo", 103 | "react-native-dotenv" 104 | ] 105 | } 106 | ], 107 | "unicorn/import-style": "off", 108 | "no-unused-vars": "off" 109 | } 110 | } 111 | ] 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /tea.yaml: -------------------------------------------------------------------------------- 1 | # https://tea.xyz/what-is-this-file 2 | --- 3 | version: 1.0.0 4 | codeOwners: 5 | - '0x2dc2C7d5D3feefFcBF3869acf933020429593dc0' 6 | quorum: 1 7 | --------------------------------------------------------------------------------