|
應(yīng)用場(chǎng)景
項(xiàng)目概述我的這條業(yè)務(wù)線叫歡樂送(項(xiàng)目名為enjoy_given),是轉(zhuǎn)轉(zhuǎn)旗下一個(gè)免費(fèi)的以物換物平臺(tái) 因?yàn)槲覀冞@條業(yè)務(wù)線小程序是用mpvue構(gòu)建的(整個(gè)項(xiàng)目也是通過mpvue的cli生成的),所以后面相關(guān)配置都是以mpvue為例,如果是wepy項(xiàng)目基本也大同小異。 下面就是我們的目錄結(jié)構(gòu)
src目錄下的幾個(gè)js文件需要專門介紹下: src/App.vue 是小程序的入口文件,里面定義的是小程序的生命周期 src/main.js 里面初始化通用業(yè)務(wù)、定義小程序頁面路徑和全局變量 src/vars.js 存放整個(gè)項(xiàng)目的全局變量 src/baseInstall.js 基礎(chǔ)方法裝配邏輯(如:給vue對(duì)象掛載登錄、統(tǒng)計(jì)邏輯、識(shí)別渠道號(hào)等) 分包配置概述
分包接入需要注意的地方
一套代碼,通過不同打包命令生成對(duì)應(yīng)的程序包(獨(dú)立包和分包)package.json中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"
}
獨(dú)立小程序(調(diào)試) npm run dev 獨(dú)立小程序(構(gòu)建) npm run build 主程序分包(構(gòu)建) npm run build_subPkg 為什么沒有主程序分包(測(cè)試)因?yàn)槲覀儫o論是構(gòu)建測(cè)試分包還是構(gòu)建正式分包,都要把生成dist下的代碼拷貝到主程序的subPages/enjoy_given/目錄下,成本基本是一樣的,所以,就沒有寫構(gòu)件分包的命令 分包webpack配置因?yàn)樾枰嫒莳?dú)立小程序和分包業(yè)務(wù),webpack我們建議分開配置
我們對(duì)測(cè)試環(huán)境和正式環(huán)境分別配置了webpack,通過對(duì)webpack配置替換全局變量,直接修改項(xiàng)目的全局參數(shù)。 為了分開配置,我們拷貝了一份build.js更名為build-subpkg.js
"scripts": {
...,
"build_subPkg": "node build/build-subpkg.js && sh ./scripts/path-replace.sh"
}
build_subPkg命令就是讀取的build-subpkg.js文件
var webpackConfig = require('./webpack.prod.conf')
變更為
var webpackConfig = require('./webpack.subpkg.prod.conf')
所以下一步就是創(chuàng)建webpack.subpkg.prod.conf文件 // 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
}),
...
]
})
里面通過定義多個(gè)全局變量,實(shí)現(xiàn)打包時(shí),通過不同的命令替換對(duì)應(yīng)環(huán)境下的全局變量
var path = require('path')
module.exports = {
build: {
env: require('./prod.env'),
...
},
dev: {
env: require('./dev.env'),
...
}
}
引入了dev.env.js和prod.env.js 以prod.env.js為例
module.exports = {
// 環(huán)境
NODE_ENV: '"production"',
// 歡樂送獨(dú)立小程序source
APP_SOURCE: '114',
// 歡樂送分包小程序source
APP_SUB_PKG_SOURCE: '103',
// 歡樂送獨(dú)立程序appid
APP_ID: '"wxaaaaaaaaaaaaaaa"',
// 歡樂送分包程序appid
APP_SUB_PKG_ID: '"wxbbbbbbbbbbbbbbbb"',
// udesk測(cè)試標(biāo)志位
UDESK_DEBUG: false,
// 歡樂送獨(dú)立小程序頁面路徑前綴
APP_PATH_RREFIX: '""',
// 歡樂送分包小程序頁面路徑前綴
APP_SUB_PKG_PATH_RREFIX: '"/subPages/enjoy_given"',
// 是否啟用crazyFormId
IS_USE_CRAZY_FORMD_ID: true
}
然后我們?cè)賮砜匆幌麓娣湃肿兞康奈募rc/vars.js(上面項(xiàng)目截圖中有)
// 小程序常量
export default {
...
// 小程序版本號(hào)
version: '1.3.5',
// 小程序appid
appId: app.id,
// 小程序source(由webpack根據(jù)不同環(huán)境統(tǒng)一替換)
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
}),
...
]
})
在打包完成后,全局變量文件中的”app.xxx”會(huì)被webpack中的同名變量替換掉
這樣整個(gè)替換全局變量的流程就跑完了 ==作為分包,接入主程序中,自己的main.js和App.vue都不會(huì)執(zhí)行==這個(gè)是大坑,因?yàn)楹芏嗤ㄓ脴I(yè)務(wù)的初始化如登錄、cookie、統(tǒng)計(jì)都是在這里完成的。 解決方案
把基礎(chǔ)功能的裝配業(yè)務(wù)(如在錄、統(tǒng)計(jì)、識(shí)別渠道號(hào)等邏輯)從main.js中抽離到另一個(gè)文件,我這里叫baseInstall.js。 那這樣的話,src/main.js就會(huì)變得非常簡(jiǎn)單,
import Vue from 'vue'
import App from './App'
import baseInstall from './baseInstall'
App.mpType = 'app'
baseInstall.init() // ?。。∽铌P(guān)鍵就是這行代碼?。?!
const app = new Vue(App)
app.$mount()
export default {
config: {
pages: [
'^pages/content/index/main', // 首頁
...
],
window: {
...
}
}
}
里面最關(guān)鍵的是baseInstall.init()這行代碼 下面我們來看看baseInstall.js
// 通用業(yè)務(wù)裝配初始化
...
async function init (opts) {
let options = opts
...
// 獲取指定渠道號(hào)
const channel = options.channel || options.c || ''
// 設(shè)置渠道號(hào)
if (channel) {
VARS.channel = channel.indexOf('waeg_') === 0 ? channel : ('waeg_' + channel)
}
...
if (!VARS.baseInstallFlag) {
// 為了避免重復(fù)裝備,通過標(biāo)志位進(jìn)行區(qū)分
VARS.baseInstallFlag = true
...
// 登錄配置
ZZLogin.config({
source: VARS.source
})
ZZLogin.install()
Navigator.install()
// 統(tǒng)計(jì)
LeStatic.config({
appid: VARS.source,
pageTypePrefix (currentRoute) {
return 'waeg_'
}
}).install()
...
}
// 寫入cookie
cookie.set({
channelid: VARS.channel,
fromShareUid: VARS.shareUid
})
return options
}
export default {
init
}
為什么要用VARS.baseInstallFlag標(biāo)志位因?yàn)椋诜职鼤r(shí)候是不執(zhí)行main.js的,實(shí)際場(chǎng)景,會(huì)從主包的業(yè)務(wù)直接跳轉(zhuǎn)到分包的一些頁面。 由于沒有固定入口,所以在這些頁面中都要加入baseInstall.js的引入,為了避免重復(fù)裝配,才會(huì)設(shè)置這個(gè)標(biāo)志位。 為什么要把這些業(yè)務(wù)抽離baseInstall.init里面涵蓋了所有啟動(dòng)小程序時(shí)需要初始化的業(yè)務(wù) 前面也提到了在作為分包時(shí),自己的App.vue和main.js是不會(huì)執(zhí)行的。
那怎么辦,這樣,就在所有的頁面中,在onLoad的生命周期中加入baseInstall.init方法。 以首頁為例(pages/content/index/index.vue)
import baseInstall from '@/baseInstall'
export default {
...
async onLoad (options) {
options = await baseInstall.init(options)
...
}
}
因?yàn)橹鞒绦虿粫?huì)讀取main.js,所以,所有的分包頁面路徑,都要統(tǒng)一在主程序中注冊(cè)
頁面路徑在分包中,所有頁面路徑訪問要加入前綴
async navigateTo (route) {
route.url = VARS.pathPrefix + (route.url.indexOf('/') === 0 ? '' : '/') + route.url // 這里做前綴處理
console.log('[Navigator] navigateTo:', route)
...
wx.navigateTo(route)
}
這里面需不需要加前綴,都是由全局變量VARS中的pathPrefix來決定 而pathPrefix是在打包過程中由webpack根據(jù)打包命令動(dòng)態(tài)替換的 圖片訪問路徑問題圖片訪問路徑統(tǒng)一采用cdn的資源訪問路徑,不要用本地訪問路徑,要不然在分包路徑中是有問題的,同時(shí)也會(huì)增加程序包的體積 wxss路徑問題用mpvue生成的wxss文件,里面會(huì)把通用的vendor.wxss引入,但是引入路徑是根路徑,作為分包,直接引入根路徑,會(huì)去訪問主包的路徑,導(dǎo)致文件無法找到。
@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}...
解決方案
通過shell腳本對(duì)文件進(jìn)行批量替換 #!/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` 這段shell腳本的目的就是把./dist/static/css/pages/下所有的wxss文件中的/static/css/vendor.wxss替換成/subPages/huanlesong/static/css\vendor.wxss
替換完成后,路徑變更ok 分享路徑問題主程序和獨(dú)立小程序分享出來的路徑也是一樣的,處理方式和跳轉(zhuǎn)類似。 解決方案建議通過通用方法統(tǒng)一處理,我們的做法是,在頁面的onShareAppMessage中加入通用方法Share.getFinalShareInfo 以首頁分享為例
import Share from '@/lib/share'
export default {
...
onShareAppMessage () {
...
return Share.getFinalShareInfo({
title: 'xxx',
path: `/pages/content/index/main`,
imageUrl: 'xxxx'
})
}
}
分享時(shí)統(tǒng)一調(diào)用Share.getFinalShareInfo方法 我們?cè)賮砜聪聅hare.js
export default class Share {
static getFinalShareInfo (shareInfo) {
...
// 路徑前綴處理
shareInfo.path = VARS.pathPrefix + (shareInfo.path.indexOf('/') === 0 ? '' : '/') + shareInfo.path
...
return shareInfo
}
}
這樣整個(gè)分包業(yè)務(wù)就配置完成了。是不是很麻煩~ 當(dāng)初和主程序融合時(shí)候確實(shí)踩了很多坑,這里我把解決方案和大家分享下 如果有更好的解決方案,也希望一起交流:) |