Small program multi-line integration "full subcontracting service access"

Source: Internet
Author: User
Tags vars
Application Scenarios
    • Multiple small programs under the same subject (company, Department)
    • These small programs, consisting of a master applet and later new lines of business (each line of business has a separate applet)
    • Small programs for each line of business need to be mounted under the main program, as the main program diversion
    • At the same time, the business lines of their own applet also released as usual update
    • = = A set of code, to generate a separate package and sub-package = = (the subpages directory that needs to be copied to the main program by the package command)
Project Overview

My line of business is called Happy Delivery (project name Enjoy_given), is a free exchange of things platform

Because our line-of-business applet is built with Mpvue (the entire project is also generated through the Mpvue CLI), the subsequent configuration is Mpvue for example, and if the Wepy project is basically similar.

Here's our directory structure.

Several JS files under the SRC directory need to be specifically described below:

Src/app.vue is a small program's entry file, which defines the life cycle of the applet.

Src/main.js inside Initializes common services, defines applet page paths, and global variables

Src/vars.js storing global variables for the entire project

Src/baseinstall.js Basic Method assembly logic (e.g. mount Login to Vue object, statistical logic, identify channel number, etc.)

Overview of subcontracting Configurations
  • First, you configure the source and AppID

    As a sub-package, both parameters should be unified with the main package parameters (recommended through the Webpack configuration to implement)

    Source: Is the identity used by each line of business to log in, register, and interface access, to distinguish which line of business the user is from

    AppID: Assigned applet AppID

    Why do you configure these two parameters: because you cannot log on without configuring

  • Page path Issues

    As a sub-package, all pages of the jump path will be added to the main package jump prefix (recommended through the packaging jump method NavigateTo, Redirectto, relaunch, Navigateback implementation, recommended with Webpack unified processing)

    When a new line of business is used as a sub-package to access the main program, the page jump path needs to be preceded by a prefix

    Such as: The Independent applet home path is/pages/content/index/main

    As a subcontractor, the package assigned by the main program is/subpages/enjoy_given

    Then the subcontract line of business lines home path:/subpages/enjoy_given/pages/content/index/main

  • WXSS Reference Path problem

    Do not use the introduction of the root directory (recommended by Webpack or shell script to complete)

    Because in the sub-state, the root directory is accessed directly from the root directory of the main program, the file does not exist

  • Picture path problem

    All image paths uniformly use CDN resource access, do not reference local images

  • Issues that are not performed for subcontracting Main.js and App.vue entry files

    It is possible to introduce each entry from the main package to the sub-package page by pulling out the basic business assembly method, which will be followed by

  • For h5 pages in small programs pull up applet page

    When opening webview, to add a flag bit, or prefix, tell H5 page, currently in the sub-package, open the applet path to prefix

  • Share path problem, prefix path is also added before path

    Can be handled uniformly through a common sharing method, followed by

  • All pages of the applet need to be registered in the main package entry file (App.vue), and each new page must be registered

    This is a hole, especially when the new page, it will be easy to ignore this problem, here to highlight the next

Where to pay attention to sub-package access
    • Storage naming issues, in order to avoid conflicts with the main program or other Business Line applet (recommended zz_ business name _xxx, our business name is Enjoy_given, for short, eg, such as: Zz_eg_address, ZZ refers to the transfer)

    • Login problem, the recommendation and the main program use the same cookie name, this can be a common set of user information, so that both sides maintain a set, but also avoid duplication of authorization.

    • Payment issues to ensure that the parameters in the cookie remain the same when the order is placed and when the payment is made

    • debugging, you can brahma the program to a test package for the main program, copy the generated code (contents of the Dist directory) to the main package subpages/business name/below

      For example, our directory is subpages/enjoy_given/(same as the directory structure)

A set of code that generates corresponding packages (separate packages and subcontracting) with different packaging commands

Package.json in Scripts

"scripts": {    "dev": "node build/dev-server.js",    "start": "node build/dev-server.js",    "build": "rimraf dist && node build/build.js",    "lint": "eslint --ext .js,.vue src",    "build_subPkg": "node build/build-subpkg.js && sh ./scripts/path-replace.sh"}
独立小程序(调试) npm run dev独立小程序(构建) npm run build主程序分包(构建) npm run build_subPkg
Why no main program subcontracting (test)

Because whether we build test subcontracting or build formal subcontracting, we have to copy the code under the generated dist to the subpages/enjoy_given/directory of the main program, the cost is basically the same, so there is no command to write the component sub-package

Subcontracting Webpack Configuration

Because of the need to be compatible with separate small programs and subcontracting services, Webpack we recommend separate configuration

We have configured Webpack for the test environment and the formal environment, and modify the global parameters of the project directly by replacing the global variables with the Webpack configuration .
Perform the replacement dynamically with the NPM command.

In order to separate the configuration, we copied a copy of build.js renamed Build-subpkg.js

"scripts": {    ...,    "build_subPkg": "node build/build-subpkg.js && sh ./scripts/path-replace.sh"}

The BUILD_SUBPKG command is the read Build-subpkg.js file
Build.js and Build-subpkg.js 99% of the same content, only one line is different

var webpackConfig = require('./webpack.prod.conf')变更为var webpackConfig = require('./webpack.subpkg.prod.conf')

So the next step is to create the webpack.subpkg.prod.conf file
webpack.subpkg.prod.conf by webpack.prod.conf Copy, inside still 99% content consistent

Webpack.prod.conf

...var config = require('../config')var env = config.build.env...var webpackConfig = merge(baseWebpackConfig, {    ...    plugins: [        new webpack.DefinePlugin({            'process.env': env,            'app.source': env.APP_SOURCE,            'app.udeskDebug': env.UDESK_DEBUG,            'app.id': env.APP_ID,            'app.pathPrefix': env.APP_PATH_RREFIX,            'app.isUseCrazyFormId': env.IS_USE_CRAZY_FORMD_ID        }),        ...    ]})

Webpack.subpkg.prod.conf

...var config = require('../config')var env = config.build.env...var webpackConfig = merge(baseWebpackConfig, {    ...    plugins: [        new webpack.DefinePlugin({            'process.env': env,            'app.source': env.APP_SUB_PKG_SOURCE,            'app.udeskDebug': env.UDESK_DEBUG,            'app.id': env.APP_SUB_PKG_ID,            'app.pathPrefix': env.APP_SUB_PKG_PATH_RREFIX,            'app.isUseCrazyFormId': env.IS_USE_CRAZY_FORMD_ID        }),        ...    ]})

The Defineplugin plugin is used for global substitution
such as: ' Process.env ': ' hahaha ', refers to the global process.env replaced by "hahaha"

Inside, by defining multiple global variables, when packaging is implemented, the global variables in the corresponding environment are replaced by different commands.
Let's take a look. Files in/config/index.js

var path = require('path')module.exports = {  build: {    env: require('./prod.env'),    ...  },  dev: {    env: require('./dev.env'),    ...  }}

Introduced Dev.env.js and Prod.env.js.

Taking Prod.env.js as an example

module.exports = {  // 环境  NODE_ENV: '"production"',  // 欢乐送独立小程序source  APP_SOURCE: '114',  // 欢乐送分包小程序source  APP_SUB_PKG_SOURCE: '103',  // 欢乐送独立程序appid  APP_ID: '"wxaaaaaaaaaaaaaaa"',  // 欢乐送分包程序appid  APP_SUB_PKG_ID: '"wxbbbbbbbbbbbbbbbb"',  // udesk测试标志位  UDESK_DEBUG: false,  // 欢乐送独立小程序页面路径前缀  APP_PATH_RREFIX: '""',  // 欢乐送分包小程序页面路径前缀  APP_SUB_PKG_PATH_RREFIX: '"/subPages/enjoy_given"',  // 是否启用crazyFormId  IS_USE_CRAZY_FORMD_ID: true}

And then we'll take a look at the file src/vars.js that holds the global variable (in the item above)

// 小程序常量export default {  ...  // 小程序版本号  version: '1.3.5',  // 小程序appid  appId: app.id,  // 小程序source(由webpack根据不同环境统一替换)  source: app.source,  // 路径前缀  pathPrefix: app.pathPrefix,  // 是否启用CrazyFormId  isUseCrazyFormId: app.isUseCrazyFormId}
var webpackConfig = merge(baseWebpackConfig, {    ...    plugins: [        new webpack.DefinePlugin({            'process.env': env,            'app.source': env.APP_SUB_PKG_SOURCE,            'app.udeskDebug': env.UDESK_DEBUG,            'app.id': env.APP_SUB_PKG_ID,            'app.pathPrefix': env.APP_SUB_PKG_PATH_RREFIX,            'app.isUseCrazyFormId': env.IS_USE_CRAZY_FORMD_ID        }),        ...    ]})

After packaging is complete, "app.xxx" in the global variable file is replaced by the variable with the same name in the Webpack.

If the appId:app.id app.id in Vars.js is replaced, the value is "WXAAAAAAAAAAAAAAA" when the standalone applet is "WXBBBBBBBBBBBBBB" when it is a subcontracting business

So the whole process of replacing global variables runs out.

= = as a sub-package, access to the main program, their own main.js and App.vue will not execute = =

This is the big pit, because many of the common business initialization such as login, cookie, statistics are done here.

Solution Solutions

The basic functions of the Assembly business (such as recording, statistics, identification channel number and other logic) from Main.js to another file, I called baseinstall.js here.
I also joined in the processing of query, such as channel number and entrance scene.

In that case, the src/main.js will be very simple,

import Vue from 'vue'import App from './App'import baseInstall from './baseInstall'App.mpType = 'app'baseInstall.init()  // !!!最关键就是这行代码!!!const app = new Vue(App)app.$mount()export default {  config: {    pages: [      '^pages/content/index/main',            // 首页      ...    ],    window: {      ...    }  }}

The key is Baseinstall.init () This line of code

Now let's take a look at baseinstall.js.

// 通用业务装配初始化...async function init (opts) {  let options = opts  ...  // 获取指定渠道号  const channel = options.channel || options.c || ''  // 设置渠道号  if (channel) {    VARS.channel = channel.indexOf('waeg_') === 0 ? channel : ('waeg_' + channel)  }  ...  if (!VARS.baseInstallFlag) {    // 为了避免重复装备,通过标志位进行区分    VARS.baseInstallFlag = true    ...    // 登录配置    ZZLogin.config({      source: VARS.source    })    ZZLogin.install()    Navigator.install()    // 统计    LeStatic.config({      appid: VARS.source,      pageTypePrefix (currentRoute) {        return 'waeg_'      }    }).install()    ...  }  // 写入cookie  cookie.set({    channelid: VARS.channel,    fromShareUid: VARS.shareUid  })  return options}export default {  init}
Why use the VARS.BASEINSTALLFLAG flag bit

Because, in the subcontracting time does not perform the main.js, the actual scene, will jump from the main package business directly to some sub-package of the page.

Because there is no fixed entrance, so in these pages to join the introduction of baseinstall.js, in order to avoid repeated assembly, will be set this flag bit.

Why do you want to pull these operations away?

The baseinstall.init contains all the services that need to be initialized when starting a small program

It is also mentioned that in the case of subcontracting, your own App.vue and main.js will not be executed.

So, on all pages, add the Baseinstall.init method to the OnLoad life cycle.
, so we have to pull away for a more convenient reuse.

Take home page for example (Pages/content/index/index.vue)

import baseInstall from '@/baseInstall'export default {    ...    async onLoad (options) {        options = await baseInstall.init(options)        ...    }}

Async/await is used because some logic in Baseinstall.init uses asynchronous requests

Because the main program does not read main.js, all the subcontracting page paths must be registered in the main program uniformly.

Note: Each new page will be registered in the main program. That is, to add a page, notify the main program side, in their files unified registration

Page path

In subcontracting, all page path accesses are prefixed

such as: The original visit/pages/content/index/main can be

However, the access path for the subcontracting is:/subpages/enjoy_given/pages/content/index/main

Solution:

Take the navigateto of packing as an example

async navigateTo (route) {    route.url = VARS.pathPrefix + (route.url.indexOf('/') === 0 ? '' : '/') + route.url // 这里做前缀处理    console.log('[Navigator] navigateTo:', route)    ...    wx.navigateTo(route)}

This requires no prefix, which is determined by the Pathprefix in the global variable VARs.

And Pathprefix is dynamically replaced by Webpack according to the packaging commands during the packaging process.

Picture Access Path Issues

Image access Path unifies the resource access path of the CDN, do not use the local access path, otherwise there is a problem in the subcontracting path, but also increase the volume of the package

WXSS path problem

The Wxss file generated by Mpvue will be introduced into the generic VENDOR.WXSS, but the introduction path is the root path, and as a sub-package, the root path is directly introduced and the path of the main package is accessed, resulting in the file not being found.

@import "/static/css/vendor.wxss"; //在分包中用根路径是无法找到文件的._button,._input[type=button],._input[type=reset],._input[type=submit],._textarea{-webkit-appearance:none}._button:after{border:none}page{background-color:#fff}...
Solution Solutions

Batch substitution of files with shell scripts
scripts/path-replace.sh

#!/bin/shsed -i "_bak" "s/\/static\/css\/vendor\.wxss/\/subPages\/enjoy_given\/static\/css\/vendor\.wxss/g" `grep "\/static\/css\/vendor\.wxss" -rl ./dist/static/css/pages/**/*.wxss ./dist/static/css/pages/*/*/*.wxss`

The purpose of this shell script is to replace the/STATIC/CSS/VENDOR.WXSS in all WXSS files under the./dist/static/css/pages/with the/subpages/huanlesong/static/css\ Vendor.wxss

Path change OK when replace is complete
When generating a formal package, use NPM run build_subpkg to be OK.

Sharing path Issues

The same path is shared between the main program and the standalone applet, which is similar in handling and jumping.

Solution Solutions

It is recommended that the common approach be handled uniformly, and we do this by adding a common method to the onshareappmessage of the page share.getfinalshareinfo

Take home share as an example

import Share from '@/lib/share'export default {    ...    onShareAppMessage () {        ...        return Share.getFinalShareInfo({            title: 'xxx',            path: `/pages/content/index/main`,            imageUrl: 'xxxx'        })    }}

Unified call Share.getfinalshareinfo method when sharing

Let's see Share.js again.

export default class Share {    static getFinalShareInfo (shareInfo) {        ...        // 路径前缀处理        shareInfo.path = VARS.pathPrefix + (shareInfo.path.indexOf('/') === 0 ? '' : '/') + shareInfo.path        ...        return shareInfo    }}

So the entire subcontracting business is configured to complete. is not very troublesome ~

When the original and the main process is really stepping on a lot of pits, here I put the solution to share with you

If there is a better solution, also want to communicate together:)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.