使用Node.js实现动态路由 精简Express项目all_routes.js重复代码
Express静态渲染路由精简方案
方案1:路由配置映射表批量注册(最稳妥,改造成本最低)
你当前所有路由都是请求路径和渲染模板一一对应的规则,先把映射关系抽成配置数组,循环注册即可,不需要修改其他业务代码,直接替换all_routes.js内容就行:
var express = require("express"); var router = express.Router(); // 抽离路由-模板映射关系,后续加新路由只需要往这个数组加条目即可 const routeMap = [ { path: '/', tpl: 'home/index.html' }, { path: '/about', tpl: 'about/index.html' }, { path: '/contact', tpl: 'contact/index.html' }, { path: '/product', tpl: 'product/index.html' }, { path: '/product/demo-product', tpl: 'demo-product/index.html' }, { path: '/product/request-product', tpl: 'request-product/index.html' }, { path: '/service', tpl: 'product/index.html' }, { path: '/service/what-we-do', tpl: 'what-we-do/index.html' }, { path: '/service/how-we-do', tpl: 'how-we-do/index.html' }, ] // 批量注册路由 routeMap.forEach(item => { router.get(item.path, (req, res, next) => { res.render(item.tpl) }) }) module.exports = router
方案2:通配符动态路由(代码量最少,适合路径和模板路径规则统一的场景)
如果你的路由路径和模板路径遵循固定匹配规则,也可以用通配符匹配路由,不需要手动维护配置表:
var express = require("express"); var router = express.Router(); const fs = require('fs') const path = require('path') // 替换为你项目实际的视图文件存储目录 const VIEW_ROOT = path.join(__dirname, '../views') // 特殊规则优先注册,优先级高于通配符路由 router.get('/', (req, res) => res.render('home/index.html')) router.get('/service', (req, res) => res.render('product/index.html')) // 匹配所有一级、二级路径 router.get('/:page/:subpage?', (req, res, next) => { const { page, subpage } = req.params const tplName = subpage || page const tplPath = path.join(VIEW_ROOT, tplName, 'index.html') // 模板存在则渲染,不存在则走后续404逻辑 if (fs.existsSync(tplPath)) { res.render(`${tplName}/index.html`) } else { next() } }) module.exports = router
注意:特殊路由必须写在通配符路由前面,否则会被通配符规则覆盖。
方案3:自动扫描视图目录生成路由(零配置,新增页面无需修改路由代码)
如果项目后续会频繁新增页面,可以写目录扫描逻辑,自动识别views目录下的所有index.html生成对应路由,新增页面只需要建对应视图文件夹即可,不需要修改路由代码:
var express = require("express"); var router = express.Router(); const fs = require('fs') const path = require('path') const VIEW_DIR = path.join(__dirname, '../views') // 递归扫描视图目录,自动生成路由 function scanViewDir(dir, baseRoute = '') { const files = fs.readdirSync(dir) files.forEach(file => { const fullPath = path.join(dir, file) const stat = fs.statSync(fullPath) if (stat.isDirectory()) { scanViewDir(fullPath, path.join(baseRoute, file)) } else if (file === 'index.html') { // 生成路由路径 const routePath = baseRoute === 'home' ? '/' : `/${baseRoute.replace(/\\/g, '/')}` // 跳过已经手动注册的特殊路由 const isRegistered = router.stack.some(layer => layer.route?.path === routePath) if (!isRegistered) { const tplPath = path.join(baseRoute, 'index.html').replace(/\\/g, '/') router.get(routePath, (req, res) => res.render(tplPath)) } } }) } // 先注册特殊规则路由 router.get('/service', (req, res) => res.render('product/index.html')) // 自动扫描注册剩余路由 scanViewDir(VIEW_DIR) module.exports = router
内容的提问来源于stack exchange,提问作者user16041868
相关产品推荐
相关产品推荐

