当前位置: 首页 > news >正文

uniapp 多渠道打包实现方案

首先一个基础分包方案:
项目整体结构
build编译前相关问题
src资源文件和vue布局文件分包结构
包不用区分渠道,只是通过文件名进行区分,公共代码逻辑可以通过mixins进行混入。

这样分包后就需要在打包时只针对编译的渠道包文件进行替换打包,其他渠道包的文件不打包进去,通过工具类实现替换。

项目主目录下的manifest.json 和 pages.json 可以是空内容,都是通过工具类将prebuild目录下不同渠道不同平台的对应文件内容复制然后写到项目主目录下去的。

  1. 先看主要配置文件:
//package.json
{"name": "demo","config": {"dev": "cross-env NODE_ENV=development uniapp-cli custom","pro": "cross-env NODE_ENV=production uniapp-cli custom"},"version": "0.1.0","private": true,"scripts": {"dev:ks-brandA": "cross-env-shell $npm_package_config_dev bd-brandA --minimize","dev:tt-brandA": "cross-env-shell $npm_package_config_dev tt-brandA --minimize","dev:bd-brandA": "cross-env-shell $npm_package_config_dev ks-brandA --minimize","build:bd-brandA": "cross-env-shell $npm_package_config_pro bd-brandA --minimize","build:tt-brandA": "cross-env-shell $npm_package_config_pro tt-brandA --minimize","build:ks-brandA": "cross-env-shell $npm_package_config_pro ks-brandA --minimize","dev:ks-brandB": "cross-env-shell $npm_package_config_dev bd-brandB --minimize","dev:tt-brandB": "cross-env-shell $npm_package_config_dev tt-brandB --minimize","dev:bd-brandB": "cross-env-shell $npm_package_config_dev ks-brandB --minimize","build:bd-brandB": "cross-env-shell $npm_package_config_pro bd-brandB --minimize","build:tt-brandB": "cross-env-shell $npm_package_config_pro tt-brandB --minimize","build:ks-brandB": "cross-env-shell $npm_package_config_pro ks-brandB --minimize",},"dependencies": {"@dcloudio/uni-app": "^2.0.2-3081220230817001","@dcloudio/uni-app-plus": "^2.0.2-3081220230817001","@dcloudio/uni-h5": "^2.0.2-3081220230817001","@dcloudio/uni-i18n": "^2.0.2-3081220230817001","@dcloudio/uni-mp-360": "^2.0.2-3081220230817001","@dcloudio/uni-mp-alipay": "^2.0.2-3081220230817001","@dcloudio/uni-mp-baidu": "^2.0.2-3081220230817001","@dcloudio/uni-mp-jd": "^2.0.2-3081220230817001","@dcloudio/uni-mp-kuaishou": "^2.0.2-3081220230817001","@dcloudio/uni-mp-lark": "^2.0.2-3081220230817001","@dcloudio/uni-mp-qq": "^2.0.2-3081220230817001","@dcloudio/uni-mp-toutiao": "^2.0.2-3081220230817001","@dcloudio/uni-mp-vue": "^2.0.2-3081220230817001","@dcloudio/uni-mp-weixin": "^2.0.2-3081220230817001","@dcloudio/uni-mp-xhs": "^2.0.2-3081220230817001","@dcloudio/uni-quickapp-native": "^2.0.2-3081220230817001","@dcloudio/uni-quickapp-webview": "^2.0.2-3081220230817001","@dcloudio/uni-stacktracey": "^2.0.2-3081220230817001","@dcloudio/uni-stat": "^2.0.2-3081220230817001","@dcloudio/uni-ui": "^1.4.28","@vue/shared": "^3.0.0","core-js": "^3.8.3","crypto-js": "^3.1.9-1","flyio": "^0.6.2","vue": ">= 2.6.14 < 2.7","vuex": "^3.2.0"},"devDependencies": {"@dcloudio/types": "^3.3.2","@dcloudio/uni-automator": "^2.0.2-3081220230817001","@dcloudio/uni-cli-i18n": "^2.0.2-3081220230817001","@dcloudio/uni-cli-shared": "^2.0.2-3081220230817001","@dcloudio/uni-helper-json": "*","@dcloudio/uni-migration": "^2.0.2-3081220230817001","@dcloudio/uni-template-compiler": "^2.0.2-3081220230817001","@dcloudio/vue-cli-plugin-hbuilderx": "^2.0.2-3081220230817001","@dcloudio/vue-cli-plugin-uni": "^2.0.2-3081220230817001","@dcloudio/vue-cli-plugin-uni-optimize": "^2.0.2-3081220230817001","@dcloudio/webpack-uni-mp-loader": "^2.0.2-3081220230817001","@dcloudio/webpack-uni-pages-loader": "^2.0.2-3081220230817001","@vue/cli-plugin-babel": "~5.0.0","@vue/cli-service": "~5.0.0","babel-plugin-import": "^1.11.0","clean-webpack-plugin": "^4.0.0","copy-webpack-plugin": "^11.0.0","cross-env": "^7.0.2","jest": "^25.4.0","less": "^4.1.3","less-loader": "^7.3.0","mini-types": "*","miniprogram-api-typings": "*","postcss-comment": "^2.0.0","sass": "^1.49.8","sass-loader": "^8.0.2","vue-template-compiler": ">= 2.6.14 < 2.7","webpack-cli": "^5.1.4","vconsole": "^3.15.0"},"browserslist": ["Android >= 4.4","ios >= 9"],"uni-app": {"scripts": {"tt-brandA": {"env": {"UNI_PLATFORM": "h5"},"define": {"MP-BRANDA": true}},"ks-brandA": {"env": {"UNI_PLATFORM": "mp-kuaishou"},"define": {"MP-BRANDA": true}},"tt-brandB": {"env": {"UNI_PLATFORM": "h5"},"define": {"MP-BRANDB": true}},"ks-brandB": {"env": {"UNI_PLATFORM": "mp-kuaishou"},"define": {"MP-BRANDB": true}},"bd-brandB": {"env": {"UNI_PLATFORM": "mp-baidu"},"define": {"MP-BRANDB": true}},}}
}//src/pages.js:: 直接复制 prebuild下对应brand和平台platform下的pages.js文件
const {getApp,getHostCode} = require("../prebuild/env");
const path = require('path')
module.exports = (pagesJson, loader) => {let brandName = getApp();let code = getHostCode()const srcPath = path.join(__dirname, `../prebuild/${brandName}/pages-${code}.js`)let pagesJsonNew = require(srcPath)loader.addDependency(require.resolve(srcPath))return pagesJsonNew
}//vue.config.js
const fs = require("fs");
const CopyWebpackPlugin = require('copy-webpack-plugin')
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
const {getApp,getOS} = require("./prebuild/env");/** 本函数重定向输出路径到下面路径 ** */
function rebuildOutputPath(brand) {let separator = getOS() == 'win' ? '\\' : '/'const lastIndex = process.env.UNI_OUTPUT_DIR.lastIndexOf(separator)let pre = process.env.UNI_OUTPUT_DIR.substring(0, lastIndex)console.log("vue.config--buildOutputPath::",process.env.UNI_OUTPUT_DIR.substring(lastIndex))process.env.UNI_OUTPUT_DIR = process.env.UNI_OUTPUT_DIR.substring(lastIndex) + separator + brand
}const brandName = getApp()
rebuildOutputPath(brandName)let clearDir = ['static/img-*']
module.exports = {chainWebpack: (config) => {//本插件将图片资源目录例如img-brandA, 拷贝到输出目录的static/img下面config.plugin('copy').use(CopyWebpackPlugin, [{patterns: [{from: `src/static/img-${brandName}`,to: 'static/imgs/'}]}])//本插件将输出目录下,重复无效的/static/img-*目录删除掉config.plugin('clean').use(CleanWebpackPlugin, [{cleanAfterEveryBuildPatterns: clearDir}])//本插件进行预编译相关的拷贝工作,拷贝指定brand的manifest和生成build.lessconfig.plugin('CopyPlugin').use(require('./prebuild/CopyPlugin', [{brand: brandName}]))//对目标brand相关的非公用源文件进行监控更新编译的loaderconfig.module.rule('module_replace').test(/\.vue$/).pre().use('./prebuild/module_replace').loader('./prebuild/module_replace').end()}
}// 本代码模块配合module_replace的loader完成【对目标brand相关的非公用源文件进行监控更新编译】
const chokidar = require('chokidar');//监测改动时触发编译
const ignoreFiles = [];
const brandSign = `-${brandName}.`
const watcher = chokidar.watch('src/').on('ready', async () => {await watcher.close()chokidar.watch('src/', {ignored: ignoreFiles}).on('change', (path, stats) => {console.log('changed file', path);let brandSignIndex = path.lastIndexOf(brandSign)let endFix = path.substring(brandSignIndex + brandSign.length)let preFix = path.substring(0, brandSignIndex)let destPath = preFix + '.' + endFixconst destContent = fs.readFileSync(destPath, {encoding: "utf-8"})fs.writeFileSync(destPath, destContent + '\n')fs.writeFileSync(destPath, destContent)})
}).on('add', (path) => {if (path.indexOf(brandSign) <= 0) ignoreFiles.push(path)
})

vue.config.js 是项目打包入口,在里面使用了三个工具类,env.js CopyPlugin.js module_replace.js;通过不同的brand读取指定brand文件,重写到指定文件,实现分渠道打包

  1. 三个不可缺少工具类:
//env.js文件
module.exports = {getApp() {if (process.env.UNI_SCRIPT) {const script = process.env.UNI_SCRIPTlet subs = script.split('-')if (subs.length == 2) return subs[1]}console.error('错误!!未检测到有效的brand名称!!')return 'default'},makeDateTimeString(date) {let year = date.getFullYear();let month = date.getMonth() + 1;let day = date.getDate();if (month < 10) month = '0' + monthif (day < 10) day = '0' + daylet hour = date.getHours();let min = date.getMinutes();let sec = date.getSeconds()if (min < 10) min = '0' + minif (sec < 10) sec = '0' + secreturn `${year}-${month}-${day} ${hour}:${min}:${sec}`},getOS() {let host = 'ios'let arch = process.env.MSYSTEM_CARCHif (arch == 'x86_64' || arch == 'x86_32') host = 'win'return host},getHostCode() {if (process.env.UNI_SCRIPT) {const script = process.env.UNI_SCRIPTlet subs = script.split('-')if (subs.length == 2) return subs[0]}console.error('错误!!未检测到有效的brand名称!!')return ''}
}//CopyPlugin.js文件
const fs = require("fs");
const path = require('path');
const {getApp, getHostCode
} = require("./env");class CopyPlugin {log(...param) {console.log("CopyPlugin", ...param)}constructor() {this.log('constructed')}apply(compiler) {compiler.hooks.environment.tap('Manifest', params => {let brandName = getApp()const platform = process.env.UNI_PLATFORMconsole.log('brandName=' + brandName, 'platform=' + platform)// 构造build.lesslet buildStr = '@brand: ' + brandName + ';'fs.writeFileSync('src/build.less', buildStr)//复制manifest.jsonlet manifestPath = `prebuild/${brandName}/manifest.json`console.log('manifestPath=',manifestPath)let destManifestPath = 'src/manifest.json'const manifestContent = fs.readFileSync(manifestPath, {encoding: "utf-8"});fs.writeFileSync(destManifestPath, manifestContent)})}
}module.exports = CopyPlugin//module_replace.js 文件
const {getApp} = require("./env");
const fs = require("fs");
const tag = 'loader:module-replace'const brandName = getApp()
const brandSign = `-${brandName}.`module.exports = function(content) {let resourcePath = this.resourcePathlet dotIndex = resourcePath.lastIndexOf('.')let endFix = resourcePath.substring(dotIndex)let srcPath = resourcePath.substring(0, dotIndex) + '-' + brandName + endFixif (srcPath.indexOf(brandSign) <= 0) return contentif (!fs.existsSync(srcPath)) return contentconsole.log(tag, 'replace from', srcPath)const newContent = fs.readFileSync(srcPath, {encoding: "utf-8"});return newContent
}

运行打包时只需要控制台中输入package.json中指定的脚本key值即可:
npm run dev:tt-barndA
npm run build:ks-barndB
按照上述方法分包后即使实现一个项目多平台多渠道打包,如有问题请多指教
资源包在下一篇文章

相关文章:

uniapp 多渠道打包实现方案

首先一个基础分包方案&#xff1a; 包不用区分渠道&#xff0c;只是通过文件名进行区分&#xff0c;公共代码逻辑可以通过mixins进行混入。 这样分包后就需要在打包时只针对编译的渠道包文件进行替换打包&#xff0c;其他渠道包的文件不打包进去&#xff0c;通过工具类实现…...

请你学习:前端布局3 - 浮动 float

1 标准流&#xff08;也称为普通流、文档流&#xff09; 标准流&#xff08;也称为普通流、文档流&#xff09;是CSS中元素布局的基础方式&#xff0c;它决定了元素在页面上的默认排列方式。这种布局方式遵循HTML文档的结构&#xff0c;不需要额外的CSS样式来指定元素的位置。…...

PyCharm 2024.1 总结和最新变化

​ 您好&#xff0c;我是程序员小羊&#xff01; 前言 PyCharm 2024.1 是 JetBrains 最新发布的Python集成开发环境&#xff08;IDE&#xff09;&#xff0c;旨在提供更强大的功能和更好的用户体验。以下是对这个版本的总结和最新变化的介绍 智能代码建议和自动完成&#xff1a…...

RGB红绿灯——Arduino

光的三原色 牛顿发现光的色散奥秘之后&#xff0c;进一步计算发现&#xff1a;七种色光中只有红、绿、蓝三种色光无法被分解&#xff0c;而其他四种颜色的光均可由这三种色光以不同比例相合而成。于是红、绿、蓝被称为“三原色光”或“光的三原色”。后经证实&#xff1a;红、绿…...

浅谈用二分和三分法解决问题(c++)

目录 问题引入[NOIP2001 提高组] 一元三次方程求解题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示思路分析AC代码 思考关于二分和三分例题讲解进击的奶牛题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 思路AC代码 平均数题目描述输入格式输出格式样例 …...

Cocos Creator2D游戏开发(9)-飞机大战(7)-爆炸效果

这个爆炸效果我卡在这里好长时间,视频反复的看, 然后把代码反复的测试,修改,终于给弄出来 视频中这段,作者也是修改了好几次, 跟着做也走了不少弯路; 最后反正弄出来了; 有几个坑; ① 动画体创建位置是enemy_prefab ② enemy_prefab预制体下不用放动画就行; ③ 代码中引用Anima…...

终于有人把华为认证全部说清楚了

在信息技术领域&#xff0c;华为认证好比一座金字招牌&#xff0c;吸引着无数技术专业人士的青睐。 市场上关于华为认证的声音纷繁复杂&#xff0c;存在不少争议&#xff0c;让人难以辨别真伪。 今天就来好好讲讲华为认证&#xff0c;从头到尾都帮你盘盘清楚。 01 华为认证是…...

【知识】pytorch中的pinned memory和pageable memory

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 目录 概念简介 pytorch用法 速度测试 反直觉情况 概念简介 默认情况下&#xff0c;主机 &#xff08;CPU&#xff09; 数据分配是可分页的。GPU 无…...

【系统架构设计】数据库系统(五)

数据库系统&#xff08;五&#xff09; 数据库模式与范式数据库设计备份与恢复分布式数据库系统数据仓库数据挖掘NoSQL大数据 数据库模式与范式 数据库设计 备份与恢复 分布式数据库系统 数据仓库 数据挖掘 对数据挖掘技术进行支持的三种基础技术已经发展成熟&#xff0c…...

如何对人工智能系统进行测试|要点,方法及流程

当今社会&#xff0c;人工智能发展非常快。现在人工智能的发展已经渗透到了我们生活的方方面面&#xff0c;自动驾驶、或者我们手机里经常用到的一些应用都或多或少涉及到了一些人工智能的功能&#xff0c;比如说美图秀秀、新闻推荐、机器翻译以及个性化的购物推荐等等都涉及到…...

CVE-2023-37569~文件上传【春秋云境靶场渗透】

# 今天我们拿下CVE-2023-37569这个文件上传漏洞# 经过简单账号密码猜测 账号&#xff1a;admin 密码&#xff1a;password# 找到了文件上传的地方# 我们直接给它上传一句话木马并发现上传成功# 上传好木马后&#xff0c;右键上传的木马打开发现上传木马页面# 直接使用蚁剑进行连…...

MySQL简介 数据库管理与表管理

文章目录 1 MySQL的优势2 MySQL数据类型1 数字类型2 日期和时间类型3 字符串类型 3 数据库管理4 数据表管理参考 1 MySQL的优势 性能优化&#xff1a;通过优化存储引擎&#xff08;InnoDB&#xff0c;MyISAM&#xff09;和查询优化。解决大规模数据处理和查询优化开源&#xf…...

PHP 函数性能优化的技巧是什么?

本文由 ChatMoney团队出品 本文将详细介绍 PHP 函数性能优化的技巧。通过分析 PHP 函数的执行过程和性能瓶颈&#xff0c;提供一系列实用的优化方法&#xff0c;并结合代码示例&#xff0c;帮助读者提升 PHP 代码的执行效率。文章内容将涵盖变量作用域、递归算法、循环优化、内…...

小程序支付(前端)

前端只需要调用 wx.requestPayment(Object object) 文档 参考代码 const openId wx.getStorageSync(openId)payOrder({payId: this.data.resData.payId,openId}).then((res) > {console.log(2222, res);try {const data JSON.parse(res.res)console.log(22, data)const {…...

开发一个自己的VSCode插件

1、前言 对于一个前端开发者来说&#xff0c;开发工具&#xff0c;最常用的应该就是VSCode了&#xff0c;因为它免费&#xff0c;速度快&#xff0c;提供了丰富了插件等优点&#xff0c;使得越来越多的前端开发者都来使用它了&#xff0c;在开发的时候如果有丰富的插件提供支持…...

Milvus 向量数据库进阶系列丨构建 RAG 多租户/多用户系统 (上)

本系列文章介绍 在和社区小伙伴们交流的过程中&#xff0c;我们发现大家最关心的问题从来不是某个具体的功能如何使用&#xff0c;而是面对一个具体的实战场景时&#xff0c;如何选择合适的向量数据库解决方案或最优的功能组合。在 “Milvus 向量数据库进阶” 这个系列文章中&…...

前缀和(更新中)

目录 1.寻找数组的中心下标 2.除自身以外数组的乘积 3.和为k的子数组 4.可被k整除的子数组 5.连续数组 1.寻找数组的中心下标 . - 力扣&#xff08;LeetCode&#xff09; class Solution { public:int pivotIndex(vector<int>& nums) {int size nums.size();v…...

记录一次单例模式乱用带来的危害。

项目场景&#xff1a; 我们在接受到短信网关下发的回执之后&#xff0c;需要将回执内容也下发给我们的下游服务。为了防止下游响应超时&#xff0c;我们需要将超时的信息存放到Redis中然后进行补发操作。 问题描述 在使用Redis进行数据存储的时候&#xff0c;报NPE问题。 原因…...

外卖项目day14(day11)---数据统计

Apache ECharts 大家可以看我这篇文章&#xff1a; Apache ECharts-CSDN博客 营业额统计 产品原型 接口设计 新建admin/ReportController /*** 数据统计相关接口*/ RestController RequestMapping("/admin/report") Api(tags "数据统计相关接口") Slf…...

养猫科普!牙口不好的猫咪怎么选粮?好吃易消化主食罐推荐

我家的猫猫已经九岁了&#xff0c;已经是一位老奶奶了&#xff0c;她的牙口不太好。对于她来说&#xff0c;膨化猫粮过于硬&#xff0c;很难咀嚼&#xff0c;所以我为她准备了质地柔软的主食罐头。哪种主食罐头更适合牙口不好的猫咪呢&#xff1f;下面&#xff0c;我就来分享一…...

Linux链表操作全解析

Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表&#xff1f;1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...

VB.net复制Ntag213卡写入UID

本示例使用的发卡器&#xff1a;https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建

制造业采购供应链管理是企业运营的核心环节&#xff0c;供应链协同管理在供应链上下游企业之间建立紧密的合作关系&#xff0c;通过信息共享、资源整合、业务协同等方式&#xff0c;实现供应链的全面管理和优化&#xff0c;提高供应链的效率和透明度&#xff0c;降低供应链的成…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

vue3 字体颜色设置的多种方式

在Vue 3中设置字体颜色可以通过多种方式实现&#xff0c;这取决于你是想在组件内部直接设置&#xff0c;还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法&#xff1a; 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

linux 下常用变更-8

1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行&#xff0c;YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID&#xff1a; YW3…...

多模态大语言模型arxiv论文略读(108)

CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题&#xff1a;CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者&#xff1a;Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包

文章目录 现象&#xff1a;mysql已经安装&#xff0c;但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时&#xff0c;可能是因为以下几个原因&#xff1a;1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

听写流程自动化实践,轻量级教育辅助

随着智能教育工具的发展&#xff0c;越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式&#xff0c;也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建&#xff0c;…...

深度学习习题2

1.如果增加神经网络的宽度&#xff0c;精确度会增加到一个特定阈值后&#xff0c;便开始降低。造成这一现象的可能原因是什么&#xff1f; A、即使增加卷积核的数量&#xff0c;只有少部分的核会被用作预测 B、当卷积核数量增加时&#xff0c;神经网络的预测能力会降低 C、当卷…...