分享 Route Mapper - JavaScript 实现的 Rails Routing 风格的路由系统

fundon · 2015年01月19日 · 3497 次阅读

Route Mapper

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');
  });

});

结合现有 Node.js 的 web frameworks

Express

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);

Koa

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 等能力很强,但总感觉过于松散,每次下手都得对目录结构想一番。 该模块还在不懂的完善中。:)

暂无回复。
需要 登录 后方可回复, 如果你还没有账号请 注册新账号