應(yīng)用場景
項目概述我的這條業(yè)務(wù)線叫歡樂送(項目名為enjoy_given),是轉(zhuǎn)轉(zhuǎn)旗下一個免費的以物換物平臺 因為我們這條業(yè)務(wù)線小程序是用mpvue構(gòu)建的(整個項目也是通過mpvue的cli生成的),所以后面相關(guān)配置都是以mpvue為例,如果是wepy項目基本也大同小異。 下面就是我們的目錄結(jié)構(gòu)
src目錄下的幾個js文件需要專門介紹下: src/App.vue 是小程序的入口文件,里面定義的是小程序的生命周期 src/main.js 里面初始化通用業(yè)務(wù)、定義小程序頁面路徑和全局變量 src/vars.js 存放整個項目的全局變量 src/baseInstall.js 基礎(chǔ)方法裝配邏輯(如:給vue對象掛載登錄、統(tǒng)計邏輯、識別渠道號等) 分包配置概述
分包接入需要注意的地方
一套代碼,通過不同打包命令生成對應(yīng)的程序包(獨立包和分包)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" } 獨立小程序(調(diào)試) npm run dev 獨立小程序(構(gòu)建) npm run build 主程序分包(構(gòu)建) npm run build_subPkg 為什么沒有主程序分包(測試)因為我們無論是構(gòu)建測試分包還是構(gòu)建正式分包,都要把生成dist下的代碼拷貝到主程序的subPages/enjoy_given/目錄下,成本基本是一樣的,所以,就沒有寫構(gòu)件分包的命令 分包webpack配置因為需要兼容獨立小程序和分包業(yè)務(wù),webpack我們建議分開配置
我們對測試環(huán)境和正式環(huán)境分別配置了webpack,通過對webpack配置替換全局變量,直接修改項目的全局參數(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 }), ... ] })
里面通過定義多個全局變量,實現(xiàn)打包時,通過不同的命令替換對應(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"', // 歡樂送獨立小程序source APP_SOURCE: '114', // 歡樂送分包小程序source APP_SUB_PKG_SOURCE: '103', // 歡樂送獨立程序appid APP_ID: '"wxaaaaaaaaaaaaaaa"', // 歡樂送分包程序appid APP_SUB_PKG_ID: '"wxbbbbbbbbbbbbbbbb"', // udesk測試標(biāo)志位 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根據(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”會被webpack中的同名變量替換掉
這樣整個替換全局變量的流程就跑完了 ==作為分包,接入主程序中,自己的main.js和App.vue都不會執(zhí)行==這個是大坑,因為很多通用業(yè)務(wù)的初始化如登錄、cookie、統(tǒng)計都是在這里完成的。 解決方案
把基礎(chǔ)功能的裝配業(yè)務(wù)(如在錄、統(tǒng)計、識別渠道號等邏輯)從main.js中抽離到另一個文件,我這里叫baseInstall.js。 那這樣的話,src/main.js就會變得非常簡單, import Vue from 'vue' import App from './App' import baseInstall from './baseInstall' App.mpType = 'app' baseInstall.init() // ?。?!最關(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 ... // 獲取指定渠道號 const channel = options.channel || options.c || '' // 設(shè)置渠道號 if (channel) { VARS.channel = channel.indexOf('waeg_') === 0 ? channel : ('waeg_' + channel) } ... if (!VARS.baseInstallFlag) { // 為了避免重復(fù)裝備,通過標(biāo)志位進行區(qū)分 VARS.baseInstallFlag = true ... // 登錄配置 ZZLogin.config({ source: VARS.source }) ZZLogin.install() Navigator.install() // 統(tǒng)計 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)志位因為,在分包時候是不執(zhí)行main.js的,實際場景,會從主包的業(yè)務(wù)直接跳轉(zhuǎn)到分包的一些頁面。 由于沒有固定入口,所以在這些頁面中都要加入baseInstall.js的引入,為了避免重復(fù)裝配,才會設(shè)置這個標(biāo)志位。 為什么要把這些業(yè)務(wù)抽離baseInstall.init里面涵蓋了所有啟動小程序時需要初始化的業(yè)務(wù) 前面也提到了在作為分包時,自己的App.vue和main.js是不會執(zhí)行的。
那怎么辦,這樣,就在所有的頁面中,在onLoad的生命周期中加入baseInstall.init方法。 以首頁為例(pages/content/index/index.vue) import baseInstall from '@/baseInstall' export default { ... async onLoad (options) { options = await baseInstall.init(options) ... } }
因為主程序不會讀取main.js,所以,所有的分包頁面路徑,都要統(tǒng)一在主程序中注冊
頁面路徑在分包中,所有頁面路徑訪問要加入前綴
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ù)打包命令動態(tài)替換的 圖片訪問路徑問題圖片訪問路徑統(tǒng)一采用cdn的資源訪問路徑,不要用本地訪問路徑,要不然在分包路徑中是有問題的,同時也會增加程序包的體積 wxss路徑問題用mpvue生成的wxss文件,里面會把通用的vendor.wxss引入,但是引入路徑是根路徑,作為分包,直接引入根路徑,會去訪問主包的路徑,導(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腳本對文件進行批量替換 #!/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 分享路徑問題主程序和獨立小程序分享出來的路徑也是一樣的,處理方式和跳轉(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' }) } } 分享時統(tǒng)一調(diào)用Share.getFinalShareInfo方法 我們再來看下share.js export default class Share { static getFinalShareInfo (shareInfo) { ... // 路徑前綴處理 shareInfo.path = VARS.pathPrefix + (shareInfo.path.indexOf('/') === 0 ? '' : '/') + shareInfo.path ... return shareInfo } } 這樣整個分包業(yè)務(wù)就配置完成了。是不是很麻煩~ 當(dāng)初和主程序融合時候確實踩了很多坑,這里我把解決方案和大家分享下 如果有更好的解決方案,也希望一起交流:) |
工作日 8:30-12:00 14:30-18:00
周六及部分節(jié)假日提供值班服務(wù)