Skip to content

Commit f185f62

Browse files
feat: add vite plugin (#121)
* feat(vite): added vite plugin * feat(docs): added vite plugin documentation
1 parent 9f6a87c commit f185f62

File tree

11 files changed

+933
-188
lines changed

11 files changed

+933
-188
lines changed

README.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Here are some of the benefits of using `dotenv-run`:
2020
| Core | [@dotenv-run/core](#dotenv-runcore) ||
2121
| ESBuild | [@dotenv-run/esbuild](#dotenv-runesbuild) ||
2222
| Rollup | [@dotenv-run/rollup](#dotenv-runrollup) ||
23-
| Vite | [@dotenv-run/rollup](#dotenv-runrollup) ||
23+
| Vite | [@dotenv-run/vite](#dotenv-runvite) ||
2424
| Node.js preload | @dotenv-run/load ||
2525
| Angular | [@ngx-env/builder](#ngx-envbuilder) ||
2626

@@ -31,6 +31,7 @@ Here are some of the benefits of using `dotenv-run`:
3131
- [@dotenv-run/core](#dotenv-runcore)
3232
- [@dotenv-run/esbuild](#dotenv-runesbuild)
3333
- [@ngx-env/builder](#ngx-envbuilder)
34+
- [Testimonials](#testimonials)
3435
- [Demos](#demos)
3536
- [Quick start](#quick-start-1)
3637
- [@dotenv-run/webpack](#dotenv-runwebpack)
@@ -275,6 +276,19 @@ export default {
275276
};
276277
```
277278

279+
280+
[`@dotenv-run/vite`](https://www.npmjs.com/package/@dotenv-run/vite) is a plugin for vite that can be used to inject environment variables into your applications.
281+
282+
```js
283+
import env from "@dotenv-run/vite";
284+
285+
export default {
286+
envPrefix: 'MY_PREFIX_',
287+
envDir: './my-env-directory',
288+
plugins: [env()],
289+
};
290+
```
291+
278292
## Credits
279293

280294
- [dotenv](https://github.com/motdotla/dotenv)

docs/astro.config.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export default defineConfig({
3131
{ label: 'Node.js', link: '/integrations/loader/' },
3232
{ label: 'Rollup', link: '/integrations/rollup/' },
3333
{ label: 'Webpack', link: '/integrations/webpack/' },
34-
// { label: 'Vite', link: '/integrations/vite/' },
34+
{ label: 'Vite', link: '/integrations/vite/' },
3535
// { label: 'Babel', link: '/integrations/webpack/' },
3636
// { label: 'Jest', link: '/integrations/jest/' },
3737
// { label: 'SWC', link: '/integrations/swc/' },
Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,27 @@
11
---
22
title: Vite
3-
---
3+
---
4+
5+
## Install
6+
7+
```console
8+
npm add @dotenv-run/vite --save-dev
9+
```
10+
11+
## Usage
12+
13+
Create a `vite.config.js` [configuration file](https://vite.dev/config) and import the plugin:
14+
15+
```js
16+
import env from "@dotenv-run/vite";
17+
18+
export default {
19+
envPrefix: 'MY_PREFIX_',
20+
envDir: './my-env-directory',
21+
plugins: [env()],
22+
};
23+
```
24+
25+
Then call `vite` or `vite build` either via the [CLI](https://vite.dev/guide/cli.html).
26+
27+
The available options are similar to those supported by [`@dotenv-run/core`](https://www.npmjs.com/package/@dotenv-run/core), but this plugin seamlessly integrates with Vite by automatically deriving the root, prefix, and environment values from its standard configuration, ensuring a more cohesive experience. For more details, refer to the API section.

packages/vite/README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# @dotenv-run/vite
2+
3+
- ✅ Load environment variables from the command line `API_BASE=/v1/ vite`
4+
- ✅ Load environment variables from `.env` files
5+
- ✅ Expand environment variables `API_URL=$API_BASE/users`
6+
- ✅ Define environment variables for a specific environment (e.g. `.env.production`)
7+
- ✅ Load priorities of `.env.*` files (e.g. `.env.production` > `.env`)
8+
- ✅ Hierarchical cascading configuration in monorepo projects ([Nx](https://nx.dev), [Turbo](https://turbo.build/), etc.)
9+
`apps/next-app/.env` > `apps/.env` > `.env`
10+
11+
## Install
12+
13+
```sh
14+
npm add @dotenv-run/vite --save-dev
15+
```
16+
17+
## Usage
18+
19+
Create a `vite.config.js` [configuration file](https://vite.dev/config) and import the plugin:
20+
21+
```js
22+
import env from "@dotenv-run/vite";
23+
24+
export default {
25+
envPrefix: 'MY_PREFIX_',
26+
envDir: './my-env-directory',
27+
plugins: [env()],
28+
};
29+
```
30+
31+
Then call `vite` or `vite build` either via the [CLI](https://vite.dev/guide/cli.html).
32+
33+
The available options are similar to those supported by [`@dotenv-run/core`](https://www.npmjs.com/package/@dotenv-run/core), but this plugin seamlessly integrates with Vite by automatically deriving the root, prefix, and environment values from its standard configuration, ensuring a more cohesive experience. For more details, refer to the API section.

packages/vite/package.json

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"name": "@dotenv-run/vite",
3+
"version": "1.0.0",
4+
"description": "Run your scripts with dotenv variables",
5+
"homepage": "https://github.com/chihab/dotenv-run",
6+
"main": "dist/index.js",
7+
"types": "dist/index.d.ts",
8+
"type": "module",
9+
"scripts": {
10+
"dev": "tsc -w",
11+
"build": "tsc"
12+
},
13+
"files": [
14+
"dist",
15+
"README.md"
16+
],
17+
"keywords": [
18+
"dotenv",
19+
"run",
20+
"cli",
21+
"vite",
22+
"vite-plugin"
23+
],
24+
"author": "Iacopo Ciao <[email protected]>",
25+
"license": "ISC",
26+
"dependencies": {
27+
"@dotenv-run/core": "workspace:^1.3.6",
28+
"@rollup/plugin-replace": "^5.0.7",
29+
"lodash-es": "^4.17.21",
30+
"vite": "^6.2.0"
31+
},
32+
"devDependencies": {
33+
"@types/lodash-es": "^4.17.12",
34+
"@types/node": "^16.18.112"
35+
}
36+
}

packages/vite/src/constants.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export const DEFAULT_PREFIX = 'VITE_';
2+
3+
export const DEFAULT_ENV_FILES = [
4+
/** vault file */ `.env.vault`,
5+
/** default file */ `.env`,
6+
];

packages/vite/src/index.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { env as loadEnv } from "@dotenv-run/core";
2+
import { Plugin } from "vite";
3+
import { viteEnvPrefixToPrefix } from "./mapper.js";
4+
import { sanitizeOptions, ViteDotenvRunOptions } from "./options.js";
5+
import replace from "@rollup/plugin-replace";
6+
import { DEFAULT_ENV_FILES } from "./constants.js";
7+
8+
/**
9+
* Vite plugin to load environment variables from .env files using `@dotenv-run/core`.
10+
*
11+
* This plugin seamlessly integrates with Vite by automatically deriving the root,
12+
* prefix and environment options from Vite's `envDir`, `envPrefix` and `mode`,
13+
* ensuring a more cohesive experience.
14+
*
15+
* @param {ViteDotenvRunOptions} [options] - Options for configuring the plugin.
16+
* See {@link ViteDotenvRunOptions} for more details.
17+
*
18+
* @returns {Plugin} Vite plugin object that enhances the Vite configuration.
19+
*
20+
* @example
21+
* // Usage in a Vite config file
22+
* import dotenvRun from 'vite-plugin-dotenv-run';
23+
*
24+
* export default {
25+
* envDir: '../..',
26+
* envPrefix: ['VITE_', 'CUSTOM_'],
27+
* plugins: [
28+
* dotenvRun(),
29+
* ],
30+
* };
31+
*/
32+
const dotenvRun = (options?: ViteDotenvRunOptions): Plugin => {
33+
options = sanitizeOptions(options);
34+
const files = options?.files ?? DEFAULT_ENV_FILES;
35+
36+
return {
37+
name: "vite-plugin-dotenv-run",
38+
config: (config, configEnv) => {
39+
const prefix = viteEnvPrefixToPrefix(config.envPrefix);
40+
41+
const { full } = loadEnv({
42+
files,
43+
prefix,
44+
root: config.envDir,
45+
environment: configEnv.mode,
46+
...options,
47+
});
48+
49+
return {
50+
...config,
51+
...replace({
52+
preventAssignment: true,
53+
values: full,
54+
}),
55+
};
56+
},
57+
};
58+
};
59+
60+
export { dotenvRun, ViteDotenvRunOptions };
61+
export default dotenvRun;

packages/vite/src/mapper.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import {
2+
castArray,
3+
escapeRegExp,
4+
first,
5+
isEmpty,
6+
isNil,
7+
negate,
8+
} from "lodash-es";
9+
import { DEFAULT_PREFIX } from "./constants.js";
10+
11+
/**
12+
* Converts a Vite `envPrefix` configuration value into a usable prefix or RegExp for @dotenv-run/core.
13+
*
14+
* @param {string | string[] | undefined} prefixes - The prefix or list of prefixes to filter environment variables.
15+
* @returns {string | RegExp} - A single prefix as a string if only one is provided, or a RegExp if multiple prefixes are given.
16+
*
17+
* @throws {Error} If an empty string (`''`) is included in the prefixes, as this could expose all environment variables.
18+
*
19+
* @example
20+
* viteEnvPrefixToPrefix("VITE_") // Returns: "VITE_"
21+
* viteEnvPrefixToPrefix(["VITE_", "CUSTOM_"]) // Returns: /^VITE_|CUSTOM_/
22+
* viteEnvPrefixToPrefix(undefined) // Returns: DEFAULT_PREFIX
23+
*
24+
* @see {@link https://vite.dev/config/shared-options.html#envprefix Vite Documentation on envPrefix}
25+
*
26+
* @security
27+
* The `envPrefix` option should **never** be set to an empty string (`''`),
28+
* as this will expose **all** environment variables, potentially leaking sensitive information.
29+
* Vite has a built-in safeguard that throws an error when detecting `''` as a prefix.
30+
*
31+
* If you need to expose an unprefixed environment variable, use the `define` option instead:
32+
*
33+
* ```
34+
* define: {
35+
* "process.env.MY_VAR": JSON.stringify(process.env.MY_VAR)
36+
* }
37+
* ```
38+
*/
39+
export const viteEnvPrefixToPrefix = (
40+
prefixes: string | string[] | undefined
41+
): string | RegExp => {
42+
prefixes = castArray(prefixes).filter(negate(isNil));
43+
44+
if (isEmpty(prefixes)) {
45+
return DEFAULT_PREFIX;
46+
}
47+
48+
if (prefixes.includes("")) {
49+
throw new Error(
50+
`envPrefix option contains value '', which could lead unexpected exposure of sensitive information.`
51+
);
52+
}
53+
54+
if (prefixes.length === 1) {
55+
return first(prefixes);
56+
}
57+
58+
return new RegExp(`^(${prefixes.map(escapeRegExp).join("|")})`);
59+
};

packages/vite/src/options.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import type { DotenvRunOptions } from "@dotenv-run/core";
2+
import { pick } from "lodash-es";
3+
4+
/**
5+
* Options for configuring the @dotenv-run/vite plugin.
6+
*
7+
* @interface ViteDotenvRunOptions
8+
* @extends {Pick<DotenvRunOptions, 'verbose' | 'unsecure' | 'builtIn' | 'global' | 'nodeEnv' | 'runtime' | 'dotenv' | 'files'>}
9+
*
10+
* @property {DotenvConfigOptions} [dotenv] - Options for configuring dotenv.
11+
* @property {string[]} [files] - Environment files to load. Defaults to `['.env.vault', '.env']`.
12+
* @property {boolean} [unsecure] - Display environment variables in debug output.
13+
* @property {boolean} [nodeEnv] - Node environment.
14+
* @property {boolean} [verbose] - Print verbose output.
15+
* @property {Dict} [builtIn] - Built-in environment variables.
16+
* @property {boolean} [runtime] - Whether to use runtime variables.
17+
* @property {string} [global] - Global variable name.
18+
*/
19+
export type ViteDotenvRunOptions = Pick<DotenvRunOptions, 'verbose' | 'unsecure' | 'builtIn' | 'global' | 'nodeEnv' | 'runtime' | 'dotenv' | 'files'>;
20+
21+
export const sanitizeOptions = <T extends ViteDotenvRunOptions>(options?: T): ViteDotenvRunOptions | undefined => {
22+
return pick(options, 'verbose', 'unsecure', 'builtIn', 'global', 'nodeEnv', 'runtime', 'dotenv', 'files');
23+
}

packages/vite/tsconfig.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"include": ["src"],
3+
"compilerOptions": {
4+
"outDir": "dist",
5+
"moduleResolution": "node",
6+
"module": "ES2022",
7+
"strict": true,
8+
"allowSyntheticDefaultImports": true,
9+
"forceConsistentCasingInFileNames": true,
10+
"strictPropertyInitialization": false,
11+
"strictNullChecks": false,
12+
"pretty": true,
13+
"sourceMap": true,
14+
"declaration": true,
15+
"skipLibCheck": true
16+
},
17+
"exclude": ["node_modules"],
18+
"compileOnSave": false,
19+
"buildOnSave": false
20+
}

0 commit comments

Comments
 (0)