uniapp支持编译到多端,如微信、抖音、支付宝等等,在日常开发中针对小程序关于域名、appid和一些各端自有的文件配置,往往要手动修改代码,或者是创建文件。
还有,要想生成一个小程序码,要打开编辑器切换分支,运行对应编译命令,然后打开模拟器生成预览码,颇为不便。
为了优化开发体验,增加开发效率,对项目进行自定义编译改造,和开发自动化构建平台。
自定义编译
脚本配置
在 package.json 设置自定义脚本
"uni-app": {
"scripts": {
"wx-dev": {
"title": "微信小程序-开发环境",
"env": {
"UNI_PLATFORM": "mp-weixin",
"ENV_TYPE": "dev"
}
}
}
}
会在编辑器生成对应的脚本,点击即可运行
设置config目录存储数据及脚本
- config
- env.js
- script.js
config\env.js 根据不同端口和环境存储数据
export default {
dev: {
wxUrl: 'https://xxxxxx.dev.xxxxxx.com',
ttUrl: 'https://xxxxxx.dev.xxxxxx.com/tt',
ttAppid: 'xxxxxxxxx',
},
test: {
wxUrl: 'https://xxxxxx.dev.xxxxxx.com',
ttUrl: 'https://xxxxxx.dev.xxxxxx.com/tt',
ttAppid: 'xxxxxxxxx',
},
ready: {
wxUrl: 'https://xxxxxx.dev.xxxxxx.com',
ttUrl: 'https://xxxxxx.dev.xxxxxx.com/tt',
ttAppid: 'xxxxxxxxx',
},
prod: {
wxUrl: 'https://xxxxxx.dev.xxxxxx.com',
ttUrl: 'https://xxxxxx.dev.xxxxxx.com/tt',
ttAppid: 'xxxxxxxxx',
},
}
config\script.js 对不能通过环境变量处理及要手动生成的文件做处理 如抖音小程序的配置文件
// 生成抖音的配置文件,目前并不能在uniapp项目里面配置,需要手动生成
const fs = require('fs')
const path = require('path')
export function createPackage() {
const dirPath = path.join(__dirname, '../dist/dev/mp-toutiao/app.js')
const filePath = path.join(__dirname, '../dist/dev/mp-toutiao/package.json')
function writeFile() {
fs.writeFileSync(
filePath,
`{ "industrySDK": true, "ttPlugins": { "dependencies": { "microapp-trade-plugin": { "version": "1.1.2", "isDynamic": true } } } }`
)
console.error('--------------------生成package.json文件成功--------------------')
}
try {
// 这里使用循环检测文件存在来判断是否编译完成
const key = setInterval(() => {
if (fs.existsSync(dirPath, fs.constants.F_OK)) {
writeFile()
clearInterval(key)
}
}, 1000)
} catch (error) {
console.error('生成package.json文件失败', error)
}
}
vite.config.ts 文件注入全局变量和执行脚本
// 根据执行命令的类型获取变量,以及执行脚本
const ENV_TYPE = process.env?.UNI_CUSTOM_DEFINE ? (JSON.parse(process.env.UNI_CUSTOM_DEFINE!)).ENV_TYPE : 'prod'
// 生成抖音文件
if (process.env.UNI_PLATFORM === 'mp-toutiao') {
createPackage()
}
// 注入全局变量
export default defineConfig(({ mode }) => ({
define: {
'process.env': process.env,
'process.ENV_CONFIG': ENV_CONFIG,
'process.ENV_TYPE': {type:ENV_TYPE},
},
}));
全局变量使用
以接口域名为例
option.url = process.ENV_CONFIG[process.ENV_TYPE.type].wxUrl + option.url
自动化构建平台
目标设计:支持代码分支自由选择,支持环境变量选择(依赖上面的自定义构建)
要完成上述目标,有几个关键点
- 分支切换:使用 simple-git 库来执行命令
- 支持根据环境变量,进行自动化构建:依赖上述的自定义构建,和微信小程序的CLI包
- 前端页面及服务器开发:使用 nuxt 进行开发,有 VUE 的原生优势,也可以调用 node 能力
代码分支控制–git
引入simple-git 库,针对于各种场景的分支操作做封装,包括分支更新、切换
import simpleGit from "simple-git";
const projectPath = "../cd-mini-program";
export function gitFetch() {
return new Promise((resolve, reject) => {
try {
const git = simpleGit(projectPath);
git.fetch((err: any) => {
if (err) {
console.error(err);
reject(err);
return;
}
console.log("------更新分支成功-----");
resolve("200");
});
} catch (error) {
reject(error);
}
});
}
自动化构建
uniapp项目编译
对于 HBuilderX 创建的项目可以引入cli支持,确保可以执行命令来编译项目 预计设计引入 shelljs 库执行 npm 命令来打包 uniapp,运行时切换目录到小程序项目根目录下,执行命令。
微信小程序预览
引入 miniprogram-ci 库,这是微信小程序官方的库,支持编译、预览和上传等代码操作。 这里主要用到预览功能,以此为例。
const project = new ci.Project({
appid: "xxxx", // 小程序项目的 appid
type: "miniProgram",
projectPath: `${PATH}/dist/${buildType}/mp-weixin`, // 项目路径
privateKeyPath: `xxxxx.key`, // 项目私钥
ignores: [`node_modules/**/*`],
});
const previewResult = await ci.preview({
project,
setting: { // 支持的配置参数,与模拟器同理
minifyJS: true,
minifyWXML: true,
minifyWXSS: true,
minify: true,
},
bigPackageSizeSupport: true, // 非官方文档用法
qrcodeFormat: "image",
qrcodeOutputDest: `./${envType}.png`,
useCOS: true, // 非官方文档用法
onProgressUpdate: (data: any) => {
// console.log('onProgressUpdate',data);
},
});
vite 插件支持环境化处理
使用 vite 处理 uniapp 环境化
// vite-plugin-uni-script.js
const fs = require('fs')
const path = require('path')
let env_config
const UNI_PLATFORM = process.env.UNI_PLATFORM // 运行平台
const ENV_TYPE = process.env.UNI_CUSTOM_DEFINE
? JSON.parse(process.env.UNI_CUSTOM_DEFINE).ENV_TYPE
: 'prod' // 环境类型
const PLATFORM_MAP = {
'mp-toutiao': '抖音',
'mp-alipay': '支付宝',
'mp-weixin': '微信',
}
// 修改 appid
function modifyAppId(platform, appId) {
const filePath = path.join(__dirname, '../src/manifest.json')
try {
const fileContent = fs.readFileSync(filePath, 'utf-8')
const obj = JSON.parse(fileContent)
obj[platform]['appid'] = appId
fs.writeFileSync(filePath, JSON.stringify(obj, null, 2)) // 格式化 JSON 输出
console.info(
`--------------------修改${PLATFORM_MAP[platform]} appid成功--------------------`
)
} catch (error) {
console.error(`修改${PLATFORM_MAP[platform]} appid失败`, error)
}
}
export default function uniScriptPlugin(resolvedConfig) {
return {
name: 'vite-plugin-uni-script',
configResolved(config) {
env_config = config.env_config
},
buildStart() {
if (UNI_PLATFORM === 'mp-toutiao') {
modifyAppId('mp-toutiao', env_config[ENV_TYPE].ttAppid)
} else if (UNI_PLATFORM === 'mp-alipay') {
modifyAppId('mp-alipay', env_config[ENV_TYPE].alAppId)
}
},
writeBundle() {
if (UNI_PLATFORM === 'mp-toutiao') {
const filePath = path.join(__dirname, '../dist/dev/mp-toutiao/package.json')
try {
const txt = JSON.stringify(
{
industrySDK: true,
ttPlugins: {
dependencies: {
'microapp-trade-plugin': {
version: '1.1.2',
isDynamic: true,
},
},
},
},
null,
2
) // 格式化 JSON 输出
fs.writeFileSync(filePath, txt)
console.info('--------------------生成package.json文件成功--------------------')
} catch (error) {
console.error('生成package.json文件失败', error)
}
} else if (UNI_PLATFORM === 'mp-alipay') {
// ...
}
},
}
}
// vite.config.ts
import uniScriptPlugin from './vite-plugin-uni-script'
export default defineConfig(({ mode }) => ({
plugins: [uni(),vitePluginUniScript(ENV_CONFIG)],
env_config: ENV_CONFIG,
}));
// ENV_CONFIG 定义
const ENV_CONFIG = {
dev: {
ttAppid: 'ttAppid',
alUrl: 'alUrl',
},
prod: {
ttAppid: 'ttAppid',
alUrl: 'alUrl',
}
}
求内推
广州/深圳-前端求内推