Skip to content

Commit 3d8b4f5

Browse files
authored
Merge pull request #7 from expatfile/feat/colorized-terminal-messages
feat: ✨ next.js style terminal string styling
2 parents 962ef1e + 7f015a5 commit 3d8b4f5

File tree

9 files changed

+113
-28
lines changed

9 files changed

+113
-28
lines changed

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@
3131
"url": "https://github.com/expatfile/next-runtime-env/issues"
3232
},
3333
"homepage": "https://github.com/expatfile/next-runtime-env#readme",
34+
"dependencies": {
35+
"chalk": "4.1.2"
36+
},
3437
"devDependencies": {
3538
"@types/eslint": "^8.37.0",
3639
"@types/jest": "^29.5.1",

pnpm-lock.yaml

Lines changed: 5 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/helpers/get-public-env.spec.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
1+
import chalk from 'chalk';
2+
13
import { getPublicEnv } from './get-public-env';
24

5+
const infoSpy = jest.spyOn(console, 'info');
6+
7+
beforeAll(() => {
8+
infoSpy.mockImplementation();
9+
});
10+
11+
afterAll(() => {
12+
infoSpy.mockRestore();
13+
});
14+
315
describe('getPublicEnv()', () => {
416
afterEach(() => {
517
delete process.env.FOO;
@@ -10,7 +22,17 @@ describe('getPublicEnv()', () => {
1022
delete process.env.NEXT_PUBLIC_BAZ;
1123
});
1224

13-
it('should return a allow-listed value', () => {
25+
it('should show an info message after reading the environment', () => {
26+
getPublicEnv();
27+
28+
expect(infoSpy).toHaveBeenCalledWith(
29+
`${chalk.cyan(
30+
`info`
31+
)} - [next-runtime-env] - Read environment variables prefixed with 'NEXT_PUBLIC_' from process.env.`
32+
);
33+
});
34+
35+
it('should return an allow-listed value', () => {
1436
process.env.NEXT_PUBLIC_FOO = 'foo';
1537

1638
expect(getPublicEnv()).toEqual({

src/helpers/get-public-env.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
import * as log from '../utils/log';
2+
13
/**
24
* Gets a list of environment variables that start with `NEXT_PUBLIC_`.
35
*/
46
export function getPublicEnv() {
5-
return Object.keys(process.env)
7+
const publicEnv = Object.keys(process.env)
68
.filter((key) => /^NEXT_PUBLIC_/i.test(key))
79
.reduce(
810
(env, key) => ({
@@ -11,4 +13,10 @@ export function getPublicEnv() {
1113
}),
1214
{} as NodeJS.ProcessEnv
1315
);
16+
17+
log.info(
18+
`Read environment variables prefixed with 'NEXT_PUBLIC_' from process.env.`
19+
);
20+
21+
return publicEnv;
1422
}

src/helpers/write-browser-env.spec.ts

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import chalk from 'chalk';
12
import fs from 'fs';
23

34
import { writeBrowserEnv } from './write-browser-env';
@@ -7,6 +8,9 @@ const infoSpy = jest.spyOn(console, 'info');
78
const base = fs.realpathSync(process.cwd());
89
const path = `${base}/public`;
910
const file = `${path}/__ENV.js`;
11+
const message = `${chalk.cyan(
12+
`info`
13+
)} - [next-runtime-env] - Wrote browser runtime environment variables to ${file}`;
1014

1115
beforeAll(() => {
1216
infoSpy.mockImplementation();
@@ -28,10 +32,7 @@ describe('writeBrowserEnv()', () => {
2832
it('should write an empty env', () => {
2933
writeBrowserEnv({});
3034

31-
expect(infoSpy).toHaveBeenCalledWith(
32-
'> [next-runtime-env] Writing browser runtime env',
33-
file
34-
);
35+
expect(infoSpy).toHaveBeenCalledWith(message);
3536

3637
const content = fs.readFileSync(file).toString();
3738

@@ -43,10 +44,7 @@ describe('writeBrowserEnv()', () => {
4344
NEXT_PUBLIC_FOO: 'foo',
4445
});
4546

46-
expect(infoSpy).toHaveBeenCalledWith(
47-
'> [next-runtime-env] Writing browser runtime env',
48-
file
49-
);
47+
expect(infoSpy).toHaveBeenCalledWith(message);
5048

5149
const content = fs.readFileSync(file).toString();
5250

@@ -60,10 +58,7 @@ describe('writeBrowserEnv()', () => {
6058
NEXT_PUBLIC_BAZ: 'baz',
6159
});
6260

63-
expect(infoSpy).toHaveBeenCalledWith(
64-
'> [next-runtime-env] Writing browser runtime env',
65-
file
66-
);
61+
expect(infoSpy).toHaveBeenCalledWith(message);
6762

6863
const content = fs.readFileSync(file).toString();
6964

src/helpers/write-browser-env.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import fs from 'fs';
22

3+
import * as log from '../utils/log';
4+
35
/**
46
* Writes the environment variables to the public __ENV.js file and make them
57
* accessible under `window.__ENV`.
@@ -8,10 +10,9 @@ export function writeBrowserEnv(env: NodeJS.ProcessEnv) {
810
const base = fs.realpathSync(process.cwd());
911
const path = `${base}/public/__ENV.js`;
1012

11-
// eslint-disable-next-line no-console
12-
console.info('> [next-runtime-env] Writing browser runtime env', path);
13-
1413
const content = `window.__ENV = ${JSON.stringify(env)};`;
1514

1615
fs.writeFileSync(path, content);
16+
17+
log.info(`Wrote browser runtime environment variables to ${path}`);
1718
}

src/make-env-public.spec.ts

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
1+
import chalk from 'chalk';
2+
13
import { makeEnvPublic } from './make-env-public';
24

35
const warnSpy = jest.spyOn(console, 'warn');
6+
const infoSpy = jest.spyOn(console, 'info');
47

58
beforeAll(() => {
69
warnSpy.mockImplementation();
10+
infoSpy.mockImplementation();
711
});
812

913
afterAll(() => {
1014
warnSpy.mockRestore();
15+
infoSpy.mockRestore();
1116
});
1217

1318
describe('makeEnvPublic()', () => {
@@ -38,19 +43,50 @@ describe('makeEnvPublic()', () => {
3843

3944
expect(process.env.FOO).toEqual('foo');
4045
expect(process.env.NEXT_PUBLIC_FOO).toEqual('foo');
46+
4147
expect(process.env.BAR).toEqual('bar');
4248
expect(process.env.NEXT_PUBLIC_BAR).toEqual('bar');
49+
4350
expect(process.env.BAZ).toEqual('baz');
4451
expect(process.env.NEXT_PUBLIC_BAZ).toEqual('baz');
4552
});
4653

54+
it('should show an info message when env vars are prefixed', () => {
55+
process.env.FOO = 'foo';
56+
process.env.BAR = 'bar';
57+
process.env.BAZ = 'baz';
58+
59+
makeEnvPublic('FOO');
60+
makeEnvPublic(['BAR', 'BAZ']);
61+
62+
expect(infoSpy).toHaveBeenCalledWith(
63+
`${chalk.cyan(
64+
`info`
65+
)} - [next-runtime-env] - Prefixed environment variable 'FOO'.`
66+
);
67+
68+
expect(infoSpy).toHaveBeenCalledWith(
69+
`${chalk.cyan(
70+
`info`
71+
)} - [next-runtime-env] - Prefixed environment variable 'BAR'.`
72+
);
73+
74+
expect(infoSpy).toHaveBeenCalledWith(
75+
`${chalk.cyan(
76+
`info`
77+
)} - [next-runtime-env] - Prefixed environment variable 'BAZ'.`
78+
);
79+
});
80+
4781
it('should warn when the env var already starts with NEXT_PUBLIC_', () => {
4882
process.env.NEXT_PUBLIC_FOO = 'foo';
4983

5084
makeEnvPublic('NEXT_PUBLIC_FOO');
5185

5286
expect(warnSpy).toHaveBeenCalledWith(
53-
'> [next-runtime-env] The environment variable "NEXT_PUBLIC_FOO" is already public.'
87+
`${chalk.yellow(
88+
`warn`
89+
)} - [next-runtime-env] - Environment variable 'NEXT_PUBLIC_FOO' is already public.`
5490
);
5591
});
5692
});

src/make-env-public.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1+
import * as log from './utils/log';
2+
13
function prefixKey(key: string) {
24
// Check if the key already is already public.
35
if (/^NEXT_PUBLIC_/i.test(key)) {
4-
// eslint-disable-next-line no-console
5-
console.warn(
6-
`> [next-runtime-env] The environment variable "${key}" is already public.`
7-
);
6+
log.warn(`Environment variable '${key}' is already public.`);
87
}
98

109
const prefixedKey = `NEXT_PUBLIC_${key}`;
1110

1211
process.env[prefixedKey] = process.env[key];
12+
13+
log.info(`Prefixed environment variable '${key}'.`);
1314
}
1415

1516
/**

src/utils/log.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/* eslint-disable no-console */
2+
3+
import chalk from 'chalk';
4+
5+
const libraryName = '[next-runtime-env]';
6+
const librarySeperator = '-';
7+
const libraryPrefix = `${libraryName} ${librarySeperator}`;
8+
9+
const prefixes = {
10+
warn: `${chalk.yellow(`warn`)} - ${libraryPrefix}`,
11+
info: `${chalk.cyan(`info`)} - ${libraryPrefix}`, // Double space before the dash aligns messages in the terminal and improves readability.
12+
};
13+
14+
export function warn(message: string) {
15+
console.warn(`${prefixes.warn} ${message}`);
16+
}
17+
18+
export function info(message: string) {
19+
console.info(`${prefixes.info} ${message}`);
20+
}

0 commit comments

Comments
 (0)