Skip to content

Commit 4c5784d

Browse files
committed
feat: expose env variables as root level in index.html template
1 parent 2dcdedd commit 4c5784d

File tree

4 files changed

+43
-10
lines changed

4 files changed

+43
-10
lines changed

docs/env.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,20 @@ In addition to `VUE_APP_*` variables, there are also two special variables that
5858
- `NODE_ENV` - this will be one of `"development"`, `"production"` or `"test"` depending on the [mode](#modes) the app is running in.
5959
- `BASE_URL` - this corresponds to the `baseUrl` option in `vue.config.js` and is the base path your app is deployed at.
6060

61+
### Env Variables in Index HTML
62+
63+
All resolved env variables will be available inside `public/index.html` via [lodash template interpolation](https://lodash.com/docs/4.17.5#template):
64+
65+
- `<%= VAR %>` for unescaped interpolation;
66+
- `<%- VAR %>` for HTML-escaped interpolationl;
67+
- `<% expression %>` for JavaScript control flows.
68+
69+
For example, to reference static assets copied from the root of `public`, you will need to use the `BASE_URL` variable:
70+
71+
``` html
72+
<link rel="shortcut icon" href="<%= BASE_URL %>favicon.ico">
73+
```
74+
6175
### Local Only Variables
6276

6377
Sometimes you might have env variables that should not be committed into the codebase, especially if your project is hosted in a public repository. In that case you should use an `.env.local` file instead. Local env files are ignored in `.gitignore` by default.

packages/@vue/cli-service/__tests__/build.spec.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ test('build', async () => {
3030
// should preload css
3131
expect(index).toMatch(/<link [^>]+app[^>]+\.css rel=preload>/)
3232

33+
// should reference favicon with correct base URL
34+
expect(index).toMatch(/<link rel=icon href=\/favicon.ico>/)
35+
3336
const port = await portfinder.getPortPromise()
3437
server = createServer({ root: path.join(project.dir, 'dist') })
3538

packages/@vue/cli-service/generator/template/public/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<meta charset="utf-8">
55
<meta http-equiv="X-UA-Compatible" content="IE=edge">
66
<meta name="viewport" content="width=device-width,initial-scale=1.0">
7-
<link rel="shortcut icon" href="<%%= webpackConfig.output.publicPath %%>favicon.ico">
7+
<link rel="icon" href="<%%= BASE_URL %%>favicon.ico">
88
<title><%= rootOptions.projectName %></title>
99
</head>
1010
<body>

packages/@vue/cli-service/lib/config/app.js

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,34 @@ module.exports = (api, options) => {
88
}
99

1010
// HTML plugin
11-
const fs = require('fs')
12-
const htmlPath = api.resolve('public/index.html')
1311
const resolveClientEnv = require('../util/resolveClientEnv')
12+
const htmlOptions = {
13+
templateParameters: (compilation, assets, pluginOptions) => {
14+
// enhance html-webpack-plugin's built in template params
15+
let stats
16+
return Object.assign({
17+
// make stats lazy as it is expensive
18+
get webpack () {
19+
return stats || (stats = compilation.getStats().toJson())
20+
},
21+
compilation: compilation,
22+
webpackConfig: compilation.options,
23+
htmlWebpackPlugin: {
24+
files: assets,
25+
options: pluginOptions
26+
}
27+
}, resolveClientEnv(options.baseUrl, true /* raw */))
28+
}
29+
}
30+
// only set template path if index.html exists
31+
const htmlPath = api.resolve('public/index.html')
32+
if (require('fs').existsSync(htmlPath)) {
33+
htmlOptions.template = htmlPath
34+
}
35+
1436
webpackConfig
1537
.plugin('html')
16-
.use(require('html-webpack-plugin'), [
17-
Object.assign(
18-
fs.existsSync(htmlPath) ? { template: htmlPath } : {},
19-
// expose client env to html template
20-
{ env: resolveClientEnv(options.baseUrl, true /* raw */) }
21-
)
22-
])
38+
.use(require('html-webpack-plugin'), [htmlOptions])
2339

2440
// inject preload/prefetch to HTML
2541
const PreloadPlugin = require('preload-webpack-plugin')

0 commit comments

Comments
 (0)