【万字详解】如何在微信小程序的 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.rhkb.cn/news/466040.html

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

相关文章

不愧是阿里巴巴最新开源的Java面试笔记,30万字精华总结 + 面试1300问附答案整理

前言 作为一个 Java 程序员&#xff0c;你平时总是陷在业务开发里&#xff0c;每天噼里啪啦忙敲着代码&#xff0c;上到系统开发&#xff0c;下到 Bug 修改&#xff0c;你感觉自己无所不能。然而偶尔的一次聚会&#xff0c;你听说和自己一起出道的同学早已经年薪 50 万&#x…

C6.【C++ Cont】cout的格式输出

目录 1.头文件 2.使用 1.控制宽度和填充 setw函数(全称set field width设置字段宽度) setfill函数(全称Set fill character设置填充字符) 2.控制数值格式 3.控制整数格式 4.控制对齐方式 1.头文件 用cout进行格式化输出前,先引用头文件iomanip(全称input&output m…

基于SSM+小程序的高校寻物平台管理系统(失物1)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1、项目介绍 本基于微信小程序的高校寻物平台有管理员&#xff0c;用户以及失主三个角色。 1、管理员功能有个人中心&#xff0c;用户管理&#xff0c;失主管理&#xff0c;寻物启示管理&#xff0c;拾…

视频——教学篇——拍摄和剪辑

文章目录 拍摄与录制。如何提升音质&#xff1f;如何提升画质&#xff1f;一、提升视频呈现的重点1.音质在很大程度上优先于画质2.在音质层面&#xff0c;环境可能比设备好坏更重要。3.提升视频画面方面&#xff0c;打光比买更好的相机更重要。4.画面的构图不如分镜的节奏来的重…

在线绘制带颜色标注的大脑脑区图

导读&#xff1a;大脑是人体最为复杂的器官之一&#xff0c;由多个功能特化的脑区构成。每个脑区承担着特定的生理和认知功能。通过应用定量数据映射技术&#xff0c;将数值以色彩编码的形式呈现于各个脑区&#xff0c;可以显著增强对不同脑区定量信息的视觉识别和理解。 《bio…

第十九周机器学习笔记:GAN的数学理论知识与实际应用的操作

第十九周周报 摘要Abstratc一、机器学习——GAN Basic Theory1. Maximum Likelihood Estimation2. 复习训练GAN的过程3. Objective function与JS散度相关性推导4. GAN的实际做法 总结 摘要 本周周报主要围绕生成对抗网络&#xff08;GAN&#xff09;的基础知识和理论进行深入探…

刷题小记11:栈队列

包括单调栈和优先队列 232. 用栈实现队列 用栈实现队列 两个栈 入队&#xff1a;向入队栈中加入元素 出队&#xff1a;从出队栈中出栈元素&#xff0c;如果出队栈为空&#xff0c;将入队栈所有元素入栈到出队栈。这样顺序就对了 225. 用队列实现栈 用队列实现栈 优化 …

【Qt问题】解决 Cannot retrieve debugging output

【Qt问题】解决 Cannot retrieve debugging output Chapter1 【Qt问题】解决 Cannot retrieve debugging output方案1 关闭其他Qt工程实例&#xff08;等于没说&#xff09;方案2 在PRO文件中&#xff0c;加上CONFIG console Chapter1 【Qt问题】解决 Cannot retrieve debuggi…

git 提交代码流程

1. 公-->私-->本-->私-->公 缺点&#xff1a;多了一个步骤&#xff0c;就多了一次申请时间&#xff0c;首先在公仓申请合并到私仓&#xff0c;私仓同意合并&#xff0c;获取到公仓最新版本&#xff1b; 优点&#xff1a;不容易污染公仓 2. 公-->本-->私--&…

Java 中的 transient 关键字:深入解析与实战

在 Java 编程中&#xff0c;transient 关键字是一个非常有用的工具&#xff0c;尤其是在处理对象序列化时。尽管 transient 关键字在日常开发中可能不常被使用&#xff0c;但了解它的作用和使用场景对于提升代码的安全性和性能至关重要。本文将深入探讨 transient 关键字的作用…

App渠道来源追踪方案全面分析(iOS/Android/鸿蒙)

一、App 渠道来源追踪概述 渠道来源统计/追踪&#xff0c;其原理都可以称之为归因&#xff0c;归因是用于判断用户在什么原因、什么时间、什么场景下载了 App&#xff0c;以及打通他们在激活 App 后进行的一系列操作&#xff08;比如注册、付费、加购等&#xff09;。 渠道来…

参数跟丢了之JS生成器和包装器

如需转载请注明出处.欢迎小伙伴一起讨论技术. 逆向网址:aHR0cHM6Ly91bmlvbi5qZC5jb20vcHJvTWFuYWdlci9pbmRleD9wYWdlTm89MQ 跟踪接口:aHR0cHM6Ly9hcGkubS5qZC5jb20vYXBp 跟踪参数:h5st 本文目标:记录学习下自定义的生成器和包装器,不做具体的参数加密逻辑分析 直接启动器进…

Redis集群——针对实习面试

目录 Redis集群Redis集群解决了什么问题&#xff1f;Redis集群是如何分片的&#xff1f;什么是Sentinel&#xff1f;Redis如何使用哨兵&#xff08;Sentinel&#xff09;系统&#xff1f;集群如何进行故障转移&#xff1f;Redis集群中的主从复制模型是怎样的&#xff1f;Redis集…

【种完麦子,我就往南走,去西双版纳,过个冬天!】

麦子奶奶&#xff1a;冰哥&#xff0c;你好。 大冰&#xff1a;你好&#xff0c;咱俩不定谁大呢。 麦子奶奶&#xff1a;嗯&#xff0c;我大&#xff0c;我60多了&#xff0c;你各方面都是哥。 大冰&#xff1a;阿姨好 麦子奶奶&#xff1a;我想出去看看祖国的大好河山&…

长亭那个检测能力超强的 WAF,出免费版啦

告诉你们一个震撼人心的消息&#xff0c;那个检测能力超强的 WAF——长亭雷池&#xff0c;他推出免费社区版啦&#xff0c;体验地址见文末。 八年前我刚从学校毕业&#xff0c;在腾讯做安全研究&#xff0c;看到宇森在 BlackHat 上演讲的议题 《永别了&#xff0c;SQL 注入》 …

Elasticsearch+kibana+filebeat的安装及使用

版本7.6.0 自己去官网下载或者私信找我要&#xff0c;jdk是8版本 1.ES安装 网上有好多安装教程可以自己去搜索 这个是我的es文件路径&#xff1a; { “name” : “node-1”, “cluster_name” : “elasticsearch”, “cluster_uuid” : “NIepktULRfepkje3JHw8NA”, “ve…

NVR小程序接入平台/设备EasyNVR多品牌NVR管理工具/设备汇聚公共资源场景方案全析

随着信息技术的飞速发展&#xff0c;视频监控已经成为现代社会安全管理和业务运营不可或缺的一部分。特别是在公共资源管理方面&#xff0c;视频监控的应用日益广泛&#xff0c;涵盖了智慧城市、智能交通、大型企业以及校园安防等多个领域。NVR小程序接入平台EasyNVR作为一款功…

ThingsBoard规则链节点:RPC Call Reply节点详解

引言 1. RPC Call Reply 节点简介 2. 节点配置 2.1 基本配置示例 3. 使用场景 3.1 设备控制 3.2 状态查询 3.3 命令执行 4. 实际项目中的应用 4.1 项目背景 4.2 项目需求 4.3 实现步骤 5. 总结 引言 ThingsBoard 是一个开源的物联网平台&#xff0c;提供了设备管理…

【论文复现】基于图卷积网络的轻量化推荐模型

本文所涉及所有资源均在这里可获取。 &#x1f4d5;作者简介&#xff1a;热爱跑步的恒川&#xff0c;致力于C/C、Java、Python等多编程语言&#xff0c;热爱跑步&#xff0c;喜爱音乐、摄影的一位博主。 &#x1f4d7;本文收录于论文复现系列&#xff0c;大家有兴趣的可以看一看…

sql数据库-DQL-基本查询

目录 举例表emp 查询多个字段 查询整张表所有数据 给字段名起别名&#xff08;更方便阅读&#xff09; 去除重复的数据 举例表emp 查询多个字段 SELECT 字段1,字段2,字段3...FROM 表名; 举例查询emp表中的name&#xff0c;workno&#xff0c;age字段返回 查询整张表所有数据 …