Skip to content

Commit

Permalink
Merge pull request #11 from aedart/add-env
Browse files Browse the repository at this point in the history
Add Env component
  • Loading branch information
aedart authored May 6, 2024
2 parents e03e5c9 + c2ac6a3 commit ee4ed3b
Show file tree
Hide file tree
Showing 33 changed files with 1,207 additions and 6 deletions.
19 changes: 19 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Environment file.

# Foo / Bar example variable...
FOO=BAR

# Null
NULL_VAL_TRUE=null

# Boolean values
BOOL_VAL_TRUE=true
BOOL_VAL_FALSE=false

# String values
STR_VAL_EMPTY=
STR_VAL_NO_QUOTE=Okay # Unquoted...
STR_VAL_SINGLE_QUOTE='Beauty is a rainy whale.'
STR_VAL_DOUBLE_QUOTE="Arrr, endurance!"
STR_VAL_MULTI_LINE="Ares de fin.
Mu verci."
3 changes: 3 additions & 0 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ jobs:
- name: "Install dependencies"
run: npm install

- name: "Make .env file"
run: npm run make:env

- name: "Lint"
run: npm run lint

Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

* Core `Application` in `@aedart/core` (_new package_).
* `@aedart/support/services` (_new submodule_).
* `@aedart/support/env` (_new submodule_).
* Abstract `ServiceProvider` in `@aedart/support/services`.
* `ServiceRegistrar` in `aedart/support/services`.
* `isServiceProviderConstructor()` and `isServiceProvider()` utils in `@aedart/support/services`.
* `Env` and `env()` utilities in `aedart/support/env`.

### Changed

* TypeScript compile options now use `composite: true`, `incremental: true` and `clean: false` settings, in `shared/rollup.config.mjs` (_decreases build duration_).
* `@rollup/plugin-json` has now been enabled for all packages.
* `.env` file is parsed as `__ENV__`, for tests (_for root package only. File is parsed in `shared/tests/webpack.config.js`_).

### Fixed

* Various internal types in `@aedart/support/*` submodules.
* Es-lint warning for `type: any` property in `Facade`, in `@aedart/support/facades`.
* Test suite name(s) for container related tests.
* Babel plugins not applied by webpack, for tests.

## [0.11.0] - 2024-04-09

Expand Down
1 change: 1 addition & 0 deletions aliases.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ module.exports = {
'@aedart/contracts/core': path.resolve(__dirname, './packages/contracts/core'),
'@aedart/contracts/support/arrays': path.resolve(__dirname, './packages/contracts/support/arrays'),
'@aedart/contracts/support/concerns': path.resolve(__dirname, './packages/contracts/support/concerns'),
'@aedart/contracts/support/env': path.resolve(__dirname, './packages/contracts/support/env'),
'@aedart/contracts/support/exceptions': path.resolve(__dirname, './packages/contracts/support/exceptions'),
'@aedart/contracts/support/facades': path.resolve(__dirname, './packages/contracts/support/facades'),
'@aedart/contracts/support/meta': path.resolve(__dirname, './packages/contracts/support/meta'),
Expand Down
10 changes: 10 additions & 0 deletions docs/.vuepress/archive/Version0x.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,16 @@ export default PagesCollection.make('v0.x', '/v0x', [
'packages/support/concerns/jsdoc',
]
},
{
text: 'Env',
collapsible: true,
children: [
'packages/support/env/',
'packages/support/env/usage',
'packages/support/env/bundlers',
'packages/support/env/security',
]
},
{
text: 'Exceptions',
collapsible: true,
Expand Down
19 changes: 19 additions & 0 deletions docs/archive/current/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,25 @@ _TBD: "To be decided"._

## `v0.x` Highlights

### Env <Badge type="tip" text="Available since v0.12" />

The `Env` component offers a way to retrieve environment variables for your application's runtime.

```js
import { Env } from "@aedart/support/env";

// During your application's bootstrapping...
Env.define({
APP_ENV: 'production'
});

// Later in your application
const environment = Env.get('APP_ENV');
console.log(environment); // production
```

See the [documentation](./packages/support/env/README.md) for additional details.

### Service Container <Badge type="tip" text="Available since v0.11" />

An adaptation of Laravel's Service Container that offers a way to with powerful tool to manage dependencies and perform
Expand Down
29 changes: 29 additions & 0 deletions docs/archive/current/packages/support/env/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
title: About Env
description: Environment Variables
---


# About Env <Badge type="tip" text="Available since v0.12" vertical="middle" />

The `@aedart/support/env` submodule offers a way to use [environment variables](https://en.wikipedia.org/wiki/Environment_variable)
in your application's runtime.

```js
import { Env } from "@aedart/support/env";

// During your application's bootstrapping...
Env.define({
APP_ENV: 'production'
});

// Later in your application
const environment = Env.get('APP_ENV');
console.log(environment); // production
```

::: warning Disclaimer
By itself, this submodule does not read any `.env` files, nor does it access node's [`process.env.`](https://nodejs.org/en/learn/command-line/how-to-read-environment-variables-from-nodejs).
It only acts as a "repository" that can access a key-value store.
Please see the [bundlers](./bundlers.md) section for additional details.
:::
129 changes: 129 additions & 0 deletions docs/archive/current/packages/support/env/bundlers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
---
title: Bundlers
description: Using bundlers for defining environment variables
sidebarDepth: 0
---

# Bundlers

In order to load environment variables and make them available for your application's runtime, e.g. from an `.env` file,
you are required to use other tools, such as [dotenv](https://github.com/motdotla/dotenv) and a JavaScript module bundler.

[[TOC]]

## DotEnv

The [dotenv](https://github.com/motdotla/dotenv) packages is able to read environment variables that are defined in a
file, and parse them either into node's [`process.env.`](https://nodejs.org/en/learn/command-line/how-to-read-environment-variables-from-nodejs)
or a custom object.

The following example shows a general approach on how to read the contents of a `.env` file and parse it into an object,
which can then be exposed to your application's runtime, by your module bundler.

```js
const fs = require('node:fs');
const dotEnv = require('dotenv');

// use dotEnv to parse contents of .env file into an object...
const ENV = dotEnv.parse(
fs.readFileSync('.env', 'utf8')
);
```

## Webpack

For [Webpack](https://webpack.js.org/), you can use [`DefinePlugin`](https://webpack.js.org/plugins/define-plugin/) to
replace variables (_or tokens_) in your code at compile time.
The following example shows how to read the contents of a `.env` file, parse it into an object and "inject" it into a
`__ENV__` variable, which will be made available in your runtime.

```js
// In your webpack.config.js
const fs = require('node:fs');
const dotEnv = require('dotenv');
const webpack = require('webpack');

const ENV = dotEnv.parse(
fs.readFileSync('.env', 'utf8')
);

module.exports = {
plugins: [
// The __ENV__ variable will be replaced with the
// parsed .env object...
new webpack.DefinePlugin({
__ENV__: JSON.stringify(ENV)
})
],

module: {
rules: [
// ...not shown...
],
},
};
```

## Rollup

You can use the [replace](https://github.com/rollup/plugins/tree/master/packages/replace) plugin for [Rollup](https://rollupjs.org/)
to "inject" an object in your runtime, with the contents of a `.env` file.

```js
// In your rollup.config.js
import replace from '@rollup/plugin-replace';
const fs = require('node:fs');
const dotEnv = require('dotenv');

const ENV = dotEnv.parse(
fs.readFileSync('.env', 'utf8')
);

export default {
input: 'src/index.js',
output: {
dir: 'output',
format: 'es'
},
plugins: [
replace({
__ENV__: JSON.stringify(ENV)
})
]
};
```

## Esbuild

In your [esbuild's](https://esbuild.github.io/) configuration file, your can use the [`define`](https://esbuild.github.io/api/#define)
setting to "inject" the parsed contents of your `.env` file, into your runtime.

```js
const esbuild = require('esbuild');
const fs = require('node:fs');
const dotEnv = require('dotenv');

const ENV = dotEnv.parse(
fs.readFileSync('.env', 'utf8')
);

esbuild
.build({
define: {
__ENV__: JSON.stringify(ENV),
}
// ...other configuraiton not shown
})
.then(() => console.log('⚡Bundle build complete ⚡'))
.catch(() => {
process.exit(1);
});
```

## Other Bundlers

::: tip Help Wanted
There are many more JavaScript module bundlers than covered here.
If you are using a bundler that is not covered by this guide, then you are welcome to help improve this guide.
See the [contribution guide](../../../contribution-guide.md) for additional details.
:::
26 changes: 26 additions & 0 deletions docs/archive/current/packages/support/env/security.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
title: Security
description: Security Considerations when working with env files
sidebarDepth: 0
---

# Security

You should be very mindful what environment variables you chose to expose in your runtime environment.
If you are parsing `.env` files and injecting them into your runtime, please consider using a dedicated
file for your front-end application only (_e.g. name it `.front-end`, `.browser` or something similar._).
It is important that you are able to clearly distinguish between environment variables for your backend, and
for your front-end. You do not want to end up in a situation where you accidentally expose sensitive variables
to the front-end!

Furthermore, the `Env` component is **_NOT_** able to prevent unintended access to the environment variables, that you
may choose to expose to your front-end application. You should always assume that
**_all_** environment variables are **_PUBLICLY AVAILABLE_**, in the browser!

For additional information concerning `.env` files and environment variables, consider reading the
following articles:

* [What is the use of .env file in projects?](https://medium.com/@sujathamudadla1213/what-is-the-use-of-env-8d6b3eb94843)
* [Best practices for managing and storing secrets in frontend development](https://blog.logrocket.com/best-practices-for-managing-and-storing-secrets-in-frontend-development/)
* [It’s time to deprecate the .env file](https://medium.com/@tony.infisical/its-time-to-deprecate-the-env-file-for-a-better-stack-a519ac89bab0)
* [How to improve the security of your frontend](https://community.aws/content/2djybfoALqneZO9EA2UA7a5lCbn/how-to-improve-the-security-of-your-frontend-application-using-aws-secret-manager)
73 changes: 73 additions & 0 deletions docs/archive/current/packages/support/env/usage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
---
title: How to use
description: How to use the Env component
sidebarDepth: 0
---

# How to use Env

[[TOC]]

## Define "Environment Variables"

The `define()` method allows you to define your application's environment variables (_at runtime_).
It is intended to be used during your application's boot or initialisation logic.
The method accepts two arguments:

* `variables: Record<PropertyKey, any>`: a key-value object
* `safe: boolean = true`: (_optional_) If `true`, then the defined variables cannot be changed¹

¹: _Defined variables can still be [cleared](#clear-all)!_

```js
import { Env } from "@aedart/support/env";

Env.define({
APP_ENV: 'development'
});
```

Once the environment variables have been defined, you can [access](#retrieve-values) them throughout your entire application.

::: warning Caution
`define()` automatically invokes the [`clear()`](#clear-all) method, before storing the environment
variables, in the `Env`'s internal repository.
:::

::: tip .env Files
The `Env` component is **NOT** able to define real [environment variables](https://en.wikipedia.org/wiki/Environment_variable).
It can only act as a key-value store, during your application's runtime.
See [bundlers](./bundlers.md) for examples on how to read `.env` files and injecting environment variables into
your runtime.
:::

## Retrieve Values

Use the `get()` method to retrieve a value for a defined variable.
The method accepts the following arguments:

* `key: PropertyKey`: The name of the environment variable
* `defaultValue?: any` (_optional_) Eventual default value to return, if environment variable does not exist.

```js
const url = Env.get('HOME', 'https://localhost.test');
```

### `env()`

Alternatively, you can also use the `env()` util, to retrieve values. It acts as an alias for `Env.get()`.

```js
import { env } from "@aedart/support/env";

const environment = env('APP_ENV', 'production');
```

## Clear All

In rare situations, you may wish to clear all defined environment variables (_e.g. in your tests_).
To do so, call the `clear()` method.

```js
Env.clear();
```
2 changes: 2 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit ee4ed3b

Please sign in to comment.