webpack进阶篇(十七):静态资源内联

简介: webpack进阶篇(十七):静态资源内联

说明

玩转webpack课程学习笔记。



什么是资源内联


资源内联(inline resource),就是将一个资源以内联的方式嵌入进另一个资源里面.

1、HTML 内联 CSS (内联 CSS 或者 行内 CSS)

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



2、CSS 内联图片

通常将小图片通过 base64 的方式内嵌进 CSS 里面

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



资源内联的意义


1、代码层面


  • 页面框架的初始化脚本
  • 上报相关打点
  • css 内联避免页面闪动


2、请求层面

  • 减少 HTTP ⽹网络请求数
  • 小图片或者字体内联 (url-loader)



HTML 和 JS 内联

安装0.5.1的版本npm i raw-loader@0.5.1 -D

0.5.1 版本的 raw-loader 的代码

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


注意:需要使用 raw-loader 的 0.5.1 版本,最新的版本的 raw-loader 使用了导出模块的时候使用了 export default 语法, html 里面用的话有问题.

1、raw-loader 内联 html

<%= require('raw-loader!./meta.html') %>


2、raw-loader 内联 JS

<script><%= require('raw-loader!babel-loader!../node_modules/lib-flexible/flexible.js') %></script>


3、添加meta.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/">


4、修改search.html

<!DOCTYPE html>
<html lang="en">
<head>
    <%= require('raw-loader!./meta.html') %>
    <title>Document</title>
    <script><%= require('raw-loader!babel-loader!../node_modules/lib-flexible/flexible.js') %></script>
</head>
<body>
    <div id="root"></div>
</body>
</html>


4、结果

20200626181448747.PNG



HTML内联增强版

1、实现一个 loader 去解析 HTML 里面的?__inline 语法,inline-html-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)}`;
}



2、使用:

<!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"></div>
</body>
</html>


3、效果

image.png



CSS 内联

1、方案一:借助 style-loader

module.exports = {
  module: {
    rules: [
      {
        test: /\.scss$/,
        use: [
          {
            loader: 'style-loader',
            options: {
              insertAt: 'top', // 样式插入到<head>
              singleton: true, //将所有的style标签合并成一个
            }
          },
          "css-loader",
          "sass-loader"
        ],
      },
    ]
  },
};

2、方案二:html-inline-css-webpack-plugin

npm i html-inline-css-webpack-plugin -D


<link rel="stylesheet" /> => <style>...<style/>

注意html-inline-css-webpack-plugin 需要放在 html-webpack-plugin 后面。

const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const HtmlWebpackPlugin = require('html-webpack-plugin');
const HTMLInlineCSSWebpackPlugin = require("html-inline-css-webpack-plugin").default;
module.exports = {
  plugins: [
    new MiniCssExtractPlugin({
        filename: '[name]_[contenthash:8].css'
    }),
    new HtmlWebpackPlugin(),
    new HTMLInlineCSSWebpackPlugin()
  ]
}


3、效果

20200626181925667.PNG




CSS 内联的思路


1、style-loader 插入样式是一个动态的过程,查看打包后的 html 源码并不会看到 html 有 style 样式的。style-loader 是代码运行时动态的创建 style 标签,然后将 css style 插入到 style 标签里面去。


2、css-loader 的作用是将 css 转换成 commonjs 对象,也就是样式代码会被放到 js 里面去了。


3、对应的源码:https://github.com/webpack-contrib/style-loader/blob/master/src/runtime/injectStylesIntoStyleTag.js#L260


4、CSS 内联的思路是:


   将页面打包过程的产生的所有 CSS 提取成一个独立的文件,然后将这个 CSS 文件内联进 HTML head 里面。这里需要借助 mini-css-extract-plugin 和 html-inline-css-webpack-plugin 来实现 CSS 的内联功能。


   先将 css 提取打包成一个独立的 css 文件(使用MiniCssExtractPlugin.loader)

   然后读取提取出的 css 内容注入到页面的 style 里面去。这个过程在构建阶段完成。



图片、字体内联


1、图片和字体的内联可以借助 url-loader,通过修改 webpack 配置让小于 10k 的图片或者字体文件在构建阶段自动 base64。



2、增强版

   url-loader 做资源内联最大的缺陷就是:不能个性化的去设置某张图片自动编码。

借鉴下 FIS 的语法糖,实现 ?__inline 的语法糖,引用某个图片的时候看到这个后缀则自动的将这张图片进行 base64 编码


3、实现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')}`
    )}`;
  }
}



4、使用

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



代码查看




目录
相关文章
|
JavaScript 开发工具 git
webpack进阶篇(二十五):webpack打包组件和基础库
webpack进阶篇(二十五):webpack打包组件和基础库
451 0
webpack进阶篇(二十五):webpack打包组件和基础库
|
监控 JavaScript 前端开发
webpack进阶篇(十九):使⽤ source map
webpack进阶篇(十九):使⽤ source map
115 0
webpack进阶篇(十九):使⽤ source map
|
JavaScript
webpack进阶篇(二十九):构建异常和中断处理
webpack进阶篇(二十九):构建异常和中断处理
181 0
webpack进阶篇(二十九):构建异常和中断处理
|
开发者
webpack进阶篇(二十八):优化构建时命令行的显示日志
webpack进阶篇(二十八):优化构建时命令行的显示日志
408 0
webpack进阶篇(二十八):优化构建时命令行的显示日志
|
前端开发 JavaScript
webpack进阶篇(二十七):webpack实现SSR打包(下)
webpack进阶篇(二十七):webpack实现SSR打包(下)
162 0
webpack进阶篇(二十七):webpack实现SSR打包(下)
|
存储 前端开发 JavaScript
webpack进阶篇(二十六):webpack实现SSR打包(上)
webpack进阶篇(二十六):webpack实现SSR打包(上)
259 0
webpack进阶篇(二十六):webpack实现SSR打包(上)
|
JSON JavaScript 前端开发
webpack进阶篇(二十四):在webpack中使用ESLint
webpack进阶篇(二十四):在webpack中使用ESLint
115 0
webpack进阶篇(二十四):在webpack中使用ESLint
|
JavaScript
webpack进阶篇(二十三):代码分割和动态import
webpack进阶篇(二十三):代码分割和动态import
216 0
webpack进阶篇(二十三):代码分割和动态import
webpack进阶篇(二十二):Scope Hoisting使用和原理分析
webpack进阶篇(二十二):Scope Hoisting使用和原理分析
62 0
webpack进阶篇(二十二):Scope Hoisting使用和原理分析
webpack进阶篇(二十一):Tree Shaking的使用和原理分析
webpack进阶篇(二十一):Tree Shaking的使用和原理分析
179 0
webpack进阶篇(二十一):Tree Shaking的使用和原理分析