Skip to content

Commit 67e8319

Browse files
committed
feat: expose function for validation without running Vite
1 parent cfa9502 commit 67e8319

File tree

3 files changed

+66
-25
lines changed

3 files changed

+66
-25
lines changed

README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,31 @@ export const env: ImportMetaEnvAugmented = import.meta.env;
181181

182182
By using `env` instead of `import.meta.env` in your code, TypeScript will now throw an error if you try to access an unknown variable.
183183

184+
## Validation without Vite
185+
186+
If you want to load and validate your environment variables the same way the plugin would do it, but without actually running Vite, you can use the additionally exposed `loadAndValidateEnv` function:
187+
188+
```ts
189+
import { loadAndValidateEnv } from '@julr/vite-plugin-validate-env';
190+
191+
const env = await loadAndValidateEnv(
192+
{ // Simulated Vite configuration
193+
mode: 'development', // required
194+
root: process.cwd(), // optional
195+
envDir: process.cwd(), // optional
196+
envPrefix: 'VITE_', // optional
197+
},
198+
{ // Plugin options
199+
validator: 'builtin',
200+
schema: {
201+
VITE_MY_VAR: Schema.string()
202+
},
203+
},
204+
);
205+
206+
Object.assign(process.env, env);
207+
```
208+
184209
## 💖 Sponsors
185210

186211
If you find this useful, consider [sponsoring me](https://github.com/sponsors/Julien-R44)! It helps support and maintain the project 🙏

src/index.ts

Lines changed: 37 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import path from 'node:path'
22
import { cwd } from 'node:process'
3+
import { type Plugin } from 'vite'
34
import { createConfigLoader as createLoader } from 'unconfig'
4-
import { type ConfigEnv, type Plugin, type UserConfig } from 'vite'
55

66
import { initUi, type UI } from './ui.js'
77
import { builtinValidation } from './validators/builtin/index.js'
88
import { standardValidation } from './validators/standard/index.js'
9-
import type { FullPluginOptions, PluginOptions, Schema } from './types.js'
9+
import type { ConfigOptions, FullPluginOptions, PluginOptions, Schema } from './types.js'
1010

1111
/**
1212
* Load schema defined in `env.ts` file using unconfig
@@ -71,42 +71,27 @@ function shouldLogVariables(options: PluginOptions) {
7171
/**
7272
* Main function. Will call each validator defined in the schema and throw an error if any of them fails.
7373
*/
74-
async function validateEnv(
75-
ui: UI,
76-
userConfig: UserConfig,
77-
envConfig: ConfigEnv,
78-
inlineOptions?: PluginOptions,
79-
) {
74+
async function validateEnv(ui: UI, config: ConfigOptions, inlineOptions?: PluginOptions) {
8075
/**
8176
* Dynamic import of Vite helpers to using the ESM build of Vite and
8277
* avoiding CJS since it will be deprecated
8378
* See : https://vitejs.dev/guide/troubleshooting.html#vite-cjs-node-api-deprecated
8479
*/
8580
const { normalizePath, loadEnv } = await import('vite')
86-
const rootDir = userConfig.root || cwd()
81+
const rootDir = config.root || cwd()
8782

88-
const resolvedRoot = normalizePath(
89-
userConfig.root ? path.resolve(userConfig.root) : process.cwd(),
90-
)
83+
const resolvedRoot = normalizePath(config.root ? path.resolve(config.root) : process.cwd())
9184

92-
const envDir = userConfig.envDir
93-
? normalizePath(path.resolve(resolvedRoot, userConfig.envDir))
85+
const envDir = config.envDir
86+
? normalizePath(path.resolve(resolvedRoot, config.envDir))
9487
: resolvedRoot
9588

96-
const env = loadEnv(envConfig.mode, envDir, userConfig.envPrefix)
89+
const env = loadEnv(config.mode, envDir, config.envPrefix)
9790

9891
const options = await loadOptions(rootDir, inlineOptions)
9992
const variables = await validateAndLog(ui, env, options)
10093

101-
return {
102-
define: variables.reduce(
103-
(acc, { key, value }) => {
104-
acc[`import.meta.env.${key}`] = JSON.stringify(value)
105-
return acc
106-
},
107-
{} as Record<string, unknown>,
108-
),
109-
}
94+
return variables
11095
}
11196

11297
async function validateAndLog(ui: UI, env: Record<string, string>, options: PluginOptions) {
@@ -139,10 +124,37 @@ export const ValidateEnv = (options?: PluginOptions): Plugin => {
139124
// @ts-expect-error - only used for testing as we need to keep each instance of the plugin unique to a test
140125
ui: process.env.NODE_ENV === 'testing' ? ui : undefined,
141126
name: 'vite-plugin-validate-env',
142-
config: (config, env) => validateEnv(ui, config, env, options),
127+
config: ({ envDir, envPrefix, root }, { mode }) =>
128+
validateEnv(ui, { envDir, envPrefix, root, mode }, options).then((variables) => ({
129+
define: variables.reduce(
130+
(acc, { key, value }) => {
131+
acc[`import.meta.env.${key}`] = JSON.stringify(value)
132+
return acc
133+
},
134+
{} as Record<string, string>,
135+
),
136+
})),
143137
}
144138
}
145139

140+
/**
141+
* Load environment variables using the provided Vite configuration
142+
* and validate them against a schema the same way `ValidateEnv` does it
143+
* @returns An object mapping environment variable names to validation results
144+
*/
145+
export const loadAndValidateEnv = (config: ConfigOptions, options?: PluginOptions) => {
146+
const ui = initUi()
147+
return validateEnv(ui, config, options).then((variables) =>
148+
variables.reduce(
149+
(acc, { key, value }) => {
150+
acc[key] = value
151+
return acc
152+
},
153+
{} as Record<string, any>,
154+
),
155+
)
156+
}
157+
146158
export const defineConfig = <T extends PluginOptions>(config: T): T => config
147159

148160
export { schema as Schema } from '@poppinss/validator-lite'

src/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { z } from 'zod'
2+
import type { ConfigEnv, UserConfig } from 'vite'
23
import type { StandardSchemaV1 } from '@standard-schema/spec'
34
import type { ValidateFn } from '@poppinss/validator-lite/types'
45

@@ -23,6 +24,9 @@ export type StandardSchema = RecordViteKeys<StandardSchemaV1>
2324

2425
export type Schema = PoppinsSchema | StandardSchema
2526

27+
export type ConfigOptions = Pick<UserConfig, 'envDir' | 'envPrefix' | 'root'> &
28+
Pick<ConfigEnv, 'mode'>
29+
2630
/**
2731
* Infer the schema type from the plugin options
2832
*/

0 commit comments

Comments
 (0)