Skip to content

Commit

Permalink
feat: add option for custom prefix (#30)
Browse files Browse the repository at this point in the history
  • Loading branch information
chihab authored Jan 14, 2023
1 parent 126c5b2 commit 6aea3af
Show file tree
Hide file tree
Showing 23 changed files with 116 additions and 68 deletions.
32 changes: 30 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,34 @@ The environment variables will be defined for you on `process.env`. For example,
## `NG_APP_*`

You must create custom environment variables beginning with `NG_APP_`.
You must create custom environment variables beginning with `NG_APP_` or using your custom prefix.

Any other variables will be ignored to avoid accidentally exposing a private key on the machine that could have the same name. See how to [use system environment variables](#expanding-env).
If you want to have a shorter prefix like `NG_` or if you want to access some domain specific variables directly, you can set the prefix in the `angular.json` configuration

```ts
"architect": {
"build": {
"builder": "@ngx-env/builder:browser",
"options": {
...
"scripts": []
"ngxEnv": {
"prefix": "ORG_"
}
}
}
}
```

or using `ng config`

```sh
ng config projects.YOUR_APP_NAME.architect.build.options.ngxEnv.prefix 'ORG_'
```

Any other variables not starting with `NG_APP_` or your custom prefix will be ignored to avoid accidentally exposing a private key on the machine that could have the same name.

See how to [use system environment variables](#expanding-env).

**Changing any environment variables will require you to restart the development server if it is running.**

Expand All @@ -88,6 +113,8 @@ There is also a built-in environment variable called `NG_APP_ENV`. You can read

By default `NG_APP_ENV` is set to `NODE_ENV` but you are free to override it.

Note that `NG_APP_ENV` remains available even if you define a custom prefix not matching `NG_APP`.

Having access to the `NG_APP_ENV` is also useful for performing actions conditionally:

```js
Expand Down Expand Up @@ -214,6 +241,7 @@ NG_APP_FOO=$DOMAIN/foo
NG_APP_BAR=$DOMAIN/bar
```


# How It Works

I wrote an article on [InDepth.dev](https://indepth.dev/tutorials/angular/inject-environment-variables) explaining how it works.
Expand Down
4 changes: 2 additions & 2 deletions apps/ngx-env-demo/.env
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
USER_HOME=/home/chihab
NG_APP_VERSION=$npm_package_version
NG_APP_USER_HOME=$USER_HOME
NGX_VERSION=$npm_package_version
NGX_USER_HOME=$USER_HOME
2 changes: 1 addition & 1 deletion apps/ngx-env-demo/.env.local
Original file line number Diff line number Diff line change
@@ -1 +1 @@
NG_APP_NOT_IN_TEST=ONLY_DEV
NGX_NOT_IN_TEST=ONLY_DEV
7 changes: 4 additions & 3 deletions apps/ngx-env-demo/package.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
{
"name": "@ngx-env/demo",
"version": "15.0.1",
"version": "15.1.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"test": "cross-env NODE_ENV=test NG_APP_BRANCH_NAME=main ng test --watch=false"
"pretest": "yarn ng config projects.ngx-env-demo.architect.test.options.ngxEnv.prefix 'NGX_'",
"test": "cross-env NODE_ENV=test NGX_BRANCH_NAME=main ng test --watch=false"
},
"dependencies": {
"@angular/animations": "~15.0.1",
Expand All @@ -26,7 +27,7 @@
"@angular-devkit/build-angular": "~15.0.1",
"@angular/cli": "~15.0.1",
"@angular/compiler-cli": "~15.0.1",
"@ngx-env/builder": "^15.0.1",
"@ngx-env/builder": "^15.1.0",
"@types/jasmine": "~3.8.0",
"@types/node": "^12.11.1",
"cross-env": "^7.0.3",
Expand Down
20 changes: 10 additions & 10 deletions apps/ngx-env-demo/src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,30 @@
</thead>
<tbody>
<tr>
<td>NG_APP_ENV</td>
<td>ENV</td>
<td>
<span id="NG_APP_ENV">{{ "process.env.NG_APP_ENV" | env }}</span>
<span id="ENV">{{ "process.env.NG_APP_ENV" | env }}</span>
</td>
</tr>
<tr>
<td>NG_APP_VERSION</td>
<td>VERSION</td>
<td>
<span id="VERSION">{{ "process.env.NG_APP_VERSION" | env }}</span>
<span id="VERSION">{{ "process.env.NGX_VERSION" | env }}</span>
</td>
</tr>
<tr>
<td>NG_APP_BRANCH_NAME</td>
<td>BRANCH_NAME</td>
<td>
<span id="NG_APP_BRANCH_NAME">{{
"process.env.NG_APP_BRANCH_NAME" | env
<span id="BRANCH_NAME">{{
"process.env.NGX_BRANCH_NAME" | env
}}</span>
</td>
</tr>
<tr>
<td>NG_APP_USER_HOME</td>
<td>USER_HOME</td>
<td>
<span id="NG_APP_USER_HOME">{{
"process.env.NG_APP_USER_HOME" | env
<span id="USER_HOME">{{
"process.env.NGX_USER_HOME" | env
}}</span>
</td>
</tr>
Expand Down
6 changes: 3 additions & 3 deletions apps/ngx-env-demo/src/app/app.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ describe('AppComponent', () => {
const fixture = TestBed.createComponent(AppComponent);
const elt: Element = fixture.nativeElement;
fixture.detectChanges();
expect(elt.querySelector('#NG_APP_ENV')?.innerHTML).toEqual('test');
expect(elt.querySelector('#NG_APP_BRANCH_NAME')?.innerHTML).toEqual('main');
expect(elt.querySelector('#NG_APP_USER_HOME')?.innerHTML).not.toEqual('');
expect(elt.querySelector('#ENV')?.innerHTML).toEqual('test');
expect(elt.querySelector('#BRANCH_NAME')?.innerHTML).toEqual('main');
expect(elt.querySelector('#USER_HOME')?.innerHTML).not.toEqual('');
});
});
8 changes: 4 additions & 4 deletions apps/ngx-env-demo/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import { environment } from 'src/environments/environment';
})
export class AppComponent {
env = process.env.NG_APP_ENV;
version = environment.env.NG_APP_VERSION;
branch = process.env.NG_APP_BRANCH_NAME;
version = environment.env.NGX_VERSION;
branch = process.env.NGX_BRANCH_NAME;
appHome = process.env.NGX_USER_HOME;
home = process.env.USER_HOME;
appHome = process.env.NG_APP_USER_HOME;
notInTest = process.env.NG_APP_NOT_IN_TEST;
notInTest = process.env.NGX_NOT_IN_TEST;
constructor() {
console.log(process.env);
}
Expand Down
2 changes: 1 addition & 1 deletion apps/ngx-env-demo/src/environments/environment.prod.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export const environment = {
production: true,
env: {
NG_APP_VERSION: process.env.NG_APP_VERSION,
NGX_VERSION: process.env.NGX_VERSION,
},
};
2 changes: 1 addition & 1 deletion apps/ngx-env-demo/src/environments/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
export const environment = {
production: false,
env: {
NG_APP_VERSION: process.env.NG_APP_VERSION,
NGX_VERSION: process.env.NGX_VERSION,
},
};

Expand Down
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"packages/*",
"apps/*"
],
"version": "15.0.1",
"version": "15.1.0",
"npmClient": "yarn",
"useWorkspaces": true,
"command": {
Expand Down
4 changes: 2 additions & 2 deletions packages/builder/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ngx-env/builder",
"version": "15.0.1",
"version": "15.1.0",
"description": "Easily inject environment variables into your Angular applications",
"author": "chihab <chihab@gmail.com>",
"homepage": "https://github.com/chihab/ngx-env",
Expand All @@ -27,7 +27,7 @@
"start": "tsc -w",
"build": "tsc",
"copy-dist": "ts-node src/builders/schema-dist.ts",
"postbuild": "node dist/schema.js"
"postbuild": "node dist/schema-copy.js"
},
"dependencies": {
"@angular-devkit/schematics": "^14.0.0",
Expand Down
6 changes: 3 additions & 3 deletions packages/builder/src/builders/browser/index.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import {
BuilderContext,
createBuilder,
targetFromTargetString,
} from "@angular-devkit/architect";
import {
BrowserBuilderOptions,
executeBrowserBuilder,
} from "@angular-devkit/build-angular";
import { NgxEnvSchema } from "../ngx-env/ngx-env-schema";
import { plugin } from "../plugin";

export const buildWithPlugin = (
options: BrowserBuilderOptions,
options: BrowserBuilderOptions & NgxEnvSchema,
context: BuilderContext
): ReturnType<typeof executeBrowserBuilder> => {
return executeBrowserBuilder(options, context, plugin());
return executeBrowserBuilder(options, context, plugin(options.ngxEnv));
};

export default createBuilder<BrowserBuilderOptions>(buildWithPlugin);
9 changes: 5 additions & 4 deletions packages/builder/src/builders/dev-server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,22 @@ import { DevServerBuilderOutput } from "@angular-devkit/build-angular";
import { Observable, from } from "rxjs";
import { switchMap } from "rxjs/operators";
import { plugin } from "../plugin";
import { NgxEnvSchema } from "../ngx-env/ngx-env-schema";

export const buildWithPlugin = (
options: DevServerBuilderOptions,
options: DevServerBuilderOptions & NgxEnvSchema,
context: BuilderContext
): Observable<DevServerBuilderOutput> => {
const browserTarget = targetFromTargetString(options.browserTarget);
async function setup() {
return context.getTargetOptions(
browserTarget
) as unknown as DevServerBuilderOptions;
) as unknown as DevServerBuilderOptions & NgxEnvSchema;
}

return from(setup()).pipe(
switchMap((_options) => {
return executeDevServerBuilder(options, context, plugin());
const ngxEnvOptions = {...options.ngxEnv, ..._options.ngxEnv};
return executeDevServerBuilder(options, context, plugin(ngxEnvOptions));
})
);
};
Expand Down
5 changes: 3 additions & 2 deletions packages/builder/src/builders/extract-i18n/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ import {
executeExtractI18nBuilder,
ExtractI18nBuilderOptions,
} from "@angular-devkit/build-angular";
import { NgxEnvSchema } from "../ngx-env/ngx-env-schema";
import { plugin } from "../plugin";

export const buildWithPlugin = (
options: ExtractI18nBuilderOptions,
options: ExtractI18nBuilderOptions & NgxEnvSchema,
context: BuilderContext
): ReturnType<typeof executeExtractI18nBuilder> => {
return executeExtractI18nBuilder(options, context, plugin());
return executeExtractI18nBuilder(options, context, plugin(options.ngxEnv));
};

export default createBuilder<ExtractI18nBuilderOptions>(buildWithPlugin);
5 changes: 3 additions & 2 deletions packages/builder/src/builders/karma/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ import {
executeKarmaBuilder,
KarmaBuilderOptions,
} from "@angular-devkit/build-angular";
import { NgxEnvSchema } from "../ngx-env/ngx-env-schema";
import { plugin } from "../plugin";

export const buildWithPlugin = (
options: KarmaBuilderOptions,
options: KarmaBuilderOptions & NgxEnvSchema,
context: BuilderContext
): ReturnType<typeof executeKarmaBuilder> => {
return executeKarmaBuilder(options, context, plugin());
return executeKarmaBuilder(options, context, plugin(options.ngxEnv));
};
export default createBuilder<KarmaBuilderOptions>(buildWithPlugin);
6 changes: 6 additions & 0 deletions packages/builder/src/builders/ngx-env/ngx-env-schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface NgxEnvOptions {
prefix?: string;
}
export interface NgxEnvSchema {
ngxEnv?: NgxEnvOptions
}
12 changes: 12 additions & 0 deletions packages/builder/src/builders/ngx-env/ngx-env.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"ngxEnv": {
"type": "object",
"properties": {
"prefix": {
"type": "string",
"description": "@ngx-env/builder prefix",
"default": "NG_APP"
}
}
}
}
16 changes: 10 additions & 6 deletions packages/builder/src/builders/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@ import * as webpack from "webpack";
import { Configuration } from "webpack";
import * as fs from "fs";
import * as path from "path";
import { NgxEnvOptions } from "./ngx-env/ngx-env-schema";

const NG_APP_ENV = 'NG_APP_ENV';

function escapeStringRegexp(str: string) {
return str.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&").replace(/-/g, "\\x2d");
}

function getClientEnvironment(prefix: RegExp) {
const env = process.env.NG_APP_ENV || process.env.NODE_ENV;
const env = process.env[NG_APP_ENV] || process.env.NODE_ENV;
const dotenvBase = path.resolve(process.cwd(), ".env");
const dotenvFiles = [
env && `${dotenvBase}.${env}.local`,
Expand All @@ -37,10 +40,10 @@ function getClientEnvironment(prefix: RegExp) {
});
const processEnv = {
...process.env,
NG_APP_ENV: env,
[NG_APP_ENV]: env,
};
return Object.keys(processEnv)
.filter((key) => prefix.test(key))
.filter((key) => prefix.test(key) || key === NG_APP_ENV)
.reduce(
(env, key) => {
env.raw[key] = processEnv[key];
Expand All @@ -54,8 +57,9 @@ function getClientEnvironment(prefix: RegExp) {
);
}

export function plugin() {
const { raw, stringified } = getClientEnvironment(/^NG_APP/i);
export function plugin(options: NgxEnvOptions) {
console.log('@ngx-env/builder using prefix', options.prefix)
const { raw, stringified } = getClientEnvironment(new RegExp(`^${options.prefix}`, 'i'));
return {
webpackConfiguration: async (webpackConfig: Configuration) => {
webpackConfig.plugins.push(
Expand All @@ -68,7 +72,7 @@ export function plugin() {
indexHtml: async (content: string) => {
const rawWithEnv = {
...raw,
NG_APP_ENV: raw["NG_APP_ENV"],
[NG_APP_ENV]: raw[NG_APP_ENV],
};
return Object.keys(rawWithEnv).reduce(
(html, key) =>
Expand Down
12 changes: 1 addition & 11 deletions packages/builder/src/builders/schema-dist.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
/**
* For each builder
* - Copy the schema
* - Validate the generated schema
*/

import * as cpy from "cpy";
import * as fs from "fs";

Expand All @@ -26,8 +20,4 @@ function copyDistSchemas() {
);
}

(() => {
copyDistSchemas();
})();

// cp node_modules/@angular-devkit/build-angular/src/builders/dev-server/schema.json ./packages/builder/src/builders/dev-server/dev-server.json
copyDistSchemas();
Loading

0 comments on commit 6aea3af

Please sign in to comment.