node小工具 | 根据文件列表自动生成路由提升工作效率

1,067 阅读4分钟

老话说得好光说不练假把式,要学会学以致用,今天搞了个node小工具方便我们在开发中提升效率

问题

我们来分析一下现在存在的问题(小问题🤔)目前在我们的开发工作中如果新建一个可跳转显示的路由页面一般需要下面几步

1、在当前文件夹下面新建页面或者是.vue或者是.jsx
2、在路由配置列表中新建对应的路径配置信息
3、如果需要像router-link这种跳转方式还需要手动创建一个

如果是一个新的项目可想而知我们需要重复N次以上步骤,浪费时间是肯定的那么今天我们的目的就是解决以上存在的问题,能让我们有更多的时间去写bug,最后可以做到只要在当前文件夹下建立文件之后,路由配置和router-link会自动生成

原理

对于以上功能我们先说原理之后在实现,我觉得这样可能更方便后面的理解,大概有几个步骤

1、首先监听当前文件夹下文件的变化,如果有变化就执行方法
2、监测到变化执行refresh刷新方法
3、方法内部会获取文件夹下所有文件名字最后用于生产路由配置
4、创建一个compile方法用于读取模版引擎和渲染路由配置
5、最后输出log

准备

我们需要做几个准备工作
1、创建环境本次选用的是vue的环境使用,vue-cli工具生成
2、创建模版引擎页面,在根目录创建template文件夹在内部放入router.js.hbsApp.vue.hbs,这两个模版引擎使用的是handlebars(如果不了解的同学可以先去看一下)

router.js.hbs

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

export default new Router({
  mode: 'history',
  base: process.env.BASE_URL,
  routes: [
    {{#each list}}
    {
      path: '/{{path}}',
      name: '{{path}}',
      component: () => import('../components/{{file}}')
    },
    {{/each}}
  ]
})

App.vue.hbs

<template>
  <div id="app">
    <div id="nav">
      {{#each list}}
        <router-link to="/{{path}}">{{path}}</router-link>
      {{/each}}
    </div>
    <router-view/>
  </div>
</template>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

ok到这里准备工作就已经完成了可以开始操作了,我们先看一下页面的样子,之后自动生成的路由会在后面排队显示

WechatIMG26.png

开始

1、在根目录下创建components文件夹之后在下面创建两个页面home.vuelogin.vue
2、更改App.vuerouter/index.js让路由先跑起来

home.vue

<template>
  <div class="home">
    <h2>home</h2>
  </div>
</template>

<script>
export default {
  name: 'home',
  data () {
    return {
      msg: 'Welcome to Your Vue.js App'
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>

</style>

login.vue

<template>
  <div class="login">
      login
  </div>
</template>

<script>
export default {
  name: 'login',
  data () {
    return {
      msg: 'Welcome to Your Vue.js App'
    }
  }
}
</script>

<style scoped>

</style>

App.vue

<template>
  <div id="app">
    <div id="nav">
        <router-link to="/home">home</router-link>
        <router-link to="/login">login</router-link>
    </div>
    <router-view/>
  </div>
</template>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

router/index.js

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

export default new Router({
  mode: 'history',
  base: process.env.BASE_URL,
  routes: [
    {
      path: '/home',
      name: 'home',
      component: () => import('../components/Home.vue')
    },
    {
      path: '/login',
      name: 'login',
      component: () => import('../components/login.vue')
    },
  ]
})

在package.json增加启动命令refresh启动命令

"scripts": {
    "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
    "start": "npm run dev",
    "refresh": "node ./lib/server.js", 
    "build": "node build/build.js"
  },

在根目录创建一个lib文件夹在下面创建server.js用来监听components下面的变化

//yarn add -D watch

const watch = require('watch')

let isRefresh = false
watch.watchTree('./src/components', async () => {
    //监听到文件变化
    if (!isRefresh) {
        isRefresh = true
        //执行刷新路由文件
        await require('./refresh')()
        setTimeout(() => {
            isRefresh = false
        }, 500)
    }
})

创建refresh.js用来刷新路由并且展示日志

//yarn add -D handlebars figlet chalk clear
 
const fs = require('fs')
const handelBarse = require('handlebars')
const { promisify } = require('util')
const figlet = promisify(require('figlet')) //获取设置终端logo方式
const clear = require('clear')
const chalk = require('chalk')
const logGreen = content => console.log(chalk.green(content))
const logRed = content => console.log(chalk.red(content))

let prevList = [] //存储上一次的更新记录
   
module.exports = async () => {
    //读取文件目录
    const list = fs.readdirSync('./src/components').map(file => ({
        path: file.replace('.vue', '').toLocaleLowerCase(),
        file
    }))
    
    //创建编译更新函数
    const compile = async (meta, filepath, templatePath) => {
        if (fs.existsSync(templatePath)) {
            const content = fs.readFileSync(templatePath).toString()
            //执行模版引擎传入参数
            const result = handelBarse.compile(content)(meta)
            //写入文件
            fs.writeFileSync(filepath, result)
        }
    }
    
    //覆盖router/index.js
    compile({ list }, './src/router/index.js', './template/router.js.hbs')
    //覆盖App.vue
    compile({ list }, './src/App.vue', './template/App.vue.hbs')
    clear()
    //输出更新日志
    inputLog(list, prevList)
    prevList = list
}

inputLog

const inputLog = async (currList, prevList) => {

    if (prevList.length !== 0) {
        let file = ''
        let prevListPath = prevList.map(item => item.path)
        let currListPath = currList.map(item => item.path)

        if (prevListPath.length > currList.length) {
            file = prevList.find(item => !currListPath.includes(item.path))?.file || ''
            if (file) logRed(`删除${file}🚀🚀🚀`)
        } else {
            file = currList.find(item => !prevListPath.includes(item.path))?.file || ''
            if (file) logGreen(`新增${file}🚀🚀🚀`)
            else logGreen(`更新完成🚀🚀🚀`)
        }
    } else {
        const tips = await figlet(`start success`)
        logGreen(tips)
    }
}

试验

执行npm run server启动监听

WechatIMG27.png

之后在components下面创建一个test3.vue文件

WechatIMG28.png

接下来在删除test3.vue文件

WechatIMG29.png

可以在控制台中看出都是能监听到的,这样的话我们在创建新页面的时候就只需要在当前目录下创建文件即可,不需要在考虑其他配置路由路径的情况

总结

写作的话对自己有个加深的印象,而且以后复盘起来也比较方便同时又是学习一遍的过程,如果大家觉得有用的话留个赞呗☕️