Skip to content

Package Loading

In some cases, developers need to divide the small program into different sub-packages, package them into different sub-packages when building, and load them on demand when users use them.

When building a mini program subcontracting project, the build will output one or more subpackages. Each mini program that uses subcontracting must contain a main package, the so-called main package, which places the default startup page/TabBar page, and some subpackages. Public resources/JS scripts are required; and subcontracting is divided according to the developer's configuration.

When the mini program is started, the main package will be downloaded by default and the page in the main package will be launched. When the user enters a page in the sub-package, the client will download the corresponding sub-package and display it after the download is completed.

Currently, the mini program subpackage size has the following restrictions:

  • The size of all subpackages of the entire mini program does not exceed 24M.
  • The size of a single subpackage/main package cannot exceed 2M.
Subpackages of mini programs can optimize the download time of the mini program when it is first launched, and can better decouple collaboration when multiple teams are developing together.

1.Use subpackages

1.1Configuration method

Assume that the directory structure of the mini program that supports subpackages is as follows:

js
├── app.js
├── app.json
├── app.wxss
├── packageA
│   └── pages
│       ├── cat
│       └── dog
├── packageB
│   └── pages
│       ├── apple
│       └── banana
├── pages
│   ├── index
│   └── logs
└── utils

The developer declares the project subpackage structure in the subpackages field of app.json:

TIP

It is also supported to write it as subPackages.

js
{
  "pages":[
    "pages/index",
    "pages/logs"
  ],
  "subpackages": [
    {
      "root": "packageA",
      "pages": [
        "pages/cat",
        "pages/dog"
      ]
    }, {
      "root": "packageB",
      "name": "pack2",
      "pages": [
        "pages/apple",
        "pages/banana"
      ]
    }
  ]
}

In subpackages, the configuration of each subpackage has the following items:

FieldsTypeDescription
rootStringSubpackage root directory
nameStringSubpackage alias,Subpackage pre-download Can be used
pagesStringArraySubpackage page path, relative to subpackage root directory
independentBooleanIs the subpackage Independent subpackage

1.2Packaging principle

  • After declaring subpackages, they will be packaged according to the subpackage configuration path, and the directories outside the subpackage configuration path will be packaged into the main package.
  • The main package can also have its own pages, that is, the outermost pages field.
  • The root directory of a subpackage cannot be a subdirectory in another subpackage.
  • The tabBar page must be in the main package.

1.3Reference principle

  • packageA cannot require packageB JS files, but can require JS files in the main package and packageA; this restriction does not apply when using Subpackage Asynchronization .
  • packageA cannot import packageB's template, but can require templates in the main package and packageA.
  • packageA cannot use packageB's resources, but can use resources in the main package and packageA.

2.Independent Subpackage

Independent subpackage is a special type of subpackage in the mini program, which can run independently of the main package and other subpackages. When entering the mini program from the page in the independent subpackage, the main package does not need to be downloaded. The main package will only be downloaded when the user enters the ordinary subpackage or the page in the main package.

Developers can configure certain pages with certain functional independence into independent subpackages as needed. When the mini program is started from the ordinary subpackage page, the main package needs to be downloaded first; independent subpackages can run without relying on the main package, which can greatly improve the startup speed of the subpackage page.

There can be multiple independent subpackages in a mini program.

2.1Configuration method

Assume that the directory structure of the mini program is as follows:

js
├── app.js
├── app.json
├── app.wxss
├── moduleA
│   └── pages
│       ├── rabbit
│       └── squirrel
├── moduleB
│   └── pages
│       ├── pear
│       └── pineapple
├── pages
│   ├── index
│   └── logs
└── utils

The developer declares the corresponding subpackage as an independent subpackage by defining the independent field in the corresponding subpackage configuration item in the subpackages field of app.json.

js
{
  "pages": [
    "pages/index",
    "pages/logs"
  ],
  "subpackages": [
    {
      "root": "moduleA",
      "pages": [
        "pages/rabbit",
        "pages/squirrel"
      ]
    }, {
      "root": "moduleB",
      "pages": [
        "pages/pear",
        "pages/pineapple"
      ],
      "independent": true
    }
  ]
}

2.2 Restrictions

Independent subpackages are a type of subpackage. All restrictions of ordinary subpackages are valid for independent subpackages. The processing method of custom components in independent subpackages is the same as that of ordinary subpackages.

In addition, when using independent subpackages, please note:

  • Independent subpackages cannot rely on the content in the main package and other subpackages, including js files, templates, wxss, custom components, etc. (use Subpackage asynchronousWhen js files and custom components are not subject to this restriction);
  • app.wxss in the main package is invalid for independent subpackages, and styles in app.wxss should be avoided in independent subpackage pages;
  • App can only be defined in the main package, and cannot be defined in independent subpackages, which will cause unexpected behavior;

2.3 Notes

2.3.1 About getApp()

Unlike ordinary subpackages, when an independent subpackage is running, the App is not necessarily registered, so getApp() may not necessarily obtain the App object:

  • When a user starts a mini program from an independent subpackage page, the main package does not exist, and the App does not exist either. At this time, calling getApp() will get undefined. When the user enters an ordinary subpackage or a page in the main package, the main package will be downloaded and the App will be registered.
  • When the user jumps to the independent subpackage page from an ordinary subpackage or a page in the main package, the main package already exists, and calling getApp() can get the real App.
Due to this limitation, developers cannot use the App object to share global variables between independent subpackages and other parts of the mini program.

In order to meet this requirement in independent subpackages, getApp supports the [allowDefault] parameter, which returns a default implementation when App is undefined. When the main package is loaded and the App is registered, the properties defined in the default implementation will be overwritten and merged into the real App.

Sample code:

  • In an independent subpackage
js
const app = getApp({ allowDefault: true }); // {}
app.data = 456;
app.global = {};
  • In app.js
js
App({
  data: 123,
  other: "hello",
});

console.log(getApp()); // {global: {}, data: 456, other: 'hello'}

2.3.2 About the App lifecycle

When launching a mini program from an independent subpackage, the onLaunch and first onShow of the App in the main package will be called when entering the main package or other ordinary subpackage pages for the first time from the independent subpackage page.

Since the App cannot be defined in an independent subpackage, the monitoring of the mini program lifecycle can be completed using wx.onAppShow, wx.onAppHideOther events on the App can be completed using wx.onError, wx.onPageNotFound Monitoring.

3. Subpackage pre-download

Developers can configure that when entering a page of the mini program, the framework automatically pre-downloads the subpackages that may be needed, which improves the startup speed when entering subsequent subpackage pages. Independent subpackage, You can also pre-download the main package

Subpackage pre-download is currently only supported by configuration, and is not supported by calling APIs.

TIP

There is a log message starting with preloadSubpackages in vConsole, which can be used to verify the pre-download situation.

3.1 Configuration method

The pre-download subpackage behavior is triggered when entering a certain page, and is controlled by adding preloadRule configuration in app.json.

js
{
  "pages": ["pages/index"],
  "subpackages": [
    {
      "root": "important",
      "pages": ["index"],
    },
    {
      "root": "sub1",
      "pages": ["index"],
    },
    {
      "name": "hello",
      "root": "path/to",
      "pages": ["index"]
    },
    {
      "root": "sub3",
      "pages": ["index"]
    },
    {
      "root": "indep",
      "pages": ["index"],
      "independent": true
    }
  ],
  "preloadRule": {
    "pages/index": {
      "network": "all",
      "packages": ["important"]
    },
    "sub1/index": {
      "packages": ["hello", "sub3"]
    },
    "sub3/index": {
      "packages": ["path/to"]
    },
    "indep/index": {
      "packages": ["__APP__"]
    }
  }
}

In preloadRule, key is the page path, and value is the pre-download configuration for entering this page. Each configuration has the following items:

FieldsTypeRequiredDefault valueDescription
packagesStringArrayYesNoneThe root or name of the pre-download subpackage after entering the page, __APP__ represents the main package
networkStringNowifiPre-download under the specified network, the optional values 1.all: Unlimited network 2.wifi: Pre-download only under wifi

3.2 Restrictions

Pages in the same subpackage share a common pre-download size limit of 2M, which will be checked when packaging in the tool.

For example, pages A and B are in the same subpackage, A pre-downloads subpackages with a total size of 0.5M, and B can only pre-download subpackages with a total size of 1.5M.

4. Subpackage asynchronization

In mini programs, different subpackages correspond to different download units; therefore, except that non-independent subpackages can rely on the main package, subpackages cannot use custom components or require each other. The "subpackage asynchronization" feature will allow some cross-subpackage content to be used asynchronously after waiting for download through some configurations and new interfaces, thereby solving this limitation to a certain extent.

4.1 Cross-subpackage custom component reference

When a subpackage uses custom components of other subpackages, because other subpackages have not been downloaded or injected, the components of other subpackages are in an unavailable state. By setting Placeholder components, , we can render the placeholder component as a substitute first, and then replace it after the subpackage is downloaded. For example:

js
// subPackageA/pages/index.json
{
  "usingComponents": {
    "button": "../../commonPackage/components/button",
    "list": "../../subPackageB/components/full-list",
    "simple-list": "../components/simple-list",
    "plugin-comp": "plugin://pluginInSubPackageB/comp"
  },
  "componentPlaceholder": {
    "button": "view",
    "list": "simple-list",
    "plugin-comp": "view"
  }
}

In this configuration, the two custom components button and list are cross-subpackage reference components. When button is rendered, the built-in component view is used as a substitute, and list is rendered with the custom component simple-list in the current subpackage as a substitute; after the two subpackages are downloaded, the placeholder component will be replaced with the corresponding cross-subpackage component.

4.2 Cross-subpackage JS code reference

When the code in a subpackage references the code in other subpackages, in order to prevent the download from blocking the code from running, we need to obtain the reference result asynchronously, such as:

js
// subPackageA/index.js
// Use a callback function style call
require('../subPackageB/utils.js', utils => {
  console.log(utils.whoami) // Wechat MiniProgram
}, ({mod, errMsg}) => {
  console.error(`path: ${mod}, ${errMsg}`)
})
// Or use a Promise-style call
require.async('../commonPackage/index.js').then(pkg => {
  pkg.getPackageName() // 'common'
}).catch(({mod, errMsg}) => {
  console.error(`path: ${mod}, ${errMsg}`)
})

For details, please refer to Modularization - require section, , we can render the placeholder component as a substitute first, and then replace it after the subpackage is downloaded. For example: