Skip to content

Commit

Permalink
feat: support for custom config file path
Browse files Browse the repository at this point in the history
close #22
  • Loading branch information
Julien-R44 committed Feb 11, 2024
1 parent a6ae092 commit 6720e16
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 49 deletions.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,22 @@ export default defineConfig({
})
```

### Custom config file path

By default, the plugin is looking for a file named `env.ts` at the root of your project. If you want to use a different file, you can specify the path to your file in the plugin options.

```ts
// vite.config.ts
import { defineConfig } from 'vite'
import { ValidateEnv } from "@julr/vite-plugin-validate-env";

export default defineConfig({
plugins: [ValidateEnv({ envFile: 'config/env' })],
})
```

This will look for a file named `env.ts` in the `config` folder at the root of your project. Make sure to not include the file extension in the path as the plugin will automatically search for `.js`, `.ts` and other valid file extensions.

## Transforming variables
In addition to the validation of your variables, there is also a parsing that is done. This means that you can modify the value of an environment variable before it is injected.

Expand Down
32 changes: 19 additions & 13 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,28 @@ import type { FullPluginOptions, PluginOptions, Schema } from './types.js'
/**
* Load schema defined in `env.ts` file using unconfig
*/
async function loadConfig(rootDir: string) {
async function loadOptions(rootDir: string, inlineConfig?: PluginOptions) {
let source = 'env'

/**
* If configFile is defined in the inlineConfig, use it as the source
*/
if (inlineConfig && 'configFile' in inlineConfig && inlineConfig.configFile) {
source = inlineConfig.configFile
}

const loader = createLoader<PluginOptions>({
sources: [{ files: 'env', extensions: ['ts', 'cts', 'mts', 'js', 'cjs', 'mjs'] }],
sources: [{ files: source, extensions: ['ts', 'cts', 'mts', 'js', 'cjs', 'mjs'] }],
cwd: rootDir,
defaults: inlineConfig,
})

const result = await loader.load()
return result.config
const config = result.config

if (!config) throw new Error('Missing configuration for vite-plugin-validate-env')

return config
}

/**
Expand Down Expand Up @@ -61,7 +75,7 @@ async function validateEnv(
ui: UI,
userConfig: UserConfig,
envConfig: ConfigEnv,
options?: PluginOptions,
inlineOptions?: PluginOptions,
) {
const rootDir = userConfig.root || cwd()

Expand All @@ -75,15 +89,7 @@ async function validateEnv(

const env = loadEnv(envConfig.mode, envDir, userConfig.envPrefix)

const isInlineConfig = options !== undefined
if (!isInlineConfig) {
options = await loadConfig(rootDir)
}

if (!options) {
throw new Error('Missing configuration for vite-plugin-validate-env')
}

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

return {
Expand Down
7 changes: 4 additions & 3 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ export type RecordViteKeys<T> = Record<`${string}_${string}`, T>
*/
export type PluginOptions = Schema | FullPluginOptions

export type FullPluginOptions =
| { validator: 'builtin'; schema: PoppinsSchema; debug?: boolean }
| { validator: 'zod'; schema: ZodSchema; debug?: boolean }
export type FullPluginOptions = (
| { validator: 'builtin'; schema: PoppinsSchema }
| { validator: 'zod'; schema: ZodSchema }
) & { debug?: boolean; configFile?: string }

/**
* Contract for schema definition for poppins validator
Expand Down
33 changes: 0 additions & 33 deletions tests/common.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,39 +81,6 @@ test.group('vite-plugin-validate-env', () => {
assert.deepEqual(define['import.meta.env.VITE_URL_TRAILING'], '"test.com/"')
})

test('Dedicated config file', async ({ assert, fs }) => {
assert.plan(1)

const plugin = ValidateEnv()

await fs.create(`.env.development`, `VITE_MY_VAR=true`)
await fs.create(
`env.ts`,
`export default {
VITE_TEST: () => {
throw new Error('Error validating')
}
}`,
)

try {
// @ts-ignore
await plugin.config({ root: fs.basePath }, viteEnvConfig)
} catch (error: any) {
assert.include(error.message, 'Error validating')
}
})

test('Should fail if no schema is found', async ({ assert, fs }) => {
const plugin = ValidateEnv()

await fs.create(`.env.development`, `VITE_MY_VAR=true`)

// @ts-expect-error - `config` is the handler
const fn = plugin.config!.bind(plugin, { root: fs.basePath }, viteEnvConfig)
await assert.rejects(fn, 'Missing configuration for vite-plugin-validate-env')
})

test('Should pick up var with custom prefix', async ({ assert, fs }) => {
assert.plan(1)

Expand Down
93 changes: 93 additions & 0 deletions tests/config.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { test } from '@japa/runner'

import type { UI } from '../src/ui.js'
import { ValidateEnv as CoreTypedValidateEnv, Schema } from '../src/index.js'

const viteEnvConfig = { mode: 'development', command: 'serve' } as const

const ValidateEnv = CoreTypedValidateEnv as (
...args: Parameters<typeof CoreTypedValidateEnv>
) => ReturnType<typeof CoreTypedValidateEnv> & { ui: UI }

test.group('Config loading', () => {
test('Dedicated config file', async ({ fs }) => {
const plugin = ValidateEnv()

await fs.create(`.env.development`, `VITE_MY_VAR=true`)
await fs.create(
`env.ts`,
`export default {
VITE_TEST: () => {
throw new Error('Error validating')
}
}`,
)

// @ts-ignore
await plugin.config({ root: fs.basePath }, viteEnvConfig)
}).throws(/Error validating/)

test('dedicated config file custom path', async ({ fs }) => {
const plugin = ValidateEnv({ configFile: 'import_env' })

await fs.create(`.env.development`, `VITE_MY_VAR=true`)
await fs.create(
`import_env.ts`,
`export default {
VITE_TEST: () => {
throw new Error('Error validating')
}
}`,
)

// @ts-ignore
await plugin.config({ root: fs.basePath }, viteEnvConfig)
}).throws(/Error validating/)

test('Should fail if no schema is found', async ({ assert, fs }) => {
const plugin = ValidateEnv()

await fs.create(`.env.development`, `VITE_MY_VAR=true`)

// @ts-expect-error - `config` is the handler
const fn = plugin.config!.bind(plugin, { root: fs.basePath }, viteEnvConfig)
await assert.rejects(fn, 'Missing configuration for vite-plugin-validate-env')
})

test('if inline config is also specified, it should be merged with the dedicated config file', async ({
fs,
assert,
}) => {
const plugin = ValidateEnv({ VITE_VAR: Schema.number() })

await fs.create(`.env.development`, `VITE_TEST=true\nVITE_VAR=34`)
await fs.create(
`env.ts`,
`export default {
VITE_TEST: () => 42
}`,
)

// @ts-ignore
const { define } = await plugin.config({ root: fs.basePath }, viteEnvConfig)

assert.deepEqual(define['import.meta.env.VITE_VAR'], '34')
assert.deepEqual(define['import.meta.env.VITE_TEST'], '42')
})

test('dedicated config file in another folder', async ({ fs }) => {
const plugin = ValidateEnv({ configFile: 'config/env' })

await fs.create(
`config/env.ts`,
`export default {
VITE_TEST: (key, value) => {
throw new Error('Error validating')
}
}`,
)

// @ts-ignore
await plugin.config({ root: fs.basePath }, viteEnvConfig)
}).throws(/Error validating/)
})

0 comments on commit 6720e16

Please sign in to comment.