Vue.js在<body>中而不是在index.html(webpack,HtmlWebpackPlugin)的<head>中注入样式

时间:2019-10-07 04:50:17

标签: vue.js webpack html-webpack-plugin html-rendering loading-animation

基本上,我想实现以下index.html结构:

<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>

我想要这样做的原因是,我的html完全能够向用户显示初始加载的动画,并且我希望它在加载index.html后立即立即渲染,而不是取决于任何其他资源。 真的,我想这是每个人都想要的...

但是debault的Vue配置为将已编译的styles包含到<head>标记中,该标记会阻止页面的呈现,直到加载这些样式为止。我找不到任何有关如何更改它的文档。


更新:图片!

因此,我设法手动模拟了两种变体:

  1. 样式以<head>(默认)注入
  2. 样式注入<body>中(需要)

以下是视觉差异的图片:

1)样式以<head>注入(默认):

styles are injected in head

2)样式以<body>注入(需要):

styles are injected in body

图片上的标签“ html渲染开始”表示用户实际上能看到正在完全在html中定义的加载动画(在我的情况下为svg和样式的一小部分,在一般情况下可以是任何东西)并且不依赖任何其他外部资源来呈现它。

1 个答案:

答案 0 :(得分:1)

解决方案

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)
        ;
        // ...
    }
    // ...
};

注释