Moving from PHP to a nodejs full stack
CMS
September 2014
Andrew	
  Zuercher	
  
Introductions
Keystonejs 2
Andrew Zuercher
Chief Innovation Officer
CMS - Wordpress way
Keystonejs 3
•  LAMP
•  Data
–  Custom fields
–  Taxonomies
•  Themes/Marketplaces
•  Lots of plugins
BUT ITS STILL IN PHP!!!!
Makeandbuild.com – wordpress version
Keystonejs 4
•  Took an existing theme
•  Customized/Tweaked CSS
•  Different models
–  Posts
–  Portfolio items (work)
–  Service items (capabilities)
TIME TO MARKET: 2+ months
Keystone POC
Keystonejs 5
•  Drivers
–  Mongo
–  Bootstrap
–  Choice of templating
–  Express
ALL IN TOOLS WORK WITH!!!
Migration
Keystonejs 6
•  Time to market
–  Rewrote in 2 weeks
–  Integrated into sales force
–  Backported all routes
–  Development streamlined – mongo over MySQL
•  PERFORMANCE INCREASE OF 200%
Admin UI
Keystonejs 7
•  Part of keystone module
•  Default route – xxxx/keystone
•  Supports multiple users
–  active/inactive
–  Permissions
•  Editor
–  Tinymce/WYSIWYG
•  image support
•  Published/Draft/Support state support
Tech Stack Details
Keystonejs 8
•  express/connect – dynamic routes
•  Mongo – flexible model
•  Templating - jade/handlebars/mustache
•  LESS/SASS support
Services
Keystonejs 9
•  Google analytics
•  Google Maps
•  Amazon s3
•  Cloudinary
•  Embed.ly
•  Mandrill
Getting Started
Keystonejs 10
•  Yeoman generator - https://github.com/keystonejs/generator-keystone
•  Boostrap based (LESS)
> sudo npm install –g generator-keystone
> mkdir myproject
> cd myproject
> yo keystone
> node keystone
http://localhost:3000
Project structure
Keystonejs 11
•  keystone.js – intital load
•  .env – system properties
•  templates/views/xxx.hbs
•  models/xxx.js -
•  public/(styles|images|js|fonts) – static assets
•  routes/
–  index.js – baseline
–  Views/xxx.js – controllers
Adding a new model
Keystonejs 12
var	
  Project	
  =	
  new	
  keystone.List('Project',	
  {	
  
	
  map:	
  {	
  name:	
  '@tle'	
  },	
  
	
  autokey:	
  {	
  path:	
  'slug',	
  from:	
  '@tle',	
  unique:	
  true	
  },	
  
	
  sortable:	
  true,	
  
	
  defaultSort:	
  'sortOrder'	
  
});	
  
Project.add({	
  
	
  @tle:	
  {	
  type:	
  String,	
  required:	
  true	
  },	
  
	
  company:	
  {	
  type:	
  String,	
  required:	
  true,	
  ini@al:	
  true,	
  },	
  
	
  state:	
  {	
  type:	
  Types.Select,	
  op@ons:	
  'draL,	
  published,	
  archived',	
  default:	
  'draL',	
  index:	
  true	
  },	
  
	
  image:	
  {	
  type:	
  Types.S3File	
  },	
  
	
  metaData:	
  {	
  
	
   	
  @tle:	
  {	
  type:	
  Types.Text	
  },	
  
	
   	
  descrip@on:	
  {	
  type:	
  Types.Text	
  }	
  
	
  },	
  
	
  content:	
  {	
  type:	
  Types.Html,	
  wysiwyg:	
  true,	
  height:	
  400	
  },	
  
	
  tes@monial:	
  {	
  
	
   	
  text:	
  {	
  type:	
  Types.Text,	
  wysiwyg:	
  true,	
  height:	
  150	
  },	
  
	
   	
  author:	
  {	
  type:	
  String	
  },	
  
	
   	
  @tle:	
  {	
  type:	
  String	
  }	
  
	
  },	
  
	
  categories:	
  {	
  type:	
  Types.Rela@onship,	
  ref:	
  'ProjectCategory',	
  many:	
  true	
  }	
  
});	
  
	
  
Adding a new Controller
Keystonejs 13
exports	
  =	
  module.exports	
  =	
  func@on(app)	
  {	
  
	
  …	
  
	
  app.get('/work',	
  routes.views.work);	
  
	
  app.get('/work/:project',	
  
routes.views.project);	
  
•  index.js
•  Routes/views/work.js
var	
  view	
  =	
  new	
  keystone.View(req,	
  res),locals	
  =	
  res.locals;	
  
View.on(‘init’,	
  func@on(next)	
  {	
  
	
  //access	
  model	
  and	
  store	
  results	
  in	
  res.locals.data	
  
}); 	
  	
  
//	
  Render	
  the	
  view	
  
view.render('work');	
  
Adding a View
Keystonejs 14
•  Templates/views/work.hbs
<div	
  class="container">	
  
	
  <div	
  class="row">	
  
	
   	
  <div	
  class="col-­‐sm-­‐12	
  col-­‐md-­‐12">	
  
	
   	
   	
  <div	
  class="blog	
  ar@cle-­‐list">	
  
	
   	
   	
   	
  {{#	
  each	
  data.items.results}}	
  
	
   	
   	
   	
  <a	
  href="/work/{{slug}}"	
  class="ar@cle	
  blog-­‐post	
  work-­‐post">	
  
	
   	
   	
   	
   	
  <div	
  class="blog-­‐image">	
  
	
   	
   	
   	
   	
   	
  <img	
  src="{{image.url}}"	
  alt="{{company}}"	
  class="img-­‐responsive">	
  
	
   	
   	
   	
   	
  </div>	
  
	
   	
   	
   	
   	
  <div	
  class="blog-­‐content">	
  
	
   	
   	
   	
   	
   	
  <h1	
  class="blog-­‐@tle	
  cap">{{@tle}}</h1>	
  
	
   	
   	
   	
   	
   	
  <h3	
  class="work-­‐meta	
  uc">{{company}}</h3>	
  
	
   	
   	
   	
   	
  </div>	
  
	
   	
   	
   	
  </a>	
  
	
   	
   	
   	
  {{/each}}	
  
	
   	
   	
  </div>	
  
	
   	
  </div>	
  
	
  </div>	
  
</div>	
  
Additional items
Keystonejs 15
•  templates/views/layouts/default.hbs
•  Make use of bower
•  routes/middleware.js – setup injections
–  requireUser, etc
Administration UI Customization
Keystonejs 16
•  Currently they are switching to ReactJS for the Admin Ui and moving it to the
client side to allow customizable Admin Sections
•  They have made a branch with the reactjs but haven't completed a stable
version.
•  https://github.com/keystonejs/keystone/issues/204
•  https://github.com/keystonejs/keystone/issues/503
•  Once complete, plugin framework next
CMS (THEME)
Keystonejs 17
•  Seems like all their focus is the switch to React.js for the customizability. So
all other things have been pushed off. But their plan is to eventually allow for
themes.
•  THEY really want theme capability wordpress has.
•  https://github.com/keystonejs/keystone/issues/67
Example Sites
Keystonejs 18
•  sydjs.com
•  http://keystonejs.com/examples/
Security
Keystonejs 19
•  Can make use of the User permission based model and roll own
–  Check req.user to see if user is logged in
–  Identify needed chain in middleware as identified earlier (pre-route)
–  Modify chain in routes themselves ex:
exports	
  =	
  module.exports	
  =	
  func@on(app)	
  {	
  
	
  app.get('/resumes/:filename',	
  middleware.requireUser,	
  routes.views.resumes);	
  
};	
  
Deployment
Keystonejs 20
•  Don’t control .env
•  Nginx reverse proxy
•  Run via forever
•  See the oneline docs for config
–  http://keystonejs.com/docs/configuration/#options
QUESTIONS?
Keystonejs 21
Q&A

Moving from PHP to a nodejs full stack CMS

  • 1.
    Moving from PHPto a nodejs full stack CMS September 2014 Andrew  Zuercher  
  • 2.
  • 3.
    CMS - Wordpressway Keystonejs 3 •  LAMP •  Data –  Custom fields –  Taxonomies •  Themes/Marketplaces •  Lots of plugins BUT ITS STILL IN PHP!!!!
  • 4.
    Makeandbuild.com – wordpressversion Keystonejs 4 •  Took an existing theme •  Customized/Tweaked CSS •  Different models –  Posts –  Portfolio items (work) –  Service items (capabilities) TIME TO MARKET: 2+ months
  • 5.
    Keystone POC Keystonejs 5 • Drivers –  Mongo –  Bootstrap –  Choice of templating –  Express ALL IN TOOLS WORK WITH!!!
  • 6.
    Migration Keystonejs 6 •  Timeto market –  Rewrote in 2 weeks –  Integrated into sales force –  Backported all routes –  Development streamlined – mongo over MySQL •  PERFORMANCE INCREASE OF 200%
  • 7.
    Admin UI Keystonejs 7 • Part of keystone module •  Default route – xxxx/keystone •  Supports multiple users –  active/inactive –  Permissions •  Editor –  Tinymce/WYSIWYG •  image support •  Published/Draft/Support state support
  • 8.
    Tech Stack Details Keystonejs8 •  express/connect – dynamic routes •  Mongo – flexible model •  Templating - jade/handlebars/mustache •  LESS/SASS support
  • 9.
    Services Keystonejs 9 •  Googleanalytics •  Google Maps •  Amazon s3 •  Cloudinary •  Embed.ly •  Mandrill
  • 10.
    Getting Started Keystonejs 10 • Yeoman generator - https://github.com/keystonejs/generator-keystone •  Boostrap based (LESS) > sudo npm install –g generator-keystone > mkdir myproject > cd myproject > yo keystone > node keystone http://localhost:3000
  • 11.
    Project structure Keystonejs 11 • keystone.js – intital load •  .env – system properties •  templates/views/xxx.hbs •  models/xxx.js - •  public/(styles|images|js|fonts) – static assets •  routes/ –  index.js – baseline –  Views/xxx.js – controllers
  • 12.
    Adding a newmodel Keystonejs 12 var  Project  =  new  keystone.List('Project',  {    map:  {  name:  '@tle'  },    autokey:  {  path:  'slug',  from:  '@tle',  unique:  true  },    sortable:  true,    defaultSort:  'sortOrder'   });   Project.add({    @tle:  {  type:  String,  required:  true  },    company:  {  type:  String,  required:  true,  ini@al:  true,  },    state:  {  type:  Types.Select,  op@ons:  'draL,  published,  archived',  default:  'draL',  index:  true  },    image:  {  type:  Types.S3File  },    metaData:  {      @tle:  {  type:  Types.Text  },      descrip@on:  {  type:  Types.Text  }    },    content:  {  type:  Types.Html,  wysiwyg:  true,  height:  400  },    tes@monial:  {      text:  {  type:  Types.Text,  wysiwyg:  true,  height:  150  },      author:  {  type:  String  },      @tle:  {  type:  String  }    },    categories:  {  type:  Types.Rela@onship,  ref:  'ProjectCategory',  many:  true  }   });    
  • 13.
    Adding a newController Keystonejs 13 exports  =  module.exports  =  func@on(app)  {    …    app.get('/work',  routes.views.work);    app.get('/work/:project',   routes.views.project);   •  index.js •  Routes/views/work.js var  view  =  new  keystone.View(req,  res),locals  =  res.locals;   View.on(‘init’,  func@on(next)  {    //access  model  and  store  results  in  res.locals.data   });     //  Render  the  view   view.render('work');  
  • 14.
    Adding a View Keystonejs14 •  Templates/views/work.hbs <div  class="container">    <div  class="row">      <div  class="col-­‐sm-­‐12  col-­‐md-­‐12">        <div  class="blog  ar@cle-­‐list">          {{#  each  data.items.results}}          <a  href="/work/{{slug}}"  class="ar@cle  blog-­‐post  work-­‐post">            <div  class="blog-­‐image">              <img  src="{{image.url}}"  alt="{{company}}"  class="img-­‐responsive">            </div>            <div  class="blog-­‐content">              <h1  class="blog-­‐@tle  cap">{{@tle}}</h1>              <h3  class="work-­‐meta  uc">{{company}}</h3>            </div>          </a>          {{/each}}        </div>      </div>    </div>   </div>  
  • 15.
    Additional items Keystonejs 15 • templates/views/layouts/default.hbs •  Make use of bower •  routes/middleware.js – setup injections –  requireUser, etc
  • 16.
    Administration UI Customization Keystonejs16 •  Currently they are switching to ReactJS for the Admin Ui and moving it to the client side to allow customizable Admin Sections •  They have made a branch with the reactjs but haven't completed a stable version. •  https://github.com/keystonejs/keystone/issues/204 •  https://github.com/keystonejs/keystone/issues/503 •  Once complete, plugin framework next
  • 17.
    CMS (THEME) Keystonejs 17 • Seems like all their focus is the switch to React.js for the customizability. So all other things have been pushed off. But their plan is to eventually allow for themes. •  THEY really want theme capability wordpress has. •  https://github.com/keystonejs/keystone/issues/67
  • 18.
    Example Sites Keystonejs 18 • sydjs.com •  http://keystonejs.com/examples/
  • 19.
    Security Keystonejs 19 •  Canmake use of the User permission based model and roll own –  Check req.user to see if user is logged in –  Identify needed chain in middleware as identified earlier (pre-route) –  Modify chain in routes themselves ex: exports  =  module.exports  =  func@on(app)  {    app.get('/resumes/:filename',  middleware.requireUser,  routes.views.resumes);   };  
  • 20.
    Deployment Keystonejs 20 •  Don’tcontrol .env •  Nginx reverse proxy •  Run via forever •  See the oneline docs for config –  http://keystonejs.com/docs/configuration/#options
  • 21.