Reputation: 10999
Basically, I want achieve this index.html
structure:
<html>
<head>
<!-- titles, metas and other "static" stuff -->
<link rel="preload/prefetch" ...> <!-- injected by webpack (ok) -->
<!-- By default compiled styles are injected here, in head, I want them in body -->
</head>
<body>
<div>
My static loading animation
All possible styling is inlined
It doesn't depend on anything!
It also could be anything, even just a plain "Loading..." text.
You still WON'T see it until all style's in head are loaded.
</div>
<div id="app">Vue application goes here</div>
<link rel="stylesheet" href="..."> <!-- Styles injected by webpack (WANTED!) -->
<script src="..."></script> <!-- Scripts injected by webpack (by default, OK) -->
</body>
The reason I want this, is that my html is completely capable of displaying initial loading animation to the user and I want it to render instantly as soon as index.html
is loaded and not depend on any other resources. Really, I think this is everybody want, just to say...
But Vue by debault is configured to include it's compiled styles
to the <head>
tag, which blocks rendering of the page until these styles are loaded. I cannot find any docs of how I could change it.
So, I've managed to manually simulate two variants:
<head>
(default)<body>
(wanted)Here are the pictures of the visual difference:
<head>
(default):<body>
(wanted):The label "html rendering starts" on pictures means that a user actually sees loading animation, defined completely inside html (small piece of svg and styling in my case, could be anything in general case) and doesn't depend on any other external resources for it to render.
Upvotes: 3
Views: 1737
Reputation: 10999
vue.config.js
class InjectStylesInBody {
apply(compiler) {
compiler.hooks.compilation.tap('inject-styles-in-body', (compilation) => {
if (!compilation.hooks.htmlWebpackPluginAlterAssetTags) return;
compilation.hooks.htmlWebpackPluginAlterAssetTags.tap('inject-styles-in-body', function(pluginArgs) {
const { head, body } = pluginArgs;
head
.filter(asset => asset.tagName === 'link' && asset.attributes && asset.attributes.rel === 'stylesheet')
.forEach(asset => {
head.splice(head.indexOf(asset), 1);
body.push(asset);
});
});
});
}
}
module.exports = {
// ...
chainWebpack: config => {
// ...
config
.plugin('inject-styles-in-body')
.use(InjectStylesInBody)
;
// ...
}
// ...
};
Eventually, this has nothing to do with Vue.js. One could easily use this with other frameworks or with naked webpack.
It could be much easier if HtmlWebpackPlugin
had some inject-css
option for styles as it has for scripts.
See: https://github.com/jantimon/html-webpack-plugin/blob/e2c6990e94b298ff66bcd885c9a03a78221479f6/index.js#L548
Upvotes: 3