webpack 页面图片-webpack4中如何实现资源内联

2023-09-21 0 6,875 百度已收录

专题课程中没有对CSS内联进行演示。 明天我会系统介绍Webpack4上资源内联(HTML/CSS/JS/Image/Font)的正确姿势!

首先,我们来了解一下什么是资源内联。

什么是内联资源?

资源内联(inlineresource)就是将一个资源以内联的形式嵌入到另一个资源中。 我们通过几个小反例来直观地理解一下。

HTML内联CSS,这显然就是我们一般所说的内联CSS或者内联CSS。 我们可以写几行resetCSS,然后通过style标签嵌入到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内嵌图片是指我们通常将小图片以base64的形式嵌入到CSS中。 我们可以将搜索图标内联到 CSS 中:

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

了解了资源内联的基本概念后,你可能会问资源内联的意义是什么? 接下来我们从几个维度来看看为什么需要资源内联。

资源内联的含义

webpack 页面图片-webpack4中如何实现资源内联

这里我将从工程维护、页面加载性能、页面加载体验三个方面来阐述资源内联的意义。

工程维护

我们来看看资源内联对于项目维护的意义。 这是一个基本的 HTML 结构。 现在流行的Hybrid开发架构中,都会有一张一张的H5页面webpack 页面图片,对应后端项目中的多页面应用(MPA)。

当我们打包多页面应用时,我们会使用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编码工具(如:)来转换各种图片(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)Base64到代码中,可以大大减少页面请求次数,从而提高页面加载时间。

页面加载体验

资源内联的另一个重要意义是改善页面加载体验。 我们都知道浏览器是从上到下解析HTML源代码的,所以我们会把CSS放在后面,JS放在上面。 以SSR场景为例,如果打包的CSS没有内嵌到HTML中,那么下载HTML时页面的结构就已经有了webpack 页面图片,需要发送请求来请求CSS。 只有这样页面才会闪烁。 ,当网络状况较差时,这种现象更加明显。

资源内联类型

资源内联的类型主要包括:

如果您以前使用过FIS或者阅读过FIS文档,您会发现FIS对资源内联有极好的支持。 详细文档:嵌入资源

FISHTML 内联 HTML 片段:

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

FISHTML 内联 JS 脚本:

webpack 页面图片-webpack4中如何实现资源内联

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

接下来我们看一下webpack4中各类内联的实现。

HTML 内联基础知识

HTML内联HTML片段、CSS或者JS(Babel编译的,比如内联一个npm组件)的思路很简单,就是直接读取一个文件的内容,然后插入到对应的位置。 我们可以使用raw-loader@0.5.1版本。 最新的raw-loader会有问题(因为导入模块时使用的是exportdefault句型),但是你可以自己实现这样的raw-loader。

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-webpack-plugin提供的):

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

改良版

我们可以实现一个对开发者更加友好的句型糖,比如实现一个loader来解析HTML中的?__inline句型。 这里我实现了一个html-inline-loader,它的代码如下:

webpack 页面图片-webpack4中如何实现资源内联

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 = //gmi; const jsReg = /.*?/gmi;
content = content.replace(jsReg, (matched) => { const jsContent = getContent(matched, /src="(.*)?__inline/,%20this.resourcePath); return `${jsContent}`; }).replace(htmlReg, (matched) => { const htmlContent = getContent(matched, /href="(.*)?__inline/,%20this.resourcePath); return htmlContent; });
return `module.exports = ${JSON.stringify(content)}`;}

之后,您可以像这样使用它:

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

看看效果:

CSS 内联

一般情况下,为了更好的加载体验,我们会将打包好的CSS内联到HTML后面,这样HTML加载完之后就可以直接渲染CSS,防止页面闪烁。 如何实现CSS内联?

CSS内联的核心思想是将页面打包过程中形成的所有CSS提取到一个单独的文件中,然后将这个CSS文件内联到HTML头中。 这里需要使用mini-css-extract-plugin和html-inline-css-webpack-plugin来实现CSS的内联功能。

// 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。 例如,您可以在创建阶段将 webpack 配置更改为手动使用 Base64 图像或大于 10k 的字体文件。

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

利用images的内联功能,我们可以将上面搜索图标的内联写法改为:

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

终于

下面是本文的代码演示材料。 如果你需要的话,你可以自己去拿。

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

悟空资源网 webpack webpack 页面图片-webpack4中如何实现资源内联 https://www.wkzy.net/game/197623.html

常见问题

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务