本鱼拟成立工作室承接项目开发/软件定制/云设施开发运维/办公设备技术支持等,如您有相关需求,欢迎来询 | ::博客文章推荐::

uni-app中使用lime-echart后移除主包中的额外文件

: WEB前端 木魚 55℃ 0评论

你要问我为啥突然搞uni-app了?这……我不造啊……这不临时接手捯饬捯饬么。

说实话啊,在这之前,我只在很久以前摸过一次hbuilder,并没有怎么使用,对于uni-app也没接触过,这才造成了这次苦难。

0. 由来

这是一个历史传承的小程序项目,基于 uni-app vue2。项目中使用了 lime-echart来画图,这是一个基于echarts的组件包。

后来由于资源零零总总多了些,便进行分包,与echarts依赖的页面被放进了子包中。

但是在项目运行或发行后,你会发现,主包下会出现一系列“无依赖代码文件”,大小比较可观,这主要是因为echarts本身就是个大家伙。

这几个“无依赖代码文件”不会对开发及调试产生什么影响,但是如果你计划上传或发布,就会带来问题:因为它会导致主包变大,一方面是微信对主包要求不得大于2MB,因此很容易导致超限无法上传,再就是这个文件本身很大,却是无依赖的,就很让人膈应。而这几个文件,实际上已经被打包到 vendor.js里去了,因此不应该独立出现。

如果你在微信开发者工具中手动删除这几个文件,会发现并不影响开发运行,却可能会导致主包超过2MB大小引发拒绝上传。

所以之前在问负责这个小程序的前端开发是咋回事时,他给我的答复是,用了lime-echart这个库就会这样,自动生成这几个文件,手动删一下就行。

我说每次手动删吗,很膈应啊。他说解决不了。

35.gif

也就这么将就了。

那么现在为什么我又开始搞这个东西了呢,是因为我想把小程序的打包及发布搞到CI里面去。搞到CI里面的话,不好还要手动删了吧?看了些hbuilder的文档,觉得可以用hbuilder cli来做这个事情,编译打包上传一气呵成,那么这个多余的文件还是得想办法解决一下的。毕竟打包后的这个小程序就3.4M不到,而这几个文件直接就占了接近20%,就算你不会导致我无法上传也会让我很难受啊。

既然如此,那就收拾它。

1. 先看看人家怎么做的

我觉得这个问题肯定不是只有我会觉得是个问题。

因此第一件事就是进行了搜索。果然找到了一些帖子提供解决方案。

第一个帖子来自于 《uni-app小程序分包中使用 Echarts, 并在分包里加载依赖》。这个帖子看了下,大概思路就是把lime-echart这个包从主包的根目录移到子包的目录下,然后还需要改动一部分代码,否则可能无法使用。我开始时还试了试,但试到一半感觉味道不太对,这样移动到子目录里的包实际上已经不会被认为是项目的引入包了,总觉得怪怪的,且没有最终确认是去掉了这几个多余的文件还是只是换了个地方,便放弃这条思路。

第二个帖子来自于《uniapp小程序分包异步化实践—-echarts分包实战》,这个帖子说的更复杂,不仅用了webpack的CopyWebpackPlugin,还要修改引用echarts组件的方式,大工又大料,也许有独特的优势,但对于我这个场景以及只是想不让这几个冗余文件出现的需求,似乎有点过于沉重了。

搜索了很多资料,也问了AI,好像都没什么有价值的信息,不得不吐槽一下uni-app的文档资料真的是少得可怜。

想了想,自力更生吧。

2. 第一次尝试

简单看了下uni-app的构成,就可以知道这个底层是webpack进行打包。那么我的第一个思路是,在打包完成后手动删一下这几个文件。

不过在探索了一番hubuilder后,发现这个思路行不通,它没有类似Visual Studio的Post Build事件,似乎CLI也是基于它自身的,没有入手点。

那么,就从webpack下手。

基于webpack,最先想到的是,从webpack配置出发,看看有没有钩子函数之类的,可以手动处理。

通过uni-app官方文档中的vue.config.js介绍可以看出,可以通过这个文件对webpack进行定制。

兜兜转转,我觉得没准 IgnorePlugin 可以解决这个问题。

于是先在hbuilder里写下这样的代码。

const webpack = require('webpack');

module.exports = {
    configureWebpack: {
        plugins: [
            new webpack.IgnorePlugin({
                resourceRegExp: /(echarts\.min|ecStat\.min|uni\.webview\..*?)\.js$/,
            })
        ]
    }
}

但是以上代码直接无法编译。

[HBuilder] 19:20:57.507  ERROR  Error loading vue.config.js:  
[HBuilder] 19:20:57.507  ERROR  Error: Cannot find module 'webpack'  
[HBuilder] 19:20:57.507 Require stack:  
[HBuilder] 19:20:57.507 - ======\vue.config.js  
[HBuilder] 19:20:57.507 - ======\HBuilderX\plugins\uniapp-cli\node_modules\@vue\cli-service\lib\Service.js  
[HBuilder] 19:20:57.507 - ======\HBuilderX\plugins\uniapp-cli\bin\uniapp-cli.js  
[HBuilder] 19:20:57.507 Error: Cannot find module 'webpack'  
[HBuilder] 19:20:57.507 Require stack:  
[HBuilder] 19:20:57.507 - ======\vue.config.js  
[HBuilder] 19:20:57.508 - ======\HBuilderX\plugins\uniapp-cli\node_modules\@vue\cli-service\lib\Service.js  
[HBuilder] 19:20:57.508 - ======\HBuilderX\plugins\uniapp-cli\bin\uniapp-cli.js  
[HBuilder] 19:20:57.508     at Module._resolveFilename (node:internal/modules/cjs/loader:1140:15)  
[HBuilder] 19:20:57.508     at Module._resolveFilename (======\HBuilderX\plugins\uniapp-cli\node_modules\module-alias\index.js:49:29)  
[HBuilder] 19:20:57.508     at Module._load (node:internal/modules/cjs/loader:981:27)  
[HBuilder] 19:20:57.508     at Module.require (node:internal/modules/cjs/loader:1231:19)  
[HBuilder] 19:20:57.508     at require (node:internal/modules/helpers:177:18)  
[HBuilder] 19:20:57.508     at Object.<anonymous> (======\vue.config.js:1:17)

这里可以看出。编译的工具包是在HbuilderX的安装目录下的,这个目录下确实也有 webpack 的包,但是require会直接报错,无法找到webpack包。

试了试倒是可以本地 npm install 一下,但……明明构建服务里已经有一个webpack了,我这里还要为了require再去装一个webpack以及它的七大姑八大姨,这怎么听怎么别扭,你这跟让我去装一下360 鲁大师之类的有啥区别。

再就是,现在明明有webpack了只是无法require,应该是哪里存在问题,再去装一个双份的明显不是合理的思路。

到这时已经很晚了,于是我决定先到dcloud的社区里提个问,下次再说。

3. 解决require的问题

第二天我继续来解决这个webpack的问题。

群里有人require成功了,不过他是项目里npm install了一下。我始终觉得这不是正确的思路。

问了下AI,基本上也就是让你安装之类的回复。

这时候我在琢磨一个问题,就是明明构建服务里有webpack但是打包的配置文件里require无法加载,应该是路径有问题,或者模块加载器哪里解析有问题,但苦于对hbuilderx这套东西不熟,还真的有点一筹莫展。

忽然dcloud社区里有人回复了,定睛一看……好嘛,手动拼出来完整的webpack地址去加载……

const { resolve } = require('path')  
const rootModulePath = resolve(process.cwd(), 'node_modules')  
function resolveModulePath(dir) {  
  return resolve(rootModulePath, dir)  
}  
const webpack = require(resolveModulePath('webpack'))

这……怎么说呢,就是……可以工作,但真的丑,应该是构建系统里的模块加载机制不完善,导致配置文件中require时只能加载项目目录里的,并不能fallback到内置的包目录。

但,总归是能解决加载的问题,你就说能不能用吧。

4. 自己写插件吧

在解决webpack的加载问题后,继续尝试了一下 IgnorePlugin,发现没有按预期的方式工作,生成的目录里还是有对应的几个文件。

到这里我不太想继续研究这东西到底应该怎么弄了,因为……我觉得我这是个非常简单的诉求,没必要把简单的事情复杂化。

于是我就把目光转向了自己写个简单的webpack插件。

const removeAssets = [
    /^uni_modules\/lime-echart\/static\/(echarts\.min|ecStat\.min|uni\.webview\..*?)\.js$/,
    /^project\.private\.config\.json$/,
];

class RemoveAssetsPlugin {
    constructor(options) {
        this.options = options || {}
    }
    apply(compiler) {
        compiler.hooks.emit.tapAsync('RemoveAssetsPlugin', (compilation, callback) => {

            for (const name of Object.keys(compilation.assets)) {
                if (removeAssets.find(r => r.test(name))) {
                    console.info(`[RemoveAssetsPlugin] 强制删除多余的资源文件:${name}`);
                    delete compilation.assets[name];
                }
            }
            callback();
        });
    }
}


module.exports = {
    configureWebpack: {
        plugins: [
            new RemoveAssetsPlugin()
        ]
    }
}

写完后build一下。

17:40:38.062 [RemoveAssetsPlugin] 强制删除多余的资源文件:uni_modules/lime-echart/static/echarts.min.js
17:40:38.062 [RemoveAssetsPlugin] 强制删除多余的资源文件:project.private.config.json
17:40:38.062 [RemoveAssetsPlugin] 强制删除多余的资源文件:uni_modules/lime-echart/static/ecStat.min.js
17:40:38.062 [RemoveAssetsPlugin] 强制删除多余的资源文件:uni_modules/lime-echart/static/uni.webview.1.5.5.js
17:40:38.062 [RemoveAssetsPlugin] 强制删除多余的资源文件:uni_modules/lime-echart/static/uni.webview.1.5.3.js
17:40:38.149 项目 **** 编译成功。前端运行日志,请另行在小程序开发工具的控制台查看。

看起来完美解决了需求,也没有引入第三方依赖。

嗯哼,收工。

喜欢 (0)
发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址