小程序和其他环境不一样,打包后的体积真是寸土寸金,图片资源最好是用网络地址,所以写一个loader来上传文件,返回网络地址
url-laoder 或是 postcss-loader
taro 用了 url-laoder 或是 postcss-loader 将图片 base64 打到 js 里,虽说又 limit 参数,但我试了试不好用,就算好用,打到本地图片也不是我希望的。
url-loader 有一个配置是,超出 limit 上线,可以走 fallback 一个自己的 loader
修改 taro 打包配置
需要修改一下 taro 的编译配置
mini.postcss.url
url: {
enable: true,
config: {
limit: 0, // 设定转换尺寸上限
url: ''
},
},
用 webpackChain 修改 image rule 的 loader 参数
再 url-loader 添加 fallback 让他走自己写的 loader
webpackChain(chain) {
chain.plugin('WxssImportPlugin').use(WxssImportPlugin)
chain.module
.rule('image')
.use('urlLoader')
.tap(options => {
options.fallback = path.resolve(__dirname, '../build/ImageUploadLoader/index.js')
return options
})
// console.log(chain.resolve.plugins)
}
loader 部分的代码
每次构建都会走 loader 的代码,我不希望每次都上传图片,所以可以用 md5 再本地做一个上传结果的缓存
// index.js
const buf2Url = require('./utils/buf2Url')
/**
* 因为小程序分包大小问题,我们把所有本地图片上传到fs上,然后用返回网络地址
*
* 存储一个md5 作为缓存,在memo中的地址,直接使用,不存在的上传fs
*/
module.exports = async function (value) {
const callback = this.async();
const raw = this._module.rawRequest.split('/')
const filename = raw[raw.length - 1]
const url = await buf2Url(value, filename)
callback(null, moduleStr(url))
}
function moduleStr(str) {
return `module.exports='${str}'`
}
url-loader 会传入 buffer,拿着 buffer 上传文件,拿到 url 地址
// utils/buf2url.js
const md5 = require('md5')
const axios = require('axios')
const fs = require('fs')
const path = require('path')
const FormData = require('form-data')
const UploadPath = # 上传地址
module.exports = function (buf, filename) {
// 获取md5值
const key = md5(buf)
console.log('filename', filename)
let memo
try {
memo = JSON.parse(fs.readFileSync(path.resolve(__dirname, '../md5memo.json')))
} catch (e) {
memo = {}
}
return new Promise(resolve => {
// 是否在memo中存在
if (key in memo) {
resolve(memo[key].fullPath)
} else {
// 上传
try {
let form = new FormData()
form.append('file', buf, { filename })
axios.post(UploadPath, form, {
headers: {
'Content-Type': 'multipart/form-data',
...form.getHeaders()
}
}).then(res => {
try {
memo = JSON.parse(fs.readFileSync(path.resolve(__dirname, '../md5memo.json')))
} catch (e) {
memo = {}
}
// 存json
memo[key] = {
# 取网络地址
fullPath: res.data.data.fullPath,
filename
}
fs.writeFileSync(path.resolve(__dirname, '../md5memo.json'), JSON.stringify(memo, null, 2))
resolve(res.data.data.fullPath)
})
} catch (e) {
console.log('出错了?')
resolve()
}
}
})
}