小程序模板網(wǎng)

【babel+小程序】上

發(fā)布時(shí)間:2018-05-05 14:34 所屬欄目:小程序開發(fā)教程

話不多說先上圖,簡要說明一下干了些什么事。圖可能太模糊,可以點(diǎn) svg 看看

背景

最近公司開展了小程序的業(yè)務(wù),派我去負(fù)責(zé)這一塊的業(yè)務(wù),其中需要處理的一個(gè)問題是接入我們web開發(fā)的傳統(tǒng)架構(gòu)-- 模塊化開發(fā) 。

我們來詳細(xì)說一下模塊化開發(fā)具體是怎么樣的。

我們的git工作流采用的是 git flow 。一個(gè)項(xiàng)目會(huì)拆分成幾個(gè)模塊,然后一人負(fù)責(zé)一個(gè)模塊(對(duì)應(yīng)git flow的一個(gè)feature)獨(dú)立開發(fā)。模塊開發(fā)并與后端聯(lián)通后再合并至develop進(jìn)行集成測試,后續(xù)經(jīng)過一系列測試再發(fā)布版本。

目錄結(jié)構(gòu)大體如圖所示,一個(gè)模塊包含了他自己的pages / components / assets / model / mixins / apis / routes / scss等等。

這種開發(fā)模式的好處不言而喻,每個(gè)人都可以并行開發(fā),大大提升開發(fā)速度。這次就是要移植這種開發(fā)模式到小程序中。

目標(biāo)

背景說完了,那么來明確一下我們的目標(biāo)。

我采用的是 wepy 框架,類vue語法的開發(fā),開發(fā)體驗(yàn)非常棒。在vue中,一個(gè)組件就是單文件,包含了js、html、css。wepy采用vue的語法,但由與vue稍稍有點(diǎn)區(qū)別,wepy的組件分為三種--wepy.app類,wepy.page類,wepy.component類。

對(duì)應(yīng)到我們的目錄結(jié)構(gòu)中,每個(gè)模塊實(shí)際上就是一系列的page組件。要組合這一系列的模塊,那么很簡單,我們要做的就是把這一系列page的路由掃描成一個(gè)路由表,然后 插入到小程序的入口--app.json中 。對(duì)應(yīng)wepy框架那即是app.wpy中的pages字段。

export default class extends wepy.app {
  config = {
    pages: 'modules/home/pages/index',//here!!!!
    window: {
      backgroundTextStyle: 'light',
      navigationBarBackgroundColor: '#fff',
      navigationBarTitleText: '大家好我是渣渣輝',
      navigationBarTextStyle: 'black'
    }
  }
//...
}

掃描路由表

第一步!先得到所有pages的路由并綜合成一個(gè) 路由表 !

我的方案是,在每個(gè)模塊中新建一份routes文件,相當(dāng)于注冊每個(gè)需要插入到入口的page的路由,不需要接入業(yè)務(wù)的page就不用注冊啦。是不是很熟悉呢,對(duì)的,就是參考vue-router的注冊語法。

//routes.js
module.exports = [
    {
        name: 'home-detail',//TODO: name先占位,后續(xù)再嘗試通過讀name跳轉(zhuǎn)某頁
        page: 'detail',//需要接入入口的page的文件名。例如這里是index.wpy。相對(duì)于src/的路徑就是`modules/${moduleName}/pages/index`。
    },
    {
        name: 'home-index',
        page: 'index',
        meta: {
            weight: 100//這里加了一個(gè)小功能,因?yàn)樾〕绦蛑付╬ages數(shù)組的第一項(xiàng)為首頁,后續(xù)我會(huì)通過這個(gè)權(quán)重字段來給pages路由排序。權(quán)重越高位置越前。
        }
    }
]

而掃描各個(gè)模塊并合并路由表的腳本非常簡單,讀寫文件就ok了。

const fs = require('fs')
const path = require('path')

const routeDest = path.join(__dirname, '../src/config/routes.js')
const modulesPath = path.join(__dirname, '../src/modules')

let routes = []

fs.readdirSync(modulesPath).forEach(module => {
    if(module.indexOf('.DS_Store') > -1) return 

    const route = require(`${modulesPath}/${module}/route`)
    route.forEach(item => {
        item.page = `modules/${module}/pages/${item.page.match(/\/?(.*)/)[1]}`
    })
    routes = routes.concat(route)
})

fs.writeFileSync(routeDest,`module.exports = ${JSON.stringify(routes)}`, e => {
    console.log(e)
})

路由排序策略

const strategies = {
    sortByWeight(routes) {
        routes.sort((a, b) => {
            a.meta = a.meta || {}
            b.meta = b.meta || {}

            const weightA = a.meta.weight || 0
            const weightB = b.meta.weight || 0

            return weightB - weightA
        })
        return routes
    }
}

最后得出路由表

const Strategies = require('../src/lib/routes-model')
const routes = Strategies.sortByWeight(require('../src/config/routes'))
const pages = routes.map(item => item.page)
console.log(pages)//['modules/home/pages/index', 'modules/home/pages/detail']

替換路由數(shù)組

So far so good...問題來了,如何替換入口文件中的路由數(shù)組。我如下做了幾步嘗試。

直接引入

我第一感覺就是,這不很簡單嗎?在wepy編譯之前,先跑腳本得出路由表,再import這份路由表就得了。

import routes from './routes'
export default class extends wepy.app {
  config = {
    pages: routes,//['modules/home/pages/index']
    window: {
      backgroundTextStyle: 'light',
      navigationBarBackgroundColor: '#fff',
      navigationBarTitleText: '大家好我是渣渣輝',
      navigationBarTextStyle: 'black'
    }
  }
//...
}

然而這樣小程序肯定會(huì)炸啦,pages字段的值必須是靜態(tài)的,在小程序運(yùn)行之前就配置好,動(dòng)態(tài)引入是不行的!不信的話諸君可以試試。那么就是說,劃重點(diǎn)--- 我們必須在wepy編譯之前再預(yù)編譯一次 ---事先替換掉pages字段的值!

正則匹配替換

既然要事先替換,那就是要精準(zhǔn)定位pages字段的值,然后再替換掉。難點(diǎn)在于如果精準(zhǔn)定位pages字段的值呢?

最撈然而最快的方法:正則匹配。

事先定好編碼規(guī)范,在pages字段的值的前后添加 /* __ROUTES__ */ 的注釋

腳本如下:

const fs = require('fs')
const path = require('path')
import routes from './routes'

function replace(source, arr) {
    const matchResult = source.match(/\/\* __ROUTE__ \*\/([\s\S]*)\/\* __ROUTE__ \*\//)
    if(!matchResult) {
        throw new Error('必須包含/* __ROUTE__ */標(biāo)記注釋')
    }
    const str = arr.reduce((pre, next, index, curArr) => {
        return pre += `'${curArr[index]}', `
    }, '')
    return source.replace(matchResult[1], str)
}

const entryFile = path.join(__dirname, '../src/app.wpy')
let entry = fs.readFileSync(entryFile, {encoding: 'UTF-8'})

entry = replace(entry, routes)

fs.writeFileSync(entryFile, entry)

app.wpy的變化如下:

//before
export default class extends wepy.app {
  config = {
    pages: [
    /* __ROUTE__ */
    /* __ROUTE__ */
    ],
    window: {
      backgroundTextStyle: 'light',
      navigationBarBackgroundColor: '#fff',
      navigationBarTitleText: '大家好我是渣渣輝',
      navigationBarTextStyle: 'black'
    }
  }
//...
}
//after
export default class extends wepy.app {
  config = {
    pages: [
/* __ROUTE__ */'modules/home/pages/index', /* __ROUTE__ */
    ],
    window: {
      backgroundTextStyle: 'light',
      navigationBarBackgroundColor: '#fff',
      navigationBarTitleText: '大家好我是渣渣輝',
      navigationBarTextStyle: 'black'
    }
  }
//...
}

行吧,也總算跑通了。因?yàn)轫?xiàng)目很趕,所以先用這個(gè)方案開發(fā)了一個(gè)半星期。開發(fā)完之后總覺得這種方案太難受,于是密謀著換另一種各精準(zhǔn)的自動(dòng)的方案。。。


本文地址:http://22321a.com/wxmini/doc/course/24246.html 復(fù)制鏈接 如需定制請聯(lián)系易優(yōu)客服咨詢:800182392 點(diǎn)擊咨詢
QQ在線咨詢