Day 24: 使用Yeoman自动构建Ember项目

简介: 到目前为止,我们这个系列讨论了Bower、AngularJS、GruntJS、PhoneGap、Meteor、Ember和TimelineJS等JavaScript技术。今天的《30天学习30种新技术》,我决定学习前端开发的效率工具Yeoman。本文将首先介绍Yeoman的基本情况,接着我们会使用Yeoman开发一个Ember应用。本文不会介绍EmberJS的基本知识,所以请参考day 19。

编者注:我们发现了有趣的系列文章《30天学习30种新技术》,正在翻译,一天一篇更新,年终礼包。下面是第 天的内容。


到目前为止,我们这个系列讨论了BowerAngularJSGruntJSPhoneGapMeteorEmberTimelineJS等JavaScript技术。今天的《30天学习30种新技术》,我决定学习前端开发的效率工具Yeoman。本文将首先介绍Yeoman的基本情况,接着我们会使用Yeoman开发一个Ember应用。本文不会介绍EmberJS的基本知识,所以请参考day 19

image.png

Yeoman是什么?

Yeoman按照官方说法,它不只是一个工具,还是一个工作流。它其实包括了三个部分yo、grunt、bower,分别用于项目的启动、文件操作、包管理。

  1. Yo: Yo是一个项目初始化工具,可以生成一套启动某类项目必需的项目文件。
  2. GruntJS: GruntJS是基于JavaScript的命令行构建工具,它可以帮助开发者们自动化重复性的工作。阅读day 5获取更多信息。
  3. Bower: Bower是一个客户端技术的软件包管理器,它可用于搜索、安装和卸载如JavaScript、HTML、CSS之类的网络资源。阅读day 1获取更多信息。


我为什么关心Yeoman

如果你需要说服自己学习Yeoman,你可以读读Yeoman网站上的whyyeoman


安装

使用npm安装:

npm install -g yeoman

安装Yeoman Ember生成器

Yeoman依赖生成器为web项目提供支架。所有的现代JavaScript MV* 框架都有相应的生成器。本文使用Ember:

npm install -g generator-ember

我们将开发一个社交化书签应用,允许用户提交和分享链接。你可以在这里查看这个应用。这个应用和我们day 19开发的一样。


Github仓库

今天的示例应用代码可从Github取得。


创建Ember应用

现在开始应用开发。首先创建项目目录,接着运行yo ember命令,它会询问你是否使用Twitter Bootstrap。我习惯在自己的项目中使用Bootstrap,所以我选了是。

; mkdir getbookmarks

; cd getbookmarks

; yo ember

    _-----_

   |       |

   |--(o)--|   .--------------------------.

  ---------  |    Welcome to Yeoman,    |

   ( __ )   |   ladies and gentlemen!  |

   /___A___\   '__________________________'

    |  ~  |

  __'.___.'__

[?] Would you like to include Twitter Bootstrap for Sass? Yes

之后Yeoman会创建一个Ember应用,自动使用bowernpm安装依赖。

现在让我们看看Yeoman生成的Ember应用。应用有三个顶层目录:appnode_modulestest。还有一些配置文件:.bowerrc.gitignore.jshintrcGruntfile.jspackage.json。目录结构如下所示。

image.png

所有的应用相关代码都在app目录下。目录结构遵循Ember的最佳实践。

image.png

  1. bower_components目录包括了客户端依赖,例如Ember、Twitter Bootstrap,等等。Bower在所有文件夹内安装所有依赖。
  2. image目录包括了应用相关的图像。Yeoman会优化image目录内的图片。
  3. index.html包含了所有的ember.js依赖,所有的bootstrap依赖,以及build注释(Gruntfile.js可以据此替换或移除引用的未优化的脚本和样式表)。
  4. scripts目录包含了Ember应用的controller、view、model和route。
  5. styles目录包含了应用相关的css文件。
  6. templates目录包含了应用的handlebar模板。


现在我们可以启动预览服务器了:

grunt server


这会使用系统默认浏览器打开应用:

image.png

生成Story Model

我们在day19中开发的GetBookmarks应用中创建了一个Ember Model:Story。Yeoman的次级生成器可以用来构建项目的部分,包括model。运行如下命令生成Story model:

yo ember:model Story

命令的输出如下:

  create app/scripts/models/story_model.js

  invoke   ember:controller:/usr/local/lib/node_modules/generator-ember/model/index.js

  create     app/scripts/controllers/stories_controller.js

  create     app/scripts/controllers/story_edit_controller.js

  create     app/scripts/routes/stories_route.js

  create     app/scripts/routes/story_route.js

  create     app/scripts/routes/story_edit_route.js

  invoke       ember:view:/usr/local/lib/node_modules/generator-ember/controller/index.js

  create         app/scripts/views/story_view.js

  create         app/scripts/views/story_edit_view.js

  create         app/scripts/views/stories_view.js

  create         app/templates/story.hbs

  create         app/templates/story_edit.hbs

  create         app/templates/stories.hbs

  create         app/scripts/views/bound_text_field_view.js

  invoke       ember:router:/usr/local/lib/node_modules/generator-ember/controller/index.js

conflict         app/scripts/router.js

[?] Overwrite app/scripts/router.js? overwrite

   force         app/scripts/router.js

这会在app/scripts/models目录下生成story_model.js,同时会生成相应的view、controller和route。

修改下story_model

Emberapp.Story = DS.Model.extend({

 url : DS.attr('string'),

   tags : DS.attr('string'),

   fullname : DS.attr('string'),

   title : DS.attr('string'),

   excerpt : DS.attr('string'),

   submittedOn : DS.attr('date')

});

重新启动Grunt server以便改动生效。


安装Ember LocalStorage适配器

我们将使用HTML 5 LocalStorage来存储数据。使用bower安装适配器。

bower install --save ember-localstorage-adapter

然后更新index.html页面,添加依赖:

<scriptsrc="bower_components/ember-localstorage-adapter/localstorage_adapter.js"></script>

同时更新app/scripts/store.js,配置应用使用LSAdapter:

Getbookmarks.Store = DS.Store.extend();

Getbookmarks.ApplicationAdapter = DS.LSAdapter.extend({

 namespace: 'stories'

});

更新路由

修改router.js:

Getbookmarks.Router.map(function () {

 this.resource('index',{path : '/'});

 this.resource('story', { path: '/story/:story_id' });

 this.resource('story_edit', { path: '/story/new' });

});

提交新报道

我们首先添加用户访问#/story/new后会出现的表单。修改app/templates/story_edit.hbs

<formclass="form-horizontal"role="form">

     <divclass="form-group">

       <labelfor="title"class="col-sm-2 control-label">Title</label>

       <divclass="col-sm-10">

         <inputtype="title"class="form-control"id="title"name="title"placeholder="Title of the link"required>

       </div>

     </div>

     <divclass="form-group">

       <labelfor="excerpt"class="col-sm-2 control-label">Excerpt</label>

       <divclass="col-sm-10">

         <textareaclass="form-control"id="excerpt"name="excerpt"placeholder="Short description of the link"required></textarea>

       </div>

     </div>

     <divclass="form-group">

       <labelfor="url"class="col-sm-2 control-label">Url</label>

       <divclass="col-sm-10">

         <inputtype="url"class="form-control"id="url"name="url"placeholder="Url of the link"required>

       </div>

     </div>

     <divclass="form-group">

       <labelfor="tags"class="col-sm-2 control-label">Tags</label>

       <divclass="col-sm-10">

         <textareaid="tags"class="form-control"name="tags"placeholder="Comma seperated list of tags"rows="3"required></textarea>

       </div>

     </div>

     <divclass="form-group">

       <labelfor="fullname"class="col-sm-2 control-label">Full Name</label>

       <divclass="col-sm-10">

         <inputtype="text"class="form-control"id="fullname"name="fullname"placeholder="Enter your Full Name like Shekhar Gulati"required>

       </div>

     </div>

     <divclass="form-group">

       <divclass="col-sm-offset-2 col-sm-10">

         <buttontype="submit"class="btn btn-success"{{action'save'}}>Submit Story</button>

       </div>

     </div>

 </form>

现在,访问 http://localhost:9000/#/story/new 可以看到提交报道的表单。

更新StoryEditController,将数据持续化入本地存储:

Getbookmarks.StoryEditController = Ember.ObjectController.extend({

 save: function(){

   var url = $('#url').val();

       var tags = $('#tags').val();

       var fullname = $('#fullname').val();

       var title = $('#title').val();

       var excerpt = $('#excerpt').val();

       var submittedOn = newDate();

       var store = this.get('store');

       console.log('Store .. '+store);

       var story = store.createRecord('story',{

           url : url,

           tags : tags,

           fullname : fullname,

           title : title,

           excerpt : excerpt,

           submittedOn : submittedOn

       });

   story.save();

   this.transitionToRoute('index');

 }

});

列出所有报道

接下来我们要实现的功能是在侧边栏展示报道列表。

application_route.js,我们从本地存储获取所有的报道。

Getbookmarks.ApplicationRoute = Ember.Route.extend({

   model : function(){

       var stories = this.get('store').findAll('story');

       return stories;

   }

});

接着我们更新application.hbs,为每个报道的标题添加链接:

<div>

   <navclass="navbar navbar-default navbar-fixed-top"role="navigation">

       <divclass="navbar-header">

           <buttontype="button"class="navbar-toggle"data-toggle="collapse"data-target=".navbar-ex1-collapse">

               <spanclass="sr-only">Toggle navigation</span>

               <spanclass="icon-bar"></span>

               <spanclass="icon-bar"></span>

               <spanclass="icon-bar"></span>

           </button>

           <aclass="navbar-brand"href="#">GetBookmarks</a>

       </div>

       <divclass="collapse navbar-collapse navbar-ex1-collapse">

           <ulclass="nav navbar-nav pull-right">

               <li>{{#link-to'story_edit'}}<spanclass="glyphicon glyphicon-plus"></span> Submit Story{{/link-to}}</li>

           </ul>

       </div>

   </nav>

   <divclass="container"id="main">

       <divclass="row">

           <div>

               <divclass="col-md-3">

                   <divclass="well sidebar-nav">

                       <tableclass='table'>

                         <thead>

                           <tr><th>Recent Stories</th></tr>

                         </thead>

                         {{#each controller}}

                           <tr><td>

                           {{#link-to'story' this}}

                             {{title}}

                           {{/link-to}}

                           </td></tr>

                         {{/each}}

                       </table>

                   </div>

               </div>

               <divclass="col-md-9">

                   {{outlet}}

               </div>

           </div>

       </div>

   </div>

</div>

应用的用户界面会刷新。


查看单独的报道

最后要添加的功能是,用户访问 http://localhost:9000/#/story/:id 的时候可以查看单独的报道。:id对应于story id。修改story_routejs

Getbookmarks.StoryRoute = Ember.Route.extend({

 model : function(params){

       var store = this.get('store');

       return store.find('story',params.story_id);

 }

});

修改app/templates/story.hbs

<h1>{{title}}</h1>

<h2> by {{fullname}}<smallclass="muted">{{submittedOn}}</small></h2>

{{#each tagnames}}

 <spanclass="label label-primary">{{this}}</span>

{{/each}}

<hr>

<pclass="lead">

     {{excerpt}}

</p>

为生产环境构建

最后,我们运行grunt build命令创建一个可分发的应用。grunt build命令将app目录下的源文件转换成dist目录下的可分发的应用。

grunt build

今天就这些。保持反馈。

相关文章
|
8月前
|
存储 缓存 分布式计算
Hello Monorepo(上)
Hello Monorepo(上)
198 0
|
8月前
|
数据可视化 JavaScript 前端开发
Hello Monorepo(下)
Hello Monorepo(下)
117 0
|
8月前
|
JSON JavaScript 数据格式
使用pnpm搭建monorepo开发环境
使用pnpm搭建monorepo开发环境
363 0
|
8月前
|
JavaScript jenkins 持续交付
Jenkins自动化构建Vue项目的实践
在现代的Web开发中,Vue.js已经成为一种非常流行的JavaScript框架。为了更高效地管理和部署Vue.js项目,使用自动化构建工具是至关重要的。Jenkins作为一款强大的持续集成和持续部署(CI/CD)工具,为我们提供了一种便捷的方式来自动化构建Vue.js项目。本文将介绍如何在Jenkins中配置和使用自动化构建Vue.js项目的步骤。
184 1
Jenkins自动化构建Vue项目的实践
|
前端开发 JavaScript
React框架创建项目详细流程-项目的基本配置-项目的代码规范(二)
React框架创建项目详细流程-项目的基本配置-项目的代码规范(二)
|
Web App开发 存储 缓存
前端MonoRepo实战:pnpm+nx搭建MonoRepo项目
之前大多数是理论知识,能让我们知道pnpm 和nx 是什么,但是具体要到项目实战就有点懵,不知道从而下手,下面我们就一步步开始搭建pnpm+nx的Monorepo仓库。
1702 0
|
存储 资源调度 JavaScript
基于 Yeoman 脚手架技术构建前端项目的实践
基于 Yeoman 脚手架技术构建前端项目的实践
180 0
|
JSON 资源调度 JavaScript
Vue3源码阅读(1):使用 pnpm 搭建 monorepo 开发环境
本文介绍了如何使用新一代的包管理工具 Pnpm 快速创建一个 Monorepo 环境,并使用 esbuil 实现了一个打包脚本。
1771 2
|
监控 前端开发 JavaScript
Gulp前端自动化构建工具的应用
实际前端开发不再仅仅是静态页面的开发了,丰富的前端技术让前端的代码逻辑越来越复杂, 模块化开发和各类框架也增加了在生产环境中部署开发环境代码的难度,这种情况下,前端自动化构建在前端开发中尤为重要。 我们会遇到下面的问题: a. 每次修改了HTML、JS、CSS等文件,都需要手动刷新浏览器,能不能修改了让浏览器自动刷新呢 ? b. 在发布项目的时候,需要将前端资源进行合并、压缩,尽量减少http请求,手动去完成合并压缩不仅繁琐,还容易出错,有什么技术可以自动地执行这些操作,解放我们的双手呢?
143 0
Gulp前端自动化构建工具的应用
在vuecli3怎么提升构建打包速度?
在vuecli3怎么提升构建打包速度?
330 0