Vue.js вставляет стили в <body>вместо <head>файла index.html (webpack, HtmlWebpackPlugin) - PullRequest
1 голос
/ 07 октября 2019

По сути, я хочу добиться этой 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 загружается и не зависит от каких-либо других ресурсов. На самом деле, я думаю, что этого хотят все, просто сказать ...

Но 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 Ответ

1 голос
/ 07 октября 2019

Решение

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

Примечания

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...