-
-
Notifications
You must be signed in to change notification settings - Fork 6.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Accessing env variables from index.html #3105
Comments
You should use ejs template variables to have something more stable: diff --git a/vite.config.ts b/vite.config.ts
index aaf065b..8cdf521 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -1,12 +1,12 @@
// @ts-ignore
import dotenv from 'dotenv';
-dotenv.config();
+const { parsed } = dotenv.config();
// https://vitejs.dev/config/
export default defineConfig({
- plugins: [reactRefresh(), injectHtml()],
+ plugins: [reactRefresh(), injectHtml({ injectData: parsed })],
})
diff --git a/index.html b/index.html
index 7e1616f..8c7fce7 100644
--- a/index.html
+++ b/index.html
@@ -4,7 +4,7 @@
<title>Vite App</title>
</head>
<body>
- <% if (process.env.VITE_SHOW_TAG === '1') { %>
+ <%if (VITE_SHOW_TAG === '1') { %>
works
<% } %>
<script type="module" src="/src/index.tsx"></script> (though I'd probably pass in required variables explicitly) |
@netchampfaris makes sense, thank you! But should Vite be more definite in this case and have same behavior for dev\prod while working with index.html? |
Maybe @patak-js can weigh in. The define plugin doesn't handle this case during dev: And the import analysis plugin, which does, is always executed after the plugins: https://github.com/vitejs/vite/blob/5fe9a69/packages/vite/src/node/plugins/index.ts#L66 So the plugins do not see the rewritten env. Is this something we want to enable? |
I think it makes sense for Just for reference, looks like there are plugins available also https://github.com/lxs24sxl/vite-plugin-html-env |
https://github.com/IndexXuan/vite-plugin-html-template |
But what about a more regular case, if I just simply need to access env variable. For example Snowpack and CRA support this: |
@zardoy use transform html hook or plugin above. |
In Vue CLI this was something native, and it's kind of weird anyway for it to work on build and not on dev. <script src="https://www.paypal.com/sdk/js?client-id=<%= import.meta.env.VITE_SOME_KEY %>&disable-funding=credit,card,venmo,sepa,bancontact,eps,giropay,ideal,mybank,p24,sofort"></script> That's actually my use-case. I don't think using an external plugin for that is a good solution knowing it works in build mode. |
yes we need this feature |
If you have multiple modes something like this lets you reuse Vite's env parsing: import {defineConfig, loadEnv} from "vite";
import tsconfigPaths from "vite-tsconfig-paths";
import reactRefresh from "@vitejs/plugin-react-refresh";
import {injectHtml} from "vite-plugin-html";
export default defineConfig(({mode}) => {
const env = loadEnv(mode, "env"); // reuse vite's env parser to inject into our index.html
console.log(`Using env mode ${mode}`, env);
return {
plugins: [reactRefresh(), tsconfigPaths(), injectHtml({injectData: {...env, MODE: mode}})],
envDir: "env",
server: {port: 3001},
};
}); This enables me to use |
There seem to be some shortcomings of the EJS/HTML injection technique. From what I can tell it doesn't like including double quotes
I've attempted to use the unescaped EJS tag as using the escaped HTML tag will result in a non-desirable output. |
@nightah You should probably post the EJS tags you're using in your template and how you inject data. I've noticed similar problems, maybe our two use-cases can provide some solid background for this issue. |
@idleberg a completely reproducible case can be found here with the following relevant portions:
It's worthwhile noting that during the dev mode with
Which mirrors the configuration: https://github.com/authelia/authelia/blob/82f1847e75b9fbb1c26527fb38ec1b787b582a7d/web/.env.development#L2-L5 If I instead try to perform a production build here's the output I see from the HTML:
This is similar to the configuration here however with the small key difference that it's consuming the quotes surrounding the EJS tags. I've also tested to confirm that the issue isn't specifically relating to the values being rendered in the EJS tags, if I copy the value from I thought perhaps I could get around this issue by including explicit double quotes |
Okay so I've got to the bottom of this, the consumption of the quotes isn't a Vite issue, it's a problem that manifests from If I don't use that plugin Vite's output of the For clarity here's an output <!doctype html><html lang=en><head><base href={{.BaseURL}}><meta property=csp-nonce content={{.CSPNonce}} /><meta charset=utf-8 /><meta name=viewport content="width=device-width,initial-scale=1"/><meta name=theme-color content=#000000 /><meta name=description content="Authelia login portal for your apps"/><link rel=manifest href=./manifest.json /><link rel=icon href=./favicon.ico /><title>Login - Authelia</title><script type=module crossorigin src=./static/js/index.829172be.js></script><link rel=modulepreload href=./static/js/vendor.d0bc79df.js><link rel=stylesheet href=./static/css/index.393eb37d.css></head><body data-basepath={{.Base}} data-rememberme={{.RememberMe}} data-resetpassword={{.ResetPassword}} data-theme={{.Theme}}><noscript>You need to enable JavaScript to run this app.</noscript><div id=root></div></body></html> You'll notice in the above extract that almost all sets of double quotes Output with Vite and the <!DOCTYPE html>
<html lang="en">
<head>
<base href="{{.BaseURL}}">
<meta property="csp-nonce" content="{{.CSPNonce}}" />
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta name="description" content="Authelia login portal for your apps" />
<link rel="manifest" href="./manifest.json" />
<link rel="icon" href="./favicon.ico" />
<title>Login - Authelia</title>
<script type="module" crossorigin src="./static/js/index.dd4afd07.js"></script>
<link rel="modulepreload" href="./static/js/vendor.88e06a7b.js">
<link rel="stylesheet" href="./static/css/index.6d03b4c9.css">
</head>
<body data-basepath="{{.Base}}" data-rememberme="{{.RememberMe}}" data-resetpassword="{{.ResetPassword}}" data-theme="{{.Theme}}">
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html> For those that are looking at a solution similar to CRA or others where you can just template import {defineConfig, loadEnv} from "vite";
import tsconfigPaths from "vite-tsconfig-paths";
import reactRefresh from "@vitejs/plugin-react-refresh";
export default defineConfig(({mode}) => {
const env = loadEnv(mode, "env");
const htmlPlugin = () => {
return {
name: "html-transform",
transformIndexHtml(html: string) {
return html.replace(/%(.*?)%/g, function (match, p1) {
return env[p1];
});
},
};
};
return {
plugins: [htmlPlugin(), reactRefresh(), tsconfigPaths()],
};
}); Just remember that only variables that are prefixed with @idleberg feel free to give this a try and let me know if it resolves your problem. |
I don't know if this is related but I give it a try. I'm trying to use a environment variable in my index.html by passing it like this: <script async src="https://www.googletagmanager.com/gtag/js?id=import.meta.env.VITE_ANALYTICS_ID"></script> but this gives bad html output because vite adds double quotes around the interpolated value so that my html end up looking like: <script async src="https://www.googletagmanager.com/gtag/js?id="G-XXXXXX""></script> Is there any way to disable Vite adding double quotes around these injected variables? |
Vite doesn't do that. Check you |
Solution mentioned in #3105 (comment) worked great
Invoking plugin before Vite core plugins with This is probably a side-effect of #6199 which makes html plugin use [decodeURI] for assets: Workaround: use |
Update: using // vite.config.ts
import { defineConfig, loadEnv } from 'vite'
export default defineConfig(({ mode }) => ({
plugins: [
htmlPlugin(loadEnv(mode, '.')),
]
}))
/**
* Replace env variables in index.html
* @see https://github.com/vitejs/vite/issues/3105#issuecomment-939703781
* @see https://vitejs.dev/guide/api-plugin.html#transformindexhtml
*/
function htmlPlugin(env: ReturnType<typeof loadEnv>) {
return {
name: 'html-transform',
transformIndexHtml: {
enforce: 'pre' as const,
transform: (html: string): string =>
html.replace(/%(.*?)%/g, (match, p1) =>
env[p1] ?? match
),
}
}
} |
I haven't seen any issues upgrading to v2.7.5 or v2.7.6 for that matter with the aforementioned method. |
I installed import { ViteEjsPlugin } from 'vite-plugin-ejs';
export default defineConfig({
plugins: [ViteEjsPlugin]
}); Then I could use |
林某人已收到您的邮件了:)
|
This doesn't look like an issue with Vite, but rather the html plugin |
Finally, I got it working with this commit. |
the simpliest way |
I had to change the function to this: function htmlPlugin (env: ReturnType<typeof loadEnv>) {
return {
name: 'html-transform',
transformIndexHtml: {
enforce: 'pre' as const,
transform: (html: string) => {
return html.replace(/<%=(.*?)%>/g, (match, p1) => env[p1] ?? match)
},
},
}
} In order to also support things that output a full tag: <!DOCTYPE html>
<html lang="en">
<head>
<%=VITE_CONTENT_SECURITY_POLICY%>
</head> Edit: looks like this doesn't work in dev mode 😢 |
I'm using
Is this technically correct since it's working, or is there a better way to do this? |
I needed conditional logic right inside HTML to add vite.config.ts: import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { ViteEjsPlugin } from 'vite-plugin-ejs'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
ViteEjsPlugin((viteConfig) => ({
// viteConfig is the current Vite resolved config
env: viteConfig.env,
})),
vue(),
],
// ...
}) Then inside index.html: <% if (env.VITE_APP_ENV !== 'local') { %>
<script>console.log('production or development')</script>
<% } else { %>
<script>console.log('local')</script>
<% } %>
<% if (env.VITE_APP_ENV === 'production') { %>
<script src="https://widget.intercom.io/widget/<%= env.VITE_APP_INTERCOM_APP_ID %>"></script>
<% } %>
<body>
<% if (env.VITE_APP_ENV !== 'local' ) { %>
<!-- <Google Tag Manager (noscript)> -->
<noscript>
<iframe src="https://www.googletagmanager.com/ns.html?id=..."
height="0"
width="0"
style="display:none;visibility:hidden"
></iframe>
</noscript>
<!-- </Google Tag Manager (noscript)> -->
<% } %>
</body> |
P.S. <script vite-if="import.meta.env.VITE_APP_ENV === local">console.log('local')</script>
<script vite-else>console.log('production or development')</script> P.P.S. |
Thanks @johnsmithjsjs , your solution worked perfectly |
If you're already using vite.config.ts createHtmlPlugin({
// add environment variables to build
inject: { data: Object.assign({ mode }, process.env) },
}) This will allow you to use environment variables in <script>
console.log(<%- JSON.stringify(locals, null, 2) -%>)
</script> |
We discussed this feature with the team and decided the use case is typical enough to justify having built-in support in Vite core. We're considering providing interpolation of env variables only, and using the proposed syntax: |
Is this already released in version 4.1.4? |
@Birddle The PR is yet to be merged => #12202, so no. |
@patak-dev Thanks for adding support for this in vite@4.2 #12202 (comment) |
@lorand-horvath the shoutout goes to @bluwy for implementing it ❤️ |
Describe the bug
I try to insert html tag by environment variable condition and use
vite-plugin-html
for it. But Vite behaviour is weirdReproduction
https://github.com/xSorc/test-vite-index-env
This code works only in build
During server i have this error
This code works only in dev server
But during build this doesn't work, because Vite replace
process.env
with this:I suppose that first or second variant should works
System Info
Output of
npx envinfo --system --npmPackages vite,@vitejs/plugin-vue --binaries --browsers
:Used package manager:
Before submitting the issue, please make sure you do the following
The text was updated successfully, but these errors were encountered: