爱意满满的作品展示区。
fundon

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

  •  
  •   fundon · Jan 19, 2015 · 4100 views
    This topic created in 4160 days ago, the information mentioned may be changed or developed.

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

    2 replies    2015-01-23 14:09:15 +08:00
    GPU
        1
    GPU  
       Jan 19, 2015 via iPhone
    轮子哦,赞赞
    Temo
        2
    Temo  
       Jan 23, 2015 via iPhone
    赞一个!
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   3135 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 108ms · UTC 13:24 · PVG 21:24 · LAX 06:24 · JFK 09:24
    ♥ Do have faith in what you're doing.