Why write this article

Presumably, students who have used Taro to develop large small program applications often encounter such a problem: the main package size of small programs exceeds 2M, and there is no way to preview and release.

Package restrictions given on the official website of wechat applet:

At present, the size of small program subcontract has the following restrictions:

  • The subcontract size of the whole small program shall not exceed 20M
  • The size of a single subcontract or main package cannot exceed 2M

Why is it so easy to use Taro and the main package is oversubscribed? Is it the framework or am I using it the wrong way? Uh uh uh…

Those of you who have used Taro development know that the code we write will eventually go through the webpack plug-in SplitChunksPlugin to split chunks. Taro’s complete default configuration of this plug-in can be seen here

.common: {
  name: config.isBuildPlugin ? 'plugin/common' : 'common'.minChunks: 2.priority: 1}...Copy the code

Any file referenced by both chunks is packaged into the common of the main package, but each page of our subcontract is packaged into a separate chunk. That is, if two pages in the subcontract refer to the same file, the file will be packaged into common.js, which is obviously not what we want.

After understanding the cause and effect, we naturally have to solve it. This is also the reason why I write this article. I hope to give students with this problem some of their own experience and suggestions.

Next, I will introduce some effective ways to reduce the size of the main package, including Taro2x and 3X, such as the usual methods: reducing the use of local images, importing components as needed, removing useless code, and so on.

Methods for reducing the volume of the main package:

Use what the framework itself providesoptimizeMainPackage

module.exports = {
  // ...
  mini: {
    // ...
    optimizeMainPackage: {
      enable: true}}}Copy the code

This feature was supported in version 3.2.9, but it was not fixed until 3.2.12. But there are still a few problems,

  1. In the development environment, an error will be reported that a file can not be found, you can see the specific reason for this issue, it seems that it has not been fixed. Solution:

    • There is a comment in the issue that the temporary sub-common should be moved out of the project to avoid being monitored by the IDE. The need to change under the node_modules @ tarojs/mini – runner/dist/plugins/MiniSplitChunksPlugin js file.

    • This function can only be enabled in the production environment. Add the above configuration under config/prod.js. For lazy students, you can do this first.

  2. Cannot Read Property ‘getCacheGroup’ of NULL

2. Imitate optimizeMainPackage

Someone has an taro version earlier than 3.2.9 and cannot upgrade to 3.2.9. What should I do? The first approach is essentially a WebPack plug-in, so let’s find an Taro project that supports optimizeMainPackage, Copy node_modules / @ tarojs/mini – runner/dist/plugins/MiniSplitChunksPlugin js, put in your own project as a local plug-in, through webpackChain import plug-in is not line?

This method is slightly different in taro2X and TARo3X configurations, which I describe below:

taro3x

Taro3x is very simple, just do the following configuration.

// config/index.js
const MiniSplitChunksPlugin = require('The location of the file where you copied the code.'); .webpackChain: function (chain) {
  chain.plugin('optimizeMainPackage')
  	// We added before because the plugin must execute before the miniPlugin
    .use(MiniSplitChunksPlugin, [{ exclude: true }]).before('miniPlugin'); }...Copy the code
taro2x

Taro2x is a bit of a problem.

  1. To be modifiedMiniSplitChunksPlugin.jsFiles, because he uses them a lottarojs/helperMany auxiliary methods of tarO2 are not available, so we need to supplement them.
  2. I need to add oneapp.config.jsTaro3 has been changed to use app.config.js as the routing configuration file.

This method changes a lot on the whole, and it is troublesome to configure app.js and app.config.js for each new page. Because the configuration down the code is more, I will not stick here, there is a need to project clone down to see their own.

If you are interested and capable, you can change the code of the plug-in by yourself. You can go directly to app. TSX to read the configuration, so that you do not need to use app.config.js.

3. Modify splitChunks

To tell the truth, with the above two methods, basically can meet all kinds of situations. For those who find the appellate approach to TarO2.x too cumbersome, an alternative approach is provided for reference. AddChunkPages is an official capability that is configured to separate the subcontract public files via webPack configuration optimization.splitChunks, and then to import the subcontract public files for the subcontract page via mini-.addChunkPages.

For example, have the following directory structure:

└ ─ ─ the SRC ├ ─ ─ page# main package│ ├── index │ ├── index# the subcontract├ ─ ─ page1 ├ ─ ─ index. The TSX# refers to utils.ts├ ─ ─ page2 ├ ─ ─ index. The TSX# refers to utils.ts├ ─ ─ utils. TsCopy the code

We want the utils to be packaged only into the subpackage, so we can do this:

addChunkPages(pages, pagesNames) {
  pagesNames.forEach(pagename= > {
    if (/subpackage\//.test(pagename)) {
      pages.set(pagename, ['subpackage/subpackage-common']); }}); },webpackChain: function (chain) {
   chain.merge({
     optimization: {
       splitChunks: {
         cacheGroups: {
           subpackage: {
             name: 'subpackage/subpackage-common'.minChunks: 2.test: (module, chunks) = > {
               return /\/subpackage\//.test(module.resource)
             },
             priority: 200}}}}})}Copy the code

Once packaged, utils. Ts is packaged under subpackage/subpackage-common.js.

Iv. Mixed development

It is believed that many people, in contact with and use taro, there has been a use of native code development of a small program, and a short time can not be abandoned, so there is the use of TARO development, packaging completed copy code into the main package, as a subcontract.

The subpackage is copied to the main package after it is packaged, so there is no need for subpackages to be packaged into common.js of the main package. This is also a way to reduce the size of the main package.

taro2x
  1. Create an empty applets environment (applets packaged with Taro do not work, for reasons unknown) and use them as the main package. Your main package may provide some common variables, methods for each subpackage to use, which can be mounted on the applet’s App instance.

    // app.js
    import sdk from "./sdk"
    App({
    	...
      SDK: sdk,
      ...
    })
    
    // Reference in subcontracting
    const app = Taro.getApp();
    app.SDK.request();
    Copy the code
  2. Use Taro to create your subcontract. As it is directly used as a subcontract, the app.js file packaged with taro will not be executed. We can only manually introduce some of its dependencies to each page.

    // config/index.js
    mini: {...outputRoot: 'Where do you put the subcontract on the main package?'.// Import app.js for each subcontracted page
      addChunkPages(pages, pagesNames) {
        pagesNames.forEach(page= > {
         	// Vendors may not be available, so you can just copy the require in the packaged app.js header
            pages.set(page, ['runtime'.'common'.'vendors'])}); },... }Copy the code

    For those of you who might find it difficult to decide if you have this file, I’ve also provided a webPack plugin to help you add it automatically (using the code from Taro’s plugin-indie).

    // config/index.js.webpackChain(chain, webpack) {
      chain.plugin('AutoRequirePlugin').use(new AutoRequirePlugin())
    },
    ...
    Copy the code
    / / webpack plug-in
    const { ConcatSource } = require('webpack-sources')
    const path = require('path');
    
    class AutoRequirePlugin {
      constructor(event) {
        this.needRequireChunkNames = ['runtime'.'common'.'vendors'.'taro'];
      }
    
      addRequireToSource(id, modules, needRequireChunks) {
        const source = new ConcatSource()
        needRequireChunks.forEach(chunk= > {
          source.add(`require(The ${JSON.stringify(this.promoteRelativePath(path.relative(id, chunk.name)))}); \n`)
        })
        source.add('\n')
        source.add(modules)
        source.add('; ')
        return source
      }
    
      promoteRelativePath(fPath) {
        const fPathArr = fPath.split(path.sep);
        let dotCount = 0;
        fPathArr.forEach(item= > {
          if (item.indexOf('.. ') > =0) { dotCount++; }});if (dotCount === 1) {
          fPathArr.splice(0.1.'. ');
          return fPathArr.join('/');
        }
        if (dotCount > 1) {
          fPathArr.splice(0.1);
          return fPathArr.join('/');
        }
        return normalizePath(fPath);
      }
    
      getIdOrName(chunk) {
        if (typeof chunk.id === 'string') {
          return chunk.id
        }
        return chunk.name
      }
    
      apply(compiler) {
        compiler.hooks.make.tap('AutoRequirePlugin'.(compilation) = > {
          let needRequireChunks = [];
          compilation.hooks.afterOptimizeChunks.tap('afterOptimizeChunks'.(chunks) = > {
            needRequireChunks = chunks.filter(chunk= > this.needRequireChunkNames.includes(chunk.name)).reverse();
          })
          compilation.chunkTemplate.hooks.renderWithEntry.tap('renderWithEntry'.(modules, chunk) = > {
            if(! chunk.entryModule)return
            const entryModule = chunk.entryModule.rootModule ? chunk.entryModule.rootModule : chunk.entryModule
            const { miniType } = entryModule
            const id = this.getIdOrName(chunk)
            if (miniType === 'PAGE' || miniType === 'STATIC') {
              return this.addRequireToSource(id, modules, needRequireChunks)
            }
          })
        })
      }
    }
    
    module.exports = AutoRequirePlugin; 
    Copy the code
taro3x

Taro’s official website says that taro3.0.25+ provides this hybrid development capability, the specific can see the document, very detailed.

conclusion

These are several ways I can summarize to use TARO to reduce the size of the main package. You can choose one suitable for your business scenario.

Due to personal ability and limited time, not every method is thoroughly researched, and also can not guarantee, after my magic change the code will not have a problem. The main purpose of this article is to provide an idea for reducing the volume of packets. If you guys have a better way or find something wrong, feel free to point it out.