|
應用場景
項目概述我的這(zhe)條業務線叫(jiao)歡(huan)樂送(項目名為enjoy_given),是轉(zhuan)(zhuan)轉(zhuan)(zhuan)旗下一個免費的以物(wu)換物(wu)平臺 因為(wei)我們這條(tiao)業務線小程序是(shi)用mpvue構建的(整個項(xiang)目(mu)也是(shi)通過mpvue的cli生成的),所以后面相關配置都是(shi)以mpvue為(wei)例,如果是(shi)wepy項(xiang)目(mu)基本也大同小異。 下面(mian)就(jiu)是我們的目錄結構
src目錄下(xia)的幾個js文件需要專(zhuan)門(men)介(jie)紹下(xia): src/App.vue 是小(xiao)程序(xu)的(de)入口文件,里面定義的(de)是小(xiao)程序(xu)的(de)生命周(zhou)期 src/main.js 里面初始化通用業務(wu)、定義小程(cheng)序頁面路徑和全局變量 src/vars.js 存放整個(ge)項(xiang)目的全局變量 src/baseInstall.js 基礎方法裝配邏(luo)輯(如:給vue對象掛載登錄(lu)、統計(ji)邏(luo)輯、識別渠道號(hao)等(deng)) 分包配置概述
分包接入需要注意的地方
一套代碼,通過不同打包命令生成對應的程序包(獨立包和分包)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"
}
獨立小程序(調試) npm run dev 獨立小程序(構建) npm run build 主程序分包(構建) npm run build_subPkg 為什么沒有主程序分包(測試)因為我們無論是構建測試分包(bao)還是構建正(zheng)式分包(bao),都要把(ba)生(sheng)成dist下(xia)的(de)代(dai)碼拷(kao)貝到主程序的(de)subPages/enjoy_given/目錄下(xia),成本(ben)基(ji)本(ben)是一(yi)樣的(de),所以,就沒有寫構件(jian)分包(bao)的(de)命令 分包webpack配置因為需要(yao)兼(jian)容獨立小程(cheng)序和分包業務,webpack我們建議分開(kai)配(pei)置
我們對測試環境和正式環境分別配置了webpack,通過對webpack配置替換全局變量,直接修改項目的全局參數。 為(wei)了(le)分(fen)開配置,我們(men)拷貝了(le)一份(fen)build.js更名為(wei)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')
所以下一步就是創建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
}),
...
]
})
里面通過定義多個全局變量,實現打包時,通過不同的命令替換對應環境下的全局變量
var path = require('path')
module.exports = {
build: {
env: require('./prod.env'),
...
},
dev: {
env: require('./dev.env'),
...
}
}
引(yin)入了dev.env.js和prod.env.js 以prod.env.js為例
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
}
然后我們再來看一下(xia)存放全局變量的(de)文件src/vars.js(上面項目(mu)截(jie)圖(tu)中有)
// 小程序常量
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
}),
...
]
})
在打包完成后(hou),全局變(bian)量文件中(zhong)的(de)”app.xxx”會(hui)被(bei)webpack中(zhong)的(de)同名變(bian)量替換掉(diao)
這樣整(zheng)個替換(huan)全(quan)局變量的(de)流程就跑完了 ==作為分包,接入主程序中,自己的main.js和App.vue都不會執行==這個是(shi)大坑,因為很多通用業務(wu)的(de)初(chu)始化如登錄(lu)、cookie、統計都是(shi)在這里完(wan)成的(de)。 解決方案
把基礎功能的裝配業務(如在錄、統計、識別渠道號等邏輯)從main.js中抽離到另一個文件,我這里叫baseInstall.js。 那這樣的(de)話(hua),src/main.js就會變(bian)得非常簡單,
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: {
...
}
}
}
里面最關鍵(jian)的(de)是baseInstall.init()這行代碼 下面我們來(lai)看(kan)看(kan)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
}
為什么要用VARS.baseInstallFlag標志位因為,在分(fen)包時(shi)候是不執行main.js的,實(shi)際場景,會從主包的業務直(zhi)接(jie)跳轉到分(fen)包的一些頁面(mian)。 由于沒(mei)有固定入口(kou),所以在這些頁面中(zhong)都要加入baseInstall.js的引入,為了避免重復(fu)裝配(pei),才會設置這個標志位。 為什么要把這些業務抽離baseInstall.init里面(mian)涵蓋(gai)了(le)所有啟動小程序時需要初始化(hua)的(de)業(ye)務 前面也提到(dao)了在作為(wei)分(fen)包(bao)時,自己的App.vue和main.js是不(bu)會執行的。
那怎么辦,這樣,就在所有的頁面中,在onLoad的生命周期中加入baseInstall.init方法。 以首頁為例(li)(pages/content/index/index.vue)
import baseInstall from '@/baseInstall'
export default {
...
async onLoad (options) {
options = await baseInstall.init(options)
...
}
}
因為主程序不會讀取main.js,所以,所有的分包頁面路徑,都要統一在主程序中注冊
頁面路徑在分包中,所有(you)頁面路徑(jing)訪(fang)問要加入(ru)前綴
async navigateTo (route) {
route.url = VARS.pathPrefix + (route.url.indexOf('/') === 0 ? '' : '/') + route.url // 這里做前綴處理
console.log('[Navigator] navigateTo:', route)
...
wx.navigateTo(route)
}
這里面需不需要加前綴,都是由全局(ju)變量(liang)VARS中的pathPrefix來決定(ding) 而pathPrefix是在打包過程中由(you)webpack根據打包命令動態(tai)替換的 圖片訪問路徑問題圖片訪(fang)(fang)問(wen)路徑(jing)統一采用cdn的(de)(de)資源訪(fang)(fang)問(wen)路徑(jing),不(bu)要用本地訪(fang)(fang)問(wen)路徑(jing),要不(bu)然在分包路徑(jing)中是有(you)問(wen)題的(de)(de),同(tong)時也(ye)會增加程(cheng)序包的(de)(de)體(ti)積 wxss路徑問題用mpvue生(sheng)成的wxss文件,里面會把通用的vendor.wxss引入,但(dan)是引入路(lu)徑(jing)是根路(lu)徑(jing),作為分包,直接引入根路(lu)徑(jing),會去訪問主(zhu)包的路(lu)徑(jing),導致文件無法找到。
@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腳本對文件進行批量替換 #!/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腳本的(de)(de)目的(de)(de)就(jiu)是把./dist/static/css/pages/下所有的(de)(de)wxss文(wen)件中的(de)(de)/static/css/vendor.wxss替(ti)換成/subPages/huanlesong/static/css\vendor.wxss
替換完成后,路徑變更ok 分享路徑問題主程序(xu)和獨立小程序(xu)分享出來的路(lu)徑(jing)也是一(yi)樣的,處(chu)理方式和跳轉類似。 解決方案建議(yi)通過通用(yong)方(fang)法統一處(chu)理,我們的(de)做法是(shi),在(zai)頁(ye)面(mian)的(de)onShareAppMessage中加入通用(yong)方(fang)法Share.getFinalShareInfo 以首頁(ye)分享為(wei)例
import Share from '@/lib/share'
export default {
...
onShareAppMessage () {
...
return Share.getFinalShareInfo({
title: 'xxx',
path: `/pages/content/index/main`,
imageUrl: 'xxxx'
})
}
}
分(fen)享時統(tong)一調用Share.getFinalShareInfo方法 我們再(zai)來(lai)看下share.js
export default class Share {
static getFinalShareInfo (shareInfo) {
...
// 路徑前綴處理
shareInfo.path = VARS.pathPrefix + (shareInfo.path.indexOf('/') === 0 ? '' : '/') + shareInfo.path
...
return shareInfo
}
}
這樣整個(ge)分包業務就配置完成了。是不是很(hen)麻煩~ 當初和主程序融(rong)合時(shi)候(hou)確實踩(cai)了很(hen)多坑,這里我把解決方案(an)和大(da)家分(fen)享下 如果有(you)更好的解決(jue)方(fang)案,也(ye)希望一起(qi)交流:) |