How do small programs subcontract

background

2017.01.09 When the mini program was launched, the official limit of code package size can not exceed 1MB, the purpose is to consider the speed of the small program, hope users can use any small program, can get a “second on” experience. However, the 1MB size also limits the extension of applets’ capabilities, and the growth of applets’ business may require a larger size.

So, is there a way to increase the size of small packages while still maintaining decent startup speed?

In order to solve this contradiction, the official launch of “subcontracting loading” this technical solution.

Introduction to subcontracting loading

In the subcontract project, build a small program to build outputs one or more of the functions of the subcontract, a small program that each subcontractor must contain a main package, the so-called master package, which placed the default start page/TabBar page, as well as some public resources/JS script used by all the subcontract, the subcontract is according to the configuration of the developer.

When the small program starts, the main package will be downloaded and the page in the main package will be started by default. If the user needs to open a page in the subpackage, the client will download the corresponding subpackage and display it after downloading.

Advantages:

  • For developers, it can make small programs have larger code volume, bearing more functions and services
  • For users, you can open small programs faster and use more features without affecting startup speed

Limitations:

  • The subcontracting size of the whole small program does not exceed 8M
  • The size of a single subcontract/main package cannot exceed 2M

Configuration of subcontract loading

Suppose the applets that support subcontracting have the following directory structure:

├ ─ ─ 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"."pages": [
        "pages/apple"."pages/banana"]]}}Copy the code

### Principle of subcontracting

  • After subPackages are declared, directories outside the subPackages configuration path will be packaged into APP (main package)
  • 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
  • The TAB page of the home page 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

How to subcontract using MPVue?

Package. The json

  • Update: “mpvue – loader”, “^ 1.1.2 – rc. 4” “webpack – mpvue – asset – the plugin” : “^ while”
  • Added: “relative”: “^3.0.2”

Matters needing attention

  • 1.1.2-RC. 5 Fixed slot file path generation error
  • The 1.1.x version is not very stable. Projects requiring high stability are advised to use the 1.1.x version for the time being

src/main.js

Delete the config

-export default {-- // Go to app.json -config: {- // pages with the ^ symbol at the front of the page will be compiled into the home page, other pages can be optional, we will automatically add webpack entry pages: ['pages/logs/main'.'^pages/index/main'],
-    window: {
-      backgroundTextStyle: 'light',
-      navigationBarBackgroundColor: '#fff',
-      navigationBarTitleText: 'WeChat',
-      navigationBarTextStyle: 'black'-} -} -}Copy the code

SRC /main.json(new file is the same as main.js)

Migrate the config from the original JS to the main.json file

Note: Subcontracting should be in the same root directory as the main package

main.json

+{
+ "pages": [+"pages/index/main",
+   "pages/logs/main"+ +]"subPackages": [+ {+"root": "pages/packageA",
+     "pages": [+"counter/main"+] +} +], +"window": {+"backgroundTextStyle": "light",
+ "navigationBarBackgroundColor": "#fff",
+ "navigationBarTitleText": "WeChat",
+ "navigationBarTextStyle": "black"+}}Copy the code

Webpack configuration works with the upgrade guide

  • build/webpack.base.conf.js
// build/webpack.base.conf.js

+var CopyWebpackPlugin = require('copy-webpack-plugin')
+var relative = require('relative')

 function resolve (dir) {
   return path.join(__dirname, '.. ', dir)
 }

-function getEntry (rootSrc, pattern) {
-  var files = glob.sync(path.resolve(rootSrc, pattern))
-  return files.reduce((res, file) => {
-    var info = path.parse(file)
-    var key = info.dir.slice(rootSrc.length + 1) + '/' + info.name
-    res[key] = path.resolve(file)
-    return res
-  }, {})
+function getEntry (rootSrc) {
+  var map = {};
+  glob.sync(rootSrc + '/pages/**/main.js')
+  .forEach(file => {
+    var key = relative(rootSrc, file).replace('.js'.' '); + map[key] = file; + +})return map;
 }

const appEntry = { app: resolve('./src/main.js') }
 const pagesEntry = getEntry(resolve('./src'), 'pages/**/main.js') const entry = object. assign({}, appEntry, pagesEntry) @@-105,6 +122,14 @@module. Exports = {]}, plugins: [ - new MpvuePlugin() + new MpvuePlugin(), + new CopyWebpackPlugin([{ + from:'**/*.json',
+      to: 'app.json'
+    }], {
+      context: 'src/'}), + new CopyWebpackPlugin({+ from: path.resolve(__dirname,)), + {+ from: path.resolve(__dirname,)'.. /static'),
+        to: path.resolve(__dirname, '.. /dist/static'),
+        ignore: ['*'] +} +])]}Copy the code
  • build/webpack.dev.conf.js

Modify the path of the generated file so that the generated file path can be placed under the original page

module.exports = merge(baseWebpackConfig, {
   devtool: '#source-map',
   output: {
     path: config.build.assetsRoot,
-    filename: utils.assetsPath('js/[name].js'),
-    chunkFilename: utils.assetsPath('js/[id].js')
+    filename: utils.assetsPath('[name].js'),
+    chunkFilename: utils.assetsPath('[id].js') }, plugins: [new webpack.defineplugin ({@@-exports = new webpack.defineplugin ({@@-exports = new webpack.defineplugin ({@@-exports = new webpack.defineplugin ({@@module.exports = new webpackconfig, { // copy from ./webpack.prod.conf.js // extract css into its own file new ExtractTextPlugin({ - filename: utils.assetsPath('css/[name].wxss')
+      filename: utils.assetsPath('[name].wxss'}), @@module. Exports = merge(baseWebpackConfig, {}}), new webpack.optimize.CommonsChunkPlugin({ - name:'vendor',
+      name: 'common/vendor',
       minChunks: function (module, count) {
         // any required modules inside node_modules are extracted to vendor
         return(@ @ 64, + 64, 9. @ @ the module exports = merge (baseWebpackConfig, {}}), the new webpack.optimize.Com monsChunkPlugin ({name: -'manifest',
-      chunks: ['vendor']
+      name: 'common/manifest',
+      chunks: ['common/vendor']
     }),
-    // copy custom static assets
-    new CopyWebpackPlugin([
-      {
-        from: path.resolve(__dirname, '.. /static'),
-        to: config.build.assetsSubDirectory,
-        ignore: ['*'] -} -]),Copy the code
  • build/webpack.prod.conf.js

With the build/webpack. Dev. Conf. Js

@ @ - 24, 10 + 24, 10 @ @ var webpackConfig = merge (baseWebpackConfig, {devtool: config. Build. ProductionSourceMap?'#source-map' : false,
   output: {
     path: config.build.assetsRoot,
-    filename: utils.assetsPath('js/[name].js'),
-    chunkFilename: utils.assetsPath('js/[id].js')
+    filename: utils.assetsPath('[name].js'),
+    chunkFilename: utils.assetsPath('[id].js') }, plugins: [/ / @ @ http://vuejs.github.io/vue-loader/en/workflow/production.html - 39, 8 + 8 @ @ var webpackConfig = 39 merge(baseWebpackConfig, { }), // extract css into its own file new ExtractTextPlugin({ - // filename: utils.assetsPath('css/[name].[contenthash].css')
-      filename: utils.assetsPath('css/[name].wxss')
+      // filename: utils.assetsPath('[name].[contenthash].css')
+      filename: utils.assetsPath('[name].wxss')}), // Compress extracted CSS. We are using this plugin so that possible // duplicated CSS from different components can be Deduped. @ @ + 72-72, 7, 7 @ @ var webpackConfig = merge (baseWebpackConfig, {new webpack. HashedModuleIdsPlugin (), // split vendor js into its own file new webpack.optimize.CommonsChunkPlugin({ - name:'vendor',
+      name: 'common/vendor',
       minChunks: function (module, count) {
         // any required modules inside node_modules are extracted to vendor
         return(@@-85,17 +85,9 @@var webpackConfig = merge(baseWebpackConfig, { // extract webpack runtime and module manifest to its own filein order to
     // prevent vendor hash from being updated whenever app bundle is updated
     new webpack.optimize.CommonsChunkPlugin({
-      name: 'manifest',
-      chunks: ['vendor']
-    }),
+      name: 'common/manifest',
+      chunks: ['common/vendor']
+    })
-    // copy custom static assets
-    new CopyWebpackPlugin([
-      {
-        from: path.resolve(__dirname, '.. /static'),
-        to: config.build.assetsSubDirectory,
-        ignore: ['*'[-} -])]})Copy the code
  • config/index.js
module.exports = {
     env: require('./prod.env'),
     index: path.resolve(__dirname, '.. /dist/index.html'),
     assetsRoot: path.resolve(__dirname, '.. /dist'),
-    assetsSubDirectory: 'static'+ assetsSubDirectory:' ',
     assetsPublicPath: '/',
     productionSourceMap: false, // Gzip off by default as many popular static hosts such as @@-26,7 +26,7 @@module. exports = {port: 8080, // No need to automatically open the browser autoOpenBrowser in applets developer tools:false,
-    assetsSubDirectory: 'static'+ assetsSubDirectory:' ',
     assetsPublicPath: '/',
     proxyTable: {},
     // CSS Sourcemaps off by default because relative paths are "buggy"

Copy the code