Skip to content

Commit eb27ce8

Browse files
authored
small next tweaks, docs improvements (#79)
1 parent 5b7dfc6 commit eb27ce8

16 files changed

Lines changed: 281 additions & 338 deletions

File tree

.changeset/moody-crabs-fry.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@varlock/nextjs-integration": patch
3+
"varlock": patch
4+
---
5+
6+
onboarding tweaks from user feedback

CONTRIBUTING.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ If you have any questions please reach out to us on [Discord](https://chat.dmno.
88

99
You'll need, at minimum, node 22 and pnpm 10+ installed.
1010

11-
We recommend using [fnm](https://github.com/Schniz/fnm) to manage node versions. If you use `fnm` with `corepack` you can run `corepack enable` to enable pnpm and you should be good to go.
11+
We recommend using [fnm](https://github.com/Schniz/fnm) to manage node versions. If you use `fnm` with [`corepack`](https://github.com/nodejs/corepack) you can run `corepack enable` to enable pnpm and you should be good to go.
1212

1313
Then install the dependencies:
1414

@@ -26,9 +26,10 @@ pnpm build:libs
2626
## Packages
2727

2828
- [packages/env-spec-parser](./packages/env-spec-parser) - Parser for the @env-spec language
29-
- [packages/varlock](./packages/varlock) - CLI for loading .env files and applying schemas
30-
- [packages/varlock-website](./packages/varlock-website) - Website for varlock and env-spec
31-
- [packages/vscode-plugin](./packages/vscode-plugin) - VSCode extension for env-spec
29+
- [packages/varlock](./packages/varlock) - CLI for loading .env files, and library for integration into JS projects
30+
- [packages/varlock-website](./packages/varlock-website) - Docs website for varlock and @env-spec
31+
- [packages/vscode-plugin](./packages/vscode-plugin) - VSCode extension for @env-spec
32+
- [packages/integrations/nextjs](./packages/integrations/nextjs) - Next.js integration for varlock
3233

3334
> See the README.md for each package for more details.
3435

packages/env-graph/src/lib/env-graph.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,11 @@ export class EnvGraph {
102102
if (source.loadingError) {
103103
throw source.loadingError;
104104
}
105+
// example files will always be ignored, except during init flow
106+
if (source.type === 'example') {
107+
source.disabled = true;
108+
continue;
109+
}
105110

106111
// check for @envFlag so we know which item should control loading env-specific files (eg: .env.production)
107112
if (source.decorators?.envFlag) {

packages/integrations/nextjs/README.md

Lines changed: 8 additions & 219 deletions
Original file line numberDiff line numberDiff line change
@@ -2,227 +2,16 @@
22

33
This package helps you integrate [varlock](https://varlock.dev) into a [Next.js](https://nextjs.org) project.
44

5-
It is designed as a drop-in replacement for `@next/env`, which is the internal package that Next.js uses to load `.env` files.
5+
It is designed as a drop-in replacement for [`@next/env`](https://www.npmjs.com/package/@next/env), which is the internal package that Next.js uses to load `.env` files, as well as a small plugin for your `next.config.*` file that enables additional security features.
66

7-
It also provides a plugin for your `next.config.*` file to enable additional security features, such as:
8-
- Redacting sensitive config values from logs
9-
- Preventing sensitive config values from being leaked – both at build time and runtime
7+
Compared to the default `@next/env` behavior, this package provides:
108

9+
- validation of your env vars against your `.env.schema`
10+
- type-generation and type-safe env var access with built-in docs
11+
- redaction of sensitive values from application logs
12+
- leak detection and prevention, both at build and runtime
13+
- more flexible multi-env handling - you can load env-specific files other than `.env.development`/`.env.production`
1114

12-
## Installation
13-
14-
First install this module and `varlock` using your package manager of choice:
15-
> `npm install @varlock/nextjs-integration varlock` (or pnpm, yarn, etc)
16-
17-
### Step 1: Install `@next/env` override
18-
19-
You must tell your package manager to override all resolution of `@next/env` with `@varlock/nextjs-integration`.
20-
21-
The method for doing this depends on your package manager:
22-
23-
**NPM**
24-
See [NPM overrides docs](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#overrides)
25-
26-
NPM lets you reference another installed dependency in overrides. For example: `"dep-to-override": "$other-installed-dep"`.
27-
28-
_package.json_
29-
```
30-
"overrides": {
31-
"@next/env": "npm:@varlock/nextjs-integration"
32-
}
33-
```
34-
35-
**Yarn**
36-
See [yarn resolutions docs](https://yarnpkg.com/configuration/manifest#resolutions)
37-
38-
_root package.json_
39-
```
40-
"resolutions": {
41-
"**/@next/env": "npm:@varlock/nextjs-integration"
42-
}
43-
```
44-
45-
> ⚠️ If in a monorepo, this must be done in the monorepo root `package.json` file
46-
47-
**pnpm (version 10+)**
48-
See [pnpm overrides docs](https://pnpm.io/settings#overrides)
49-
50-
> ⚠️ This must be set in `pnpm-workspace.yaml`, regardless of whether you are using a monorepo or not
51-
52-
_pnpm-workspace.yaml_
53-
```
54-
overrides:
55-
"@next/env": "npm:@varlock/nextjs-integration"
56-
```
57-
58-
**pnpm (version 9)**
59-
See [pnpm overrides docs](https://pnpm.io/settings#overrides)
60-
61-
> ⚠️ If in a monorepo, this must be set in the root `package.json` file
62-
63-
_root package.json_
64-
```
65-
"pnpm": {
66-
"overrides": {
67-
"@next/env": "npm:@varlock/nextjs-integration"
68-
}
69-
}
70-
```
71-
72-
73-
### Step 2: Enable `next.config.*` plugin
74-
75-
While using _only_ the override will swap `.env` loading duties over to varlock, to get the full benefits, you must also add a config plugin in your `next.config.ts` (or `next.config.js`) file.
76-
77-
Next.js does not have a proper plugin system, but we can add a small transformation function on top of your existing config, which will install the necessary adjustments.
78-
79-
Here is an example of how to do this:
80-
81-
```ts
82-
import type { NextConfig } from "next";
83-
import { varlockNextConfigPlugin } from '@varlock/nextjs-integration/plugin';
84-
85-
const nextConfig: NextConfig = {
86-
// your existing config...
87-
};
88-
89-
export default varlockNextConfigPlugin()(nextConfig);
90-
```
91-
92-
93-
94-
## Accessing env vars in your code
95-
While your resolved config will be re-injected as normal env vars and you can continue to use `process.env.SOMEVAR` as usual, we recommend using varlock's imported `ENV` object instead. For example:
96-
97-
```ts
98-
import { ENV } from 'varlock/env';
99-
100-
console.log(process.env.SOMEVAR); // 🆗 still works
101-
console.log(ENV.SOMEVAR); // ✨ but this is recommended
102-
```
103-
104-
### Type-safety
105-
106-
To enable type-safety and IntelliSense for your env vars, you must enable the [`@generateTypes` root decorator](https://varlock.dev/reference/root-decorators/#generatetypes) in your `.env.schema`.
107-
> ⚠️ If you ran `npx varlock init`, this will likely already be enabled for you.
108-
109-
```env-spec
110-
# @generateTypes(lang='ts', path='env.d.ts')
111-
# ---
112-
# your config items...
113-
```
114-
115-
This will make types available both for `process.env` and for varlock's `ENV` object.
116-
117-
### Why use `ENV` instead of `process.env`?
118-
- Any non-string values (e.g., number, boolean) will actually be their coerced value, rather than a string
119-
- _All_ non-sensitive items will be replaced at build time, not just `NEXT_PUBLIC_` prefixed items
120-
- Better error messages when using invalid keys, or server-side keys that are not available on the client
121-
- Enables further DX improvements in the future, such as tighter control over which items are bundled at build time.
122-
123-
124-
125-
## Managing multiple environments (dev, preview, prod, etc)
126-
127-
Varlock excels at managing multiple environments and can load multiple _environment-specific_ .env files (e.g., `.env.development`, `.env.preview`, `.env.production`, etc.).
128-
129-
While `.env.schema`, `.env`, and `.env.local` will always be loaded, loading env-specific files is controlled by a notion of an _environment flag_.
130-
131-
[Next.js .env handling](https://nextjs.org/docs/pages/guides/environment-variables#loading-environment-variables-with-nextenv) has the following behavior to set the env flag and control loading env-specific .env files:
132-
- use `test` if `NODE_ENV` is set to `test`
133-
- otherwise use `development` if running `next dev`
134-
- otherwise use `production`
135-
136-
By default, this module will match that behaviour, but we recommend using the [`@envFlag` root decorator](https://varlock.dev/reference/root-decorators/#envflag) in your `.env.schema` to specify your own _custom environment flag_, such as `APP_ENV`.
137-
138-
**⚠️ Without a custom env flag, you will not have the ability to use a non-production env file (e.g., `.env.preview`, `.env.staging`, etc) for your non-prod deployments.**
139-
140-
How we set the value of our env flag will depend on your deployment platform.
141-
142-
When running locally, or building and deploying your next app on a platform you control, you can set it explicitly, often passed in via `package.json` scripts. For example:
143-
```json
144-
// package.json
145-
"scripts": {
146-
"build:preview": "APP_ENV=preview next build",
147-
"start:preview": "APP_ENV=preview next start",
148-
"build:prod": "APP_ENV=production next build",
149-
"start:prod": "APP_ENV=production next start",
150-
"test": "APP_ENV=test jest"
151-
}
152-
```
153-
154-
However on some cloud platforms (e.g., Vercel, Cloudflare, etc), you may not have control over a boot command, or even the ability to vary environment variables as you would like.
155-
Even if you do, it's not always ideal to have this configuration buried in a UI rather than your code.
156-
157-
In these cases, we can set the value of `APP_ENV` (or whatever you name your env flag) using resolver functions to transform existing env vars that the platform's CI/CD pipeline provides (e.g., branch name, platform's notion of env, etc)
158-
159-
The following examples show how you could do this, but note that you could segment your environments (and name them) however you like.
160-
161-
### Vercel
162-
163-
In Vercel, you can set `APP_ENV` explicitly in their env vars UI. But to keep everything contained in your schema, you can use the injected `VERCEL_ENV`.
164-
165-
```env-spec
166-
# @envFlag=APP_ENV
167-
# ---
168-
# current environment type, injected by vercel during deployments
169-
# @type=enum(development, preview, production)
170-
# @docsUrl="https://vercel.com/docs/environment-variables/system-environment-variables#system-environment-variables"
171-
VERCEL_ENV=
172-
# Our env flag, used to toggle loading of env-specific files
173-
APP_ENV=fallback($VERCEL_ENV, development)
174-
```
175-
176-
If you need more specific environments based on branch names, you can use `VERCEL_GIT_COMMIT_REF` instead. See the Cloudflare example below for more details.
177-
178-
### Cloudflare Workers Build
179-
180-
In Cloudflare Workers Builds, it is not possible to alter our build command for prod versus non-prod builds, and there is no concept of branch-specific env vars.
181-
182-
We must rely on the current branch name, injected as `WORKERS_CI_BRANCH`, to determine what our env flag should be.
183-
184-
We can use the following strategy to set our env flag:
185-
- `production` – if `WORKERS_CI_BRANCH` is set to `main`, this is a production deployment
186-
- `preview` – if `WORKERS_CI_BRANCH` is set to anything else, this is a preview deployment
187-
- `development` – if `WORKERS_CI_BRANCH` is not set, this means we are not within CI, so we must be doing local development
188-
- `test` – we can set this explicitly in our test command. For example, in our `package.json` scripts, we could use `"test": "APP_ENV=test jest"`.
189-
190-
```env-spec
191-
# @envFlag=APP_ENV
192-
# ---
193-
# current branch set by Cloudflare Workers Build
194-
# @docsUrl="https://developers.cloudflare.com/workers/ci-cd/builds/configuration/#environment-variables"
195-
WORKERS_CI_BRANCH=
196-
# Our env flag, used to toggle loading of env-specific files
197-
# @type=enum(development, preview, production, test)
198-
APP_ENV=remap($WORKERS_CI_BRANCH, production="main", preview=regex(.*), development=undefined)
199-
```
200-
201-
## Managing Sensitive Config Values
202-
203-
Next.js itself uses the [`NEXT_PUBLIC_` prefix](https://nextjs.org/docs/pages/guides/environment-variables#bundling-environment-variables-for-the-browser) to determine which env vars can be considered _public_ (i.e., not sensitive). These public vars will be bundled at build-time made available in the browser.
204-
205-
Varlock controls the default sensitive behavior via the [`@defaultSensitive` root decorator](https://varlock.dev/reference/root-decorators/#defaultsensitive).
206-
207-
If you want to continue using the prefix, you can use `# @defaultSensitive=inferFromPrefix('NEXT_PUBLIC_')` in your `.env.schema` file.
208-
209-
```env-spec
210-
# @defaultSensitive=inferFromPrefix('NEXT_PUBLIC_')
211-
# ---
212-
FOO= # sensitive
213-
NEXT_PUBLIC_FOO= # non-sensitive, due to prefix
214-
```
215-
216-
However, we recommend you set `@defaultSensitive` to `true` or `false` and then explicitly tag individual items using the [`@sensitive`](https://varlock.dev/reference/item-decorators/#sensitive) item decorator. For example:
217-
218-
```env-spec
219-
# @defaultSensitive=true
220-
# ---
221-
SECRET_FOO= # will be sensitive, due to default
222-
# @sensitive=false
223-
NON_SECRET_FOO=
224-
```
225-
226-
> ⚠️ NOTE - All non-sensitive items will be bundled at build-time via varlock's `ENV` object, while `process.env` replacements will only include `NEXT_PUBLIC_` prefixed items.
15+
See [our docs site](https://varlock.dev/integrations/nextjs/) for complete installation and usage instructions.
22716

22817

packages/integrations/nextjs/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
"types": "dist/next-env-compat.d.ts",
1212
"exports": {
1313
".": "./dist/next-env-compat.js",
14-
"./runtime": "./dist/runtime.js",
1514
"./plugin": "./dist/plugin.js"
1615
},
1716
"files": ["dist"],

packages/integrations/nextjs/src/next-env-compat.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -283,8 +283,8 @@ export function loadEnvConfig(
283283
varlockLoadedEnv = JSON.parse(varlockLoadedEnvBuf.toString());
284284
} catch (err) {
285285
const { status, stdout, stderr } = err as ReturnType<typeof spawnSync>;
286-
const stdoutStr = stdout?.toString();
287-
const stderrStr = stderr?.toString();
286+
const stdoutStr = stdout?.toString() || '';
287+
const stderrStr = stderr?.toString() || '';
288288
if (stderrStr.includes('command not found')) {
289289
console.error([
290290
'',

packages/integrations/nextjs/tsup.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export default defineConfig({
1717
clean: true, // Clean output directory before building
1818
outDir: 'dist', // Output directory
1919

20+
// ! we are exporting cjs to match @next/env
2021
format: ['cjs'], // Output format(s)
2122
splitting: false,
2223
});

0 commit comments

Comments
 (0)