@rivinia/env 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +95 -33
- package/package.json +1 -1
- package/schematics/collection.json +1 -1
- package/schematics/ng-add/index.cjs +22 -17
- package/schematics/ng-add/schema.json +19 -7
package/README.md
CHANGED
|
@@ -3,50 +3,49 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@rivinia/env)
|
|
4
4
|
[](https://www.npmjs.com/package/@rivinia/env)
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
`@rivinia/env` provides the `BaseEnvironment` TypeScript contract and an
|
|
7
|
+
Angular CLI `ng add` schematic. It does not read environment values at
|
|
8
|
+
runtime: Angular's build file replacements select a statically imported
|
|
9
|
+
environment file.
|
|
10
10
|
|
|
11
|
-
-
|
|
12
|
-
-
|
|
11
|
+
- Prepared patch: **0.3.1** (latest published: **0.3.0**)
|
|
12
|
+
- No runtime providers or services; the package supplies a type and CLI tooling.
|
|
13
|
+
- The generated model imports `BaseEnvironment` from this package.
|
|
13
14
|
|
|
14
|
-
## Install
|
|
15
|
+
## Install and scaffold
|
|
16
|
+
|
|
17
|
+
From an Angular CLI workspace:
|
|
15
18
|
|
|
16
19
|
```bash
|
|
17
20
|
npm install @rivinia/env
|
|
18
|
-
ng add @rivinia/env
|
|
21
|
+
ng add @rivinia/env
|
|
19
22
|
```
|
|
20
23
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
+
The schematic prompts for environments when interactive; the default and
|
|
25
|
+
non-interactive selection is all three (`dev`, `stage`, `prod`). Select only
|
|
26
|
+
what you need with a comma-separated option:
|
|
24
27
|
|
|
25
28
|
```bash
|
|
26
|
-
ng add @rivinia/env --environments
|
|
29
|
+
ng add @rivinia/env --environments stage,prod
|
|
27
30
|
```
|
|
28
31
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
overwrite files or duplicate configuration.
|
|
32
|
+
Accepted names are `dev`, `stage` (or `stag`), and `prod`. `--project <name>`
|
|
33
|
+
selects a project in a multi-project workspace; otherwise it uses
|
|
34
|
+
`defaultProject` from `angular.json`, falling back to the first project.
|
|
35
|
+
The schematic uses that project's `sourceRoot` (or `<root>/src`, then `src`).
|
|
34
36
|
|
|
35
|
-
|
|
37
|
+
The model and development base file are always scaffolded. The selected
|
|
38
|
+
environment files are created only if they do not already exist:
|
|
36
39
|
|
|
40
|
+
```text
|
|
41
|
+
src/environments/
|
|
42
|
+
environment.model.ts # AppEnvironment extends BaseEnvironment
|
|
43
|
+
environment.ts # development defaults; not replaced by the CLI
|
|
44
|
+
environment.staging.ts # only when stage is selected
|
|
45
|
+
environment.prod.ts # only when prod is selected
|
|
37
46
|
```
|
|
38
|
-
environment.model.ts # AppEnvironment extends BaseEnvironment — extend it
|
|
39
|
-
environment.ts # development defaults (used as-is by `development`)
|
|
40
|
-
environment.staging.ts # staging values (production: true)
|
|
41
|
-
environment.prod.ts # production values
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
and wires `angular.json`: `production` gains its replacement if missing, and a
|
|
45
|
-
`staging` configuration (copied from `production`) is created if absent.
|
|
46
|
-
`development` intentionally gets no replacement (CLI standard). The app version
|
|
47
|
-
is snapshotted from your `package.json` into each file (`0.0.0` fallback).
|
|
48
47
|
|
|
49
|
-
|
|
48
|
+
The generated contract and values have this shape:
|
|
50
49
|
|
|
51
50
|
```ts
|
|
52
51
|
// environment.model.ts
|
|
@@ -55,14 +54,77 @@ import type { BaseEnvironment } from '@rivinia/env';
|
|
|
55
54
|
export interface AppEnvironment extends BaseEnvironment {
|
|
56
55
|
readonly apiUrl: string;
|
|
57
56
|
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
// environment.ts (generated development defaults)
|
|
61
|
+
import type { AppEnvironment } from './environment.model';
|
|
62
|
+
|
|
63
|
+
export const environment: AppEnvironment = {
|
|
64
|
+
production: false,
|
|
65
|
+
version: '1.2.3',
|
|
66
|
+
apiUrl: 'http://localhost:3000/api',
|
|
67
|
+
};
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Staging and production files have the same fields, with `production: true`;
|
|
71
|
+
their generated API URLs are `https://staging.example.com/api` and
|
|
72
|
+
`https://api.example.com/api`. Replace these example URLs and any other
|
|
73
|
+
generated values with the app's real configuration.
|
|
74
|
+
|
|
75
|
+
The schematic adds a file replacement to an existing `production`
|
|
76
|
+
configuration when `prod` is selected. When `stage` is selected, it creates a
|
|
77
|
+
`staging` configuration if needed (copying `production` settings except its
|
|
78
|
+
`fileReplacements` and `outputPath`) and adds the staging replacement.
|
|
79
|
+
`development` intentionally uses `environment.ts` directly. The schematic
|
|
80
|
+
does not create a missing `production` or `development` configuration.
|
|
81
|
+
|
|
82
|
+
For selected configurations that exist, it sets `outputPath` to
|
|
83
|
+
`builds/dev`, `builds/stag`, or `builds/prod` only if no output path is
|
|
84
|
+
already configured. If that adds an output path and a root `.gitignore`
|
|
85
|
+
exists, `/builds` is appended once. Existing output paths and files are never
|
|
86
|
+
overwritten; repeated runs do not duplicate replacements.
|
|
87
|
+
|
|
88
|
+
The version in generated files is copied from the workspace-root
|
|
89
|
+
`package.json` when each file is first created (`0.0.0` if unavailable).
|
|
90
|
+
Since the schematic never overwrites existing files, update `version` in
|
|
91
|
+
those environment files manually when releasing a new app version; rerunning
|
|
92
|
+
`ng add` will not refresh it.
|
|
58
93
|
|
|
59
|
-
|
|
94
|
+
## Use the selected environment
|
|
95
|
+
|
|
96
|
+
Always import the base path from the app, not a stage/prod-specific file:
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
// src/app/trip.service.ts
|
|
100
|
+
import { Injectable } from '@angular/core';
|
|
60
101
|
import { environment } from '../environments/environment';
|
|
61
|
-
|
|
62
|
-
|
|
102
|
+
|
|
103
|
+
@Injectable({ providedIn: 'root' })
|
|
104
|
+
export class TripService {
|
|
105
|
+
readonly apiUrl = environment.apiUrl;
|
|
106
|
+
}
|
|
63
107
|
```
|
|
64
108
|
|
|
65
|
-
|
|
109
|
+
The Angular CLI replaces `environment.ts` for the selected build
|
|
110
|
+
configuration. For example:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
ng build --configuration development
|
|
114
|
+
ng build --configuration staging
|
|
115
|
+
ng build --configuration production
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
The generated files are compile-time configuration, not secrets: values
|
|
119
|
+
included in a browser build are visible to its users. `BaseEnvironment`
|
|
120
|
+
requires only readonly `production: boolean` and `version: string`; extend
|
|
121
|
+
AppEnvironment with the fields your app needs.
|
|
122
|
+
|
|
123
|
+
## Public API
|
|
124
|
+
|
|
125
|
+
| Export | Kind | Purpose |
|
|
126
|
+
| ----------------- | ---- | ---------------------------------------------------------------------- |
|
|
127
|
+
| `BaseEnvironment` | type | Required `production` and `version` fields for app environment models. |
|
|
66
128
|
|
|
67
129
|
## License
|
|
68
130
|
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "../../../node_modules/@angular-devkit/schematics/collection-schema.json",
|
|
3
3
|
"schematics": {
|
|
4
4
|
"ng-add": {
|
|
5
|
-
"description": "Scaffold typed environment files and wire dev/
|
|
5
|
+
"description": "Scaffold typed environment files and wire dev/stage/prod configurations.",
|
|
6
6
|
"factory": "./ng-add/index.cjs#ngAdd",
|
|
7
7
|
"schema": "./ng-add/schema.json"
|
|
8
8
|
}
|
|
@@ -14,19 +14,25 @@ export interface AppEnvironment extends BaseEnvironment {
|
|
|
14
14
|
readonly apiUrl: string;
|
|
15
15
|
}
|
|
16
16
|
`;
|
|
17
|
-
const ALL_ENVIRONMENTS = ['
|
|
17
|
+
const ALL_ENVIRONMENTS = ['dev', 'stage', 'prod'];
|
|
18
18
|
/** Short aliases users actually type (`prod`, `dev`, `stag`). */
|
|
19
19
|
const ENVIRONMENT_ALIASES = {
|
|
20
|
-
dev: '
|
|
21
|
-
prod: '
|
|
22
|
-
stag: '
|
|
23
|
-
stage: '
|
|
20
|
+
dev: 'dev',
|
|
21
|
+
prod: 'prod',
|
|
22
|
+
stag: 'stage',
|
|
23
|
+
stage: 'stage',
|
|
24
24
|
};
|
|
25
25
|
/** Output directory short names: builds/dev, builds/prod, builds/stag. */
|
|
26
26
|
const OUTPUT_DIR = {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
dev: 'builds/dev',
|
|
28
|
+
stage: 'builds/stag',
|
|
29
|
+
prod: 'builds/prod',
|
|
30
|
+
};
|
|
31
|
+
/** Maps an environment name to its Angular CLI configuration name. */
|
|
32
|
+
const CONFIG_NAME = {
|
|
33
|
+
dev: 'development',
|
|
34
|
+
stage: 'staging',
|
|
35
|
+
prod: 'production',
|
|
30
36
|
};
|
|
31
37
|
const fileDefs = (sourceRoot, selected) => {
|
|
32
38
|
const files = [
|
|
@@ -44,7 +50,7 @@ const fileDefs = (sourceRoot, selected) => {
|
|
|
44
50
|
`};\n`,
|
|
45
51
|
},
|
|
46
52
|
];
|
|
47
|
-
if (selected.includes('
|
|
53
|
+
if (selected.includes('stage')) {
|
|
48
54
|
files.push({
|
|
49
55
|
name: `${sourceRoot}/environments/environment.staging.ts`,
|
|
50
56
|
content: (version) => `import type { AppEnvironment } from './environment.model';\n\n` +
|
|
@@ -56,7 +62,7 @@ const fileDefs = (sourceRoot, selected) => {
|
|
|
56
62
|
`};\n`,
|
|
57
63
|
});
|
|
58
64
|
}
|
|
59
|
-
if (selected.includes('
|
|
65
|
+
if (selected.includes('prod')) {
|
|
60
66
|
files.push({
|
|
61
67
|
name: `${sourceRoot}/environments/environment.prod.ts`,
|
|
62
68
|
content: (version) => `import type { AppEnvironment } from './environment.model';\n\n` +
|
|
@@ -105,11 +111,9 @@ function ngAdd(options) {
|
|
|
105
111
|
const unknown = [...new Set(cleaned)].filter((e) => !ALL_ENVIRONMENTS.includes(e));
|
|
106
112
|
if (unknown.length > 0) {
|
|
107
113
|
throw new schematics_1.SchematicsException(`[rivinia/env] unknown environment(s): ${unknown.join(', ')}. ` +
|
|
108
|
-
`Choose from
|
|
114
|
+
`Choose from dev, stage (stag), prod.`);
|
|
109
115
|
}
|
|
110
|
-
const selected = cleaned.length > 0
|
|
111
|
-
? [...new Set(cleaned)]
|
|
112
|
-
: [...ALL_ENVIRONMENTS];
|
|
116
|
+
const selected = cleaned.length > 0 ? [...new Set(cleaned)] : [...ALL_ENVIRONMENTS];
|
|
113
117
|
const configsSnapshot = () => JSON.stringify(project.architect?.build?.configurations ?? null);
|
|
114
118
|
const configsBefore = configsSnapshot();
|
|
115
119
|
let created = 0;
|
|
@@ -122,13 +126,13 @@ function ngAdd(options) {
|
|
|
122
126
|
tree.create(path, file.content(version));
|
|
123
127
|
created++;
|
|
124
128
|
}
|
|
125
|
-
if (selected.includes('
|
|
129
|
+
if (selected.includes('prod')) {
|
|
126
130
|
ensureReplacement(tree, angular, name, 'production', {
|
|
127
131
|
replace: `${sourceRoot}/environments/environment.ts`,
|
|
128
132
|
with: `${sourceRoot}/environments/environment.prod.ts`,
|
|
129
133
|
});
|
|
130
134
|
}
|
|
131
|
-
if (selected.includes('
|
|
135
|
+
if (selected.includes('stage')) {
|
|
132
136
|
ensureStaging(tree, angular, name, sourceRoot, context);
|
|
133
137
|
}
|
|
134
138
|
ensureOutputPaths(tree, angular, name, selected, context);
|
|
@@ -224,7 +228,8 @@ function ensureOutputPaths(tree, angular, name, selected, context) {
|
|
|
224
228
|
const configurations = getConfigurations(angular, name);
|
|
225
229
|
let touched = false;
|
|
226
230
|
for (const env of selected) {
|
|
227
|
-
const
|
|
231
|
+
const configName = CONFIG_NAME[env];
|
|
232
|
+
const target = configurations[configName];
|
|
228
233
|
if (!target || 'outputPath' in target)
|
|
229
234
|
continue;
|
|
230
235
|
target['outputPath'] = OUTPUT_DIR[env];
|
|
@@ -6,23 +6,35 @@
|
|
|
6
6
|
"properties": {
|
|
7
7
|
"environments": {
|
|
8
8
|
"type": ["array", "string"],
|
|
9
|
-
"description": "Which environments to scaffold and wire: array, or comma-separated string on the CLI (--environments
|
|
10
|
-
"default": ["
|
|
11
|
-
"items": {
|
|
9
|
+
"description": "Which environments to scaffold and wire: array, or comma-separated string on the CLI (--environments stage,prod). Model + base file always. Omit for all three.",
|
|
10
|
+
"default": ["dev", "stage", "prod"],
|
|
11
|
+
"items": {
|
|
12
|
+
"type": "string",
|
|
13
|
+
"enum": ["dev", "stage", "prod", "stag"]
|
|
14
|
+
},
|
|
12
15
|
"x-prompt": {
|
|
13
16
|
"message": "Which environments should ng-add scaffold and wire?",
|
|
14
17
|
"type": "list",
|
|
15
18
|
"multiselect": true,
|
|
16
19
|
"items": [
|
|
17
|
-
{
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
{
|
|
21
|
+
"value": "dev",
|
|
22
|
+
"label": "dev \u2014 base file, no replacement"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"value": "stage",
|
|
26
|
+
"label": "stage \u2014 staging file + configuration"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"value": "prod",
|
|
30
|
+
"label": "prod \u2014 prod file + replacement"
|
|
31
|
+
}
|
|
20
32
|
]
|
|
21
33
|
}
|
|
22
34
|
},
|
|
23
35
|
"project": {
|
|
24
36
|
"type": "string",
|
|
25
|
-
"description": "Angular CLI project name
|
|
37
|
+
"description": "Angular CLI project name \u2014 only for multi-app workspaces. Defaults to the workspace default project.",
|
|
26
38
|
"default": ""
|
|
27
39
|
}
|
|
28
40
|
},
|