uniapp通过目录结构和自定义路由自动生成pages.json文件

场景描述

Uniapp 微信小程序项目使用的页面路由文件是Json格式的文件,cli项目在新增页面的时候需要手动添加页面路径,非常麻烦。

设计思路

通过nodejs遍历项目主包,分包路径,过滤出指定页面文件(如:index.vue)路径,然后整理重新写入pages.json文件,将方法封装成打包器插件,在指定路径下文件有修改时重新执行方法,热更新。

自定义路由存在的目的是为了兼容名称非 index.vue 的页面文件

具体实现

Tips: 本文仅介绍 Vue3 vite cli构建的项目 Vue2 webpack 版本详见
由HBuilderX 构建的项目在添加文件时会自动在pages.json中添加页面路径

项目目录

在这里插入图片描述

主函数 (build-routes.js)

import fs from "fs"
import path from "path"
import lodash from "lodash"

// 函数传入一个options 包含四个属性
// {
//    mainRootPath: "",      主包根路径(作者习惯将主包放进main中统一格式)
//    subRootPath: [],       分包根路径(也就是pages.json中 subPackages[] -> root)
//    pagesJsonPath: '',	 pages.json 文件的路径 一般不会变化
//    routesPath: ''         自定义路由文件的路径
// }
// 所有路径统一使用相对路径
function BuildRoutes(options) {
  const {
    mainRootPath = "main",
    subRootPath = [],
    pagesJsonPath = "src/pages.json",
    routesPath = "src/routes/index.json"
  } = options //默认属性值
  const customRoutes = readExportedData(path.join(__dirname, routesPath)) // 提取自定义路由

  //主包文件路径集合
  const _main = getAllFiles(path.join(__dirname, "src/" + mainRootPath), [], "src/").map((item) => {
    return {
      path: item
    }
  })
  //分包文件路径集合 
  const subPackages = subRootPath.map((_path) => {
    return {
      root: _path,
      pages: getAllFiles(path.join(__dirname, "src/" + _path), [], `src/${_path}/`).map((item) => {
        return {
          path: item
        }
      })
    }
  })
  // 合并主包、分包路由,判断有没有分包路由 没就不加了
  const routes = {
    pages: _main
  }
  if (!lodash.isEmpty(subPackages)) {
    routes.subPackages = subPackages
  }
  //合并遍历出来的文件路由和自定义路由,后续的所有自定义路由修改会同步到pages.json中
  const result = mergeObjects(routes, customRoutes)
  //pages.json文件权限管理,防止不小心修改
  fs.chmodSync(path.join(__dirname, pagesJsonPath), 0o666)
  fs.writeFileSync(
    path.join(__dirname, pagesJsonPath),
    `//此文件按照目录结构由build-routes.js自动生成,请勿手动修改!\n//如需单独修改页面样式请在/${routesPath}中添加需要修改的页面内容!\n
      ${JSON.stringify(result, null, 2)}`,
    "utf-8"
  )
  fs.chmodSync(path.join(__dirname, pagesJsonPath), 0o444)
}

function getAllFiles(dirPath, arrayOfFiles, split) {
  let files = []
  files = fs.readdirSync(dirPath)
  files.forEach(function (file) {
    const filePath = path.join(dirPath, file)
    if (fs.statSync(filePath).isDirectory()) {
      arrayOfFiles = getAllFiles(filePath, arrayOfFiles, split)
    } else if (path.basename(filePath) === "index.vue") { // 约定页面文件名字为index.vue
      arrayOfFiles.push(filePath.replaceAll("\\", "/").split(split)[1].replaceAll(".vue", ""))
    }
  })

  return arrayOfFiles
}

function readExportedData(filePath) {
  const fileData = fs.readFileSync(filePath, "utf-8")
  return JSON.parse(fileData)
}

// 合并函数,主包按照path来合并,分包按照root和path合并。
function mergeObjects(target, source) {
  for (let key in source) {
    if (key in target) {
      if (typeof source[key] === "object" && !Array.isArray(source[key])) {
        if (!target[key]) {
          target[key] = {}
        }
        mergeObjects(target[key], source[key])
      } else if (Array.isArray(source[key])) {
        source[key].forEach((item) => {
          const id = item.path || item.root
          const index = target[key].findIndex((t) => t.path === id || t.root === id)
          if (index >= 0) {
            mergeObjects(target[key][index], item)
          } else {
            target[key].push(item)
          }
        })
      } else {
        target[key] = source[key]
      }
    } else {
      target[key] = source[key]
    }
  }
  return target
}

export default BuildRoutes

vite插件 (vite-plugin-use-callback.js)

import chokidar from "chokidar"
// 监听path路径下的文件变动,当文件发生变动时执行callback函数
export default function vitePluginUseCallback(options) {
  const { path, callback } = options
  let hasCalled = false
  return {
    name: "vite-plugin-use-callback",
    enforce: "pre",
    buildStart: (options) => {
      if (!hasCalled && process.env.NODE_ENV === "development") {
        callback()
        const watcher = chokidar.watch(path)
        watcher.on("all", (file) => {
          callback()
        })
        hasCalled = true
      }
    }
  }
}

使用(vite.config.js)

import { defineConfig } from "vite"
import uni from "@dcloudio/vite-plugin-uni"
import vitePluginUseCallback from "./plugins/vite-plugin-use-callback.js"
import path from "path"
import buildRoutes from "./build-routes.js"

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    uni(),
    vitePluginUseCallback({
      path: path.join(__dirname, "./src"),
      callback: () => {
        buildRoutes({
          mainRootPath: "main",
          subRootPath: []
        })
      }
    })
  ]
})


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值