Taro解决小程序包体积过大的问题

目前小程序分包大小有以下限制:
整个小程序所有分包大小不超过 8M
单个分包/主包大小不能超过 2M

所以说8M的限制是要分包至少4个包,单个分包上限其实还是2M

解决这个问题一种是分包

官方给出的分包官网文档

另一种是减少包中的图片

其实造成包体积过大的因素,很大原因是因为包里有图片,那体积就会变得很大。那我们可以将图片上传到CDN上,变成网络链接,这样的话就不会把图片打包进去了。但是这样又有一个不足,比如说我们一开始开发项目的时候,UI同学给了我们设计图,那我们要将图片一张张的上传到CDN上去吗?如果后期UI走查的时候要换图片呢?而且万一CDN上的图片被人误删了或者服务到期了呢(当然这种可能性很小,但也可以考虑进去),这时候我们的原图都会找不到,只能干着急。。。

那么最好的方式就是将图片放在项目中,本地开发的时候引用的就是本地的,增删改找起来也方便,但是打包构建的时候将图片压缩并上传CDN,同时将项目中的图片引用路径改成网络链接,然后删除dist中的所有图片。那么接下来我们就写个脚本实现一下。

直接上代码吧

先写上传方法,用于打包完上传,先压缩再上传到阿里oss

// config/upload.js
const OSS = require("ali-oss");
const fs = require("fs");
const path = require("path");
const rimraf = require("rimraf");
const imagemin = require('imagemin')
const imageminJpegtran = require('imagemin-jpegtran')
const imageminPngquant = require('imagemin-pngquant')
const imageminSvgo = require('imagemin-svgo')
const imageminGifsicle = require('imagemin-gifsicle')

const client = new OSS({
  region: "",
  endpoint: "",
  accessKeyId: "",
  accessKeySecret: "",
  bucket: ""
});
async function compress() {
  const files = await imagemin(['../dist/**/*.{jpg,jpeg,png,svg,gif}'], {
    destination: '../dist/assets',
    plugins: [
      imageminJpegtran({
        progressive: true,
        quality: 80,
      }),
      imageminPngquant({
        quality: [0.6, 0.8],
      }),
      imageminSvgo({
        plugins: [{ removeViewBox: false }],
      }),
      imageminGifsicle(),
    ],
  })
  console.log('compress all images success!'.info)
  return files
}
const putOSS = async function(src, dist) {
  try {
    let result = await client.put(dist, src);
    console.log("oss上传成功: " + result.name);
  } catch (e) {
    console.log(e);
  }
};

const workList = [];

/**
 *
 * @param {string} src 需要上传的文件夹
 * @param {string} dist oss文件夹
 */

const addFileToOSSSync = function(src, dist) {
  try {
    await compress()
    var docs = fs.readdirSync(src);
  } catch (error) {
    console.log(src + "不存在");
    return;
  }

  docs.forEach(function(doc) {
    const _src = src + "/" + doc;
    const _dist = dist + "/" + doc;
    const st = fs.statSync(_src);
    // 判断是否为文件
    if (st.isFile() && doc !== ".DS_Store") {
      workList.push(putOSS(_src, _dist));
      // console.log(_src + '是文件', _dist);
    } else if (st.isDirectory()) {
      addFileToOSSSync(_src, _dist);
    }
  });
};

addFileToOSSSync("dist/assets", "weixin/gongyi/sdg/images");

Promise.all(workList).then(res => {
  rimraf(path.join(__dirname, "../dist/assets"), error => {
    if (error) {
      throw error;
    }
    console.log("done!");
  });
});

上传方法写完了,什么时候调用呢,应该在构建完之后调用,因为上传完要删除包中dist下的图片,那么我们应该package.json中更改命令

// package.json
"build:weapp": "NODE_ENV=online taro build --type weapp && node config/upload.js"

还有设置一个全局变量

// Taro打包入口处
const ossPath = '你的cdn域名'
let projectPublicPath = '/'

if (process.env.NODE_ENV !== 'development') {
  // 你上传的cdn路径
  projectPublicPath = `${ossPath}/1v1mp/${process.env.TARO_ENV}/${process.env.NODE_ENV}`
}

let assetsPre =
  process.env.TARO_ENV === 'weapp'
    ? process.env.NODE_ENV === 'development'
      ? ''
      : projectPublicPath
    : ''
var config = {
  // ...其他配置正常写,主要是注意这两项
  alias: {
    '@': path.resolve(__dirname, '..', 'src'),
  },
  defineConstants: {
    assetsPre: `"${assetsPre}"`,
  },
}

最后使用需要注意:

  • 所有图片文件放入src/assets目录下,可以在assets目录下创建各模块目录

  • 使用 import 引入后在src处使用 ${assetsPre}${pic}的方式使用, assetsPre是全局定义好的常量,可以直接使用。

    例如:

    import pic from '@/assets/defualt.jpg'
    
    export default function Index() {
      // do some logic
    
      return <Image src={`${assetsPre}${pic}`} />
    }
    

tip: 有一点要说一下,虽然import引入了,但其实是个pic是个路径,webpack5以前会把它通过loader转为路径,webpack5通过内置Asset Modules转为路径。具体文档可见:加载images图像