What I want:
In my Vue project, when doing a vue run build
, everything is packed (webpack) into the dist
directory.
I could deploy this entire package to the test server, but since the test server needs another set of credentials (for database etc.), one file, namely config.js
, must be different on each environment.
My strategy:
config.js
from being packed into the app.12314...js bundleconfig.js
as being emitted unaltered as a file (via webpack's file-loader
)What I did:
In the Vue component files which need config data, config is included via:
<script>
import config from '@/config/config.js';
</script>
I created a vue.config.js
file for modifying the default webpack settings like this:
const path = require("path");
// vue.config.js
module.exports = {
publicPath: '/',
configureWebpack: {
module: {
rules: [
{
test: /config.*config\.js$/,
use: [
{
// exclude config file from being packed. The config file should simply reside as a plain file on the
// file system, since it must be replaced with the target environoment specific config file on the server,
// e.g. for setting the correct database connection
loader: 'file-loader',
options: {
name: 'config/config.js'
},
}
]
}
]
}
}
}
What I expected:
config.js
will be emitted as a plain file, not bundled => dist
folder will contain a bundled app....js
file and a separate config.js
filedist
folder to the test server and the generated code will take care of loading config.js
adequately, so that the components can use the config dataProblem:
Granted, config.js
is now emitted as a file, so my dist
folder looks like this:
.
├── config
│ └── config.js
├── css
│ ├── app.eb377513.css
│ └── chunk-vendors.2da46af1.css
├── favicon.png
├── index.html
└── js
├── app.724607ed.js
├── app.724607ed.js.map
├── chunk-vendors.426dad42.js
└── chunk-vendors.426dad42.js.map
As you can see, a separate file config.js
! All other JS code has been bundled into app.724607ed.js
. So far, so good.
However, the application on the test server would not load config.js
, so every component which tries to use the variables in it, fails.
I noticed that in Chrome's developer tools, there is no network traffic for config.js
. Apparently, the webpack code does not try to actually load the file from the file system. I expected this to be the case automatically.
Apparently, Webpack's file-loader
does emit the file separately (good), but does not add code for loading it in the webapp (bad). I assumed that file-loader
would take care of inserting the correct <script>
tag in the index.html
file, so that:
config.js
file will be loadedconfig.js
is the same as for the other (packed) artifacts, like this:(in the Vue component file:)
<script>
import backend from '@/utils/backend.js'; // <-- normal way of requiring modules in Vue component
import config from '@/config/config.js'; // <-- would work the same, but actually will load emitted file
</script>
Unfortunately, seems I was wrong. Since Webpack does not care about loading the file in the webapp, I switch to a manual way, like this:
Step 1: Emit as a separate file
This one is important, since I want the config.js
file to be separate (not packed and minified along with the rest of the Vue app). I already described how to do this in the question (define a separate rule for config.js
and use file-loader
for it).
Step 2: Take care yourself of loading the config file in the webapp
Since the file-loader
does not add loading code, make it manually. In index.html
, insert the following line:
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.png">
<script type="text/javascript" src="config/config.js" ></script> <-------- insert this line!
<title>replayer-gui4</title>
</head>
Step 3: change config.js
to be compatible with legacy importing method (without ES2015 module)
Now, the commonJS syntax is not viable anymore because config.js
should be loaded by the browser. And I am not sure how to mix ES2015 type module loading (with native import
syntax) with Webpack code (which would replace all import
's with Webpack loading code). So I decided to switch to a legacy method: let config.js
simply register a global (yuck!) variable like in old times:
var config = (() => {
return {
databaseCredentials: ...
};
})();
Consequently, in each Vue module consuming config settings, adapt the "import" code - simply remove the imports because the variable config
will be avalailable globally anyway (after our changes in config.js
in this step):
<script>
// import config from '@/config/config.js'; // <-- commented out - or just REMOVE this line
</script>
Step 4: Trigger Webpack to consider config.js
at all
The only caveat now is that since config.js
is never referenced in a Javascript file in an import
statement, Webpack would not "find" the file and would never take it into consideration. Which means that config.js
also never would get emitted.
So, force Webpack to handle it, in App.vue
:
<script>
import configDummy from '@/config/config.js';
</script>
Note that we never use the configDummy
reference (variable), this is just that Webpack finds it - and applies its rules to the file. The rule in this case would be: emit it as a separate file in the dist
folder (i.e. produce a dist/config/config.js
file)
That's it! We used Webpack's file-loader
so that config.js
is not minified and bundled into the application bundle, but kept as a separate file. Further we took care of loading it via index.html
which means the config settings are globally available.
What I do not like about this solution is that the nice methodology with import
methods is corrupted for this special file. But I found no simple solution which just would make Webpack take care of these things.
If somebody has a suggestion, I would be glad to hear!
Update 09.04.2019: No, this is NOT an ideal solution. This works for the packaging/deploying (the npm run build
part), but not for the development server (the npm run serve
part). In order for the dev server to work, I had to copy config.js
into the path public/config/config.js
, so that the dev server can find it at the place which index.html
is telling it, i.e. config/config.js
(this is resolved relative to the index.html
file).
So, again: it works, but sort of clumsy. And I do not like this solution.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With