Как реализовать встраивание ресурсов в webpack4?

Webpack

Webpack4 внутри встроенных ресурсов в рамках этой статьи представит систему (HTML/CSS/JS/Image/Font) правильной осанки.

Во-первых, давайте разберемся, что такое встраивание ресурсов.

Что такое встраивание ресурсов?

HTML встроенный CSS, на самом деле это то, что мы обычно называем встроенным CSS или встроенным CSS. Мы можем написать несколько строк CSS для сброса, а затем передатьstyleтеги встроены в HTML:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        body {
            font-size: 12px;
            font-family: Arial, Helvetica, sans-serif;
            background: #fff;
        }
        ul, ol, li {
            list-style-type: none;
        }
    </style>
</head>
<body>
    
</body>
</html>

Инлайн-изображения CSS, то есть мы обычно встраиваем небольшие изображения в CSS через base64. Мы можем встроить значок поиска в CSS:

// index.css
.search {
  background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABJ0lEQVQ4T6XSsUoEMRAG4H/ClZaLmbSW1pZ6+gAnFrK+gZXoK6jvIILgE6gIcnYWgmJno6AgYp1Z2EcIGQnsHbuaQ9abMkO+TGaGMGfQnPfxC3DOrajqPoB1AArgnohOvffPucc6ADMfAjgCUMYYH9MFY8wagEsAxyKScp2YAtbaERGNRST7LWZWVd2squq2LbSBMyK6E5GrXKnW2i1jzMh7v5sFmPkzhDCs69rngKIo3GAweBKRpVnAVwhh9Q/gRUQWs4Bz7jzGeFNV1ThXATOXAA5EJDV1Gr2aSETb3vvrLJAOmTmNKY2yVNUHVSVjzBDABYA3ADsi8j4TSIlmkfYAbABYUNUPACdE9NpAHaTXKjPz8k+kF9B8s4P0BibIpBf/AtpN/AYx54AR58WxmQAAAABJRU5ErkJggg==) no-repeat;
}

После понимания основных концепций встраивания ресурсов вы можете спросить, в чем смысл встраивания ресурсов? Далее давайте посмотрим, зачем нам нужно встраивание ресурсов из нескольких измерений.

Значение встраивания ресурсов

Здесь я объясню значение встраивания ресурсов с трех аспектов: обслуживание проекта, производительность загрузки страниц и опыт загрузки страниц.

Инженерное обслуживание

Давайте посмотрим на важность встраивания ресурсов для обслуживания проекта Это базовая структура HTML. В современной популярной гибридной гибридной архитектуре разработки будут страницы H5 одна за другой, соответствующие многостраничному приложению (MPA) во внешнем проекте.

HTML Structure

Когда мы будем упаковывать многостраничные приложения, мы будем использовать html-webpack-plugin, и каждая страница будет иметь соответствующий ей HTML-шаблон. Каждый HTML-шаблон будет содержать много похожего контента, такого как метаинформация или некоторые заполнители, которые необходимо использовать в SSR и т. д. Просто подумайте о влиянии на обслуживание кода, если вы скопируете следующий метакод и поместите его в каждый HTML-шаблон.

<meta charset="UTF-8">
<meta name="viewport" content="viewport-fit=cover,width=device-width,initial-scale=1,user-scalable=no">
<meta name="format-detection" content="telephone=no">
<meta name="keywords" content="now,now直播,直播,腾讯直播,QQ直播,美女直播,附近直播,才艺直播,小视频,个人直播,美女视频,在线直播,手机直播">
<meta name="name" itemprop="name" content="NOW直播—腾讯旗下全民视频社交直播平台"><meta name="description" itemprop="description" content="NOW直播,腾讯旗下全民高清视频直播平台,汇集中外大咖,最in网红,草根偶像,明星艺人,校花,小鲜肉,逗逼段子手,各类美食、音乐、旅游、时尚、健身达人与你24小时不间断互动直播,各种奇葩刺激的直播玩法,让你跃跃欲试,你会发现,原来人人都可以当主播赚钱!">
<meta name="image" itemprop="image" content="https://pub.idqqimg.com/pc/misc/files/20170831/60b60446e34b40b98fa26afcc62a5f74.jpg"><meta name="baidu-site-verification" content="G4ovcyX25V">
<meta name="apple-mobile-web-app-capable" content="no">
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
<link rel="dns-prefetch" href="//11.url.cn/">
<link rel="dns-prefetch" href="//open.mobile.qq.com/">

В настоящее время рекомендуется поддерживать файл meta.html и помещать в него вышеприведенный код. В каждый HTML-шаблон встроен фрагмент meta.html.

Другим распространенным сценарием обслуживания проекта является встраивание изображений, шрифтов и др. Например, многие студенты обычно заходят в Интернет, чтобы найти онлайн-инструмент для кодирования base64 (такой как:www.base64code.com/) для кодирования различных картинок (png, jpg, gif) или шрифтов (ttf, otf), а затем поместить закодированную длинную строку в код. Например, в предыдущем значке поиска эта длинная строка вообще не имеет семантики при размещении в исходном коде, и это тоже катастрофа для сопровождающего.

// index.css
.search {
  background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABJ0lEQVQ4T6XSsUoEMRAG4H/ClZaLmbSW1pZ6+gAnFrK+gZXoK6jvIILgE6gIcnYWgmJno6AgYp1Z2EcIGQnsHbuaQ9abMkO+TGaGMGfQnPfxC3DOrajqPoB1AArgnohOvffPucc6ADMfAjgCUMYYH9MFY8wagEsAxyKScp2YAtbaERGNRST7LWZWVd2squq2LbSBMyK6E5GrXKnW2i1jzMh7v5sFmPkzhDCs69rngKIo3GAweBKRpVnAVwhh9Q/gRUQWs4Bz7jzGeFNV1ThXATOXAA5EJDV1Gr2aSETb3vvrLJAOmTmNKY2yVNUHVSVjzBDABYA3ADsi8j4TSIlmkfYAbABYUNUPACdE9NpAHaTXKjPz8k+kF9B8s4P0BibIpBf/AtpN/AYx54AR58WxmQAAAABJRU5ErkJggg==) no-repeat;
}

Мы можем избежать этой проблемы с помощью более элегантного синтаксиса встраивания ресурсов, который будет рассмотрен позже в этой статье.

скорость загрузки страницы

Второй момент встраивания ресурсов заключается в том, что он может уменьшить количество HTTP-запросов.Конечно, если ваш сайт использует HTTP2, это может быть не так существенно. Вставка в код различных мелких картинок и мелких шрифтов (например: менее 5k) в производственной среде может значительно сократить количество запросов страниц, тем самым улучшив время загрузки страниц.

опыт загрузки страницы

Еще одним важным значением встраивания ресурсов является улучшение процесса загрузки страницы. Все мы знаем, что браузеры анализируют исходный код HTML сверху вниз, поэтому мы поместим CSS в начало, а JS — в конец. Возьмем в качестве примера сценарий SSR, если вы не встраиваете упакованный CSS в HTML, структура страницы уже существует, когда HTML выходит, но вам все равно нужно отправить запрос на запрос CSS. , страница будет мерцать и появится ситуация с сетью.Это более очевидно, когда она плохая.

Тип встраивания ресурсов

  • Изображения, шрифты, встроенные

Если вы использовали FIS или читали документацию FIS, вы обнаружите, что FIS очень хорошо поддерживает встраивание ресурсов.Подробная документация:Встроить ресурсы

FIS HTML Фрагмент встроенного HTML:

 <link rel="import" href="demo.html?__inline">

FIS HTML Inline JS Script:

  <script type="text/javascript" src="demo.js?__inline"></script>

Далее давайте посмотрим на реализацию каждого встроенного в WebPack4 в отдельности.

Встроенный HTML

Базовая версия

HTML Встроенные HTML-фрагменты, CSS или JS (компилированные babel, такие как встроенный компонент npm) Идея очень проста, то есть непосредственно читать содержимое файла, а затем вставлять его в соответствующую позицию. Мы можем использовать версию raw-loader@0.5.1, у последнего raw-загрузчика будут проблемы (потому что он использует экспорт по умолчанию при экспорте модулей), но вы можете реализовать такой raw-загрузчик самостоятельно.

Код для версии 0.5.1 raw-loader:

module.exports = function(content) {
	this.cacheable && this.cacheable();
	this.value = content;
	return "module.exports = " + JSON.stringify(content);
}

Встроенный синтаксис, реализованный с помощью raw-loader, выглядит следующим образом:

// 内联 HTML 片段
${ require('raw-loader!./meta.html')}

// 内联 JS
<script>${ require('raw-loader!babel-loader!../../node_modules/lib-flexible/flexible.js')}</script>

Расширенное издание

Мы можем реализовать более удобный для разработчиков синтаксический сахар, например реализовать загрузчик для разбора синтаксиса ?__inline в HTML. Здесь я реализовалhtml-inline-loaderЕго код выглядит следующим образом:

const fs = require('fs');
const path = require('path');

const getContent = (matched, reg, resourcePath) => {
    const result = matched.match(reg);
    const relativePath = result && result[1];
    const absolutePath = path.join(path.dirname(resourcePath), relativePath);
    return fs.readFileSync(absolutePath, 'utf-8');
};

module.exports = function(content) {
  const htmlReg = /<link.*?href=".*?\__inline">/gmi;
  const jsReg = /<script.*?src=".*?\?__inline".*?>.*?<\/script>/gmi;

  content = content.replace(jsReg, (matched) => {
    const jsContent = getContent(matched, /src="(.*)\?__inline/, this.resourcePath);
    return `<script type="text/javascript">${jsContent}</script>`;
  }).replace(htmlReg, (matched) => {
    const htmlContent = getContent(matched, /href="(.*)\?__inline/, this.resourcePath);
    return htmlContent;
  });

  return `module.exports = ${JSON.stringify(content)}`;
}

Затем вы можете использовать так:

<!DOCTYPE html>
<html lang="en">
<head>
    <link href="./meta.html?__inline">
    <title>Document</title>
    <script type="text/javascript" src="../../node_modules/lib-flexible/flexible.js?__inline"></script>
</head>
<body>
    <div id="root"><!--HTML_PLACEHOLDER--></div>
    <!--INITIAL_DATA_PLACEHOLDER-->
</body>
</html>

Посмотреть Результаты:

Обычно для лучшей загрузки мы встраиваем упакованный CSS в заголовок HTML, чтобы CSS мог отображаться сразу после загрузки HTML, чтобы избежать мерцания страницы. Так как же работает встраивание CSS?

Основная идея заключается в встроенном CSS: CSS будет производить процесс упаковки, извлекая страницу как отдельный файл и связывая ее с заголовком HTML внутри файла CSS. Это должно быть реализовано с помощью встроенной функции CSS mini-css-extract-plugin и html-inline-css-webpack-plugin.

// webpack.config.js

const path = require('path');

module.exports = {
    entry: {
        index: './src/index.js',
        search: './src/search.js'
    },
    output: {
        path: path.join(__dirname, 'dist'),
        filename: '[name]_[chunkhash:8].js'
    },
    mode: 'production',
    plugins: [
        new MiniCssExtractPlugin({
            filename: '[name]_[contenthash:8].css'
        }),
        new HtmlWebpackPlugin(),
        new HTMLInlineCSSWebpackPlugin()
    ]
};

Примечание: html-inline-css-webpack-plugin необходимо разместить после html-webpack-plugin.

Изображение, встроенный шрифт

Базовая версия

Встраивание изображений и шрифтов можно сделать с помощьюurl-loaderНапример, вы можете сделать изображения или файлы шрифтов меньше 10 КБ автоматически base64 на этапе сборки, изменив конфигурацию веб-пакета.

// webpack.config.js

const path = require('path');

module.exports = {
    entry: {
        index: './src/index.js',
        search: './src/search.js'
    },
    output: {
        path: path.join(__dirname, 'dist'),
        filename: '[name]_[chunkhash:8].js'
    },
    mode: 'production',
    module: {
        rules: [
            {
                test: /.(png|jpg|gif|jpeg)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            name: '[name]_[hash:8].[ext]',
                            limit: 10240
                        }
                    }
                ]
            },
            {
                test: /.(woff|woff2|eot|ttf|otf)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            name: '[name]_[hash:8][ext]',
                            limit: 10240
                        }
                    }
                ]
            }
        ]
    }
};

Расширенное издание

Однако самым большим недостатком url-loader при встраивании ресурсов является то, что его нельзя настроить для установки автоматического кодирования определенного изображения.Для решения этой проблемы мы можем узнать из синтаксического сахара FIS, чтобы реализовать синтаксический сахар ?__inline, при ссылке на изображение Когда вы видите этот суффикс, изображение автоматически кодируется base64. Эта функция также очень проста в реализации, вы можете обратиться к моей реализацииinline-file-loader, основной код:

export default function loader(content) {
  const options = loaderUtils.getOptions(this) || {};

  validateOptions(schema, options, {
    name: 'File Loader',
    baseDataPath: 'options',
  });

  const hasInlineFlag = /\?__inline$/.test(this.resource);

  if (hasInlineFlag) {
    const file = this.resourcePath;
    // Get MIME type
    const mimetype = options.mimetype || mime.getType(file);

    if (typeof content === 'string') {
      content = Buffer.from(content);
    }

    return `module.exports = ${JSON.stringify(
      `data:${mimetype || ''};base64,${content.toString('base64')}`
    )}`;
  }

С помощью встроенной функции изображения мы можем изменить предыдущую встроенную запись значка значка поиска на:

// index.css
.search {
  background: url(./search-icon.png?__inline) no-repeat;
}

наконец

Вот код презентации этой статьи, если есть спрос, то можно получить самостоятельно.


Мой личный блог:GitHub.com/CPS Elvis/ был бы…