How to Async Load Large Third‑Party Libraries in WeChat Mini‑Programs via Subpackages

This article explains how to overcome the 2 MB main‑package size limit in WeChat mini‑programs by asynchronously loading large third‑party libraries such as MQTT.js through subpackages, comparing subpackages with plugins, and providing practical Webpack and uni‑app solutions—including custom require handling, retry mechanisms, and performance gains.

Huolala Tech
Huolala Tech
Huolala Tech
How to Async Load Large Third‑Party Libraries in WeChat Mini‑Programs via Subpackages

Background

HuoLala's moving mini‑program provides convenient, safe, and reliable moving services, but the official package size limit of 2 MB makes it difficult to include large third‑party libraries such as tim‑wx‑sdk (~500 KB), MQTT.js (186 KB) and lottie‑miniprogram (200 KB) in the main package.

Including these libraries in the main package would exceed the limit, preventing upload.

WeChat mini‑programs offer subpackage asynchronous loading to address this scenario.

We will use MQTT.js as an example to demonstrate subpackage async loading; the same approach applies to other libraries.

Start

According to the official documentation, using the require keyword can asynchronously import code from a subpackage.

First, register a subpackage named external-library-mqtt and place an empty index.vue and the mqtt.min.js source file inside:

subPackages: [<br/>  {<br/>    root: 'pages/external-library-mqtt',<br/>    pages: [<br/>      {<br/>        path: 'index',<br/>      },<br/>    ],<br/>  },<br/>]

Then modify the MQTT import in the main package:

// src/plugins/mqtt/index.js<br/>- import mqtt from './mqtt.min.js'<br/><br/>+ let mqtt<br/>+ require('../pages/external-library-mqtt/mqtt.min.js', res => {<br/>   console.log('require mqtt.min.js:
', res)<br/>   mqtt = res<br/>}, ({mod, errMsg}) => {<br/>   console.error(`path: ${mod}, ${errMsg}`)<br/>})

Compilation fails because the Uni‑app framework uses Webpack, which does not support the CommonJS require keyword.

We can instead use the requirePlugin method to load the library from a plugin.

However, placing large libraries in plugins adds constraints and can break the single‑responsibility principle of plugins.

Subpackage VS Plugin

Comparison of differences

Subpackage : No separate review, each subpackage cannot exceed 2 MB, total mini‑program size cannot exceed 20 MB, no publishing restrictions.

Plugin : Requires separate review and publishing, each plugin cannot exceed 2 MB, only one plugin per AppID.

Thus, subpackages are more flexible for our scenario.

Re‑trying the Build

To avoid the require compilation error, we replace it with a custom placeholder that will be restored later:

// src/plugins/mqtt/index.js<br/>+ customRequire && customRequire('../pages/external-library-mqtt/mqtt.min.js', res => {<br/>   // ...<br/>   mqttReady()<br/>}, ...)

We then create a Webpack plugin that replaces customRequire back to require in the compiled dist/common/vendor.js file.

export class MyPlugin {<br/>  apply(compiler) {<br/>    compiler.hooks.emit.tap('MyPlugin', (compilation) => {<br/>      let content = compilation.assets['common/vendor.js'].source();<br/>      content = content.replace(/customRequire/g, 'require');<br/>      compilation.assets['common/vendor.js'] = {<br/>         source() { return content; },<br/>         size() { return content.length; }<br/>      };<br/>    });<br/>  }<br/>}

We also use copy-webpack-plugin to copy mqtt.min.js into the subpackage output directory so it is available at runtime.

// vue.config.js<br/>+ const CopyWebpackPlugin = require('copy-webpack-plugin')<br/><br/>module.exports = {<br/>  configureWebpack: {<br/>    plugins: [<br/>      new MyPlugin(),<br/>      new CopyWebpackPlugin([<br/>        {<br/>          from: path.join(__dirname, 'src/pages/external-library-mqtt/mqtt.min.js'),<br/>          to: path.join(__dirname, 'dist', process.env.NODE_ENV === 'production' ? 'build' : 'dev', process.env.UNI_PLATFORM, 'pages/external-library-mqtt'),<br/>        }<br/>      ]),<br/>    ],<br/>  },<br/>};

After rebuilding, the console prints the MQTT source code, confirming successful async loading. The main package size is reduced by 186 KB.

Cache Queue

Because the MQTT API may be called before the async load finishes, we introduce a queue to cache calls until the library is ready:

// src/plugins/mqtt/index.js<br/>+ const queue = []<br/>+ const mqttReady = () => {<br/>    const run = () => {<br/>        const fn = queue.shift();<br/>        if (typeof fn !== 'function') return;<br/>        fn();<br/>        run();<br/>    };<br/>    run();<br/> }<br/><br/>customRequire && customRequire('../pages/external-library-mqtt/mqtt.min.js', res => {<br/>    mqtt = res;<br/>    mqttReady();<br/>}, ...);<br/><br/>+ const beforehook = (fn) => (...args) => {<br/>    if (!mqtt) {<br/>        queue.push(() => fn(...args));<br/>    } else {<br/>        fn(...args);<br/>    }<br/> };<br/><br/>+ const login = beforehook(() => {...});

Simpler Approach

Webpack provides __non_webpack_require__, which is left untouched by the bundler and later resolved to require. Replacing the custom placeholder with this variable removes the need for a custom plugin.

// src/plugins/mqtt/index.js<br/>- customRequire && customRequire('../pages/external-library-mqtt/mqtt.min.js', res => {...})<br/>+ __non_webpack_require__ && __non_webpack_require__('../pages/external-library-mqtt/mqtt.min.js', res => {...})

Failure Considerations

Failure Rate

The code only attempts async loading on cold start (onLaunch).

Metrics show a failure rate of 0.02 %–0.03 % for the async load. To further reduce it, we add a retry mechanism.

Retry Mechanism

When loading fails, we delay and retry a configurable number of times.

// src/plugins/mqtt/index.js<br/>+ const asyncRequire = (retry) => {<br/>+  let _retry = retry;<br/>+  const loadError = async(error, resolve) => { ... };<br/>+  const loadResource = (resolve) => {<br/>+    __non_webpack_require__.async('../pages/external-library-mqtt/mqtt.min.js')<br/>+      .then(...).catch(...);<br/>+  };<br/>+  return new Promise((resolve) => {<br/>+    loadResource(resolve);<br/>+  });<br/>+ };<br/>+ const { error, res } = await asyncRequire(3);<br/>+ if (res) mqtt = res;

With retries, the failure rate drops to 0.003 %.

Project Benefits

Originally, the Tencent Cloud IM SDK (~500 KB) had to be moved to a subpackage, increasing subpackage size. After implementing async loading, the SDK can stay in the main package without inflating its size.

Performance measurements show reduced download times for key pages:

Message Center page: 750 ms → 620 ms (‑17 %). Order Detail page: 800 ms → 670 ms (‑16 %).

Conclusion

This article addresses the common pain point of main‑package size limits in WeChat mini‑programs by presenting a robust subpackage asynchronous loading solution that works even when the underlying framework only supports plugin loading. The approach improves extensibility, reduces subpackage download time, and yields measurable performance gains, with a failure rate as low as 0.003 % after adding retries.

References

[1]

Subpackage async loading: https://developers.weixin.qq.com/miniprogram/dev/framework/subpackages/async.html [2] MQTT.js: https://github.com/mqttjs/MQTT.js [3] Webpack hooks: https://webpack.docschina.org/api/compiler-hooks/#hooks [4] Webpack __non_webpack_require__: https://webpack.docschina.org/api/module-variables/#__non_webpack_require__-webpack-specific

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

performance optimizationwebpackasync loadingWeChat MiniProgramuni-appSubpackage
Huolala Tech
Written by

Huolala Tech

Technology reshapes logistics

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.