JavaScript 实现(ES6+ 编写)的 Rails Routing 风格的路由系统。 通过它可以生成 routes mapper,借助 routes mapper 可以进行 DIY,方便、简化路由入口与其他模块的整合开发。
基本上实现算法都是参照 actionpack/lib/action_dispatch/routing 及好文 Rails 路由系统源码探索。 使用 JavaScript ES6+ 进行编写开发(跟上时代步伐……)。
rails new blog
生成路由模板)let routeMapper = new RouteMapper();
routeMapper.draw((m) => {
// You can have the root of your site routed with "root"
m.root('welcome#index');
// /products/233 controller = catalog, action = view
m.get('products/:id', { to: 'catalog#view' });
// Example named route that can be invoked with purchase_path(id: product.id)
// /products/233/purchase === purchase_path(233)
m.get('products/:id/purchase', { to: 'catalog#purchase', as: 'purchase' });
// Example resource route (maps HTTP verbs to controller actions automatically):
m.resources('products');
// Example resource route with options:
m.resources('products', () => {
m.member(() => {
m.get('short');
m.post('toggle');
});
m.collection(() => {
m.get('sold');
});
});
// Example resource route with sub-resources:
m.resources('products', () => {
m.resources('comments', 'sales');
m.resource('seller');
});
// Example resource route with more complex sub-resources:
m.resources('products', () => {
m.resources('comments')
m.resources('sales', () => {
m.get('recent', { on: 'collection' });
});
});
// Example resource route with concerns:
m.concern('toggleable', () => {
m.post('toggle');
});
m.resources('posts', { concerns: 'toggleable' });
m.resources('photos', { concerns: 'toggleable' });
// Example resource route within a namespace:
m.namespace('admin', () => {
// Directs /admin/products/*
m.resources('products');
});
});
import express from 'express';
import RouteMapper from '../..';
let app = express();
let routeMapper = new RouteMapper();
routeMapper.draw((m) => {
m.root('welcome#index');
m.resources('photos');
m.constraints({ subdomain: 'api' }, () => {
m.namespace('api', { defaults: { format: 'json' }, path: '/' }, () => {
m.scope({ module: 'v1' }, () => {
m.resources('users');
});
}
);
});
});
app.use(function (req, res, next) {
res.locals.urlHelpers = routeMapper.urlHelpers;
next();
});
routeMapper.routes.forEach((r) => {
r.via.forEach((m) => {
let controller = r.controller;
let action = r.action;
let c = require(__dirname + '/controllers/' + controller + '.js');
let a;
if (c && (a = c[action])) {
if (!Array.isArray(a)) {
a = [a];
}
app[m](r.path, ...a);
};
});
});
app.listen(3300);
import koa from 'koa';
import router from 'koa-router';
import RouteMapper from '../..';
let app = koa();
let routeMapper = new RouteMapper();
routeMapper.draw((m) => {
m.root('welcome#index');
m.get('about', { to: 'welcome#about' });
m.resources('posts', () => {
m.resources('comments');
});
m.scope({ path: '~:username?', module: 'users', as: 'user'}, () => {
m.root('welcome#index');
});
});
app.use(function *(next) {
this.urlHelpers = routeMapper.urlHelpers;
yield next;
});
app.use(router(app));
routeMapper.routes.forEach((r) => {
r.via.forEach((m) => {
let controller = r.controller;
let action = r.action;
let c = require(__dirname + '/controllers/' + controller + '.js');
let a;
if (c && (a = c[action])) {
if (!Array.isArray(a)) {
a = [a];
}
app[m](r.path, ...a);
};
});
});
app.listen(3300);
Rails 在这些地方的设计确实很棒,Express.js,Koa.js 等 Node.js Web 框虽然 DIY 等能力很强,但总感觉过于松散,每次下手都得对目录结构想一番。 该模块还在不懂的完善中。:)