小程序模板网

【babel+小程序】上

话不多说先上图,简要说明一下干了些什么事。图可能太模糊,可以点 svg 看看

背景

最近公司开展了小程序的业务,派我去负责这一块的业务,其中需要处理的一个问题是接入我们web开发的传统架构-- 模块化开发 。

我们来详细说一下模块化开发具体是怎么样的。

我们的git工作流采用的是 git flow 。一个项目会拆分成几个模块,然后一人负责一个模块(对应git flow的一个feature)独立开发。模块开发并与后端联通后再合并至develop进行集成测试,后续经过一系列测试再发布版本。

目录结构大体如图所示,一个模块包含了他自己的pages / components / assets / model / mixins / apis / routes / scss等等。

这种开发模式的好处不言而喻,每个人都可以并行开发,大大提升开发速度。这次就是要移植这种开发模式到小程序中。

目标

背景说完了,那么来明确一下我们的目标。

我采用的是 wepy 框架,类vue语法的开发,开发体验非常棒。在vue中,一个组件就是单文件,包含了js、html、css。wepy采用vue的语法,但由与vue稍稍有点区别,wepy的组件分为三种--wepy.app类,wepy.page类,wepy.component类。

对应到我们的目录结构中,每个模块实际上就是一系列的page组件。要组合这一系列的模块,那么很简单,我们要做的就是把这一系列page的路由扫描成一个路由表,然后 插入到小程序的入口--app.json中 。对应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的路由并综合成一个 路由表 !

我的方案是,在每个模块中新建一份routes文件,相当于注册每个需要插入到入口的page的路由,不需要接入业务的page就不用注册啦。是不是很熟悉呢,对的,就是参考vue-router的注册语法。

//routes.js
module.exports = [
    {
        name: 'home-detail',//TODO: name先占位,后续再尝试通过读name跳转某页
        page: 'detail',//需要接入入口的page的文件名。例如这里是index.wpy。相对于src/的路径就是`modules/${moduleName}/pages/index`。
    },
    {
        name: 'home-index',
        page: 'index',
        meta: {
            weight: 100//这里加了一个小功能,因为小程序指定pages数组的第一项为首页,后续我会通过这个权重字段来给pages路由排序。权重越高位置越前。
        }
    }
]

而扫描各个模块并合并路由表的脚本非常简单,读写文件就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']

替换路由数组

So far so good...问题来了,如何替换入口文件中的路由数组。我如下做了几步尝试。

直接引入

我第一感觉就是,这不很简单吗?在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'
    }
  }
//...
}

然而这样小程序肯定会炸啦,pages字段的值必须是静态的,在小程序运行之前就配置好,动态引入是不行的!不信的话诸君可以试试。那么就是说,划重点--- 我们必须在wepy编译之前再预编译一次 ---事先替换掉pages字段的值!

正则匹配替换

既然要事先替换,那就是要精准定位pages字段的值,然后再替换掉。难点在于如果精准定位pages字段的值呢?

最捞然而最快的方法:正则匹配。

事先定好编码规范,在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__ */标记注释')
    }
    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'
    }
  }
//...
}

行吧,也总算跑通了。因为项目很赶,所以先用这个方案开发了一个半星期。开发完之后总觉得这种方案太难受,于是密谋着换另一种各精准的自动的方案。。。


本文地址:https://www.eyoucms.com/wxmini/doc/course/24246.html 复制链接 如需定制请联系易优客服咨询:800182392 点击咨询
QQ在线咨询