個人這條業務線叫歡樂送(項目名爲enjoy_given),是轉轉旗下一個免費的以物換物平臺css
由於咱們這條業務線小程序是用mpvue構建的(整個項目也是經過mpvue的cli生成的),因此後面相關配置都是以mpvue爲例,若是是wepy項目基本也大同小異。vue
下面就是咱們的目錄結構node
src目錄下的幾個js文件須要專門介紹下:webpack
src/App.vue 是小程序的入口文件,裏面定義的是小程序的生命週期web
src/main.js 裏面初始化通用業務、定義小程序頁面路徑和全局變量shell
src/vars.js 存放整個項目的全局變量npm
src/baseInstall.js 基礎方法裝配邏輯(如:給vue對象掛載登陸、統計邏輯、識別渠道號等)json
首先要配置source和appid小程序
做爲分包時,這兩個參數都要統一採用主包參數(建議經過webpack配置來實現)bash
source:是每條業務線登陸、註冊、和接口訪問時用的標識,用來區分該用戶來自於哪條業務線
appid:微信分配的小程序appid
爲何要配置這兩參數:由於不配置無法登陸
頁面路徑問題
做爲分包時,全部頁面的跳轉路徑都要加主包的跳轉前綴(建議經過包裝跳轉方法navigateTo、redirectTo、reLaunch、navigateBack實現,建議配合webpack統一處理)
當新業務線做爲分包接入主程序時,頁面跳轉路徑前須要統一加一個前綴
如:獨立小程序首頁路徑爲 /pages/content/index/main
做爲分包時,主程序分配的包爲/subPages/enjoy_given
那麼分包業務線首頁路徑爲: /subPages/enjoy_given/pages/content/index/main
wxss引用路徑問題
不要用使根目錄引入方式(建議採用webpack或者shell腳原本完成)
由於在分包狀態下,用根目錄訪問方式會直接訪問主程序的根目錄,文件是不存在的
圖片路徑問題
全部圖片路徑統一採用cdn資源訪問方式,不要引用本地圖片
對於分包的main.js和App.vue入口文件不執行的問題
能夠經過抽離基礎業務裝配方法,對於每個從主包跳到分包頁面的入口分別引入,後面會細說
對於小程序內的h5頁面拉起小程序頁面
在打開webview時候,要加入一個標誌位,或者prefix,告訴h5頁面,當前處於分包當中,打開的小程序path要加前綴
分享路徑問題,在路徑前面也要加入路徑前綴
能夠經過一個通用的分享方法,進行統一處理,後面會細說
小程序的全部頁面都須要在主包入口文件(app.vue)註冊,每新增頁面都要註冊
這個是坑,尤爲新增頁面時,會很容易忽略這個問題,這裏要特別強調下
storage命名問題,爲了不和主程序或者其餘業務線小程序發生衝突(建議採用 zz_業務名_xxx, 咱們業務名是enjoy_given,簡稱eg,如: zz_eg_address, zz指的就是轉轉)
登陸問題,推薦和主程序使用一樣的cookie名稱,這樣能夠通用一套用戶信息,省得雙方各維護一套,還能避免重複受權。
支付問題,保證下單時和支付時,cookie中的參數保持一致
調試,能夠找主程序那邊要個主程序的測試包,把生成的代碼(dist目錄下的內容)拷貝到主程序包的 subPages/業務名/ 下面
例如咱們的目錄是 subPages/enjoy_given/(目錄結構同上)
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
複製代碼
由於咱們不管是構建測試分包仍是構建正式分包,都要把生成dist下的代碼拷貝到主程序的subPages/enjoy_given/目錄下,成本基本是同樣的,因此,就沒有寫構件分包的命令
由於須要兼容獨立小程序和分包業務,webpack咱們建議分開配置
咱們對測試環境和正式環境分別配置了webpack,經過對webpack配置替換全局變量,直接修改項目的全局參數。 經過npm命令動態執行替換。
爲了分開配置,咱們拷貝了一份build.js改名爲build-subpkg.js
"scripts": {
...,
"build_subPkg": "node build/build-subpkg.js && sh ./scripts/path-replace.sh"
}
複製代碼
build_subPkg命令就是讀取的build-subpkg.js文件 build.js和build-subpkg.js中99%的內容都同樣,只有一行不同
var webpackConfig = require('./webpack.prod.conf')
變動爲
var webpackConfig = require('./webpack.subpkg.prod.conf')
複製代碼
因此下一步就是建立webpack.subpkg.prod.conf文件 webpack.subpkg.prod.conf由webpack.prod.conf拷貝而來,裏面依舊99%的內容一致
// 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
}),
...
]
})
複製代碼
DefinePlugin插件是用來進行全局替換的 如:'process.env': '"hahaha"', 指的就是全局process.env替換爲"hahaha"
裏面經過定義多個全局變量,實現打包時,經過不一樣的命令替換對應環境下的全局變量 咱們看一下../config/index.js中的文件
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 = {
// 環境
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
}
複製代碼
而後咱們再來看一下存放全局變量的文件src/vars.js(上面項目截圖中有)
// 小程序常量
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
}),
...
]
})
複製代碼
在打包完成後,全局變量文件中的"app.xxx"會被webpack中的同名變量替換掉
如vars.js中 appId: app.id的app.id會被替換,獨立小程序時該值爲"wxaaaaaaaaaaaaaaa",做爲分包業務時,該值爲"wxbbbbbbbbbbbbbb"
這樣整個替換全局變量的流程就跑完了
這個是大坑,由於不少通用業務的初始化如登陸、cookie、統計都是在這裏完成的。
把基礎功能的裝配業務(如在錄、統計、識別渠道號等邏輯)從main.js中抽離到另外一個文件,我這裏叫baseInstall.js。 裏面我還加入了對query的處理,好比渠道號channel和微信入口scene。
那這樣的話,src/main.js就會變得很是簡單,
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: {
...
}
}
}
複製代碼
裏面最關鍵的是baseInstall.init()這行代碼
下面咱們來看看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
}
複製代碼
由於,在分包時候是不執行main.js的,實際場景,會從主包的業務直接跳轉到分包的一些頁面。
因爲沒有固定入口,因此在這些頁面中都要加入baseInstall.js的引入,爲了不重複裝配,纔會設置這個標誌位。
baseInstall.init裏面涵蓋了全部啓動小程序時須要初始化的業務
前面也提到了在做爲分包時,本身的App.vue和main.js是不會執行的。
那怎麼辦,這樣,就在全部的頁面中,在onLoad的生命週期中加入baseInstall.init方法。 ,因此咱們抽離確定是爲了更方便的複用了。
以首頁爲例(pages/content/index/index.vue)
import baseInstall from '@/baseInstall'
export default {
...
async onLoad (options) {
options = await baseInstall.init(options)
...
}
}
複製代碼
用async/await是由於baseInstall.init中部分邏輯用到了異步請求
注:每新增一個頁面,都要在主程序中註冊。也就是新增一個頁面,就要通知主程序那邊,在他們的文件裏統一註冊
在分包中,全部頁面路徑訪問要加入前綴
如:原來訪問/pages/content/index/main就能夠了
可是分包的訪問路徑爲:/subPages/enjoy_given/pages/content/index/main
以包裝的navigateTo爲例
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根據打包命令動態替換的
圖片訪問路徑統一採用cdn的資源訪問路徑,不要用本地訪問路徑,要否則在分包路徑中是有問題的,同時也會增長程序包的體積
用mpvue生成的wxss文件,裏面會把通用的vendor.wxss引入,可是引入路徑是根路徑,做爲分包,直接引入根路徑,會去訪問主包的路徑,致使文件沒法找到。
@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腳本對文件進行批量替換 scripts/path-replace.sh
#!/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 生成正式包的時候,用npm run build_subPkg就ok了
主程序和獨立小程序分享出來的路徑也是同樣的,處理方式和跳轉相似。
建議經過通用方法統一處理,咱們的作法是,在頁面的onShareAppMessage中加入通用方法Share.getFinalShareInfo
以首頁分享爲例
import Share from '@/lib/share'
export default {
...
onShareAppMessage () {
...
return Share.getFinalShareInfo({
title: 'xxx',
path: `/pages/content/index/main`,
imageUrl: 'xxxx'
})
}
}
複製代碼
分享時統一調用Share.getFinalShareInfo方法
咱們再來看下share.js
export default class Share {
static getFinalShareInfo (shareInfo) {
...
// 路徑前綴處理
shareInfo.path = VARS.pathPrefix + (shareInfo.path.indexOf('/') === 0 ? '' : '/') + shareInfo.path
...
return shareInfo
}
}
複製代碼
這樣整個分包業務就配置完成了。是否是很麻煩~
當初和主程序融合時候確實踩了不少坑,這裏我把解決方案和你們分享下
若是有更好的解決方案,也但願一塊兒交流:)