【万字详解】如何在微信小程序的 Taro 框架中设置静态图片 assets/image 的 Base64 转换上限值

设置方法

mini 中提供了 imageUrlLoaderOptionpostcss.url

其中:
config.limitimageUrlLoaderOption.limit 服务于 Taro 的 MiniWebpackModule.js , 值的写法要 ()KB * 1024
config.maxSize 服务于 postcss-url 的 inline.js , 值的写法要 ()KB

关于为什么 limitmaxSize 的写法不同?
因为在源码层:
limit 在使用时是判断 limit2 * 1024 的值: maxSize: options.limit || 2 * 1024
maxSize 在使用时是判断 maxSize0 ,再乘以 1024const maxSize = (options.maxSize || 0) * 1024;
所以在配置时要注意区分。

const config = {// ...mini: {// ...imageUrlLoaderOption: {limit: num * 1024,},postcss: {// ...url: {enable: true / false,config: {limit: num * 1024,maxSize: num,},},// ...},},// ...
};// ...

Base64 转换上限值分以下 12 种情况去配置:

url config imageUrlLoaderOption 转成 Base64 的图片上限
url.enable 为 true config.limit 和 config.maxSize 都存在 没有 imageUrlLoaderOption.limit config.limit 和 maxSize的最大值
有 imageUrlLoaderOption.limit config.limit、imageUrlLoaderOption.limit 、 maxSize的最大值
config.maxSize 不存在, config.limit 存在 没有 imageUrlLoaderOption.limit 全部图片都被转成 Base64
有 imageUrlLoaderOption.limit 全部图片都被转成 Base64
config.limit 不存在, config.maxSize 存在 没有 imageUrlLoaderOption.limit 当 maxSize > 10 ,以 maxSize 为主;否则小于 10KB 的图片被转成 Base64
有 imageUrlLoaderOption.limit imageUrlLoaderOption.limit 和 maxSize的最大值
config.limit 和 config.maxSize 都不存在 没有 imageUrlLoaderOption.limit 全部图片都被转成 Base64
有 imageUrlLoaderOption.limit 全部图片都被转成 Base64
url.enable 为 false - 没有 imageUrlLoaderOption.limit 2KB
有 imageUrlLoaderOption.limit imageUrlLoaderOption.limit
不存在 url - 没有 imageUrlLoaderOption.limit 全部图片都被转成 Base64
有 imageUrlLoaderOption.limit 全部图片都被转成 Base64

最实用的配置:

不使用 postcss 插件,通过 Taro 提供的 imageUrlLoaderOption 来设置转换上限值

// ...
const config = {// ...mini: {// ...imageUrlLoaderOption: {limit: -1,},postcss: {// ...url: {enable: false,},// ...},},// ...
};
// ...

关于 limit

config.limitimageUrlLoaderOption.limit 的替换关系如图所示

limit 的对决

源码解析

Taro 部分

class MiniWebpackModule 是 Taro 框架中用于处理和封装 Webpack 构建模块的类。它负责配置、加载和编译与各类文件格式相关的模块,通常在 Taro 生成项目构建配置时发挥作用。它的目标是将开发者的源代码转换成适用于小程序、 H5 、 React Native 等平台的最终代码。

getModules

getModules 方法的核心作用是配置和返回不同类型模块的处理规则,包括对 Sass 、 Scss 、 Less 、 Stylus 等样式文件的处理,并将其与 CSS 、 PostCSS 等工具结合起来,最终生成适合各种小程序平台的构建规则。

parsePostCSSOptions() 解析 PostCSS 的配置选项,返回 postcssOptionpostcssUrlOptioncssModuleOption 等。

通过 getDefaultPostcssConfig 方法获取 PostCSS 的默认配置,返回给 this.__postcssOption 进行保存。

调用 getImageRule 方法对 image 进行配置,并将配置存入 rule 对象中。

getModules() {const { appPath, config, sourceRoot, fileType } = this.combination;const { buildAdapter, sassLoaderOption, lessLoaderOption, stylusLoaderOption, designWidth, deviceRatio } = config;const { postcssOption, postcssUrlOption, cssModuleOption } = this.parsePostCSSOptions();this.__postcssOption = (0, postcss_mini_1.getDefaultPostcssConfig)({designWidth,deviceRatio,postcssOption,alias: config.alias,});const rule = {image: this.getImageRule(postcssUrlOption)};return { rule };
}

parsePostCSSOptions

defaultUrlOption 确实默认启用 postcss-url,并设置 limit 为 10KB(10240 字节)。代码中 postcssOption.url 会通过 recursiveMerge 方法与 defaultUrlOption 合并,如果配置中提供了 postcss-url 的自定义配置,将会覆盖默认值。

postcssUrlOption 不会赋值,即 config/index.ts 中配置的 config 不会被使用或存储。

parsePostCSSOptions() {const { postcss: postcssOption = {} } = this.combination.config;const defaultUrlOption = {enable: true,config: {limit: 10 * 1024 // limit 10k base on document}};const urlOptions = (0, helper_1.recursiveMerge)({}, defaultUrlOption, postcssOption.url);let postcssUrlOption = {};if (urlOptions.enable) {postcssUrlOption = urlOptions.config;}return {postcssOption,postcssUrlOption};
}

getDefaultPostcssConfig

接收 postcssOption ,从中提取 url 配置,并通过 recursiveMerge 将其与 defaultUrlOption 合并为 urlOption 。如果 postcssOption.url 存在,就会用自定义配置来替代或合并默认配置。

const getDefaultPostcssConfig = function ({ postcssOption = {} }) {const { url } = postcssOption,options = __rest(postcssOption, ["url"]);const urlOption = (0, helper_1.recursiveMerge)({}, defaultUrlOption, url);return [["postcss-url", urlOption, require("postcss-url")],...Object.entries(options),];
};

getImageRule

当调用 getImageRule 时,postcssOptionsimageUrlLoaderOption 合并生成新的 options ,并传递给 WebpackModule.getImageRule()limit 的优先级以 imageUrlLoaderOption.limit 为主导。

getImageRule(postcssOptions) {const sourceRoot = this.combination.sourceRoot;const { imageUrlLoaderOption } = this.combination.config;const options = Object.assign({}, postcssOptions, imageUrlLoaderOption);return WebpackModule_1.WebpackModule.getImageRule(sourceRoot, options);
}

WebpackModule_1.WebpackModule.getImageRule

如果 postcss.url.config.limit 没有设置,系统应有逻辑保证 limit 的默认值为 2KB。

static getImageRule(sourceRoot, options) {return {test: helper_1.REG_IMAGE,type: 'asset',parser: {dataUrlCondition: {maxSize: options.limit || 2 * 1024 // 2kb}},generator: {emit: options.emitFile || options.emit,outputPath: options.outputPath,publicPath: options.publicPath,filename({ filename }) {if ((0, shared_1.isFunction)(options.name))return options.name(filename);return options.name || filename.replace(sourceRoot + '/', '');}}};
}

postcss-url 部分

plugin

options 是个对象,属性有 urllimitmaxSizeurl 默认值是 inline

enable 设为 falseoptions{} ;设为 trueoptions 为打印配置中所设的,可能有 urllimitmaxSize

styles.walkDecls((decl) =>{}); 遍历 CSS 文件中的每个声明(decl)。对每个声明,调用 declProcessor 函数,并将结果(是个 Promisepushpromises 数组中。返回的 Promise 通过 then 打印的结果,是一个数组,值为'url("OSS || Base64 || assets")'

const plugin = (options) => {options = options || {};return {postcssPlugin: "postcss-url",Once(styles, { result }) {const promises = [];const opts = result.opts;const from = opts.from ? path.dirname(opts.from) : ".";const to = opts.to ? path.dirname(opts.to) : from;styles.walkDecls((decl) =>promises.push(declProcessor(from, to, options, result, decl)));return Promise.all(promises);},};
};

declProcessor

获取 patten ,值存在 undefined/(url\(\s*['"]?)([^"')]+)(["']?\s*\))/g 还有其他。

如果 pattenundefined ,直接返回 Promise.resolve() 。这是为了在 pattern 不存在时直接短路,避免不必要的计算。

正常函数内部执行了 Promise.resolve() 后,后面的代码是可以继续执行的。

如果 patten 不是 undefined ,新建一个 promises 数组,用来存储所有异步操作的 Promisedecl.value.replace(pattern, (matched, before, url, after) => { ... }) 使用 replace 函数遍历和处理 decl.value 中的每个匹配项。 replace 函数的第二个函数是个回调函数,最终的返回值是 matched

在回调函数中执行 replaceUrl 函数,返回一个为 PromisenewUrlPromise ,然后调用 then 方法获取 newUrlPromise 的值。

如果 newUrlPromise 的值是 undefined ,直接返回 matched 。这种情况会发生在没有转换成 Base64 编码的本地图片路径上。

declProcessor 最终返回的是 Promise.all(promises) (是个 Promise )。

const declProcessor = (from, to, options, result, decl) => {const dir = { from, to, file: getDirDeclFile(decl) };const pattern = getPattern(decl);if (!pattern) return Promise.resolve();const promises = [];decl.value = decl.value.replace(pattern, (matched, before, url, after) => {const newUrlPromise = replaceUrl(url, dir, options, result, decl);promises.push(newUrlPromise.then((newUrl) => {if (!newUrl) return matched;if (WITH_QUOTES.test(newUrl) && WITH_QUOTES.test(after)) {before = before.slice(0, -1);after = after.slice(1);}decl.value = decl.value.replace(matched, `${before}${newUrl}${after}`);}));return matched;});return Promise.all(promises);
};

replaceUrl

asset 是一个对象,里面有 urloriginUrlpathnameabsolutePathrelativePathsearchhash

当传入的是 OSS 路径或者 data:font/woff;base64 时, matchedOptionsundefined ,直接返回 Promise.resolve()
当传入的是 asset/images 下的图片时, matchedOptionsoptions 的值。会判断 matchedOptions 是不是个数组。如果是数组,则对数组里面的值一一执行 process 函数;不是数组,直接执行 process 函数。

process 函数里的 getUrlProcessor 函数会根据 url 的值判断走哪种类型的编译方法。
process 函数里的 wrapUrlProcessor 函数实现了对 urlProcessor 的“增强”,使其在处理 URL 的过程中可以记录警告信息和依赖关系。

replaceUrl 最终返回一个 Promise ,在 resultPromise.then(...) 的链式调用中, return newUrl ; 实际上是将 newUrl 封装在一个新的 Promise 中作为最终返回值,并且 Promise 的解析值是 newUrl ,可以是经过编码的 URL 、文件路径或 undefined

const replaceUrl = (url, dir, options, result, decl) => {const asset = prepareAsset(url, dir, decl);const matchedOptions = matchOptions(asset, options);if (!matchedOptions) return Promise.resolve();const process = (option) => {const wrappedUrlProcessor = wrapUrlProcessor(getUrlProcessor(option.url),result,decl);return wrappedUrlProcessor(asset, dir, option);};let resultPromise = Promise.resolve();if (Array.isArray(matchedOptions)) {for (let i = 0; i < matchedOptions.length; i++) {resultPromise = resultPromise.then(() => process(matchedOptions[i])).then((newUrl) => {asset.url = newUrl;return newUrl;});}} else {resultPromise = process(matchedOptions);}return resultPromise.then((newUrl) => {asset.url = newUrl;return newUrl;});
};

getUrlProcessor

根据 url 的值判断走哪种 post-url 类型

function getUrlProcessor(optionUrl) {const mode = getUrlProcessorType(optionUrl);if (PROCESS_TYPES.indexOf(mode) === -1) {throw new Error(`Unknown mode for postcss-url: ${mode}`);}return require(`../type/${mode}`);
}

wrapUrlProcessor

wrapUrlProcessor 实现了对 urlProcessor 的“增强”,使其在处理 URL 的过程中可以记录警告信息和依赖关系。

const wrapUrlProcessor = (urlProcessor, result, decl) => {const warn = (message) => decl.warn(result, message);const addDependency = (file) =>result.messages.push({type: "dependency",file,parent: getPathDeclFile(decl),});return (asset, dir, option) =>urlProcessor(asset, dir, option, decl, warn, result, addDependency);
};

inline.js

根据 options 中的 maxSize 获取 maxSize ,所以配置表中传入的maxSize不需要乘 1024

如果 maxSize 不是 0 ,获取图片的 size 。如果图片的 size 大于 maxSize ,调用 processFallback ,按回退处理方式(如文件路径链接)返回;如果图片的 size 小于 maxSize ,调用 inlineProcess 编译成 Base64 。

module.exports = function (asset,dir,options,decl,warn,result,addDependency
) {return getFile(asset, options, dir, warn).then((file) => {if (!file) return;if (!file.mimeType) {warn(`Unable to find asset mime-type for ${file.path}`);return;}const maxSize = (options.maxSize || 0) * 1024;if (maxSize) {const size = Buffer.byteLength(file.contents);if (size >= maxSize) {return processFallback.apply(this, arguments);}}return inlineProcess(file, asset, warn, addDependency, options);});
};

processFallback

根据 options.fallback 的值进行调用,当前 options.fallbackundefined ,直接返回 Promise.resolve();

function processFallback(originUrl, dir, options) {if (typeof options.fallback === "function") {return options.fallback.apply(null, arguments);}switch (options.fallback) {case "copy":return processCopy.apply(null, arguments);case "rebase":return processRebase.apply(null, arguments);default:return Promise.resolve();}
}

inlineProcess

该方法实现了将文件进行 Base64 转换,如果是 SVG 文件,则使用 encodeURIComponent ,否则使用 base64 编码。

const inlineProcess = (file, asset, warn, addDependency, options) => {const isSvg = file.mimeType === "image/svg+xml";const defaultEncodeType = isSvg ? "encodeURIComponent" : "base64";const encodeType = options.encodeType || defaultEncodeType;// Warn for svg with hashes/fragmentsif (isSvg && asset.hash && !options.ignoreFragmentWarning) {// eslint-disable-next-line max-lenwarn(`Image type is svg and link contains #. Postcss-url cant handle svg fragments. SVG file fully inlined. ${file.path}`);}addDependency(file.path);const optimizeSvgEncode = isSvg && options.optimizeSvgEncode;const encodedStr = encodeFile(file, encodeType, optimizeSvgEncode);const resultValue =options.includeUriFragment && asset.hash? encodedStr + asset.hash: encodedStr;// wrap url by quotes if percent-encoded svgreturn isSvg && encodeType !== "base64" ? `"${resultValue}"` : resultValue;
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/58939.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【MatLab手记】 --从0到了解超超超详过程!!!

文章目录 MatLab笔记一、命令行窗口二、变量命名规则三、数据类型1. 数字2. 字符与字符串3. 矩阵3.1 矩阵创建3.2 矩阵的修改和删除3.3 矩阵的拼接与重构重排3.4 矩阵的运算方法3.5 矩阵的下标 4. 元胞数组&#xff08;类似数据容器&#xff09;5. 结构体 四、逻辑与流程控制五…

实现uniapp-微信小程序 搜索框+上拉加载+下拉刷新

pages.json 中的配置 { "path": "pages/message", "style": { "navigationBarTitleText": "消息", "enablePullDownRefresh": true, "onReachBottomDistance": 50 } }, <template><view class…

IDM扩展添加到Edge浏览器

IDM扩展添加到Edge浏览器 一般情况下&#xff0c;当安装IDM软件后&#xff0c;该软件将会自动将IDM Integration Module浏览器扩展安装到Edge浏览器上&#xff0c;但在某些情况下&#xff0c;需要我们手动安装&#xff0c;以下为手动安装步骤 手动安装IDM扩展到Edge浏览器 打…

AndroidStudio-常用布局

一、线性布局LinearLayout 线性布局内部的各视图有两种排列方式: 1.orientation属性值为horizontal时&#xff0c;内部视图在水平方向从左往右排列。 2.orientation属性值为vertical时&#xff0c;内部视图在垂直方向从上往下排列。 如果不指定orientation属性&#xff0c;…

Pr 入门系列之八:使用关键帧(上)

不论是固定效果、标准效果或是第三方效果&#xff0c;都可以通过改变属性的值来达到效果控制的目的。 任何动画要表现运动或变化&#xff0c;前后至少要给出属性值的两个不同的关键状态&#xff0c;称之为“关键帧” Keyframe。 而中间状态的变化和衔接&#xff0c;则是由计算机…

万字长文解读深度学习——循环神经网络RNN、LSTM、GRU、Bi-RNN

&#x1f33a;历史文章列表&#x1f33a; 深度学习——优化算法、激活函数、归一化、正则化深度学习——权重初始化、评估指标、梯度消失和梯度爆炸深度学习——前向传播与反向传播、神经网络&#xff08;前馈神经网络与反馈神经网络&#xff09;、常见算法概要汇总万字长文解读…

qt QMovie详解

1、概述 QMovie 是 Qt 框架中用于处理动画文件的类。它支持多种动画格式&#xff0c;包括 GIF 和一些常见的视频格式&#xff08;尽管对视频格式的支持依赖于底层平台&#xff09;。QMovie 类主要用于在 QLabel 或 QGraphicsView 等控件中显示动画。通过加载动画文件&#xff…

2.2 栈与队列

2.2 栈与队列 在我们日常生活中&#xff0c;一些排列和存储物品的方式可以很好地帮助我们理解栈和队列这两种数据结构。 栈&#xff08;Stack&#xff09; 栈是一种后进先出&#xff08;Last In First Out&#xff0c;简称LIFO&#xff09;的数据结构&#xff0c;就像我们堆…

ip addr show

本文内容来自智谱清言 ip addr show 是 Linux 系统中用于显示网络接口配置的命令。这个命令属于 iproute2 软件包&#xff0c;该软件包在大多数 Linux 发行版中都是预安装的。ip addr show 命令可以用来查看所有网络接口的当前配置&#xff0c;或者指定某个特定接口的配置。 …

【编程语言】理解C/C++当中的指针

指针是C/C语言中一个非常强大且重要的概念&#xff0c;也是编写高效程序的基础之一。对于没有编程背景的初学者来说&#xff0c;理解指针可能有些难度&#xff0c;但通过本篇文章的介绍&#xff0c;相信你会对指针有一个清晰的认识。本文将从指针的基本概念、作用、代码示例、注…

hive切换表底层文件类型以及分隔符

1、改底层文件存储类型&#xff0c;但是一般只会在数据文件与期望类型一致的时候使用&#xff0c;比如load等方式时发现建表时没指定对这样的&#xff0c;因为这个语句不会更改具体的底层文件内容&#xff0c;只改元数据 ALTER TABLE 表名 SET FILEFORMAT 希望类型;2、更改数据…

【ESP32】ESP-IDF开发 | 低功耗管理+RTC唤醒和按键唤醒例程

1. 简介 ESP32支持5种低功耗模式&#xff0c;低功耗管理单元包括调压器、功耗控制器、电源开关单元、电源域隔离单元 (Isolation Cell) 等部分。 1.1 RTC单元 RTC单元是ESP32低功耗管理的核心&#xff0c;可用于管理低功耗模式的进入和退出&#xff0c;控制时钟源、PLL、电源开…

vue链接跳转

在 Vue 3 的组合式 API 中&#xff0c;你可以使用 ref 和 setup 函数来实现外部链接跳转功能。 方法 1&#xff1a;使用 click 和 window.open&#xff08;新标签页跳转&#xff09; 这种方式在点击时会打开一个新标签页并跳转到外部链接。 <menu-item value"item2&…

重学 Android 自定义 View 系列(三):自定义步数进度条

前言 本篇文章主要是实现仿QQ步数View&#xff0c;很老的一个View了&#xff0c;但技术永不落后&#xff0c;开搂&#xff01; 最终效果如下&#xff1a; 1. 结构分析 QQStepView 主要由三个元素组成&#xff1a; 显示一个圆环进度条&#xff0c;通过外环和内环的角度变化来…

非关系型数据库NoSQL的类型与优缺点对比

NoSQL数据库根据数据模型和应用场景主要分为四种类型&#xff1a;键值型、列族型、文档型和图形型。以下是对每种类型的详细描述&#xff0c;包括其应用场景、优缺点的比较&#xff1a; 1. 键值型数据库 (Key-Value Store) 典型代表 RedisMemcachedAmazon DynamoDB 应用场景…

Spring中的过滤器和拦截器

Spring中的过滤器和拦截器 一、引言 在Spring框架中&#xff0c;过滤器&#xff08;Filter&#xff09;和拦截器&#xff08;Interceptor&#xff09;是实现请求处理的两种重要机制。它们都基于AOP&#xff08;面向切面编程&#xff09;思想&#xff0c;用于在请求的生命周期…

查缺补漏----用户上网过程(HTTP,DNS与ARP)

&#xff08;1&#xff09;HTTP 来自湖科大计算机网络微课堂&#xff1a; ① HTTP/1.0采用非持续连接方式。在该方式下&#xff0c;每次浏览器要请求一个文件都要与服务器建立TCP连接当收到响应后就立即关闭连接。 每请求一个文档就要有两倍的RTT的开销。若一个网页上有很多引…

core-js 解决浏览器兼容性问题的工具之一

core-js 是一个非常流行的JavaScript库&#xff0c;它提供了大量的 polyfills&#xff0c;使得开发者可以在旧版浏览器中使用新的JavaScript特性。core-js 实现了ECMAScript标准中的许多新特性&#xff0c;还包括一些Web APIs。这使得开发者可以编写现代JavaScript代码&#xf…

C++之vector类的模拟实现

片头 嗨~小伙伴们&#xff0c;今天我们来一起学习关于C的vector类的模拟实现&#xff0c;准备好了吗&#xff1f;咱们开始咯~ 一、基本框架 namespace bit {template<class T>class vector {public:typedef T* iterator;typedef const T* const_iterator;// 针对const修…

C# 中 LibraryImport 和 DllImport有什么不同

libraryimport 和 dllimport 是两个与动态链接库&#xff08;DLL&#xff09;相关的术语&#xff0c;它们在不同的编程语言和上下文中有不同的含义和用途。 在 C# 中&#xff0c;DllImportAttribute 是一个特性&#xff0c;用于指示一个方法声明是作为对非托管 DLL 中函数的 P…