Application scenarios
- There are multiple applets under the same principal (company, department)
- These applets consist of a main applets and later new lines of business (each line of business has its own applets)
- Applets for each line of business need to be mounted below the main program because main program diversion is required
- At the same time each line of business own small program also issued updates as usual
- == a set of code to generate independent packages and subpackages by packaging commands == (after subpackages are generated, copy them to the subPages directory of the main program)
Description of project
My business line is called Enjoy_Given, a free barter platform owned by Zhuan
Because our business line applet is built with MPVue (the whole project is also generated through THE CLI of MPVue), the subsequent configuration is based on MPVue as an example, and the wepy project is basically the same.
Here is our directory structure
SRC directory js files need special introduction:
SRC/app. vue is the entry file of the applet, which defines the life cycle of the applet
SRC /main.js to initialize the generic business, define the applets page path and global variables
SRC /vars.js holds global variables for the entire project
SRC/baseinstall.js basic method assembly logic (e.g., mounting logins to vUE objects, statistical logic, identifying channel numbers, etc.)
Overview of subcontracting Configuration
-
Start by configuring the source and appID
As a subpackage, both of these parameters should be used as the main package parameters (webPack configuration is recommended)
Source: identifies each line of service for login, registration, and interface access. It is used to identify which line of service the user comes from
Appid: small program appID assigned by wechat
Why do YOU need to set these two parameters: Because you cannot log in without setting these parameters
-
Page path problem
As a subcontract, the jump path of all pages should be prefixed with the jump prefix of the main package (it is suggested to implement the package jump method navigateTo, redirectTo, reLaunch and navigateBack, and it is suggested to deal with them in a unified manner with Webpack).
When a new line is connected to the main program as a subcontract, a prefix must be added before the page jump path
Such as: independent small program home page path to/pages/content/index/main
As a subcontractor, the main program assigns packages as /subPages/enjoy_given
So the subcontract business line path is: the home page/subPages enjoy_given/pages/content/index/main
-
WXSS reference path problem
Do not use root import (webpack or shell scripts are recommended)
Because in the subcontracting state, using root access directly accesses the root directory of the main program, the file does not exist
-
Image path problem
All image paths adopt THE CDN resource access mode, and do not reference local images
-
Problem with subcontracted main.js and app.vue entry files not being executed
Each entry from the main package to the subcontract page can be introduced separately by pulling away from the base business assembly method, as discussed later
-
Pull up the applet page for the H5 page within the applet
When opening the WebView, add a flag bit, or prefix, to tell the H5 page that it is currently in subcontract and that the open path applet should be prefixed
-
Share path problem, add path prefix before path
This can be done through a common sharing method, which will be discussed later
-
All pages of the applet need to be registered in the main package entry file (app.vue), and every new page needs to be registered
This is a pit, especially when new pages, will be easy to ignore this problem, here to emphasize
Subcontracting access needs attention
-
Storage naming problem, in order to avoid conflicts with the main program or other business line small program (recommended to use zz_ business name _xxx, our business name is enjoy_given, eg for short, such as: zz_eg_address, zz refers to around)
-
For login problems, it is recommended to use the same cookie name as the main program, so that a common set of user information can be used to avoid the maintenance of a set by both parties, and duplicate authorization can be avoided.
-
Payment problem, ensure that the parameters in the cookie are consistent when placing an order and when paying
-
For debugging, you can ask for a test package of the main program from the main program side and copy the generated code (contents in the dist directory) to subPages/ business name/under the main program package
For example, our directory is subPages/enjoy_given/
A set of code that generates corresponding packages (standalone and subcontracted) from different packaging commands
Package. The scripts in json
"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"
}
Copy the code
Independent applets (debug) NPM run dev Independent applets (build) NPM run Build Main program subpkg (build) NPM run build_subPkgCopy the code
Why is there no main program subcontracting (testing)
Since we need to copy the code under generated DIST to subPages/enjoy_given/ of the main program, the cost is basically the same no matter whether we build test subcontracting or formal subcontracting, so there is no command to write component subcontracting
Subcontract webPack configuration
Because of the need to be compatible with independent applets and subcontracting business, we recommend separate configuration of Webpack
We configured Webpack for the test environment and the formal environment respectively. By replacing global variables with webpack configuration, we directly modified the global parameters of the project. The replacement is performed dynamically through the NPM command.
To separate the configuration, we made a copy of build.js and renamed it build-subpkg.js
"scripts": {... ."build_subPkg": "node build/build-subpkg.js && sh ./scripts/path-replace.sh"
}
Copy the code
Build_subPkg/build_subPkg/build_subPkg/build_subPkg/build_subPkg/build_subPkg/build_subPkg/build_subPkg/build_subPkg/build_subPkg/build_subPkg/build_subPkg/build_subPkg/build_subPkg/build_subPkg
var webpackConfig = require('./webpack.prod.conf'Var webpackConfig = require('./webpack.subpkg.prod.conf')
Copy the code
So the next step is to create the webpack.subpkg.prod.conf file webpack.subpkg.prod.conf which is copied from webpack.prod.conf and still contains 99% of the same content
// 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
}),
...
]
})
Copy the code
// 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
}),
...
]
})
Copy the code
DefinePlugin is used for global substitution such as ‘process.env’: ‘”hahaha”, which means global process.env is replaced with “hahaha”.
Inside by defining a number of global variables, to achieve packaging, through different commands to replace the corresponding environment of global variables let’s have a look.. File in /config/index.js
var path = require('path')
module.exports = {
build: {
env: require('./prod.env'),... }, dev: { env: require('./dev.env'),... }}Copy the code
Dev.env.js and prod.env.js are introduced
To prod. Env. Js, for example
Module. exports = {// environment NODE_ENV:'"production"', // Joy sends independent appletssource
APP_SOURCE: '114', // Joy send subcontracting small programsource
APP_SUB_PKG_SOURCE: '103'Appid APP_ID:'"wxaaaaaaaaaaaaaaa"'Appid APP_SUB_PKG_ID:'"wxbbbbbbbbbbbbbbbb"'// udesk test flag UDESK_DEBUG:falseAPP_PATH_RREFIX:'" "', // Happy send applets page path prefix APP_SUB_PKG_PATH_RREFIX:'"/subPages/enjoy_given"', // Whether to enable crazyFormId IS_USE_CRAZY_FORMD_ID:true
}
Copy the code
Then let’s take a look at the file SRC /vars.js that holds the global variables (shown in the project screenshot above)
// Applet constantsexportdefault { ... // Small program version number:'1.3.5, // appId appid: app.id, // appletssource(Replaced by Webpack for different environments)source: app.source, // pathPrefix: app.pathPrefix, // Whether to enable CrazyFormId isUseCrazyFormId: app.isUseCrazyFormId}Copy the code
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
}),
...
]
})
Copy the code
After the packaging is complete, “app.xxx” in the global variables file is replaced with a variable of the same name in the Webpack
For example, app.id of appId: app.id in vars.js is replaced with “wxaaAAAAAAAAaaaaa” for standalone applets and “WXBBBBBBBBBBBBBBBBBBBB” for subcontractors.
This completes the whole process of replacing global variables
== as a subcontractor, connected to the main program, its own main.js and app. vue will not execute ==
This is a big hole, because a lot of initialization of common services such as login, cookies, statistics is done here.
The solution
Remove the basic functionality of assembly operations (such as logging, statistics, identifying channel numbers, etc.) from main.js to another file, which I call baseInstall.js. I also added query processing, such as channel number and wechat entrance scene.
In that case, SRC /main.js becomes very simple,
import Vue from 'vue'
import App from './App'
import baseInstall from './baseInstall'
App.mpType = 'app'Baseinstall.init () //!! The key is this line of code!! const app = new Vue(App) app.$mount(a)export default {
config: {
pages: [
'^pages/content/index/main', // 首页
...
],
window: {
...
}
}
}
Copy the code
The key is the baseInstall.init() line of code
Let’s take a look at baseinstall.js
// General business assembly initialization... asyncfunction init (opts) {
letoptions = opts ... No. / / for specified channels const channel = options. The channel | | options. C | |' '// Set the channel numberif (channel) {
VARS.channel = channel.indexOf('waeg_') = = = 0? channel : ('waeg_' + channel)
}
...
if(! Vars.baseinstallflag) {// To avoid duplicate installations, vars.baseinstallFlag = is distinguished by flag bitstrue. Zzlogin. config({source: vars.source}) zzlogin. install() navigator.install () // count lestatic.config ({appid: VARS.source, pageTypePrefix (currentRoute) {return 'waeg_'} }).install() ... } // write cookie cookie.set({channelID: vars.channel, fromShareUid: vars.shareuid)return options
}
export default {
init
}
Copy the code
Why use VARS. BaseInstallFlag flag bit
Because main.js is not executed during subcontracting, the actual scenario will jump directly from the main package to some of the subcontracting pages.
Since there is no fixed entry point, baseInstall.js is introduced in each of these pages, and this flag bit is set to avoid repeated assembly.
Why do you want to separate these businesses
Baseinstall. init covers all the services that need to be initialized when starting applets
As mentioned earlier, app.vue and main.js are not executed as subcontractors.
Add the baseInstall.init method to the onLoad lifecycle for all pages. , so we must be removed for more convenient reuse.
In home page, for example (pages/content/index/index. The vue)
import baseInstall from '@/baseInstall'
exportdefault { ... async onLoad (options) { options = await baseInstall.init(options) ... }}Copy the code
Async /await is used because part of the logic in baseInstall.init uses asynchronous requests
Since the main program does not read main.js, all subcontracted page paths must be registered in the main program
Note: Each new page must be registered in the main application. That is, to add a page, to notify the main application side, in their file unified registration
Page path
In subcontracting, all page path accesses are prefixed
Such as: the original access/pages/content/index/main
But the subcontract of the access path is: / subPages/enjoy_given/pages/content/index/main
Solution:
Take the packaged navigateTo, for example
async navigateTo (route) {
route.url = VARS.pathPrefix + (route.url.indexOf('/') = = = 0?' ' : '/'+ route.url // do prefix processing console.log()'[Navigator] navigateTo:', route)
...
wx.navigateTo(route)
}
Copy the code
The need for a prefix is determined by the pathPrefix in the global VARS variable
PathPrefix is dynamically replaced by Webpack according to the packaging command during the packaging process
The image access path is faulty
The image access path uniformly adopts the CDN resource access path, do not use the local access path, otherwise there is a problem in the subcontracting path, but also increase the volume of the program package
WXSS path problem
In the WXSS file generated by MPvue, the general vendor. WXSS will be introduced, but the introduction path is the root path. As a subcontract, the direct introduction of the root path will access the path of the main package, resulting in the file cannot be 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}...
Copy the code
The solution
Scripts /path-replace.sh are used to replace files in batches using shell scripts
#! /bin/sh
sed -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`
Copy the code
The purpose of this section of the shell script is to turn to. / dist/static/CSS/pages/all WXSS file under/static/CSS/vendor WXSS replace/subPages/huanlesong/static/CSS \ vendor WXSS
NPM run build_subPkg is ok when the path change OK generates the official package after the replacement
Sharing path Problems
The path shared by the main program and the independent applet is the same, and is treated like a jump.
The solution
It is suggested to use the common method to handle the problem uniformly. What we do is to add the common method Share. GetFinalShareInfo in the onShareAppMessage of the page
Take home page sharing as an example
import Share from '@/lib/share'
export default {
...
onShareAppMessage() {...return Share.getFinalShareInfo({
title: 'xxx',
path: `/pages/content/index/main`,
imageUrl: 'xxxx'}}})Copy the code
The share.getFinalShareInfo method is called when sharing
Let’s take a look at share.js
exportdefault class Share { static getFinalShareInfo (shareInfo) { ... / / path prefix treatment shareInfo path = VARS. PathPrefix + (shareInfo. Path. IndexOf ('/') = = = 0?' ' : '/') + shareInfo.path
...
return shareInfo
}
}
Copy the code
This completes the configuration of the entire subcontracting business. Is not very troublesome ~
At the beginning and the main program fusion time really stepped on a lot of pits, here I share the solution with you
If there is a better solution, we hope to communicate with each other 🙂