Cause of the matter
Recently I took over a small program, which is developed using the Taro framework. Because it is the first time to take over small procedures, encountered a lot of problems, in this record. As it was the first time to take over the small program, I was not very familiar with the development process of small program. During the development process, I suddenly found that I could not preview in dev mode, and the main package reported exceeded 2M.You can’t preview, and you can’t debug the real machine. If you need a real preview, you need to build it first, and you can’t debug it. Greatly affected the development efficiency and development experience.
To explore the reasons
Checking wechat developer documents, WE found that wechat has a limit on the size of a single package, and the size of a single package cannot exceed 2M. When building a applets subcontract project, the build outputs one or more subcontracts. Each subcontracting applet must contain a main package. The main package, which places the default startup page /TabBar page, and some common resource /JS scripts for all the subpackages; Subcontracting is divided according to the developer’s configuration.
When the small program starts, the main package will be downloaded and the page in the main package will be started by default. When the user enters a page in the subpackage, the client will download the corresponding subpackage and display it after downloading.
Currently, the subcontracting size of small program has the following limitations:
The size of all subcontracts of the entire small program shall not exceed 16M. The size of a single subcontract/main package shall not exceed 2MCopy the code
Subcontracting the applets optimizes the download time for the first startup of the applets and allows better decoupling and collaboration when multiple teams work together.
Principle of the subcontract
The applets directory structure is as follows:
├ ─ ─ app. Js ├ ─ ─ app. Json ├ ─ ─ app. WXSS ├ ─ ─ packageA │ └ ─ ─ pages │ ├ ─ ─ the cat │ └ ─ ─ dog ├ ─ ─ packageB │ └ ─ ─ pages │ ├ ─ ─ apple │ └ ─ ─ banana ├ ─ ─ pages │ ├ ─ ─ index │ └ ─ ─ logs └ ─ ─ utilsCopy the code
The developer declares the project subpackage structure in the app.json subpackages field:
{
"pages":[
"pages/index",
"pages/logs"
],
"subpackages": [
{
"root": "packageA",
"pages": [
"pages/cat",
"pages/dog"
]
}, {
"root": "packageB",
"name": "pack2",
"pages": [
"pages/apple",
"pages/banana"
]
}
]
}
Copy the code
Packaging principles
- Subpackages will be packaged by subPackages configuration path. Directories outside the subPackages configuration path will be packaged into APP (main package) (important)
- An APP (main package) can also have its own Pages (the outermost Pages field)
- The root directory of a subpackage cannot be a subdirectory within another subpackage
- TabBar pages must be in the APP (main package)
Refer to the principle of
- PackageA cannot require packageB JS files, but can require JS files in app and its own package
- PackageA cannot import packageB templates, but can require templates in app and its own package
- PackageA cannot use packageB resources, but can use resources in app and its own package
Special subcontracting — independent subcontracting
Independent subcontracting is a special type of subcontracting in small programs that can operate independently of the main package and other subcontracting. There is no need to download the main package when entering the applet from the standalone subcontracting page. The main package is downloaded only when the user enters the normal package or main package page.
Developers can configure certain functional independence pages into independent subcontracting as needed. When the applets start from the normal subcontracting page, the main package needs to be downloaded first; Independent subcontracting can run independently of the main package, which can greatly improve the startup speed of the subcontracting page.
You can have multiple independent subcontractors in a small program
Restrictions on independent subcontracting
- Independent packages cannot rely on the contents of the main package and other packages, including JS files, templates, WXSS, custom components, plug-ins, and so on. App.wxss in the main package is not valid for individual subcontracting, so avoid using the style in App.wxSS in individual subcontracting pages;
- App can only be defined in the main package. App cannot be defined in independent subcontracting, which will cause unexpected behavior.
- Plugins are not currently supported in standalone subcontracting.
In summary, it can be understood that independent subcontracting exists independently and cannot rely on any type of document outside its own file.
Considerations for independent subcontracting
(1) getApp()
Unlike normal subcontracting, when standalone subcontracting runs, App is not necessarily registered, so getApp() does not necessarily get the App object:
- When the user starts the applet from the independent subcontract page, the main package does not exist, and the App does not exist. In this case, getApp() gets undefined. The main package will be downloaded and the App will be registered only when the user enters the page of ordinary subpackage or main package.
- When the user jumps from the page of ordinary subcontracting or the page of main package to the page of independent subcontracting, the main package already exists, and the real App can be obtained by calling getApp().
Because of this limitation, developers cannot implement independent subcontracting and global variable sharing from other parts of the applet through App objects.
To meet this requirement in standalone subcontracting, the base library version 2.2.4 starts with getApp supporting the [allowDefault] parameter, returning a default implementation if App is not defined. When the main package is loaded and the App is registered, the properties defined in the default implementation are overridden and merged into the real App.
const app = getApp({allowDefault: true}) // {}
app.data = 456
app.global = {}
Copy the code
(2) About App life cycle
The onLaunch and first onShow of the App in the main package are called when the main package or other normal package pages are first entered from the independent package page when the applet is launched from the independent package page.
Since App cannot be defined in independent subcontracting, monitoring of the applet life cycle can be done using wx.onAppShow, wx.onAppHide. Other events on the App can be listened for using wx.onError, wx.onPageNotFound.
Subcontract predownload
In order to give the customer a better experience and reduce the user’s wait time, subcontract preloading can be carried out.
Base library 2.3.0 starts to support, earlier versions need to be compatible processing. Please use version 1.02.1808300 or later for developer tools, download here.Copy the code
Configuration method
The preload subcontract behavior is triggered when entering a page and is controlled by adding a preloadRule configuration to app.json.
{
"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__"]
}
}
}
Copy the code
Preloading limit
Pages in the same subcontract have a common pre-download size limit of 2M, which is verified when packaged in the tool. For example, both page A and page B are in the same subcontract. Subcontract with A total size of 0.5m can be pre-downloaded in A, and subcontract with A total size of 1.5m can be pre-downloaded in B at most.Copy the code
To solve the problem
The project is analyzed first by analyzing the package volume using the Webpack-bundle-Analyzer plug-in.
$NPM install webpack-bundle-Analyzer -d $yarn add --dev webpack-bundle-AnalyzerCopy the code
Then add the following configuration to mini. WebpackChain.
const config = {
mini: {
webpackChain (chain, webpack) {
chain.plugin('analyzer')
.use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin, [])
}
}
}
Copy the code
The startup TAB will then display this analysis diagram
You can see the specific dependencies for each file and the size of the dependent file by clicking the Stat button of Treemap Sizes: in the navigation on the left. You can view your main package about those files are relatively large, you can have for compression and migration.
After I analyzed the project, I found that vendors.js and common.js had the highest percentage of sizes. So let’s solve for these two.
In 2.x, four public files are extracted by default, respectively
- Runtime: WebPack runtime entry
- Vendors: node_modules files are removed
- Taro: remove taro dependencies in node_modules
- Common: Business code common files are removed from the project
To reduce the vendors. Js
Since vendors default to pulling out the node_modules file for all references except the Taro dependencies, if developers introduce too many NPM packages themselves, vendors. Js can become too large, with a fix: One is to use NPM packages as little as possible, and the other is to configure finer splitting yourself. Now configure the second method. For example, if loDash is introduced, since LoDash itself is relatively large, you can configure mini. WebpackChain to separate LoDash
const config = {
mini: {
webpackChain (chain, webpack) {
chain.merge({
optimization: {
splitChunks: {
cacheGroups: {
lodash: {
name: 'lodash',
priority: 1000,
test (module) {
return /node_modules[\\/]lodash/.test(module.context)
}
}
}
}
}
})
}
}
}
Copy the code
The LoDash public files need to be added through the mini.monchunks configuration
const config = {
mini: {
commonChunks (commonChunks) {
commonChunks.push('lodash')
return commonChunks
}
}
}
Copy the code
This allows loDash-related dependencies to be extracted separately into LoDash.js, enabling unaggregation of vendors
To reduce the common. Js
Common.js is a common file for the business code in your project. Includes public components and global utils, static files, public variable definition files, etc. The following figureThese all lead to the main package being too large. Therefore, projects can be modularized according to business requirements, with each module having its own components, apis, and stores. Try to integrate related modules under a subpackage. Only modules that are closely related or modules or components that are needed globally are put into the main package (including TabBar pages). Reduce the main package size as much as possible.
The project structure is divided. Subcontract according to relevance. Within each subcontract there is a folder for the components of that subcontract. The following figure
This preserves extensibility. In the future, if new business needs are added, which subcontract can be written into or new subcontract folder can be opened according to the business associated line. But be aware of the limitations of applets
Written in the end
Summary of subcontracting for small procedures:
- Subcontracting begins at the time of development
- Modularize the project, putting closely related business and modules into the same subcontract
- Put public controls that are not used globally into subcontracting
- Do not put stores, apis, or static files that are not used globally into the main package
- Minimize references to NPM packages
- Use mini. WebpackChain to split reference files in node_modules
So far my personal opinion on subcontracting strategies for small programs has been written. The understanding of small program is not very sufficient, if there is an error please do not hesitate to point out. There is a better solution to the subcontracting problem welcome to share.
Reference documentation
Wechat document – subcontract loading. Taro’s website