/
docMap.json
343 lines (343 loc) · 515 KB
/
docMap.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
{
"About": {
"src": {
"path": "docs/about.md"
},
"body": "\n## Goals\n\n\n\nDoneJS has three primary goals:\n\n1. To enable developers to easily create high performance, maintainable, highly usable (amazing) applications.\n2. To continually evolve with new techniques and tools.\n3. To support the technology community.\n\n### Amazing Applications\n\nBuilding a modern application is increasingly difficult. Your app\nneeds to look good and run fast on every\nplatform and browser. And, you need to get your app done yesterday.\nNot kinda done. Done done.\n\nHelping you get a high performance, sublimely usable, and maintainable application\ndone fast is DoneJS's primary goal. This is why our logo\nis a browser that looks like a checkered flag. We're committed\nto your release.\n\nWe aim to help in three main ways:\n\n#### 1. Solving difficult technical problems\n\nDoneJS has good solutions for:\n\n - [Building mobile and desktop applications](./Features.html#ios-android-and-desktop-builds)\n - [Server Side Rendering](./Features.html#server-side-rendered)\n - [Automatic real-time updates](./Features.html#real-time-connected)\n - [Fast download times](./Features.html#progressive-loading)\n\nThese are just a few examples from our [features page](./Features.html). If\nthere's a hard problem that you keep running into, we want to solve it.\n\n#### 2. Providing an integrated solution\n\nToo many choices can make decision making difficult. DoneJS simplifies\nmatters by providing a full stack of frontend tooling tested to work\ngreat together. The start of the [features page](./Features.html)\ngoes into detail with examples of this benefit.\n\n_Note: Despite being an integrated solution, you can replace parts of\nDoneJS with alternatives._\n\n\n#### 3. Doing the right thing\n\nWriting tests and documentation, setting up continuous integration and deployment\nisn't fun or easy. DoneJS tries to lower the barrier enough to\nmaking doing the _right thing_ simply part of the normal development cycle.\n\nCheck out what DoneJS does for:\n\n- [Tests](./Features.html#comprehensive-testing)\n- [Documentation](./Features.html#documentation)\n- [Continuous Integration and Deployment](./Features.html#continuous-integration--deployment)\n- [Modlets](./Features.html#modlets)\n- [Generators](./Features.html#generators)\n\n### Evolve\n\nApplication development and maintenance often\nlasts many years. Stability is needed to release complex applications. However,\nnew techniques and best practices are constantly evolving.\n\nDoneJS's goal is to strike a balance between immovable stability and irresistible progress. We do this by evolving frequently, while maintaining backward compatibility between major releases.\n\nIt can be a bumpy road, with lots of little changes. But it\navoids rewrites, resulting in greater productivity: \n\n<img src=\"https://www.bitovi.com/hubfs/Imported_Blog_Media/mountain-climb1.jpg\"/>\n\n\nDoneJS is the successor to JavaScriptMVC. If your project chose JavaScriptMVC in 2007, you would have made a wise decision, giving your team an upgrade path to a modern application for the past 10 years.\n\nWe hope to continue this trend until programs start writing themselves.\n\n### Community\n\nSoftware is better with friends. Our goal is to establish a world-wide\ncommunity with people of all backgrounds and skill levels dedicated to\nteaching, exploring, and innovating.\n\n#### Teaching\n\nTechnology is worth nothing if people don't know how to use it. We want\nto create great learning material, but also create an environment\nwhere people feel comfortable getting help. \n\nThe core team is always available on [Slack](https://www.bitovi.com/community/slack) ([#donejs channel](https://bitovi-community.slack.com/messages/CFC80DU5B))\nand provides [weekly training](https://www.bitovi.com/blog/free-weekly-online-javascript-training). Signup for a [meetup](./community.html) and we will come to your\ncity and teach you DoneJS!\n\n\n#### Exploring\n\nDoneJS has benefited greatly from other projects ideas and technology. It should continue to enhance other communities. \n\nYou can already use many of DoneJS parts with other projects:\n\n - StealJS works great with ReactJS.\n - CanJS works with RequireJS or Browserify.\n - can-connect works on its own.\n\nWe should always seek to cooperate with others.\n\n#### Attract\n\nIf you have the next great JS idea, we want to encourage and help you to build it as part of the DoneJS family. You'll find DoneJS a supportive environment to nurture your ideas. You can even pair with the full-time developers to build out your idea. Reach out to us on\n[Slack](https://www.bitovi.com/community/slack) ([#donejs channel](https://bitovi-community.slack.com/messages/CFC80DU5B))\nor create an issue.\n\n\n## History\n\nDoneJS’s history goes back for almost a decade! Learn why JavaScriptMVC was started and how it evolved into DoneJS.\n\n### Beginning Steps\n\nWe begin [our story](https://forum.javascriptmvc.com/topic/a-brief-history-of-javascriptmvc) in 2007 when Justin Meyer, the CEO of Bitovi, was working for Accenture. He had an idea to build something like [ZoHo Creator](https://creator.zoho.com/home), so you could set up REST services and use an online IDE to write JavaScript apps from those services — you could sell your apps and everything. He called it Scaffold.\n\nHe worked with Brian, a friend from college (who’s now the CTO of Bitovi). Brian quit graduate school so they could start working on it together. They worked on it for about a year and managed to sell it to a few places, but it never really took off. They then started building JavaScript tools for Scaffold to help people write their apps.\n\nTheir initial work was based off a library called [TrimPath](https://code.google.com/archive/p/trimpath/). It had templates, an MVC pattern, etc. They worked with Steve Yen for a little bit, but their client-only focus left them to split of trimpath/trimjunction into what they called JSJunction. Eventually, they didn’t like the name JSJunction and changed it to JavaScriptMVC.\n\nIn JavaScriptMVC’s first release, it had support for things such as:\n\n- Model - View - Controller design pattern\n- History & routing\n- Templates\n- Plugins for filtering, paginating, sorting, etc.\n\nEven in JavaScriptMVC’s early days, Justin knew that [“developers need a repeatable way of building their applications and separating concerns.”](https://groups.google.com/forum/#!searchin/jquery-dev/jQuery$20enterprise/jquery-dev/HsTcpuAmFtY/mN4qFyHw54oJ) When a dev team can work with a standard set of tools and processes, their productivity can greatly increase.\n\nFuncUnit and StealJS both started in 2010, and in 2012 we started splitting JavaScriptMVC into smaller, focused projects, including CanJS, jQuery++, DocumentJS, and DocumentCSS. Then, in 2015, we rebranded JavaScriptMVC to DoneJS and released it to the public.\n\n### Tomorrow's Roadmap\n\nThe following are our highest priority, non-bug-fix features:\n\n- [can-set support sort](https://github.com/canjs/can-set/pull/10)\n- [documentjs configured in package.json](https://github.com/bitovi/documentjs/issues/202)\n- [StealJS dependency injection](https://github.com/stealjs/steal/issues/509)\n- [can-connect supporting other frameworks](https://github.com/canjs/can-connect/issues/42)\n- [Animation utilities](https://github.com/canjs/can-animate)\n- [O(log n) derived list modification](https://github.com/canjs/can-derive)\n- [CanJS Roadmap Discussion](https://forums.bitovi.com/t/canjs-roadmap-discussion/75)\n\n## Team\n\nThe DoneJS family of technologies is built by hundreds of contributors just like you! Our [contributing contribution guide] includes information about reporting bugs, finding ways to contribute, submitting new code, and more!\n\nIf you’d like to take your commitment to DoneJS or its sub-projects to the next level, you can join our core team. To become a part of the core team, you simply have to:\n\n- [Email](mailto:contact@bitovi.com) the core team expressing your interest.\n- Attend the weekly _DoneJS Contributors_ meeting twice a month. [DoneJS Calendar](https://www.google.com/calendar/embed?src=jupiterjs.com_g27vck36nifbnqrgkctkoanqb4%40group.calendar.google.com&ctz=America/Chicago)\n- Make one small contribution, even a spelling correction, each month.\n\n### Core team\n\nThe core team is made up of both part-time and full-time contributors.\n\n<div class=\"core-team-member\">\n <img class=\"member-avatar\" src=\"https://avatars2.githubusercontent.com/u/2445805?v=3&s=400\" alt=\"Kevin Dillon profile picture\" />\n <h4>Kevin Dillon</h4>\n <p>\n Kevin is a senior infrastructure engineer at The MathWorks in the Web and Mobile Tools team.\n He focuses on the development of FuncUnit and Syn.\n </p>\n <a href=\"https://github.com/kdillon\" target=\"_blank\">GitHub</a>\n</div>\n\n<div class=\"core-team-member\">\n <img class=\"member-avatar\" src=\"https://avatars2.githubusercontent.com/u/10070176?v=3&s=400\" alt=\"Chasen Le Hara profile picture\" />\n <h4>Chasen Le Hara</h4>\n <p>\n Chasen is a 🍺 🏃 with a passion for building great web apps.\n He supports the DoneJS community by leading developer advocacy for DoneJS.\n </p>\n <a href=\"https://twitter.com/chasenlehara\" target=\"_blank\">@chasenlehara</a>\n <a href=\"https://github.com/chasenlehara\" target=\"_blank\">GitHub</a>\n</div>\n\n<div class=\"core-team-member\">\n<img class=\"member-avatar\" src=\"https://avatars3.githubusercontent.com/u/4830283?v=3&s=300\"/>\n<h4>Prashant Sharma</h4>\n<p>\nPrashant is based in Bangalore, India. He likes the understated elegance of CanJS. He also believes DoneJS is a great framework in the making, since it makes technology selection a no-brainer by uniquely offering developers an all-in-one technology stack.\n</p>\n<a href=\"https://github.com/prashantsharmain\" target=\"_blank\">GitHub</a>\n</div>\n\n<div class=\"core-team-member\">\n<img class=\"member-avatar\" src=\"https://lh3.googleusercontent.com/-UOTrK62q0fM/AAAAAAAAAAI/AAAAAAAAADc/1_BqFteAC4Y/s300-p-rw-no/photo.jpg\"/>\n<h4>Julian Kern</h4>\n<p>\nA 29 old guy from Germany, Julian started coding at the age of 16. Now he freelances with CanJS. He likes the clean structure of Model, Views, and ViewModels.\n</p>\n<a href=\"https://twitter.com/22_Solutions\" target=\"_blank\">@22_Solutions</a>\n</div>\n\n<div class=\"core-team-member\">\n<img class=\"member-avatar\" src=\"https://avatars1.githubusercontent.com/u/109013?v=3&s=300\"/>\n<h4>Mohamed Cherif Bouchelaghem</h4>\n<p>\nMohamed Cherif BOUCHELAGHEM from Algiers, Algeria, almost a server side developer in day work, JavaScript developer after work hours especially using DoneJS/CanJS. He likes to help people to learn and find solutions to issues with DoneJS framework and build applications and code samples that help to show the best from DoneJS/Canjs and learn it faster.\n</p>\n<a href=\"https://twitter.com/Cherif_b\" target=\"_blank\">@Cherif_b</a>\n<a href=\"https://github.com/cherifGsoul\" target=\"_blank\">GitHub</a>\n\n</div>\n\n\n<div class=\"core-team-member\">\n<img class=\"member-avatar\" src=\"https://avatars1.githubusercontent.com/u/5851984?v=3&s=300\"/>\n<h4>Kevin Phillips</h4>\n<p>\nKevin is based in Chicago (well, close enough). He wants to make it easy for anyone to get started with DoneJS and will work on features that help solve complex problems.\n</p>\n<a href=\"https://twitter.com/kdotphil\" target=\"_blank\">@kdotphil</a>\n<a href=\"https://github.com/phillipskevin\" target=\"_blank\">GitHub</a>\n\n</div>\n\n<div class=\"core-team-member\">\n<img class=\"member-avatar\" src=\"https://avatars3.githubusercontent.com/u/78602?v=3&s=300\"/>\n<h4>Justin Meyer</h4>\n<p>\nJustin dances and plays basketball in Chicago. He created JavaScriptMVC and manages the\nDoneJS project, and shouldn't code on it as much as he does.\n</p>\n<a href=\"https://twitter.com/justinbmeyer\" target=\"_blank\">@justinbmeyer</a>\n<a href=\"https://github.com/justinbmeyer\" target=\"_blank\">GitHub</a>\n</div>\n\n<div class=\"core-team-member\">\n<img class=\"member-avatar\" src=\"https://avatars3.githubusercontent.com/u/338316?v=3&s=300\"/>\n<h4>David Luecke</h4>\n<p>\nDavid is a Canadian by way of Germany. His focus is on CanJS and\nDoneJS's testing stack.\n</p>\n<a href=\"https://twitter.com/daffl\" target=\"_blank\">@daffl</a>\n<a href=\"https://github.com/daffl\" target=\"_blank\">GitHub</a>\n</div>\n\n<div class=\"core-team-member\">\n<img class=\"member-avatar\" src=\"https://avatars2.githubusercontent.com/u/361671?v=3&s=300\"/>\n<h4>Matthew Phillips</h4>\n<p>\nMatthew, keeper of beards, is the lead maintainer of StealJS and its related tools.\n</p>\n<a href=\"https://twitter.com/matthewcp\" target=\"_blank\">@matthewcp</a>\n<a href=\"https://github.com/matthewp\" target=\"_blank\">GitHub</a>\n</div>\n\n\n### Sponsors\n\nIf you'd like to support the development of DoneJS, please find available options on our [Patreon page](https://www.patreon.com/donejs). If you have other ideas, or would like to customize your support,\nplease [email us](mailto:contact@bitovi.com).\n\n\n[Bitovi](https://www.bitovi.com/), a JavaScript consulting company, is the primary sponsor of DoneJS.\n\n",
"description": " \n<img src=\"https://www.bitovi.com/hubfs/Imported_Blog_Media/donejs-logo-ie.png\"/>\n\nDoneJS' goal is to help the JavaScript community get amazing applications done fast.\nAmazing applications are fast, sublimely usable, and maintainable.\n\nBut times change and new techniques emerge. We strive to adopt these\ntechniques, improve the stack, and provide a simple upgrade path along the way.\n\nWe are part of a community that helps developers of all skill levels and\nbackgrounds learn the technology, excel at it, and accomplish their\ngoals.\n\nLearn about the goals, history, roadmap, and team behind DoneJS.\n\n",
"name": "About",
"type": "page",
"parent": "DoneJS",
"hideSidebar": true,
"outline": {
"depth": 2,
"tag": "ol"
},
"comment": " "
},
"survey": {
"src": {
"path": "docs/survey.md"
},
"body": "\n__We want to hear from you.__ What do you love and hate about CanJS, DoneJS, and\nStealJS? What can the core team work on to make you grow fonder of these\nprojects?\n\n<div class=\"cta\">\n <a href=\"https://www.surveymonkey.com/r/bitovi-may-2019\" target=\"_blank\">\n Take the community survey\n </a>\n</div>\n<script charset=\"utf-8\" type=\"text/javascript\" src=\"//js.hsforms.net/forms/v2.js\"></script>\n<script>\nvar endTime = new Date('May 8 2019 14:00:00 UTC');// 7 a.m. Pacific\nif (new Date() < endTime) {// Survey has not yet ended\n var elements = document.getElementsByClassName('comment');\n var container = elements[0];\n if (container) {\n container.className = container.className + ' survey-is-active';\n }\n} else {// Survey has ended\n hbspt.forms.create({\n css: '',\n portalId: '2171535',\n formId: '45da8caa-c096-4099-a444-450f5c303ba0'\n });\n}\n</script>\n\n<div class=\"form-explanation\">\n\nProvide your email address (and optionally your GitHub username) above and\nyou’ll be signed up for our survey:\n\n- You’ll receive an email about\n[every six weeks](https://calendar.google.com/calendar/embed?src=jupiterjs.com_g27vck36nifbnqrgkctkoanqb4%40group.calendar.google.com)\nwith a link to the survey.\n- Each survey will be about five questions and take just a few minutes to complete.\n- An opt-out/unsubscribe link will be included in each email.\n\n</div>\n\nWe will look at every single response and use it to prioritize what the team\nworks on in the coming months. Short of [hiring us](https://www.bitovi.com/contact)\nto work on something in particular, __this is the best way to have a direct impact\non our priorities.__\n\n<div class=\"youtube-embed\" style=\"display: none\">\n <p>Watch the discussion below to learn more about each item on the survey:</p>\n <iframe width=\"560\" height=\"315\" src=\"https://www.youtube-nocookie.com/embed/UxBJtHm4Km0?start=55\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe>\n</div>\n\n[Read more about the survey in our announcement blog post.](https://www.bitovi.com/blog/help-us-improve-canjs-stealjs-and-the-rest-of-the-donejs-family)\nIf you have any questions, please don’t hesitate to ask on\n[our forums](https://forums.bitovi.com/),\n[Slack](https://www.bitovi.com/community/slack) ([#donejs channel](https://bitovi-community.slack.com/messages/CFC80DU5B)), or\n[Twitter](https://twitter.com/donejs)\n\n<figure>\n <img alt=\"Photo of the DoneJS core team\" src=\"https://www.bitovi.com/hs-fs/hubfs/DoneJS%20core%20team%20photo%20(small).jpg?t=1505933448740&cos_cdn=1&width=2160&cos_cdn=1&name=DoneJS%20core%20team%20photo%20(small).jpg\" />\n <figcaption>The core team thanks you for participating in our survey!</figcaption>\n</figure>\n\n",
"description": "Help us improve CanJS, StealJS, and the rest of the DoneJS family by taking a short email survey every six weeks.\n\n",
"name": "survey",
"title": "Community Survey",
"type": "page",
"parent": "DoneJS",
"hideSidebar": true,
"comment": " "
},
"Apis": {
"src": {
"path": "docs/apis.md"
},
"body": "\n## Application flow overview\n\nLets talk about how the typical behavior of a DoneJS application works. We'll use\nthe chat application as an example in development. We'll cover what happens when:\n\n - A user navigates their browser from a different domain to `https://chat.donejs.com/`\n - A user navigates from `https://chat.donejs.com/` to another `https://chat.donejs.com/chat`.\n\n\n### First page load\n\n1. An http request for `https://chat.donejs.com/` is sent to a node server. The node server is configured,\n in this case with express, to use [done-ssr-middleware](#done-ssr) to render a DoneJS application:\n\n ```js\n var ssr = require('done-ssr-middleware');\n\n app.use('/', ssr());\n ```\n\n2. [done-ssr](#done-ssr) uses [steal](#stealjs) to load the application's main module which results in loading the\n entire application. Loading the application only happens once for all page requests.\n\n A DoneJS's main module is specified where all configuration of a DoneJS application happens, its `package.json`.\n The main module is usually a [can-stache](#canstache) template processed with the [done-autorender](#done-autorender)\n plugin. The module name is specified like: `index.stache!done-autorender`. `index.stache` might look like:\n\n ```html\n <html>\n <head>\n <title>My Site</title>\n </head>\n <body>\n <can-import from=\"styles.less\"/>\n <can-import from=\"donejs-chat/app\" export-as=\"viewModel\" />\n\n {{pageComponent}}\n\n <script src=\"node_modules/steal/steal.js\" main=\"index.stache!done-autorender\"></script>\n </body>\n </html>\n ```\n\n The [done-autorender](#done-autorender) plugin, in NodeJS, exports this template so it can be rendered.\n\n3. Once [done-ssr](#done-ssr) has the [done-autorender](#done-autorender)'s `template` and `viewModel` export it:\n\n 1. Creates a new instance of the viewModel, setting properties on it\n using [can-route](#canroute)'s routing rules. \n 2. Creates a new [virtual DOM](#can-simple-dom) instance.\n 3. Renders the [template](#canstache) with the `viewModel` into the `virtual DOM` instance.\n 4. [done-autorender](#done-autorender) templates waits for all promises to complete\n before providing a final result. Once the template is finished rendering, [done-ssr](#done-ssr) converts it to a\n string and sends it back to the browser.\n 5. The browser downloads the page's HTML, which includes a `<script>` tag that points to [steal](#stealjs). \n\n ```html\n <script src=\"node_modules/steal/steal.js\" main></script>\n ```\n\n In development, this loads `steal.js` which then loads `index.stache` and processes it with\n the `done-autorender`. \n\n6. In the browser, `done-autorender`:\n\n 1. Creates a new instance of the [viewModel](#canmap), setting properties on it\n using [can-route](#canroute)'s routing rules. \n 2. Renders the [template](#canstache) with the `viewModel` into a document fragment.\n 3. Once all asynchronous activity has completed, it replaces the document with the rendered result.\n\n### Pushstate change\n\n1. A pushstate is triggered by user action, usually by clicking a link. [can-route](#canroute)'s routing rules determines the properties set on the application [viewModel](#canmap).\n\n ```js\n route.register('{page}', { page: 'home' });\n ```\n\n2. [done-autorender](#done-autorender) previously bound the AppViewModel to [can-route](#canroute) which causes any change in the route to be reflected in the ViewModel instance.\n\n3. Live binding causes the initial template to reflect in the change in route. If the new route is `/chat` it will cause the `page` to be **chat**:\n\n ```html\n <html>\n <head>\n <title>My Site</title>\n </head>\n <body>\n <can-import from=\"styles.less\"/>\n <can-import from=\"donejs-chat/app\" export-as=\"viewModel\" />\n\n {{pageComponent}}\n\n <script src=\"node_modules/steal/steal.js\" main></script>\n </body>\n </html>\n ```\n\n## CLI and Generators\n\nAfter installing DoneJS globally with `npm install donejs -g` you will have the `donejs` command available on the command line. It lets you initialize a new application and - when navigating within a DoneJS project - run scripts provided locally by your application. Within your application folder the `donejs` command is a convenience wrapper for the functionality described below and you can also get a list of all commands by running\n\n```\ndonejs help\n```\n\n### npm scripts\n\n[npm scripts](https://docs.npmjs.com/misc/scripts) are defined in the `scripts` section of your applications `package.json`. There are some standard scripts that every Node application uses (like `npm start` or `npm test` - both of which are already set up for you) and you can add your own which is what DoneJS does with commands like `npm run develop` or `npm run build`.\nThe `donejs` command makes running those commands easier by allowing you to run them like `donejs start`, `donejs develop` or `donejs build`\n\n### Generators\n\n`donejs add` lets you run the [Yeoman](http://yeoman.io/) generators provided by [generator-donejs](https://github.com/donejs/generator-donejs/). Currently the following generators are available:\n\n- `donejs add app [folder]` which will initialize a new application (optionally within the given folder)\n- `donejs add component <modulename> <tagname>` to create a new can-component\n- `donejs add supermodel <modulename>` to generate a new model\n- `donejs add plugin [folder]` which will initialize a new plugin project\n- `donejs add generator [folder]` which will initialize a new generator project\n\n### Third-party generators\n\nIf `donejs add` can’t find a built-in generator, e.g. when running `donejs add mygenerator`, DoneJS will try to install the `donejs-mygenerator` package from npm and run the Yeoman generators it provides. This is how we can enable a desktop application build of the application by simply running:\n\n```\ndonejs add electron\n```\n\nWhich will install the [donejs-electron](https://github.com/donejs/donejs-electron) package and then run its generator, which initializes everything you need. This also works for adding a mobile application build using [donejs-cordova](https://github.com/donejs/donejs-cordova) like this:\n\n```\ndonejs add cordova\n```\n\nThis way you can use DoneJS’s growing list of plugins and generators without having to add anything to your application that you don't use.\n\n## StealJS\n\nThe base of any good JavaScript application is its dependency management system. \nDoneJS uses [StealJS](https://stealjs.com/) which\nitself is split into two sub-projects:\n\n- `steal` - loads CommonJS, ES6, and AMD modules. It can also load styles, templates and more.\n- `steal-tools` - builds your application's modules for production and also provides hot-module-swapping.\n\n### steal\n\nTo use [steal](https://stealjs.com/docs/steal.html), simply add a script tag to `steal.js`\nin an HTML page or in a [done-autorender](#done-autorender) `template` and\npoint the `main` attribute to a module to load like:\n\n```html\n<script src=\"../../node_modules/steal/steal.js\" main=\"my-app/my-module\"></script>\n```\n\nUsing the default DoneJS [system.directories.lib](https://stealjs.com/docs/npm.html#configuration) configuration, this will load\n`my-app/src/my-module.js`. From there, use CommonJS, ES6, or AMD to load your modules:\n\n```js\n// my-app/src/my-module.js\nimport $ from \"jquery\";\nimport \"./styles.css\";\n\n$('body')\n```\n\nIf an `import`, `require` or `define` module reference ends with `\"/\"`, is a shorthand\nfor importing a module in the modlet format. The moduleName imported is the same\nas the module reference, but with the last folder name added again.\n\nSome examples:\n\n```js\n// in components/person module.\nimport \"can-component\"; //imports \"can-component\";\nimport \"./edit/\"; // imports \"components/person/edit/edit\";\n```\n\nConfigure [steal](https://stealjs.com/docs/steal.html)'s behavior in your `package.json` in the `steal` object like:\n\n```js\n// package.json\n{\n \"main\": \"index.stache!done-autorender\",\n ...\n \"steal\": {\n \"meta\": {\n \"ui/core\": {\n \"deps\": [\n \"jquery\",\n \"theme/core.css\",\n \"theme/theme.css\"\n ]\n }\n }\n }\n}\n```\n\n### steal-tools\n\nIn DoneJS applications, [steal-tools](https://stealjs.com/docs/steal-tools.html) is primarily used to:\n\n - [build](https://stealjs.com/docs/steal-tools.build.html) and minify your application to production-ready bundles.\n - add [hot module swapping](https://stealjs.com/docs/steal-tools.cmd.live-reload.html)\n\nIt can also be used to [export](https://stealjs.com/docs/steal-tools.export.html) your\nmodules to different formats.\n\nDoneJS comes with a `build.js` script that call's steal-tools' [build](https://stealjs.com/docs/steal-tools.build.html):\n\n```js\n//build.js\nvar stealTools = require(\"steal-tools\");\n\nvar buildPromise = stealTools.build({\n config: __dirname + \"/package.json!npm\"\n}, {\n bundleAssets: true\n});\n```\n\nThis is already configured to run with:\n\n```\n> donejs build\n```\n\nBut you could also run it with:\n\n```\n> node build.js\n```\n\nHot module swapping is done with [live-reload](https://stealjs.com/docs/steal-tools.cmd.live-reload.html) which\nis bundled within steal-tools. \n\nBy default `donejs develop` starts the live-reload server. However, you could start one\nyourself with:\n\n```\n> steal-tools live-reload\n```\n\n## CanJS\n\nCanJS provides:\n\n- __observables__ with [can-map](#canmap), [can-list](#canlist), and [can-compute](#cancompute).\n- __one-way and two-way binding templates__ with [can-stache](#canstache) and [can-stache-bindings](#canviewbindings).\n- __custom elements__ with [can-component](#cancomponent).\n- __routing__ with [can-route](#canroute).\n\nObservables act as the `ViewModel` and part of the `Model`.\n\nOne-way and two-way binding templates act as the `View`.\n\n[can-component](#cancomponent) is used to combine `View` and `ViewModel` into\neasy to instantiate and assemble custom elements.\n\nCheckout the following quick examples of their use:\n\n__observables__:\n\n```js\n// Observable objects:\nvar person = new DefineMap({first: \"Justin\", last: \"Meyer\"});\n\n// Observable arrays:\nvar hobbies = new DefineList([\"basketball\", \"hip-hop dancing\"]);\n\n// Observable single values:\nvar age = compute(33);\n\n// Observable computed values:\nvar info = compute(function(){\n return person.first + \" \" + person.last + \" is \" +\n \tage() + \" and likes \" + hobbies.join(\",\") + \".\";\n});\n\n// Get the compute's value\ninfo() //-> Justin Meyer is 33 and likes\\\n // basketball, hip-hop dancing.\n\n// Listen to changes in the compute\ninfo.bind(\"change\", function(ev, newValue){\n newValue //-> Justin Meyer is 33 and likes\\\n // basketball, hip-hop dancing.\n});\n\nhobbies.pop(); // causes `change` event above\n```\n\n__one and two-way binding templates__:\n\n```js\n// Programmatically create a template\n// `value:bind` cross binds the input's value\n// to `first` in the scope.\nvar template = stache(\"<h1>{{first}}</h1>\"+\n\t\"<input value:bind='first'/>\");\n\n// Create observable data for the template\nvar person = new DefineMap({first: \"Payal\"});\n\n// Render the template with data\nvar frag = template(person);\n\n// Add the result to the document\ndocument.body.appendChild(frag);\n\n// Document shows rendered result\ndocument.body //-> <h1>Payal</h1><input value='Payal'/>\n\n// ... User changes the input's value to \"Ramiya\" ...\n\n// Document is updated with changes\ndocument.body //-> <h1>Ramiya</h1><input value='Ramiya'/>\n```\n\n__custom elements__:\n\n```js\n// Create a custom `can-define/map/map` constructor function\n// with a helper function.\nvar PersonEditViewModel = DefineMap.extend({\n first: \"string\",\n last: \"string\",\n fullName: function(){\n return this.first + \" \" + this.last;\n }\n});\n\n// Create a template that will be rendered within\n// `<person-edit>` elements.\nvar template = stache(`\n Update {{fullName}}:\n\t<input value:bind='first'>\n\t<input value:bind='last'>\n`);\n\n// Create the `<person-edit>` element with the specified\n// viewModel and template (view).\nComponent.extend({\n tag: \"person-edit\",\n ViewModel: PersonEditViewModel,\n view: view\n});\n\n// Use that custom element within another template.\n// `first.bind` cross binds `<person-edit>`'s\n// `first` property to `firstName` in the scope.\nvar parentTemplate = stache(`\n <h1>{{firstName}} {{lastName}}</h1>\n <person-edit first:bind='firstName' last:bind='lastName'>\n`);\n\n// Render the parent template with some data:\nvar frag = parentTemplate(new DefineMap({\n firstName: \"Brian\",\n lastName: \"Moschel\"\n}));\n\ndocument.body.appendChild(frag);\n```\n\n### can-define/map/map\n\n[can-define](https://canjs.com/doc/can-define.html) is used to create observable\nJavaScript Object-like objects. Create an instance of the\nbase can-define/map/map like:\n\n```js\nvar person = new DefineMap({first: \"Justin\", last: \"Meyer\"});\n```\n\nRead or write a `map`'s properties:\n\n```js\nperson.first //-> Justin\n\nperson.first = \"Ramiya\";\nperson.get() //-> {first: \"Ramiya\", last: \"Meyer\"}\n\nperson.first = \"Brian\";\nperson.last = \"Moschel\";\nperson.get() //-> {first: \"Brian\", last: \"Moschel\"}\n```\n\nBind to changes in a person's properties with [.on](https://canjs.com/doc/can-define/map/map.prototype.on.html):\n\n```js\nperson.on(\"first\", function(ev, newValue, oldValue){\n newValue //-> \"Laura\"\n oldvalue //-> \"Brian\"\n});\n\n// changing `first` causes the function\n// call above.\nperson.first = \"Laura\";\n```\n\nExtend a `DefineMap` to create a new constructor function. This is\nvery useful for creating Models and View Models:\n\n```js\n// pass extend an object of prototype values\nvar Person = DefineMap.extend({\n first: \"string\",\n last: \"string\",\n fullName: function(){\n person.first + \" \" + person.last;\n }\n})\n\nvar me = new Person({first: \"Kathrine\", last: \"Iannuzzi\"});\nme.fullName() //-> \"Kathrine Iannuzzi\"\n```\n\nThe [can-define](https://canjs.com/doc/can-define.html) allows\nyou to control the behavior of attributes. You can define\n[default values](https://canjs.com/doc/can-define.types.value.html),\n[getters](https://canjs.com/doc/can-define.types.get.html),\n[setters](https://canjs.com/doc/can-define.types.set.html), and\n[type](https://canjs.com/doc/can-define.types.type.html) converters.\n\n```js\nvar Todo = DefineMap.extend({\n percentComplete: {\n default: 0.1,\n type: \"number\",\n get: function(value){\n return \"\"+value+\"%\"\n },\n set: function(newValue){\n return newValue*100;\n }\n }\n});\n\nvar todo = new Todo();\ntodo.percentComplete //-> 10%\n```\n\nYou can even describe asynchronous behavior which is critical for working\nwith service data:\n\n```js\nvar Todo = DefineMap.extend({\n ownerId: \"number\",\n owner: {\n get: function(lastSetValue, resolve){\n User.get({id: this.ownerId}).then(resolve);\n }\n }\n});\n\ntodo = new Todo({ownerId: 5});\n\n// async values only become valid when bound\n// this isn't a problem because templates usually bind for you\ntodo.on(\"owner\", function(ev, owner){\n owner //-> a User instance\n});\n```\n\n\n### can-define/list/list\n\n[can-define/list/list](https://canjs.com/doc/can-define/list/list.html) is used to create observable\nJavaScript Array-like objects. Create an instance of the\nbase `DefineList` like:\n\n```js\nvar hobbies = new DefineList([\"basketball\",\"dancing\"]);\n```\n\nRead and write items from the list or to read the length:\n\n```js\nfor(var i = 0, len = hobbies.length; i < len; i++){\n var hobby = hobbies.get(i);\n}\nhobbies.set(1, \"hip hop dancing\");\nhobbies.get() //-> [\"basketball\", \"dancing\"]\n```\n\nUse array methods like [.push](https://canjs.com/doc/can-define/list/list.prototype.push.html), [.pop](https://canjs.com/doc/can-define/list/list.prototype.pop.html), and [.splice](https://canjs.com/doc/can-define/list/list.prototype.splice.html) to modify the array:\n\n```js\nhobbies.pop();\n\nhobbies.generated() //-> [\"basketball\"];\n\nhobbies.push(\"football\");\n\nhobbies //-> DefineList[\"basketball\",\"football\"]\n```\n\nUse [.forEach](https://canjs.com/doc/can-define/list/list.prototype.forEach.html), [.map](https://canjs.com/doc/can-define/list/list.prototype.map.html), or [.filter](https://canjs.com/doc/can-define/list/list.prototype.filter.html) to loop through the array. All\nthese methods return a `DefineList`\n\n```js\nvar intramurals = hobbies.map(function(hobby){\n return \"intramural \"+hobby;\n})\nintramurals //-> DefineList[\"intramural basketball\",\n \"intramural football\"]\n```\n\nListen to when a list changes by binding on `add` or `remove` or `length`\nevents.\n\n```js\nhobbies.on(\"add\", function(ev, newHobbies, index){\n console.log(\"added\", newHobbies,\"at\", index);\n })\n .on(\"remove\", function(ev, removedHobbies, index){\n console.log(\"removed\", newHobbies,\"at\", index);\n })\n .on(\"length\", function(ev, newVal, oldVal){\n console.log(\"length is\", newVal);\n });\n\nhobbies.splice(1,1,\"pumpkin carving\",\"gardening\");\n // console.logs:\n // removed [football] 1\n // added [\"pumpkin carving\",\"gardening\"] 1\n // length is 3\n```\n\n\nBy default, if you initialize a list with plain JavaScript objects,\nthose objects are converted to a `DefineMap`:\n\n```js\nvar people = new DefineList([\n {first: \"Justin\", last: \"Meyer\", age: 72},\n {first: \"David\", last: \"Luecke\", age: 20},\n {first: \"Matthew\", last: \"Phillips\", age: 30}\n]);\n\npeople.get(0).first //-> Justin\n```\n\nYou can create your own custom `DefineList` constructor functions\nby extending `DefineList`:\n\n```js\nvar People = DefineList.extend({\n seniors: function(){\n return this.filter(function(person){\n return person.age >= 65\n });\n }\n});\n\nvar people = new People([\n {first: \"Justin\", last: \"Meyer\", age: 72},\n {first: \"David\", last: \"Luecke\", age: 20},\n {first: \"Matthew\", last: \"Phillips\", age: 30}\n]);\n\npeople.seniors() //-> People[{Justin}]\n```\n\nWhen extending `DefineList` you can specify the default `Map` type\nthat's created when plain JS objects are added to the list:\n\n```js\nvar Person = can.Map.extend({\n fullName: function(){\n person.first + \" \" + person.last;\n }\n});\n\nvar People = DefineList.extend({\n \"#\": Person\n},{\n seniors: function(){\n return this.filter(function(person){\n return person.age >= 65\n });\n }\n});\n\nvar people = new People([\n {first: \"Justin\", last: \"Meyer\", age: 72},\n {first: \"David\", last: \"Luecke\", age: 20},\n {first: \"Matthew\", last: \"Phillips\", age: 30}\n]);\n\npeople.get(0).fullName() //-> \"Justin Meyer\"\n```\n\n### can-compute\n\n[can-compute](https://canjs.com/doc/can-compute.html) isn't used\ndirectly much anymore. However, it's used heavily in [can-define](#candefine)\n[getters](https://canjs.com/doc/can-define.types.get.html) and live binding\nso it's worth understanding the basics.\n\n`can-compute` allows you to define single observable values like:\n\n```js\nvar age = compute(33);\n```\n\nor derived values like:\n\n```js\nvar person = new DefineMap({first: \"Justin\", last: \"Meyer\"}),\n hobbies = new DefineList([\"basketball\", \"hip-hop dancing\"]);\n\nvar info = compute(function(){\n return person.first + \" \" + person.last + \" is \" +\n \tage() + \" and likes \" + hobbies.join(\",\") + \".\";\n});\n```\n\nRead a compute by calling it like a function:\n\n```js\ninfo() //-> \"Justin Meyer is 33 and likes\\\n // basketball, hip-hop dancing.\"\n```\n\nListen to a compute by binding on its `change` event:\n\n```js\ninfo.on(\"change\", function(ev, newVal, oldVal){\n console.log(\"IS:\\n\",newVal,\"\\nWAS:\\n\", oldVal);\n})\n```\n\nInternally, `on` runs the compute function, identifying what observable\nvalues it reads, and listening to them. It caches the return result so that\nreading the compute again like `info()` just returns the cached result.\n\nWhen any of the read observables change, it updates the cached value,\nand calls back any event handlers:\n\n```js\nperson.first = \"Brian\";\nperson.last = \"Moschel\";\n\n// console.logs:\n// IS:\n// Brian Moschel is 33 and likes basketball, hip-hop dancing.\n// WAS:\n// Justin Meyer is 33 and likes basketball, hip-hop dancing.\n```\n\n### can-stache\n\n[can-stache](https://canjs.com/doc/can-stache.html) is a Handlebars and\nMustache compliant live-binding templating language.\n\nCreate a template programmatically with `can-stache` like:\n\n```js\nvar template = stache(\"<h1>{{first}} {{last}}</h1>\");\n```\n\n`template` is a __renderer__ function that, when called with observable data,\nreturns a [DocumentFragment](https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment) that is updated when the observable data changes.\n\nAdd those fragments to the page to see the result:\n\n```js\nvar person = new DefineMap({first: \"Brian\", last: \"Moschel\"})\n\nvar frag = template(person);\n\ndocument.body.appendChild(frag);\n\ndocument.body //-> <h1>Brian Moschel</h1>\n\nperson.first = \"Ramiya\";\nperson.last = \"Meyer\";\n\ndocument.body //-> <h1>Ramiya Meyer</h1>\n```\n\nIn a DoneJS application, templates are used primarily as part of\na [can-component](#cancomponent) or as the [done-autorender](#done-autorender)ed main template.\n\nWhen used in a [can-component](#cancomponent), the templates are often put in their own file. For\nexample, a `person_edit.js` component file might have a `person_edit.stache` file like:\n\n```js\n// person_edit.stache\nUpdate {{fullName}}:\n<input value:bind='first'/>\n<input value:bind='last'/>\n```\n\nThis template's __renderer__ function is imported in `person_edit.js` like:\n\n```js\n// person_edit.js\nimport template from \"./person_edit.stache\";\nimport Component from \"can-component\";\n\nComponent.extend({\n tag: \"person-edit\",\n template: template\n});\n```\n\n`can-stache` template behavior is controlled by what's\nwithin magic tags like `{{ }}`. There are different tag types, lots of\nhelper functions, and different ways to call methods and functions.\n\nThere's too much to cover so we will highlight the important APIs.\n\nThe different tag types:\n\n - [{{key}}](https://canjs.com/doc/can-stache.tags.escaped.html) -\n inserts an escaped value.\n\n ```js\n stache(\"{{key}}\")({key: \"<b>Foo</b>\"}) //-> `<b>Foo</b>`\n ```\n\n - [{{{key}}}](https://canjs.com/doc/can-stache.tags.unescaped.html) -\n inserts an unescaped value.\n\n ```js\n stache(\"{{key}}\")({key: \"<b>Foo</b>\"}) //-> `<b>Foo</b>`\n ```\n\n- [{{#key}} ... {{/key}}](https://canjs.com/doc/can-stache.tags.section.html) -\n renders a subsection depending on the value of the key.\n\n ```js\n // boolean values render the subsection or its inverse\n stache(\"{{#key}}A{{/key}}\")({key: true}) //-> `A`\n stache(\"{{#key}}A{{/key}}\")({key: false}) //-> ``\n stache(\"{{#key}}A{{else}}B{{/key}}\")({key: false}) //-> `B`\n\n // iterative values render the subsection for each value\n stache(\"{{#key}}A{{/key}}\")({key: [null,0]}) //-> `AA`\n stache(\"{{#key}}A{{/key}}\")({key: []}) //-> ``\n\n ```\n\n The subsection is rendered with the `key` value as the top of the [scope](https://canjs.com/doc/can-view-scope.html):\n\n ```js\n stache(\"{{#key}}{{child}}{{/key}}\")({key: {child:\"C\"}}) //->`C`\n ```\n\n- [{{^key}} ... {{/key}}](https://canjs.com/doc/can-stache.tags.inverse.html) -\n opposite of `{{#key}}`.\n\n ```js\n stache(\"{{^key}}A{{/key}}\")({key: true}) //-> ``\n stache(\"{{^key}}A{{/key}}\")({key: false}) //-> `A`\n stache(\"{{^key}}A{{/key}}\")({key: [null,0]}) //-> ``\n\n stache(\"{{^key}}A{{else}}B{{/key}}\")({key: false}) //-> `B`\n ```\n\nThe following are stache's most commonly used helpers:\n\n - [{{#if expr}} .. {{/if}}](https://canjs.com/doc/can-stache.helpers.if.html) - renders the subsection if the expr is truthy.\n\n ```js\n stache(\"{{#if key}}A{{/if}}\")({key: true}) //-> `A`\n stache(\"{{#if key}}A{{/if}}\")({key: false}) //-> ``\n\n stache(\"{{#if key}}A{{else}}B{{/if}}\")({key: false}) //-> `B`\n ```\n\n - [{{#is expr1 expr2}} ... {{/is}}](https://canjs.com/doc/can-stache.helpers.is.html) - compares two expressions and renders a subsection depending on the result.\n\n ```js\n stache(\"{{#is page 'A'}}A{{/is}}\")({page: 'A'}) //-> `A`\n stache(\"{{#is page 'A'}}A{{/is}}\")({page: 'B'}) //-> ``\n\n stache(\"{{#is page 'A'}}A{{else}}C{{/is}}\")({page: 'C'}) //-> `B`\n ```\n\n - [{{#each key}} ... {{/each}}](https://canjs.com/doc/can-stache.helpers.each.html) - renders a subsection for each item in a key's value.\n\n ```js\n stache('{{#each hobbies}}<p>{{.}}</p>{{/each}}')(['Hockey', 'Hiking']) //-> `<p>Hockey</p><p>Hiking</p>`\n ```\n\n If the value of a key is a [DefineList](#section=section_definelist) only the minimum amount of DOM updates occur when the list changes.\n\n - [{{routeUrl hashes}}](https://canjs.com/doc/can-stache/helpers/route.html) - generates a url using [can-route](#canroute) for the provided hashes.\n\n ```js\n stache(\"<a href=\"{{routeUrl page='details' id='23'}}\">{{name}}</a>\")({name: 'Item 23'}) //-> `<a href=\"#!&page=details&id=23\">Item 23</a>`\n ```\n\n[Call methods](https://canjs.com/doc/can-stache.expressions.html#Callexpressions) in your scope like: `{{method(value)}}`\n\n```js\nstache('<p>10 {{pluralize(\"Baloon\" 10)}}</p>')({\n pluralize: function(subject, howMany) {\n if(howMany > 1) {\n subject += 's';\n }\n return subject;\n }\n}); //-> \"<p>10 Baloons</p>\"\n```\n\n### can-stache-bindings\n\n`can-stache-bindings` allows you to bind to viewModel or DOM events and create one-way or two-way bindings on element's properties/attributes, can-component viewModels and `can-stache`'s scope.\n\nCreate a one-way binding from the parent scope to a child's properties/attributes or viewModel:\n\n- [childProp:from=\"value\"](https://canjs.com/doc/can-stache-bindings.toChild.html) - One-way bind `name` in the scope to `userName` property on the viewModel or the `value` attribute on the `input` element.\n\n\n ```html\n <my-component userName:from=\"name\"></my-component>\n\n <input value:from=\"name\" type=\"text\">\n ```\n\nCreate a one-way binding from the child's properties/attributes or viewModel to the parent scope:\n\n- [childProp:to=\"name\"](https://canjs.com/doc/can-stache-bindings.toParent.html) - One-way bind the value of `userName` property on the viewModel or the `value` attribute on the `input` element to the `name` property in the parent scope.\n\n ```html\n <my-component userName:to=\"name\"></my-component>\n\n <input value:to=\"name\" type=\"text\">\n ```\n\nCreate two-way bindings between the parent scope and the child's viewModel or property/attributes:\n\n- [propName:bind=\"value\"](https://canjs.com/doc/can-stache-bindings.twoWay.html) - Two-way bind the value of `userName` property in the viewModel or `value` attribute on the `input` element to the `name` in the parent scope.\n\n ```html\n <my-component userName:bind=\"name\"></my-component>\n\n <input value:bind=\"name\" type=\"text\">\n ```\n\nCreate bindings to viewModel or DOM events:\n\n- [on:EVENT=\"handler()\"](https://canjs.com/doc/can-stache-bindings.event.html) - Listen to the DOM event or viewModel `EVENT` and use `handler` as the event handler.\n\nListen to the `click` event emitted by a DOM element:\n\n ```html\n <div on:click=\"updateThing()\"></my-component>\n ```\n\nListen to the `show` event emitted by the viewModel, `vm`:\n\n ```html\n <my-component on:show=\"showTheThing()\"></my-component>\n ```\n\n### can-component\n\n[can-component](https://canjs.com/doc/can-component.html) lets you\ncreate widgets with well-defined View Models and are instantiated with\ncustom elements.\n\nDefine a `can-component` by extending one with a `tag` name, [can-define](#candefine) `viewModel` and\n[can-stache template](#canstache) like:\n\n```js\n// Define the view model\nvar HelloViewModel = DefineMap.extend({\n excitedMessage: function(){\n return this.attr(\"message\")+\"!\"\n }\n});\n\nComponent.extend({\n tag: \"hello-world\",\n ViewModel: HelloViewModel,\n view: stache(\"<h1>{{excitedMessage}}</h1>\")\n});\n```\n\nTo instantiate this component so it says `Hello World!`, add\na `<hello-world>` element to the page like:\n\n```html\n<hello-world message=\"Hello World\"/>\n```\n\nUse [can-stache-bindings](#canstachebindings)\nto send a value from the `can-stache` scope like:\n\n```js\n// a `DefineMap` that will be available in the scope\nvar appViewModel = new DefineMap({\n greeting: \"Howdy Planet\"\n});\n\nvar template = stache('<hello-world message:from=\"greeting\"/>');\n\nvar frag = template(appViewModel);\n\nfrag //-> <hello-world message:from=\"greeting\">\n // <h1>Howdy Planet!</h1>\n // </hello-world>\n```\n\n`can-component`s are usually built as [modlets](./Features.html#modlets),\nmeaning their template and styles are another file and imported:\n\n```js\n// hello-world.js\nimport Component from 'can-component';\nimport Map from 'can-define/map/map';\nimport './hello-world.less';\nimport view from './hello-world.stache';\n\nexport const ViewModel = Define.extend({\n message: \"string\",\n excitedMessage: function(){\n return this.message+\"!\"\n }\n});\n\nexport default Component.extend({\n tag: \"hello-world\",\n ViewModel: ViewModel,\n view\n});\n```\n\nSome components are so small, they they don't require three\nseparate files. For these, you can use a `.component` file:\n\n```html\n<!-- hello-world.component -->\n<can-component tag=\"<%= tag %>\">\n <style type=\"less\">\n display: block;\n </style>\n <template>\n <h1>{{excitedMessage}}</h1>\n </template>\n <view-model>\n import DefineMap from 'can-define/map/map';\n\n export default DefineMap.extend({\n message: \"string\",\n excitedMessage: function(){\n return this.message+\"!\"\n }\n });\n </view-model>\n</can-component>\n```\n\n### can-route\n\n[can-route](https://canjs.com/doc/can-route.html) provides powerful 2-way, nested, routing to your application, supporting both hash and [pushstate](https://canjs.com/doc/can-route-pushstate.html).\n\nConfigure routing rules to define property values on your application's\nView Model when a url is matched.\n\n\nThe following sets the application ViewModel's `page` property\nto `\"chat\"` when the url looks like `/chat`:\n\n```js\nroute.register(\"{page}\");\n```\n\nYou can define defaults that get set when `{page}` is empty. The\nfollowing sets the default `page` property to `\"home\"`.\n\n```js\nroute.register(\"{page}\", { page: \"home\" });\n```\n\nYou can specify multiple properties to set for a given url:\n\n```js\nroute.register(\"{page}/{slug}\");\nroute.register(\"{page}/{slug}/{action}\");\n```\n\n\nUpdate the url by changing `can-route`:\n\n```js\nroute.attr(\"page\", \"restaurants\");\n// location.href -> \"/restaurants\"\n```\n\nOr change `route` by modifying the url:\n\n```js\nhistory.pushState(null, null, \"/\");\n// route.attr(\"page\"); // -> \"home\"\n```\n\nIn a DoneJS application can.route is bound to the [application View Model](#candefine), but you can connect `can-route` to other\nmaps:\n\n```js\nvar DefineMap = require(\"can-define/map/map\");\n\nvar AppViewModel = DefineMap.extend({\n ...\n});\n\nvar viewModel = new AppViewModel();\n\nroute.data = viewModel;\n```\n\nWhich will cause any changes in the route to reflect in the View Model instance, and any changes in the View Model instance to reflect in the route.\n\n## Data Layer APIs\n\n\n### can-realtime-rest-model\n\n[can-realtime-rest-model](https://canjs.com/doc/can-realtime-rest-model.html) is used to connect typed\ndata to backend services. In a DoneJS application, that typed data is a\n[can-define/map/map](#candefine) and [can-define/list/list](#candefinelistlist) type.\n\nTo make a simple connection to a restful interface:\n\n```js\n// First, create custom Map and List type\nvar Todo = DefineMap.extend({\n ownerId: \"number\",\n canComplete: function(ownerId) {\n return this.ownerId === ownerId;\n }\n});\n\nvar TodoList = DefineList.extend({\n \"*\": Todo\n},{\n incomplete: function(){\n return this.filter(function(todo){\n return !todo.complete;\n });\n }\n});\n\n// Then, make a connection with the right behaviors and options.\nvar todoConnection = realtimeRestModel({\n Map: Todo,\n List: TodoList,\n url: \"/services/todos\"\n});\n```\n\nThis adds a [getList](https://canjs.com/doc/can-connect/can/map/map.getList.html),\n[.get](https://canjs.com/doc/can-connect/can/map/map.get.html),\n[.save](https://canjs.com/doc/can-connect/can/map/map.prototype.save.html) and\n[.destroy](https://canjs.com/doc/can-connect/can/map/map.prototype.destroy.html) methods to\n`Todo` allowing you to CRUD `Todo`s and `TodoList`s from the service layer like:\n\n```js\n// Get a list of todos\nTodo.getList({due: \"today\"}).then(function(todos){ ... });\n\n// Get a single todo\nTodo.get({id: 5}).then(function(todo){ ... });\n\n// Create a todo\nvar todo = new Todo({name: \"dishes\"})\n\n// Create it on the server\ntodo.save().then(function(todo){\n\n // Update its properties\n todo.name = \"Do the dishes\";\n // Update the service layer with changes\n todo.save().then(function(todo){\n\n // Delete the todo on the service layer\n todo.destroy();\n });\n});\n```\n\n`can-connect` comes with a wide variety of behaviors that\ncan be mixed into a connection. Examples include:\n\n- [real-time](https://canjs.com/doc/can-connect/real-time/real-time.html) keeps `can.List`s updated with changes.\n- [fall-through-cache](https://canjs.com/doc/can-connect/fall-through-cache/fall-through-cache.html)\n\nTo make the process of creating `can.Map` based connections easier,\nDoneJS comes with a [supermodel generator](#generators)\ncreates a [super-map](https://canjs.com/doc/can-connect/can/super-map/super-map.html).\n\nA realtime rest model is just a connection with a bunch of the mostly commonly used\nbehaviors. Create one with the `superMap` function like:\n\n```js\nexport const messageConnection = realtimeRestModel({\n url: \"/services/todos\",\n Map: Todo,\n List: TodoList,\n name: 'todo'\n});\n```\n\n### can-query-logic\n\n[can-query-logic](https://canjs.com/doc/can-query-logic.html) is used to define the rules of an API service, in order to compare queries that are represented by the parameters commonly passed\nto service requests.\n\n\nFor example, if you want all todos for user `5` that are complete, you\nmight call:\n\n```js\nTodo.getList({ filter: { userId: 5, complete: true } })\n```\n\n`{userId: 5, complete: true}` represents a set. Using\n`can-query-logic` we can compare it to other sets. The following\nreturns `true` because `{userId: 5, complete: true}` represents\na subset of `{userId: 5}`.\n\n```js\nqueryLogic.isSubset({filter:{userId: 5, complete: true}}, {userId: 5}); // -> true\n```\n\nBehind the scenes can-query-logic uses `can-set` which can perform more complex logic with custom [set Algebras](https://github.com/canjs/can-set#setalgebra).\n\nThe following creates a set-algebra that is able to combine ranges:\n\n```js\n// Create a set Algebra\nvar algebra = new set.Algebra(\n set.comparators.rangeInclusive(\"start\",\"end\"));\n\n// use it\nalgebra.union({start: 1, end: 10},\n {start: 11, end: 20}) //-> {start: 1, end: 20}\n```\n\nIn a DoneJS application, you create custom query logics to pass to [realtime rest model](https://canjs.com/doc/can-realtime-rest-model.html) connections. The\nconnection's behaviors use that [querylogic](https://canjs.com/doc/can-query-logic.html) to their optimizations.\n\n## Testing APIs\n\n### QUnit\n\n[QUnit](https://qunitjs.com/) is DoneJS's default JavaScript unit testing framework. It is provided for DoneJS by the [steal-qunit](https://github.com/stealjs/steal-qunit) project. A basic unit test for a can.Component view-model looks like this:\n\n```js\nimport QUnit from 'steal-qunit';\nimport { ViewModel } from 'my/component/';\n\n// ViewModel unit tests\nQUnit.module('my/component');\n\nQUnit.test('Has message', function(){\n var vm = new ViewModel();\n QUnit.equal(vm.message, 'This is the my-component component');\n});\n```\n\nWhile the generators create QUnit tests by default you can switch your own tests easily to [Jasmine](https://github.com/stealjs/steal-jasmine) or [Mocha](https://github.com/stealjs/steal-mocha).\nTo use Mocha instead for the previous view-model example we just need to install the wrapper with\n\n```\nnpm install steal-mocha --save-dev\nnpm install assert --save-dev\n```\n\nAnd then change the test file to:\n\n```js\nimport mocha from 'steal-mocha';\nimport assert from 'assert';\nimport { ViewModel } from 'my/component/';\n\nmocha.setup('bdd');\n\n// ViewModel unit tests\ndescribe('my/component', function() {\n it('Has a message', function() {\n var vm = new ViewModel();\n assert.equal(vm.message, 'This is the my-component component');\n });\n});\n```\n\n### FuncUnit\n\n[FuncUnit](https://funcunit.com/) enhances QUnit, Mocha or Jasmine and enables them to simulate user actions, easily test asynchronous behavior, and support black box testing. It uses a jQuery-like syntax to write functional or unit tests. When generating an application, DoneJS already includes a basic FuncUnit smoke-test which runs alongside the other tests. It looks like this:\n\n```js\nimport F from 'funcunit';\nimport QUnit from 'steal-qunit';\n\nF.attach(QUnit);\n\nQUnit.module('my-app functional smoke test', {\n beforeEach() {\n F.open('../development.html');\n }\n});\n\nQUnit.test('my-app main page shows up', function() {\n F('title').text('my-app', 'Title is set');\n});\n```\n\nThis will open the main application (`development.html` is the HTML file that loads our DoneJS app without server-side-rendering) and ensures that the `<title>` is set to the name (which is the default in a newly generated application). To learn more about the user interactions and assertions available, follow up in the [FuncUnit API documentation](https://funcunit.com/docs/index.html).\n\n### Testee\n\n[Testee](https://github.com/bitovi/testee) is a JavaScript test runner that can run your QUnit, Mocha and Jasmine tests from the command line. The command executed when running `donejs test` (which is the same as running `npm test`) is located in the `package.json` `scripts` section and already set up to run the main test suite in Firefox like this:\n\n```\ntestee src/test.html --browsers firefox --reporter Spec\n```\n\nTo change the browsers that our tests run on we can update the list of browsers, for example to add Safari and Google Chrome Canary by changing the test script to:\n\n```\ntestee src/test.html --browsers firefox,canary,safari --reporter Spec\n```\n\nTestee supports all [Mocha command line reporters](https://mochajs.org/#reporters). For example, running the tests in the default browser [PhantomJS](http://phantomjs.org/) (DoneJS only works with PhantomJS >= 2.0) on a [Jenkins CI](https://jenkins-ci.org/) server that uses XUnit output from a `testresults.xml` can be accomplished like this:\n\n```\ntestee src/test.html --reporter XUnit > testresults.xml\n```\n\nFor more configuration options follow up in the [Testee documentation](https://github.com/bitovi/testee#testee).\n\n## DocumentJS\n\nWhen working on large applications keeping updated documentation is critical.\n[DocumentJS](https://documentjs.com/) generates API documentation for your\napplication supporting [JSDoc](http://usejsdoc.org/) syntax that can be multi-versioned.\n\n### Configuration\n\nDocumentJS is configured with a [docConfig](https://documentjs.com/docs/DocumentJS.docConfig.html) specified\nin a **documentjs.json** file within your project:\n\n```js\n{\n \"sites\": {\n \"docs\": {\n \"dest\": \"docs\",\n \"glob\" : \"**/*.{js,md}\"\n }\n }\n}\n```\n\nThis specifies to look in JavaScript and Markdown files for jsdoc tags. When ran the documentation will be written to the **docs** folder.\n\n### Documenting\n\nDocumentJS includes most [tags](https://documentjs.com/docs/documentjs.tags.html) you need to document a web application and includes an API to create your own.\n\nHere's how you would document a [can-component](#cancomponent) View Model:\n\n```js\n/**\n * @add order/new\n */\nexport const ViewModel = Define.extend({\n /**\n * @property {String} slug\n *\n * The restaurants slug (short name). Will\n * be used to request the actual restaurant.\n */\n slug: {\n type: 'string'\n },\n /**\n * @property {place-my-order/models/order} order\n *\n * The order that is being processed. Will\n * be an empty new order inititally.\n */\n order: {\n Default: Order\n },\n /**\n * @property {can.Deferred} saveStatus\n *\n * A deferred that contains the status of the order when\n * it is being saved.\n */\n saveStatus: {\n Default: Object\n },\n /**\n * @property {Boolean} canPlaceOrder\n *\n * A flag to enable / disable the \"Place my order\" button.\n */\n canPlaceOrder: {\n get() {\n let items = this.order.items;\n return items.length;\n }\n }\n\n /**\n * @function placeOrder\n *\n * Save the current order and update the status Deferred.\n *\n * @return {boolean} false to prevent the form submission\n */\n placeOrder() {\n let order = this.order;\n this.saveStatus = order.save();\n return false;\n },\n\n /**\n * @function startNewOrder\n *\n * Resets the order form, so a new order can be placed.\n *\n * @return {boolean} false to prevent the form submission\n */\n startNewOrder: function() {\n this.order = new Order();\n this.saveStatus = null;\n return false;\n }\n});\n```\n\n### Generating\n\nDoneJS preconfigures your app to be documented with:\n\n```\ndonejs document\n```\n\nOr you can run the [documentjs](https://documentjs.com/docs/DocumentJS.apis.generate.documentjs.html) command directly with:\n\n```\nnode_modules/.bin/documentjs\n```\n\n## DOM APIs\n\n### jQuery\n\n[jQuery](https://jquery.com/) is the ubiquitous DOM manipulation\nlibrary. While you don't often need to write jQuery directly,\n[CanJS](#canjs) is built making it safe to use jQuery when needed.\n\nFor example, you can make your own custom elements that call jQuery\nplugins:\n\n```js\ncallbacks.tag(\"tooltip\", function(el){\n $(el).tooltip({\n content: el.getAttribute(\"content\"),\n items: \"tooltip\"\n });\n})\n```\n\n[can-stache-bindings](#canstachebindings) lets you listen\nto [jQuery special events](http://benalman.com/news/2010/03/jquery-special-events/) like:\n\n```html\n<div on:tripleclick=\"doSomething()\">\n```\n\n[can-component](#cancomponent)'s events object also supports this:\n\n```js\nComponent.extend({\n events: {\n \"li tripleclick\": function(li, ev){ ... }\n }\n})\n```\n\n\nCanJS adds special [inserted](https://canjs.com/docs/can.events.inserted.html), [removed](https://canjs.com/docs/can.events.removed.html), and [attributes](https://canjs.com/docs/can.events.attributes.html) events. This allows you to\nteardown any behavior when the DOM is modified:\n\n```js\n$(el).bind(\"removed\", function(){\n $(el).tooltip(\"teardown\");\n})\n```\n\nCanJS's live-binding also hooks into these same events. So if you remove\nan element with jQuery, CanJS will also teardown its bindings. This means that if\nyou were to call:\n\n```js\n$(\"body\").empty();\n```\n\n### jQuery++\n\n[jQuery++](https://jquerypp.com/) adds a bunch of special events and other DOM\nutilties to jQuery.\n\n - DOM utilities\n - [animate](https://jquerypp.com/#animate) - Overwrites `jQuery.animate` to use CSS3 animations if possible.\n - [compare](https://jquerypp.com/#compare) - Compare the position of two elements in the page.\n - [range](https://jquerypp.com/#range) - Manipulate text ranges.\n - [within](https://jquerypp.com/#within) - Get the elements within a specified area.\n - Special events\n - [drag / drop](https://jquerypp.com/#drag) - drag drop events.\n - [hover](https://jquerypp.com/#hover) - hover events.\n - [key](https://jquerypp.com/#key) - get a string representation of the key pressed.\n - [resize](https://jquerypp.com/#resize) - listen to when an element changes size.\n - [swipe](https://jquerypp.com/#swipe) - mobile swipe events.\n\n\n## Server Side Rendering APIs\n\n### done-ssr\n\n[done-ssr](https://github.com/donejs/done-ssr) enables DoneJS applications to be\nserver-side rendered. Paired with [done-autorender](#done-autorender)\nit allows you to render the entire document from a single template.\n\n```js\nvar http = require(\"http\");\nvar ssr = require(\"done-ssr\");\nvar render = ssr();\n\nvar server = http.createServer(function(request, response){\n render(request).pipe(response);\n});\n\nserver.listen(8080);\n```\n\nThe render function is called with a string url to render and returns a response\nobject that contains the html string that was rendered. Use any Node-based\nhttp framework with done-ssr.\n\nFor convenience we have published an [Express](https://expressjs.com/) middleware:\n\n```js\nvar ssr = require(\"done-ssr-middleware\");\nvar app = require(\"express\")();\n\napp.use(ssr(\n config: __dirname + \"/package.json!npm\"\n));\n```\n\nAdditionally DoneJS has [done-serve](https://github.com/donejs/done-serve)\nwhich acts as a rendering front-end for your application. It will host static\ncontent, render your application, and proxy requests to another back-end server.\n\n```\ndone-serve --proxy http://localhost:7070 --port 8080\n```\n\n### done-autorender\n\n[done-autorender](https://github.com/donejs/autorender) is a Steal plugin that\nenables using a [can.stache](#canstache) template as your application's entry point. Create a template like:\n\n```html\n<html>\n<head>\n <title>app | {{page}}</title>\n</head>\n<body>\n <can-import from=\"app/state\" export-as=\"viewModel\"/>\n\n <div>Hello {{name}}</div>\n</body>\n</html>\n```\n\n**done-autorender** will insert this template on page load. The `can-import` tag with\nthe `export-as=\"viewModel\"` attribute is a [can-define/map/map](#candefine) that acts as the View Model\nfor the application.\n\nIf you have [live-reload](https://stealjs.com/docs/steal.live-reload.html#use) enabled done-autorender will additionally use those APIs to re-render the\napplication when any modules are reloaded.\n\ndone-autorender handles requests when running in Node for server-side rendering and\nwill wait for all asynchronous events to complete.\n\n### can-simple-dom\n\n[can-simple-dom](https://github.com/canjs/can-simple-dom) is a minimal virtual DOM implementation used\nfor server-side and worker thread rendering. It contains enough of the DOM APIs to get basic\njQuery usage to work, as well as what is typical of CanJS applications.\n\nIf you are working on an advanced plugin you might use can-simple-dom directly,\nin which case you would import it:\n\n```js\nimport simpleDOM from \"can-simple-dom\";\n\nconst document = new simpleDOM.Document();\n```\n\nFrom here document has the normal DOM apis such as `document.createElement`.\n\n",
"description": "DoneJS is comprised of many projects that are documented separately. This page contains overviews of each project and links to their official APIs. \n### Application Infrastructure\n\nThe blue boxes in the following architecture diagram represent modules provided by DoneJS.\n\n<object type=\"image/svg+xml\" data=\"static/img/donejs-stack-app.svg\"></object>\n\n- [StealJS](#stealjs) - Module loader and build system. [api](https://stealjs.com/docs/index.html).\n- [CanJS](#canjs) - Views, ViewModels, modeling part of Models, custom elements, routing. [api](https://canjs.com/doc/api.html)\n- [can-query-logic](https://canjs.com/doc/can-query-logic.html) Data service modelling.\n- [jQuery](#jquery) - DOM utilities. [api](https://jquery.com/)\n- [done-ssr](#done-ssr) - Incremental server-side rendering for NodeJS. [api](https://github.com/donejs/done-ssr)\n- [done-autorender](#done-autorender) - Processes templates so they can be server-side rendered. [api](https://github.com/donejs/autorender#use)\n- [can-simple-dom](#can-simple-dom) - A lightweight virtual DOM. [api](https://github.com/canjs/can-simple-dom)\n\n### Tooling\n\nDoneJS provides many aspects of JavaScript application tooling, shown in the diagram below.\n\n<object type=\"image/svg+xml\" data=\"static/img/donejs-stack-tooling.svg\"></object>\n\n- [donejs-cli](#cli-and-generators) - The commands available to the donejs command line interface. [api](https://github.com/donejs/cli)\n- [generator-donejs](#cli-and-generators) - Default generators are bundled with DoneJS. [api](https://github.com/donejs/generator-donejs/)\n- [QUnit](#qunit) - Default test assertion library. [api](https://qunitjs.com/)\n- [FuncUnit](#funcunit) - Functional test utilities. [api](https://funcunit.com/)\n- [Testee](#testee) - Browser launcher and test reporter. [api](https://github.com/bitovi/testee)\n- [DocumentJS](#documentjs) - Documentation engine. [api](https://documentjs.com/)\n\n",
"name": "Apis",
"type": "page",
"parent": "DoneJS",
"hideSidebar": true,
"outline": {
"depth": 2,
"tag": "ol"
},
"comment": " "
},
"Features": {
"src": {
"path": "docs/features.md"
},
"body": "\n## Performance Features\n\nDoneJS is configured for maximum performance right out of the box.\n\n### Server-Side Rendered\n\nDoneJS applications are written as [Single Page Applications](https://en.wikipedia.org/wiki/Single-page_application),\nand are able to be rendered on the server by running the same code. This is known as [Isomorphic JavaScript](http://isomorphic.net/javascript), or [Universal JavaScript](https://medium.com/@mjackson/universal-javascript-4761051b7ae9).\n\nServer-side rendering (SSR) provides two large benefits over traditional single page apps: much better page load performance and SEO support.\n\nSSR apps return fully rendered HTML. Traditional single page apps return a page with a spinner. The benefit to your users is a noticeable difference in perceived page load performance:\n\n<img src=\"static/img/donejs-server-render-diagram.svg\" alt=\"donejs-server-render-diagram.svg\" />\n\nCompared to other server-side rendering systems, which require additional code and infrastructure to work correctly, DoneJS is uniquely designed to make turning on SSR quick and easy, and the server it runs is lightweight and fast.\n\n#### SEO\n\nSearch engines can't easily index SPAs. Server-side rendering fixes that problem entirely. Even if [Google can understand some JavaScript now](http://googlewebmastercentral.blogspot.ca/2014/05/understanding-web-pages-better.html), many other search engines cannot.\n\nSince search engines see the HTML that your server returns (if you want search engines to find your pages) you'll want Google and other search engines seeing fully rendered content, not the spinners that normally show after initial SPAs load.\n\n#### How it works\n\nDoneJS implements SSR with a single-context virtual DOM utilizing [zones](https://davidwalsh.name/can-zone).\n\n**Single context** means every request to the server reuses the same context: including memory, modules, and even the same instance of the application.\n\n**Virtual DOM** means a virtual representation of the DOM: the fundamental browser APIs that manipulate the DOM, but stubbed out.\n\nA **zone** is used to isolate the asynchronous activity of one request. Asynchronous activity like API requests are *tracked* and DoneJS' SSR will wait for all to complete, ensuring that the page is fully rendered before showing HTML to the user.\n\nWhen using DoneJS SSR, the same app that runs on the client is loaded in Node. When a request comes in:\n 1. The server handles the incoming request by reusing the application that is already running in memory. It doesn't reload the application which means the initial response is very fast.\n 1. The app renders content the same way it would in the browser, but with a mocked out virtual DOM, which is much faster than a real DOM.\n 1. The server creates a new zone to wait for all your asynchronous data requests to finish before signaling that rendering is complete.\n 1. When rendering is complete, the virtual DOM renders the string representation of the DOM, which is sent back to the client.\n\n\nSince SSR produces fully rendered HTML, it's possible to insert a caching layer, or use a service like Akamai, to serve most requests. Traditional SPAs don't have this option.\n\nRather than a virtual DOM, some other SSR systems use a headless browser on the server, like PhantomJS, which uses a real DOM. These systems are much slower and require much more intensive server resources.\n\nSome systems, even if they do use a virtual DOM, require a new browser instance entirely, or at the very least, reloading the application and its memory for each incoming request, which also is slower and more resource intensive than DoneJS SSR.\n\n##### Prepping your app for SSR\n\nAny app that is rendered on the server needs a way to notify the server that any pending asynchronous data requests are finished, and the app can be rendered.\n\nReact and other frameworks that support SSR don't provide much in the way of solving this problem. You're left to your own devices to check when all asynchronous data requests are done, and delay rendering.\n\nIn a DoneJS application, asynchronous data requests are tracked automatically. Using can-zone, DoneJS keeps a count of requests that are made and waits for all of them to complete.\n\n<a class=\"btn\" href=\"https://github.com/donejs/done-ssr\"><span>View the Documentation</span></a>\n<a class=\"btn\" href=\"./Guide.html\"><span>View the Guide</span></a>\n\n_Server-side rendering is a feature of [done-ssr](https://github.com/donejs/done-ssr)_\n\n### Incremental Rendering\n\nDoneJS applications by default employ [incremental rendering](https://www.bitovi.com/blog/utilizing-http2-push-in-a-single-page-application) to get the best possible load performance. If SEO is important go for [Server-side rendering](#server-side-rendered) instead.\n\nIncrementally rendering apps return an initial HTML that includes the *skeleton* of your application and a tiny runtime script that connects *back* to the server to receive and apply incremental rendering instructions.\n\n#### How it works\n\nIncremental rendering uses most of the same mechanisms as server-side rendering in DoneJS: the single context virtual DOM provided by done-ssr, zones using can-zone.\n\nWhat makes incremental rendering different is that it gets an initial page to the user as quickly as possible, while it *continues to render*. Any changes that take place on the server after HTML is sent get streamed as mutation instructions back to the browser where they are reapplied.\n\n<img src=\"static/img/incremental-rendering.png\" alt=\"Incremental rendering diagram\" />\n\n1. Like with SSR, the server reuses the existing application context and renders the requested route.\n1. Once the page skeleton is ready the HTML is sent back to the browser. Along with the HTML is a small script that makes a request back to the server like `_donessr_instructions/uniqueId`.\n1. These instructions are PUSHed with http/2 or preloaded with http/1.\n1. Back on the server, the app continues to render as data requests are completed and other asynchronous activity takes place.\n1. The script connects using [fetch()](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) and applies the DOM mutations that are streamed from the server.\n1. Meanwhile the *application begins to run in the client* the same way it would in any Single-page Application.\n1. The embedded script detects when the client-side application catches up to the mutations and __flips__ so that the app is shown.\n\n### Progressive Loading\n\nWhen you first load a single page app, you're typically downloading all the JavaScript and CSS for every part of the application. These kilobytes of extra weight slow down page load performance, especially on mobile devices.\n\nDoneJS applications load only the JavaScript and CSS they need, when they need it, in highly optimized and cacheable bundles. That means your application will load *fast*.\n\nThere is no configuration needed to enable this feature, and wiring up progressively loaded sections of your app is simple.\n\n#### How it works\n\n<div class=\"youtube-container\"><div class=\"youtube-player\" data-videoid=\"C-kM0v9L9UY\"></div></div>\n\nOther build tools require you to manually configure bundles, which doesn't scale with large applications.\n\nIn a DoneJS application any components (either modlets or `.component` files) contained within the `~/pages` folder are progressively loaded.\n\nThen you run the build.\n\n```\ndonejs build\n```\n\nA build time algorithm analyzes the application's dependencies and groups them into bundles, optimizing for minimal download size.\n\nThat's it! No need for additional configuration in your JavaScript.\n\n<a class=\"btn\" href=\"https://stealjs.com/docs/StealJS.guides.progressive_loading.html\"><span>View the Documentation</span></a>\n<a class=\"btn\" href=\"./Guide.html#switch-between-pages\"><span>View the Guide</span></a>\n\n_Progressive Loading is a feature of [StealJS](https://stealjs.com/) with additional support via the [`<can-import>` tag](https://canjs.com/docs/can%7Cview%7Cstache%7Csystem.import.html) of [CanJS](https://canjs.com/)_\n\n### Caching and Minimal Data Requests\n\nDoneJS improves performance by intelligently managing the data layer, taking advantage of various forms of caching and request reduction techniques.\n\nUndoubtedly, the slowest part of any web application is round trips to the server. Especially now that [more than 50% of web traffic comes from mobile devices](http://searchengineland.com/its-official-google-says-more-searches-now-on-mobile-than-on-desktop-220369), where connections are notoriously slow and unreliable, applications must be smart about reducing network requests.\n\nMaking matters worse, the concerns of maintainable architecture in single page applications are at odds with the concerns of minimizing network requests. This is because independent, isolated UI widgets, while easier to maintain, often make AJAX requests on page load. Without a layer that intelligently manages those requests, this architecture leads to too many AJAX requests before the user sees something useful.\n\nWith DoneJS, you don't have to choose between maintainability and performance.\n\nDoneJS uses the following strategies to improve perceived performance (reduce the amount of time before users see content rendered):\n\n - [Fall through caching](#fall-through-caching) - Cache data in localStorage. Automatically show cached data immediately, but look for updates on the server in the background and merge changes.\n - [Combining requests](#combining-requests) - Instead of making multiple, independent requests to the same API, combine them into a single request.\n - [Request caching](#request-caching) - Reduce the number and size of server requests by intelligently using cached datasets.\n - [Inline cache](#inline-cache) - Use data embedded in the page response instead of making duplicate requests.\n\n#### How it works\n\n[can-connect](https://canjs.com/doc/can-connect.html) makes up part of the DoneJS model layer. Since all requests flow through this data layer, by making heavy use of set logic and localStorage caching, it's able to identify cache hits, even partial hits, and make the most minimal set of requests possible.\n\nIt acts as a central hub for data requests, making decisions about how to best serve each request, but abstracting this complexity away from the application code. This leaves the UI components themselves able to make requests independently, and with little thought to performance, without actually creating a poorly performing application.\n\n##### Fall through caching\n\nFall through caching serves cached data first, but still makes API requests to check for changes.\n\nThe major benefit of this technique is improved perceived performance. Users will see content faster. Most of the time, when there is a cache hit, that content will still be accurate, or at least mostly accurate.\n\nThis benefits two types of situations. First is page loads after the first page load (the first page load populates the cache). This scenario is less relevant when using server-side rendering. Second is long-lived applications that make API requests after the page has loaded. These types of applications will enjoy improved performance.\n\nBy default, this is turned on, but can easily be deactivated for data that should not be cached.\n\nHere's how the caching logic works:\n\n1. When the application loads, it checks for available cache connections.\n1. When a request is made, it checks for a cache hit.\n1. If there is a hit, the request is completed immediately with the cached data.\n1. Regardless of a hit or miss, a request is made in the background to the actual API endpoint.\n1. When that response comes back, if there was a difference between the API response data and the cache hit data, the initial request promise's data is updated with the new data. Template data bindings will cause the UI to update automatically with these changes.\n1. Updated response data is automatically saved in the cache, to be used for future requests - whether that's in the current page session, or when the user comes back in the future.\n\n<video style=\"width:100%;\" controls poster=\"static/img/poster-fall-thru-caching.jpg\" preload=\"none\">\n <source src=\"static/img/donejs-fallthrough-caching.webm\" type=\"video/webm\">\n <source src=\"static/img/donejs-fallthrough-caching.ogg\" type=\"video/ogg\">\n <source src=\"static/img/donejs-fallthrough-caching.mp4\" type=\"video/mp4\">\n</video>\n\n##### Combining requests\n\nCombining requests combines multiple incoming requests into one, if possible. This is done with the help of [set algebra](https://en.wikipedia.org/wiki/Algebra_of_sets).\n\nDoneJS collects requests that are made within a few milliseconds of each other, and if they are pointed at the same API, tries to combine them into a single superset request.\n\nFor example, the video below shows an application that shows two filtered lists of data on page load - a list of completed and incomplete todos. Both are subsets of a larger set of data - the entire list of todos.\n\nCombining these into a single request reduces the number of requests. This optimization is abstracted away from the application code that made the original request.\n\n<video style=\"width:100%;\" controls poster=\"static/img/poster-combine-requests.jpg\" preload=\"none\">\n <source src=\"static/img/donejs-combine-requests.webm\" type=\"video/webm\">\n <source src=\"static/img/donejs-combine-requests.ogg\" type=\"video/ogg\">\n <source src=\"static/img/donejs-combine-requests.mp4\" type=\"video/mp4\">\n</video>\n\n##### Request caching\n\nRequest caching is a type of caching that is more aggressive than fallthrough caching. It is meant for data that doesn't change very often. Its advantage is it reduces both the number of requests that are made, and the size of those requests.\n\nThere are two differences between request and fallthrough caching:\n\n1. Cached data is not invalidated.\n\nOnce data is in the cache, no more requests to the API for that same set of data are made. You can write code that invalidates the cache at certain times, or after a new build is released.\n\n2. The smallest possible request is made, based on the contents of the cache, and merged into a complete result set.\n\nThe request logic is more aggressive in its attempts to find subsets of the data within the cache, and to only make an API request for the subset NOT found in the cache. In other words, partial cache hits are supported.\n\nThe video below shows two example scenarios. The first shows the cache containing a superset of the request. The second shows the cache containing a subset of the request.\n\n<video style=\"width:100%;\" controls poster=\"static/img/poster-request-caching.jpg\" preload=\"none\">\n <source src=\"static/img/donejs-request-caching.webm\" type=\"video/webm\">\n <source src=\"static/img/donejs-request-caching.ogg\" type=\"video/ogg\">\n <source src=\"static/img/donejs-request-caching.mp4\" type=\"video/mp4\">\n</video>\n\n\n##### Inline cache and server push\n\nServer-side rendered single page apps (SPAs) have a problem with wasteful duplicate requests. These can cause the browser to slow down, waste bandwidth, and reduce perceived performance.\n\n1. When a page is rendered server-side, it makes data requests on the server to various APIs.\n1. After the page's rendered HTML loads in the client, the SPA is loaded in the client, so that subsequent requests are handled within the SPA.\n1. The SPA will want to re-request for the same data that was already requested on the server.\n\nDoneJS solves this problem with server push and an inline cache - embedded inline JSON data sent back with the server rendered content, which is used to serve the initial SPA data requests.\n\nDoneJS uniquely makes populating and using the inline cache easy. Using plain XHR:\n\n1. Tells the SSR server to wait for a promise to resolve before rendering.\n1. Collects data from each promise and uses it to populate the inline cache. In http/2 servers it does a server PUSH instead, which elimnates the need for inlining the data in HTML.\n\nFor example:\n\n```js\nComponent.extend({\n tag: \"user-name\",\n view: `{{user.name}}`,\n ViewModel: {\n id: \"number\",\n get userPromise() {\n return User.get({ id: this.id });\n }\n }\n});\n```\n\nThe model layer seamlessly integrates the inline cache in client side requests, without any special configuration.\n\nWhile this flow would be possible in other SSR systems, it would require manually setting up all of these steps.\n\nThis video illustrates how it works.\n\n<video style=\"width:100%;\" controls poster=\"static/img/poster-inline-cach.jpg\" preload=\"none\">\n <source src=\"static/img/donejs-inline-cache.webm\" type=\"video/webm\">\n <source src=\"static/img/donejs-inline-cache.ogg\" type=\"video/ogg\">\n <source src=\"static/img/donejs-inline-cache.mp4\" type=\"video/mp4\">\n</video>\n\n\n<a class=\"btn\" href=\"https://canjs.com/doc/can-query-logic.html\"><span>View the Documentation</span></a>\n<a class=\"btn\" href=\"./Guide.html#messages-page\"><span>View the Guide</span></a>\n\n_Caching and minimal data requests is a feature of [can-connect](https://github.com/canjs/can-connect)_\n\n### Minimal DOM Updates\n\nThe rise of templates, data binding, and MV* separation, while boosting maintainability, has come at the cost of performance. Many frameworks are not careful or smart with DOM updates, leading to performance problems as apps scale in complexity and data size.\n\nDoneJS' view engine touches the DOM more minimally and specifically than competitor frameworks, providing better performance in large apps and a \"closer to the metal\" feel.\n\nTake the TodoMVC application as an example. If you measure how long it takes DoneJS and React to render the same number of todos you'll see the performance advantage of minimal DOM updates. In fact, we did just that and here's the result:\n\n<img class=\"img-with-caption\" src=\"static/img/donejs-minimal-dom-updates-todomvc.png\" alt=\"Measuring React and DoneJS using TodoMVC.\" />\n_For a small set of todos the difference is negligible but as the number increases the gap widens to the point where React is 6 times slower than DoneJS when rendering 1000 todos._\n\nYou can run this test for yourself at <a href=\"https://output.jsbin.com/zigovul/7\" target=\"_blank\">JS Bin</a>.\n\n#### How it works\n\nConsider the following template:\n\n```html\n{{#for(row of this.rows)}}\n<div>{{row.name}}</div>\n{{/for}}\n```\n\nAnd the following change to its data:\n\n```js\nrows[0].name = 'changed'; // change the first row's name\n```\n\nIn DoneJS, which uses the [can-stache](https://canjs.com/doc/can-stache.html) view engine, that would:\n\n 1. Trigger an event (because of the [DefineMap](https://canjs.com/doc/can-define/map/map.html) object observe API)\n 1. The event invokes a data binding event handler in the template layer\n 1. The handler immediately results in the following code being run:\n```js\ntextNode.nodeValue = 'changed';\n```\n\nIn Backbone, you would need to manually re-render the template or roll your own rendering library.\n\nIn Angular, at the end of the current $digest cycle, that would result in an expensive comparison between the old rows array and the new one to see what properties have changed. After the changed property is discovered, the specific DOM node would be updated.\n\nIn React, that would result in the virtual DOM being re-rendered. A diff algorithm comparing the new and old virtual DOM would discover the changed node, and then the specific DOM node would be updated.\n\nOf these four approaches, DoneJS knows about the change the quickest, and updates the DOM the most minimally.\n\nTo see this in action run the test embedded below that shows how DoneJS, React and Angular compare when updating the DOM when a single property changes:\n<img src=\"static/img/donejs-minimal-dom-updates-circles.png\" alt=\"Measuring DoneJS, React and Angular rendering a simple property change.\" />\n\nYou can run this test yourself at <a href=\"https://output.jsbin.com/wotevub/2\" target=\"_blank\">JS Bin</a>\n\nWith synchronously observable objects and data bindings that change minimal pieces of the DOM, DoneJS aims to provide the best possible mix between powerful, yet performant, templates.\n\n<a class=\"btn\" href=\"https://canjs.com/doc/can-stache.html\"><span>can-stache Documentation</span></a>\n<a class=\"btn\" href=\"https://canjs.com/doc/can-define/map/map.html\"><span>DefineMap Documentation</span></a>\n\n_Minimal DOM updates is a feature of [CanJS](https://canjs.com/)_\n\n### Memory Safety\n\nPreventing memory leaks is a critical feature of any client-side framework. The biggest source of memory leaks in client-side applications is event handlers. When adding an event handler to a DOM node you have to be sure to remove that handler when the node is removed. If you do not, that DOM node will never be garbage collected by the browser.\n\n#### How it works\n\nWhen event listeners are created in a DoneJS application using template event binding or by binding using Controls, internally these handlers are stored. This looks like:\n\n```html\n<a href=\"/todos/new\" on:click=\"this.newTodo()\">New Todo</a>\n```\n\nInternally CanJS listens for this element's \"removed\" event. The \"removed\" event is a synthetic event that will be used to:\n\n* Remove all event listeners.\n* Remove DOM data associated with the element.\n* Remove any template bindings, such as computes bound to text within the template.\n\nCanJS is different from other frameworks in that it will clean up its own memory event when not using the framework to tear down DOM. For example, if you were to do:\n\n```js\ntodoAnchor.parentNode.removeChild(todoAnchor);\n```\n\nThe event listener created would still be torn down. This is because CanJS uses a [MutationObserver](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) to know about all changes to the DOM. When it sees an element was removed it will trigger the \"removed\" event, cleaning up the memory.\n\n### Deploy to a CDN\n\nDoneJS makes it simple to deploy your static assets to a CDN (content delivery network).\n\nCDNs are distributed networks of servers that serve static assets (CSS, JS, and image files). You only push your files to one service, and the CDN takes care of pushing and updating your assets on different servers across the country and globe. As your app scales CDNs will keep up with the demand, and help support users regardless if they are in New York or Melbourne.\n\n<img class=\"img-with-caption\" src=\"static/img/DoneJS-Animated-No-CDN.gif\" alt=\"User request across the globe without a CDN.\" />\n_Without a CDN, requests will take longer to fulfill if the user is located further away from your servers._\n<hr />\n\n\n<img class=\"img-with-caption\" src=\"static/img/DoneJS-Animated-With-CDN.gif\" alt=\"User request across the globe with a CDN.\" />\n_With a CDN, requests can be fulfilled much quicker. Users are served content from the servers located nearest to them._\n\n#### How it works\n\nIt's widely known that CDNs offer the best performance for static assets, but most apps don't use them, mainly because its annoying: annoying to automate, configure, and integrate with your build process.\n\nDoneJS comes with integrations with [S3](https://aws.amazon.com/s3/) and [Firebase](https://www.firebase.com) (popular CDN services) that make configuring and deploying to a CDN dirt simple.\n\n 1. You sign up for Firebase.\n 2. You run: `donejs add firebase` in your terminal. It asks a few questions, most of which you can accept the default answer.\n 3. You run `donejs deploy`.\n\nThat's it. Now when you run your server in production mode, all static assets (CSS, JS, images, etc) are served from the CDN.\n\nEven better, you can set up [continuous deployment](./place-my-order.html#continuous-deployment), so that TravisCI or other tools will deploy your code, including pushing out your latest static files to the CDN, automatically.\n\n<a class=\"btn\" href=\"./Guide.html#deploy\"><span>View the Guide</span></a>\n\n## Usability features\n\nDoneJS is used to make beautiful, real-time user interfaces that can be exported to run on every platform.\n\n### iOS, Android, and Desktop Builds\n\nWrite your application once, then run it natively on every device and operating system. You can make iOS, Android, and desktop builds of your DoneJS application with no extra effort.\n\n<img src=\"static/img/desktop-mobile.gif\" />\n_Our DoneJS Chat App running as a macOS desktop app and inside an iOS emulator._\n\n#### How it works\n\nFor iOS and Android builds, DoneJS integrates with [Apache Cordova](https://cordova.apache.org/) to generate a mobile app that is ready to be uploaded to Apple's App Store or Google Play.\n\nFor native desktop applications, DoneJS integrates with [Electron](https://electron.atom.io/) or [NW.js](https://github.com/nwjs/nw.js) to create a native macOS, Windows, or Linux application.\n\nAdding this integration is as simple as running\n\n```\ndonejs add cordova\ndonejs add nw\ndonejs add electron\ndonejs build\n```\n\nWith these simple integrations, you can expand your potential audience without having to build separate applications.\n\n<a class=\"btn\" href=\"https://github.com/stealjs/steal-cordova\"><span>View the Documentation</span></a>\n<a class=\"btn\" href=\"./Guide.html#desktop-and-mobile-apps\"><span>View the Guide</span></a>\n\n_Cordova, Electron, and NW.js integration are features of the [steal-electron](https://github.com/stealjs/steal-electron), [steal-cordova](https://github.com/stealjs/steal-cordova), and [steal-nw](https://github.com/stealjs/steal-nw) projects._\n\n### Supports All Browsers, Even IE11\n\nDoneJS applications support Internet Explorer 11 with minimal additional configuration. You can even write applications using [most ES6 features](https://babeljs.io/docs/usage/caveats/), using the built-in babel integration.\n\nMany people won't care about this because Internet Explorer is on its way out, which is a very good thing!\n\nBut it's [not quite dead yet](https://youtu.be/grbSQ6O6kbs?t=61). For many mainstream websites, banks, and e-commerce applications, IE continues to hang around the browser stats.\n\nAnd while other frameworks don't support Internet Explorer at all, DoneJS makes it easy to write one app that runs everywhere.\n\n<a class=\"btn\" href=\"./Guide.html\"><span>View the Guide</span></a>\n\n### Real Time Connected\n\nDoneJS is designed to add real-time behavior to applications using any backend technology stack.\n\n[Socket.io](https://socket.io) provides the basics to add real-time capabilities to any JavaScript application, but the challenge of integrating real-time updates into your code remains.\n\nWhen new data arrives, how do you know what data structures to add it to? And where to re-render? Code must be written to send socket.io data across your application, but that code becomes aware of too much, and therefore is brittle and hard to maintain.\n\nDoneJS makes weaving Socket.io backends into your UI simple and automatic.\n\n#### How it works\n\n<div class=\"youtube-container\"><div class=\"youtube-player\" data-videoid=\"w4mp4oSb6BQ\"></div></div>\n\nDoneJS' model layer uses set logic to maintain lists of data represented by JSON properties, like a list of todos with `{'ownerId': 2}`. These lists are rendered to the UI via data bound templates.\n\nWhen server-side updates are sent to the client, items are automatically removed or added to any lists they belong to. They also automatically show up in the UI because of the data bindings.\n\nAll of this happens with about 4 lines of code.\n\n```js\nconst socket = io('https://chat.donejs.com');\nsocket.on('messages created',\n order => messageConnection.createInstance(order));\nsocket.on('messages updated',\n order => messageConnection.updateInstance(order));\nsocket.on('messages removed',\n order => messageConnection.destroyInstance(order));\n```\n\n[Follow the guide](./Guide.html#enable-a-real-time-connection) to see an example in action. View the can-connect real-time documentation [here](https://canjs.com/doc/can-connect/real-time/real-time.html).\n\n<a class=\"btn\" href=\"https://canjs.com/doc/can-connect/real-time/real-time.html\"><span>View the Documentation</span></a>\n<a class=\"btn\" href=\"./Guide.html#enable-a-real-time-connection\"><span>View the Guide</span></a>\n\n_Real time connections is a feature of the [can-connect](https://canjs.com/doc/can-connect.html) project._\n\n### Pretty URLs with Pushstate\n\nDoneJS applications use [pushstate](https://developer.mozilla.org/en-US/docs/Web/API/History_API#The_pushState()_method) to provide navigable, bookmarkable pages that support the back and refresh buttons, while still keeping the user on a single page.\n\nThe use of pushstate allows your apps to have \"Pretty URLs\" like `myapp.com/user/1234` instead of uglier hash-based URLs like `myapp.com#page=user&userId=1234` or `myapp.com/#!user/1234`.\n\nWiring up these pretty URLs in your code is simple and intuitive.\n\n#### How it works\n\n<div class=\"youtube-container\"><div class=\"youtube-player\" data-videoid=\"aHA504Vx0eU\"></div></div>\n\nRouting works a bit differently than other libraries. In other libraries, you might declare routes and map those to controller-like actions.\n\nDoneJS application [routes](https://canjs.com/doc/can-route.html) map URL patterns, like `/user/1`, to properties in our application state, like `{'userId': 1}`. In other words, our routes will just be a representation of the application state.\n\nThis architecture simplifies routes so that they can be managed entirely in simple data bound templates, like the following example:\n\n```html\n{{#switch page}}\n {{#case \"home\"}}\n <myapp-home></myapp-home>\n {{/case}}\n {{#case \"users\"}}\n {{#if(slug)}}\n <myapp-user-detail userId:bind=\"slug\"></myapp-user-detail>\n {{else}}\n <myapp-users></myapp-users>\n {{/if}}\n {{/case}}\n{{/switch}}\n```\n\n<a class=\"btn\" href=\"./place-my-order.html#setting-up-routing\"><span>View the Guide</span></a>\n\n_Pretty URLs and routing are features of the [CanJS](https://canjs.com/) project._\n\n## Maintainability features\n\nDoneJS helps developers get things done quickly with an eye toward maintenance.\n\n### Comprehensive Testing\n\nNothing increases the maintainability of an application more than good automated testing. DoneJS includes a comprehensive test layer that makes writing, running, and maintaining tests intuitive and easy.\n\nDoneJS provides tools for the entire testing lifecycle:\n\n* [Generators](#generators) - create boilerplate tests to get started quickly\n* [Unit testing](#unit-tests) - assertion libraries to test your module interfaces\n* [Functional testing](#functional-tests) - scripting the browser, simulating user actions, and testing your UI modules\n* [User action event simulation](#event-simulation-accuracy) - accurate event simulation for clicks, types, drags, and other user actions\n* [A command line test runner](#running-tests-from-the-command-line) - invoke the same tests from the CLI\n* [A browser launcher](#running-tests-from-the-command-line) - launch several browsers and target your tests against them\n* [A reporting tool](#running-tests-from-the-command-line) - report results, including code coverage, to the CLI, in various formats\n* [Simple integration with continuous integration tools](#continuous-integration--deployment) - one step to hook into TravisCI or other CI systems\n* [A mock layer](#mocking-server-apis) - mock out your server APIs so you can test your app in isolation from a server\n\n<div class=\"maintainable wrapper\">\n <div class=\"background video\">\n <video tabindex=\"0\" preload=\"none\" class=\"img-responsive\" poster=\"static/img/donejs-testing.jpg\">\n <source src=\"static/img/donejs-testing-no-fade-in.mov\" type=\"video/mp4\">\n <source src=\"static/img/donejs-testing-no-fade-in.mp4\" type=\"video/mp4\">\n <source src=\"static/img/donejs-testing-no-fade-in.ogg\" type=\"video/mp4\">\n <source src=\"static/img/donejs-testing-no-fade-in.webm\" type=\"video/webm\">\n </video>\n </div>\n</div>\n\n#### How it works\n\nTesting JavaScript apps is a complex task process unto itself. To do it right, you need many tools that have to work together seamlessly. DoneJS provides everything you need - the whole stack.\n\n##### Generators\n\nThe DoneJS app generator command `donejs add app` creates a working project-level test HTML and JS file. Component generators via `donejs add component cart` create a test script and individual test page for each test.\n\n##### Unit tests\n\nUnit tests are used to test the interface for modules like models and view models. You can choose between BDD style unit tests with Jasmine, Mocha, or a more traditional TDD assertion style with QUnit.\n\n##### Functional tests\n\nFunctional tests are used to test UI components by simulating user behavior. The syntax for writing functional tests is jQuery-like, chainable, and asynchronous, simulating user actions and waiting for page elements to change asynchronously.\n\n```js\ntest('destroying todos', function() {\n F('#new-todo').type('Sweet. [enter]');\n\n F('.todo label:contains(\"Sweet.\")').visible('basic assert');\n F('.destroy').click();\n\n F('.todo label:contains(\"Sweet.\")').missing('destroyed todo');\n});\n```\n\n##### Event simulation accuracy\n\nUser action methods, like click, type, and drag, simulate exactly the sequence of events generated by a browser when a user performs that action. For example this:\n```js\nF( \".menu\" ).click();\n```\n\nis not just a click event. It triggers a mousedown, then blur, then focus, then mouseup, then click. The result is more accurate tests that catch bugs early.\n\nEven further, there are differences between how IE and Safari handle a click. DoneJS tests take browser differences into account when running functional tests.\n\n##### Running tests from the command line\n\nDoneJS comes with a command line test runner, browser launcher, and reporting tool that integrates with any [continuous integration](#continuous-integration--deployment) environment.\n\nNo setup required, running a DoneJS project's test is as simple as running:\n\n```\ndonejs test\n```\n\nYou can run launch your unit and functional tests from the cli, either in headless browser mode, or via multiple real browsers. You can even launch browserstack virtual machines to test against any version of Android, Windows, etc.\n\nThe reporting tool gives detailed information about coverage statistics, and lets you choose from many different output formats, including XML or JSON files.\n\n##### Mocking server APIs\n\nAutomated frontend testing is most useful when it has no external dependencies on API servers or specific sets of data. Thus a good mock layer is critical to writing resilient tests.\n\nDoneJS apps use fixtures to emulate REST APIs. A default set of fixtures is created by generators when a new model is created. Fixtures are very flexible, and can be used to simulate error states and slow performing APIs.\n\n```js\nimport fixture from 'can-fixture';\n\nconst store = fixture.store([\n { name: 'Calisota', short: 'CA' },\n { name: 'New Troy', short: 'NT'}\n],{});\n\nfixture('/api/states/{short}', store);\n\nexport default store;\n```\n\n##### Simple authoring\n\nSeveral DoneJS features converge to make authoring tests extremely simple.\n\nBecause of [ES6 Module](#es6-modules) support, everything in a DoneJS app is a module, so a test can simply import the modules it needs - such as fixtures and module under test:\n\n```js\nimport restaurantStore from 'place-my-order/models/fixtures/restaurant';\nimport { ViewModel } from './list';\n```\n\nThis means the test is small, isolated, and simple. Tests themselves are modules too, so they can be collected easily into sets of tests.\n\nBecause of the [modlet](#modlets) pattern, each component contains its own working test script and test file, which can be worked on in isolation.\n\nBecause of [hot module swapping](#hot-module-swapping), you can write, debug, and run tests without constantly reloading your page.\n\nOther frameworks require a build step before tests can be run. These builds concatenate dependencies and depend on the specific order of tests running, which is a brittle and inefficient workflow.\n\nBecause DoneJS uses a client side loader that makes it simple to start a new page that loads its own dependencies, there is no build script needed to compile and run tests.\n\nYou just run the generator, load your modules, write your test, and run it - from the browser or CLI.\n\n<blockquote class=\"fun-quotes\">\n <div class=\"fun-intro\">You spend less time messing with test infrastructure,</div>\n <div class=\"fun-link\">...and more time <a href=\"javascript:void(0)\" data-toggle=\"popover\" data-placement=\"top\" data-html=\"true\" data-content='<div class=\"youtube-container\"><div class=\"youtube-player\" data-videoid=\"s4faD0fox_s\" data-params=\"start=261\"></div></div>'>mud ridin'.</a></div>\n <img class=\"fun-img\" src=\"static/img/funny-muddin.png\">\n</blockquote>\n\n##### More information\n\nThe DoneJS testing layer involves many pieces, so if you want to learn more:\n\n * follow along in the [Unit testing view model and fixtures](./place-my-order.html#creating-a-unit-tested-view-model) section of the guide\n * see how to run tests and set up CI automation in the [CI section](./place-my-order.html#continuous-integration) of the guide\n * read about [FuncUnit](https://funcunit.com/), the functional testing and asynchronous user action simulating library\n * read about [syn](https://github.com/bitovi/syn) - the synthetic event library\n * read about the [Testee.js](https://github.com/bitovi/testee) browser launcher, test runner, and reporting tool\n * read the [can-fixture](https://canjs.com/doc/can-fixture.html) docs\n\n### Documentation\n\nDocumentation is critical for maintainability of any complex application. When your team adds developers, docs ensure minimal ramp up time and knowledge transfer.\n\nYet most teams either don't write docs, or they'll do it \"later\" - a utopian future period that is always just out of reach. Why? Because it's extra work to set up a tool, configure it, create and maintain separate documentation files.\n\nDoneJS comes with a documentation tool built in, and it generates multi-versioned documentation from inline code comments. It eliminates the barrier to producing documentation, since all you have to do is comment your code (which most people already do) and run `donejs document`.\n\n<div class=\"maintainable wrapper\">\n <div class=\"background video\">\n <video tabindex=\"0\" preload=\"none\" class=\"img-responsive\" poster=\"static/img/done-js-documentation.jpg\">\n <source src=\"static/img/donejs-documentation-no-fade-in.mov\" type=\"video/mp4\">\n <source src=\"static/img/donejs-documentation-no-fade-in.mp4\" type=\"video/mp4\">\n <source src=\"static/img/donejs-documentation-no-fade-in.ogg\" type=\"video/mp4\">\n <source src=\"static/img/donejs-documentation-no-fade-in.webm\" type=\"video/webm\">\n </video>\n </div>\n</div>\n\n#### How it works\n\nYou write comments above the module, method, or object that you want to document:\n\n```js\n/**\n * @module {function} utils/add\n * @parent utils\n *\n * The module's description is the first paragraph.\n *\n * The body of the module's documentation.\n *\n * @param {Number} first This param's description.\n * @param {Number} second This param's description.\n * @return {Number} This return value's description.\n */\nexport default function(){ ... };\n```\n\nThen run `donejs document`. A browsable documentation website will be generated.\n\n<img src=\"static/img/docs.png\" alt=\"A documentation website\" />\n\nDoneJS applications use [DocumentJS](https://documentjs.com) to produce multi-versioned documentation. It lets you:\n\n- Write docs inline or in markdown files.\n- Specify your code's behavior precisely with JSDoc and [Google Closure Compiler annotations](https://developers.google.com/closure/compiler/docs/js-for-compiler?hl=en) - a well-known documentation syntax.\n- Customize your site's theme and layout.\n- Generate multi-versioned documentation.\n- Document CSS alongside JavaScript. You can even make a [live style guide](https://documentjs.com/examples/styles/index.html).\n\nYou can keep it simple like the example above, or you can customize your docs with many powerful features. In fact, this entire site and the [CanJS](https://canjs.com/doc/api.html) site are generated using DocumentJS.\n\n<blockquote class=\"fun-quotes\">\n <div class=\"fun-intro\">You spend less time messing with Documentation generators,</div>\n <div class=\"fun-link\">...and more time <a href=\"javascript:void(0)\" data-toggle=\"popover\" data-placement=\"top\" data-html=\"true\" data-content='<div class=\"youtube-container\"><div class=\"youtube-player\" data-videoid=\"7WaLCWaTo8\"></div></div>'>perfecting your moonwalk.</a></div>\n <img class=\"fun-img\" src=\"static/img/funny-moonwalk.png\">\n</blockquote>\n\n<a class=\"btn\" href=\"https://documentjs.com/docs/index.html\"><span>View the Documentation</span></a>\n<a class=\"btn\" href=\"./place-my-order.html#create-documentation\"><span>View the Guide</span></a>\n\n_DoneJS Documentation is a feature of [DocumentJS](https://documentjs.com/)_\n\n### Continuous Integration & Deployment\n\nContinuous Integration (CI) and Continuous Deployment (CD) are must have tools for any modern development team.\n\nCI is a practice whereby all active development (i.e. a pull request) is checked against automated tests and builds, allowing problems to be detected early (before merging the code into the release branch).\n\n<img src=\"static/img/git-failed.gif\" srcset=\"static/img/git-failed.gif 1x, static/img/git-failed-2x.gif 2x\" alt=\"A pull request that breaks the build or fails tests\">\n_Example of a GitHub pull request with Travis CI integrated. Warns users in advance of merges if their changes will break builds or fail tests._\n\nCD means that any release or merges to your release branch will trigger tests, builds, and deployment.\n\nPaired together, CI and CD enable automatic, frequent releases. CD isn't possible without CI. Good automated testing is a must to provide the confidence to release without introducing bugs.\n\nDoneJS provides support for simple integration into popular CI and CD tools, like TravisCI and Jenkins.\n\n<div class=\"maintainable wrapper\">\n <div class=\"background video\">\n <video tabindex=\"0\" preload=\"none\" class=\"img-responsive\" poster=\"static/img/continuous-integration0deployment.jpg\">\n <source src=\"static/img/donejs-continuous-integration0deployment-no-fade-in.mov\" type=\"video/mp4\">\n <source src=\"static/img/donejs-continuous-integration0deployment-no-fade-in.mp4\" type=\"video/mp4\">\n <source src=\"static/img/donejs-continuous-integration0deployment-no-fade-in.ogg\" type=\"video/mp4\">\n <source src=\"static/img/donejs-continuous-integration0deployment-no-fade-in.webm\" type=\"video/webm\">\n </video>\n </div>\n</div>\n\n#### How it works\n\nSetting up continuous integration and deployment involves several steps:\n 1. Writing tests\n 1. Setting up a test harness that runs tests from the command line\n 1. Creating simple scripts for running a build, test, and deploy\n 1. Integrating with a service that runs the scripts at the proper times\n\nSteps 1, 2, and 3 are the hard parts. Step 4 is simple. DoneJS supports in two main ways: proper test support and simple CLI commands.\n\n##### Proper test support\n\nDoneJS comes with comprehensive support for testing. The [Testing](#comprehensive-testing) section contains much more detail about testing support.\n\n[Generators](#generators) create working test scripts right off the bat, and the plumbing for test automation is built into each project. Each [modlet](#modlets) contains a skeleton for unit tests. All that is left for the developer to do is write tests.\n\n##### Simple CLI commands\n\nAnother hurdle is creating automated build, test, and deployment scripts. Every DoneJS app comes with a build, test, and deployment one-liner: `donejs build`, `donejs test`, and `donejs deploy`.\n\n##### Tool integration\n\nOnce the tests are written and the scripts are automated, integrating with the tools that automatically runs these scripts is quite simple. For instance, setting up Travis CI involves signing up and adding a `.travis.yml` file to the project:\n\n```\nlanguage: node_js\nnode_js: node\nscript: npm start & npm test\nbefore_install:\n - \"export DISPLAY=:99.0\"\n - \"sh -e /etc/init.d/xvfb start\"\n```\n\n<a class=\"btn\" href=\"./place-my-order.html#continuous-integration\"><span>View the CI Guide</span></a>\n<a class=\"btn\" href=\"./place-my-order.html#continuous-deployment\"><span>View the CD Guide</span></a>\n\n### Modlets\n\nThe secret to building large apps is to never build large apps. Break up your application into small pieces. Then, assemble.\n\nDoneJS encourages the use of the modlet file organization pattern. Modlets are small, decoupled, reusable, testable mini applications.\n\n#### How it works\n\nLarge apps have a lot of files. There are two ways to organize them: by type or by module.\n\n<img src=\"static/img/donejs-modlet-diagram.png\" srcset=\"static/img/donejs-modlet-diagram.png 1x, static/img/donejs-modlet-diagram-2x.png 2x\" alt=\"DoneJS Modlet Organization Diagram\" />\n\nOrganization by module - or modlets - make large applications easier to maintain by encouraging good architecture patterns. The benefits include:\n\n * Each modlet contains its own demo page and its own test page. Getting a demo page running forces separation of concerns and isolated modules - hallmarks of good design. A standalone demo and test page makes it easy to work on pieces of your application in isolation.\n * Developers are more likely to update tests and documentation if they are sitting right next to the module they are editing. The test is not hidden in a `tests` folder that is more easily ignored.\n * You can develop the application without having to load the entire application and all of its tests on every change.\n\nAn example modlet from the [in-depth guide](./place-my-order.html) is the [order/new](https://github.com/donejs/place-my-order/tree/master/src/restaurant/list) component. It has its own [demo page](http://www.place-my-order.com/src/order/new/demo.html) and [test page](http://www.place-my-order.com/src/order/new/test.html).\n\nDoneJS generators create modlets to get you started quickly. To learn more about the modlet pattern, read this [blog post](http://blog.bitovi.com/modlet-workflows/).\n\n<a class=\"btn\" href=\"https://youtu.be/eIfUsPdKF4A?t=97\"><span>View the Video</span></a>\n<a class=\"btn\" href=\"./Guide.html#generate-custom-elements\"><span>View the Guide</span></a>\n\n_Modlets are a feature of DoneJS [generators](#generators)._\n\n### npm Packages\n\nDoneJS makes it easy to share and consume modules via package managers like npm and Bower.\n\nYou can import modules from any package manager in any format - CommonJS, AMD, or ES6 - without any configuration. And you can convert modules to any other format.\n\nThe goal of these features is to transform project workflows, making it easier to share and reuse ideas and modules of functionality across applications, with less hassle.\n\n\n<div class=\"maintainable wrapper\">\n <div class=\"background video\">\n <video tabindex=\"0\" preload=\"none\" class=\"img-responsive\" poster=\"static/img/donejs-npm-packaging-custom-elements.jpg\">\n <source src=\"static/img/donejs-npm-packaging-custom-elements-no-fade-in.mov\" type=\"video/mp4\">\n <source src=\"static/img/donejs-npm-packaging-custom-elements-no-fade-in.mp4\" type=\"video/mp4\">\n <source src=\"static/img/donejs-npm-packaging-custom-elements-no-fade-in.ogg\" type=\"video/mp4\">\n <source src=\"static/img/donejs-npm-packaging-custom-elements-no-fade-in.webm\" type=\"video/webm\">\n </video>\n </div>\n</div>\n\n#### How it works\n\nDoneJS apps use [StealJS](https://stealjs.com/) to load modules and install packages. This video introduces npm import and export in StealJS:\n\n<div class=\"youtube-container\"><div class=\"youtube-player\" data-videoid=\"eIfUsPdKF4A\"></div></div>\n\n##### Zero config package installation\n\nUnlike Browserify or Webpack, StealJS is a client side loader, so you don't have to run a build to load pages.\n\nInstalling a package in a DoneJS app via npm or bower involves no configuration. Install your package from the command line:\n\n```\nnpm install jquery --save\n```\n\nThen immediately consume that package (and its dependencies) in your app:\n\n```js\nimport $ from \"jquery\";\n```\n\nUsing require.js or other client side loaders, you'd have to add pathing and other information to your configuration file before being able to use your package. In DoneJS, this step is bypassed because of scripts that add config to your package.json file as the package is installed.\n\nYou can import that package in any format: CommonJS, AMD, or ES6 module format.\n\n##### Convert to any format\n\nDoneJS supports converting a module to any other format: CommonJS, AMD, or ES6 module format, or script and link tags.\n\nThe advantage is that you can publish your module to a wider audience of users. Anyone writing JavaScript can use your module, regardless of which script loader they are using (or if they aren't using a script loader).\n\nJust create an [export script](https://stealjs.com/docs/steal-tools.export.html) that points to the output formats you want, along with some options:\n```js\nvar stealTools = require(\"steal-tools\");\nstealTools.export({\n system: {\n config: __dirname+\"/package.json!npm\"\n },\n outputs: {\n amd: {\n format: \"amd\",\n graphs: true,\n dest: __dirname + \"/dist/amd\"\n }\n});\n```\n\nand run it from your command line:\n```\nnode myexport.js\n```\n\n##### Modular workflow\n\nIn combination with other DoneJS features, npm module import and export make it possible for teams to design and share components easily.\n\n[Generators](#generators) make it easy to bootstrap new modules of functionality quickly, and the [modlet pattern](#modlets) makes it easy to organize small, self-contained modules. It's even easy to create tests and documentation for each module.\n\nDoneJS enables a modular workflow, where pieces of small, reusable functionality can be easily created, shared, and consumed.\n\n 1. Use generators to create a modlet\n 1. Develop rich functionality\n 1. Write tests and docs\n 1. Export and publish it - internally or externally\n 1. Consume it across applications\n\nSimilar to the way that the [microservices](http://microservices.io/patterns/microservices.html) architecture encourages reuse of APIs across applications, the modular workflow encourages reuse of self-contained modules of JavaScript across applications.\n\nImagine an organization where every app is broken into many reusable pieces, each of which is independently tested, developed, and shared. Over time, developers would be able to quickly spin up new applications, reusing previous functionality. DoneJS makes this a real possibility.\n\n<a class=\"btn\" href=\"https://stealjs.com/docs/steal.html\"><span>View the Documentation</span></a>\n<a class=\"btn\" href=\"./place-my-order.html#importing-other-projects\"><span>View the Guide</span></a>\n\n_npm package support is a feature of [StealJS](https://stealjs.com/)_\n\n### ES6 Modules\n\nDoneJS supports the compact and powerful [ES6 module](http://www.2ality.com/2014/09/es6-modules-final.html) syntax, even for browsers that don't support it yet. Besides future proofing your application, writing ES6 modules makes it easier to write modular, maintainable code.\n\n````js\nimport { add, subtract } from \"math\";\n\nexport function subtract(a, b) {\n return a - b;\n}\n````\n\n#### How it works\n\nDoneJS applications are actually able to import or export any module type: ES6, AMD and CommonJS. This means you can slowly phase in ES6, while still using your old code. You can also use any of the many exciting [ES6 language features](https://github.com/lukehoban/es6features).\n\nA compiler is used to convert ES6 syntax to ES5 in browsers that don't yet support ES6. During development, the compiler runs in the browser, so changes are happening live without a build step. During the build, your code is compiled to ES5, so your production code will run natively in every browser. You can even run your [ES6 application in IE11+](#supports-all-browsers-even-ie11)!\n\n<a class=\"btn\" href=\"https://stealjs.com/docs/syntax.es6.html\"><span>View the Documentation</span></a>\n<a class=\"btn\" href=\"./place-my-order.html\"><span>View the Guide</span></a>\n\n_Pretty URLs and routing are features of the [stealjs/transpile](https://github.com/stealjs/transpile) project._\n\n### Custom HTML Elements\n\nOne of the most important concepts in DoneJS is splitting up your application functionality into independent, isolated, reusable custom HTML elements.\n\nThe major advantages of building applications based on custom HTML elements are:\n\n 1. **Ease of page composition** - Designers can do it! Non-developers can express complex behavior with little to no JavaScript required. All you need to build a new page or feature is HTML.\n 1. **Forced modularity** - Because the nature of HTML, elements are isolated modules, custom HTML elements must be designed as small, isolated components. This makes them easier to test, debug, and understand.\n 1. **Reuse** - Custom elements are designed to be reusable across pages and applications.\n\nJust like HTML's natural advantages, composing entire applications from HTML building blocks allows for powerful and easy expression of dynamic behavior.\n\n#### How it works\n\nFirst, it's important to understand the background of custom elements and their advantages. Then, we'll discuss the details of creating powerful custom elements in specifically DoneJS, and why they're special.\n\n##### Benefits of custom elements\n\nBefore custom HTML elements existed, to add a datepicker to your page, you would:\n\n 1. Load a datepicker script\n 1. Add a placeholder HTML element\n\n```html\n<div class='datepicker' />\n```\n 3. Add JavaScript code to instantiate your datepicker\n\n```js\n$('.datepicker').datepicker()\n```\n 4. Gather your stone tipped spears and forage for small animals to feed your family for the night.\n\nWith custom HTML elements, to add the same datepicker, you would:\n\n 1. Load a datepicker script\n 1. Add the datepicker to your HTML or template:\n\n```html\n<datepicker value:bind=\"date\"/>\n```\n\nThat might seem like a subtle difference, but it is actually a major step forward. The custom HTML element syntax allows for instantiation, configuration, and location, all happening at the same time.\n\nCustom HTML elements are another name for [Web Components](http://webcomponents.org/), a browser spec that has [been implemented](http://caniuse.com/#search=components) across browsers.\n\n##### Benefits of DoneJS custom elements\n\nDoneJS uses CanJS' [can-component](https://canjs.com/doc/can-component.html) to provide a modern take on web components.\n\nComponents in DoneJS have three basic building blocks:\n\n * a template\n * a viewModel object\n * event handlers\n\nThere are several unique benefits to DoneJS custom elements:\n\n * [Easily construct custom elements](#defining-a-custom-element) - you can define them within a single `.component` file, or a modlet\n * [Load data from custom elements](#data-elements--visual-elements--expressive-templates)\n * [Simple progressive loading with can-import](#in-template-dependency-declarations)\n\n##### Defining a custom element\n\nOne way to define a component is using a [DoneJS component](https://github.com/donejs/done-component) style declaration, using a single-file with a `.component` extension:\n\n```html\n<can-component tag=\"hello-world\">\n <style type=\"less\">\n i {\n color: red;\n }\n </style>\n <view>\n {{#if(this.visible)}}<b>{{this.message}}</b>{{else}}<i>Click me</i>{{/if}}\n </view>\n <script type=\"view-model\">\n import { DefineMap } from \"can\";\n\n export default DefineMap.extend({\n visible: { default: true },\n message: { default: \"Hello There!\" }\n });\n </script>\n <script type=\"events\">\n export default {\n click: function(){\n this.viewModel.visible = !this.viewModel.visible;\n }\n };\n </script>\n</can-component>\n```\n\nThis simple form of custom elements is great for quick, small widgets, since everything is contained in one place.\n\nAnother way to organize a custom element is a [modlet](#modlets) style file structure: a folder with the element broken into several independent pieces. In this pattern, the custom element's ViewModel, styles, template, event handlers, demo page, tests, and test page are all located in separate files. This type of custom element is well suited for [export and reuse](#modular-workflow).\n\nDoneJS [Generators](#generators) will create both of these types of custom elements so you can get started quickly.\n\n##### Data elements + visual elements = expressive templates\n\nThe beauty and power of custom HTML elements are most apparent when visual widgets (like graphing) is combined with elements that express data.\n\n##### Custom element libraries\n\nCustom elements are designed to be easily shareable across your organization. DoneJS provides support for simple [npm import and export](#npm-packages) and creating [documentation](#documentation) for elements. Together with custom element support, these features make it easier than ever to create reusable bits of functionality and share them.\n\nSome open source examples of DoneJS custom elements:\n\n<a class=\"btn\" href=\"https://bitovi-components.github.io/bit-c3/docs/index.html\"><span>bit-c3</span></a>\n<a class=\"btn\" href=\"https://github.com/bitovi-components/bit-tabs\"><span>bit-tabs</span></a>\n<a class=\"btn\" href=\"https://bitovi-components.github.io/bit-autocomplete/\"><span>bit-autocomplete</span></a>\n\nCheck out [their source](https://github.com/bitovi-components/bit-tabs) for good examples of shareable, documented, and tested custom elements.\n\n##### In-template dependency declarations\n\n[can-import](https://canjs.com/docs/can%7Cview%7Cstache%7Csystem.import.html) is a powerful feature that allows templates to be entirely self-sufficient. You can load custom elements, helpers, and other modules straight from a template file like:\n\n```html\n<can-import from=\"components/my_tabs\"/>\n<can-import from=\"helpers/prettyDate\"/>\n<my-tabs>\n <my-panel title=\"{{prettyDate(start)}}\">...</my-panel>\n <my-panel title=\"{{prettyDate(end)}}\">...</my-panel>\n</my-tabs>\n```\n\n<a class=\"btn\" href=\"https://canjs.com/doc/can-component.html\"><span>View the Documentation</span></a>\n<a class=\"btn\" href=\"./place-my-order.html#creating-custom-elements\"><span>View the Guide</span></a>\n\n_Custom HTML elements are a feature of [CanJS](https://canjs.com/)_\n\n### MVVM Architecture\n\nDoneJS applications employ a [Model-View-ViewModel](https://en.wikipedia.org/wiki/Model_View_ViewModel) architecture pattern, provided by [CanJS](https://canjs.com/).\n\n<img src=\"static/img/mvvm.png\" srcset=\"static/img/mvvm.png 1x, static/img/mvvm-2x.png 2x\" alt=\"MVVM Architecture Diagram\" />\n\nThe introduction of a strong ViewModel has some key advantages for maintaining large applications:\n\n * **Decouples the presentation from its business logic** - A ViewModel is essentially an object and methods representing the state of a View. This separation of concerns enables simple, dumb HTML-based Views containing minimal logic, while the ViewModel manages the complexities of application logic.\n * **Enables designer/developer cooperation** - Because the view is stripped of code and application logic, designers can safely and comfortably change the View without fear of breaking things.\n * **Enables easier [testing](#section=section_ComprehensiveTesting)** - ViewModels can be unit tested easily. Because they represent the view's state without any knowledge of the DOM, they provide a simple interface for testing.\n\n#### How it works\n\nThe following video introduces MVVM in DoneJS, focusing on the strength of the ViewModel with an example.\n\n<div class=\"youtube-container\"><div class=\"youtube-player\" data-videoid=\"kCM03jujKy4\"></div></div>\n\nDoneJS has a uniquely strong ViewModel layer compared to other frameworks. We'll discuss how it works and compares it to other frameworks.\n\n\n##### MVVM overview\n\n**Models** in DoneJS are responsible for loading data from the server. They can be reused across ViewModels. They often perform data validation and sanitization logic. Their main function is to represent data sent back from a server. Models use an intelligent set logic that enables [real-time](#real-time-connected) integration and [caching](#caching-and-minimal-data-requests) techniques.\n\n**Views** in DoneJS are templates. Specifically, templates that use handlebars syntax, but with data bindings and rewritten for better performance. Handlebars templates are designed to be logic-less.\n\n**ViewModels** will be covered in detail below.\n\n##### Independent ViewModels\n\nThe first reason DoneJS ViewModels are unique is their independence. ViewModels and Views are completely decoupled, and can be developed completely isolated from a template.\n\nFor example, here's a typical ViewModel, which is often defined in its own separate file like `viewmodel.js` and exported as its own module:\n\n```js\nexport const ViewModel = DefineMap.extend(\"FullNameViewModel\", {\n first: \"string\",\n last: \"string\",\n get fullName() {\n return this.first + \" \" + this.last;\n }\n})\n```\n\nThe template (view) lives in its own file, so a designer could easily modify it without touching any JavaScript. This template renders the ViewModel property from above:\n\n```html\n<div>{{fullName}}</div>\n```\n\nA [custom HTML element](#custom-html-elements), also known as a component, would be used to tie these layers together:\n\n```html\nimport { Component } from 'can';\nimport ViewModel from \"./viewmodel\";\nimport view from './view.stache';\n\nComponent.extend({\n tag: 'my-component',\n viewModel,\n view\n});\n```\n\nThe ViewModel is defined as its own module and exported as an ES6 module, so it can be imported into a unit test, instantiated, and tested in isolation from the DOM:\n\n```js\nimport ViewModel from \"./viewmodel\";\n\nQUnit.test('fullName works', function() {\n var vm = new ViewModel();\n vm.first = John;\n vm.last = Doe;\n QUnit.equal(vm.fullName, 'John Doe');\n});\n```\n\nIn other frameworks, ViewModels don't enjoy this level of independence. Every React class has a render function, which is essentially a template, so the View, ViewModel, and component definition are typically part of the same module. Every Angular directive is a ViewModel. In DoneJS, separating the ViewModel, template, and custom element is encouraged, making each module more decoupled and easier to unit test.\n\n##### Powerful observable data layer\n\nA powerful observable data layer binds the layers together with very minimal code.\n\nDoneJS supports the following features:\n\n1. **Direct observable objects** - changes to a property in an object or array immediately and synchronously notify any event listeners.\n\n1. **Computed properties** - ViewModels can define properties that depend on other properties, and they'll automatically recompute only when their dependent properties change.\n\n1. **Data bound templates** - templates bind to property changes and update the DOM as needed.\n\nIn the simple ViewModel example above, `fullName`'s value depends on `first` and `last`. If something in the application changes `first`, `fullName` will recompute.\n\n```js\nexport const ViewModel = DefineMap.extend({\n first: \"string\",\n last: \"string\",\n get fullName() {\n return this.first + \" \" + this.last;\n }\n});\n```\n\n`fullName` is data bound to the view that renders it:\n\n```html\n<div>{{fullName}}</div>\n```\n\nIf `first` is changed:\n\n```js\nviewModel.first = Jane;\n```\n\n`fullName` recomputes, then the DOM automatically changes to reflect the new value.\n\nThe interplay of these layers provides amazing power to developers. ViewModels express complex relationships between data, without regard to its display. Views express properties from the ViewModel, without regard to how the properties are computed. The app then comes alive with rich functionality.\n\nWithout automatic ties connecting these layers, achieving the same `fullName` functionality would require more code explicitly performing these steps. There would need to be communication between layers, removing the isolation achieved above. Any change to `first` would need to notify ViewModel's `fullName` of a change. Any change to `fullName` would need to tell the view to re-render itself. These dependencies grow and quickly lead to unmaintainable code.\n\nIn Angular, there are no direct observables. It uses dirty checking with regular JavaScript objects, which means at the end of the current $digest cycle, it will run an algorithm that determines what data has changed. This has performance drawbacks, as well as making it harder to write simple unit tests.\n\nIn React, there is no observable data layer. You could define a `fullName` like we showed above, but it would be recomputed every time `render` is called, whether or not it has changed. Though it's possible to isolate and unit test its ViewModel, it's not quite set up to make this easy.\n\n##### More information\n\nTo learn more:\n\n * Models - read about [can-connect](https://canjs.com/doc/can-connect.html) and [can-define](https://canjs.com/doc/can-define.html)\n * Computed properties - read about [can-compute](https://canjs.com/doc/can-compute.html)\n * Observable data layer - read about [DefineMap](https://canjs.com/doc/can-define/map/map.html) and [DefineList](https://canjs.com/doc/can-define/list/list.html)\n * Views - read about [can-stache](https://canjs.com/doc/can-stache.html)\n * [Create a unit tested ViewModel](./place-my-order.html#creating-a-unit-tested-view-model) in the in-depth guide\n\n_The MVVM architecture in DoneJS is provided by [CanJS](https://canjs.com/)._\n\n### Hot Module Swapping\n\nGetting and staying in [flow](https://en.wikipedia.org/wiki/Flow_(psychology)) is critical while writing complex apps. In DoneJS, whenever you change JavaScript, CSS, or a template file, the change is automatically reflected in your browser, without a browser refresh.\n\n<div class=\"maintainable wrapper\">\n <div class=\"background video\">\n <video tabindex=\"0\" preload=\"none\" class=\"img-responsive\" poster=\"static/img/donejs-live-reload.jpg\">\n <source src=\"static/img/donejs-live-reload-no-fade-in.mov\" type=\"video/mp4\">\n <source src=\"static/img/donejs-live-reload-no-fade-in.mp4\" type=\"video/mp4\">\n <source src=\"static/img/donejs-live-reload-no-fade-in.ogg\" type=\"video/mp4\">\n <source src=\"static/img/donejs-live-reload-no-fade-in.webm\" type=\"video/webm\">\n </video>\n </div>\n</div>\n\n#### How it works\n\nLive reload servers generally watch for file changes and force your browser window to refresh. DoneJS doesn’t refresh the page, it re-imports modules that are marked as dirty, in real-time.\n\nThe correct terminology is actually [hot swapping](https://en.wikipedia.org/wiki/Hot_swapping), not live reload. Regardless of what it's called, the result is a blazing fast development experience.\n\nThere is no configuration needed to enable this feature. Just start the dev server and begin:\n\n```\ndonejs develop\n```\n\n<blockquote class=\"fun-quotes\">\n <div class=\"fun-intro\">You spend less time waiting for refreshes and builds,</div>\n <div class=\"fun-link\">...and more time <a href=\"javascript:void(0)\" data-toggle=\"popover\" data-placement=\"top\" data-html=\"true\" data-content='<div class=\"youtube-container\"><div class=\"youtube-player\" data-videoid=\"LbVZs80WMWI\"></div></div>'>doing trust falls with giant yellow M&Ms.</a></div>\n <img class=\"fun-img\" src=\"static/img/funny-mandm.png\">\n</blockquote>\n\n<a class=\"btn\" href=\"https://stealjs.com/docs/steal.live-reload.html\"><span>View the Documentation</span></a>\n\n_Live reload is a feature of [StealJS](https://stealjs.com/)._\n\n\n### Generators\n\nDoneJS generators help you kickstart new projects and components. They'll save you time, eliminating boilerplate by scaffolding a working project, component, or module.\n\nGenerator templates set up many of the best practices and features discussed in the rest of this page, without you even realizing it.\n\n#### How it works\n\nThe DoneJS generator uses Yeoman to bootstrap your application, component, or model.\n\nThere are four generators by default (and you can easily create your own).\n\n##### Project generator\n\nFrom the command line, run:\n\n```\ndonejs add app\n```\n\nYou'll be prompted for a project name, source folder, and other setup information. DoneJS' project dependencies will be installed, like StealJS and CanJS. In the folder that was created, you'll see:\n\n```\n├── .yo-rc.json\n├── build.js\n├── development.html\n├── package.json\n├── production.html\n├── readme.md\n├── test.html\n├── src/\n| ├── app.js\n| ├── index.stache\n| ├── models/\n| | ├── fixtures\n| | | ├── fixtures.js\n| | ├── test.js\n| ├── styles.less\n| ├── test.js\n├── node_modules/\n```\n\nYou're now a command away from running application wide tests, generating documentation, and running a build. Start your server with `donejs develop`, open your browser, and you'll see a functioning, server-side rendered hello world page.\n\n##### Modlet component generator\n\nTo create a [component](https://canjs.com/doc/can-component.html) organized with the [modlet](#modlets) file organization pattern:\n\n```\ndonejs add component <folder-path> <component-name>\n```\n\nIt will create the following files:\n\n\n```\nrestaurant/\n├── list/\n| ├── list.html\n| ├── list.js\n| ├── list.less\n| ├── list.md\n| ├── list.stache\n| ├── list_test.js\n| ├── test.html\n```\n\nThis folder contains everything a properly maintained component needs: a working demo page, a basic test, and documentation placeholder markdown file.\n\n##### Simple component generator\n\nFor simple, standalone components:\n\n```\ndonejs add component <file-name>.component <component-name>\n```\n\nWhich will generate a working component in a single file.\n\n##### Model generator\n\nTo create a new [model](https://canjs.com/doc/can-super-model.html):\n\n```\ndonejs add supermodel <model-name>\n```\n\nThis will create:\n\n - a working model in the application's `models` folder\n - a working fixture file for that model\n - a working test, and add the test as a dependency for the application's model test\n\n<blockquote class=\"fun-quotes\">\n <div class=\"fun-intro\">You spend less time setting up your app,</div>\n <div class=\"fun-link\">...and more time <a href=\"javascript:void(0)\" data-toggle=\"popover\" data-placement=\"top\" data-html=\"true\" data-content='<div class=\"youtube-container\"><div class=\"youtube-player\" data-videoid=\"xiE5AQHKj_Y\" data-params=\"start=26\"></div></div>'>searching for carrots.</a></div>\n <img class=\"fun-img\" src=\"static/img/funny-carrots.png\">\n</blockquote>\n\n<a class=\"btn\" href=\"https://github.com/donejs/generator-donejs\"><span>View the Documentation</span></a>\n<a class=\"btn\" href=\"./Guide.html#generate-the-application\"><span>View the Guide</span></a>\n\n_Generators are provided by the [Generator DoneJS](https://github.com/donejs/generator-donejs) project with additional support via the [donejs-cli](https://github.com/donejs/cli) project_\n\n",
"description": " \nLearn about the features that will help you get your app done.\n\n### All-in-one stack\n\nDoneJS offers everything you need to build a modern web app. It comes with a module loader, build system, MVVM utilities, full testing layer, documentation generator, server side rendering utilities, a data layer, and more. Its completeness is itself a feature.\n\nThere's no mixing and matching pieces of your stack. Just `npm install` and get started.\n\nChoosing a modern stack is not at all simple or straightforward.\n\n1. *What types of tools do you want?* Server-side rendering? What is a virtual DOM? Do I need one? MVVM or Flux? Should I set up testing infrastructure? Documentation?\n\n2. *Choose all your pieces.* The good news is, you have [many choices](http://microjs.com/#). The bad news is, you have many choices. React, Angular, or Vue? WebPack, rollup, or parcel? Mocha or QUnit? What tool will run my tests?\n\n3. *Finally, you have to make sure your chosen tools work together effectively.* Does parcel work well with Angular? Does Karma work with Browserify? What about React and Babel?\n\nDoneJS gives you a full solution. It's our mission to eliminate any ambiguity around choosing technology for building an app, so you spend less time tinkering with your stack, and more time actually building your app.\n\nAnd as we've proven [over the last 8 years](./About.html#evolve), we'll keep updating the stack as the state of the art evolves over time.\n\n### Integrated layers\n\nJust like Apple integrates the hardware and software for its devices, DoneJS integrates different technologies in a way that creates unique advantages that you can only get from using an integrated solution.\n\n#### Cross-layer features\n\nDoneJS makes it easier to do things that are not possible, or at best DIY, with competitor frameworks, by spanning technology layers. Here are a couple examples:\n\n##### 1. [Server-side rendering](#server-side-rendered)\n\nServer-side rendering (SSR), which you can read about in more detail in its [section](#server-side-rendered) below, spans many layers to make setup and integration simple.\n\nIt uses [zones](https://davidwalsh.name/can-zone) to automatically notify the server to delay rendering, [hot module swapping](#hot-module-swapping) automatically integrates (no need to restart the server while developing), data is cached on the server and pushed to the client (http/2 server [PUSH](https://www.smashingmagazine.com/2017/04/guide-http2-server-push/) or [Preload Links](https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content) for http/1.1) automatically and used to prevent duplicate AJAX requests. Support for these features is only possible because of code that spans layers, including can-zone, done-ssr, CanJS, and StealJS.\n\nBy contrast, React supports SSR, but you're left to your own devices to support delaying rendering, hot module swapping, and request reuse.\n\n##### 2. [Progressive enhancement](#how-it-works-1)\n\nParts of your application can be progressively loaded using [steal.import](https://stealjs.com/docs/steal.import.html):\n\n```js\nimport { DefineMap } from \"can\";\n\nexport default DefineMap.extend(\"AppViewModel\", {\n page: \"string\",\n get pageComponent() {\n let moduleName = `~/pages/${this.page}/`;\n let Component = (await steal.import(moduleName)).default;\n return new Component();\n }\n})\n```\n\nand then running `donejs build`.\n\nDoneJS' generators define anything within `~/pages` to be split into bundles. This feature spans StealJS, steal-tools, and donejs-cli.\n\n#### Story-level solutions\n\nAnother advantage of the integration between DoneJS' parts is the ability to solve development problems on the level of [**stories**](http://searchsoftwarequality.techtarget.com/definition/user-story) rather than just features.\n\nSolving a story means a packaged solution to a development problem, where several features across layers converge to solve the problem from start to finish. Here are several examples of stories that DoneJS solves:\n\n1. [Modular workflow](#modular-workflow) - DoneJS makes it possible for teams to design and share components easily. Starting with [generators](#generators), users can create [modlets](#modlets) that encapsulate everything a [custom element](#custom-html-elements) needs, easily add [documentation](#documentation) and [testing](#comprehensive-testing), then use [npm import and export](#npm-packages) to easily share the modules with other developers, no matter what module format they're using.\n\n2. [Performance](#performance-features) - DoneJS was designed from the start to solve the performance story, packaging [server-side rendering](#server-side-rendered), [progressive loading](#progressive-loading), [worker thread rendering](#worker-thread-rendering), [data layer caching](#caching-and-minimal-data-requests), and more, all under one roof.\n\n3. [Maintainability](#maintainability-features) - [testing](#comprehensive-testing), [docs](#documentation), [MVVM](#mvvm-architecture)\n\n4. Developer efficiency - [zero-config npm imports](#npm-packages), [hot module swapping](#hot-module-swapping), [ES6 support](#es6-modules)\n\n### Feature comparison\n\n<div class=\"matrix-wrapper\">\n <div class=\"matrix-legend\" id=\"js-matrix-legend-affix\">\n <div class=\"title\">SOLUTION LEGEND</div>\n <ul>\n <li>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-excellent.svg\">\n <div>EASY</div>\n </li>\n <li>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-very-good.svg\">\n <div>GOOD</div>\n </li>\n <li>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-good.svg\">\n <div>DIFFICULT</div>\n </li>\n <li>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-fair.svg\">\n <div>THIRD-PARTY</div>\n </li>\n <li>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-poor.svg\">\n <div>NO</div>\n </li>\n </ul>\n </div>\n <div class=\"table-wrapper\">\n <div class=\"scrollable\">\n <table id=\"js-matrix-table-affix\" class=\"matrix-table responsive\">\n <thead>\n <tr>\n <th class=\"features\">FEATURES</th>\n <th><img class=\"framework-logo\" src=\"static/img/donejs-logo-matrix.png\"></th>\n <th><img class=\"framework-logo\" src=\"static/img/angular-logo.png\"></th>\n <th><img class=\"framework-logo\" src=\"static/img/react-logo.png\"></th>\n </tr>\n </thead>\n <tbody>\n <tr>\n <td class=\"features\">\n <div class=\"feature-description\"><a href=\"#server-side-rendered\">Server-Side Rendering</a></div>\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-excellent.svg\">\n </td>\n <td>\n <div class=\"has-popover\" data-toggle=\"popover\" data-placement=\"bottom\" data-html=\"true\" data-content=\"Requires some <a href='https://universal.angular.io/' target='_blank'>manual setup</a>.\" title=\"Requires some <a href='https://universal.angular.io/' target='_blank'>manual setup</a>.\">\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-very-good.svg\"><span class=\"asterisk\"></span>\n </div>\n </td>\n <td>\n <div class=\"has-popover\" data-container=\"matrix-wrapper\" data-toggle=\"popover\" data-placement=\"bottom\" data-html=\"true\" data-content=\"Requires some <a href='https://reactjsnews.com/isomorphic-javascript-with-react-node' target='_blank'>manual setup</a> and lacks most of the features/support DoneJS has.\" title=\"Requires some manual setup and lacks most of the features/support DoneJS has.\">\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-fair.svg\"><span class=\"asterisk\"></span>\n </div>\n </td>\n </tr>\n <tr>\n <td class=\"features\">\n <div class=\"feature-description\"><a href=\"#progressive-loading\">Progressive Dependency Loading</a></div>\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-excellent.svg\">\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-poor.svg\">\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-very-good.svg\">\n </td>\n </tr>\n <tr>\n <td class=\"features\">\n <div class=\"feature-description\"><a href=\"#caching-and-minimal-data-requests\">Caching & Minimal Data Requests</a></div>\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-excellent.svg\">\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-good.svg\">\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-poor.svg\">\n </td>\n </tr>\n <tr>\n <td class=\"features\">\n <div class=\"feature-description\"><a href=\"#minimal-dom-updates\">Minimal DOM Updates</a></div>\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-very-good.svg\">\n </td>\n <td>\n <div class=\"has-popover\" data-toggle=\"popover\" data-placement=\"bottom\" data-html=\"true\" data-content=\"Updates DOM quickly, but only after expensive dirty check calculation.\" title=\"Updates DOM quickly, but only after expensive dirty check calculation.\">\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-good.svg\"><span class=\"asterisk\"></span>\n </div>\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-excellent.svg\">\n </td>\n </tr>\n <tr>\n <td class=\"features\">\n <div class=\"feature-description\"><a href=\"#worker-thread-rendering\">Worker Thread Rendering</a></div>\n </td>\n <td>\n <div data-toggle=\"popover\" data-placement=\"bottom\" data-html=\"true\" data-content=\"Previously well supported but hasn't been updated in a few versions.\" title=\"Previously well supported but hasn't been updated in a few versions.\">\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-good.svg\"><span class=\"asterisk\"></span>\n </div>\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-good.svg\">\n </td>\n <td>\n <div class=\"has-popover\" data-toggle=\"popover\" data-placement=\"bottom\" data-html=\"true\" data-content=\"There is a virtual dom. So, Its possible, but there is no support out of the box.\" title=\"There is a virtual dom. So, Its possible, but there is no support out of the box.\">\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-good.svg\"><span class=\"asterisk\"></span>\n </div>\n </td>\n </tr>\n <tr>\n <td class=\"features\">\n <div class=\"feature-description\"><a href=\"#deploy-to-a-cdn\">Deploy to a CDN</a></div>\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-excellent.svg\">\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-fair.svg\">\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-fair.svg\">\n </td>\n </tr>\n <tr>\n <td class=\"features\">\n <div class=\"feature-description\"><a href=\"#ios-android-and-desktop-builds\">iOS, Android, and Desktop Builds</a></div>\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-excellent.svg\">\n </td>\n <td>\n <div class=\"has-popover\" data-toggle=\"popover\" data-placement=\"bottom\" data-html=\"true\" data-content=\"While native app builds are possible, it requires the use of NativeScript.\" title=\"While native app builds are possible, it requires the use of NativeScript.\">\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-good.svg\"><span class=\"asterisk\"></span>\n </div>\n </td>\n <td>\n <div class=\"has-popover\" data-toggle=\"popover\" data-placement=\"bottom\" data-html=\"true\" data-content=\"While native app builds are possible, there's no infrastructure to make it easy.\" title=\"While native app builds are possible, there's no infrastructure to make it easy.\">\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-good.svg\"><span class=\"asterisk\"></span>\n </div>\n </td>\n </tr>\n <tr>\n <td class=\"features\">\n <div class=\"feature-description\"><a href=\"#supports-all-browsers-even-ie11\">Browser Support</a></div>\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-excellent.svg\">\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-excellent.svg\">\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-excellent.svg\">\n </td>\n </tr>\n <tr>\n <td class=\"features\">\n <div class=\"feature-description\"><a href=\"#real-time-connected\">Real-Time</a></div>\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-excellent.svg\">\n </td>\n <td>\n <div class=\"has-popover\" data-toggle=\"popover\" data-placement=\"bottom\" data-html=\"true\" data-content=\"While connecting to real time data is possible, there is no built in support to make it easy.\" title=\"While connecting to real time data is possible, there is no built in support to make it easy.\">\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-poor.svg\"><span class=\"asterisk\"></span>\n </div>\n </td>\n <td>\n <div class=\"has-popover\" data-toggle=\"popover\" data-placement=\"bottom\" data-html=\"true\" data-content=\"While connecting to real time data is possible, there is no built in support to make it easy.\" title=\"While connecting to real time data is possible, there is no built in support to make it easy.\">\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-poor.svg\"><span class=\"asterisk\"></span>\n </div>\n </td>\n </tr>\n <tr>\n <td class=\"features\">\n <div class=\"feature-description\"><a href=\"#pretty-urls-with-pushstate\">Pretty URLs</a></div>\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-excellent.svg\">\n </td>\n <td>\n <div class=\"has-popover\" data-toggle=\"popover\" data-placement=\"bottom\" data-html=\"true\" data-content=\"Built-in routing is difficult to configure and maintain.\" title=\"Built-in routing is difficult to configure and maintain.\">\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-very-good.svg\"><span class=\"asterisk\"></span>\n </div>\n </td>\n <td>\n <div class=\"has-popover\" data-toggle=\"popover\" data-placement=\"bottom\" data-html=\"true\" data-content=\"React-router supports this, but is not part of the core library.\" title=\"React-router supports this, but is not part of the core library.\">\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-fair.svg\"><span class=\"asterisk\"></span>\n </div>\n </td>\n </tr>\n <tr>\n <td class=\"features\">\n <div class=\"feature-description\"><a href=\"#comprehensive-testing\">Comprehensive Testing</a></div>\n </td>\n <td>\n <div class=\"has-popover\" data-toggle=\"popover\" data-placement=\"bottom\" data-html=\"true\" data-content=\"Includes built-in support for every part of the testing lifecycle\" title=\"Includes built-in support for every part of the testing lifecycle\">\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-excellent.svg\"><span class=\"asterisk\"></span>\n </div>\n </td>\n <td>\n <div class=\"has-popover\" data-toggle=\"popover\" data-placement=\"bottom\" data-html=\"true\" data-content=\"Supports dependency injection and end-to-end testing.\" title=\"Supports dependency injection and end-to-end testing.\">\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-very-good.svg\"><span class=\"asterisk\"></span>\n </div>\n </td>\n <td>\n <div class=\"has-popover\" data-toggle=\"popover\" data-placement=\"bottom\" data-html=\"true\" data-content=\"Includes some basic test utilities and mocks, but no support for other parts of the testing lifecycle.\" title=\"Includes some basic test utilities and mocks, but no support for other parts of the testing lifecycle.\">\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-good.svg\">\n <span class=\"asterisk\"></span>\n </div>\n </td>\n </tr>\n <tr>\n <td class=\"features\">\n <div class=\"feature-description\"><a href=\"#documentation\">Documentation</a></div>\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-excellent.svg\">\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-very-good.svg\">\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-poor.svg\">\n </td>\n </tr>\n <tr>\n <td class=\"features\">\n <div class=\"feature-description\"><a href=\"#continuous-integration--deployment\">Continuous Integration & Deployment</a></div>\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-excellent.svg\">\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-fair.svg\">\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-fair.svg\">\n </td>\n </tr>\n <tr>\n <td class=\"features\">\n <div class=\"feature-description\"><a href=\"#npm-packages\">npm Packages - Imports & Exports</a></div>\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-excellent.svg\">\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-very-good.svg\">\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-very-good.svg\">\n </td>\n </tr>\n <tr>\n <td class=\"features\">\n <div class=\"feature-description\"><a href=\"#es6-modules\">ES6 modules</a></div>\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-excellent.svg\">\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-very-good.svg\"><span class=\"asterisk\"></span>\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-very-good.svg\"><span class=\"asterisk\"></span>\n </td>\n </tr>\n <tr>\n <td class=\"features\">\n <div class=\"feature-description\"><a href=\"#custom-html-elements\">Custom HTML Elements</a></div>\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-excellent.svg\">\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-excellent.svg\">\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-fair.svg\">\n </td>\n </tr>\n <tr>\n <td class=\"features\">\n <div class=\"feature-description\"><a href=\"#mvvm-architecture\">MVVM Architecture</a></div>\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-excellent.svg\">\n </td>\n <td>\n <div class=\"has-popover\" data-toggle=\"popover\" data-placement=\"top\" data-html=\"true\" data-content=\"Not explicitly MVVM, but could be implemented\" title=\"Not explicitly MVVM, but could be implemented\">\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-very-good.svg\"><span class=\"asterisk\"></span>\n </div>\n </td>\n <td>\n <div class=\"has-popover\" data-toggle=\"popover\" data-placement=\"top\" data-html=\"true\" data-content=\"React is just the view layer. You'll need to implement your own MVVM architecture.\" title=\"React is just the view layer. You'll need to implement your own MVVM architecture.\">\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-good.svg\"><span class=\"asterisk\"></span>\n </div>\n </td>\n </tr>\n <tr>\n <td class=\"features\">\n <div class=\"feature-description\"><a href=\"#hot-module-swapping\">Hot Module Swapping</a></div>\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-excellent.svg\">\n </td>\n <td>\n <div class=\"has-popover\" data-toggle=\"popover\" data-placement=\"top\" data-html=\"true\" data-content=\"Third-party libraries available for some support.\" title=\"Third-party libraries available for some support.\">\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-fair.svg\"><span class=\"asterisk\"></span>\n </div>\n </td>\n <td>\n <div class=\"has-popover\" data-toggle=\"popover\" data-placement=\"top\" data-html=\"true\" data-content=\"Third-party libraries available for some support.\" title=\"Third-party libraries available for some support.\">\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-fair.svg\"><span class=\"asterisk\"></span>\n </div>\n </td>\n </tr>\n <tr>\n <td class=\"features\">\n <div class=\"feature-description\"><a href=\"#generators\">Generators</a></div>\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-excellent.svg\">\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-fair.svg\">\n </td>\n <td>\n <img class=\"matrix-rating-icon\" src=\"static/img/icon-fair.svg\">\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n </div>\n</div>\n\n",
"name": "Features",
"type": "page",
"parent": "DoneJS",
"hideSidebar": true,
"outline": {
"depth": 2,
"tag": "ol"
},
"comment": " "
},
"donejs": {
"body": "<div class=\"container-fluid\">\n <div class=\"row\">\n <div class=\"hero clearfix\">\n <div class=\"transparency clearfix\">\n <div class=\"lead-in\">\n <a class=\"est2007Logo\" href=\"./About.html#evolve\">\n <img src=\"./static/img/est-2007-01.svg\" alt=\"Est. 2007\">\n </a>\n <h1 class=\"heavy\">Your App. Done.</h1>\n <h3 class=\"lead\"><span class=\"heavy\">DoneJS</span> is an open source JavaScript framework that makes it easy to build high performance, real-time web and mobile applications.</h3>\n <div class=\"overview-nav hidden-sm hidden-md hidden-lg\">\n <a href=\"#usability\" class=\"overview-btn usability-btn\">\n <span class=\"light\">Improved App </span><span class=\"heavy\">Usability</span>\n </a>\n <a href=\"#performance\" class=\"overview-btn performance-btn\">\n <span class=\"light\">Better </span><span class=\"heavy\">Performance</span>\n </a>\n <a href=\"#maintainable\" class=\"overview-btn maintainable-btn\">\n <span class=\"light\">More </span><span class=\"heavy\">Maintainable</span>\n </a>\n </div>\n <div class=\"install hidden-sm hidden-md hidden-lg\">\n <div class=\"col-xs-12 guide\">\n <div class=\"social\">\n <a href=\"https://twitter.com/donejs\" class=\"twitter-follow-button\" data-show-count=\"true\" data-dnt=\"true\" data-show-screen-name=\"false\">Follow @donejs</a>\n <iframe height=\"20px\" class=\"ghbtns\" src=\"https://ghbtns.com/github-btn.html?user=donejs&repo=donejs&type=watch&count=true\" allowtransparency=\"true\" frameborder=\"0\" scrolling=\"0\"></iframe>\n </div>\n </div>\n <div class=\"col-xs-12 install-donejs\">\n <p class=\"caption\">Ready to install DoneJS?</p>\n <textarea>npm install -g donejs donejs add app my-app</textarea>\n <p><a class=\"btn\" href=\"Guide.html\" role=\"button\">Get Started</a></p>\n\n </div>\n </div>\n <div class=\"install hidden-xs\">\n <div class=\"col-xs-12 col-sm-6 install-donejs\">\n <p class=\"caption\">Ready to install DoneJS?</p>\n <textarea>npm install -g donejs donejs add app my-app</textarea>\n </div>\n <div class=\"col-xs-12 col-sm-6 guide\">\n <p><a class=\"btn\" href=\"Guide.html\" role=\"button\">Get Started</a></p>\n <div class=\"social\">\n <a href=\"https://twitter.com/donejs\" class=\"twitter-follow-button\" data-show-count=\"true\" data-dnt=\"true\" data-show-screen-name=\"false\">Follow @donejs</a>\n <iframe height=\"20px\" class=\"ghbtns\" src=\"https://ghbtns.com/github-btn.html?user=donejs&repo=donejs&type=watch&count=true\" allowtransparency=\"true\" frameborder=\"0\" scrolling=\"0\"></iframe>\n </div>\n </div>\n </div>\n </div>\n <div class=\"triptych hidden-xs\">\n <div class=\"col-xs-12 col-sm-4 box usability\" data-scrollto=\"#usability\">\n <h2><span class=\"light\">Improved App</span><br>Usability</h2>\n <p>\n <a href=\"./Features.html#ios-android-and-desktop-builds\">iOS, Android, and Desktop Builds</a>;\n <a href=\"./Features.html#supports-all-browsers-even-ie11\">Supports All Browsers, even IE11+</a>;\n <a href=\"./Features.html#real-time-connected\">Real time Connected</a>;\n <a href=\"./Features.html#pretty-urls-with-pushstate\">Pretty URL’s with Pushstate</a>\n </p>\n </div>\n <div class=\"col-xs-12 col-sm-4 box performance\" data-scrollto=\"#performance\">\n <h2><span class=\"light\">Better</span><br>Performance</h2>\n <p>\n <a href=\"./Features.html#server-side-rendered\">Server Side Rendered (Isomorphic)</a>;\n <a href=\"./Features.html#progressive-loading\">Progressive Loading </a>;\n <a href=\"./Features.html#caching-and-minimal-data-requests\">Minimal Data Requests</a>;\n <a href=\"./Features.html#minimal-dom-updates\">Minimal DOM Updates</a>;\n <a href=\"./Features.html#worker-thread-rendering\">Worker Thread Rendering</a>;\n <a href=\"./Features.html#deploy-to-a-cdn\">Deploy to a CDN</a>\n </p>\n </div>\n <div class=\"col-xs-12 col-sm-4 box maintainable\" data-scrollto=\"#maintainable\">\n <h2><span class=\"light\">More</span><br>Maintainable</h2>\n <p>\n <a href=\"./Features.html#comprehensive-testing\">Comprehensive Testing</a>;\n <a href=\"./Features.html#documentation\">Documentation</a>;\n <a href=\"./Features.html#continuous-integration--deployment\">Continuous Integration & Deployment</a>;\n <a href=\"./Features.html#npm-packages\">npm Packages</a>;\n <a href=\"./Features.html#es6-modules\">ES6 Modules</a>;\n <a href=\"./Features.html#modlets\">Modlets</a>;\n <a href=\"./Features.html#custom-html-elements\">Custom HTML Elements</a>;\n <a href=\"./Features.html#mvvm-architecture\">MVVM Architecture</a>;\n <a href=\"./Features.html#hot-module-swapping\">Hot Module Swapping</a>;\n <a href=\"./Features.html#generators\">Generators</a>\n </p>\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"usability wrapper\">\n <div class=\"lead-in\">\n <a id=\"usability\" style=\"vertical-align: top;\"></a>\n <h1><span class=\"light\">Improved App</span> <span class=\"heavy\">Usability</span></h1>\n <h3 class=\"lead\"><span class=\"bold\">DoneJS</span><span class=\"normal\"> is used to make beautiful, real-time user interfaces that can be exported to run on every platform.</span></h3>\n <h3 class=\"heavy\">Take our example app for a spin:</h3>\n <div class=\"spacer\"></div>\n <div class=\"usability-row\">\n <div class=\"col-xs-6 col-sm-3\">\n <div class=\"phase ios\">\n <img src=\"./static/img/thumb-ios.svg\">\n <a class=\"btn\" href=\"https://github.com/donejs/place-my-order/wiki/Deploying-to-iOS-for-testing\" role=\"button\">\n iOS\n <span class=\"img-wrap\">\n <img src=\"./static/img/donejs-final_arrow-icon_2.svg\">\n </span>\n </a>\n </div>\n </div>\n <div class=\"col-xs-6 col-sm-3\">\n <div class=\"phase android\">\n <img src=\"./static/img/thumb-android.svg\">\n <a class=\"btn\" href=\"https://github.com/donejs/place-my-order/releases/download/v0.2.0/android-release-unsigned.apk\" role=\"button\">\n Android\n <span class=\"img-wrap\">\n <img src=\"./static/img/donejs-final_arrow-icon_2.svg\">\n </span>\n </a>\n </div>\n </div>\n <div class=\"col-xs-6 col-sm-3\">\n <!-- be careful of JS classes here. -->\n <div class=\"phase desktop\">\n <img src=\"./static/img/thumb-desktop.svg\">\n <a class=\"btn\" href=\"#\" onclick=\"return false;\" role=\"button\">\n Desktop\n <span class=\"img-wrap\">\n <img src=\"./static/img/donejs-final_arrow-icon_2.svg\">\n </span>\n </a>\n <div class=\"usability-dl-options\">\n <a href=\"https://github.com/donejs/place-my-order/releases/download/v0.2.0/place-my-order-osx64.zip\">\n OSX\n </a>\n <a href=\"https://github.com/donejs/place-my-order/releases/download/v0.2.0/place-my-order-win64.zip\">\n Windows 64bit\n </a>\n <a href=\"https://github.com/donejs/place-my-order/releases/download/v0.2.0/place-my-order-win32.zip\">\n Windows 32bit\n </a>\n </div>\n </div>\n </div>\n <div class=\"col-xs-6 col-sm-3\">\n <div class=\"phase ontheweb\">\n <img src=\"./static/img/thumb-on-the-web.svg\">\n <a class=\"btn\" href=\"http://www.place-my-order.com/\" role=\"button\">\n On the Web\n <span class=\"img-wrap\">\n <img src=\"./static/img/donejs-final_arrow-icon_2.svg\">\n </span>\n </a>\n </div>\n </div>\n </div>\n <h3 class=\"light learn\">Learn how to build this in our <a href=\"./place-my-order.html\">in-depth guide!</a></h3>\n <h2 class=\"heavy better\">More ways DoneJS is better for users:</h2>\n <p class=\"trail\">\n <a href=\"./Features.html#ios-android-and-desktop-builds\">iOS, Android, and Desktop Builds</a><span class=\"pipe-spacer\"> | </span>\n <a href=\"./Features.html#supports-all-browsers-even-ie11\">Supports All Browsers, even IE11+</a><span class=\"pipe-spacer\"> | </span>\n <a href=\"./Features.html#real-time-connected\">Real Time Connected</a><span class=\"pipe-spacer\"> | </span>\n <a href=\"./Features.html#pretty-urls-with-pushstate\">Pretty URL’s with Pushstate</a>\n </p>\n </div>\n </div>\n\n <div class=\"performance wrapper col-xs-12\">\n <a id=\"performance\" style=\"vertical-align: top;\"></a>\n <div class=\"lead-in hidden-md hidden-lg\">\n <div class=\"title-padding\">\n <h1><span class=\"light\">Better</span> <span class=\"heavy\">Performance</span></h1>\n <h3 class=\"lead\"><span class=\"bold\">DoneJS</span> is configured for maximum performance right out of the box.</h3>\n <h3 class=\"heavy\">Scroll the graph to see how it works:</h3>\n </div>\n <div class=\"spacer\"></div>\n </div>\n <div class=\"mobile-graph hidden-md hidden-lg\">\n <div class=\"graph-logos\">\n <img src=\"./static/img/donejs-mobile-guide-logos.png\" srcset=\"./static/img/donejs-mobile-guide-logos.png 1x, ./static/img/donejs-mobile-guide-logos-2x.png 2x\">\n </div>\n <div class=\"graph-timeline-wrapper\">\n <div class=\"graph-timeline\">\n <img src=\"./static/img/donejs-mobile-guide-timeline.gif\" srcset=\"./static/img/donejs-mobile-guide-timeline.gif 1x, ./static/img/donejs-mobile-guide-timeline-2x.gif 2x\">\n </div>\n </div>\n </div>\n <div class=\"performance-mobile-trail col-xs-12 hidden-md hidden-lg\">\n <h2 class=\"heavy\">More ways DoneJS improves app performance:</h2>\n <p class=\"trail\">\n <a href=\"./Features.html#server-side-rendered\">Server Side Rendered (Isomorphic)</a><span class=\"pipe-spacer\"> | </span>\n <a href=\"./Features.html#progressive-loading\">Progressive Loading</a><span class=\"pipe-spacer\"> | </span>\n <a href=\"./Features.html#caching-and-minimal-data-requests\">Minimal Data Requests</a><span class=\"pipe-spacer\"> | </span>\n <a href=\"./Features.html#minimal-dom-updates\">Minimal DOM Updates</a><span class=\"pipe-spacer\"> | </span>\n <a href=\"./Features.html#worker-thread-rendering\">Worker Thread Rendering</a><span class=\"pipe-spacer\"> | </span>\n <a href=\"./Features.html#deploy-to-a-cdn\">Deploy to a CDN</a>\n </p>\n </div>\n <div class=\"hidden-xs hidden-sm\">\n <div class=\"lead-in\">\n <div class=\"title-padding\">\n <h1><span class=\"light\">Better</span> <span class=\"heavy\">Performance</span></h1>\n <h3 class=\"lead\"><span class=\"bold\">DoneJS</span> is configured for maximum performance right out of the box.</h3>\n <h3 class=\"heavy\">Hover over the graph to see how it works:</h3>\n </div>\n <div class=\"spacer\"></div>\n </div>\n <div class=\"graph\">\n <div class=\"performance-row\">\n <div class=\"col donejs\">\n <div class=\"svg-links\">\n <a id=\"ssr\" href=\"./Features.html#server-side-rendered\" title=\"Learn about DoneJS's server side rendering.\"></a>\n <a id=\"inlineCache\" href=\"./Features.html#caching-and-minimal-data-requests\" title=\"Learn about inline caches.\"></a>\n <a id=\"progressiveLoading\" href=\"./Features.html#progressive-loading\" title=\"See how progressive loading works.\"></a>\n <a id=\"cdn\" href=\"./Features.html#deploy-to-a-cdn\" title=\"Learn about CDN deployment.\"></a>\n </div>\n <img class=\"donejs-text\" src=\"./static/img/donejs-final_Graph_1.svg\">\n <img class=\"donejs-thumbs\" src=\"./static/img/donejs-final_Graph_2.svg\">\n </div>\n <div class=\"col naive\">\n <img class=\"naive-thumbs\" src=\"./static/img/donejs-final_Graph_3.svg\">\n <img class=\"naive-text\" src=\"./static/img/donejs-final_Graph_4.svg\">\n </div>\n </div>\n </div>\n <h2 class=\"heavy\">More ways DoneJS improves app performance:</h2>\n <p class=\"trail\">\n <a href=\"./Features.html#server-side-rendered\">Server Side Rendered (Isomorphic)</a><span class=\"pipe-spacer\"> | </span>\n <a href=\"./Features.html#progressive-loading\">Progressive Loading</a><span class=\"pipe-spacer\"> | </span>\n <a href=\"./Features.html#caching-and-minimal-data-requests\">Minimal Data Requests</a><span class=\"pipe-spacer\"> | </span>\n <a href=\"./Features.html#minimal-dom-updates\">Minimal DOM Updates</a><span class=\"pipe-spacer\"> | </span>\n <a href=\"./Features.html#worker-thread-rendering\">Worker Thread Rendering</a><span class=\"pipe-spacer\"> | </span>\n <a href=\"./Features.html#deploy-to-a-cdn\">Deploy to a CDN</a>\n </p>\n </div>\n </div>\n\n <div class=\"maintainable wrapper\">\n <div class=\"lead-in\">\n <a id=\"maintainable\"></a>\n <h1><span class=\"light\">More</span> <span class=\"heavy\">Maintainable</span></h1>\n <h3 class=\"lead\"><span class=\"bold\">DoneJS</span> helps developers get things done quickly with an eye toward maintenance.</h3>\n <div class=\"maintain-blocks\">\n <div class=\"col-xs-12 col-sm-6 background video\">\n <video tabindex=\"0\" preload=\"none\" poster=\"./static/img/mvvm-reactive.jpg\" class=\"img-responsive\">\n <source src=\"./static/img/donejs-mvvm-movie.mov\" type=\"video/mp4\">\n <source src=\"./static/img/donejs-mvvm-movie.mp4\" type=\"video/mp4\">\n <source src=\"./static/img/donejs-mvvm-movie.ogg\" type=\"video/mp4\">\n <source src=\"./static/img/donejs-mvvm-movie.webm\" type=\"video/webm\">\n </video>\n <div class=\"caption\">\n <h2 class=\"heavy\">MVVM Architecture</h2>\n <p>DoneJS applications are architecturally Model-View-ViewModel, with a uniquely powerful and isolated ViewModel.</p>\n <a href=\"./Features.html#mvvm-architecture\" class=\"btn\">Learn More</a>\n </div>\n </div>\n <div class=\"col-xs-12 col-sm-6 background video\">\n <video tabindex=\"0\" preload=\"none\" poster=\"./static/img/donejs-testing.jpg\" class=\"img-responsive\">\n <source src=\"./static/img/donejs-testing.mov\" type=\"video/mp4\">\n <source src=\"./static/img/donejs-testing.mp4\" type=\"video/mp4\">\n <source src=\"./static/img/donejs-testing.ogg\" type=\"video/mp4\">\n <source src=\"./static/img/donejs-testing.webm\" type=\"video/webm\">\n </video>\n <div class=\"caption\">\n <h2 class=\"heavy\">Comprehensive Testing</h2>\n <p>Comprehensive tools for the entire testing lifecycle that make writing, running, and maintaining tests intuitive and easy.</p>\n <a href=\"./Features.html#comprehensive-testing\" class=\"btn\">Learn More</a>\n </div>\n </div>\n </div>\n <div class=\"maintain-blocks\">\n <div class=\"col-xs-12 col-sm-6 background video\">\n <video tabindex=\"0\" preload=\"none\" poster=\"./static/img/donejs-npm-packaging-custom-elements.jpg\" class=\"img-responsive\">\n <source src=\"./static/img/donejs-npm-packaging-custom-elements.mov\" type=\"video/mp4\">\n <source src=\"./static/img/donejs-npm-packaging-custom-elements.mp4\" type=\"video/mp4\">\n <source src=\"./static/img/donejs-npm-packaging-custom-elements.ogg\" type=\"video/mp4\">\n <source src=\"./static/img/donejs-npm-packaging-custom-elements.webm\" type=\"video/webm\">\n </video>\n <div class=\"caption\">\n <h2 class=\"heavy\">npm Packages and Custom HTML Elements</h2>\n <p>Split your app into reusable custom HTML elements, and easily share and consume them as npm modules.</p>\n <a href=\"./Features.html#npm-packages\" class=\"btn\">npm Packages</a>\n <a href=\"./Features.html#custom-html-elements\" class=\"btn\">Custom Elements</a>\n </div>\n </div>\n <div class=\"col-xs-12 col-sm-6 background video\">\n <video tabindex=\"0\" preload=\"none\" poster=\"./static/img/continuous-integration0deployment.jpg\" class=\"img-responsive\">\n <source src=\"./static/img/donejs-continuous-integration0deployment.mov\" type=\"video/mp4\">\n <source src=\"./static/img/donejs-continuous-integration0deployment.mp4\" type=\"video/mp4\">\n <source src=\"./static/img/donejs-continuous-integration0deployment.ogg\" type=\"video/mp4\">\n <source src=\"./static/img/donejs-continuous-integration0deployment.webm\" type=\"video/webm\">\n </video>\n <div class=\"caption\">\n <h2 class=\"heavy\">Continuous Integration and Deployment</h2>\n <p>Run tests on every commit to detect problems early. Automate deployment to release early and often.</p>\n <a href=\"./Features.html#continuous-integration--deployment\" class=\"btn\">Learn More</a>\n </div>\n </div>\n </div>\n <div class=\"maintain-blocks\">\n <div class=\"col-xs-12 col-sm-6 background video\">\n <video tabindex=\"0\" preload=\"none\" poster=\"./static/img/donejs-live-reload.jpg\" class=\"img-responsive\">\n <source src=\"./static/img/donejs-live-reload.mov\" type=\"video/mp4\">\n <source src=\"./static/img/donejs-live-reload.mp4\" type=\"video/mp4\">\n <source src=\"./static/img/donejs-live-reload.ogg\" type=\"video/mp4\">\n <source src=\"./static/img/donejs-live-reload.webm\" type=\"video/webm\">\n </video>\n <div class=\"caption\">\n <h2 class=\"heavy\">Hot Module Swapping</h2>\n <p>Changes to JavaScript, CSS, or template files are automatically reflected in your browser, without a refresh.</p>\n <a href=\"./Features.html#hot-module-swapping\" class=\"btn\">Learn More</a>\n </div>\n </div>\n <div class=\"col-xs-12 col-sm-6 background video\">\n <video tabindex=\"0\" preload=\"none\" poster=\"./static/img/done-js-documentation.jpg\" class=\"img-responsive\">\n <source src=\"./static/img/donejs-documentation.mov\" type=\"video/mp4\">\n <source src=\"./static/img/donejs-documentation.mp4\" type=\"video/mp4\">\n <source src=\"./static/img/donejs-documentation.ogg\" type=\"video/mp4\">\n <source src=\"./static/img/donejs-documentation.webm\" type=\"video/webm\">\n </video>\n <div class=\"caption\">\n <h2 class=\"heavy\">Documentation</h2>\n <p>Generate a multi-versioned, browsable documentation website from inline code comments.</p>\n <a href=\"./Features.html#documentation\" class=\"btn\">Learn More</a>\n </div>\n </div>\n </div>\n <h2>More ways DoneJS helps developers do their jobs</h2>\n <p class=\"trail\">\n <a href=\"./Features.html#comprehensive-testing\">Comprehensive Testing</a><span class=\"pipe-spacer\"> | </span>\n <a href=\"./Features.html#hot-module-swapping\">Hot Module Swapping</a><span class=\"pipe-spacer\"> | </span>\n <a href=\"./Features.html#documentation\">Documentation</a><span class=\"pipe-spacer\"> | </span>\n <a href=\"./Features.html#npm-packages\">npm Packages</a><span class=\"pipe-spacer\"> | </span>\n <a href=\"./Features.html#continuous-integration--deployment\">Continuous Integration and Deployment</a><span class=\"pipe-spacer\"> | </span>\n <a href=\"./Features.html#es6-modules\">ES6 Modules</a><span class=\"pipe-spacer\"> | </span>\n <a href=\"./Features.html#modlets\">Modlets</a><span class=\"pipe-spacer\"> | </span>\n <a href=\"./Features.html#custom-html-elements\">Custom HTML Elements</a><span class=\"pipe-spacer\"> | </span>\n <a href=\"./Features.html#mvvm-architecture\">MVVM Architecture</a><span class=\"pipe-spacer\"> | </span>\n <a href=\"./Features.html#generators\">Generators</a>\n </p>\n\n </div>\n </div>\n\n <div class=\"community wrapper\">\n <div class=\"lead-in\">\n <h1><span class=\"heavy\">Community</span></h1>\n <h4>We’re always here to help, and we’d love to hear from you. <br>Here are some links to help you out.</h4>\n <p>\n If you’re looking for help the best place to start is our <a href=\"https://www.bitovi.com/community/slack\">Slack</a> or <a href=\"https://forums.bitovi.com/\">the forums</a>.\n </p>\n </div>\n <div class=\"links\">\n <div class=\"col-sm-4\">\n <h3><span class=\"heavy\">Help</span></h3>\n <p><a href=\"https://www.bitovi.com/community/slack\">Slack</a></p>\n <p><a href=\"https://forums.bitovi.com/\">Forums</a></p>\n <p><a href=\"https://stackoverflow.com/search?q=donejs\">Stack Overflow</a></p>\n </div>\n <div class=\"col-sm-4\">\n <h3><span class=\"heavy\">Keep in Touch</span></h3>\n <p><a href=\"https://twitter.com/donejs\">Twitter</a></p>\n <p><a href=\"https://www.youtube.com/playlist?list=PL--xV5crGpX-gESr_qqX5BDlO9jjUBw7m\">YouTube</a></p>\n <p><a href=\"https://www.bitovi.com/blog/topic/open-source\">Blog</a></p>\n\n </div>\n <div class=\"col-sm-4\">\n <h3><span class=\"heavy\">Contribute</span></h3>\n <p><a href=\"https://github.com/donejs\">GitHub</a></p>\n <p><a href=\"https://github.com/donejs/donejs/issues\">Submit Issues</a></p>\n </div>\n </div>\n </div>\n </div>\n</div>\n",
"type": "template",
"name": "donejs"
},
"community": {
"body": "<div class=\"container-fluid\">\n <div class=\"row\">\n <div class=\"hero clearfix\">\n <div class=\"transparency clearfix\">\n <div class=\"lead-in\">\n <h1>The DoneJS <span class=\"heavy\">Community</span></h1>\n <div class=\"col-sm-8 col-sm-offset-2\">\n <div class=\"embed-responsive embed-responsive-16by9\">\n <iframe class=\"embed-responsive-item\" src=\"https://www.youtube.com/embed/lBnKNaSJvGI\" frameborder=\"0\" allowfullscreen></iframe>\n </div>\n </div>\n\n <div class=\"community-quick-links col-xs-12\">\n <ul class=\"quick-link-list\">\n <li>\n <a href=\"https://www.bitovi.com/community/slack\">\n <img class=\"quick-link-icon\" src=\"./static/img/icon-slack-gray.svg\">\n <span class=\"quick-link-label\">Chat</span>\n </a>\n </li>\n <li>\n <a href=\"https://github.com/donejs\">\n <img class=\"quick-link-icon\" src=\"./static/img/icon-github-gray.svg\">\n <span class=\"quick-link-label\">GitHub</span>\n </a>\n </li>\n <li>\n <a href=\"https://stackoverflow.com/search?q=donejs\">\n <img class=\"quick-link-icon\" src=\"./static/img/icon-stackoverflow-gray.svg\">\n <span class=\"quick-link-label\">Stack Overflow</span>\n </a>\n </li>\n <li>\n <a href=\"https://forums.bitovi.com/\">\n <img class=\"quick-link-icon\" src=\"./static/img/icon-forums-gray.svg\">\n <span class=\"quick-link-label\">Forums</span>\n </a>\n </li>\n <li>\n <a href=\"https://www.meetup.com/find/?allMeetups=false&keywords=donejs&radius=Infinity&sort=recommended&eventFilter=mysugg\">\n <img class=\"quick-link-icon\" src=\"./static/img/icon-meetup-gray.svg\">\n <span class=\"quick-link-label\">Meetup</span>\n </a>\n </li>\n <li>\n <a href=\"https://www.youtube.com/channel/UCEnTQUfJi0L6l7g8IRuaVkg\">\n <img class=\"quick-link-icon\" src=\"./static/img/icon-youtube-gray.svg\">\n <span class=\"quick-link-label\">YouTube</span>\n </a>\n </li>\n <li>\n <a href=\"https://twitter.com/donejs\">\n <img class=\"quick-link-icon\" src=\"./static/img/icon-twitter-gray.svg\">\n <span class=\"quick-link-label\">Twitter</span>\n </a>\n </li>\n <li>\n <a href=\"https://www.bitovi.com/blog/rss.xml\">\n <img class=\"quick-link-icon\" src=\"./static/img/icon-rss-gray.svg\">\n <span class=\"quick-link-label\">RSS</span>\n </a>\n </li>\n </ul>\n </div>\n\n <div class=\"overview-nav hidden-sm hidden-md hidden-lg\">\n <a href=\"#resources\" class=\"overview-btn usability-btn\">\n <span class=\"heavy\">Help</span> <span class=\"light\">&</span><br> <span class=\"heavy\">Learning Resources</span>\n <span class=\"overview-nav-fixed-btn\">Resources</span>\n </a>\n <a href=\"#events\" class=\"overview-btn performance-btn\">\n <span class=\"light\">Upcoming</span><br><span class=\"heavy\">Events</span> <span class=\"light\">&</span> <span class=\"heavy\">Meetups</span>\n <span class=\"overview-nav-fixed-btn\">Events</span>\n </a>\n <a href=\"#contribute\" class=\"overview-btn maintainable-btn\">\n <span class=\"heavy\">Contribute</span> <span class=\"light\">to</span><br><span class=\"heavy\">Done</span><span class=\"light\">JS</span>\n <span class=\"overview-nav-fixed-btn\">Contribute</span>\n </a>\n </div>\n </div>\n <div class=\"triptych hidden-xs\">\n <div class=\"col-xs-12 col-sm-4 box usability\" data-scrollto=\"#usability\">\n <h2>Help <span class=\"light\">&</span><br> Learning Resources</h2>\n </div>\n <div class=\"col-xs-12 col-sm-4 box performance\" data-scrollto=\"#performance\">\n <h2><span class=\"light\">Upcoming</span><br>Events <span class=\"light\">&</span> Meetups</h2>\n </div>\n <div class=\"col-xs-12 col-sm-4 box maintainable\" data-scrollto=\"#maintainable\">\n <h2>Contribute <span class=\"light\">to</span><br>Done<span class=\"light\">JS</span></h2>\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"usability resources wrapper\">\n <div class=\"lead-in\">\n <a id=\"resources\" style=\"vertical-align: top;\"></a>\n <a id=\"usability\" style=\"vertical-align: top;\"></a>\n <h1><span class=\"heavy\">Help</span> <span class=\"light\">&</span> <span class=\"heavy\">Learning Resources</span></h1>\n </div>\n <div class=\"col-sm-10 col-lg-7 center-block featured-resources\">\n <div class=\"col-sm-6\">\n <h3><a href=\"https://www.bitovi.com/community/slack\"><img class=\"featured-resource-icon\" src=\"./static/img/icon-slack-black.svg\"> Slack</a></h3>\n <p>\n Get help and chat with our team in realtime! We love to answer questions and help out.\n </p>\n </div>\n <div class=\"col-sm-5 col-sm-offset-1 col-lg-5\">\n <h3><a href=\"https://stackoverflow.com/search?q=donejs\"><img class=\"featured-resource-icon\" src=\"./static/img/icon-stackoverflow-black.svg\"> Stack Overflow</a></h3>\n <p>\n Search questions about DoneJS. We actively watch SO for questions to provide answers to the community.\n </p>\n </div>\n </div>\n <div class=\"col-sm-10 col-lg-7 center-block weekly-trainings clearfix\">\n <h2>Free Weekly Trainings</h2>\n <p>\n Join us every <a href=\"https://www.bitovi.com/blog/free-weekly-online-javascript-training#subscribe\">Wednesday at Noon, CST </a>for free DoneJS and JavaScript trainings lead by members of our team. We discuss different topics every week from the basics to advanced level techniques to help you step up your game. Also check out all of our past training sessions on youtube.\n </p>\n <div class=\"col-sm-4\">\n <div class=\"embed-responsive embed-responsive-16by9\">\n <iframe class=\"embed-responsive-item\" src=\"https://www.youtube.com/embed/ZwjW54kNXnQ\" frameborder=\"0\" allowfullscreen></iframe>\n </div>\n </div>\n <div class=\"col-sm-4\">\n <div class=\"embed-responsive embed-responsive-16by9\">\n <iframe class=\"embed-responsive-item\" src=\"https://www.youtube.com/embed/OCw1yb8Zcwo\" frameborder=\"0\" allowfullscreen></iframe>\n </div>\n </div>\n <div class=\"col-sm-4\">\n <div class=\"embed-responsive embed-responsive-16by9\">\n <iframe class=\"embed-responsive-item\" src=\"https://www.youtube.com/embed/Li-BEEYKYqw\" frameborder=\"0\" allowfullscreen></iframe>\n </div>\n </div>\n </div>\n <div class=\"col-sm-12 text-center\">\n <a class=\"btn\" href=\"https://www.bitovi.com/blog/free-weekly-online-javascript-training#subscribe\">View the Calendar</a>\n </div>\n\n </div>\n\n <div class=\"performance upcoming-events wrapper col-xs-12\">\n <a id=\"performance\" style=\"vertical-align: top;\"></a>\n <a id=\"events\" style=\"vertical-align: top;\"></a>\n <div class=\"lead-in\">\n <div class=\"title-padding\">\n <h1><span class=\"light\">Upcoming</span> <span class=\"heavy\">Events</span></h1>\n </div>\n </div>\n <div class=\"inner-wrapper\">\n <div class=\"col-sm-10 col-lg-9 center-block table-row\">\n <calendar-events api-key=\"AIzaSyBsNpdGbkTsqn1BCSPQrjO9OaMySjK5Sns\"\n calendar-id=\"jupiterjs.com_g27vck36nifbnqrgkctkoanqb4@group.calendar.google.com\" \n event-count=\"3\">\n <template>\n <div class=\"upcoming-event\">\n <div class=\"event-description\">\n <div class=\"header\">\n <h4 class='event-title'></h4>\n <p class='detail'>\n <span class='event-date'></span>\n </p>\n </div>\n <p class='event-body'></p>\n </div>\n <div class=\"footer\">\n <a class=\"event-url open-in-new\" target=\"_blank\">View Event</a>\n </div>\n </div>\n\n </template>\n </calendar-events>\n </div>\n </div>\n\n\n <div class=\"lead-in\">\n <div class=\"title-padding\">\n <h1><span class=\"heavy\">Done</span><span class=\"light\">JS</span> <span class=\"heavy\">Meetups</span></h1>\n </div>\n </div>\n <div class=\"inner-wrapper\">\n <div class=\"col-sm-10 col-lg-9 center-block meetup-locations hidden-xs\">\n <div class=\"col-sm-3\">\n <ul class=\"meetup-list\">\n <li>\n <a href=\"https://www.meetup.com/DoneJS-Boston/\" class=\"meetup-item\">Boston</a>\n </li>\n <li>\n <a href=\"https://www.meetup.com/DoneJS-Chicago/\" class=\"meetup-item\">Chicago</a>\n </li>\n </ul>\n </div>\n <div class=\"col-sm-3\">\n <ul class=\"meetup-list\">\n <li>\n <a href=\"https://www.meetup.com/DoneJS-Silicon-Valley/\" class=\"meetup-item\">Silicon Valley</a>\n </li>\n <li>\n <a href=\"https://www.meetup.com/DoneJS-LA/\" class=\"meetup-item\">Los Angeles</a>\n </li>\n <li>\n <a href=\"https://www.meetup.com/DoneJS-Fort-Lauderdale/\" class=\"meetup-item\">Ft. Lauderdale</a>\n </li>\n </ul>\n </div>\n <div class=\"col-sm-3\">\n <ul class=\"meetup-list\">\n <li>\n <a href=\"https://www.meetup.com/DoneJS-NYC/\" class=\"meetup-item\">New York</a>\n </li>\n <li>\n <a href=\"https://www.meetup.com/DoneJS-Phoenix/\" class=\"meetup-item\">Phoenix</a>\n </li>\n <li>\n <a href=\"https://www.meetup.com/DoneJS-raleigh-durham/\" class=\"meetup-item\">Raleigh-Durham</a>\n </li>\n </ul>\n </div>\n <div class=\"col-sm-3\">\n <ul class=\"meetup-list\">\n <li>\n <a href=\"https://www.meetup.com/DoneJS-San-Francisco/\" class=\"meetup-item\">San Francisco</a>\n </li>\n <li>\n <a href=\"https://www.meetup.com/DoneJS-Seattle/\" class=\"meetup-item\">Seattle</a>\n </li>\n </ul>\n </div>\n </div>\n <div class=\"meetup-locations hidden-sm hidden-md hidden-lg\">\n <div class=\"col-xs-6\">\n <ul class=\"meetup-list\">\n <li>\n <a href=\"https://www.meetup.com/DoneJS-Boston/\" class=\"meetup-item\">Boston</a>\n </li>\n <li>\n <a href=\"https://www.meetup.com/DoneJS-Silicon-Valley/\" class=\"meetup-item\">Silicon Valley</a>\n </li>\n <li>\n <a href=\"https://www.meetup.com/DoneJS-Fort-Lauderdale/\" class=\"meetup-item\">Ft. Lauderdale</a>\n </li>\n <li>\n <a href=\"https://www.meetup.com/DoneJS-LA/\" class=\"meetup-item\">Los Angeles</a>\n </li>\n </ul>\n </div>\n\n <div class=\"col-xs-6\">\n <ul class=\"meetup-list\">\n <li>\n <a href=\"https://www.meetup.com/DoneJS-NYC/\" class=\"meetup-item\">New York</a>\n </li>\n <li>\n <a href=\"https://www.meetup.com/DoneJS-Phoenix/\" class=\"meetup-item\">Phoenix</a>\n </li>\n <li>\n <a href=\"https://www.meetup.com/DoneJS-raleigh-durham/\" class=\"meetup-item\">Raleigh-Durham</a>\n </li>\n <li>\n <a href=\"https://www.meetup.com/DoneJS-San-Francisco/\" class=\"meetup-item\">San Francisco</a>\n </li>\n <li>\n <a href=\"https://www.meetup.com/DoneJS-Seattle/\" class=\"meetup-item\">Seattle</a>\n </li>\n </ul>\n </div>\n\n </div>\n </div>\n <div class=\"col-sm-12 new-meetup-request\">\n <h3>Don’t See Your City? Start a Meetup Today!</h3>\n <p>\n If you can gather 10 people in your nearest city, we’ll work with you to start a new meetup.\n </p>\n <a href=\"mailto:contact@bitovi.com\" class=\"btn\">Get in Touch</a>\n </div>\n </div>\n\n <div class=\"maintainable wrapper contribute\">\n <div class=\"lead-in\">\n <a id=\"contribute\" style=\"vertical-align: top;\"></a>\n <a id=\"maintainable\"></a>\n <h1><span class=\"heavy\">Contribute</span> <span class=\"light\">to</span> <span class=\"heavy\">Done</span><span class=\"light\">JS</span></h1>\n <p>\n The <a href=\"./contributing.html\">contribution guide</a> includes information about our code of conduct, reporting bugs, submitting new code, and more.\n </p>\n <p>\n We want and need your help!\n </p>\n </div>\n </div>\n </div>\n</div>\n",
"type": "template",
"name": "community"
},
"bitballs": {
"src": {
"path": "docs/guides/bitballs.md"
},
"body": "\n\n\n\n## High Level Architecture\n\nBitballs uses the following technology organized by\ntechnology layers:\n\n\n__Storage__\n\n- Database: [Postgres](http://www.postgresql.org/)\n\n> NOTE: DoneJS works perfectly fine with NOSQL approaches and other databases. We don't\n> endorse any backend storage technology. \n\n__Server and Services__\n\n- Language: JavaScript/[Node 5](https://nodejs.org/)\n- Object Relational Mapper: [Bookshelf](http://bookshelfjs.org/)\n- Migrations: [DBMigrate](http://umigrate.readthedocs.org/projects/db-migrate/en/v0.9.x/)\n- Service Middleware: [Express](https://expressjs.com/)\n- Server Side Rendering: [done-ssr's express middleware](https://www.npmjs.com/package/done-ssr-middleware)\n- Session Management: [passport](http://passportjs.org/)\n\n> NOTE: DoneJS works with any service technology. Furthermore, Bitballs' server-side code was not created by server-side NodeJS experts. There are likely many improvements that could be made. Don't learn NodeJS/Express from us. With respect to the server, our only goal with this example is to introduce service APIs that work well with DoneJS clients and give an example of how to create them.\n\n__Client__\n\n- Dependency Management: [StealJS](https://stealjs.com/) with mixed use of [CommonJS](https://stealjs.com/docs/syntax.CommonJS.html) and [ES6](https://stealjs.com/docs/syntax.es6.html).\n- Model: [can-connect](https://canjs.com/doc/can-connect.html/)\n- ViewModel: [can-define/map](http://v3.canjs.com/doc/can-define/map/map.html) and [can-define/list](http://v3.canjs.com/doc/can-define/list/list.html)\n- View: [can.stache](https://canjs.com/docs/can.stache.html)\n- Custom Elements: [can.Component](https://canjs.com/docs/can.Component.html)\n- Routing: [can.route](https://canjs.com/docs/can.route.html)\n\n__Testing__\n\n- Assertion Library: [QUnit](https://qunitjs.com/)\n- Ajax Fixtures: [can-fixture](https://www.npmjs.com/package/can-fixture)\n- Functional Testing: [FuncUnit](https://www.npmjs.com/package/funcunit)\n- Test Runner: [Testee](https://www.npmjs.com/package/testee)\n- Continuous Integration and Deployment: [Travis CI](https://travis-ci.org/)\n\n\n__Hosting__\n\n- Database and Server: [Heroku](https://www.heroku.com/)\n- Static Content: [Firebase](https://www.firebase.com/)\n\n\n__Documentation__\n\n- Engine: [DocumentJS](https://documentjs.com/)\n\n.\n\n\n### Folder organization\n\nThe [bitballs codebase](http://github.com/donejs/bitballs) can be\nthought of as two applications:\n\n- A JavaScript client app in `/public`.\n- A Restful services server in `/` and all other folders except `/public`.\n\nFirst, lets checkout the server side parts:\n\n\n```\n├── package.json - Server-side dependencies configuration\n├── install.js - Post install script, installs /public/package.json\n├── database.json - Database connection configuration\n├── documentjs.json - Documentation configuration\n├── Procfile - Heroku configuration\n├── .travis.yml - Travis configuration\n\n├── index.js - Main entrypoint of application\n\n├── readme.md - Installation instructions\n\n├── migrations/ - Database transformation scripts\n├── models/ - Bookshelf models\n├── services/ - Service middleware definitions\n```\n\nNow, lets checkout the contents of the `/public` folder:\n\n```\n├── package.json - Client configuration and dependencies\n\n├── service.js - Server side rendering middleware\n\n├── index.stache - Main entrypoint of application.\n├── app.js - Application ViewModel and routing rules\n├── app.less - Core stylesheet\n\n├── build.js - Client build script\n├── dev.html - Loads app in development without SSR\n├── prod.html - Loads app in production without SSR\n\n├── test.js - Main entrypoint for loading all tests\n├── test.html - Runs all tests in the browser.\n\n├── models/ - can-connect models\n| ├── player.js\n| ├── session.js\n| ├── state.js\n| ├── team.js\n| ├── user.js\n| ├── youtube.js\n\n| ├── test.js - Tests for the model layer\n| ├── test.html - Runs all model tests in the browser\n| ├── fixtures/ - Mocked server responses\n\n├── components/\n| ├── game/\n| | ├── details/ - Game details page\n| ├── player/\n| | ├── edit/ - Create or Edit a player widget\n| | ├── list/ - Players list page\n| ├── navigation/ - The navigation and login/logout widget\n| ├── tournament/\n| | ├── details/ - Tournament details page\n| | ├── list/ - Tournaments list page\n| ├── user/\n| | ├── details/ - Register a user or edit their password page\n| | ├── list/ - Make admin users.\n| ├── 404.component - 404 response page.\n```\n\n### Data Model and Service layer\n\nBitballs has the following tables and therefore data types:\n\n- [Tournament](http://donejs.github.io/bitballs/docs/bitballs%7Cmodels%7Ctournament.html) - A scheduled date of a basketball tournament.\n- [Player](http://donejs.github.io/bitballs/docs/bitballs%7Cmodels%7Cplayer.html) - A person with an age, height, and weight.\n- [Team](http://donejs.github.io/bitballs/docs/bitballs%7Cmodels%7Cteam.html) - A team of 4 Players for a Tournament.\n- [Game](http://donejs.github.io/bitballs/docs/bitballs%7Cmodels%7Cgame.html) - A match between two Teams for a Tournament.\n- [Stat](http://donejs.github.io/bitballs/docs/bitballs%7Cmodels%7Cstat.html) - A record of some activity for a Game and Player.\n- [User](http://donejs.github.io/bitballs/docs/bitballs%7Cmodels%7Cuser.html) - Someone who can log into the application with an email and password.\n\nThe server also has a concept of a [Session](http://donejs.github.io/bitballs/docs/bitballs%7Cmodels%7Csession.html). The Session\ncan be thought of as having a User.\n\n<img class=\"img-responsive\" src=\"static/img/bitballs/data-model.png\">\n\n\nThe restful service layer provides the following urls\n(each links to their corresponding docs):\n\n- [`/services/tournaments`](http://donejs.github.io/bitballs/docs/services%7Ctournaments.html)\n- [`/services/players`](http://donejs.github.io/bitballs/docs/services%7Cplayers.html)\n- [`/services/teams`](http://donejs.github.io/bitballs/docs/services%7Cteams.html)\n- [`/services/games`](http://donejs.github.io/bitballs/docs/services%7Cgames.html)\n- [`/services/stats`](http://donejs.github.io/bitballs/docs/services%7Cstats.html)\n- [`/services/users`](http://donejs.github.io/bitballs/docs/services%7Cusers.html)\n- [`/services/session`](http://donejs.github.io/bitballs/docs/services%7Csession.html)\n\nThe database-backed services, like `/services/teams` follow a subset of\n[Rest relational algebra](https://gist.github.com/justinbmeyer/3753564).\n\n- To get a list of items, `GET /services/{plural_type}?...`\n- To get a single item, `GET /services/{plural_type}/{id}`\n- To create an item, `POST /services/{plural_type}s`\n- To update an item, `PUT /services/{plural_type}/{id}`\n- To destroy an item, `DELETE /services/{plural_type}/{id}`\n\nThis means that you can get all Teams like:\n\n```js\nREQUEST:\n GET /services/teams\nRESPONSE:\n {\n data: [\n {\n id: 5, color: \"Orange\", name: \"Orange Crush\",\n player1Id: 57, player2Id: 12, player3Id: 99, player4Id: 1,\n gameId: 3\n },\n ...\n ]\n }\n```\n\nOr get list of teams for a particular tournament like:\n\n```js\nREQUEST:\n GET /services/teams?where[gameId]=7\nRESPONSE:\n {\n data: [\n {\n id: 5, color: \"Red\", name: \"Red Dragons\",\n player1Id: 15, player2Id: 16, player3Id: 17, player4Id: 18,\n gameId: 7\n },\n ...\n ]\n }\n```\n\nBut critically for handling data relationships, you can tell the\nserver to bring in related data like:\n\n```js\nREQUEST:\n GET /services/teams?where[gameId]=7\\\n &withRelated[]=player1\\\n &withRelated[]=player2\\\n &withRelated[]=player3\\\n &withRelated[]=player4\nRESPONSE:\n {\n data: [\n {\n id: 5, color: \"Red\", name: \"Red Dragons\",\n player1Id: 15,\n player1: {id: 15, name: \"Justin M.\"}\n player2Id: 16,\n player2: {id: 16, name: \"Matt P.\"}\n player3Id: 17,\n player3: {id: 17, name: \"Lela P.\"}\n player4Id: 18,\n player4: {id: 18, name: \"David L.\"}\n gameId: 7\n },\n ...\n ]\n }\n```\n\nGet a single Team like:\n\n```js\nREQUEST:\n GET /services/teams/5\n\nRESPONSE:\n {\n id: 5, color: \"Red\", name: \"Red Dragons\",\n player1Id: 15, player2Id: 16, player3Id: 17, player4Id: 18,\n gameId: 7\n }\n```\n\nCreate a team like:\n\n```js\nREQUEST:\n POST /services/teams\n {\n color: \"Red\", name: \"Red Dragons\",\n gameId: 7\n }\n\nRESPONSE:\n {\n id: 5, color: \"Red\", name: \"Red Dragons\",\n gameId: 7\n }\n```\n\nUpdate a team like:\n\n```js\nREQUEST:\n PUT /services/teams/5\n {\n color: \"Red\", name: \"Red Dragons\",\n player1Id: 15, player2Id: 16, player3Id: 17, player4Id: 18,\n gameId: 7\n }\n\nRESPONSE:\n {\n id: 5, color: \"Red\", name: \"Red Dragons\",\n player1Id: 15, player2Id: 16, player3Id: 17, player4Id: 18,\n gameId: 7\n }\n```\n\nDestroy a team like:\n\n```js\nREQUEST:\n DELETE /services/teams/5\n\nRESPONSE:\n {}\n```\n\nThe [`/services/session`](http://donejs.github.io/bitballs/docs/services%7Csession.html) api is singular because there can only be\none session available to a particular user. We'll discuss\nthis more in the [Users, Sessions, and Access section](#users-sessions-and-access)\n\n\n### Component map\n\nThe following diagrams show which component is responsible for each part of the application:\n\n<div class=\"row\">\n <div class=\"col-sm-6\">\n <a href=\"http://donejs.github.io/bitballs/docs/bitballs%7Ccomponents%7Cnavigation.html\">\n <img class=\"img-responsive\" src=\"static/img/bitballs/map-navlogin.png\" srcset=\"static/img/bitballs/map-navlogin.png 1x, static/img/bitballs/map-navlogin-2x.png 2x\">\n </a>\n </div>\n <div class=\"col-sm-6\">\n <a href=\"http://donejs.github.io/bitballs/docs/bitballs%7Ccomponents%7Cnavigation.html\">\n <img class=\"img-responsive\" src=\"static/img/bitballs/map-nav.png\" srcset=\"static/img/bitballs/map-nav.png 1x, static/img/bitballs/map-nav-2x.png 2x\">\n </a>\n </div>\n</div>\n<div class=\"row\">\n <div class=\"col-sm-6\">\n <a href=\"http://donejs.github.io/bitballs/docs/bitballs%7Ccomponents%7Ctournament%7Clist.html\">\n <img class=\"img-responsive\" src=\"static/img/bitballs/map-tournamentlist.png\" srcset=\"static/img/bitballs/map-tournamentlist.png 1x, static/img/bitballs/map-tournamentlist-2x.png 2x\">\n </a>\n </div>\n <div class=\"col-sm-6\">\n <a href=\"http://donejs.github.io/bitballs/docs/bitballs%7Ccomponents%7Cplayer%7Clist.html\">\n <img class=\"img-responsive\" src=\"static/img/bitballs/map-playerlist.png\" srcset=\"static/img/bitballs/map-playerlist.png 1x, static/img/bitballs/map-playerlist-2x.png 2x\">\n </a>\n </div>\n</div>\n<div class=\"row\">\n <div class=\"col-sm-6\">\n <a href=\"http://donejs.github.io/bitballs/docs/bitballs%7Ccomponents%7Ctournament%7Cdetails.html\">\n <img class=\"img-responsive\" src=\"static/img/bitballs/map-tournamentdetails.png\" srcset=\"static/img/bitballs/map-tournamentdetails.png 1x, static/img/bitballs/map-tournamentdetails-2x.png 2x\">\n </a>\n </div>\n <div class=\"col-sm-6\">\n <a href=\"http://donejs.github.io/bitballs/docs/bitballs%7Ccomponents%7Cgame%7Cdetails.html\">\n <img class=\"img-responsive\" src=\"static/img/bitballs/map-gamedetails.png\" \n srcset=\"static/img/bitballs/map-gamedetails.png 1x, static/img/bitballs/map-gamedetails-2x.png 2x\">\n </a>\n </div>\n</div>\n<div class=\"row\">\n <div class=\"col-sm-6\">\n <a href=\"http://donejs.github.io/bitballs/docs/bitballs%7Ccomponents%7Cuser%7Cdetails.html\">\n <img class=\"img-responsive\" src=\"static/img/bitballs/map-userdetails.png\" srcset=\"static/img/bitballs/map-userdetails.png 1x, static/img/bitballs/map-userdetails-2x.png 2x\">\n </a>\n </div>\n <div class=\"col-sm-6\">\n <a href=\"http://donejs.github.io/bitballs/docs/bitballs%7Ccomponents%7Cuser%7Clist.html\">\n <img class=\"img-responsive\" src=\"static/img/bitballs/map-userlist.png\" srcset=\"static/img/bitballs/map-userlist.png 1x, static/img/bitballs/map-userlist-2x.png 2x\">\n </a>\n </div>\n</div>\n\n## Users, Sessions, and Access\n\nThis section details Bitballs' access rights system. Learn\nhow users are created, sessions are established, and access\nrights are handled.\n\n### Behavior\n\nBitballs has a very simple access rights system. Only\nadmin users can manipulate tournament data.\n\n<img src=\"static/img/bitballs/new-game.png\" srcset=\"static/img/bitballs/new-game.png 1x, static/img/bitballs/new-game-2x.png 2x\">\n\nAnd only admin users can set another user as an admin user.\n\n<img src=\"static/img/bitballs/admin-view.png\">\n\nNon-admin users can read data.\n\n<img src=\"static/img/bitballs/nonadmin-games.png\" srcset=\"static/img/bitballs/nonadmin-games.png 1x, static/img/bitballs/nonadmin-games-2x.png 2x\">\n\nNon-admins can register themselves and verify their email address.\n\n<img src=\"static/img/bitballs/register.png\" srcset=\"static/img/bitballs/register.png 1x, static/img/bitballs/register-2x.png 2x\">\n\nThe only exception is when there are no users. In this situation,\nthe first created user will be automatically set as the admin user.\n\n### Responsibilities\n\nThe following breaks down what parts of the app perform which parts\nof managing users, sessions and access rights:\n\nThe [`/services/users`](http://donejs.github.io/bitballs/docs/services%7Cusers.html) service handles creating, reading, updating and deleting (CRUDing)\nof users.\n\nThe [`/services/session`](http://donejs.github.io/bitballs/docs/services%7Csession.html) service handles establishing a cookie-based session\nfor a particular user. This will add a `req.user` property to all\nserver request objects when there is a logged in user.\n\nAll other services use `req.user.isAdmin` to determine if the current user has\naccess rights for the given service.\n\nThe [`<user-details>`](http://donejs.github.io/bitballs/docs/bitballs%7Ccomponents%7Cuser%7Cdetails.html) component handles creating a\nnew user.\n\nThe [`<user-list>`](http://donejs.github.io/bitballs/docs/bitballs%7Ccomponents%7Cuser%7Clist.html) component allows an admin user to set\nother users as admin.\n\nThe [AppViewModel](http://donejs.github.io/bitballs/docs/bitballs%7Capp.html) has a `session` property that uses the [Session] model\nto request and store the available\nsession. You can read the session's user and if they are an admin like:\n\n```js\nappViewModel.user.isAdmin\n```\n\nThe [`<bitballs-navigation>`](http://donejs.github.io/bitballs/docs/bitballs%7Ccomponents%7Cnavigation.html) component allows someone to login and change\nthe `AppViewModel`'s session.\n\nAll other page-level components get passed the `AppViewModel`'s `isAdmin` property. They\nuse it to determine which functionality should be displayed.\n\n### Creating a user\n\nWhen a user navigates to `/register`, the [`<user-details>`](http://donejs.github.io/bitballs/docs/bitballs%7Ccomponents%7Cuser%7Cdetails.html) component\ncreates a form that takes a user's email and password. \n\n```html\n<form on:submit=\"this.saveUser(scope.event)\" action=\"\">\n <div class=\"form-group\">\n <label for=\"user-email\">\n Email\n </label>\n {{#is(this.userStatus, \"verified\")}}\n <div class=\"input-group has-success has-feedback\">\n <span class=\"input-group-addon\">verified!</span>\n <input\n class=\"form-control\"\n id=\"user-email\"\n {{^if(this.user.isNew)}}disabled{{/if}}\n value:bind=\"this.user.email\" />\n </div>\n {{else}}\n <input\n class=\"form-control\"\n id=\"user-email\"\n {{^if(this.user.isNew)}}disabled{{/if}}\n value:bind=\"this.user.email\" />\n {{/is}}\n </div>\n ...\n</form>\n```\n\nWhen the form is submitted, an instance of the client `User` model is created and sent to the\n[`/services/users`](http://donejs.github.io/bitballs/docs/services%7Cusers.html) service.\n\n```js\nsaveUser: function(ev) {\n if(ev) {\n ev.preventDefault();\n }\n var self = this,\n promise = this.user.save().then(function(user) {\n ...\n });\n ...\n},\n```\n\nThe service creates a user and sends the user an\nemail to verify their email address.\n\n```js\napp.post('/services/users',\n\tfunction ( req, res, next ){\n // validates request ...\n\t},\n\tpassport.authenticate( 'signup' ),\n\tfunction ( req, res ) {\n\t\tvar user = req.user.toJSON();\n\t\tvar hash = encodeURIComponent( user.verificationHash );\n\t\tvar subject = \"Complete your registration at bitballs\";\n\t\tvar htmlbody = // create email body ...\n\n\t\tnodeMail( user.email,\n 'bitballs@bitovi.com',\n subject,\n htmlbody, function ( err, info ) {\n\t\t\t...\n\t\t\tres.send( omitSensitive( user ) );\n\t\t});\n\t}\n);\n```\n\n### Getting, creating, or destroying a session\n\nThe following details how Bitballs:\n\n- Knows if a user is logged in.\n- Logs in a user.\n- Logs out a user.\n\n#### Getting the session\n\nWhen the client application starts, the app checks if\nit has a session. \n\nThis is done by defining a `session` property that will use the Session\nmodel to retrieve the current session. If there is a session, it will\nbe stored on the AppViewModel.\n\n```js\nsession: {\n serialize: false,\n default: function() {\n Session.get({}).then((session) => {\n this.session = session;\n });\n }\n},\n```\n\nThe [Session](http://donejs.github.io/bitballs/docs/bitballs%7Cmodels%7Csession.html) model makes a request to `GET /services/session`. By default,\nAJAX requests are sent with the user's cookies. \n\nPassport is used and configured to add a `req.user` property to every\nrequest object when a\nuser logs in. That user object is returned, minus any private data, as associated data on the session:\n\n```js\napp.get('/services/session', function(req, res) {\n\tif (req.user) {\n\t\tres.send({user: _.omit(req.user.toJSON(), \"password\")});\n\t} else {\n\t\tres.status(404).send(JSON.stringify({\n\t\t\tmessage : \"No session\"\n\t\t}));\n\t}\n});\n```\n\nThis means that once a user logs in, `GET /services/session` responds with\nan object like:\n\n```js\n{\n user: {email: \"justin@bitovi.com\", isAdmin: true}\n}\n```\n\nWe like to keep session data distinct from User data. In a more complex application,\nadditional session information could be returned that does not belong on the\nuser. For example:\n\n```js\n{\n createdAt: 1456512713012,\n expiresAt: 14565123013012,\n user: {email: \"justin@bitovi.com\", isAdmin: true},\n}\n```\n\nOnce the response data comes back, a `session` object with its associated `session.user`\nobject will be available on the AppViewModel.\n\nThe [`Session` client model](http://donejs.github.io/bitballs/docs/bitballs%7Cmodels%7Csession.html) makes sure that `user` is converted into a [User model](http://donejs.github.io/bitballs/docs/bitballs%7Cmodels%7Cuser.html)\nand also provides an `isAdmin` method that returns if admin functionality should\nbe available:\n\n```js\nvar Session = DefineMap.extend({\n\tdefine: {\n\t\tuser: {\n\t\t\tType: User\n\t\t}\n\t},\n\tisAdmin: function(){\n\t\treturn this.user && this.user.isAdmin;\n\t}\n});\n```\n\nThe session, its user, or the result of `isAdmin` is then passed to\nsub components depending on their needs:\n\n```html\n<tournament-details isAdmin:from='session.isAdmin'/>\n```\n\nFinally, those components use that information to control what is\nshown on the page:\n\n```html\n{{#if isAdmin}}\n<h4>New Game</h4>\n<form on:submit=\"this.createGame(scope.event)\">...</form>\n{{/if}}\n```\n\nIn more complex apps, the `user` object might include an [Access Control List](https://en.wikipedia.org/wiki/Access_control_list)\nwhich might include methods to check access rights:\n\n```html\n{{#if(this.user.acl.can(\"create\",\"game\")) }}\n<h4>New Game</h4>\n<form on:submit=\"this.createGame(scope.event)\">...</form>\n{{/if}}\n```\n\n#### Creating a session\n\nCreating a session is done with the [<bitballs-navigation>](http://donejs.github.io/bitballs/docs/bitballs%7Ccomponents%7Cnavigation.html) component. It builds a\nlogin form that takes an email and password:\n\n```html\n<form on:submit=\"this.createSession(scope.event)\" action=\"\">\n <input\n placeholder=\"email\"\n value:bind=\"this.loginSession.user.email\"/>\n\n <input\n placeholder=\"password\"\n \ttype=\"password\"\n value:bind=\"this.loginSession.user.password\"/>\n\n\t<button type=\"submit\">Login</button>\n</form>\n```\n\n\nWhen a user submits the login form its\nViewModel will save an instance of the\nSession model. When the save is successful, it will update the AppViewModel with\nthe new session instance.\n\n```js\ncreateSession: function(ev){\n if(ev) {\n ev.preventDefault();\n }\n\n this.loginSession.save().then((session) => {\n // create placeholder session for next login.\n this.loginSession = new Session({user: new User()});\n // update AppViewModel with new session\n this.app.session = session;\n\n });\n},\n```\n\nSaving a session calls `POST /services/session` to create a session server side. The service should operate on similar data as `GET /services/session`, so it's passed data like:\n\n```js\n{\n user: {email: \"justin@bitovi.com\", password: \"pass1234\"}\n}\n```\n\nThe application looks up the user, makes sure the encrypted passwords\nmatch, and then calls `req.logIn()` to set `req.user` and then\nresponds with the Session data.\n\n```js\nnew User({\n\t'email': email\n}).fetch().then(function(user) {\n\tif(user) {\n\t\t// User exists but wrong password, log the error\n\t\tif (!isValidPassword(user, password)) {\n\t\t\tres.status(401).json({message: \"wrong password\"});\n\t\t} else {\n\t\t\treq.logIn(user, function(err) {\n\t\t\t\tif (err) {\n\t\t\t\t\treturn next(err);\n\t\t\t\t}\n\t\t\t\treturn res.json({\n user: _.omit(req.user.toJSON(), \"password\")\n });\n\t\t\t});\n\t\t}\n\t} else {\n\t\treturn res.status(404).json({message: \"wrong username\"});\n\t}\n})\n```\n\n\n#### Destroy the session\n\nThe [`<bitballs-navigation>`](http://donejs.github.io/bitballs/docs/bitballs%7Ccomponents%7Cnavigation.html) component's [template](https://github.com/donejs/bitballs/blob/master/public/components/navigation/navigation.stache) as a link that\ncalls `logout()` on its ViewModel:\n\n```html\n<a href=\"javascript://\" on:click=\"this.logout()\">Logout</a>\n```\n\n`logout` calls destroy on the session and then removes the session from the AppViewModel:\n\n```js\nlogout: function(){\n this.session.destroy().then(()=>{\n this.session = null;\n });\n}\n```\n\nDestroying a session calls `DELETE /services/session` to destroy a session server side. No data needs to be passed. The server simply calls passport's `logout()` and responds\nwith an empty JSON object.\n\n```js\napp.delete(\"/services/session\", function(req, res){\n\treq.logout();\n\tres.json({});\n});\n```\n\n### Server side rendering\n\nDoneJS is able to automatically server-side render pages that use\ncookie based sessions. For example, if an admin logs into Bitballs\nand refreshes the [tournament details](https://bitballs.herokuapp.com/tournaments/2) page, they will be\nserved a page with all of the additional forms an admin user can see. \nFurthermore, they will be served a \"Logout\" link instead of \"Login\".\n\nThis works because when a browser navigates to `tournaments/5`,\nthe cookie is passed to DoneJS's server-side rendering. It adds\nthis cookie to the virtual document used to render that page\nand it makes sure any AJAX requests the client makes\nalso includes that cookie.\n\nThis means that when `Session.get()` is called by the AppViewModel\nto get the session, the right cookie information is passes to the `GET /services/session`\nservice and a session is established in the client.\n\n## Data Relationships\n\nIn this section, we'll learn about how to manage related data in a\nDoneJS application. We'll describe our approach that balances performance and\nmaintainability concerns that are vital for making high performance apps that\ncan quickly respond to changes in design.\n\n### Performance vs Maintainability\n\nBitballs [data model](#data-model-and-service-layer) has many relationships among\nits data types. For example, Tournaments have many Games and have many Teams. Games\nhave Teams and Stats. And Teams have Players.\n\nThe __tournament details__ page not only needs to load a tournament, it needs to load\nthat tournament's games, teams, and all players.\n\nThe __game details__ page needs to load the game, all of the game's stats, teams, and the teams\nplayers.\n\nBitballs needs to be able to load these pages quickly. Using a very simplistic\nRESTful service layer, the client might have to do the following to load a __game details__\npage:\n\n```js\nGET /services/games/5\n -> {id: 5, homeTeamId: 16, awayTeamId: 17, videoUrl: \"X1Ha9d8fE\", ...}\n\nGET /services/stats?gameId=5\n -> {data: [{id: 99, gameId: 5, playerId: 61, type: \"orb\"}, ...]}\n\nGET /services/teams/16\n -> {id: 16, player1Id: 61, player2Id: 62, player3Id: 63, player4Id: 64,...}\n\nGET /services/teams/17\n -> {id: 17, player1Id: 71, player2Id: 72, player3Id: 73, player4Id: 74,...}\n\nGET /services/players/61 -> {id: 61, name: \"Justin M\", ...}\nGET /services/players/62 -> {id: 61, name: \"Matt P\", ...}\nGET /services/players/63 -> {id: 61, name: \"David L\", ...}\nGET /services/players/64 -> {id: 61, name: \"Julia P\", ...}\n\nGET /services/players/71 -> {id: 61, name: \"Paula P\", ...}\nGET /services/players/72 -> {id: 61, name: \"Chris G\", ...}\nGET /services/players/73 -> {id: 61, name: \"Jan J\", ...}\nGET /services/players/74 -> {id: 61, name: \"James A\", ...}\n\n\n```\n\nThat's 12 requests! But that's not the worst part. The worst part is that\nat least 3 _serial_ batches of requests must happen. We can't load\nplayers until we have teams. We can't load teams until we\nhave the game.\n\nInstead, we'd want to load a game and get back its data with its\nnested teams and players and stats like:\n\n```js\nGET /services/games/5\n -> {\n id: 5,\n homeTeamId: 16,\n homeTeam: {\n id: 16,\n player1Id: 61,\n player1: {id: 61, name: \"Justin M\", ...},\n player2Id: 62,\n player2: {id: 61, name: \"Matt P\", ...}\n player3Id: 63,\n player3: {id: 61, name: \"David L\", ...}\n player4Id: 64,\n player4: {id: 61, name: \"Julia P\", ...}\n ...\n },\n awayTeamId: 17,\n awayTeam: {\n id: 17,\n player1Id: 71,\n player1: {id: 61, name: \"Paula P\", ...}\n player2Id: 72,\n player2: {id: 61, name: \"Chris G\", ...}\n player3Id: 73,\n player3: {id: 61, name: \"Jan J\", ...}\n player4Id: 74,\n player4: {id: 61, name: \"James A\", ...}\n ...\n },\n stats: [{id: 99, gameId: 5, playerId: 61, type: \"orb\"}, ...],\n videoUrl: \"X1Ha9d8fE\",\n ...\n}\n```\n\n> Note: Including stats is optional because stats can be requested in parallel\nto the game and its teams and players. In some apps, it might be a better\nuser experience to make two requests, allowing the client to show\nsomething when it has some data instead of all of it.\n\nWhat you __don't__ want to do, is make `/services/games/{id}` always\nreturn this nested data because you don't know the future of the __game details__\npage or all of the uses of the `/services/games/{id}` service. For example,\nit's possible someone might want to simply know the final score of a game. In this\ncase, the teams and players would not be necessary.\n\nSo how do you reconcile performance needs with the certainty that application\nrequirements and the uses of your services will change?\n\nThe answer is making expressive RESTful services and client Models and ViewModels\nthat are able to work with them. \n\n### Expressive services\n\nExpressive services allow the client to specify some of the raw behavior that\nnormally goes into database requests while being adaptive to changes in the database.\n\nThey are normally built by mapping parts of the query string to clauses in a\nbackend [Object Relational Mapper](https://en.wikipedia.org/wiki/Object-relational_mapping) (ORM).\n\nFor instance, the __game details__ page requests a game with its\nrelated fields like:\n\n```js\nGame.get({\n\tid: this.gameId,\n\twithRelated: [\n \"stats\",\n\t\t\"homeTeam.player1\",\n\t\t\"homeTeam.player2\",\n\t\t\"homeTeam.player3\",\n\t\t\"homeTeam.player4\",\n\t\t\"awayTeam.player1\",\n\t\t\"awayTeam.player2\",\n\t\t\"awayTeam.player3\",\n\t\t\"awayTeam.player4\"\n\t]\n});\n```\n\nThis results in an AJAX request like:\n\n```js\nGET /services/games/5?\\\n withRelated[]=stats&\\\n withRelated[]=homeTeam.player1&\\\n withRelated[]=homeTeam.player2&\\\n withRelated[]=homeTeam.player3&\\\n withRelated[]=homeTeam.player4&\\\n withRelated[]=awayTeam.player1&\\\n withRelated[]=awayTeam.player2&\\\n withRelated[]=awayTeam.player3&\\\n withRelated[]=awayTeam.player4\n```\n\n`withRelated` allows the client to control the the Database's `JOIN`\nclause.\n\nInstead of processing the querystring ourselves and build the corresponding\nDatabase request, most ORMs make it easy to do the expected thing.\n\nBitballs uses [Bookshelf](http://bookshelfjs.org/) as its ORM. It allows us\nto define relationships between a `Game` and other server-side models:\n\n```js\nvar Game = bookshelf.Model.extend({\n\ttableName: 'games',\n\tstats: function(){\n\t\treturn this.hasMany(Stat,\"gameId\");\n\t},\n\thomeTeam: function(){\n\t\treturn this.belongsTo(Team,\"homeTeamId\");\n\t},\n\tawayTeam: function(){\n\t\treturn this.belongsTo(Team,\"awayTeamId\");\n\t}\n});\n```\n\nIt does a similar thing for `Team`:\n\n```js\nvar Team = bookshelf.Model.extend({\n\ttableName: 'teams',\n\tplayer1: function(){\n\t\treturn this.belongsTo(Player,\"player1Id\");\n\t},\n\tplayer2: function(){\n\t\treturn this.belongsTo(Player,\"player2Id\");\n\t},\n\tplayer3: function(){\n\t\treturn this.belongsTo(Player,\"player3Id\");\n\t},\n\tplayer4: function(){\n\t\treturn this.belongsTo(Player,\"player4Id\");\n\t}\n});\n```\n\nOnce these server Models are in place, it is extremely easy\nto make a service that can dynamically include related data:\n\n```js\napp.get('/services/games/:id', function(req, res){\n\tnew Game({id: req.params.id}).fetch(req.query).then(function(game){\n\t\tres.send(game.toJSON());\n\t});\n});\n```\n\nThis setup also lets us be very adaptive to changes in the\ndatabase. For instance, if a game suddenly has\ncomments, we could make the following work:\n\n```js\nGame.get({\n\tid: this.gameId,\n\twithRelated: [\"comments\"]\n});\n```\n\nBy creating a `Comment` model and changing `Game` to\nlook like:\n\n```js\nvar Game = bookshelf.Model.extend({\n\ttableName: 'games',\n\tcomments: function(){\n\t\treturn this.hasMany(Comment,\"commentId\");\n\t},\n\tstats: function(){\n\t\treturn this.hasMany(Stat,\"gameId\");\n\t},\n\thomeTeam: function(){\n\t\treturn this.belongsTo(Team,\"homeTeamId\");\n\t},\n\tawayTeam: function(){\n\t\treturn this.belongsTo(Team,\"awayTeamId\");\n\t}\n});\n```\n\nThe goal should be changing your service code as little as possible. Instead,\nyou should be changing your ORMs and the service code adapts to them. In\nBitballs' case this means we shouldn't be changing what's in `/services`,\ninstead we should be changing what's in `/models` as the database changes.\n\nRelated data is not the only behavior that your expressive\nservice layer should provide:\n\n - filter (`WHERE`)\n - pagination (`OFFSET` and `LIMIT`)\n - sorting (`SORTBY`)\n - which properties to include or exclude\n\nFor example, I can get all of team 5's games like:\n\n```js\nGET /services/games?where[teamId]=5\n```\n\nThis happens for free because we pass the querystrng directly to bookshelf:\n\n```js\napp.get('/services/games', function(req, res){\n\tnew Games().query(req.query).fetch().then(function(games){\n\t\tres.send({data: games.toJSON()});\n\t});\n});\n```\n\nMost server technologies have an ORM that can make this process\nstraightforward. It's generally best to use a service API that\nclosely matches the API of your ORM.\n\n### Models and ViewModels\n\nOnce you've settled on an expressive service API, you need\nto make Models that connect to it and handle associated data. And if you want\nany of the advanced behavior of [can-connect](https://canjs.com/doc/can-connect.html), you have\nto create a QueryLogic that understands the service API.\n\n#### Connecting to a service\n\nBitballs' client Models are [can-connect supermodels](https://canjs.com/doc/can-connect.html/doc/can-connect%7Ccan%7Csuper-map.html). So a type and list type is defined:\n\n```js\nvar Game = DefineMap.extend({\n ...\n});\n\nGame.List = DefineList.extend({\"#\": Game},{});\n```\n\nAnd they are connected to a url:\n\n```js\nvar gameConnection = realTimeRestModel({\n Map: Game,\n List: Game.List,\n url: \"/services/games\",\n name: \"game\",\n queryLogic: new QueryLogic(Game, bookshelfService)\n});\n```\n\n#### Relational Algebra\n\nTo match the query parameters our service and eventually Bookshelf\nexpects, we need to define a custom *query logic*. For our app, it looks like this:\n\n__models/bookshelf-service.js__\n\n```js\nimport { key } from \"can\";\n\nconst bookshelfService = {\n toQuery(params) {\n return key.transform(params, {\n where: \"filter\",\n orderBy: \"sort\"\n });\n },\n toParams(query){\n return key.transform(query, {\n filter: \"where\",\n sort: \"orderBy\"\n });\n }\n};\n\nexport default bookshelfService;\n```\n\n#### Defining related properties\n\nBecause Game data can come back with a `homeTeam`,\n`awayTeam` and `stats` property, we make sure those\nare created as the right type:\n\n```js\nvar Game = DefineMap.extend({\n\thomeTeam: {\n\t\tType: Team\n\t},\n\tawayTeam: {\n\t\tType: Team\n\t},\n\tstats: {\n\t\tType: Stat.List,\n\t\tset: function(stats){\n\t\t\tstats[Stat.connection.listQueryProp] = { filter: {gameId: this.id }};\n\t\t\treturn stats;\n\t\t}\n\t},\n ...\n});\n```\n\nNotice that `stats.set` is setting the [listQueryProp](https://canjs.com/doc/can-connect/base/base.listQueryProp.html) property of the stats. This is necessary for [can-connect's real-time](https://canjs.com/doc/can-connect/real-time/real-time.html) behavior. When stats are created for this game, they will automatically appear in this list.\n\n#### Defining computed properties\n\n`Game` also has `teams` and `players` computed properties that\nderive their value from related fields:\n\n```js\nvar Game = DefineMap.extend({\n ...\n get teams() {\n var teams = [],\n home = this.homeTeam,\n away = this.awayTeam;\n\n if (home) {\n teams.push(home);\n }\n if (away) {\n teams.push(away);\n }\n return new Team.List(teams);\n },\n get players() {\n var players = [];\n this.teams.forEach(function(team) {\n [].push.apply(players, can.makeArray(team.players));\n });\n return new Player.List(players);\n }\n});\n```\n\nIn `players`, `team.players` is actually making use of a similar computed\n[`players` property](http://donejs.github.io/bitballs/docs/bitballs%7Cmodels%7Cteam.html) in the Team client model.\n\n#### Defining intermediate computed properties to avoid recomputing.\n\nSometimes ViewModels mash up Model data. For example,\nthe `<tournament-details>` component makes four requests in parallel:\n\n```js\nTournament.get({id: this.tournamentId});\nGame.getList({tournamentId: this.tournamentId});\nTeam.getList({ tournamentId: this.tournamentId });\nPlayer.getList({});\n```\n\nThis gets a tournament, the games for a tournament, the\nteams for a tournament, and all the players. All the players\nare needed to allow the admin to pick teams. This means\nit would be wasteful to use `withRelated: [\"player1\",\"player2\",...]` on the\nTeam request because all players are already loading.\n\nBut this makes it tricky to list a team's players because\nall we have are player ids on each team:\n\n<img class=\"img-responsive\" src=\"static/img/bitballs/team-list.png\" srcset=\"static/img/bitballs/team-list.png 1x, static/img/bitballs/team-list-2x.png 2x\">\n\nA naive solution would be to make a `getById` method on `Player.List` like:\n\n```js\nPlayer.List = DefineList.extend({\"#\": Player},{\n getById: function(id){\n return this.filter(function(player){\n return team.id === id;\n })[0];\n }\n});\n```\n\nAnd then use that in the template to look up the player:\n\n```js\n{{#each teams}}\n ...\n <td>{{#for(player of this.players.getById(player1Id))}}{{player.name}}{{/for}}</td>\n <td>{{#for(player of this.players.getById(player2Id))}}{{player.name}}{{/for}}</td>\n <td>{{#for(player of this.players.getById(player3Id))}}{{player.name}}{{/for}}</td>\n <td>{{#for(player of this.players.getById(player4Id))}}{{player.name}}{{/for}}</td>\n{{/each}}\n```\n\n> NOTE: The `../` is needed to use the [tournaments/details](http://donejs.github.io/bitballs/docs/bitballs%7Ccomponents%7Ctournament%7Cdetails.ViewModel.html)'s `players` property instead of the [players property on the client Game model](http://donejs.github.io/bitballs/docs/bitballs%7Cmodels%7Cgame.properties.players.html).\n\nThe problem with this is that each `.getById` call is linear search. Instead,\nwe can keep a mapping of player ids to players like:\n\n```js\nidMap: {\n type: \"any\",\n get: function(){\n\n var map = {};\n\n this.each(function(player){\n map[player.id] = player;\n });\n\n return map;\n }\n},\n```\n\nAnd make a `getById` use `idMap` like:\n\n```js\ngetById: function(id){\n\treturn this.playerIdMap[id];\n},\n```\n\nNow when `.getById` is used in the template `playerIdMap` will only ever\nbe calculated once.\n\n\n## SSR and node services\n\nIn this section, we'll learn about how to setup DoneJS's server-side rendering in the same process\nas other NodeJS services. We'll also detail how 404s and other HTTP response codes can be communicated\nfrom your client app to DoneJS's server-side rendering.\n\n> NOTE: DoneJS works with any service technology, for example Ruby on Rails, PHP,\nJava, etc. In applications where services are built without NodeJS,\nserver-side rendering is run as a separate NodeJS process. However, if your application's services\nare written in NodeJS, you can host server-side rendering in the same process as the rest of your\nNodeJS application. This is the only, relatively minor, advantage of writing backend services in NodeJS.\n\n### Setup\n\nBitballs is written using [Express middleware](https://expressjs.com/en/guide/using-middleware.html).\nWith express you order middleware functions to handle different requests. Bitballs sets up its middleware in [/index.js](https://github.com/donejs/bitballs/blob/master/index.js). The middleware is setup in the\nfollowing order:\n\n1. Static assets in the `/public` folder.\n2. Services in the `/services` folder.\n3. Server-side rendering in `public/service.js`\n\nIn general, server-side should be last in the line of middleware handlers. Static assets\nand services should be the first to respond to a given URL.\n\n[`public/service.js`](https://github.com/donejs/bitballs/blob/master/public/service.js) uses\n[done-ssr-middleware](https://github.com/donejs/done-ssr-middleware) to export a middleware handler like:\n\n```js\nvar ssr = require('done-ssr-middleware');\n\nmodule.exports = ssr({\n config: __dirname + \"/package.json!npm\",\n main: \"bitballs/index.stache!done-autorender\",\n liveReload: true\n});\n```\n\nThis passes what is needed for StealJS to load the client app to `ssr`. `ssr` uses\nStealJS to load the app, and returns an express handler that renders the client app.\nThat express handler is assigned to the `\"/\"` route in `index.js`:\n\n```js\napp.use( \"/\", require('./public/service') );\n```\n\n### 404s\n\nIn general, there are two situations where server-side rendering should respond with a 404\nstatus code:\n\n- When a user navigates to a url not matched by routing like `/total-mistake`.\n- When a user navigates to a url for an item that doesn't exist like: `/tournaments/999`.\n\n[done-ssr-middleware](https://github.com/donejs/done-ssr-middleware) uses the `statusCode` property\non the [AppViewModel](http://donejs.github.io/bitballs/docs/bitballs%7Capp.html) as the status of the http response.\n\nFor Bitballs, we implemented `statusCode` as a [define getter](https://canjs.com/docs/can.Map.prototype.define.get.html) as follows:\n\n```js\nstatusCode: {\n get: function(lastSet, resolve){\n var pageConfig = this.pageComponentConfig;\n\n if(pageConfig.statusCode) {\n return pageConfig.statusCode;\n }\n\n var pagePromise = this.pagePromise;\n if(pagePromise){\n pagePromise.then(function(){\n resolve(200);\n }, function(){\n resolve(404);\n });\n }else{\n return 200;\n }\n }\n}\n```\n\n`statusCode` derives its value from two places that reflect the two common `404`\nsituations.\n\n#### 404 when URL doesn't match a routing rule\n\n`statusCode` first checks if the `pageComponentConfig` is specifying a specific `statusCode`\nto be given. `pageComponentConfig` only specifies a `statusCode` when its state\ndoesn't match a valid route:\n\n```js\nget pageComponentConfig() {\n var page = this.page;\n if(this.gameId) {\n return {...};\n } else if(this.tournamentId) {\n return {...};\n } else if(page === \"tournaments\") {\n return {...};\n } else if(page === \"users\") {\n return {...};\n } else if(page === \"register\" || page === \"account\") {\n return {...};\n } else if(page === \"players\"){\n return {...};\n } else {\n\n return {\n title: \"Page Not Found\",\n componentName: \"four-0-four\",\n attributes: \"\",\n moduleName: \"404.component!\",\n statusCode: 404\n };\n }\n},\n```\n\nWhen the state doesn't match a valid route, users will see the contents of the\n`404.component`.\n\nWith this setup, we could also check the session and include `401 Unauthorized`\nstatus codes for pages that are only visible to an authenticated user.\n\n#### 404 when an item doesn't exist.\n\nNext, `statusCode` checks the `pagePromise` property. If the `pagePromise` resolves\nsuccessfully, a `200` status code is returned. If the `pagePromise` is rejected,\na `404` status code is returned.\n\n`pagePromise` is a promise that is passed by a child component up to the\n`AppViewModel`. Notice how [<game-details>](http://donejs.github.io/bitballs/docs/bitballs%7Ccomponents%7Cgame%7Cdetails.html) passes its `gamePromise`\nas the `pagePromise` like `{^game-promise}='./pagePromise'`:\n\n\n```js\nget pageComponentConfig() {\n var page = this.page;\n if(this.gameId) {\n return {\n title: \"Game\",\n componentName: \"game-details\",\n attributes: \"gamePromise:to='./pagePromise' gameId:from='./gameId' session:from='./session'\",\n moduleName: \"game/details/\"\n };\n\n } else if(this.tournamentId) {\n return {\n title: \"Tournament\",\n componentName: \"tournament-details\",\n attributes: \"tournamentPromise:to='./pagePromise' tournamentId:from='./tournamentId' isAdmin:from='./isAdmin'\",\n moduleName: \"tournament/details/\"\n };\n\n } else if(page === \"tournaments\") {\n return {...};\n } else if(page === \"users\") {\n return {...};\n } else if(page === \"register\" || page === \"account\") {\n return {...};\n } else if(page === \"players\"){\n return {...};\n } else {\n return {...};\n }\n},\n```\n\n[<game-details>](http://donejs.github.io/bitballs/docs/bitballs%7Ccomponents%7Cgame%7Cdetails.html)'s `gamePromise` property is used to load the game's data:\n\n```js\nget gamePromise() {\n return Game.get({\n id: this.gameId,\n withRelated: [...]\n });\n}\n```\n\nIf there is no game at `gameId`, the promise will be rejected and `statusCode` will be\nset to `404`.\n\n\n## Turn off SSR\n\nIn this section, we'll learn about how prevent code from running during server-side rendering.\n\n<div class='here-to-turn-off-highlighting'>\n\nWhile DoneJS's virtual DOM approximates a real DOM and browser, there is much that it\ncannot do such as provide element dimension information.\n\n</div>\n\nTypically, this doesn't affect the code you write because server-side rendering only runs code involved\nin the initial render of a page.\n\nHowever, in Bitballs case, the [game details](https://bitballs.herokuapp.com/games/9) page\nhas an embedded YouTube player. The YouTube API code needed to load\na player will not work in DoneJS's default server-side environment.\n\nTo detect if your code is running in `NodeJS` and therefore being server-side rendered,\nyou can use [steal-platform](https://github.com/stealjs/platform) like:\n\n```js\nvar platform = require(\"steal-platform\" );\nif (platform.isNode ) {\n // do one thing\n} else {\n // do something else\n}\n```\n\nTo prevent loading YouTube's API in node, we reject the promise\nthat would normally resolve to YouTube's API as follows:\n\n```js\nvar platform = require(\"steal-platform\" );\n\nvar promise;\n\nmodule.exports = function(){\n\tif(promise) {\n\t\treturn promise;\n\t} else {\n\t\treturn promise = new Promise(function(resolve, reject){\n\t\t\tif ( platform.isNode ) {\n\t\t\t\treject({});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\twindow.onYouTubeIframeAPIReady = function(){\n\t\t\t\tresolve(YT);\n\t\t\t};\n\t\t\tvar tag = document.createElement('script');\n\n\t\t\ttag.src = \"https://www.youtube.com/iframe_api\";\n\t\t\tdocument.head.appendChild(tag);\n\t\t});\n\n\t}\n};\n```\n\n> NOTE: If you plan on supporting NW.js, know that `platform.isNode`\nwill also be true.\n\n",
"description": " \nIn this guide, you'll learn how [Bitballs](http://bitballs.herokuapp.com) - a charity basketball tournament management application - works.\nSpecifically, this guide will walk through the implementation of the following behaviors or functionality:\n\n - Registration, login, user sessions, and access rights.\n - Handling relationships between model types.\n - Setup node services and server-side rendering on the same process.\n - How to turn off parts of the app that should not be server-side rendered.\n\nThe code for Bitballs can be found [on GitHub](http://github.com/donejs/bitballs).\nTo install and run it locally, follow its\n[development setup instructions](https://github.com/donejs/bitballs#setup-environment).\n\nBitballs was written to help organize Bitovi's yearly charity basketball tournament\nfor the American Heart and Stroke Association. Justin Meyer, one of Bitovi's founders,\nand DoneJS core contributor had a stroke. Read about his experience and the purpose of\nthe tournament [here](http://blog.bitovi.com/bitovi-hoops-for-heart-with-the-american-stroke-association/).\n\nThe application allows __admins__, who manage the tournament, to:\n\nCreate an account (and verify their email address):\n\n<img src=\"static/img/bitballs/create-user.png\" srcset=\"static/img/bitballs/create-user.png 1x, static/img/bitballs/create-user-2x.png 2x\">\n\nLogin:\n\n<img src=\"static/img/bitballs/login.png\" srcset=\"static/img/bitballs/login.png 1x, static/img/bitballs/login-2x.png 2x\">\n\nCreate, edit, and delete players:\n\n<img src=\"static/img/bitballs/create-player.png\" srcset=\"static/img/bitballs/create-player.png 1x, static/img/bitballs/create-player-2x.png 2x\">\n\nCreate, edit, and delete tournaments:\n\n<img src=\"static/img/bitballs/create-tournament.png\" srcset=\"static/img/bitballs/create-tournament.png 1x, static/img/bitballs/create-tournament-2x.png 2x\">\n\nCreate teams of players for a tournament:\n\n<img src=\"static/img/bitballs/create-team.png\" srcset=\"static/img/bitballs/create-team.png 1x, static/img/bitballs/create-team-2x.png 2x\">\n\nCreate and delete games for a tournament:\n\n<img src=\"static/img/bitballs/new-game.png\" srcset=\"static/img/bitballs/new-game.png 1x, static/img/bitballs/new-game-2x.png 2x\">\n\nAdd and remove stats for a game while watching it on YouTube:\n\n<img src=\"static/img/bitballs/add-stat.png\" srcset=\"static/img/bitballs/add-stat.png 1x, static/img/bitballs/add-stat-2x.png 2x\">\n\nVisitors who are not admins are only able to\nview the list of players, tournaments, and game details:\n\n<img src=\"static/img/bitballs/public-view.png\" srcset=\"static/img/bitballs/public-view.png 1x, static/img/bitballs/public-view-2x.png 2x\">\n\n\n",
"name": "bitballs",
"title": "Example: Bitballs",
"type": "page",
"parent": "Guides",
"hideSidebar": true,
"outline": {
"depth": 2,
"tag": "ol"
},
"comment": " "
},
"contributing": {
"src": {
"path": "docs/guides/contributing.md"
},
"body": "Thank you for your interest in contributing to DoneJS! DoneJS is maintained by [the core team](./About.html#section=section_Team) but depends on contributors like you! Whether you’re interested in [fixing issues](#finding-open-issues), [answering questions](#getting-involved-in-the-community), or [spreading the word](#evangelism), we welcome you to our community!\n\nContributing to an open source project can be an intimidating experience. We’re committed to making it as pleasant and rewarding as possible. Please always feel free to reach out to us on\n[Slack](https://www.bitovi.com/community/slack) ([#donejs channel](https://bitovi-community.slack.com/messages/CFC80DU5B)).\n\n<a id=\"section=section_CodeofConduct\"></a>\n## Code of Conduct\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to make participation in our project and community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.\n\n[Please read our Code of Conduct in its entirety before participating in our community.](https://github.com/donejs/donejs/blob/master/CODE_OF_CONDUCT.md)\n\n<a id=\"section=section_GettingHelp\"></a>\n## Getting Help\n\n[Our forums](https://forums.bitovi.com/) and [Slack](https://www.bitovi.com/community/slack)\nare the best places to ask questions. The core team regularly checks both and there are other users who generously help others.\n\nIf you’re interested in contributing to DoneJS, the core team is happy to pair with you to fix a bug or write a new feature!\nPlease either message us on Slack or the forums, or leave a comment on the GitHub issue you’re interested in helping with. We will happily walk you through setting up your development environment, creating a test and/or writing documentation, and submitting a pull request.\n\n<a id=\"section=section_ProjectOrganization\"></a>\n## Project Organization\n\nAt its core, DoneJS is a CLI tool that generates an application structure with a number of projects that are built to work together.\n\nThe following projects are a core part of DoneJS:\n\n- [CanJS](https://canjs.com/)\n- [DocumentJS](https://documentjs.com/)\n- [FuncUnit](https://funcunit.com/)\n- [jQuery++](https://jquerypp.com/)\n- [StealJS](https://stealjs.com/)\n- [Syn](https://github.com/bitovi/syn)\n- [Testee](https://github.com/bitovi/testee)\n\nHere are the DoneJS projects that glue things together and add additional functionality:\n\n- [autorender](https://github.com/donejs/autorender)\n- [cli](https://github.com/donejs/cli)\n- [css](https://github.com/donejs/css)\n- [deploy](https://github.com/donejs/deploy)\n- [component](https://github.com/donejs/done-component)\n- [done-serve](https://github.com/donejs/done-serve)\n- [done-ssr](https://github.com/donejs/done-ssr)\n- [done-ssr-middleware](https://github.com/donejs/done-ssr-middleware)\n- [donejs](https://github.com/donejs/donejs)\n- [donejs-connect-model](https://github.com/donejs/donejs-connect-model)\n- [donejs-cordova](https://github.com/donejs/donejs-cordova)\n- [donejs-documentjs](https://github.com/donejs/donejs-documentjs)\n- [donejs-electron](https://github.com/donejs/donejs-electron)\n- [donejs-feathers](https://github.com/donejs/donejs-feathers)\n- [donejs-firebase](https://github.com/donejs/donejs-firebase)\n- [donejs-jasmine](https://github.com/donejs/donejs-jasmine)\n- [donejs-jshint](https://github.com/donejs/donejs-jshint)\n- [donejs-mocha](https://github.com/donejs/donejs-mocha)\n- [donejs-nw](https://github.com/donejs/donejs-nw)\n- [donejs-react](https://github.com/donejs/donejs-react)\n- [donejs-vagrant](https://github.com/donejs/donejs-vagrant)\n- [generator-donejs](https://github.com/donejs/generator-donejs)\n- [worker-autorender](https://github.com/donejs/worker-autorender)\n\n<a id=\"section=section_ReportingBugs\"></a>\n## Reporting Bugs\n\nDoneJS uses [GitHub Issues](https://github.com/donejs/donejs/issues) to track bugs. As noted [above](#project-organization), DoneJS is made up of many individual GitHub repositories. Ideally, bugs are created within the\nrepository whose code is causing the issue. For example, if you’re having issues with the development server, you can create an issue at [donejs/done-serve/issues/new](https://github.com/donejs/done-serve/issues/new?labels=bug).\n\nIf you do not know which repository your issue belongs to, that’s okay! Please\ncreate your issue in\n[the main DoneJS repo](https://github.com/donejs/donejs/issues/new?labels=bug). The core team will\nmove the issue to the correct repository (if necessary).\n\nWhen creating an issue, it’s helpful to include:\n\n- How often you can reproduce it.\n- A detailed description of the issue with specific details to help us understand the problem.\n- A list of the steps to reproduce the issue.\n- What actually happened versus what you expected to have happen.\n- Details about your environment, including the version of DoneJS, Node.js, and npm you’re using.\n\nBefore filing a new issue, please search for previous tickets. If there’s something similar, add to that, or\ngive it a 👍. If you can provide additional information that’s not already in the issue, please add a comment to it.\n\nIf you are unsure about any of this or have any other questions, please reach out to\nus on the [Bitovi forums](https://forums.bitovi.com/c/donejs) or talk to us on\n[Slack](https://www.bitovi.com/community/slack) (in the [#donejs channel](https://bitovi-community.slack.com/messages/CFC80DU5B)).\nWe’re happy to discuss any bugs and help you file a bug report.\n\n<a id=\"section=section_SuggestingFeatures\"></a>\n## Suggesting Features\n\nDoneJS uses [GitHub Issues](https://github.com/donejs/donejs/issues) to track feature suggestions. As noted [above](#project-organization), DoneJS is made up of many individual GitHub repositories. Ideally, feature suggestions are created within the\nrepository whose code could be improved. For example, if you have a suggestion related to the development server, you can create an issue at [donejs/done-serve/issues/new](https://github.com/donejs/done-serve/issues/new?labels=enhancement).\n\nIf you do not know which repository your issue belongs to, that’s okay! Please\ncreate your issue in\n[the main DoneJS repo](https://github.com/donejs/donejs/issues/new?labels=enhancement). The core team will\nmove the issue to the correct repository (if necessary).\n\nWhen filing a feature suggestion, it’s very helpful to include:\n\n- Examples of what using the feature will look like.\n- Benefits and drawbacks of the feature.\n- Why the feature is important.\n- Any implementation details around the feature.\n\nBefore filing a new suggestion, please search for previous feature requests. If there’s something similar, add to that, or\ngive it a 👍. If you have additional ideas that are not already in the issue, please add a comment to it.\n\nIf you are unsure about any of this or have any other questions, please reach out to\nus on the [Bitovi forums](https://forums.bitovi.com/c/donejs) or talk to us on\n[Slack](https://www.bitovi.com/community/slack) (in the [#donejs channel](https://bitovi-community.slack.com/messages/CFC80DU5B)).\nWe’re happy to discuss any ideas and help you file a feature suggestion.\n\n<a id=\"section=section_FindingWaystoContribute\"></a>\n## Finding Ways to Contribute\n\nThere are many ways to contribute to DoneJS, whether you’re a developer who wants to code, a designer who can help improve the design and usability of our projects, or someone who’s interested in helping other members of the community.\n\n<a id=\"section=section_Findingopenissues\"></a>\n### Finding open issues\n\nDoneJS uses [GitHub Issues](https://github.com/donejs/donejs/issues) to track improvements we want to make to the project, whether that’s bug fixes, new features, design improvements, etc.\n\nWe use a few labels to organize issues across all of the repositories:\n\n- “help wanted” for any issues with which the core team would like help\n- “easy” for issues the core team thinks are good for someone who’s new to contributing\n- “documentation” for issues related to documenting the APIs\n- “design” for issues that could use a designer’s expertise\n- “p0”, “p1”, “p2”, etc. for prioritizing issues\n\nHere are links to GitHub searches for those terms:\n\n- DoneJS\n\t- [design](https://github.com/search?q=org%3Adonejs+label%3Adesign&state=open)\n\t- [documentation](https://github.com/search?q=org%3Adonejs+label%3Adocumentation&state=open)\n\t- [easy](https://github.com/search?q=org%3Adonejs+label%3Aeasy&state=open)\n\t- [help wanted](https://github.com/search?q=org%3Adonejs+label%3A%22help+wanted%22&state=open)\n\t- [p0](https://github.com/search?q=org%3Adonejs+label%3Ap0&state=open), [p1](https://github.com/search?q=org%3Adonejs+label%3Ap1&state=open), [p2](https://github.com/search?q=org%3Adonejs+label%3Ap2&state=open), [p3](https://github.com/search?q=org%3Adonejs+label%3Ap3&state=open), & [p4](https://github.com/search?q=org%3Adonejs+label%3Ap4&state=open)\n- CanJS\n\t- [design](https://github.com/search?q=org%3Acanjs+label%3Adesign&state=open)\n\t- [documentation](https://github.com/search?q=org%3Acanjs+label%3Adocumentation&state=open)\n\t- [easy](https://github.com/search?q=org%3Acanjs+label%3Aeasy&state=open)\n\t- [help wanted](https://github.com/search?q=org%3Acanjs+label%3A%22help+wanted%22&state=open)\n\t- [p0](https://github.com/search?q=org%3Acanjs+label%3Ap0&state=open), [p1](https://github.com/search?q=org%3Acanjs+label%3Ap1&state=open), [p2](https://github.com/search?q=org%3Acanjs+label%3Ap2&state=open), [p3](https://github.com/search?q=org%3Acanjs+label%3Ap3&state=open), & [p4](https://github.com/search?q=org%3Acanjs+label%3Ap4&state=open)\n- DocumentJS\n\t- [design](https://github.com/bitovi/documentjs/labels/design)\n\t- [documentation](https://github.com/bitovi/documentjs/labels/documentation)\n\t- [easy](https://github.com/bitovi/documentjs/labels/easy)\n\t- [help wanted](https://github.com/bitovi/documentjs/labels/help%20wanted)\n\t- [p0](https://github.com/bitovi/documentjs/labels/p0), [p1](https://github.com/bitovi/documentjs/labels/p1), [p2](https://github.com/bitovi/documentjs/labels/p2), [p3](https://github.com/bitovi/documentjs/labels/p3), & [p4](https://github.com/bitovi/documentjs/labels/p4)\n- FuncUnit\n\t- [design](https://github.com/bitovi/funcunit/labels/design)\n\t- [documentation](https://github.com/bitovi/funcunit/labels/documentation)\n\t- [easy](https://github.com/bitovi/funcunit/labels/easy)\n\t- [help wanted](https://github.com/bitovi/funcunit/labels/help%20wanted)\n\t- [p0](https://github.com/bitovi/funcunit/labels/p0), [p1](https://github.com/bitovi/funcunit/labels/p1), [p2](https://github.com/bitovi/funcunit/labels/p2), [p3](https://github.com/bitovi/funcunit/labels/p3), & [p4](https://github.com/bitovi/funcunit/labels/p4)\n- jQuery++\n\t- [design](https://github.com/bitovi/jquerypp/labels/design)\n\t- [documentation](https://github.com/bitovi/jquerypp/labels/documentation)\n\t- [easy](https://github.com/bitovi/jquerypp/labels/easy)\n\t- [help wanted](https://github.com/bitovi/jquerypp/labels/help%20wanted)\n\t- [p0](https://github.com/bitovi/jquerypp/labels/p0), [p1](https://github.com/bitovi/jquerypp/labels/p1), [p2](https://github.com/bitovi/jquerypp/labels/p2), [p3](https://github.com/bitovi/jquerypp/labels/p3), & [p4](https://github.com/bitovi/jquerypp/labels/p4)\n- StealJS\n\t- [design](https://github.com/search?q=org%3Astealjs+label%3Adesign&state=open)\n\t- [documentation](https://github.com/search?q=org%3Astealjs+label%3Adocumentation&state=open)\n\t- [easy](https://github.com/search?q=org%3Astealjs+label%3Aeasy&state=open)\n\t- [help wanted](https://github.com/search?q=org%3Astealjs+label%3A%22help+wanted%22&state=open)\n\t- [p0](https://github.com/search?q=org%3Astealjs+label%3Ap0&state=open), [p1](https://github.com/search?q=org%3Astealjs+label%3Ap1&state=open), [p2](https://github.com/search?q=org%3Astealjs+label%3Ap2&state=open), [p3](https://github.com/search?q=org%3Astealjs+label%3Ap3&state=open), & [p4](https://github.com/search?q=org%3Astealjs+label%3Ap4&state=open)\n- Syn\n\t- [design](https://github.com/bitovi/syn/labels/design)\n\t- [documentation](https://github.com/bitovi/syn/labels/documentation)\n\t- [easy](https://github.com/bitovi/syn/labels/easy)\n\t- [help wanted](https://github.com/bitovi/syn/labels/help%20wanted)\n\t- [p0](https://github.com/bitovi/syn/labels/p0), [p1](https://github.com/bitovi/syn/labels/p1), [p2](https://github.com/bitovi/syn/labels/p2), [p3](https://github.com/bitovi/syn/labels/p3), & [p4](https://github.com/bitovi/syn/labels/p4)\n- Testee\n\t- [design](https://github.com/bitovi/testee/labels/design)\n\t- [documentation](https://github.com/bitovi/testee/labels/documentation)\n\t- [easy](https://github.com/bitovi/testee/labels/easy)\n\t- [help wanted](https://github.com/bitovi/testee/labels/help%20wanted)\n\t- [p0](https://github.com/bitovi/testee/labels/p0), [p1](https://github.com/bitovi/testee/labels/p1), [p2](https://github.com/bitovi/testee/labels/p2), [p3](https://github.com/bitovi/testee/labels/p3), & [p4](https://github.com/bitovi/testee/labels/p4)\n\nTriaging issues that have no labels is also really helpful! Here are some searches you can use to find unlabeled issues:\n\n- [DoneJS](https://github.com/search?q=org%3Adonejs+is%3Aissue+no%3Alabel&state=open)\n- [CanJS](https://github.com/search?q=org%3Acanjs+is%3Aissue+no%3Alabel&state=open)\n- [DocumentJS](https://github.com/bitovi/documentjs/issues?q=is%3Aopen+is%3Aissue+no%3Alabel)\n- [FuncUnit](https://github.com/bitovi/funcunit/issues?q=is%3Aopen+is%3Aissue+no%3Alabel)\n- [jQuery++](https://github.com/bitovi/jquerypp/issues?q=is%3Aopen+is%3Aissue+no%3Alabel)\n- [StealJS](https://github.com/search?q=org%3Astealjs+is%3Aissue+no%3Alabel&state=open)\n- [Syn](https://github.com/bitovi/syn/issues?q=is%3Aopen+is%3Aissue+no%3Alabel)\n- [Testee](https://github.com/bitovi/testee/issues?q=is%3Aopen+is%3Aissue+no%3Alabel)\n\n<a id=\"section=section_Gettinginvolvedinthecommunity\"></a>\n### Getting involved in the community\n\nYou can also get involved in our community by posting in our forums, chatting with us on Slack, and answering questions on Stack Overflow.\n\n- DoneJS\n\t- [Forums](https://forums.bitovi.com/c/donejs)\n\t- [Slack](https://www.bitovi.com/community/slack) ([#donejs channel](https://bitovi-community.slack.com/messages/CFC80DU5B))\n\t- [Stack Overflow](https://stackoverflow.com/search?tab=newest&q=donejs+answers:0)\n- CanJS\n\t- [Forums](https://forums.bitovi.com/c/canjs)\n\t- [Slack](https://www.bitovi.com/community/slack) ([#canjs channel](https://bitovi-community.slack.com/messages/CFC22NZ8A))\n\t- [Stack Overflow](https://stackoverflow.com/search?tab=newest&q=canjs+answers:0)\n- DocumentJS\n\t- [Forums](https://forums.bitovi.com/c/documentjs)\n\t- [Slack](https://www.bitovi.com/community/slack)\n\t- [Stack Overflow](https://stackoverflow.com/search?tab=newest&q=documentjs+answers:0)\n- FuncUnit\n\t- [Slack](https://www.bitovi.com/community/slack)\n\t- [Stack Overflow](https://stackoverflow.com/search?tab=newest&q=funcunit+answers:0)\n- jQuery++\n\t- [Stack Overflow](https://stackoverflow.com/search?tab=newest&q=jquerypp+answers:0)\n- StealJS\n\t- [Forums](https://forums.bitovi.com/c/stealjs)\n\t- [Slack](https://www.bitovi.com/community/slack) ([#stealjs channel](https://bitovi-community.slack.com/messages/CFDDX9MJS))\n\t- [Stack Overflow](https://stackoverflow.com/search?tab=newest&q=stealjs+answers:0)\n- Syn\n\t- [Slack](https://www.bitovi.com/community/slack)\n- Testee\n\t- [Slack](https://www.bitovi.com/community/slack)\n\n<a id=\"section=section_Spreadingtheword\"></a>\n### Spreading the word\n\nWe also always need help spreading the word about the DoneJS projects. Check out the [evangelism section](#evangelism) on how you can [write a blog post](#writing-a-blog-article), [speak at a conference](#speaking-at-a-conference-or-meetup), or [organize a meetup](#organizing-a-donejs-meetup).\n\n<a id=\"section=section_DevelopingLocally\"></a>\n## Developing Locally\n\nThis section will walk you through setting up the [main DoneJS repository](https://github.com/donejs/donejs) on your computer. Remember that DoneJS is [split into multiple repositories](#project-organization), but you can apply the same general steps to set up any of the other repos.\n\n<a id=\"section=section_SigningupforGitHub\"></a>\n### Signing up for GitHub\n\nIf you don’t already have a GitHub account, you’ll need to [create a new one](https://help.github.com/articles/signing-up-for-a-new-github-account/).\n\n<a id=\"section=section_Forking_cloningtherepository\"></a>\n### Forking and cloning the repository\n\nA “fork” is a copy of a repository in your personal GitHub account. “Cloning” is the process of getting the repository’s source code on your computer.\n\nGitHub has a guide for [forking a repo](https://help.github.com/articles/fork-a-repo/). To fork DoneJS, you can start by going to its [fork page](https://github.com/donejs/donejs/fork).\n\nNext, you’ll want to clone the repo. [GitHub’s cloning guide](https://help.github.com/articles/cloning-a-repository/) explains how to do this on Linux, Mac, or Windows.\n\nGitHub’s guide will [instruct you](https://help.github.com/articles/fork-a-repo/#step-2-create-a-local-clone-of-your-fork) to clone it with a command like:\n\n```shell\ngit clone https://github.com/YOUR-USERNAME/donejs\n```\n\nMake sure you replace `YOUR-USERNAME` with your GitHub username.\n\n<a id=\"section=section_Installingthedependencies\"></a>\n### Installing the dependencies\n\nAfter you’ve [forked & cloned the repository](#forking-and-cloning-the-repository), you’ll need to install the project’s dependencies.\n\nFirst, make sure you’ve [installed Node.js and npm](https://docs.npmjs.com/getting-started/installing-node).\n\nIf you just cloned the repo from the command line, you’ll want to switch to the folder with your clone:\n\n```shell\ncd donejs\n```\n\nNext, install the project’s dependencies with npm:\n\n```shell\nnpm install\n```\n\n<a id=\"section=section_Runningthetests\"></a>\n### Running the tests\n\nFirefox is used to run the repository’s tests. If you don’t already have it, [download Firefox](https://www.mozilla.org/en-US/firefox/new/). Mozilla has guides for installing it on [Linux](https://support.mozilla.org/t5/Install-and-Update/Install-Firefox-on-Linux/ta-p/2516), [Mac](https://support.mozilla.org/t5/Install-and-Update/How-to-download-and-install-Firefox-on-Mac/ta-p/3453), and [Windows](https://support.mozilla.org/t5/Install-and-Update/How-to-download-and-install-Firefox-on-Windows/ta-p/2210).\n\nAfter Firefox is installed, you can run:\n\n```shell\nnpm test\n```\n\nIf every test passed, congratulations! You have everything you need to change the code and have the core team review it.\n\n<a id=\"section=section_Buildingthedocumentation\"></a>\n### Building the documentation\n\nThe [main DoneJS repo](https://github.com/donejs/donejs) contains [DoneJS.com](https://donejs.com/).\n\nTo build the site, run:\n\n```shell\nnpm run document\n```\n\n[`npm run`](https://docs.npmjs.com/cli/run-script) will look for the `document` script in the repository’s [`package.json`](https://github.com/donejs/donejs/blob/master/package.json) and run it.\n\n<a id=\"section=section_Viewingthesite\"></a>\n### Viewing the site\n\nAfter you [build the docs](#building-the-documentation), your `donejs` repository will contain a `site` folder with the website.\n\nTo view the site, we recommend you install [http-server](https://www.npmjs.com/package/http-server).\n\n```shell\nnpm install http-server -g\n```\n\nAfter it’s installed, you can start a server for the `site` directory:\n\n```shell\nhttp-server site\n```\n\n`http-server` will tell you where you can go in your browser to see the site. It will be something like [http://127.0.0.1:8080].\n\n<a id=\"section=section_ChangingtheCode\"></a>\n## Changing the Code\n\nNow that your computer is set up to [develop DoneJS locally](#developing-locally), you can make changes in your local repository.\n\nThe DoneJS projects generally follow the [GitHub flow](https://help.github.com/articles/github-flow/). This section will briefly explain how you can make changes on your computer and submit a pull request to have those changes merged into the main project.\n\n<a id=\"section=section_Creatinganewbranch\"></a>\n### Creating a new branch\n\nStarting in the DoneJS repository you have cloned to your computer, you can create a new branch:\n\n```shell\ngit checkout -b your-branch-name\n```\n\nReplace `your-branch-name` with the name of your feature branch. You can name the feature branch whatever you’d like. We recommend starting the name with the issue number and a few words related to the issue. For example, for [#295 “Make a contribution guide”](https://github.com/donejs/donejs/issues/295), `295-contribution-guide` is an appropriate branch name.\n\n<a id=\"section=section_Styleguide\"></a>\n### Style guide\n\nWhere possible, our code generally follows [jQuery’s coding conventions](https://contribute.jquery.org/style-guide/js/).\n\n<a id=\"section=section_Updatingtests\"></a>\n### Updating tests\n\nThe [`test` directory](https://github.com/donejs/donejs/tree/master/test) contains files related to testing the code in the repository. When fixing bugs or writing new features, you should update the existing tests or create new tests to cover your changes.\n\nAfter updating the tests, make sure you [run the tests](#running-the-tests).\n\n<a id=\"section=section_Updatingthedocumentation\"></a>\n### Updating the documentation\n\nThe [`docs`](https://github.com/donejs/donejs/tree/master/docs) and [`guides`](https://github.com/donejs/donejs/tree/master/guides) directories contain the files used to generate [DoneJS.com](https://donejs.com/).\n\nAfter making changes, make sure you [build the documentation](#building-the-documentation).\n\n<a id=\"section=section_Submittingapullrequest\"></a>\n### Submitting a pull request\n\nOnce you’ve made your changes and [run the tests](#running-the-tests), you can push your branch to GitHub:\n\n```shell\ngit push origin your-branch-name\n```\n\nMake sure you replace `your-branch-name` with the name of your branch.\n\nNext, go to the DoneJS repository’s [compare changes](https://github.com/donejs/donejs/compare) page and click on “compare across forks.” You’ll need to change the “head fork” to your repository and select your branch name.\n\nAfter you’ve selected your forked repository and branch, you can click on “Create pull request”. Give your PR a meaningful title and provide details about the change in the description, including a link to the issue(s) your PR addresses. If applicable, please include a screenshot or gif to demonstrate your change. This makes it easier for reviewers to verify that it works for them. [LICEcap](http://www.cockos.com/licecap/) is a great tool for making gifs.\n\nOnce you’ve filled out your pull request’s details, click on “Create pull request”. The core team will receive a notification about your pull request and will provide feedback.\n\nGitHub has additional documentation on [creating a pull request from a fork](https://help.github.com/articles/creating-a-pull-request-from-a-fork/) that you might find useful.\n\n<a id=\"section=section_UpdatingDoneJS_com\"></a>\n## Updating DoneJS.com\n\n[DoneJS.com](https://donejs.com/) is hosted on [GitHub pages](https://pages.github.com/) from the [`gh-pages`](https://github.com/donejs/donejs/tree/gh-pages) branch.\n\nFirst, from within your local DoneJS repository, create a new clone in the `site` folder:\n\n```shell\ngit clone git@github.com:donejs/donejs.git -b gh-pages site/\n```\n\nIf you get an error saying `Permission denied (publickey)` then you should follow GitHub’s instructions on\n[generating an SSH key](https://help.github.com/articles/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent/).\n\nInstall the dependencies, build the site, and push a new commit to the `gh-pages` branch with:\n\n```shell\nmake\n```\n\nThat’s it! [DoneJS.com](https://donejs.com/) should now have your changes.\n\n<a id=\"section=section_Evangelism\"></a>\n## Evangelism\n\nHopefully you love DoneJS as much as we do and you want to share your\nknowledge about it. Fantastic! We want to help you.\n\nThere are lots of ways to spread the word about DoneJS, including:\n\n - Writing a blog article\n - Speaking at a conference or meetup\n - Organizing a DoneJS meetup\n\nNo matter what you’re interested in, please [email Chasen Le Hara](mailto:chasen@bitovi.com) so he can help promote you and what you’re doing.\n\n<a id=\"section=section_Writingablogarticle\"></a>\n### Writing a blog article\n\nIf you’re writing something about DoneJS and would like the core team to review it,\nwe’re happy to help. Once it’s published, let us know so we can promote it.\n\n<a id=\"section=section_Speakingataconferenceormeetup\"></a>\n### Speaking at a conference or meetup\n\nThe [presentations list](./presentations.html) contains a variety of talks related to the DoneJS projects.\n\n<a id=\"section=section_OrganizingaDoneJSmeetup\"></a>\n### Organizing a DoneJS meetup\n\nThere are several local DoneJS groups:\n\n - [Boston](https://www.meetup.com/DoneJS-Boston/)\n - [Chicago](https://www.meetup.com/DoneJS-Chicago/)\n - [Ft. Lauderdale](https://www.meetup.com/DoneJS-Fort-Lauderdale/)\n - [Los Angeles](https://www.meetup.com/DoneJS-LA/)\n - [New York](https://www.meetup.com/DoneJS-NYC/)\n - [Phoenix](https://www.meetup.com/DoneJS-Phoenix/)\n - [Raleigh-Durham](https://www.meetup.com/DoneJS-raleigh-durham/)\n - [San Francisco](https://www.meetup.com/DoneJS-San-Francisco/)\n - [Seattle](https://www.meetup.com/DoneJS-Seattle/)\n - [Silicon Valley](https://www.meetup.com/DoneJS-Silicon-Valley/)\n\nWe’re always looking for people to speak at one of these groups, become an organizer,\nor start their own group. If you are interested in any of these things,\nplease let us know!\n\n",
"description": "\n",
"name": "contributing",
"title": "Contributing",
"type": "page",
"parent": "Guides",
"hideSidebar": true,
"outline": {
"depth": 2,
"tag": "ol"
},
"comment": " "
},
"generator": {
"src": {
"path": "docs/guides/generator.md"
},
"body": "\nIf you have used `donejs add nw` or `donejs add cordova` to create a [desktop or mobile version](./Features.html#ios-android-and-desktop-builds) of your application you already used a DoneJS generator. Generators are [npm](https://www.npmjs.com/) modules that provide a [Yeoman](http://yeoman.io/) generator that adds functionality to your application.\n\nIn this guide you will create your own version of [donejs-jshint](https://www.npmjs.com/package/donejs-jshint), a DoneJS generator that adds:\n\n- [JSHint](http://jshint.com/), a JavaScript code quality tool\n- A [.editorconfig](http://editorconfig.org/) file which helps text editors and IDEs to define and maintain a consistent coding style.\n\nIt will also update the `npm test` script to run JSHint with our tests. You can find the code in the [donejs-jshint](https://github.com/donejs/donejs-jshint) repository. We can run the generator with:\n\n\n $ donejs add jshint\n\n\nCurrently it will only ask if we want to use spaces or tabs and to overwrite the `package.json` to add the npm scripts for JSHint:\n\n<img src=\"static/img/donejs-generator-use.png\" alt=\"DoneJS generator\" style=\"width: 100%;\" class=\"alignnone size-full wp-image-3023\" />\n\n> __Note:__ Since `donejs-jshint` already exists we will use `donejs-<username>-jshint` with `<username>` being your GitHub username for the remainder of this article. Once published it can then be used as `donejs add <username>-jshint`.\n\n\n## Setting up\n\n### Creating the project on GitHub\n\nWe will use [GitHub](https://github.com) to host the code for the project which makes it easy for others to contribute and to automatically run the tests in [continuous integration](https://en.wikipedia.org/wiki/Continuous_integration) which we will enable later.\n\nIf you don't have an account yet, go to [GitHub](https://github.com/join) to sign up and follow [the help](https://help.github.com/articles/set-up-git/) on how to set it up for the command-line `git`. Once completed, create a new repository from your dashboard.\n\nCalling the repository `donejs-<username>-jshint` and initializing it empty (without any of the default files) looks like this:\n\n<img src=\"static/img/donejs-generator-initialize.png\" alt=\"generator-repository\" style=\"width: 100%;\" class=\"alignnone size-full wp-image-3077\" />\n\nAfter creating the repository, clone it into a new folder:\n\n\n $ git clone git@github.com:<username>/donejs-<username>-jshint.git\n $ cd donejs-<username>-jshint\n\n\n### Initializing the project\n\nTo initialize a new generator you will need DoneJS version 0.9.0+ installed globally. To check your DoneJS version run\n\n\n $ donejs --version\n\n\nTo install DoneJS or to get the latest version run:\n\n\n $ npm install donejs -g \n\n\nIn the `donejs-<username>-jshint` folder we can now initialize a new generator, very similar to a new DoneJS application, like this:\n\n\n $ donejs add generator\n\n\nThe generator will ask several question that should be answered as follows:\n\n* For the project name you can just confirm the default by pressing enter\n* For the GitHub username or organization enter the GitHub username where the repository has been created\n* All other fields can also be answered with the default or the information you would like to use\n\nOnce all done, the final prompt looks similar to this:\n\n<img src=\"static/img/donejs-generator-add.png\" alt=\"generator-init\" style=\"width: 100%;\" class=\"alignnone size-full wp-image-3050\" />\n\nNow the generator will initialize the default layout and install all its dependencies.\n\n### Setting up Travis CI\n\nWhen the installation has completed, make sure everything got set up properly by running:\n\n\n $ npm test\n\n\nThis will run some basic generator tests and output the result on the console.\n\nThis command can also be used to automatically run the tests on a [continuous integration](https://en.wikipedia.org/wiki/Continuous_integration) server. There are many open source CI servers, the most popular being [Jenkins](https://jenkins-ci.org/), and many hosted solutions like [Travis CI](https://travis-ci.org/).\n\nWe will use Travis CI as our hosted solution because it is free for open source projects. It works with your GitHub account which it will use to sign up. Once signed in, go to `Accounts` (in the dropdown under you name) to enable the `donejs-<username>-jshint` repository:\n\n<img src=\"static/img/donejs-generator-travis.png\" alt=\"generator-travis\" style=\"width: 100%;\" class=\"alignnone size-full wp-image-3054\" />\n\nYou may have to click the *\"Sync account\"* button for the repository to show up. Now, every time we push to GitHub the tests will run automatically. We can do so with our initial commit:\n\n\n $ git add . --all\n $ git commit -am \"Initial commit\"\n $ git push origin master\n\n\nIf you now go `https://travis-ci.org/<your-username>/donejs-<username>-jshint/builds` you will see the build running and eventually turn green (which will update the badge that got added in the `readme.md` file).\n\n\n## Adding the configuration files\n\nNow we can add the files that our generator should produce. All file templates will be put in the `default/templates/` folder.\n\n### .jshintrc\n\nFirst, add a `default/templates/.jshintrc` file which contains [options for JSHint](http://jshint.com/docs/options/):\n\n\n {\n \"node\": true,\n \"esnext\": true,\n \"bitwise\": true,\n \"camelcase\": true,\n \"curly\": true,\n \"eqeqeq\": true,\n \"immed\": true,\n \"indent\": 2,\n \"latedef\": \"nofunc\",\n \"newcap\": false,\n \"noarg\": true,\n \"regexp\": true,\n \"undef\": true,\n \"unused\": true,\n \"strict\": false,\n \"trailing\": true,\n \"smarttabs\": true,\n \"white\": false\n }\n\n\n### .editorconfig\n\nNext add a `default/templates/.editorconfig` file like this:\n\n\n ; Unix-style newlines\n [*]\n end_of_line = LF\n indent_style = <%= indent_style %>\n trim_trailing_whitespace = true\n\n\nAll files support [EJS](http://www.embeddedjs.com/) placeholders. Here, `<%= indent_style %>` will be used for the user choice of using whitespaces or tabs. Finally, remove `defaults/templates/file.js` since we won't be using it.\n\n\n## Implementing the generator\n\nFor the most part, DoneJS generators are simply [Yeoman](http://yeoman.io/) generators so everything documented for [writing your own Yeoman generator](http://yeoman.io/authoring/) also applies here. For the user choice of tabs vs. spaces also refer to the chapter about [interacting with the user](http://yeoman.io/authoring/user-interactions.html).\n\n### Adding the generator functionality\n\nOur generator needs to ask if we want to use spaces or tabs and then copy the `.jshintrc` and `.editorconfig` files over to their final destination. We also want to add an `npm run jshint` script to the `package.json` and make sure that JSHint runs during `npm test`. The complete generator at `default/index.js` looks like this:\n\n\n\n var Generator = require('yeoman-generator');\n var _ = require('lodash');\n\n module.exports = Generator.extend({\n initializing: function () {\n // Read the original package.json\n this.pkg = this.fs.readJSON(\n this.destinationPath('package.json'), {}\n );\n\n // Maintain a list of all files we want to copy over\n this.files = [\n '.editorconfig',\n '.jshintrc'\n ];\n },\n\n prompting: function () {\n var done = this.async();\n\n // Create a prompt setting the `indent_style` property\n // to `tab` or `space`\n this.prompt([{\n type: 'list',\n name: 'indent_style',\n message: 'What indentation style do you want to use?',\n default: 'tab',\n choices: [\n {\n name: 'Tabs',\n value: 'tab'\n },\n {\n name: 'Spaces',\n value: 'space'\n }\n ]\n }]).then(function (answers) {\n this.props = answers;\n done();\n }.bind(this));\n },\n\n writing: function () {\n var pkg = this.pkg;\n\n // Update `package.json` with the `jshint` command\n // and update the `test` script\n pkg.scripts = _.extend(pkg.scripts, {\n test: 'npm run jshint && ' +\n _.get(pkg, 'scripts.test',\n 'echo \"No tests specified\"'),\n jshint: 'jshint ' +\n _.get(pkg, 'system.directories.lib',\n 'src') +\n '/. --config'\n });\n\n // Write to `package.json` and format accordingly\n // This will prompt you to overwrite\n var indent = this.props.index === 'tab' ? '\\t' : ' ';\n this.fs.writeJSON('package.json', pkg, null, indent);\n\n // Install jshint as a development dependency\n this.npmInstall([ 'jshint' ], { saveDev: true});\n\n // Got through every file and copy it\n this.files.forEach(function(file) {\n this.fs.copyTpl(\n this.templatePath(file),\n this.destinationPath(file),\n this.props\n );\n }.bind(this));\n }\n });\n\n\nThat's it. Now we have a fully functional generator and can give it a try in a DoneJS application.\n\n### Manual testing\n\nWhen running `donejs add <generatorname>` DoneJS will\n\n- Check if `donejs-<generatorname>` is installed locally\n- If not, install it from npm\n- Then run the generator at `default/index.js`\n\nIf we want to test our generator without publishing it to npm first we can link it instead. In the generator folder run:\n\n\n $ npm link\n\n\nThen go into your test DoneJS application directory:\n\n\n $ cd ../place-my-order\n $ npm link donejs-<username>-jshint\n\n\nNow we can run\n\n\n $ donejs add <username>-jshint\n\n\n### Writing a unit test\n\nYeoman also comes with some tools for [testing generators](http://yeoman.io/authoring/testing.html). The test we initially ran with `npm test` makes sure that `default/templates/file.js` gets written. Since we deleted that file, update the test at `test/index.js` to verify that it wrote the files we want with the content we expect:\n\n\n var path = require('path');\n var helpers = require('yeoman-test');\n var assert = require('yeoman-assert');\n\n describe('donejs-<username>-jshint', function() {\n before(function(done) {\n // Run the generator in a temporary directory\n helpers.run(path.join(__dirname, '../default'))\n .inTmpDir()\n // Mock the user input by setting\n // `indent_style` to `tab`\n .withPrompts({\n 'indent_style': 'tab'\n }).on('end', done);\n });\n\n // Verify that `.jshintrc` got written\n // and has some content\n it('created .jshintrc', function() {\n assert.file(['.jshintrc']);\n assert.fileContent('.jshintrc',\n /\"latedef\": \"nofunc\"/);\n });\n\n // Verify that `.editorconfig` got written\n // with `indent_style` set to our selection\n it('.editorconfig with indent_style', function() {\n assert.file(['.editorconfig']);\n assert.fileContent('.editorconfig',\n /indent_style = tab/);\n });\n\n // Make sure that `package.json` got updated\n // with the `jshint` npm script\n it('update package.json', function() {\n assert.jsonFileContent('package.json', {\n scripts: {\n jshint: 'jshint src/. --config'\n }\n });\n });\n });\n\n\nNow we can see all tests passing when running:\n\n\n $ npm test\n\n\n\n## Publishing the plugin\n\n### Making a pull request\n\nAlthough we are working on the generator by ourselves for now, [GitHub pull requests](https://help.github.com/articles/using-pull-requests/) are a great way to keep track of our progress and to make sure that all tests are passing. In the plugin folder run:\n\n\n $ git checkout -b generator-functionality\n $ git add . --all\n $ git commit -m \"Implementing JSHint and editorconfig generator\"\n $ git push origin generator-functionality\n\n\nAnd then create a new pull request by going to `https://github.com/<username>/donejs-<username>-jshint` which will now show an option like this:\n\n<img src=\"http://www.bitovi.com/hubfs/Imported_Blog_Media/generator-pr.png\" alt=\"generator-pr\" style=\"width: 100%;\" class=\"alignnone size-full wp-image-3055\" />\n\nOnce you created the pull request, you will see a `Some checks haven’t completed yet` message that will eventually turn green:\n\n<img src=\"static/img/donejs-generator-pr.png\" alt=\"generator-pull-request\" style=\"width: 100%;\" class=\"alignnone size-full wp-image-3056\" />\n\nNow you can click the \"Merge pull request\" button. Then in the console, checkout the *master* branch and pull down the latest changes with:\n\n\n $ git checkout master\n $ git pull origin master\n\n\n\n### Publishing to npm\n\nFor others to be able to use your generator via `donejs add <generatorname>` you have to publish it to [npm](http://npmjs.org). [Create a new account](https://www.npmjs.com/signup) and then log in via\n\n\n $ npm login\n\n\n[Semantic versioning](http://semver.org/) is a great way to communicate new features and breaking changes. The generated plugin already comes with the release scripts to publish new versions according to the `major.minor.patch` schema. In our case to publish an initial version `0.1.0` we can run\n\n\n $ donejs release:minor\n\n\nNow version `0.1.0` of the generator is available and everybody can use it through\n\n\n donejs add <username>-jshint\n\n\n## Show it off\n\nOnce you published your generator, let the world know about it. [Tweet @donejs](https://twitter.com/donejs) and post it in the [Bitovi forums](https://forums.bitovi.com/) and our [Slack](https://www.bitovi.com/community/slack) (in the [#donejs channel](https://bitovi-community.slack.com/messages/CFC80DU5B)).\nThose are also great places to get quick help with any questions.\n\n",
"description": "Generators add additional functionality to DoneJS applications. In this guide, we’ll create a generator that adds JSHint and a `.editorconfig` file to a DoneJS application. \n",
"name": "generator",
"title": "Creating a generator",
"type": "page",
"parent": "Guides",
"hideSidebar": true,
"outline": {
"depth": 2,
"tag": "ol"
},
"comment": " "
},
"Guide": {
"src": {
"path": "docs/guides/guide.md"
},
"body": "\n## Setup\n\nIn this section, we will install DoneJS and generate a new application.\n\n> If you haven't already, check out the [SettingUp] guide to ensure you have all of the prerequisites installed and configured.\n\n### Install DoneJS\n\nTo get started, let’s install the DoneJS command line utility globally:\n\n```shell\nnpm install -g donejs@3\n```\n\n### Generate the application\n\nThen we’ll create a new DoneJS application called `donejs-chat`:\n\n```shell\ndonejs add app donejs-chat --yes\n```\n\nThis will create a new folder called `donejs-chat` and in it generate our application.\n\nThe initialization process will ask questions like the name of your application, the source folder, etc. We’ll answer these with the default settings by hitting enter.\n\n<img src=\"static/img/donejs-init.png\" alt=\"donejs add app\" style=\"box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.2); border-radius: 5px; border: 1px #E7E7E7 solid;\" />\n\nThis will install all of DoneJS’s dependencies, including the following:\n\n- [StealJS](https://stealjs.com) — ES6, CJS, and AMD module loader and builder\n- [CanJS](https://canjs.com) — Custom elements and Model-View-ViewModel utilities\n- [done-ssr](https://github.com/donejs/done-ssr) - Server-rendering\n- [QUnit](https://qunitjs.com/) — Assertion library (A [Mocha](https://github.com/donejs/donejs-mocha) generator is also available)\n- [FuncUnit](https://funcunit.com) — Functional tests\n- [Testee](https://github.com/bitovi/testee) — JavaScript Test runner\n\n### Turn on development mode\n\nDoneJS comes with its own development server, which hosts your development files and automatically [renders the application on the server](./Features.html#server-side-rendered). Development mode enables [hot module swapping](./Features.html#hot-module-swapping), which automatically reloads files in the browser and on the server as they change.\n\nTo start it let’s go into the `donejs-chat` application directory:\n\n```shell\ncd donejs-chat\n```\n\nWe can start development mode by running:\n\n```shell\ndonejs develop\n```\n\nThe default port is `8080`.\n\nGo to [http://localhost:8080/] to see our application showing a default homepage.\n\n<img src=\"static/img/donejs-homepage.png\" alt=\"hello world\" height=\"272\" width=\"600\" />\n\n## Adding Bootstrap\n\nDoneJS makes it easy to import other projects that are published on [npm](https://npmjs.org). In this section, we will install and add [Bootstrap](https://getbootstrap.com/) to the page, and see DoneJS’s [hot module swapping](./Features.html#hot-module-swapping) in action.\n\n### Install the npm package\n\nOpen a new terminal window so we can keep the DoneJS development server running. Then, install the [Bootstrap npm package](https://www.npmjs.com/package/bootstrap) and save it as a dependency of our application like this:\n\n```shell\nnpm install bootstrap@3 --save\n```\n\n### Add it to the page\n\nTo see hot module swapping in action, let’s update the main template to import Bootstrap’s LESS file and also add some HTML that uses its styles.\n\nUpdate `src/index.stache` to look like this:\n\n\n```html\n<html>\n <head>\n <title>{{this.title}}</title>\n </head>\n <body>\n <can-import from=\"bootstrap/less/bootstrap.less\" />\n <can-import from=\"~/styles.less\" />\n <can-import from=\"~/app\" export-as=\"viewModel\" route-data=\"routeData\" />\n\n <div class=\"container\">\n <div class=\"row\">\n <div class=\"col-sm-8 col-sm-offset-2\">\n <h1 class=\"page-header text-center\">\n <img src=\"https://donejs.com/static/img/donejs-logo-white.svg\"\n alt=\"DoneJS logo\" style=\"width: 100%;\" />\n <br>Chat\n </h1>\n </div>\n </div>\n </div>\n\n {{#eq(this.env.NODE_ENV, \"production\")}}\n <script src=\"{{joinBase('steal.production.js')}}\"></script>\n {{else}}\n <script src=\"/node_modules/steal/steal.js\" main></script>\n {{/eq}}\n </body>\n</html>\n\n```\n<div line-highlight='6,10-20,only'></div>\n\n> New APIs Used:\n> - [<can-import>](https://canjs.com/doc/can-view-import.html) — specifies template dependencies.\n\nIf you kept your browser window open at [http://localhost:8080/] you should see the updated styles and content as soon as you save the file.\n\n<img src=\"static/img/donejs-bootstrap.png\" alt=\"donejs add app\" height=\"272\" width=\"400\" style=\"box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.2); border-radius: 5px; border: 1px #E7E7E7 solid;\" />\n\nFeel free to edit the HTML or `src/styles.less` to see how hot module swapping updates the page automatically.\n\n## Routing and components\n\nIn this part, we will create our own custom HTML elements — one for the homepage and another to display the chat messages. Then we will create routes to navigate between these two pages.\n\n### Generate custom elements\n\nWe’ll use a DoneJS [generator](./Features.html#generators) to create custom components. The component generator is run by typing `donejs add component <file-or-folder> <component-name>`.\n\nThe homepage custom element (with the HTML tag name `chat-home`) won't be very big or complex, so we’ll put everything into a single `.component` file.\n\nTo generate it, run:\n\n```shell\ndonejs add component pages/home.component chat-home\n```\n\nThe messages component (with the tag `chat-messages`) will be a little more complex, so we’ll generate it using the [modlet file pattern](./Features.html#modlets).\n\n\nNow run:\n\n```shell\ndonejs add component pages/messages chat-messages\n```\n\n<img src=\"static/img/donejs-generator.png\" alt=\"chat.donejs.com\" style=\"box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.2); border-radius: 5px; border: 1px #E7E7E7 solid;\" />\n\nLater we will update the generated files with the chat messages functionality.\n\n### Navigate between pages\n\n> Routing works a bit differently than other libraries. In other libraries, you might declare routes and map those to controller-like actions. DoneJS application [routes](https://canjs.com/doc/can-route.html) map URL strings (like /user/1) to properties on an observable. In other words, our routes will just be a representation of the application state. To learn more about routing visit the [CanJS Routing guide](https://canjs.com/doc/guides/routing.html).\n\nFirst, let’s update `src/pages/home.component` with the original content from the homepage and a link to the chat messages page:\n\n\n```html\n<can-component tag=\"chat-home\">\n <style type=\"less\">\n display: block;\n\n h1.page-header { margin-top: 0; }\n </style>\n <view>\n <can-import from=\"can-stache-route-helpers\" />\n <h1 class=\"page-header text-center\">\n <img src=\"https://donejs.com/static/img/donejs-logo-white.svg\"\n alt=\"DoneJS logo\" style=\"width: 100%;\" />\n <br>Chat\n </h1>\n\n <a href=\"{{routeUrl(page='chat')}}\"\n class=\"btn btn-primary btn-block btn-lg\">\n Start chat\n </a>\n </view>\n</can-component>\n\n```\n<div line-highlight='5,8-18,only'></div>\n\n> New APIs Used:\n> - [done-component](https://github.com/donejs/done-component#done-component) — a [StealJS](https://stealjs.com/) plugin for CanJS [components](https://canjs.com/doc/can-component.html) that allows you to define a component completely within a _.component_ file.\n> - [`routeUrl`](https://canjs.com/doc/can-stache.helpers.routeUrl.html) — a helper that populates the anchor’s href with a URL that sets the `page` property to `\"chat\"` on [route.data](https://canjs.com/doc/can-route.data.html).\n\nNext, add a link to go back to the homepage from the chat page by updating `src/pages/messages/messages.stache` to:\n\n\n```html\n<can-import from=\"can-stache-route-helpers\" />\n<h5><a href=\"{{routeUrl(page='home')}}\">Home</a></h5>\n<p>{{this.message}}</p>\n\n```\n<div line-highlight='1-2,only'></div>\n\n> New APIs Used:\n> - [DefineMap](https://canjs.com/doc/can-define/map/map.html) — used to define observable types.\n> - [route](https://canjs.com/doc/can-route.html) — used to map changes in the URL to changes on the route.data `page` property.\n\n### Switch between pages\n\nFinally we'll glue together these components as separate pages. Our Application ViewModel is where we determine which page to show. This is done by determining the `pageComponent`, an instance of a [can-component](https://canjs.com/doc/can-component.html), based on the `route.data.page` property.\n\nAdd the following two new properties to `src/app.js`:\n\n\n```js\nimport { DefineMap, route } from 'can';\nimport RoutePushstate from 'can-route-pushstate';\nimport debug from 'can-debug#?./is-dev';\n\n//!steal-remove-start\nif(debug) {\n\tdebug();\n}\n//!steal-remove-end\n\nconst AppViewModel = DefineMap.extend(\"AppViewModel\", {\n env: {\n default: () => ({NODE_ENV:'development'})\n },\n title: {\n default: 'donejs-chat'\n },\n routeData: {\n default: () => route.data\n },\n pageComponentModuleName: {\n get() {\n switch (this.routeData.page) {\n case 'chat': return '~/pages/messages/';\n default: return '~/pages/home.component';\n }\n }\n },\n pageComponent: {\n get() {\n return steal.import(this.pageComponentModuleName)\n .then(({default: Component}) => {\n return new Component();\n });\n }\n }\n});\n\nroute.urlData = new RoutePushstate();\nroute.register(\"{page}\", { page: \"home\" });\n\nexport default AppViewModel;\n\n```\n<div line-highlight='20-36,only'></div>\n\nThis imports the chosen page's module and then instantiates a new instance using `new Component()`. We can use this component by placing it in the `index.stache`:\n\n\n```html\n<html>\n <head>\n <title>{{this.title}}</title>\n </head>\n <body>\n <can-import from=\"bootstrap/less/bootstrap.less\" />\n <can-import from=\"~/styles.less\" />\n <can-import from=\"~/app\" export-as=\"viewModel\" route-data=\"routeData\" />\n\n <div class=\"container\">\n <div class=\"row\">\n <div class=\"col-sm-8 col-sm-offset-2\">\n {{#if(this.pageComponent.isResolved)}}\n {{this.pageComponent.value}}\n {{else}}\n Loading...\n {{/if}}\n </div>\n </div>\n </div>\n\n {{#eq(this.env.NODE_ENV, \"production\")}}\n <script src=\"{{joinBase('steal.production.js')}}\"></script>\n {{else}}\n <script src=\"/node_modules/steal/steal.js\" main></script>\n {{/eq}}\n </body>\n</html>\n\n```\n<div line-highlight='13-17,only'></div>\n\n> New APIs Used:\n> - [steal.import](https://stealjs.com/docs/steal.import.html) - imports the pageComponentModuleName dynamically.\n> - [new Component()](https://canjs.com/doc/can-component.html#newComponent__options__) - creates new instance of the component imported.\n> - [{{#if(isResolved)}}](https://canjs.com/doc/can-stache.helpers.if.html) — Renders the components once their modules have loaded.\n> - [{{else}}](https://canjs.com/doc/can-stache.helpers.else.html) — renders _\"Loading\"_ while the modules are loading.\n\nNow each component is being dynamically loaded while navigating between the home and messages page. You should see the changes already in your browser.\n\n<img src=\"static/img/donejs-chat1.png\" alt=\"chat.donejs.com\" height=\"302\" width=\"400\" style=\"box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.2); border-radius: 5px; border: 1px #E7E7E7 solid;\" />\n\n## Homepage\n\nNow that we can navigate between pages, we will finish implementing their functionality, starting with the homepage.\n\n\n### Install bit-tabs\n\nOn the homepage, let’s install and add [bit-tabs](https://github.com/bitovi-components/bit-tabs), a simple declarative tabs widget.\n\nRun:\n\n```shell\nnpm install bit-tabs@2 --save\n```\n\n### Update the page\n\nThen, import the unstyled custom elements from `bit-tabs/unstyled` (unstyled because we will use Bootstrap’s styles) and add `<bit-tabs>` and `<bit-panel>` elements to the template.\n\nUpdate `src/pages/home.component` to:\n\n\n```html\n<can-component tag=\"chat-home\">\n <style type=\"less\">\n display: block;\n\n bit-panel p {\n padding: 10px;\n }\n </style>\n <view>\n <can-import from=\"can-stache-route-helpers\" />\n <can-import from=\"bit-tabs/unstyled\" />\n <h1 class=\"page-header text-center\">\n <img src=\"https://donejs.com/static/img/donejs-logo-white.svg\"\n alt=\"DoneJS logo\" style=\"width: 100%;\" />\n <br>Chat\n </h1>\n\n <bit-tabs tabsClass:raw=\"nav nav-tabs\">\n <bit-panel title:raw=\"CanJS\">\n <p>CanJS provides the MV*</p>\n </bit-panel>\n <bit-panel title:raw=\"StealJS\">\n <p>StealJS provides the infrastructure.</p>\n </bit-panel>\n </bit-tabs>\n\n <a href=\"{{routeUrl(page='chat')}}\"\n class=\"btn btn-primary btn-block btn-lg\">\n Start chat\n </a>\n </view>\n</can-component>\n\n```\n<div line-highlight='5-7,11,18-25,only'></div>\n\nYou'll notice tabs appear in the browser:\n\n<img src=\"static/img/donejs-tabs.png\" alt=\"chat.donejs.com\" height=\"437\" width=\"400\" style=\"box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.2); border-radius: 5px; border: 1px #E7E7E7 solid;\" />\n\n## Messages page\n\nIn this section we add live chat functionality to the messages page. We’ll need to:\n\n * Create a messages model that connects to a RESTful API.\n * Add the ability to retrieve and list messages and create new messages.\n * Make the message list receive real-time updates from other clients.\n\n### Generate Message model\n\nTo load messages from the server, we will use [can-connect’s supermodel](https://canjs.com/doc/can-connect/can/super-map/super-map.html).\n\nGenerate a `message` supermodel like this:\n\n```shell\ndonejs add supermodel message\n```\n\nWhen asked for the URL endpoint, set it to our remote RESTful API at `https://chat.donejs.com/api/messages`. When it asks if https://chat.donejs.com is your service URL answer `Yes`. The other questions can be answered with the default by hitting enter.\n\n<img src=\"static/img/donejs-model-generator.png\" alt=\"model generator\" style=\"box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.2); border-radius: 5px; border: 1px #E7E7E7 solid;\" />\n\nUpdate `src/models/message.js` to:\n\n\n```js\nimport { DefineMap, DefineList, superModel } from 'can';\nimport loader from '@loader';\n\nconst Message = DefineMap.extend('Message', {\n seal: false\n}, {\n 'id': {\n type: 'any',\n identity: true\n },\n name: 'string',\n body: 'string'\n});\n\nMessage.List = DefineList.extend('MessageList', {\n '#': Message\n});\n\nMessage.connection = superModel({\n url: loader.serviceBaseURL + '/api/messages',\n Map: Message,\n List: Message.List,\n name: 'message'\n});\n\nexport default Message;\n\n```\n<div line-highlight='10-12'></div>\n\n> New APIs Used:\n> - [QueryLogic](https://canjs.com/doc/can-query-logic.html) — used to describe a service-layer’s parameters. For example if `\"api/messages?limit=20\"` only returned 20 messages, you would configure the `limit` parameter behavior in the connection’s `queryLogic`.\n> - [DefineList](https://canjs.com/doc/can-define/list/list.html) — used to define the behavior of an observable list of `Message`s.\n> - [superModel](https://canjs.com/doc/can-super-model.html) — connects the `Message` type to the \n> restful `'/api/messages'` service. This adds [real-time](https://canjs.com/doc/can-connect/real-time/real-time.html), [fall-through-caching](https://canjs.com/doc/can-connect/fall-through-cache/fall-through-cache.html) and other useful behaviors.\n> - [loader](https://stealjs.com/docs/@loader.html) — references the module loader that is loading this code. All configuration\n> in your _package.json_’s \"steal\" property is available, including the `serviceBaseUrl`.\n\n### Use the connection\n\nThe generated file is all that is needed to connect to our RESTful API. Use it by importing it and requesting a list of all messages.\n\nUpdate `src/pages/messages/messages.js` to:\n\n\n```js\nimport { Component } from 'can';\nimport './messages.less';\nimport view from './messages.stache';\nimport Message from '../../models/message';\n\nexport default Component.extend({\n tag: 'chat-messages',\n view,\n ViewModel: {\n // EXTERNAL STATEFUL PROPERTIES\n // These properties are passed from another component. Example:\n // value: {type: \"number\"}\n\n // INTERNAL STATEFUL PROPERTIES\n // These properties are owned by this component.\n message: { default: \"This is the chat-messages component\" },\n\n // DERIVED PROPERTIES\n // These properties combine other property values. Example:\n // get valueAndMessage(){ return this.value + this.message; }\n get messagesPromise() {\n return Message.getList({});\n },\n\n // METHODS\n // Functions that can be called by the view. Example:\n // incrementValue() { this.value++; }\n\n // SIDE EFFECTS\n // The following is a good place to perform changes to the DOM\n // or do things that don't fit in to one of the areas above.\n connectedCallback(element){\n\n }\n }\n});\n\n```\n<div line-highlight='4,21-23,only'></div>\n\n> New APIs Used:\n> - [getList](https://canjs.com/doc/can-connect/connection.getList.html) — returns a promise that resolves to a `Message.List` of `Message` instances.\n\nDisplay the messages by updating `src/pages/messages/messages.stache` to:\n\n\n```html\n<can-import from=\"can-stache-route-helpers\" />\n<h5><a href=\"{{routeUrl(page='home')}}\">Home</a></h5>\n\n{{#if(this.messagesPromise.isResolved)}}\n {{#for(message of this.messagesPromise.value)}}\n <div class=\"list-group-item\">\n <h4 class=\"list-group-item-heading\">{{message.name}}</h4>\n <p class=\"list-group-item-text\">{{message.body}}</p>\n </div>\n {{else}}\n <div class=\"list-group-item\">\n <h4 class=\"list-group-item-heading\">No messages</h4>\n </div>\n {{/for}}\n{{/if}}\n\n```\n<div line-highlight='4-15,only'></div>\n\n> New APIs Used:\n> - [{{#each}}](https://canjs.com/doc/can-stache.helpers.each.html) — loops through each `Message` instance.\n> - [{{key}}](https://canjs.com/doc/can-stache.tags.escaped.html) — reads either the name or body of a\n> `Message` instance and inserts it into the output of the template.\n\n\nIf you open [localhost:8080/chat](http://localhost:8080/chat), you will see a list of messages from the server or the \"No message\" text.\n\n<img src=\"static/img/donejs-chat2.png\" alt=\"chat.donejs.com\" height=\"272\" width=\"400\" style=\"box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.2); border-radius: 5px; border: 1px #E7E7E7 solid;\" />\n\n### Create messages\n\nNow let’s add the form to create new messages. The form will two-way bind the `name` and `body` properties to the component’s view-model and calls `send()` when hitting the enter key in the message input.\n\nFirst we have to implement the `send()` method. Update `src/pages/messages/messages.js` to this:\n\n\n```js\nimport { Component } from 'can';\nimport './messages.less';\nimport view from './messages.stache';\nimport Message from '../../models/message';\n\nexport default Component.extend({\n tag: 'chat-messages',\n view,\n ViewModel: {\n // EXTERNAL STATEFUL PROPERTIES\n // These properties are passed from another component. Example:\n // value: {type: \"number\"}\n\n // INTERNAL STATEFUL PROPERTIES\n // These properties are owned by this component.\n name: 'string',\n body: 'string',\n\n // DERIVED PROPERTIES\n // These properties combine other property values. Example:\n // get valueAndMessage(){ return this.value + this.message; }\n get messagesPromise() {\n return Message.getList({});\n },\n\n // METHODS\n // Functions that can be called by the view. Example:\n // incrementValue() { this.value++; }\n send(event) {\n event.preventDefault();\n\n new Message({\n name: this.name,\n body: this.body\n }).save().then(msg => this.body = '');\n },\n\n // SIDE EFFECTS\n // The following is a good place to perform changes to the DOM\n // or do things that don't fit in to one of the areas above.\n connectedCallback(element){\n\n }\n }\n});\n\n```\n<div line-highlight='16-17,29-36,only'></div>\n\n> New APIs Used:\n> - [save()](https://canjs.com/doc/can-connect/connection.save.html) — creates a `POST` request to `/api/messages` with\n> the message data. \n\nThe `send()` method takes the `name` and `message` properties from the view-model and creates a `Message` instance, saving it to the server. Once saved successfully, it sets the message to an empty string to reset the input field.\n\nNext update `src/pages/messages/messages.stache` to look like this:\n\n\n```html\n<can-import from=\"can-stache-route-helpers\" />\n<h5><a href=\"{{routeUrl(page='home')}}\">Home</a></h5>\n\n{{#if(this.messagesPromise.isResolved)}}\n {{#for(message of this.messagesPromise.value)}}\n <div class=\"list-group-item\">\n <h4 class=\"list-group-item-heading\">{{message.name}}</h4>\n <p class=\"list-group-item-text\">{{message.body}}</p>\n </div>\n {{else}}\n <div class=\"list-group-item\">\n <h4 class=\"list-group-item-heading\">No messages</h4>\n </div>\n {{/for}}\n{{/if}}\n\n<form class=\"row\" on:submit=\"this.send(scope.event)\">\n <div class=\"col-sm-3\">\n <input type=\"text\" class=\"form-control\" placeholder=\"Your name\"\n value:bind=\"this.name\" />\n </div>\n <div class=\"col-sm-6\">\n <input type=\"text\" class=\"form-control\" placeholder=\"Your message\"\n value:bind=\"this.body\" />\n </div>\n <div class=\"col-sm-3\">\n <input type=\"submit\" class=\"btn btn-primary btn-block\" value=\"Send\" />\n </div>\n</form>\n\n```\n<div line-highlight='17-29,only'></div>\n\n> New APIs Used:\n> - [on:submit](https://canjs.com/doc/can-stache-bindings.event.html) — listens to _submit_ events and calls\n> the `send()` method on the ViewModel.\n> - [value:bind](https://canjs.com/doc/can-stache-bindings.twoWay.html) — two-way bindings a `<input>`’s value\n> to a property of the ViewModel.\n\n\nYou can now enter your name and a message! It will automatically appear in our messages list.\n\n<img src=\"static/img/donejs-chat3.png\" alt=\"chat.donejs.com\" height=\"289\" width=\"400\" style=\"box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.2); border-radius: 5px; border: 1px #E7E7E7 solid;\" />\n\nIn fact, all lists that are related to that model will be updated automatically whenever there is new, modified, or deleted data. [can-connect](https://canjs.com/doc/can-connect.html) automatically manages the lists, while also providing [caching and minimized data requests](./Features.html#caching-and-minimal-data-requests).\n\nYou can see from your console that the localStorage cache is already populated with data:\n\n<img src=\"static/img/donejs-localstorage.png\" alt=\"chat.donejs.com\" style=\"box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.2); border-radius: 5px; border: 1px #E7E7E7 solid;\" />\n\n### Enable a real-time connection\n\nRight now our chat’s messages update automatically with our own messages, but not with messages from other clients. The API server ([chat.donejs.com/api/messages](https://chat.donejs.com/api/messages)) provides a [Socket.io](https://socket.io/) server that sends out real-time updates for new, updated and deleted chat messages.\n\nTo connect to it, first we’ll install a socket.io connector, by running:\n\n```shell\nnpm install steal-socket.io --save\n```\n\nUpdate `src/models/message.js` to:\n\n\n```js\nimport { DefineMap, DefineList, superModel } from 'can';\nimport loader from '@loader';\nimport io from 'steal-socket.io';\n\nconst Message = DefineMap.extend('Message', {\n seal: false\n}, {\n 'id': {\n type: 'any',\n identity: true\n },\n name: 'string',\n body: 'string'\n});\n\nMessage.List = DefineList.extend('MessageList', {\n '#': Message\n});\n\nMessage.connection = superModel({\n url: loader.serviceBaseURL + '/api/messages',\n Map: Message,\n List: Message.List,\n name: 'message'\n});\n\nconst socket = io(loader.serviceBaseURL);\n\nsocket.on('messages created',\n message => Message.connection.createInstance(message));\nsocket.on('messages updated',\n message => Message.connection.updateInstance(message));\nsocket.on('messages removed',\n message => Message.connection.destroyInstance(message));\n\nexport default Message;\n\n```\n<div line-highlight='3,27-34,only'></div>\n\n> New APIs used:\n> - [createInstance](https://canjs.com/doc/can-connect/real-time/real-time.createInstance.html) — tells the real-time\n> system that a message has been created.\n> - [updateInstance](https://canjs.com/doc/can-connect/real-time/real-time.updateInstance.html) — tells the real-time\n> system that a message has been updated.\n> - [destroyInstance](https://canjs.com/doc/can-connect/real-time/real-time.destroyInstance.html) — tells the real-time\n> system that a message has been destroyed.\n\nThis will listen to `messages <event>` events sent by the server and tell the connection to update all active lists of messages accordingly. Try opening another browser window to see receiving messages in real-time.\n\n<img src=\"static/img/donejs-twobrowsers.png\" alt=\"two browsers\" style=\"box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.2); border-radius: 5px; border: 1px #E7E7E7 solid;\" />\n\n## Production build\n\nNow that we implemented the complete chat functionality we can get our application ready for production.\n\n### Run build\n\nWe can find the build configuration in `build.js` in the application folder.\n\nEverything is already set up, so we can simply make a build by running:\n\n```shell\ndonejs build\n```\n\nThe optimized bundles that load your JavaScript and CSS as fast as possible are sent to the `dist/` folder.\n\n### Turn on production\n\nTo test the production build, close the current server (with `CTRL + C`) and start it with the environment (`NODE_ENV`) set to `production`:\n\n```shell\nNODE_ENV=production donejs start\n```\n\nIf you’re using Windows, you must first set the environmental variable:\n\n1. For Windows **command prompt** you set with `set NODE_ENV=production`\n1. For Windows **Powershell** you set it with `$env:NODE_ENV=\"production\"`\n\nThen run your application with `donejs start`.\n\nIf we now open [localhost:8080](http://localhost:8080/) again we can see the production bundles being loaded in the network tab of the developer tools.\n\n<img src=\"static/img/donejs-prodmode.png\" alt=\"two browsers\" style=\"box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.2); border-radius: 5px; border: 1px #E7E7E7 solid;\" />\n\nAll DoneJS projects are extremely modular, which is why in development mode, you see 200 or more requests when loading the page (thanks to hot-module swapping, we only have to make those requests once). In production mode, we can see only about 8 requests and a significantly reduced file-size.\n\n## Deploy\n\nNow that we verified that our application works in production, we can deploy it to the web. In this section, we will use [Firebase](https://firebase.google.com/), a service that provides static file hosting and [Content Delivery Network](https://en.wikipedia.org/wiki/Content_delivery_network) (CDN) support, to automatically deploy and serve our application’s static assets from a CDN.\n\n### Set up Firebase\n\nSign up for free at [Firebase](https://firebase.google.com/). After you have an account go to [Firebase console](https://console.firebase.google.com/) and create an app called `donejs-chat-<user>` where `<user>` is your GitHub username. Write down the name of your app because you'll need it in the next section.\n\n> You'll get an error if your app name is too long, so pick something on the shorter side. After you're created your app be sure to note the Firebase **ID**, as this is the information you need to enter in the next section.\n\nWhen you deploy for the first time it will ask you to authorize, but first we need to configure the project.\n\n### Configure DoneJS\n\nNow we can add the Firebase deployment configuration to our `package.json` like this:\n\n```shell\ndonejs add firebase\n```\n\nWhen prompted, enter the name of the application created when you set up the Firebase app. Before you can deploy your app you need to login and authorize the Firebase tools, which you can do with:\n\n```shell\nnode_modules/.bin/firebase login\n```\n\nThen we can deploy the application by running:\n\n```shell\ndonejs build\ndonejs deploy\n```\n\nStatic files are deployed to Firebase.\n\n<img src=\"static/img/donejs-firebase.png\" alt=\"two browsers\" />\n\nAnd verify that the application is loading from the CDN by loading it after running:\n\n```shell\nNODE_ENV=production donejs start\n```\n\n> If you’re using Windows, set the NODE_ENV variable as you did previously in the Production section.\n\nWe should now see our assets being loaded from the Firebase CDN.\n\n<img src=\"static/img/donejs-deploy.png\" alt=\"two browsers\" style=\"box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.2); border-radius: 5px; border: 1px #E7E7E7 solid;\" />\n\n## Desktop and mobile apps\n\nIn the last part of this guide we will make mobile and desktop builds of our chat application, using [Cordova](https://cordova.apache.org/) and [Electron](https://electron.atom.io/).\n\n### Cordova\n\nTo build the application as a Cordova based mobile application, you need to have each platform’s SDK installed.\nWe’ll be building an iOS app if you are a Mac user, and an Android app if you’re a Windows user.\n\nMac users should download XCode from the AppStore and install the `ios-sim` package globally with:\n\n```shell\nnpm install -g ios-sim\n```\n\nWe will use these tools to create an iOS application that can be tested in the iOS simulator.\n\nWindows users should install the [Android Studio](https://developer.android.com/sdk/index.html), which gives all of the tools we need.\n\nNow we can install the DoneJS Cordova tools with:\n\n```shell\ndonejs add cordova@2\n```\n\nDepending on your operating system you can accept most of the defaults, unless you would like to build for Android, which needs to be selected from the list of platforms.\n\nTo run the Cordova build and launch the simulator we can now run:\n\n```shell\ndonejs build cordova\n```\n\nIf everything went well, we should see the emulator running our application.\n\n<img src=\"static/img/donejs-ios.png\" alt=\"ios build\" height=\"590\" width=\"320\" style=\"box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.2); border-radius: 5px; border: 1px #E7E7E7 solid;\" />\n\nWindows users will get instructions to download the latest version of the platform and to create a Virtual Device. Follow the instructions and then re-do the build. This will only happen the first time you build for Cordova.\n\n__Note:__ if you receive the error `Error: Cannot read property 'replace' of undefined`, you can work around it by running `cd build/cordova/platforms/ios/cordova/ && npm install ios-sim@6` until [this patch](https://git-wip-us.apache.org/repos/asf?p=cordova-ios.git;a=commit;h=4490abf273ec6d12810c8ff5ea16d197c58ecd4b) is released.\n\n### Electron\n\nTo set up the desktop build, we have to add it to our application like this:\n\n```shell\ndonejs add electron@2\n```\n\nAccept the default for all of the prompts.\n\n<img src=\"static/img/donejs-electron-prompt.png\" alt=\"electron prompt\" style=\"box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.2); border-radius: 5px; border: 1px #E7E7E7 solid;\" />\n\nThen we can run the build like this:\n\n```shell\ndonejs build electron\n```\n\nThe macOS application can be opened with\n\n```shell\nopen build/donejs-chat-darwin-x64/donejs-chat.app\n```\n\nThe Windows application can be opened with\n\n```shell\n.\\build\\donejs-chat-win32-x64\\donejs-chat.exe\n```\n\n<img src=\"static/img/donejs-electron-app.png\" alt=\"electron app\" style=\"box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.2); border-radius: 5px; border: 1px #E7E7E7 solid;\" />\n\n## What’s next?\n\nIn this guide we created a small chat application that connects to a remote API with DoneJS. It has routing between two pages and can send and receive messages in real-time. We built an optimized bundle for production and deployed it to a static file host and CDN. Last, we made builds of the application as a mobile and desktop application.\n\nIf you want to learn more about DoneJS - like how to create more complex custom elements and routes, write and automatically run tests, Continuous Integration and Continuous Deployment - head over to the [place-my-order Guide](./place-my-order.html).\n\nIf you’re not ready for that yet, we might suggest the following guides:\n\n- CanJS’s [TodoMVC Guide](https://canjs.com/doc/guides/todomvc.html) and [ATM Guide](https://canjs.com/doc/guides/atm.html) — to better familiarize yourself with CanJS (DoneJS’s models, views, and observables).\n- StealJS’s [Progressive Loading Guide](https://stealjs.com/docs/StealJS.guides.progressive_loading.html) — to better familiarize yourself with StealJS (DoneJS’s module loader and builder).\n\n",
"description": "In this guide, we will create [chat.donejs.com](https://chat.donejs.com), a small real-time chat application with a homepage showing a tabs widget and a messages page that lets us send and receive messages in real-time: \n<img src=\"static/img/donejs-chat.gif\" alt=\"chat.donejs.com\" style=\"box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.2); border-radius: 5px; border: 1px #E7E7E7 solid;\" />\n\nIn the first part of this guide, we will install DoneJS, [generate a new application](./Features.html#generators) and start a server that provides [hot module swapping](./Features.html#hot-module-swapping) and [server-side rendering](./Features.html#server-side-rendered). We will then [import Bootstrap from npm](./Features.html#npm-packages), create our [own custom HTML elements](./Features.html#custom-html-elements) and [set up routing](./Features.html#pretty-urls-with-pushstate) between the homepage and the chat messages page. After that, we will complete both pages by adding a tabs widget to the homepage and the ability to send messages and [receive real-time updates](./Features.html#real-time-connected).\n\nIn the final parts of the guide we will make an [optimized, progressively loaded production build](./Features.html#progressive-loading) and [deploy it to a CDN](./Features.html#deploy-to-a-cdn). We will conclude with creating a [mobile and desktop](./Features.html#ios-android-and-desktop-builds) version of the application.\n\nIf you run into any problems, let us know on [Slack](https://www.bitovi.com/community/slack) (in the [#donejs channel](https://bitovi-community.slack.com/messages/CFC80DU5B)). We’re happy to help out!\n\n> For an even easier version of this guide, one that can be done entirely online, checkout [CanJS’s Chat Guide](https://canjs.com/doc/guides/chat.html). There, you'll build the same chat widget in a [JS Bin](https://jsbin.com/), but\nwithout a mobile or desktop build and deployment to a CDN.\n>\n>\n> Similarly, if you are unfamiliar with module loading and module loaders, you may want to checkout [StealJS’s Quick Start Guide](https://stealjs.com/docs/StealJS.quick-start.html) before proceeding with this guide.\n\n",
"name": "Guide",
"title": "Quick start guide",
"type": "page",
"parent": "Guides",
"hideSidebar": true,
"outline": {
"depth": 2,
"tag": "ol"
},
"comment": " "
},
"migrate-2": {
"src": {
"path": "docs/guides/migrate-2.md"
},
"body": "\nThis guide explains how to upgrade DoneJS 1.0 app to DoneJS 2.\n\n## Pre-migration preparation\n\nBefore upgrading to DoneJS 2, it’s a good idea to make sure all of your tests are passing, your project builds successfully, and you can deploy your app. This will give you more assurance as you upgrade individual parts of your project.\n\nTo make sure tests are passing, run:\n\n```shell\ndonejs test\n```\n\nTo confirm that your build is working correctly, run:\n\n```shell\ndonejs build\nNODE_ENV=production donejs start\n```\n\nThis will create your production build and then start a local server in production mode. If you open [localhost:8080](http://localhost:8080/) in your browser, you should see the production bundles being loaded in the Network tab of your developer tools.\n\nOnce you are confident that you are ready to upgrade, create a new branch from which to work. Assuming you are using git run this command:\n\n```js\ngit checkout -b upgrade-donejs\n```\n\nIf you are using a different version control system, substitute above for the relevant commands. The idea is the same; create a new branch from which to make the DoneJS upgrade changes.\n\n## Install donejs@2\n\nOnce you have completed the preprepation, upgrade to the latest version of the __donejs__ global package.\n\n```shell\nnpm install --global donejs@2\n```\n\nNow any time you create new applications using `donejs add app`, it will scaffold out a DoneJS 2 project.\n\n## Run donejs upgrade\n\n> *Important*: Before running this step make sure your git directory is clean. It's best to create a new branch to do the upgrade, so that you can ensure everything is working before accepting it into master.\n\nDoneJS 2 include a new command `donejs upgrade` which will upgrade all of your dependencies to their latest version and run any codemods that are available. Running the following command:\n\n```shell\ndonejs upgrade\n```\n\nThis will:\n\n* Update your package.json with the latest versions of each DoneJS packages.\n* Run `npm install`, to give you the latest versions.\n* Run `can-migrate` to apply codemods for the changes that happened in CanJS 4.0.\n\nOnce this is complete you will see several changed files. It's a good idea to look at these files using your favorite diff tool to see if the changes look correct. can-migrate is conservative about the changes it makes but is not perfect.\n\nIf you would prefer *not* to run the CanJS codemods as part of the upgrade, you can skip this part by running the command as `donejs upgrade --no-canmigrate`.\n\n## Go through the CanJS 4 Migration Guide\n\nAlthough `donejs upgrade` covers a lot of the important parts of the upgrade, especially getting the correct versions of each dependency, it cannot do everything for you.\n\nThe [CanJS 4.0 migration guide](https://canjs.com/doc/migrate-4.html) goes over the parts that you might need to change manually. Reviewing this guide will also help familiarize yourself with CanJS 4, so it's a good thing to read even if you are developing a new project.\n\n## Reach out for help\n\nWe've taken care to make upgrading DoneJS apps as easy as possible. However, as always, we're available on [Slack](https://www.bitovi.com/community/slack) ([#donejs channel](https://bitovi-community.slack.com/messages/CFC80DU5B)) and [the forums](https://forums.bitovi.com/) to try and help!\n\n",
"description": "This guide walks you through the step-by-step process of upgrading a DoneJS 1 app to DoneJS 2. \n",
"name": "migrate-2",
"title": "Migrating to DoneJS 2",
"type": "page",
"parent": "Guides",
"hideSidebar": true,
"outline": {
"depth": 2,
"tag": "ol"
},
"comment": " "
},
"migrate-3": {
"src": {
"path": "docs/guides/migrate-3.md"
},
"body": "\nThis guide explains how to upgrade DoneJS 2 app to DoneJS 3.\n\n## Pre-migration preparation\n\nBefore upgrading to DoneJS 3, it’s a good idea to make sure all of your tests are passing, your project builds successfully, and you can deploy your app. This will give you more assurance as you upgrade individual parts of your project.\n\nTo make sure tests are passing, run:\n\n```shell\ndonejs test\n```\n\nTo confirm that your build is working correctly, run:\n\n```shell\ndonejs build\nNODE_ENV=production donejs start\n```\n\nThis will create your production build and then start a local server in production mode. If you open [localhost:8080](http://localhost:8080/) in your browser, you should see the production bundles being loaded in the Network tab of your developer tools.\n\nOnce you are confident that you are ready to upgrade, create a new branch from which to work. Assuming you are using git run this command:\n\n```js\ngit checkout -b upgrade-donejs\n```\n\nIf you are using a different version control system, substitute above for the relevant commands. The idea is the same; create a new branch from which to make the DoneJS upgrade changes.\n\n## Install donejs@3\n\nOnce you have completed the preprepation, upgrade to the latest version of the __donejs__ global package.\n\n```shell\nnpm install --global donejs@3\n```\n\nNow any time you create new applications using `donejs add app`, it will scaffold out a DoneJS 3 project.\n\n## Run donejs upgrade\n\nRunning `donejs upgrade` will upgrade all of your dependencies to their latest version and run any codemods that are available. Running the following command:\n\n```shell\ndonejs upgrade\n```\n\nThis will:\n\n* Update your package.json with the latest versions of each DoneJS packages.\n* Run `npm install`, to give you the latest versions.\n* Run `can-migrate` to apply codemods for the changes that happened in CanJS 5.0.\n\nOnce this is complete you will see several changed files. It's a good idea to look at these files using your favorite diff tool to see if the changes look correct. can-migrate is conservative about the changes it makes but is not perfect.\n\nIf you would prefer *not* to run the CanJS codemods as part of the upgrade, you can skip this part by running the command as `donejs upgrade --no-canmigrate`.\n\n## Go through the StealJS 2 Migration Guide\n\nStealJS 2 only has a few, small, breaking changes, so it's easiest to upgrade it first. The [StealJS 2.0 migration guide](https://stealjs.com/docs/StealJS.topics.migrating-two.html) goes over the few things you might need to change in your code.\n\n## Go through the CanJS 5 Migration Guide\n\nAlthough `donejs upgrade` covers a lot of the important parts of the upgrade, especially getting the correct versions of each dependency, it cannot do everything for you.\n\nThe [CanJS 5.0 migration guide](https://canjs.com/doc/migrate-5.html) goes over the parts that you might need to change manually. Reviewing this guide will also help familiarize yourself with CanJS 5, so it's a good thing to read even if you are developing a new project.\n\n## Getting help\n\nWe've taken care to make upgrading DoneJS apps as easy as possible. However, as always, we're available on [Slack](https://www.bitovi.com/community/slack) ([#donejs channel](https://bitovi-community.slack.com/messages/CFC80DU5B)) and [the forums](https://forums.bitovi.com/) to try and help!\n\n",
"description": "This guide walks you through the step-by-step process of upgrading a DoneJS 2 app to DoneJS 3. \n",
"name": "migrate-3",
"title": "Migrating to DoneJS 3",
"type": "page",
"parent": "Guides",
"hideSidebar": true,
"outline": {
"depth": 2,
"tag": "ol"
},
"comment": " "
},
"migrate-1": {
"src": {
"path": "docs/guides/migrate-1.md"
},
"body": "\nDoneJS 1.0 brings together the latest changes introduced in [CanJS 3.0](https://www.bitovi.com/blog/canjs-3-0-release) and [StealJS 1.0](https://www.bitovi.com/blog/stealjs-1.0-release). This guide explains how to upgrade your DoneJS 0.9 app (which uses CanJS 2.3 and StealJS 0.16) to 1.0.\n\n## Pre-migration preparation\n\nBefore upgrading to DoneJS 1.0, it’s a good idea to make sure all of your tests are passing, your project builds successfully, and you can deploy your app. This will give you more assurance as you upgrade individual parts of your project.\n\nTo make sure tests are passing, run:\n\n```shell\ndonejs test\n```\n\nTo confirm that your build is working correctly, run:\n\n```shell\ndonejs build\nNODE_ENV=production donejs start\n```\n\nThis will create your production build and then start a local server in production mode. If you open [localhost:8080](http://localhost:8080/) in your browser, you should see the production bundles being loaded in the Network tab of your developer tools.\n\nIf you are using `donejs deploy` to deploy your site to a service like Firebase, make sure it’s working before proceeding.\n\nAdditionally, if you are using either `donejs build cordova` or `donejs build nw` to create desktop or mobile apps, make sure both of those are working correctly.\n\nThere are a few more pages you might use in your normal development workflow that will be helpful during the migration process:\n\n- `development.html`: [http://localhost:8080/development.html]\n- `production.html`: [http://localhost:8080/production.html]\n- `src/test.html`: [http://localhost:8080/src/test.html]\n\nWe recommend taking a “bottom up” approach to upgrading your application by focusing on getting each of your components’ test and demo pages working first.\n\nFor example, if you have a `messages` component in `src/messages/`, the following pages should work correctly:\n\n- demo page: [http://localhost:8080/src/messages/messages.html]\n- test page: [http://localhost:8080/src/messages/test.html]\n\nYou should also follow the [CanJS 3 pre-migration preparation](https://canjs.com/doc/migrate-3.html#Pre_migrationpreparation) steps _before_ going through the rest of this guide. The pre-migration section of the [CanJS 3 migration guide](https://canjs.com/doc/migrate-3.html) includes changes you can make to your existing CanJS 2.3 app that will make migrating to CanJS 3 easier.\n\nIf you have any questions about any of the steps in this guide, please join us on [Slack](https://www.bitovi.com/community/slack) ([#donejs channel](https://bitovi-community.slack.com/messages/CFC80DU5B)) and [the forums](https://forums.bitovi.com/).\n\n## Install donejs@1\n\nFirst, upgrade to the latest version of the **donejs** package on npm:\n\n```shell\nnpm install --global donejs@1\n```\n\nNow any time you create new applications using `donejs add app`, it will scaffold out a DoneJS 1.0 project.\n\n## Use done-serve in static mode\n\nAs you do the upgrade, you’ll want to disable SSR so that you can focus on changes to your code. Once all dependencies are up to date you can switch back and everything should work.\n\nTo disable SSR, open up your `package.json` and change your **develop** script. It will look something like:\n\n```shell\ndone-serve --develop ...\n```\n\nUpdate it to remove the `--develop` flag and add the `--static` flag instead:\n\n```shell\ndone-serve --static ...\n```\n\n> *Note*: removing the `--develop` flag will disable live-reload. As we upgrade our application, it will be in a broken state most of the time, so live-reload will not work anyway. When we’ve completed the upgrade, we can switch `--develop` back on.\n\n## Upgrade to CanJS 3\n\nSee the [CanJS 3 migration guide](https://canjs.com/doc/migrate-3.html) for instructions on how to migrate CanJS. If you followed the advice above, you will have already gone through the [pre-migration](https://canjs.com/doc/migrate-3.html#Pre_migrationpreparation) steps, so you will only need to follow the [minimal migration path](https://canjs.com/doc/migrate-3.html#Minimalmigrationpath) steps. We recommend that you also follow the [modernized migration path](https://canjs.com/doc/migrate-3.html#Modernizedmigrationpath) steps as well.\n\nNow is a good time to install the latest versions of any other CanJS packages, including the following:\n\n```shell\nnpm install can-connect@1 --save\nnpm install can-fixture@1 --save-dev\nnpm install can-zone@0.6 --save\n```\n\nThis will update your `package.json` to look something like this:\n\n```json\n\"dependencies\": {\n ...\n\n \"can-connect\": \"^1.0.0\",\n \"can-zone\": \"^0.6.0\"\n},\n\n\"devDependencies\": {\n ...\n\n \"can-fixture\": \"^1.0.0\"\n}\n```\n\nOnce you’ve made these changes, the demo and test pages for your individual components should start to work but your entire test suite may not work quite yet. *Don’t worry*! Some of the DoneJS dependencies you have installed still expect to use CanJS 2.3; once we’ve upgraded all of those, we’ll start to get the other pages working again.\n\n> *Note*: if you receive an error such as `Uncaught Error: You can't have two versions of can-event/batch/batch`, you maybe be able to fix the issue by deleting your `node_modules` folder and running `npm install` to re-install all of the packages.\n\n## Upgrade other DoneJS libraries\n\nUse npm to install the latest versions of the following packages:\n\n```shell\nnpm install done-autorender@1 --save\nnpm install done-component@1 --save\n```\n\nThis will update your `package.json` to look something like this:\n\n```json\n\"dependencies\": {\n ...\n\n \"done-autorender\": \"^1.0.0\",\n \"done-component\": \"^1.0.0\",\n}\n```\n\nAt this point, your [development.html](http://localhost:8080/development.html) and [src/test.html](http://localhost:8080/src/test.html) files should start working. Not all of your tests may pass, but you should be able to load the test page and see results.\n\n## Upgrade other dependencies\n\nYou may be using other packages that are specifically made to work with CanJS 2.x, like `bit-tabs@0`.\n\nAt this point, you should look for those other dependencies in your `package.json` and upgrade them, like so:\n\n```shell\nnpm install bit-tabs@1 --save\n```\n\nOnce you’ve upgraded CanJS and these ancillary packages, your app should generally work. SSR is still disabled, but the front-end should be okay.\n\n## Upgrade to StealJS 1\n\nRefer to the [StealJS 1 guide](https://stealjs.com/docs/StealJS.topics.migrating-one.html) to upgrade StealJS.\n\nAdditionally, upgrade to the latest versions of these packages:\n\n```shell\nnpm install done-css@3 --save\nnpm install steal-less@1 --save\nnpm install steal-qunit@1 --save-dev\nnpm install steal-stache@3 --save\n```\n\nThis will update your `package.json` to look something like this:\n\n```json\n\"dependencies\": {\n ...\n\n \"done-css\": \"^3.0.0\",\n \"steal-less\": \"^1.2.0\",\n \"steal-stache\": \"^3.0.5\"\n},\n\n\"devDependencies\": {\n ...\n\n \"steal-qunit\": \"^1.0.0\"\n}\n```\n\nYour package.json’s **steal** section (which used to be called **system**) should have this configuration:\n\n```json\n\"steal\": {\n ...\n\n \"plugins\": [\n \"done-component\",\n \"done-css\",\n \"steal-less\",\n \"steal-stache\"\n ]\n}\n```\n\nThis configures Steal to be able to load file types other than JavaScript.\n\n## Upgrade other utilities\n\nThe last thing is to upgrade *everything else* that you haven’t already changed. This should include the following:\n\n```shell\nnpm install done-serve@1 --save\nnpm install donejs-cli@1 --save-dev\nnpm install funcunit@3 --save-dev\nnpm install generator-donejs@1 --save\nnpm install testee@0.4 --save-dev\n```\n\nThis will update your `package.json` to look something like this:\n\n```json\n\"dependencies\": {\n ...\n\n \"done-serve\": \"^1.0.0\",\n \"generator-donejs\": \"^1.0.0\"\n},\n\"devDependencies\": {\n ...\n\n \"donejs-cli\": \"^1.0.0\",\n \"funcunit\": \"^3.3.0\",\n \"testee\": \"^0.4.0\"\n}\n```\n\nOnce this is done, you should be able to start up a server using `donejs start`. If that works, then re-enable SSR and live-reload in your **develop** script (remove the `--static` flag we added earlier):\n\n```shell\ndone-serve --develop ...\n```\n\nIf everything seems to work and your tests pass when running `donejs test`, congratulations! Your project is now on DoneJS 1.0. 🎉\n\nIf you run into problems, please refer to the [dependency list here](https://github.com/donejs/cli/blob/v1.0.1/package.json#L59) and make sure that your version numbers match.\n\nAs always, we’re available on [Slack](https://www.bitovi.com/community/slack) ([#donejs channel](https://bitovi-community.slack.com/messages/CFC80DU5B)) and [the forums](https://forums.bitovi.com/) to try and help!\n\n",
"description": "This guide walks you through the step-by-step process of upgrading a DoneJS 0.9 app to DoneJS 1. \n",
"name": "migrate-1",
"title": "Migrating to DoneJS 1",
"type": "page",
"parent": "Guides",
"hideSidebar": true,
"outline": {
"depth": 2,
"tag": "ol"
},
"comment": " "
},
"plugin": {
"src": {
"path": "docs/guides/plugin.md"
},
"body": "\nWe will create the project on [GitHub](https://github.com), initialize the repository as a new DoneJS plugin and then set up continuous integration with Travis CI. After running development mode we will implement the component functionality and tests and submit it as a pull request to the repository. Finally we will make a build and publish the plugin to [npm](http://npmjs.org) as well as look how to use the published module in other projects.\n\nYou can find the code in the [donejs-number-input](https://github.com/donejs/donejs-number-input) repository. The final result looks like this:\n\n<a class=\"jsbin-embed\" href=\"https://jsbin.com/nuxiyay/1/embed?html,css,js,output\">JS Bin on jsbin.com</a><script src=\"https://static.jsbin.com/js/embed.min.js?3.41.10\"></script>\n\n## Setting up\n\n### Creating the project on GitHub\n\nWe will use [GitHub][3] to host the code for the project which makes it easy for others to contribute and to automatically run the tests in [continuous integration][5] which we will enable later.\n\nIf you don't have an account yet, go to [GitHub][6] to sign up and follow [the help][7] on how to set it up for the command-line `git`. Once completed, you can create a new repository from your dashboard.\n\n> **Important:** In the remainder of the article the plugin name will be `<username>-number-input`. You will have to replace `<username>` with your GitHub username to get a unique module name that can be published to npm.\n\nCalling the repository `<username>-number-input` and initializing it empty (without any of the default files) looks like this:\n\n[<img src=\"http://www.bitovi.com/hubfs/Imported_Blog_Media/Screen-Shot-2016-02-16-at-1.53.10-PM.png\" alt=\"Screen Shot 2016-02-16 at 1.53.10 PM\" style=\"width: 100%;\" class=\"alignnone size-full wp-image-2665\" />][8]\n\nAfter creating the repository, we can clone it into a new folder:\n\n```\n$ git clone git@github.com:<username>/<username>-number-input.git\n$ cd <username>-number-input\n``` \n\n### Initializing the plugin\n\nTo initialize a new plugin you will need DoneJS version 0.7.0+ installed globally. To check your DoneJS version run\n\n```\n$ donejs --version\n```\n\nTo install DoneJS or to get the latest version run:\n\n```\n$ npm install donejs -g \n```\n\nIn the `<username>-number-input` folder we can now initialize a new plugin like this:\n\n```\n$ donejs add plugin\n```\n\nThe plugin generator will ask several question that should be answered as follows:\n\n* For the project name you can just confirm the default by pressing enter\n* For the GitHub username or organization enter the GitHub username where the repository has been created\n* All other fields can also be answered with the default\n\nOnce all done, the final prompt looks similar to this:\n\n[<img src=\"static/img/donejs-plugin.png\" alt=\"DoneJS adding a new plugin\" style=\"width: 100%;\" class=\"alignnone size-full wp-image-2666\" />][9]\n\nNow the generator will initialize the default plugin layout and install all its dependencies.\n\n### Setting up Travis CI\n\nWhen the installation has completed, we can make sure everything got set up properly by running:\n\n```\n$ npm test\n```\n\nThis will open a Firefox browser, run two tests and output the result on the console.\n\nThis command can also be used to automatically run the tests on a [continuous integration][5] server. There are many open source CI servers, the most popular being [Jenkins][10], and many hosted solutions like [Travis CI][11].\n\nWe will use Travis CI as our hosted solution because it is free for open source projects. It works with your GitHub account which it will use to sign up. Once signed in, go to `Accounts` (in the dropdown under you name) to enable the `<username>-number-input` repository:\n\n[<img src=\"http://www.bitovi.com/hubfs/Imported_Blog_Media/Screen-Shot-2016-02-16-at-2.03.56-PM.png\" alt=\"Enabling on Travis CI\" style=\"width: 100%;\" class=\"alignnone size-full wp-image-2669\" />][12]\n\nYou may have to click the *\"Sync account\"* button for the repository to show up. Now, every time we push to GitHub the tests will run automatically. We can do so with our initial commit:\n\n```\n$ git add . --all\n$ git commit -am \"Initial commit\"\n$ git push origin master\n```\n\nIf you now go `https://travis-ci.org/<your-username>/<username>-number-input/builds` you will see the build running and eventually turn green (which will update the badge that got added in the `readme.md` file).\n\n## Implementing functionality\n\n### Development mode\n\nLike a DoneJS application, a DoneJS plugin provides a development mode that starts a server and enables live-reload by running:\n\n```\n$ donejs develop\n```\n\nThe server will run at `http://localhost:8080`. You can view the main test page at [localhost:8080/src/test/test.html][13]. Any changes to the test file or module will re-run the tests right away thanks to hot-module-swapping.\n\n### Creating the component\n\nA plugin can contain anything from shared utility functions to model- or component collections. Just like in a DoneJS application it is possible to add components and models. In our case we want to create a new component which we can do like this:\n\n```\n$ donejs add component <username>-number-input\n```\n\nThis creates a complete component using the `<username>-number-input` tag with tests and documentation. Because the module name is the same as the plugin name (`<username>-number-input`), the generator will put the component files directly in the `src/` folder (instead of a subfolder). Confirm the default tag name by pressing enter. Confirm the prompts to overwrite the existing files by typing `Y` and pressing enter. The initialized component can now be viewed at `http://localhost:8080/src/<username>-number-input.html`. The component tests are available at [localhost:8080/src/test.html][15].\n\n### Creating and testing the view-model\n\nOur number input view-model should provide the following functionality:\n\n* Update its value either through a number input field or +/- buttons\n* Have a maximum and minimum value (which will also disable the proper button)\n\nWe can use the [define plugin][16] to define a `min` and `max` value and [a setter][17] for the `value` to make sure that it always is within those constraints. We will also add an `increment` and `decrement` method that will modify the value by 1. The component view-model (in `src/<username>-number-input.js`) then looks like this:\n\n\n```js\nimport Component from 'can-component';\nimport DefineMap from 'can-define/map/';\nimport './donejs-number-input.less';\nimport view from './donejs-number-input.stache';\n\nexport const ViewModel = DefineMap.extend({\n\tvalue: {\n\t\tdefault: 0,\n\t\ttype: 'number',\n\t\tset(value) {\n\t\t\tif(value > this.max) {\n\t\t\t\treturn this.max;\n\t\t\t}\n\n\t\t\tif(value < this.min) {\n\t\t\t\treturn this.min;\n\t\t\t}\n\n\t\t\treturn value;\n\t\t}\n\t},\n\tmax: {\n\t\tdefault: Infinity,\n\t\ttype: 'number'\n\t},\n\tmin: {\n\t\tdefault: 0,\n\t\ttype: 'number'\n\t},\n\tincrement() {\n\t\tthis.value++;\n\t},\n\tdecrement() {\n\t\tthis.value--;\n\t}\n});\n\nexport default Component.extend({\n\ttag: 'donejs-number-input',\n\tViewModel,\n\tview\n});\n\n```\n<div line-highlight='7-35,only'></div>\n\nTo test this functionality, we can change the tests in `src/<username>-number-input-test.js` to look like this:\n\n\n```js\nimport QUnit from 'steal-qunit';\nimport { ViewModel } from './donejs-number-input.js';\n\n// ViewModel unit tests\nQUnit.module('donejs-number-input/component');\n\nQUnit.test('Initializes the ViewModel', function(){\n\tvar vm = new ViewModel();\n\n\tQUnit.equal(vm.value, 0, 'Default value is 0');\n\tQUnit.equal(vm.max, Infinity, 'Max value is infinity');\n\tQUnit.equal(vm.min, 0, 'Max value is number max value');\n});\n\nQUnit.test('.increment', function(){\n\tvar vm = new ViewModel();\n\n\tvm.increment();\n\tQUnit.equal(vm.value, 1, 'Value incremented');\n});\n\nQUnit.test('.decrement', function(){\n\tvar vm = new ViewModel();\n\n\tvm.increment();\n\tvm.increment();\n\tvm.decrement();\n\tQUnit.equal(vm.value, 1, 'Value updated');\n});\n\n```\n<div line-highlight='7-29,only'></div>\n\nYou can run all tests either by going to [localhost:8080/src/test/test.html](http://localhost:8080/src/test/test.html) in the browser or via\n\n```\n$ npm test\n```\n\n### Adding the template\n\nIn the template we will use [Bootstrap][2] and [can-view-import][23], so first install them as dependencies:\n\n```\n$ npm install bootstrap@3 can-view-import --save\n```\n\nThen we can update `src/<username>-number-input.stache` to look like this:\n\n\n```html\n<can-import from=\"bootstrap/less/bootstrap.less!\" />\n<form class=\"form-inline\">\n <div class=\"form-group\">\n <div class=\"input-group\">\n <div class=\"input-group-btn\">\n <button class=\"btn btn-primary\" type=\"button\"\n {{#eq value min}}disabled{{/eq}}\n on:click=\"decrement\">\n -\n </button>\n </div>\n <input type=\"number\" class=\"form-control\"\n value:bind=\"value\">\n <div class=\"input-group-btn\">\n <button class=\"btn btn-primary\" type=\"button\"\n {{#eq value max}}disabled{{/eq}}\n on:click=\"increment\">\n +\n </button>\n </div>\n </div>\n </div>\n</form>\n\n```\n\nThis template first imports the Bootstrap LESS. Then we create a button group with a `-` button on the left, a number input in the middle and a `+` button on the right. When the buttons are clicked the `increment` or `decrement` view-model methods are being called. The value of the input field is two-way bound with the `value` property of the view-model. When the value is either `min` or `max`, the `-` or `+` buttons will be disabled.\n\n## Publishing the plugin\n\n### Making a pull request\n\nAlthough we are working on the plugin by ourselves for now, [GitHub pull requests][18] are a great way to keep track of our progress and to make sure that all tests are passing. In the plugin folder we can run:\n\n```\n$ git checkout -b number-input-component\n$ git add . --all\n$ git commit -m \"Implementing number-input component functionality, template and tests\"\n$ git push origin number-input-component\n```\n\nAnd then create a new pull request by going to `https://github.com/<your-username>/<username>-number-input` which will now show an option like this:\n\n[<img src=\"http://www.bitovi.com/hubfs/Imported_Blog_Media/Screen-Shot-2016-02-16-at-8.17.50-AM.png\" alt=\"Screen Shot 2016-02-16 at 8.17.50 AM\" class=\"alignnone size-full wp-image-2658\" />][19]\n\nOnce you created the pull request, you will see a `Some checks haven’t completed yet` message that will eventually turn green:\n\n[<img src=\"http://www.bitovi.com/hubfs/Imported_Blog_Media/Screen-Shot-2016-02-16-at-8.30.41-AM.png\" alt=\"Screen Shot 2016-02-16 at 8.30.41 AM\" style=\"width: 100%;\" class=\"alignnone size-full wp-image-2662\" />][20]\n\nNow you can click the \"Merge pull request\" button. Then in the console, checkout the *master* branch and pull down the latest changes with:\n\n```\n$ git checkout master\n$ git pull origin master\n```\n\n### Making a build\n\nNow that we implemented the number input functionality and have all tests passing we can make a build of our plugin that is usable standalone in the Browser, with an AMD module loader like [RequireJS](http://requirejs.org/) or as a CommonJS module which works e.g. with [Browserify](http://browserify.org/).\n\n```\n$ donejs build\n```\n\nWill create a `dist/` folder with the `global`, `amd` and `commonjs` version of our plugin.\n\n### Publishing to npm\n\n[npm][4] is the best way to share modules and make them easily installable without having to manage dependencies manually. To be able to publish your own modules, [create a new account][21] and then run\n\n```\n$ npm login\n```\n\n[Semantic versioning][22] is a great way to communicate new features and breaking changes. The generated plugin already comes with the release scripts to publish new versions according to the `major.minor.patch` schema. In our case to publish an initial version `0.1.0` we can run\n\n```\n$ donejs release:minor\n```\n\nNow version `0.1.0` of our plugin is available on npm.\n\n### Usage in other projects\n\nIn another DoneJS application we can now install the plugin with\n\n```\n$ npm install donejs-number-input --save\n```\n\n> For your own published plugin you would use `<username>-number-import` of course.\n\nThen import it in a template and load it with:\n\n```html\n<can-import from=\"<username>-number-input\" />\n<donejs-number-input></donejs-number-input>\n```\n\n## Show it off\n\nOnce you published your plugin, let the world know about it. [Tweet @donejs](https://twitter.com/donejs) and post it in the [Bitovi forums](https://forums.bitovi.com/) and on [Slack](https://www.bitovi.com/community/slack) (in the [#donejs channel](https://bitovi-community.slack.com/messages/CFC80DU5B)).\nThose are also great places to get quick help with any questions.\n\n [1]: https://donejs.com/\n [2]: http://getbootstrap.com/\n [3]: https://github.com\n [4]: https://www.npmjs.com/\n [5]: https://en.wikipedia.org/wiki/Continuous_integration\n [6]: https://github.com/join?source=header-home\n [7]: https://help.github.com/articles/set-up-git/\n [8]: http://www.bitovi.com/hubfs/Imported_Blog_Media/Screen-Shot-2016-02-16-at-1.53.10-PM.png\n [9]: static/img/donejs-plugin.png\n [10]: https://jenkins-ci.org/\n [11]: https://travis-ci.org/\n [12]: http://www.bitovi.com/hubfs/Imported_Blog_Media/Screen-Shot-2016-02-16-at-2.03.56-PM.png\n [13]: http://localhost:8080/src/test/test.html\n [14]: http://localhost:8080/src/donejs-number-input.html\n [15]: http://localhost:8080/src/test.html\n [16]: https://canjs.com/docs/can.Map.prototype.define.html\n [17]: https://canjs.com/docs/can.Map.prototype.define.set.html\n [18]: https://help.github.com/articles/using-pull-requests/\n [19]: http://www.bitovi.com/hubfs/Imported_Blog_Media/Screen-Shot-2016-02-16-at-8.17.50-AM.png\n [20]: http://www.bitovi.com/hubfs/Imported_Blog_Media/Screen-Shot-2016-02-16-at-8.30.41-AM.png\n [21]: https://www.npmjs.com/signup\n [22]: http://semver.org/\n [23]: https://canjs.com/doc/can-view-import.html\n\n",
"description": "DoneJS doesn't just make it easy to build high performance, real-time web and mobile applications. It can also be used to create reusable plugins that can be shared across different applications. In this guide we will create a reusable number input widget using [Bootstrap](http://getbootstrap.com) styles. \n",
"name": "plugin",
"title": "Creating a plugin",
"type": "page",
"parent": "Guides",
"hideSidebar": true,
"outline": {
"depth": 2,
"tag": "ol"
},
"comment": " "
},
"presentations": {
"src": {
"path": "docs/guides/presentations.md"
},
"body": "The following talks & trainings are available in the [Presentations folder on Google Drive](https://drive.google.com/open?id=0Bx-kNqf-wxZeaWc2ay1ZSzZZQXc).\n\nSome of the presentations are complete and have been used before; others are a work in progress. Please [email Chasen Le Hara](mailto:chasen@bitovi.com) if you plan on developing or improving a presentation.\n\nIf you make changes to one of the presentations, please bring it to the top of the list so it’s sorted by most recently updated presentations.\n\n## Full List\n\n### High-Performance Apps with DoneJS\n\n- [Description](https://drive.google.com/open?id=0B8wssyNpvaFEQXhYVjdVX2FzR28)\n- [Download](https://drive.google.com/open?id=0B8wssyNpvaFEZng3RU5ZYVhfaDg)\n- Last Modified: 2017-08-01\n\n### StealJS Progressive Loading Guide\n\n- [Download](https://drive.google.com/open?id=0Bx-kNqf-wxZeSlB2SjZ1X09YMVk)\n- Last Modified: 2017-07-25\n\n### Intro to CanJS — Building a Weather Report\n\n- [Description](https://drive.google.com/open?id=0B8wssyNpvaFEcjVUeXRITUJkSms)\n- [Download Slides (Keynote)](https://drive.google.com/open?id=0B8wssyNpvaFEbFBTNjhiSEt6Z2c)\n- [Download Slides (PDF)](https://drive.google.com/open?id=0B8wssyNpvaFEVnJUSFZyaXlxYnc)\n- Last Modified: 2017-06-12\n\n### The Who, What, Where, When, Why, and How of Open Source\n\n- [Description](https://drive.google.com/open?id=0B8wssyNpvaFETkdpMWU4QzJ3WXM)\n- [Download Slides (Keynote)](https://drive.google.com/open?id=0B8wssyNpvaFENzFQdWRzaENSQnc)\n- Last Modified: 2017-05-10\n\n### Preparing for the Future of JavaScript\n\n- [Description](https://drive.google.com/open?id=0B8wssyNpvaFEeTNGdkNuR2k0YzQ)\n- Last Modified: 2017-04-12\n\n### Getting to Know CanJS 3\n\n- [Description](https://drive.google.com/open?id=0B8wssyNpvaFEVTJQZHJyVGhid0U)\n- Last Modified: 2017-02-15\n\n### Harnessing the Power of Set Logic in Your Model Layer\n\n- [Description](https://drive.google.com/open?id=0B8wssyNpvaFEWmFCYkUwcnRCMU0)\n- Last Modified: 2017-02-15\n\n### Dynamic Animations with Declarative Templates\n\n- [Description](https://drive.google.com/open?id=0B8wssyNpvaFEek5SZFRzdy00Mk0)\n- Last Modified: 2017-02-01\n\n### StealJS Training\n\n- [Download](https://drive.google.com/open?id=0B09kZkWwiRDvNGZZTWx1Z0tqZUk)\n- Last Modified: 2017-02-01\n\n### Lightning-Fast DOM Updates with CanJS\n\n- [Description](https://drive.google.com/open?id=0B8wssyNpvaFEb244MkRjdEs4d1U)\n- Last Modified: 2017-01-31\n\n### Easy Module Loading with StealJS\n\n- [Description](https://drive.google.com/open?id=0B8wssyNpvaFEcVdyUGNFZ2xNSEk)\n- [Download](https://drive.google.com/open?id=0B09kZkWwiRDvUkU5aW5RZnJtT2s)\n- Last Modified: 2017-01-31\n\n### Server-Side Rendering Ain’t Easy\n\n- [Description](https://drive.google.com/open?id=0B8wssyNpvaFENDFqV3JyWWdSNzA)\n- [Download](https://drive.google.com/open?id=0Bx-kNqf-wxZed3pDNHprbFppc2s)\n- Last Modified: 2017-01-18\n\n### Writing Plugins: The On-Ramp to Modern JavaScript\n\n- [Description](https://drive.google.com/open?id=0B8wssyNpvaFEdDdWT29sX1BibHc)\n- Last Modified: 2017-01-19\n\n### Real-Time with CanJS\n\n- [Description](https://drive.google.com/open?id=0B8wssyNpvaFEN21ESzVLVXphLWs)\n- Last Modified: 2017-01-18\n\n### Object-Oriented and Functional Programming with CanJS\n\n- [Description](https://drive.google.com/open?id=0B8wssyNpvaFEc1J0cTRXYVY2U0U)\n- Last Modified: 2017-01-18\n\n### Federated State with CanJS\n\n- [Description](https://drive.google.com/open?id=0B8wssyNpvaFEOXNCeWxBWHYyazA)\n- Last Modified: 2017-01-18\n\n### MVVM Separation of Concerns with CanJS\n\n- [Description](https://drive.google.com/open?id=0B8wssyNpvaFESnB4U1VJTkxOSFE)\n- Last Modified: 2017-01-18\n\n### Module Loaders: Master the Pipeline\n\n- [Description](https://drive.google.com/open?id=0B8wssyNpvaFEYURlQl95eGprWnM)\n- Last Modified: 2017-01-18\n\n### Using can-connect with Angular 2\n\n- [Description](https://drive.google.com/open?id=0B8wssyNpvaFERDdKckZOTTcyc00)\n- Last Modified: 2017-01-18\n\n### Building Progressive Web Apps with DoneJS\n\n- [Description](https://drive.google.com/open?id=0B8wssyNpvaFEZGJnU1Ezd3A0SG8)\n- Last Modified: 2017-01-18\n\n### Does your DI framework belong in JS?\n\n- [Description](https://drive.google.com/open?id=0B8wssyNpvaFEekhNVWhXOGl6aDg)\n- Last Modified: 2017-01-18\n\n### How DDD & TDD Saved My Bacon\n\n- [Description](https://drive.google.com/open?id=0B8wssyNpvaFEdnZRSXdBR2hELUE)\n- Last Modified: 2017-01-18\n\n### Your Framework Won’t Save You\n\n- [Description](https://drive.google.com/open?id=0B8wssyNpvaFEeEdEUGtVNWh6Tlk)\n- Last Modified: 2017-01-17\n\n### The Modlet Pattern: A Better Way to Organize Your Front-End Code\n\n- [Description](https://drive.google.com/open?id=0B8wssyNpvaFEUU9aYnpVNTN1Z2c)\n- [Download](https://drive.google.com/open?id=0BwYNuFd8LhXyWFNnN2xmMGZMaG8)\n- Last Modified: 2017-01-04\n\n### Getting can-set and real-time to work\n\n- [Download](https://drive.google.com/open?id=0Bx-kNqf-wxZeQTF5WE5OTU9mZlk)\n- Last Modified: 2016-12-14\n\n### TodoMVC Intro to CanJS\n\n- [Download](https://drive.google.com/open?id=0Bx-kNqf-wxZeVEoxeXRMZHIweE0)\n- Last Modified: 2016-11-22\n\n### Bitballs\n\n- [Download](https://drive.google.com/open?id=0Bx1SymulhNqNUE94VE9RSTNyaXc)\n- Last Modified: 2016-11-16\n\n### can-define-stream\n\n- [Download](https://drive.google.com/open?id=0Bx-kNqf-wxZeazU3NUN5aGxTTVU)\n- Last Modified: 2016-10-26\n\n### can-define\n\n- [Download](https://drive.google.com/open?id=0Bx-kNqf-wxZeaXdJNUJBYi01T0k)\n- Last Modified: 2016-08-22\n\n### DoneJS Place My Order\n\n- [Download](https://drive.google.com/open?id=0Bx-kNqf-wxZeT2pJUnh3RTZZclk)\n- Last Modified: 2016-07-29\n\n### EZPZ ES6 (StealJS Quick Start)\n\n- [Download](https://drive.google.com/open?id=0BwsllsHQy1SdYm1BMmxjbzFuUEE)\n- Last Modified: 2016-06-07\n\n### Worker Thread Rendering\n\n- [Download](https://drive.google.com/open?id=0B09kZkWwiRDvc2NLV05QME10UVU)\n- Last Modified: 2016-05-16\n\n### Comprehensive Testing\n\n- [Download](https://drive.google.com/open?id=0B8wssyNpvaFENDh2UkZ2WnVpdTA)\n- Last Modified: 2016-05-13\n\n### DoneJS Generators\n\n- [Download](https://drive.google.com/open?id=0B9Ygfgud0btpdExjT0R3TUtXZ00)\n- Last Modified: 2016-05-13\n\n### Desktop & Mobile Builds with DoneJS\n\n- [Download](https://drive.google.com/open?id=0B8wssyNpvaFEVXF3cmNWWlZxRTQ)\n- Last Modified: 2016-05-12\n\n### Overview of can-fixture\n\n- [Download](https://drive.google.com/open?id=0Bx-kNqf-wxZeeHc5SjdfczNnN3M)\n- Last Modified: 2016-04-26\n\n### can-map-define\n\n- [Download](https://drive.google.com/open?id=0Bx-kNqf-wxZeS1BRX3JuaFc0dVk)\n- Last Modified: 2016-04-12\n\n### Continuous Integration Testing\n\n- [Download](https://drive.google.com/open?id=0Bx-kNqf-wxZeVDVXUHlZYzluTWc)\n- Last Modified: 2016-04-12\n\n### Module Loading — Past, Present, Future\n\n- [Download](https://drive.google.com/open?id=0Bx-kNqf-wxZeem9ZOEF3YWR5d3c)\n- Last Modified: 2016-04-12\n\n### Server-Side Rendering Isn’t Enough\n\n- [Download](https://drive.google.com/open?id=0Bx-kNqf-wxZeY0pFWGJjQ2s4MHM)\n- Last Modified: 2016-01-25\n\n### DoneJS Overview\n\n- [Download](https://drive.google.com/open?id=0Bx-kNqf-wxZeak9BMWVOelIzR0E)\n- Last Modified: 2016-01-25\n\n### Building SPAs the “right” way\n\n- [Download](https://drive.google.com/open?id=0Bx-kNqf-wxZeQmhxWUprOUdZQ1E)\n- Last Modified: 2016-01-15\n\n### can-set\n\n- [Download](https://drive.google.com/open?id=0Bx-kNqf-wxZeVEtLOTd6RGVlbEE)\n- Last Modified: 2015-08-21\n\n### can-connect\n\n- [Download](https://drive.google.com/open?id=0Bx-kNqf-wxZeb0FuUUJJX2t3Nms)\n- Last Modified: 2015-08-21\n\n### Change Detection in JavaScript Applications\n\n- [Description](https://drive.google.com/open?id=0B9StcZoMxwPeZklBUF9YdlAwdm8)\n- Last Modified: 2017-03-14\n\n",
"description": "\n",
"name": "presentations",
"title": "Presentations",
"type": "page",
"parent": "contributing",
"hideSidebar": true,
"outline": {
"depth": 1,
"tag": "ol"
},
"comment": " "
},
"Guides": {
"src": {
"path": "docs/guides/guides.md"
},
"body": "\n## [Quick start: donejs-chat](./Guide.html)\n<a href=\"./Guide.html\"><img class=\"app-thumbs\" src=\"static/img/donejs-chat.gif\" width=\"500\" style=\"border: 1px solid #000\"></a>\n\nIn the [quick start guide](./Guide.html), we will build a small chat application - [https://chat.donejs.com/](https://chat.donejs.com/). You'll learn about:\n\n- Hot Module Swapping\n- Server-side rendering\n- Progressive loading\n- Real time connections\n- Building and deploying to a CDN.\n- Builds to Cordova (mobile) and NW.js (desktop).\n\n## [In-depth: place-my-order](./place-my-order.html)\n<a href=\"./place-my-order.html\"><img class=\"app-thumbs\" src=\"static/img/thumb-pmo.png\" srcset=\"static/img/thumb-pmo.png 1x, static/img/thumb-pmo-2x.png 2x\"></a>\n\n\nIn the [place-my-order guide](./place-my-order.html), we will go into detail, creating [http://www.place-my-order.com](http://www.place-my-order.com), a restaurant menu order application. You'll learn everything covered in the \"Quick start\", plus more:\n\n- MVVM architecture\n- Testing\n- Nested routing\n- Continuous integration and continuous deployment\n- Documentation\n\n## [Creating a plugin](./plugin.html)\n<a href=\"./plugin.html\"><img class=\"app-thumbs\" src=\"static/img/thumb-plugin.png\" srcset=\"static/img/thumb-plugin.png 1x, static/img/thumb-plugin-2x.png 2x\"></a>\n\n\nIn the [plugin guide](plugin.html), we will create a reusable number input widget using [Bootstrap](http://getbootstrap.com) styles. We will cover:\n\n- Create the project on GitHub\n- Initialize the repository as a new DoneJS plugin\n- Set up continuous integration with Travis CI\n- Start development mode\n- Implement the component functionality and tests\n- Make a pull request to the repository\n- Make a build\n- Publish to npm\n- Use the plugin in other projects\n\n## [Example App: Bitballs](./bitballs.html)\n\n<a href=\"./bitballs.html\"><img class=\"app-thumbs\" src=\"static/img/bitballs/bitballs-video.png\" srcset=\"static/img/bitballs/bitballs-video.png 1x, static/img/bitballs/bitballs-video-2x.png 2x\"></a>\n\nIn this guide, you'll learn how [Bitballs](http://bitballs.herokuapp.com) - a charity basketball tournament management application - works.\nSpecifically, this guide will walk through the implementation of the following behaviors or functionality:\n\n - Registration, login, user sessions, and access rights.\n - Handling relationships between model types.\n - Setup node services and server-side rendering on the same process.\n - How to turn off parts of the app that should not be server-side rendered.\n\n## [migrate-1]\n\nExplains how to upgrade DoneJS 0.9 app to 1.0.\n\n## [migrate-2]\n\nExplains how to upgrade DoneJS 1.0 app to 2.0.\n\n## [migrate-3]\n\nExplains how to upgrade DoneJS 2.0 app to 3.0.\n\n## [contributing]\n\nThe [contributing contribution guide] includes information about our code of conduct, reporting bugs, submitting new code, and more!\n\n## [ssr-react]\n\nIn this guide you'll learn how to use the great features of [done-ssr](https://github.com/donejs/done-ssr) outside of a traditional DoneJS app. This guide walks through building a [React](https://reactjs.org/) app with a streaming list, and then building an HTTP/2 server that renders using done-ssr and [can-zone](https://github.com/canjs/can-zone).\n\n",
"description": "DoneJS is about getting your application ... __done__ ... so you can spend time with your friends and family. To demonstrate how easy it is to make something amazing with all the bells and\nwhistles a modern developer needs, we created the following guides.\n\n\n",
"name": "Guides",
"type": "page",
"parent": "DoneJS",
"hideSidebar": true,
"outline": {
"depth": 2,
"tag": "ol"
},
"comment": " "
},
"place-my-order": {
"src": {
"path": "docs/guides/place-my-order.md"
},
"body": "\n## Set up the project\n\nIn this section we will create our DoneJS project and set up a RESTful API for the application to use.\nYou will need [NodeJS](http://nodejs.org) installed and your code editor of choice.\n\n> If you haven't already, check out the [SettingUp] guide to ensure you have all of the prerequisites installed and configured.\n\n### Create the project\n\nTo get started, let's install the DoneJS command line utility globally:\n\n```shell\nnpm install -g donejs@3\n```\n\nThen we can create a new DoneJS application:\n\n```shell\ndonejs add app place-my-order --yes\n```\n\nThe initialization process will ask you questions like the name of your application (set to `place-my-order`) and the source folder (set to `src`). The other questions can be skipped by hitting enter. This will install all of DoneJS' dependencies. The main project dependencies include:\n\n- [StealJS](https://stealjs.com) - ES6, CJS, and AMD module loader and builder\n- [CanJS](https://canjs.com) - Custom elements and Model-View-ViewModel utilities\n- [done-ssr](https://github.com/donejs/done-ssr) - Server-rendering\n- [QUnit](https://qunitjs.com/) or Mocha - Assertion library\n- [FuncUnit](https://funcunit.com) - Functional tests\n- [Testee](https://github.com/bitovi/testee) - Test runner\n\nIf we now go into the `place-my-order` folder with\n\n```shell\ncd place-my-order\n```\n\nWe can see the following files:\n\n```shell\n├── build.js\n├── development.html\n├── package.json\n├── production.html\n├── README.md\n├── test.html\n├── src/\n| ├── app.js\n| ├── index.stache\n| ├── is-dev.js\n| ├── models/\n| | ├── fixtures\n| | | ├── fixtures.js\n| | ├── test.js\n| ├── styles.less\n| ├── test.js\n├── node_modules/\n```\n\nLet's have a quick look at the purpose of each:\n\n- [`development.html`](https://github.com/donejs/generator-donejs#developmenthtml), [`production.html`](https://github.com/donejs/generator-donejs#productionhtml) those pages can run the DoneJS application in development or production mode without a server.\n- `package.json` is the main configuration file that defines all our application dependencies and other settings.\n- `test.html` is used to run all our tests.\n- `README.md` is the readme file for your repository.\n- `src` is the folder where all our development assets live in their own modlets (more about that later).\n- `src/app.js` is the main application file, which exports the main application state.\n- `src/index.stache` is the main client template that includes server-side rendering.\n- `src/is-dev.js` is used to conditional load modules in development-mode only.\n- `src/models/` is the folder where models for the API connection will be put. It currently contains `fixtures/fixtures.js` which will reference all the specific models fixtures files (so that we can run model tests without the need for a running API server) and `test.js` which will later gather all the individual model test files.\n- `src/styles.less` is the main application styles.\n- `src/test.js` collects all individual component and model tests we will create throughout this guide as well as the functional smoke test for our application and is loaded by `test.html`.\n\n### Development mode\n\nDoneJS comes with its own server, which hosts your development files and takes care of server-side rendering. DoneJS' development mode will also enable [hot module swapping](http://blog.bitovi.com/hot-module-replacement-comes-to-stealjs/) which automatically reloads files in the browser as they change. You can start it by running:\n\n```shell\ndonejs develop\n```\n\nThe default port is 8080, so if we now go to [http://localhost:8080/] we can see our application with a default homepage. If we change `src/index.stache` or `src/app.js` all changes will show up right away in the browser. Try it by adding some HTML in `src/index.stache`.\n\n### Setup a service API\n\nSingle page applications often communicate with a RESTful API and a [WebSocket connection](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) for real-time updates. This guide will not cover how to create a REST API. Instead, we'll just install and start an existing service API created specifically for use with this tutorial:\n\n**Note**: Kill the server for now while we install a few dependencies (ctrl+c on Windows and Mac).\n\n```shell\nnpm install place-my-order-api@1 --save\n```\n\nNow we can add an API server start script into the `scripts` section of our `package.json` like this:\n\n```js\n \"scripts\": {\n \"api\": \"place-my-order-api --port 7070\",\n \"test\": \"testee test.html --browsers firefox --reporter Spec\",\n \"start\": \"done-serve --port 8080\",\n \"develop\": \"done-serve --develop --port 8080\",\n \"build\": \"node build\"\n },\n```\n\n<div line-highlight='2,2,only'></div>\n\nWhich allows us to start the server like:\n\n```shell\ndonejs api\n```\n\nThe first time it starts, the server will initialize some default data (restaurants and orders). Once started, you can verify that the data has been created and the service is running by going to [http://localhost:7070/restaurants](http://localhost:7070/restaurants), where we can see a JSON list of restaurant data.\n\n### Starting the application\n\nNow our application is good to go and we can start the server. We need to proxy the `place-my-order-api` server to `/api` on our server in order to avoid violating the [same origin policy](https://en.wikipedia.org/wiki/Same-origin_policy). This means that we need to modify the `start` and `develop` script in our `package.json` to:\n\n```js\n\"scripts\": {\n \"api\": \"place-my-order-api --port 7070\",\n \"test\": \"testee test.html --browsers firefox --reporter Spec\",\n \"start\": \"done-serve --proxy http://localhost:7070 --port 8080\",\n \"develop\": \"done-serve --develop --proxy http://localhost:7070 --port 8080\",\n \"build\": \"node build\"\n},\n```\n\n<div line-highlight='4,5,only'></div>\n\nNow we can start the application with:\n\n```shell\ndonejs develop\n```\n\nGo to [http://localhost:8080](http://localhost:8080) to see the \"hello world\" message again.\n\n### Loading assets\n\nBefore we get to the code, we also need to install the `place-my-order-assets` package which contains the images and styles specifically for this tutorial's application:\n\n```shell\nnpm install place-my-order-assets@0.1 --save\n```\n\nEvery DoneJS application consists of at least two files:\n\n 1. **A main template** (in this case `src/index.stache`) which contains the main template and links to the development or production assets.\n 1. **A main application view-model** (`src/app.js`) that initializes the application state and routes.\n\n`src/index.stache` was already created for us when we ran `donejs add app`, so update it to\nload the static assets and set a `<meta>` tag to support a responsive design:\n\n\n```html\n<html>\n <head>\n <title>{{this.title}}</title>\n <meta name=\"viewport\" content=\"minimal-ui, width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\">\n </head>\n <body>\n <can-import from=\"place-my-order-assets\" />\n <can-import from=\"~/styles.less\" />\n <can-import from=\"~/app\" export-as=\"viewModel\" route-data=\"routeData\" />\n\n <h1>The <strong>{{this.routeData.page}}</strong> page</h1>\n\n {{#eq(this.env.NODE_ENV, \"production\")}}\n <script src=\"{{joinBase('steal.production.js')}}\"></script>\n {{else}}\n <script src=\"/node_modules/steal/steal.js\" main></script>\n {{/eq}}\n </body>\n</html>\n\n```\n<div line-highlight='4,7,only'></div>\n\nThis is an HTML5 template that uses [can-stache](https://canjs.com/doc/can-stache.html) - a [Handlebars syntax](http://handlebarsjs.com/)-compatible view engine. It renders a `message` property from the application state.\n\n`can-import` loads the template's dependencies:\n 1. The `place-my-order-assets` package, which loads the LESS styles for the application\n 1. `place-my-order/app`, which is the main application file\n\nThe main application file at `src/app.js` looks like this:\n\n```js\n// src/app.js\nimport { DefineMap, route } from 'can';\nimport RoutePushstate from 'can-route-pushstate';\nimport debug from 'can-debug#?./is-dev';\n\n//!steal-remove-start\nif(debug) {\n\tdebug();\n}\n//!steal-remove-end\n\nconst AppViewModel = DefineMap.extend(\"AppViewModel\", {\n env: {\n default: () => ({NODE_ENV:'development'})\n },\n title: {\n default: 'place-my-order'\n },\n routeData: {\n default: () => route.data\n }\n});\n\nroute.urlData = new RoutePushstate();\nroute.register(\"{page}\", { page: \"home\" });\n\nexport default AppViewModel;\n\n```\n\nThis initializes a [DefineMap](https://canjs.com/doc/can-define/map/map.html): a special object that acts as the application global state (with a default `message` property) and also plays a key role in enabling server side rendering.\n\n## Creating custom elements\n\nOne of the most important concepts in DoneJS is splitting up your application functionality into individual, self-contained modules. In the following section we will create separate components for the homepage, the restaurant list, and the order history page. After that, we will glue them all together using routes and the global application state.\n\nThere are two ways of creating components. For smaller components we can define all templates, styles and functionality in a single `.component` file (to learn more see [done-component](https://github.com/donejs/done-component)). Larger components can be split up into several separate files.\n\n### Creating a homepage element\n\nTo generate a new component run:\n\n```shell\ndonejs add component pages/home.component pmo-home\n```\n\nThis will create a file at `src/pages/home.component` containing the basic ingredients of a component. We will update it to reflect the below content:\n\n\n```html\n<can-component tag=\"pmo-home\">\n <style type=\"less\">\n display: block;\n\n p { font-weight: bold; }\n </style>\n <view>\n <can-import from=\"can-stache-route-helpers\" />\n <div class=\"homepage\">\n <img src=\"{{joinBase('node_modules/place-my-order-assets/images/homepage-hero.jpg')}}\"\n alt=\"Restaurant table with glasses.\" width=\"250\" height=\"380\" />\n <h1>Ordering food has never been easier</h1>\n <p>\n We make it easier than ever to order gourmet food\n from your favorite local restaurants.\n </p>\n <p>\n <a class=\"btn\" href=\"{{routeUrl(page='restaurants')}}\" role=\"button\">Choose a Restaurant</a>\n </p>\n </div>\n </view>\n <script type=\"view-model\">\n import { DefineMap } from 'can';\n\n export default DefineMap.extend(\"PmoHomeVM\", {\n // EXTERNAL STATEFUL PROPERTIES\n // These properties are passed from another component. Example:\n // value: {type: \"number\"}\n\n // INTERNAL STATEFUL PROPERTIES\n // These properties are owned by this component.\n message: { default: \"This is the pmo-home component\" },\n\n // DERIVED PROPERTIES\n // These properties combine other property values. Example:\n // get valueAndMessage(){ return this.value + this.message; }\n\n // METHODS\n // Functions that can be called by the view. Example:\n // incrementValue() { this.value++; }\n\n // SIDE EFFECTS\n // The following is a good place to perform changes to the DOM\n // or do things that don't fit in to one of the areas above.\n connectedCallback(element){\n\n }\n });\n </script>\n</can-component>\n\n```\n<div line-highlight='8-20,only'></div>\n\nHere we created a [can-component](https://canjs.com/doc/can-component.html) named `pmo-home`. This particular component is just a basic template, it does not have much in the way of styles or functionality.\n\n### Create the order history element\n\nWe'll create an initial version of order history that is very similar.\n\n```shell\ndonejs add component pages/order/history.component pmo-order-history\n```\n\nAnd update `src/pages/order/history.component`:\n\n\n```html\n<can-component tag=\"pmo-order-history\">\n <style type=\"less\">\n display: block;\n\n p { font-weight: bold; }\n </style>\n <view>\n <div class=\"order-history\">\n <div class=\"order header\">\n <address>Name / Address / Phone</address>\n <div class=\"items\">Order</div>\n <div class=\"total\">Total</div>\n <div class=\"actions\">Action</div>\n </div>\n </div>\n </view>\n <script type=\"view-model\">\n import { DefineMap } from 'can';\n\n export default DefineMap.extend(\"PmoOrderHistoryVM\", {\n // EXTERNAL STATEFUL PROPERTIES\n // These properties are passed from another component. Example:\n // value: {type: \"number\"}\n\n // INTERNAL STATEFUL PROPERTIES\n // These properties are owned by this component.\n message: { default: \"This is the pmo-order-history component\" },\n\n // DERIVED PROPERTIES\n // These properties combine other property values. Example:\n // get valueAndMessage(){ return this.value + this.message; }\n\n // METHODS\n // Functions that can be called by the view. Example:\n // incrementValue() { this.value++; }\n\n // SIDE EFFECTS\n // The following is a good place to perform changes to the DOM\n // or do things that don't fit in to one of the areas above.\n connectedCallback(element){\n\n }\n });\n </script>\n</can-component>\n\n```\n<div line-highlight='8-15,only'></div>\n\n### Creating a restaurant list element\n\nThe restaurant list will contain more functionality, which is why we will split its template and component logic into separate files.\n\nWe can create a basic component like that by running:\n\n```shell\ndonejs add component pages/restaurant/list pmo-restaurant-list\n```\n\nThe component's files are collected in a single folder so that components can be easily tested, moved, and re-used. The folder structure looks like this:\n\n```shell\n├── node_modules\n├── package.json\n├── src/\n| ├── app.js\n| ├── index.md\n| ├── index.stache\n| ├── test.js\n| ├── models\n| ├── pages/\n| | ├── order/\n| | | ├── history.component\n| | ├── restaurant/\n| | | ├── list/\n| | | | ├── list.html\n| | | | ├── list.js\n| | | | ├── list.less\n| | | | ├── list.md\n| | | | ├── list.stache\n| | | | ├── list-test.js\n| | | | ├── test.html\n```\n\nWe will learn more about those files and add more functionality to this element later, but it already contains a fully functional component with a demo page (see [localhost:8080/src/pages/restaurant/list/list.html](http://localhost:8080/src/pages/restaurant/list/list.html)), a basic test (at [localhost:8080/src/pages/restaurant/list/test.html](http://localhost:8080/src/pages/restaurant/list/test.html)) and documentation placeholders.\n\n## Setting up routing\n\nIn this part, we will create routes - URL patterns that load specific parts of our single page app. We'll also dynamically load the custom elements we created and integrate them in the application's main page.\n\n### Create Routes\n\nRouting works a bit differently than other libraries. In other libraries, you might declare routes and map those to controller-like actions.\n\nDoneJS application [routes](https://canjs.com/doc/can-route.html) map URL strings (like /user/1) to properties in our application state. In other words, our routes will just be a representation of the application state.\n\nTo learn more about routing visit the [CanJS routing guide](https://canjs.com/doc/guides/routing.html).\n\nTo add our routes, change `src/app.js` to:\n\n\n```js\nimport { DefineMap, route } from 'can';\nimport RoutePushstate from 'can-route-pushstate';\nimport debug from 'can-debug#?./is-dev';\n\n//!steal-remove-start\nif(debug) {\n\tdebug();\n}\n//!steal-remove-end\n\nconst AppViewModel = DefineMap.extend(\"AppViewModel\", {\n page: 'string',\n slug: 'string',\n action: 'string',\n env: {\n default: () => ({NODE_ENV:'development'})\n },\n title: {\n default: 'place-my-order'\n },\n routeData: {\n default: () => route.data\n }\n});\n\nroute.urlData = new RoutePushstate();\nroute.register(\"{page}\", { page: \"home\" });\nroute.register('{page}/{slug}', { slug: null });\nroute.register('{page}/{slug}/{action}', { slug: null, action: null });\n\nexport default AppViewModel;\n\n```\n<div line-highlight='12-14,28-29,only'></div>\n\nNow we have three routes available:\n\n- `{page}` captures urls like [http://localhost:8080/home](http://localhost:8080/home) and sets the `page` property on `routeData` to `home` (which is also the default when visiting [http://localhost:8080/](http://localhost:8080/))\n- `{page}/{slug}` matches restaurant links like [http://localhost:8080/restaurants/spago](http://localhost:8080/restaurants/spago) and sets `page` and `slug` (a URL friendly restaurant short name)\n- `{page}/{slug}/{action}` will be used to show the order page for a specific restaurant e.g. [http://localhost:8080/restaurants/spago/order](http://localhost:8080/restaurants/spago/order)\n\n### Adding a header element\n\nNow is also a good time to add a header element that links to the different routes we just defined. We can run\n\n```shell\ndonejs add component components/header.component pmo-header\n```\n\nand update `src/components/header.component` to:\n\n\n```html\n<can-component tag=\"pmo-header\">\n <style type=\"less\">\n display: block;\n\n p { font-weight: bold; }\n </style>\n <view>\n <can-import from=\"can-stache-route-helpers\" />\n <header>\n <nav>\n <h1>place-my-order.com</h1>\n <ul>\n <li class=\"{{#eq(this.page, 'home')}}active{{/eq}}\">\n <a href=\"{{routeUrl(page='home')}}\">Home</a>\n </li>\n <li class=\"{{#eq(this.page, 'restaurants')}}active{{/eq}}\">\n <a href=\"{{routeUrl(page='restaurants')}}\">Restaurants</a>\n </li>\n <li class=\"{{#eq(this.page, 'order-history')}}active{{/eq}}\">\n <a href=\"{{routeUrl(page='order-history')}}\">Order History</a>\n </li>\n </ul>\n </nav>\n </header>\n </view>\n <script type=\"view-model\">\n import { DefineMap } from 'can';\n\n export default DefineMap.extend(\"PmoHeaderVM\", {\n // EXTERNAL STATEFUL PROPERTIES\n // These properties are passed from another component. Example:\n // value: {type: \"number\"}\n page: \"string\",\n\n // INTERNAL STATEFUL PROPERTIES\n // These properties are owned by this component.\n message: { default: \"This is the pmo-header component\" },\n\n // DERIVED PROPERTIES\n // These properties combine other property values. Example:\n // get valueAndMessage(){ return this.value + this.message; }\n\n // METHODS\n // Functions that can be called by the view. Example:\n // incrementValue() { this.value++; }\n\n // SIDE EFFECTS\n // The following is a good place to perform changes to the DOM\n // or do things that don't fit in to one of the areas above.\n connectedCallback(element){\n\n }\n });\n </script>\n</can-component>\n\n```\n<div line-highlight='8-24,33,only'></div>\n\nHere we use [routeUrl](https://canjs.com/doc/can-stache.helpers.routeUrl.html) to create links that will set values in the application state. For example, the first usage of routeUrl above will create a link based on the current routing rules ([http://localhost:8080/home](http://localhost:8080/home) in this case) that sets the `page` property to `home` when clicked.\n\nWe also use the Stache `eq` helper to make the appropriate link active.\n\n### Switch between components\n\nNow we can glue all those individual components together. What we want to do is - based on the current page (`home`, `restaurants` or `order-history`) - load the correct component and then initialize it.\n\nUpdate `src/app.js` to:\n\n\n```js\nimport { DefineMap, route } from 'can';\nimport RoutePushstate from 'can-route-pushstate';\nimport debug from 'can-debug#?./is-dev';\n\n//!steal-remove-start\nif(debug) {\n\tdebug();\n}\n//!steal-remove-end\n\nconst AppViewModel = DefineMap.extend(\"AppViewModel\", {\n\tpage: 'string',\n\tslug: 'string',\n\taction: 'string',\n env: {\n default: () => ({NODE_ENV:'development'})\n },\n title: {\n default: 'place-my-order'\n },\n routeData: {\n default: () => route.data\n },\n get pageComponent() {\n switch(this.routeData.page) {\n case 'home': {\n return steal.import('~/pages/home.component').then(({default: Home}) => {\n return new Home();\n });\n }\n\n case 'restaurants': {\n return steal.import('~/pages/restaurant/list/').then(({default: RestaurantList}) => {\n return new RestaurantList();\n });\n }\n\n case 'order-history': {\n return steal.import('~/pages/order/history.component').then(({default: OrderHistory}) => {\n return new OrderHistory();\n });\n }\n }\n }\n});\n\nroute.urlData = new RoutePushstate();\nroute.register(\"{page}\", { page: \"home\" });\nroute.register('{page}/{slug}', { slug: null });\nroute.register('{page}/{slug}/{action}', { slug: null, action: null });\n\nexport default AppViewModel;\n\n```\n<div line-highlight='23-44,only'></div>\n\nUpdate `src/index.stache` to:\n\n\n```html\n<html>\n <head>\n <title>{{this.title}}</title>\n <meta name=\"viewport\" content=\"minimal-ui, width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\">\n </head>\n <body>\n <can-import from=\"place-my-order-assets\" />\n <can-import from=\"~/styles.less\" />\n <can-import from=\"~/app\" export-as=\"viewModel\" route-data=\"routeData\" />\n\n <can-import from=\"~/components/header.component\" />\n <pmo-header page:from=\"this.routeData.page\"/>\n\n {{#if(this.pageComponent.isResolved)}}\n {{this.pageComponent.value}}\n {{else}}\n <div class=\"loading\"></div>\n {{/if}}\n\n {{#eq(this.env.NODE_ENV, \"production\")}}\n <script src=\"{{joinBase('steal.production.js')}}\"></script>\n {{else}}\n <script src=\"/node_modules/steal/steal.js\" main></script>\n {{/eq}}\n </body>\n</html>\n\n```\n<div line-highlight='11-12,14-18,only'></div>\n\nHere we use a `switch` statement that checks for the current `page` property on the `route.data`, then progressively loads the component with [steal.import](https://stealjs.com/docs/steal.import.html) and [initializes it](https://canjs.com/doc/can-component.html#newComponent__options__).\n\nIn the template `{{#if(this.pageComponent.isResolved)}}` shows a loading indicator while the page loads, and then inserts the page (the one instantiated in the Application ViewModel) with `{{this.pageComponent.value}}`.\n\nNow we can see the header and the home component and be able to navigate to the different pages through the header.\n\n## Getting Data from the Server\n\nIn this next part, we'll connect to the RESTful API that we set up with `place-my-order-api`, using the powerful data layer provided by [CanJS](https://canjs.com) with [QueryLogic](https://canjs.com/doc/can-query-logic.html) and [realtimeRestModel](https://canjs.com/doc/can-realtime-rest-model.html).\n\n### Creating a restaurants connection\n\nAt the beginning of this guide we set up a REST API at [http://localhost:7070](http://localhost:7070) and told `done-serve` to proxy it to http://localhost:8080/api.\n\nTo manage the restaurant data located at [http://localhost:8080/api/restaurants](http://localhost:8080/api/restaurants), we'll create a restaurant supermodel:\n\n```js\ndonejs add supermodel restaurant\n```\n\nAnswer the question about the URL endpoint with `/api/restaurants` and the name of the id property with `_id`.\n\nWe have now created a model and fixtures (for testing without an API) with a folder structure like this:\n\n```shell\n├── node_modules\n├── package.json\n├── src/\n| ├── app.js\n| ├── index.md\n| ├── index.stache\n| ├── test.js\n| ├── models/\n| | ├── fixtures/\n| | | ├── restaurants.js\n| | ├── fixtures.js\n| | ├── restaurant.js\n| | ├── restaurant-test.js\n| | ├── test.js\n```\n\n### Test the connection\n\nTo test the connection you can run the following in the browser console. You can access the browser console by right clicking in the browser and selecting **Inspect**. Then switch to the **Console** tab if not already there. Test the connection with:\n\n```js\nsteal.import(\"place-my-order/models/restaurant\")\n .then(function(module) {\n let Restaurant = module[\"default\"];\n return Restaurant.getList({});\n }).then(function(restaurants) {\n console.log(restaurants);\n });\n```\n\nThis programmatically imports the `Restaurant` model and uses it to get a list\nof all restaurants on the server and log them to the console.\n\n### Add data to the page\n\nNow, update the `ViewModel` in `src/pages/restaurant/list/list.js` to load all restaurants from the restaurant connection:\n\n\n```js\nimport { Component } from 'can';\nimport './list.less';\nimport view from './list.stache';\nimport Restaurant from '~/models/restaurant';\n\nconst RestaurantList = Component.extend({\n tag: 'pmo-restaurant-list',\n view,\n ViewModel: {\n // EXTERNAL STATEFUL PROPERTIES\n // These properties are passed from another component. Example:\n // value: {type: \"number\"}\n\n // INTERNAL STATEFUL PROPERTIES\n // These properties are owned by this component.\n restaurants: {\n default() {\n return Restaurant.getList({});\n }\n },\n\n // DERIVED PROPERTIES\n // These properties combine other property values. Example:\n // get valueAndMessage(){ return this.value + this.message; }\n\n // METHODS\n // Functions that can be called by the view. Example:\n // incrementValue() { this.value++; }\n\n // SIDE EFFECTS\n // The following is a good place to perform changes to the DOM\n // or do things that don't fit in to one of the areas above.\n connectedCallback(element){\n\n }\n }\n});\n\nexport default RestaurantList;\nexport const ViewModel = RestaurantList.ViewModel;\n\n```\n<div line-highlight='4,16-20,only'></div>\n\n> *Note*: we also removed the __message__ property.\n\nAnd update the template at `src/pages/restaurant/list/list.stache` to use the [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) returned for the `restaurants` property to render the template:\n\n\n```html\n<can-import from=\"can-stache-route-helpers\" />\n\n<div class=\"restaurants\">\n <h2 class=\"page-header\">Restaurants</h2>\n {{#if(this.restaurants.isPending)}}\n <div class=\"restaurant loading\"></div>\n {{/if}}\n\n {{#if(this.restaurants.isResolved)}}\n {{#for(restaurant of this.restaurants.value)}}\n {{let addr=restaurant.address}}\n\n <div class=\"restaurant\">\n <img src=\"{{joinBase(restaurant.images.thumbnail)}}\"\n width=\"100\" height=\"100\">\n <h3>{{restaurant.name}}</h3>\n \n {{#if(addr)}}\n <div class=\"address\">\n {{addr.street}}<br />{{addr.city}}, {{addr.state}} {{addr.zip}}\n </div>\n {{/if}}\n\n <div class=\"hours-price\">\n $$$<br />\n Hours: M-F 10am-11pm\n <span class=\"open-now\">Open Now</span>\n </div>\n\n <a class=\"btn\" href=\"{{routeUrl(page='restaurants' slug=restaurant.slug)}}\">\n Details\n </a>\n <br />\n </div>\n {{/for}}\n {{/if}}\n</div>\n\n```\n\nBy checking for `restaurants.isPending` and `restaurants.isResolved` we are able to show a loading indicator while the data are being retrieved. Once resolved, the actual restaurant list is available at `restaurants.value`. When navigating to the restaurants page now we can see a list of all restaurants.\n\nNote the usage of `routeUrl` to set up a link that points to each restaurant. `slug=slug` is not wrapped in quotes because the helper will populate each restaurant's individual `slug` property in the URL created.\n\n## Creating a unit-tested view model\n\nIn this section we will create a view model for the restaurant list functionality.\n\nWe'll show a dropdown of all available US states. When the user selects a state, we'll show a list of cities. Once a city is selected, we'll load a list of all restaurants for that city. The end result will look like this:\n\n![Restaurant list](static/img/restaurant-list.png)\n\n### Identify view model state\n\nFirst we need to identify the properties that our view model needs to provide. We want to load a list of states from the server and let the user select a single state. Then we do the same for cities and finally load the restaurant list for that selection.\n\nAll asynchronous requests return a Promise, so the data structure will look like this:\n\n```js\n{\n states: Promise<[State]>\n state: String \"IL\",\n cities: Promise<[City]>,\n city: String \"Chicago\",\n restaurants: Promise<[Restaurant]>\n}\n```\n\n### Create dependent models\n\nThe API already provides a list of available [states](http://localhost:8080/api/states) and [cities](http://localhost:8080/api/cities). To load them we can create the corresponding models like we already did for Restaurants.\n\nRun:\n\n```shell\ndonejs add supermodel state\n```\n\nWhen prompted, set the URL to `/api/states` and the id property to `short`.\n\nRun:\n\n```shell\ndonejs add supermodel city\n```\n\nWhen prompted, set the URL to `/api/cities` and the id property to `name`.\n\nNow we can load a list of states and cities.\n\n### Implement view model behavior\n\nNow that we have identified the view model properties needed and have created the models necessary to load them, we can [define](https://canjs.com/doc/can-define/map/map.html) the `states`, `state`, `cities` and `city` properties in the view model at `src/pages/restaurant/list/list.js`:\n\n\n```js\nimport { Component } from 'can';\nimport './list.less';\nimport view from './list.stache';\nimport Restaurant from '~/models/restaurant';\nimport State from '~/models/state';\nimport City from '~/models/city';\n\nconst RestaurantList = Component.extend({\n tag: 'pmo-restaurant-list',\n view,\n ViewModel: {\n // EXTERNAL STATEFUL PROPERTIES\n // These properties are passed from another component. Example:\n // value: {type: \"number\"}\n\n // INTERNAL STATEFUL PROPERTIES\n // These properties are owned by this component.\n get states() {\n return State.getList();\n },\n state: {\n type: 'string',\n default: null\n },\n get cities() {\n let state = this.state;\n\n if(!state) {\n return null;\n }\n\n return City.getList({ filter: { state } });\n },\n city: {\n type: 'string',\n value({lastSet, listenTo, resolve}) {\n listenTo(lastSet, resolve);\n listenTo('state', () => resolve(null));\n resolve(null)\n }\n },\n get restaurants() {\n let state = this.state;\n let city = this.city;\n\n if(state && city) {\n return Restaurant.getList({\n filter: {\n 'address.state': state,\n 'address.city': city\n }\n });\n }\n\n return null;\n },\n\n // DERIVED PROPERTIES\n // These properties combine other property values. Example:\n // get valueAndMessage(){ return this.value + this.message; }\n\n // METHODS\n // Functions that can be called by the view. Example:\n // incrementValue() { this.value++; }\n\n // SIDE EFFECTS\n // The following is a good place to perform changes to the DOM\n // or do things that don't fit in to one of the areas above.\n connectedCallback(element){\n\n }\n }\n});\n\nexport default RestaurantList;\nexport const ViewModel = RestaurantList.ViewModel;\n\n```\n<div line-highlight='5-6,18-56,only'></div>\n\nLet's take a closer look at those properties:\n\n- `states` will return a list of all available states by calling `State.getList({})`\n- `state` is a string property set to `null` by default (no selection).\n- `cities` will return `null` if no state has been selected. Otherwise, it will load all the cities for a given state by sending `state` as a query paramater (which will make a request like [http://localhost:8080/api/cities?state=IL](http://localhost:8080/api/cities?state=IL))\n- `city` is a string, set to `null` by default. It [listens to](https://canjs.com/doc/can-define.types.valueOptions.html) itself being set and resolves to that value. Additionally it listens to `state` and resolves back to `null` when it changes.\n- `restaurants` will always be `null` unless both a `city` and a `state` are selected. If both are selected, it will set the `address.state` and `address.city` query parameters which will return a list of all restaurants whose address matches those parameters.\n\n### Create a test\n\nView models that are decoupled from the presentation layer are easy to test. We will use [QUnit](https://qunitjs.com/) as the testing framework by loading a StealJS-friendly wrapper (`steal-qunit`). The component generator created a fully working test page for the component, which can be opened at [http://localhost:8080/src/pages/restaurant/list/test.html](http://localhost:8080/src/pages/restaurant/list/test.html). Currently, the tests will fail because we changed the view model, but in this section we will create some unit tests for the new functionality.\n\n#### Fixtures: Create fake data\n\nUnit tests should be able to run by themselves without the need for an API server. This is where [fixtures](https://canjs.com/doc/can-fixture.html) come in. Fixtures allow us to mock requests to the REST API with data that we can use for tests or demo pages. Default fixtures will be provided for every generated model. Now we'll add more realistic fake data by updating `src/models/fixtures/states.js` to:\n\n\n```js\nimport { fixture } from 'can';\nimport State from '../state';\n\nconst store = fixture.store([\n { name: 'Calisota', short: 'CA' },\n { name: 'New Troy', short: 'NT'}\n], State.connection.queryLogic);\n\nfixture('/api/states/{short}', store);\n\nexport default store;\n\n```\n<div line-highlight='4-7,only'></div>\n\nUpdate `src/models/fixtures/cities.js` to look like:\n\n\n```js\nimport { fixture } from 'can';\nimport City from '../city';\n\nconst store = fixture.store([\n { state: 'CA', name: 'Casadina' },\n { state: 'NT', name: 'Alberny' }\n], City.connection.queryLogic);\n\nfixture('/api/cities/{name}', store);\n\nexport default store;\n\n```\n<div line-highlight='4-7,only'></div>\n\nUpdate `src/models/fixtures/restaurants.js` to look like:\n\n\n```js\nimport { fixture } from 'can';\nimport Restaurant from '../restaurant';\n\nconst store = fixture.store([{\n _id: 1,\n name: 'Cheese City',\n slug:'cheese-city',\n address: {\n city: 'Casadina',\n state: 'CA'\n },\n images: {\n banner: \"node_modules/place-my-order-assets/images/1-banner.jpg\",\n owner: \"node_modules/place-my-order-assets/images/2-owner.jpg\",\n thumbnail: \"node_modules/place-my-order-assets/images/3-thumbnail.jpg\"\n }\n}, {\n _id: 2,\n name: 'Crab Barn',\n slug:'crab-barn',\n address: {\n city: 'Alberny',\n state: 'NT'\n },\n images: {\n banner: \"node_modules/place-my-order-assets/images/2-banner.jpg\",\n owner: \"node_modules/place-my-order-assets/images/3-owner.jpg\",\n thumbnail: \"node_modules/place-my-order-assets/images/2-thumbnail.jpg\"\n }\n}], Restaurant.connection.queryLogic);\n\nfixture('/api/restaurants/{_id}', store);\n\nexport default store;\n\n```\n<div line-highlight='4-30,only'></div>\n\n#### Test the view model\n\nWith fake data in place, we can test our view model by changing `src/pages/restaurant/list/list-test.js` to:\n\n\n```js\nimport QUnit from 'steal-qunit';\nimport cityStore from '~/models/fixtures/cities';\nimport stateStore from '~/models/fixtures/states';\nimport restaurantStore from '~/models/fixtures/restaurants';\nimport { ViewModel } from './list';\n\nQUnit.module('~/restaurant/list', {\n beforeEach() {\n localStorage.clear();\n }\n});\n\nQUnit.asyncTest('loads all states', function() {\n var vm = new ViewModel();\n var expectedStates = stateStore.getList({});\n\n vm.states.then(states => {\n QUnit.deepEqual(states.serialize(), expectedStates.data, 'Got all states');\n QUnit.start();\n });\n});\n\nQUnit.asyncTest('setting a state loads its cities', function() {\n var vm = new ViewModel();\n var expectedCities = cityStore.getList({ filter: { state: \"CA\" } }).data;\n\n QUnit.equal(vm.cities, null, '');\n vm.state = 'CA';\n vm.cities.then(cities => {\n QUnit.deepEqual(cities.serialize(), expectedCities, 'Got all cities');\n QUnit.start();\n });\n});\n\nQUnit.asyncTest('changing a state resets city', function() {\n var vm = new ViewModel();\n var expectedCities = cityStore.getList({ filter: { state : \"CA\" } }).data;\n\n QUnit.equal(vm.cities, null, '');\n vm.state = 'CA';\n vm.cities.then(cities => {\n QUnit.deepEqual(cities.serialize(), expectedCities, 'Got all cities');\n vm.state = 'NT';\n QUnit.equal(vm.city, null, 'City reset');\n QUnit.start();\n });\n});\n\nQUnit.asyncTest('setting state and city loads a list of its restaurants', function() {\n var vm = new ViewModel();\n vm.bind('city', () => {});\n var expectedRestaurants = restaurantStore.getList({\n filter: { address: { city: \"Alberny\" } }\n }).data;\n\n vm.state = 'NT';\n vm.city = 'Alberny';\n\n vm.restaurants.then(restaurants => {\n QUnit.deepEqual(restaurants.serialize(), expectedRestaurants, 'Fetched restaurants equal to expected');\n QUnit.deepEqual(restaurants.length, 1, 'Got expected number of restaurants');\n QUnit.start();\n });\n});\n\n```\n\nThese unit tests are comparing expected data (what we we defined in the fixtures) with actual data (how the view model methods are behaving). Visit [http://localhost:8080/src/pages/restaurant/list/test.html](http://localhost:8080/src/pages/restaurant/list/test.html) to see all tests passing.\n\n### Write the template\n\nNow that our view model is implemented and tested, we'll update the restaurant list template to support the city/state selection functionality.\n\nUpdate `src/pages/restaurant/list/list.stache` to:\n\n\n```html\n<can-import from=\"can-stache-route-helpers\" />\n\n<div class=\"restaurants\">\n <h2 class=\"page-header\">Restaurants</h2>\n <form class=\"form\">\n <div class=\"form-group\">\n <label>State</label>\n <select value:bind=\"this.state\" {{#if(this.states.isPending)}}disabled{{/if}}>\n {{#if(this.states.isPending)}}\n <option value=\"\">Loading...</option>\n {{else}}\n {{^if(this.state)}}\n <option value=\"\">Choose a state</option>\n {{/if}}\n {{#for(state of this.states.value)}}\n <option value=\"{{state.short}}\">{{state.name}}</option>\n {{/for}}\n {{/if}}\n </select>\n </div>\n <div class=\"form-group\">\n <label>City</label>\n <select value:bind=\"this.city\"{{^if(this.state)}}disabled{{/if}}>\n {{#if(this.cities.isPending)}}\n <option value=\"\">Loading...</option>\n {{else}}\n {{#if(this.state)}}\n {{^if(this.city)}}\n <option value=\"\">Choose a city</option>\n {{/if}}\n {{#for(city of this.cities.value)}}\n <option value:from=\"city.name\">{{city.name}}</option>\n {{/for}}\n {{/if}}\n {{/if}}\n </select>\n </div>\n </form>\n\n {{#if(this.restaurants.isPending)}}\n <div class=\"restaurant loading\"></div>\n {{/if}}\n\n {{#if(this.restaurants.isResolved)}}\n {{console.log(\"count\", this.restaurants.value.length)}}\n {{#for(restaurant of this.restaurants.value)}}\n {{let addr=restaurant.address}}\n\n <div class=\"restaurant\">\n <img src=\"{{joinBase(restaurant.images.thumbnail)}}\"\n width=\"100\" height=\"100\">\n <h3>{{restaurant.name}}</h3>\n\n {{#if(addr)}}\n <div class=\"address\">\n {{addr.street}}<br />{{addr.city}}, {{addr.state}} {{addr.zip}}\n </div>\n {{/if}}\n\n <div class=\"hours-price\">\n $$$<br />\n Hours: M-F 10am-11pm\n <span class=\"open-now\">Open Now</span>\n </div>\n\n <a class=\"btn\" href=\"{{routeUrl(page='restaurants' slug=restaurant.slug)}}\">\n Details\n </a>\n <br />\n </div>\n {{/for}}\n {{/if}}\n</div>\n\n```\n<div line-highlight='5-38,only'></div>\n\nSome things worth pointing out:\n\n- Since `states` and `cities` return a promise, we can check the promise's status via `isResolved` and `isPending` and once resolved get the actual value with `states.value` and `cities.value`. This also allows us to easily show loading indicators and disable the select fields while loading data.\n- The `state` and `city` properties are two-way bound to their select fields via [value:bind](https://canjs.com/doc/can-stache-bindings.twoWay.html#___child_prop____key_)\n\nNow we have a component that lets us select state and city and displays the appropriate restaurant list.\n\n### Update the demo page\n\nWe already have an existing demo page at [src/pages/restaurant/list/list.html](http://localhost:8080/src/pages/restaurant/list/list.html). We'll update it to load fixtures so it can demonstrate the use of the pmo-restaurnt-list component:\n\n\n```html\n<script src=\"../../../../node_modules/steal/steal.js\"></script>\n<script type=\"steal-module\">\n import PmoRestaurantList from \"~/pages/restaurant/list/\";\n import \"place-my-order-assets\";\n import \"~/models/fixtures/\";\n\n let pmoRestaurantList = new PmoRestaurantList({\n viewModel: {}\n });\n\n document.body.appendChild(pmoRestaurantList.element);\n</script>\n\n```\n<div line-highlight='4-5,only'></div>\n\nView the demo page at [http://localhost:8080/src/pages/restaurant/list/list.html](http://localhost:8080/src/pages/restaurant/list/list.html) .\n\n## Automated tests\n\nIn this chapter we will automate running the tests so that they can be run from from the command line.\n\n### Using the global test page\n\nWe already worked with an individual component test page in [src/pages/restaurant/list/test.html](http://localhost:8080/pages/src/pages/restaurant/list/test.html) but we also have a global test page available at [test.html](http://localhost:8080/test.html). All tests are being loaded in `src/test.js`. Since we don't have tests for our models at the moment, let's remove the `import 'place-my-order/models/test';` part so that `src/test.js` looks like this:\n\n\n```js\nimport F from 'funcunit';\nimport QUnit from 'steal-qunit';\n\nimport '~/pages/restaurant/list/list-test';\n\nF.attach(QUnit);\n\nQUnit.module('place-my-order functional smoke test', {\n beforeEach() {\n F.open('./development.html');\n }\n});\n\nQUnit.test('place-my-order main page shows up', function() {\n F('title').text('place-my-order', 'Title is set');\n});\n\n```\n\nIf you now go to [http://localhost:8080/test.html](http://localhost:8080/test.html) we still see all restaurant list tests passing but we will add more here later on.\n\n### Using a test runner\n\n**Note**: If you are using Firefox for development, close the browser temporarily so that we can run our tests.\n\nThe tests can be automated with any test runner that supports running QUnit tests. We will use [Testee](https://github.com/bitovi/testee) which makes it easy to run those tests in any browser from the command line without much configuration. In fact, everything needed to automatically run the `test.html` page in Firefox is already set up and we can launch the tests by running:\n\n```shell\ndonejs test\n```\n\nTo see the tests passing on the command line.\n\n## Continuous integration\n\nNow that the tests can be run from the command line we can automate it in a [continuous integration](https://en.wikipedia.org/wiki/Continuous_integration) (CI) environment to run all tests whenever a code change is made. We will use [GitHub](https://github.com) to host our code and [TravisCI](https://travis-ci.org/) as the CI server.\n\n### Creating a GitHub account and repository\n\nIf you don't have an account yet, go to [GitHub](https://github.com) to sign up and follow [the help](https://help.github.com/articles/set-up-git/) on how to set it up for use with the command-line `git`. Once completed, you can create a new repository from your dashboard. Calling the repository `place-my-order` and initializing it empty (without any of the default files) looks like this:\n\n![Creating a new repository on GitHub](static/img/guide-create-repo.png)\n\nNow we have to initialize Git in our project folder and add the GitHub repository we created as the origin remote (replace `<your-username>` with your GitHub username):\n\n```shell\ngit init\ngit remote add origin https://github.com/<your-username>/place-my-order.git\n```\n\nThen we can add all files and push to origin like this:\n\n```shell\ngit add --all\ngit commit -am \"Initial commit\"\ngit push origin master\n```\n\nIf you now go to [github.com/<your-username>/place-my-order](https://github.com/<your-username>/place-my-order) you will see the project files in the repository.\n\n### Setting up Travis CI\n\nThe way our application is set up, now all a continuous integration server has to do is clone the application repository, run `npm install`, and then run `npm test`. There are many open source CI servers, the most popular one probably [Jenkins](https://jenkins-ci.org/), and many hosted solutions like [Travis CI](https://travis-ci.org/).\n\nWe will use Travis as our hosted solution because it is free for open source projects. It works with your GitHub account which it will use to sign up. First, [sign up](https://travis-ci.org/), then go to `Accounts` (in the dropdown under you name) to enable the `place-my-order` repository:\n\n![Enabling the repository on Travis CI](static/img/guide-travis-ci.png)\n\nContinuous integration on GitHub is most useful when using [branches and pull requests](https://help.github.com/categories/collaborating-on-projects-using-pull-requests/). That way your main branch (master) will only get new code changes if all tests pass. Let's create a new branch with\n\n```shell\ngit checkout -b travis-ci\n```\n\nRun the [donejs-travis](https://github.com/donejs/donejs-travis/) generator to add a `.travis.yml` file to our project root, and to add a *Build Passing* badge to the top of `readme.md`:\n\n```shell\ndonejs add travis\n```\n\nWhen prompted, confirm the GitHub user name and repository by pressing the Enter key, you can also enter new values if needed:\n\n```shell\n? What is the GitHub owner name? (<your-username>)\n? What is the GitHub repository name? (place-my-order)\n```\n\nFollowing these questions, the generator will first update the [package.json's repository](https://docs.npmjs.com/files/package.json#repository) field to point it to where your code lives.\n\nConfirm the changes by pressing the Enter key,\n\n```\n conflict package.json\n? Overwrite package.json? (Ynaxdh)\n```\n\n> You can also press the `d` key to see a diff of the changes before writing to the file.\n\nThen, the generator creates a `.travis.yml` file and updates `readme.md` to include a badge indicating the status of the build, confirm the changes by pressing the Enter key:\n\n```shell\nconflict README.md\n? Overwrite README.md? (Ynaxdh)\n```\n\nThe generated `.travis.yml` should look like this:\n\n```shell\nlanguage: node_js\nnode_js: node\naddons:\n firefox: latest\nbefore_install:\n - 'export DISPLAY=:99.0'\n - sh -e /etc/init.d/xvfb start\n```\n\nBy default Travis CI runs `npm test` for NodeJS projects which is what we want. `before_install` sets up a window system to run Firefox.\n\nTo see Travis run, let's add all changes and push to the branch:\n\n```shell\ngit add --all\ngit commit -am \"Enabling Travis CI\"\ngit push origin travis-ci\n```\n\nAnd then create a new pull request by going to [github.com/<your-username>/place-my-order](https://github.com/<your-username>/place-my-order) which will now show an option for it:\n\n![Creating a new pull request on GitHub](static/img/guide-github-pr.png)\n\nOnce you created the pull request, you will see a `Some checks haven’t completed yet` message that will eventually turn green like this:\n\n![Merging a pull request with all tests passed](static/img/guide-merge-pr.png)\n\nOnce everything turns green, click the \"Merge pull request\" button. Then in your console, checkout the _master_ branch and pull down it's latest with:\n\n```shell\ngit checkout master\ngit pull origin master\n```\n\n\n## Nested routes\n\nIn this section, we will add additional pages that are shown under nested urls such as `restaurants/cheese-curd-city/order`.\n\n<div></div>\n\nUntil now we've used three top level routes: `home`, `restaurants` and `order-history`. We did however also define two additional routes in `src/app.js` which looked like:\n\n```js\nroute.register('{page}/{slug}', { slug: null });\nroute.register('{page}/{slug}/{action}', { slug: null, action: null });\n```\n\nWe want to use those routes when we are in the `restaurants` page. The relevant section in `pageComponent` currently looks like this:\n\n```js\ncase 'restaurants': {\n return steal.import('~/pages/restaurant/list/').then(({default: RestaurantList}) => {\n return new RestaurantList();\n });\n}\n```\n\nWe want to support two additional routes:\n\n- `restaurants/{slug}`, which shows a details page for the restaurant with `slug` being a URL friendly short name for the restaurant\n- `restaurants/{slug}/order`, which shows the menu of the current restaurant and allows us to make a selection and then send our order.\n\n### Create additional components\n\nTo make this happen, we need two more components. First, the `pmo-restaurant-details` component which loads the restaurant (based on the `slug`) and displays its information.\n\n```shell\ndonejs add component pages/restaurant/details.component pmo-restaurant-details\n```\n\nAnd change `src/pages/restaurant/details.component` to:\n\n\n```html\n<can-component tag=\"pmo-restaurant-details\">\n <style type=\"less\">\n display: block;\n\n p { font-weight: bold; }\n </style>\n <view>\n <can-import from=\"~/models/restaurant\" />\n <can-import from=\"can-stache-route-helpers\" />\n {{#if(this.restaurantPromise.isPending)}}\n <div class=\"loading\"></div>\n {{else}}\n {{let restaurant=this.restaurantPromise.value}}\n <div class=\"restaurant-header\"\n style=\"background-image: url({{joinBase(restaurant.images.banner)}});\">\n <div class=\"background\">\n <h2>{{restaurant.name}}</h2>\n\n {{let addr=restaurant.address}}\n {{#if(addr)}}\n <div class=\"address\">\n {{addr.street}}<br />{{addr.city}}, {{addr.state}} {{addr.zip}}\n </div>\n {{/if}}\n\n <div class=\"hours-price\">\n $$$<br />\n Hours: M-F 10am-11pm\n <span class=\"open-now\">Open Now</span>\n </div>\n\n <br />\n </div>\n </div>\n\n <div class=\"restaurant-content\">\n <h3>The best food this side of the Mississippi</h3>\n\n <p class=\"description\">\n <img src=\"{{joinBase(restaurant.images.owner)}}\" />\n Description for {{restaurant.name}}\n </p>\n <p class=\"order-link\">\n <a class=\"btn\" href=\"{{routeUrl(page='restaurants' slug=restaurant.slug action='order')}}\">\n Order from {{restaurant.name}}\n </a>\n </p>\n </div>\n {{/if}}\n </view>\n <script type=\"view-model\">\n import { DefineMap } from 'can';\n import Restaurant from '~/models/restaurant';\n\n export default DefineMap.extend(\"PmoRestaurantDetailsVM\", {\n // EXTERNAL STATEFUL PROPERTIES\n // These properties are passed from another component. Example:\n // value: {type: \"number\"}\n\n // INTERNAL STATEFUL PROPERTIES\n // These properties are owned by this component.\n message: { default: \"This is the pmo-restaurant-details component\" },\n\n // DERIVED PROPERTIES\n // These properties combine other property values. Example:\n // get valueAndMessage(){ return this.value + this.message; }\n get restaurantPromise() {\n return Restaurant.get({ _id: this.slug });\n },\n\n // METHODS\n // Functions that can be called by the view. Example:\n // incrementValue() { this.value++; }\n\n // SIDE EFFECTS\n // The following is a good place to perform changes to the DOM\n // or do things that don't fit in to one of the areas above.\n connectedCallback(element){\n\n }\n });\n </script>\n</can-component>\n\n```\n\nThe order component will be a little more complex, which is why we will put it into its own folder:\n\n```shell\ndonejs add component pages/order/new pmo-order-new\n```\n\nFor now, we will just use placeholder content and implement the functionality in\nthe following chapters.\n\n### Add to the Application ViewModel routing\n\nNow we can add those components to the `pageComponent` property (at `src/app.js`) with conditions based on the routes that we want to match. Update `src/app.js` with:\n\n\n```js\nimport { DefineMap, route, value } from 'can';\nimport RoutePushstate from 'can-route-pushstate';\nimport debug from 'can-debug#?./is-dev';\n\n//!steal-remove-start\nif(debug) {\n\tdebug();\n}\n//!steal-remove-end\n\nconst AppViewModel = DefineMap.extend(\"AppViewModel\", {\n page: 'string',\n slug: 'string',\n action: 'string',\n env: {\n default: () => ({NODE_ENV:'development'})\n },\n title: {\n default: 'place-my-order'\n },\n routeData: {\n default: () => route.data\n\t},\n get pageComponent() {\n switch(this.routeData.page) {\n case 'home': {\n return steal.import('~/pages/home.component').then(({default: Home}) => {\n return new Home();\n });\n }\n\n case 'restaurants': {\n if(this.routeData.slug) {\n switch(this.routeData.action) {\n case 'order': {\n return steal.import(\"~/pages/order/new/\")\n .then(({default: OrderNew}) => {\n return new OrderNew({\n viewModel: {\n slug: value.from(this.routeData, \"slug\")\n }\n })\n });\n }\n\n default: {\n return steal.import(\"~/pages/restaurant/details.component\")\n .then(({default: RestaurantDetail}) => {\n return new RestaurantDetail({\n viewModel: {\n slug: value.from(this.routeData, \"slug\")\n }\n });\n });\n }\n }\n }\n\n return steal.import('~/pages/restaurant/list/').then(({default: RestaurantList}) => {\n return new RestaurantList();\n });\n }\n\n case 'order-history': {\n return steal.import('~/pages/order/history.component').then(({default: OrderHistory}) => {\n return new OrderHistory();\n });\n }\n }\n }\n});\n\nroute.urlData = new RoutePushstate();\nroute.register(\"{page}\", { page: \"home\" });\nroute.register('{page}/{slug}', { slug: null });\nroute.register('{page}/{slug}/{action}', { slug: null, action: null });\n\nexport default AppViewModel;\n\n```\n<div line-highlight='1,33-57,only'></div>\n\nHere we are adding some more conditions if `page` is set to `restaurants`:\n\n- When there is no `slug` set, show the original restaurant list\n- When `slug` is set but no `action`, show the restaurant details\n- When `slug` is set and `action` is `order`, show the order component for that restaurant\n\nAs before, we import the page component based on the state of the route. Since the page component is a class, we can call `new` to create a new instance. Then we use [can-value](https://canjs.com/doc/can-value.from.html) to bind the `slug` from the route to the component.\n\n## Importing other projects\n\nThe npm integration of StealJS makes it very easy to share and import other components. One thing we want to do when showing the `pmo-order-new` component is have a tab to choose between the lunch and dinner menu. The good news is that there is already a [bit-tabs](https://github.com/bitovi-components/bit-tabs) component which does exactly that. Let's add it as a project dependency with:\n\n```shell\nnpm install bit-tabs@2 --save\n```\n\nAnd then integrate it into `src/pages/order/new/new.stache`:\n\n\n```html\n<can-import from=\"bit-tabs/unstyled\"/>\n<div class=\"order-form\">\n <h2>Order here</h2>\n\n <bit-tabs tabsClass:raw=\"nav nav-tabs\">\n <bit-panel title:raw=\"Lunch menu\">\n This is the lunch menu\n </bit-panel>\n <bit-panel title:raw=\"Dinner menu\">\n This is the dinner menu\n </bit-panel>\n </bit-tabs>\n</div>\n\n```\n\nHere we just import the `unstyled` module from the `bit-tabs` package using `can-import` which will then provide the `bit-tabs` and `bit-panel` custom elements.\n\n## Creating data\n\nIn this section, we will update the order component to be able to select restaurant menu items and submit a new order for a restaurant.\n\n### Creating the order model\n\nFirst, let's look at the restaurant data we get back from the server. It looks like this:\n\n```js\n{\n \"_id\": \"5571e03daf2cdb6205000001\",\n \"name\": \"Cheese Curd City\",\n \"slug\": \"cheese-curd-city\",\n \"images\": {\n \"thumbnail\": \"images/1-thumbnail.jpg\",\n \"owner\": \"images/1-owner.jpg\",\n \"banner\": \"images/2-banner.jpg\"\n },\n \"menu\": {\n \"lunch\": [\n {\n \"name\": \"Spinach Fennel Watercress Ravioli\",\n \"price\": 35.99\n },\n {\n \"name\": \"Chicken with Tomato Carrot Chutney Sauce\",\n \"price\": 45.99\n },\n {\n \"name\": \"Onion fries\",\n \"price\": 15.99\n }\n ],\n \"dinner\": [\n {\n \"name\": \"Gunthorp Chicken\",\n \"price\": 21.99\n },\n {\n \"name\": \"Herring in Lavender Dill Reduction\",\n \"price\": 45.99\n },\n {\n \"name\": \"Roasted Salmon\",\n \"price\": 23.99\n }\n ]\n },\n \"address\": {\n \"street\": \"1601-1625 N Campbell Ave\",\n \"city\": \"Green Bay\",\n \"state\": \"WI\",\n \"zip\": \"60045\"\n }\n}\n```\n\nWe have a `menu` property which provides a `lunch` and `dinner` option (which will show later inside the tabs we set up in the previous chapter). We want to be able to add and remove items from the order, check if an item is in the order already, set a default order status (`new`), and be able to calculate the order total. For that to happen, we need to create a new `order` model:\n\n```shell\ndonejs add supermodel order\n```\n\nLike the restaurant model, the URL is `/api/orders` and the id property is `_id`. To select menu items, we need to add some additional functionality to `src/models/order.js`:\n\n\n```js\nimport { DefineMap, DefineList, superModel } from 'can';\nimport loader from '@loader';\n\nconst Item = DefineMap.extend('Item', {\n seal: false\n}, {\n price: 'number'\n});\n\nconst ItemsList = DefineList.extend('ItemList', {\n '#': Item,\n has: function(item) {\n return this.indexOf(item) !== -1;\n },\n\n toggle: function(item) {\n var index = this.indexOf(item);\n\n if (index !== -1) {\n this.splice(index, 1);\n } else {\n this.push(item);\n }\n }\n});\n\nconst Order = DefineMap.extend('Order', {\n seal: false\n}, {\n '_id': {\n type: 'any',\n identity: true\n },\n name: 'string',\n address: 'string',\n phone: 'string',\n restaurant: 'string',\n\n status: {\n default: 'new'\n },\n items: {\n Default: ItemsList\n },\n get total() {\n let total = 0.0;\n this.items.forEach(item =>\n total += parseFloat(item.price));\n return total.toFixed(2);\n },\n markAs(status) {\n this.status = status;\n this.save();\n }\n});\n\nOrder.List = DefineList.extend('OrderList', {\n '#': Order\n});\n\nOrder.connection = superModel({\n url: loader.serviceBaseURL + '/api/orders',\n Map: Order,\n List: Order.List,\n name: 'order'\n});\n\nexport default Order;\n\n```\n<div line-highlight='4-25,34-55,only'></div>\n\nHere we define an `ItemsList` which allows us to toggle menu items and check if they are already in the order. We set up ItemsList as the Value of the items property of an order so we can use its has function and toggle directly in the template. We also set a default value for status and a getter for calculating the order total which adds up all the item prices. We also create another `<order-model>` tag to load orders in the order history template later.\n\n### Implement the view model\n\nNow we can update the view model in `src/pages/order/new/new.js`:\n\n\n```js\nimport { Component } from 'can';\nimport './new.less';\nimport view from './new.stache';\nimport Restaurant from '~/models/restaurant';\nimport Order from '~/models/order';\n\nexport const PmoOrderNew = Component.extend({\n tag: 'pmo-order-new',\n view,\n ViewModel: {\n // EXTERNAL STATEFUL PROPERTIES\n // These properties are passed from another component. Example:\n // value: {type: \"number\"}\n slug: 'string',\n\n // INTERNAL STATEFUL PROPERTIES\n // These properties are owned by this component.\n saveStatus: '*',\n order: {\n Default: Order\n },\n get restaurantPromise() {\n return Restaurant.get({ _id: this.slug });\n },\n restaurant: {\n get(lastSetVal, resolve) {\n this.restaurantPromise.then(resolve);\n }\n },\n get canPlaceOrder() {\n return this.order.items.length;\n },\n\n // DERIVED PROPERTIES\n // These properties combine other property values. Example:\n // get valueAndMessage(){ return this.value + this.message; }\n\n // METHODS\n // Functions that can be called by the view. Example:\n // incrementValue() { this.value++; }\n placeOrder(ev) {\n ev.preventDefault();\n let order = this.order;\n order.restaurant = this.restaurant._id;\n this.saveStatus = order.save();\n },\n startNewOrder() {\n this.order = new Order();\n this.saveStatus = null;\n },\n\n // SIDE EFFECTS\n // The following is a good place to perform changes to the DOM\n // or do things that don't fit in to one of the areas above.\n connectedCallback(element){\n\n }\n }\n});\n\nexport default PmoOrderNew;\nexport const ViewModel = PmoOrderNew.ViewModel;\n\n```\n<div line-highlight='4-5,14,18-32,41-50,only'></div>\n\nHere we just define the properties that we need: `slug`, `order`, `canPlaceOrder` - which we will use to enable/disable the submit button - and `saveStatus`, which will become a promise once the order is submitted. `placeOrder` updates the order with the restaurant information and saves the current order. `startNewOrder` allows us to submit another order.\n\nWhile we're here we can also update our test to get it passing again, replace `src/pages/order/new/new-test.js` with:\n\n\n```js\nimport QUnit from 'steal-qunit';\nimport { ViewModel } from './new';\n\n// ViewModel unit tests\nQUnit.module('~/pages/order/new');\n\nQUnit.test('canPlaceOrder', function(){\n var vm = new ViewModel({\n order: { items: [1] }\n });\n QUnit.equal(vm.canPlaceOrder, true, 'can place an order');\n});\n\n```\n<div line-highlight='7-12,only'></div>\n\n### Write the template\n\nFirst, let's implement a small order confirmation component with\n\n```shell\ndonejs add component components/order/details.component pmo-order-details\n```\n\nand changing `src/components/order/details.component` to:\n\n\n```html\n<can-component tag=\"pmo-order-details\">\n <view>\n {{#if(this.order)}}\n <h3>Thanks for your order {{this.order.name}}!</h3>\n <div><label class=\"control-label\">\n Confirmation Number: {{this.order._id}}</label>\n </div>\n\n <h4>Items ordered:</h4>\n <ul class=\"list-group panel\">\n {{#for(item of this.order.items)}}\n <li class=\"list-group-item\">\n <label>\n {{item.name}} <span class=\"badge\">${{item.price}}</span>\n </label>\n </li>\n {{/for}}\n\n <li class=\"list-group-item\">\n <label>\n Total <span class=\"badge\">${{this.order.total}}</span>\n </label>\n </li>\n </ul>\n\n <div><label class=\"control-label\">\n Phone: {{this.order.phone}}\n </label></div>\n <div><label class=\"control-label\">\n Address: {{this.order.address}}\n </label></div>\n {{/if}}\n </view>\n <script type=\"view-model\">\n import { DefineMap } from 'can';\n\n export default DefineMap.extend(\"PmoOrderDetailsVM\", {\n // EXTERNAL STATEFUL PROPERTIES\n // These properties are passed from another component. Example:\n // value: {type: \"number\"}\n order: \"any\",\n\n // INTERNAL STATEFUL PROPERTIES\n // These properties are owned by this component.\n message: { default: \"This is the pmo-order-details component\" },\n\n // DERIVED PROPERTIES\n // These properties combine other property values. Example:\n // get valueAndMessage(){ return this.value + this.message; }\n\n // METHODS\n // Functions that can be called by the view. Example:\n // incrementValue() { this.value++; }\n\n // SIDE EFFECTS\n // The following is a good place to perform changes to the DOM\n // or do things that don't fit in to one of the areas above.\n connectedCallback(element){\n\n }\n });\n </script>\n</can-component>\n\n```\n\nNow we can import that component and update `src/pages/order/new/new.stache` to:\n\n\n```html\n<can-import from=\"bit-tabs/unstyled\"/>\n<can-import from=\"~/components/order/details.component\" />\n\n<div class=\"order-form\">\n {{#if(this.restaurantPromise.isPending)}}\n <div class=\"loading\"></div>\n {{else}}\n {{#if(this.saveStatus.isResolved)}}\n <pmo-order-details order:from=\"this.saveStatus.value\"></pmo-order-details>\n <p><a href=\"javascript://\" on:click=\"this.startNewOrder()\">\n Place another order\n </a></p>\n {{else}}\n <h3>Order from {{this.restaurant.name}}</h3>\n\n <form on:submit=\"this.placeOrder(scope.event)\">\n <bit-tabs tabsClass:raw=\"nav nav-tabs\">\n <p class=\"info {{^if(this.order.items.length)}}text-error{{else}}text-success{{/if}}\">\n {{^if(this.order.items.length)}}\n Please choose an item\n {{else}}\n {{this.order.items.length}} selected\n {{/if}}\n </p>\n <bit-panel title:raw=\"Lunch menu\">\n <ul class=\"list-group\">\n {{#for(item of this.restaurant.menu.lunch)}}\n <li class=\"list-group-item\">\n <label>\n <input type=\"checkbox\"\n on:change=\"this.order.items.toggle(item)\"\n {{#if(this.order.items.has(item))}}checked{{/if}}>\n {{item.name}} <span class=\"badge\">${{item.price}}</span>\n </label>\n </li>\n {{/for}}\n </ul>\n </bit-panel>\n <bit-panel title:raw=\"Dinner menu\">\n <ul class=\"list-group\">\n {{#for(item of restaurant.menu.dinner)}}\n <li class=\"list-group-item\">\n <label>\n <input type=\"checkbox\"\n on:change=\"this.order.items.toggle(item)\"\n {{#if(this.order.items.has(item))}}checked{{/if}}>\n {{item.name}} <span class=\"badge\">${{item.price}}</span>\n </label>\n </li>\n {{/for}}\n </ul>\n </bit-panel>\n </bit-tabs>\n\n <div class=\"form-group\">\n <label class=\"control-label\">Name:</label>\n <input name=\"name\" type=\"text\" class=\"form-control\"\n value:bind=\"this.order.name\">\n <p>Please enter your name.</p>\n </div>\n <div class=\"form-group\">\n <label class=\"control-label\">Address:</label>\n <input name=\"address\" type=\"text\" class=\"form-control\"\n value:bind=\"this.order.address\">\n <p class=\"help-text\">Please enter your address.</p>\n </div>\n <div class=\"form-group\">\n <label class=\"control-label\">Phone:</label>\n <input name=\"phone\" type=\"text\" class=\"form-control\"\n value:bind=\"this.order.phone\">\n <p class=\"help-text\">Please enter your phone number.</p>\n </div>\n <div class=\"submit\">\n <h4>Total: ${{this.order.total}}</h4>\n {{#if(this.saveStatus.isPending)}}\n <div class=\"loading\"></div>\n {{else}}\n <button type=\"submit\"\n {{^if(this.canPlaceOrder)}}disabled{{/if}} class=\"btn\">\n Place My Order!\n </button>\n {{/if}}\n </div>\n </form>\n {{/if}}\n {{/if}}\n</div>\n\n```\n\nThis is a longer template so lets walk through it:\n\n- `<can-import from=\"place-my-order/order/details.component\" />` loads the order details component we previously created\n- If the `saveStatus` promise is resolved we show the `pmo-order-details` component with that order\n- Otherwise we will show the order form with the `bit-tabs` panels we implemented in the previous chapter and iterate over each menu item\n- `on:submit=\"this.placeOrder()\"` will call `placeOrder` from our view model when the form is submitted\n- The interesting part for showing a menu item is the checkbox `<input type=\"checkbox\" on:change=\"this.order.items.toggle(item)\" {{#if this.order.items.has(item)}}checked{{/if}}>`\n - `on:change` binds to the checkbox change event and runs `this.order.items.toggle` which toggles the item from `ItemList`, which we created in the model\n - `this.order.item.has` sets the checked status to whether or not this item is in the order\n- Then we show form elements for name, address, and phone number, which are bound to the order model using [can-stache-bindings](https://canjs.com/doc/can-stache-bindings.html)\n- Finally we disable the button with `{{^if(this.canPlaceOrder)}}disabled{{/if}}` which gets `canPlaceOrder` from the view model and returns false if no menu items are selected.\n\n## Set up a real-time connection\n\ncan-connect makes it very easy to implement real-time functionality. It is capable of listening to notifications from the server when server data has been created, updated, or removed. This is usually accomplished via [websockets](https://en.wikipedia.org/wiki/WebSocket), which allow sending push notifications to a client.\n\n### Add the Status enum type\n\nUpdate `src/models/order.js` to use [QueryLogic.makeEnum](https://canjs.com/doc/can-query-logic.makeEnum.html) so that we can declare all of the possible values for an order's `status`.\n\n\n```js\nimport { DefineMap, DefineList, superModel, QueryLogic } from 'can';\nimport loader from '@loader';\n\nconst Item = DefineMap.extend('Item', {\n seal: false\n}, {\n price: 'number'\n});\n\nconst ItemsList = DefineList.extend('ItemList', {\n '#': Item,\n has: function(item) {\n return this.indexOf(item) !== -1;\n },\n\n toggle: function(item) {\n var index = this.indexOf(item);\n\n if (index !== -1) {\n this.splice(index, 1);\n } else {\n this.push(item);\n }\n }\n});\n\nconst Status = QueryLogic.makeEnum([\"new\", \"preparing\", \"delivery\", \"delivered\"]);\n\nconst Order = DefineMap.extend('Order', {\n seal: false\n}, {\n '_id': {\n type: 'any',\n identity: true\n },\n name: 'string',\n address: 'string',\n phone: 'string',\n restaurant: 'string',\n\n status: {\n default: 'new',\n Type: Status\n },\n items: {\n Default: ItemsList\n },\n get total() {\n let total = 0.0;\n this.items.forEach(item =>\n total += parseFloat(item.price));\n return total.toFixed(2);\n },\n markAs(status) {\n this.status = status;\n this.save();\n }\n});\n\nOrder.List = DefineList.extend('OrderList', {\n '#': Order\n});\n\nOrder.connection = superModel({\n url: loader.serviceBaseURL + '/api/orders',\n Map: Order,\n List: Order.List,\n name: 'order'\n});\n\nexport default Order;\n\n```\n<div line-highlight='1,27,42-43,only'></div>\n\n### Update the template\n\nFirst let's create the `pmo-order-list` component with:\n\n```shell\ndonejs add component components/order/list.component pmo-order-list\n```\n\nAnd then change `src/components/order/list.component` to:\n\n\n```html\n<can-component tag=\"pmo-order-list\">\n <view>\n <h4>{{this.listTitle}}</h4>\n\n {{#if(this.orders.isPending)}}\n <div class=\"loading\"></div>\n {{else}}\n {{#for(order of this.orders.value)}}\n <div class=\"order {{order.status}}\">\n <address>\n {{order.name}} <br />{{order.address}} <br />{{order.phone}}\n </address>\n\n <div class=\"items\">\n <ul>\n {{#for(item of order.items)}}<li>{{item.name}}</li>{{/for}}\n </ul>\n </div>\n\n <div class=\"total\">${{order.total}}</div>\n\n <div class=\"actions\">\n <span class=\"badge\">{{this.statusTitle}}</span>\n {{#if(this.action)}}\n <p class=\"action\">\n Mark as:\n <a href=\"javascript://\" on:click=\"order.markAs(this.action)\">\n {{this.actionTitle}}\n </a>\n </p>\n {{/if}}\n\n <p class=\"action\">\n <a href=\"javascript://\" on:click=\"order.destroy()\">Delete</a>\n </p>\n </div>\n </div>\n {{else}}\n <div class=\"order empty\">{{this.emptyMessage}}</div>\n {{/for}}\n {{/if}}\n </view>\n <script type=\"view-model\">\n import { DefineMap } from 'can';\n\n export default DefineMap.extend(\"PmoOrderListVM\", {\n // EXTERNAL STATEFUL PROPERTIES\n // These properties are passed from another component. Example:\n // value: {type: \"number\"}\n orders: \"any\",\n listTitle: \"string\",\n status: \"string\",\n statusTitle: \"string\",\n action: \"string\",\n actionTitle: \"string\",\n emptyMessage: \"string\",\n\n // INTERNAL STATEFUL PROPERTIES\n // These properties are owned by this component.\n\n // DERIVED PROPERTIES\n // These properties combine other property values. Example:\n // get valueAndMessage(){ return this.value + this.message; }\n\n // METHODS\n // Functions that can be called by the view. Example:\n // incrementValue() { this.value++; }\n\n // SIDE EFFECTS\n // The following is a good place to perform changes to the DOM\n // or do things that don't fit in to one of the areas above.\n connectedCallback(element){\n\n }\n });\n </script>\n</can-component>\n\n```\n\nAlso update the order history template by changing `src/pages/order/history.component` to:\n\n\n```html\n<can-component tag=\"pmo-order-history\">\n <view>\n <can-import from=\"~/components/order/list.component\" />\n <div class=\"order-history\">\n <div class=\"order header\">\n <address>Name / Address / Phone</address>\n <div class=\"items\">Order</div>\n <div class=\"total\">Total</div>\n <div class=\"actions\">Action</div>\n </div>\n\n <pmo-order-list\n orders:from=\"this.statusNew\"\n listTitle:raw=\"New Orders\"\n status:raw=\"new\"\n statusTitle:raw=\"New Order!\"\n action:raw=\"preparing\"\n actionTitle:raw=\"Preparing\"\n emptyMessage:raw=\"No new orders\"/>\n\n <pmo-order-list\n orders:from=\"this.statusPreparing\"\n listTitle:raw=\"Preparing\"\n status:raw=\"preparing\"\n statusTitle:raw=\"Preparing\"\n action:raw=\"delivery\"\n actionTitle:raw=\"Out for delivery\"\n emptyMessage:raw=\"No orders preparing\"/>\n\n <pmo-order-list\n orders:from=\"this.statusDelivery\"\n listTitle:raw=\"Out for delivery\"\n status:raw=\"delivery\"\n statusTitle:raw=\"Out for delivery\"\n action:raw=\"delivered\"\n actionTitle:raw=\"Delivered\"\n emptyMessage:raw=\"No orders are being delivered\"/>\n\n <pmo-order-list\n orders:from=\"this.statusDelivered\"\n listTitle:raw=\"Delivered\"\n status:raw=\"delivered\"\n statusTitle:raw=\"Delivered\"\n emptyMessage:raw=\"No delivered orders\"/>\n </div>\n </view>\n <script type=\"view-model\">\n import { DefineMap } from 'can';\n import Order from '~/models/order';\n\n export default DefineMap.extend(\"PmoOrderHistoryVM\", {\n // EXTERNAL STATEFUL PROPERTIES\n // These properties are passed from another component. Example:\n // value: {type: \"number\"}\n\n // INTERNAL STATEFUL PROPERTIES\n // These properties are owned by this component.\n message: { default: \"This is the pmo-order-history component\" },\n\n // DERIVED PROPERTIES\n // These properties combine other property values. Example:\n // get valueAndMessage(){ return this.value + this.message; }\n get statusNew() {\n return Order.getList({ filter: { status: \"new\" }});\n },\n get statusPreparing() {\n return Order.getList({ filter: { status: \"preparing\" }});\n },\n get statusDelivery() {\n return Order.getList({ filter: { status: \"delivery\" }});\n },\n get statusDelivered() {\n return Order.getList({ filter: { status: \"delivered\" }});\n },\n\n // METHODS\n // Functions that can be called by the view. Example:\n // incrementValue() { this.value++; }\n\n // SIDE EFFECTS\n // The following is a good place to perform changes to the DOM\n // or do things that don't fit in to one of the areas above.\n connectedCallback(element){\n\n }\n });\n </script>\n</can-component>\n\n```\n\nFirst we import the order model and then just call `<order-model get-list=\"{status='<status>'}\">` for each order status. These are all of the template changes needed, next is to set up the real-time connection.\n\n### Adding real-time events to a model\n\nThe `place-my-order-api` module uses the [Feathers](https://feathersjs.com/) NodeJS framework, which in addition to providing a REST API, sends those events in the form of a websocket event like `orders created`. To make the order page update in real-time, all we need to do is add listeners for those events to `src/models/order.js` and in the handler notify the order connection.\n\n```shell\nnpm install steal-socket.io@4 --save\n```\n\nUpdate `src/models/order.js` to use socket.io to update the Order model in real-time:\n\n\n```js\nimport { DefineMap, DefineList, superModel, QueryLogic } from 'can';\nimport loader from '@loader';\nimport io from 'steal-socket.io';\n\nconst Item = DefineMap.extend('Item', {\n seal: false\n}, {\n price: 'number'\n});\n\nconst ItemsList = DefineList.extend('ItemList', {\n '#': Item,\n has: function(item) {\n return this.indexOf(item) !== -1;\n },\n\n toggle: function(item) {\n var index = this.indexOf(item);\n\n if (index !== -1) {\n this.splice(index, 1);\n } else {\n this.push(item);\n }\n }\n});\n\nconst Status = QueryLogic.makeEnum([\"new\", \"preparing\", \"delivery\", \"delivered\"]);\n\nconst Order = DefineMap.extend('Order', {\n seal: false\n}, {\n '_id': {\n type: 'any',\n identity: true\n },\n name: 'string',\n address: 'string',\n phone: 'string',\n restaurant: 'string',\n\n status: {\n default: 'new',\n Type: Status\n },\n items: {\n Default: ItemsList\n },\n get total() {\n let total = 0.0;\n this.items.forEach(item =>\n total += parseFloat(item.price));\n return total.toFixed(2);\n },\n markAs(status) {\n this.status = status;\n this.save();\n }\n});\n\nOrder.List = DefineList.extend('OrderList', {\n '#': Order\n});\n\nOrder.connection = superModel({\n url: loader.serviceBaseURL + '/api/orders',\n Map: Order,\n List: Order.List,\n name: 'order'\n});\n\nconst socket = io(loader.serviceBaseURL);\n\nsocket.on('orders created', order => Order.connection.createInstance(order));\nsocket.on('orders updated', order => Order.connection.updateInstance(order));\nsocket.on('orders removed', order => Order.connection.destroyInstance(order));\n\nexport default Order;\n\n```\n<div line-highlight='3,72-76,only'></div>\n\nThat's it. If we now open the [order page](http://localhost:8080/order-history) we see some already completed default orders. Keeping the page open and placing a new order from another browser or device will update our order page automatically.\n\n## Create documentation\n\nDocumenting our code is very important to quickly get other developers up to speed. [DocumentJS](https://documentjs.com/) makes documenting code easier. It will generate a full documentation page from Markdown files and code comments in our project.\n\n### Installing and Configuring DocumentJS\n\nLet's add DocumentJS to our application:\n\n```shell\ndonejs add documentjs@0.1\n```\n\nThis will install DocumentJS and also create a `documentjs.json` configuration file. Now we can generate the documentation with:\n\n```shell\ndonejs document\n```\n\nThis produces documentation at [http://localhost:8080/docs/](http://localhost:8080/docs/).\n\n### Documenting a module\n\nLet's add the documentation for a module. Let's use `src/pages/order/new/new.js` and update it with some inline comments that describe what our view model properties are supposed to do:\n\n\n```js\nimport { Component } from 'can';\nimport './new.less';\nimport view from './new.stache';\nimport Restaurant from '~/models/restaurant';\nimport Order from '~/models/order';\n\nexport const PmoOrderNew = Component.extend({\n tag: 'pmo-order-new',\n view,\n\n /**\n * @add ~/pages/order/new\n */\n ViewModel: {\n // EXTERNAL STATEFUL PROPERTIES\n // These properties are passed from another component. Example:\n // value: {type: \"number\"}\n\n /**\n * @property {string} slug\n *\n * the restaurants slug (short name). will\n * be used to request the actual restaurant.\n */\n slug: 'string',\n\n // INTERNAL STATEFUL PROPERTIES\n // These properties are owned by this component.\n\n /**\n * @property {Promise} saveStatus\n *\n * a Promise that contains the status of the order when\n * it is being saved.\n */\n saveStatus: '*',\n /**\n * @property {~/models/order} order\n *\n * the order that is being processed. will\n * be an empty new order inititally.\n */\n order: {\n Default: Order\n },\n /**\n * @property {Promise} restaurantPromise\n *\n * a Promise that contains the restaurant that is being\n * ordered from.\n */\n get restaurantPromise() {\n return Restaurant.get({ _id: this.slug });\n },\n /**\n * @property {~/models/restaurant} restaurant\n *\n * the restaurant that is being ordered from.\n */\n restaurant: {\n get(lastSetVal, resolve) {\n this.restaurantPromise.then(resolve);\n }\n },\n /**\n * @property {Boolean} canPlaceOrder\n *\n * boolean indicating whether the order\n * can be placed.\n */\n get canPlaceOrder() {\n return this.order.items.length;\n },\n\n // DERIVED PROPERTIES\n // These properties combine other property values. Example:\n // get valueAndMessage(){ return this.value + this.message; }\n\n // METHODS\n // Functions that can be called by the view. Example:\n // incrementValue() { this.value++; }\n\n /**\n * @function placeOrder\n *\n * save the current order and update the status deferred.\n */\n placeOrder(ev) {\n ev.preventDefault();\n let order = this.order;\n order.restaurant = this.restaurant._id;\n this.saveStatus = order.save();\n },\n /**\n * @function startNewOrder\n *\n * resets the order form, so a new order can be placed.\n */\n startNewOrder() {\n this.order = new Order();\n this.saveStatus = null;\n },\n\n // SIDE EFFECTS\n // The following is a good place to perform changes to the DOM\n // or do things that don't fit in to one of the areas above.\n connectedCallback(element){\n\n }\n }\n});\n\nexport default PmoOrderNew;\nexport const ViewModel = PmoOrderNew.ViewModel;\n\n```\n<div line-highlight='11-13,19-24,30-35,37-42,46-51,55-59,65-70,83-87,94-98,only'></div>\n\nIf we now run `donejs document` again, we will see the module show up in the menu bar and will be able to navigate through the different properties.\n\n## Production builds\n\nNow we're ready to create a production build; go ahead and kill your development server, we won't need it from here on.\n\n### Progressive loading\n\nOur `app.js` contains steal.import() calls for each of the pages we have implemented. These dynamic imports progressively load page components only when the user visits that page.\n\n### Bundling assets\n\nLikely you have assets in your project other than your JavaScript and CSS that you will need to deploy to production. Place My Order has these assets saved to another project, you can view them at `node_modules/place-my-order-assets/images`.\n\nStealTools comes with the ability to bundle all of your static assets into a folder that can be deployed to production by itself. Think if it as a zip file that contains everything your app needs to run in production.\n\nTo use this capability add an option to your build script to enable it. Change:\n\n```js\nlet buildPromise = stealTools.build({\n config: __dirname + \"/package.json!npm\"\n}, {\n bundleAssets: true\n});\n```\n\nto:\n\n```js\nlet buildPromise = stealTools.build({\n config: __dirname + \"/package.json!npm\"\n}, {\n bundleAssets: {\n infer: false,\n glob: \"node_modules/place-my-order-assets/images/**/*\"\n }\n});\n```\n\n<div line-highlight='4-7,only'></div>\n\nStealTools will find all of the assets you reference in your CSS and copy them to the dist folder. By default StealTools will set your [dest](https://stealjs.com/docs/steal-tools.build.html#dest) to `dist`, and will place the place-my-order-assets images in `dist/node_modules/place-my-order/assets/images`. bundleAssets preserves the path of your assets so that their locations are the same relative to the base url in both development and production.\n\n\n### Bundling your app\n\nTo bundle our application for production we use the build script in `build.js`. We could also use [Grunt](http://gruntjs.com/) or [Gulp](http://gulpjs.com/), but in this example we just run it directly with Node. Everything is set up already so we run:\n\n```shell\ndonejs build\n```\n\nThis will build the application to a `dist/` folder in the project's base directory.\n\nFrom here your application is ready to be used in production. Enable production mode by setting the `NODE_ENV` variable:\n\n```shell\nNODE_ENV=production donejs start\n```\n\nIf you're using Windows omit the NODE_ENV=production in the command, and instead see the [setting up guide](./SettingUp.html#environmental-variables) on how to set environment variables.\n\nRefresh your browser to see the application load in production.\n\n## Desktop and mobile apps\n\n### Building to iOS and Android\n\nTo build the application as a Cordova based mobile application, you need to have each platform's SDK installed.\nWe'll be building an iOS app if you are a Mac user, and an Android app if you're a Windows user.\n\nMac users should download XCode from the AppStore and install the `ios-sim` package globally with:\n\n```shell\nnpm install -g ios-sim\n```\n\nWe will use these tools to create an iOS application that can be tested in the iOS simulator.\n\nWindows users should install the [Android Studio](https://developer.android.com/sdk/index.html), which gives all of the tools we need. See the [setting up guide](./SettingUp.html#android-development-1) for full instructions on setting up your Android emulator.\n\nNow we can install the DoneJS Cordova tools with:\n\n```shell\ndonejs add cordova@2\n```\n\nAnswer the question about the URL of the service layer with `http://www.place-my-order.com`.\n\nDepending on your operating system you can accept most of the rest of the defaults, unless you would like to build for Android, which needs to be selected from the list of platforms.\n\nThis will change your `build.js` script with the options needed to build iOS/Android apps. Open this file and add the place-my-order-asset images to the **glob** property:\n\n```js\nlet cordovaOptions = {\n buildDir: \"./build/cordova\",\n id: \"com.donejs.placemyorder\",\n name: \"place my order\",\n platforms: [\"ios\"],\n plugins: [\"cordova-plugin-transport-security\"],\n index: __dirname + \"/production.html\",\n glob: [\n \"node_modules/place-my-order-assets/images/**/*\"\n ]\n};\n```\n\n<div line-highlight='9,only'></div>\n\nTo run the Cordova build and launch the simulator we can now run:\n\n```shell\ndonejs build cordova\n```\n\nIf everything went well, we should see the emulator running our application.\n\n### Building to Electron\n\nTo set up the desktop build, we have to add it to our application like this:\n\n```shell\ndonejs add electron@2\n```\n\nAnswer the question about the URL of the service layer with `http://www.place-my-order.com`. We can answer the rest of the prompts with the default.\n\nThen we can run the build like this:\n\n```shell\ndonejs build electron\n```\n\nThe macOS application can be opened with\n\n```shell\nopen build/place-my-order-darwin-x64/place-my-order.app\n```\n\nThe Windows application can be opened with\n\n```shell\n.\\build\\place-my-order-win32-x64\\place-my-order.exe\n```\n\n## Deploy\n\nNow that we verified that our application works in production, we can deploy it to the web. In this section, we will use [Firebase](https://www.firebase.com/), a service that provides static file hosting and [Content Delivery Network](https://en.wikipedia.org/wiki/Content_delivery_network) (CDN) support, to automatically deploy and serve our application's static assets from a CDN and [Heroku](https://heroku.com) to provide server-side rendering.\n\n### Static hosting on Firebase\n\nSign up for free at [Firebase](https://firebase.google.com/). After you have an account go to [Firebase console](https://console.firebase.google.com/) and create an app called `place-my-order-<user>` where `<user>` is your GitHub username:\n\n<img src=\"static/img/guide-firebase-setup.png\" alt=\"two browsers\" style=\"box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.2); border-radius: 5px; border: 1px #E7E7E7 solid; max-width: 400px;\" />\n\nWrite down the name of your app's ID because you'll need it in the next section.\n\n> You will get an error if your app name is too long, so pick something on the shorter side, for example `pmo-<user>`.\n\nWhen you deploy for the first time it will ask you to authorize with your login information, but first we need to configure the project.\n\n#### Configuring DoneJS\n\nWith the Firebase account and application in place we can add the deployment configuration to our project like this:\n\n```shell\ndonejs add firebase@1\n```\n\nWhen prompted, enter the name of the application created when you set up the Firebase app. Next, login to the firebase app for the first time by running:\n\n```shell\nnode_modules/.bin/firebase login\n```\n\nAnd authorize your application.\n\n#### Run deploy\n\nWe can now deploy the application by running:\n\n```shell\ndonejs build\ndonejs deploy\n```\n\nStatic files are deployed to Firebase and we can verify that the application is loading from the CDN by loading it running:\n\n```shell\nNODE_ENV=production donejs start\n```\n\n> If you're using Windows, set the NODE_ENV variable as you did previously in the Production section.\n\nWe should now see our assets being loaded from the Firebase CDN like this:\n\n![A network tab when using the CDN](static/img/guide-firebase-network.png)\n\n### Deploy your Node code\n\nAt this point your application has been deployed to a CDN. This contains StealJS, your production bundles and CSS, and any images or other static files. You still need to deploy your server code in order to get the benefit of server-side rendering.\n\nIf you do not have an account yet, sign up for Heroku at [signup.heroku.com](https://signup.heroku.com/). Then download the [Heroku CLI](https://devcenter.heroku.com/articles/heroku-command) which will be used to deploy.\n\nAfter installing run the [donejs-heroku](https://github.com/donejs/donejs-heroku) generator via:\n\n```shell\ndonejs add heroku\n```\n\nOnce you have logged in into your Heroku account, choose whether you want Heroku to use a random\nname for the application. If you choose not to use a random name, you will be prompted to enter\nthe application name:\n\n> We recommend you to use a random name since Heroku fails to create the app if the name is already taken.\n\n```shell\n? Do you want Heroku to use a random app name? Yes\n```\n\nWhen prompted, press the `Y` key since the application requires a proxy\n\n```shell\n? Does the application require a Proxy? Yes\n```\n\nThen enter `http://www.place-my-order.com/api` as the proxy url:\n\n```shell\n? What's the Proxy url? http://www.place-my-order.com/api\n```\n\nOnce the generator finishes, update the NODE_ENV variable via:\n\n```shell\nheroku config:set NODE_ENV=production\n```\n\nand follow the generator instructions to save our current changes:\n\n```shell\ngit add --all\ngit commit -m \"Finishing place-my-order\"\ngit push origin master\n```\n\nSince Heroku needs the build artifacts we need to commit those before pushing to Heroku. We recommend doing this in a separate branch.\n\n```shell\ngit checkout -b deploy\ngit add -f dist\ngit commit -m \"Deploying to Heroku\"\n```\n\nAnd finally do an initial deploy.\n\n```shell\ngit push heroku deploy:master\n```\n\nAny time in the future you want to deploy simply push to the Heroku remote. Once the deploy is finished you can open the link provided in your browser. If successful we can checkout the _master_ branch:\n\n```shell\ngit checkout master\n```\n\n### Continuous Deployment\n\nPreviously we set up Travis CI [for automated testing](#continuous-integration) of our application code as we developed, but Travis (and other CI solutions) can also be used to deploy our code to production once tests have passed.\n\nIn order to deploy to Heroku you need to provide Travis with your Heroku API key. Sensitive information in our `.travis.yml` should always be encrypted, and the generator takes care of encrypting the API key using the [travis-encrypt](https://www.npmjs.com/package/travis-encrypt) module.\n\n*Note: if using Windows, first install the OpenSSL package as described in the [Setting Up](https://donejs.com/SettingUp.html) guide.*\n\nRun the [donejs-travis-deploy-to-heroku](https://github.com/donejs/donejs-travis-deploy-to-heroku) generator like this:\n\n```shell\ndonejs add travis-deploy-to-heroku\n```\n\nWhen prompted, confirm each prompt by pressing the Enter key (or enter new values if needed) and then confirm the changes made to the `.travis.yml` file.\n\nThe updated `.travis.yml` should look like this:\n\n```yaml\nlanguage: node_js\nnode_js: node\naddons:\n firefox: latest\nbefore_install:\n - 'export DISPLAY=:99.0'\n - sh -e /etc/init.d/xvfb start\ndeploy:\n skip_cleanup: true\n provider: heroku\n app: <heroku-appname>\n api_key: <encrypted-heroku-api-key>\nbefore_deploy:\n - git config --global user.email \"me@example.com\"\n - git config --global user.name \"deploy bot\"\n - node build\n - git add dist/ --force\n - git commit -m \"Updating build.\"\n```\n<div line-highlight='8-18,only'></div>\n\n> The `donejs-travis-deploy-to-heroku` generator retrieves data from local configuration files, if any of the values set as default is incorrect, you can enter the correct value when prompted. To find the name of the Heroku application run `heroku apps:info`; or run `heroku auth:token` if you want to see your authentication token.\n\nNext, we set up Travis CI to deploy to [Firebase](https://www.firebase.com/) as well. To automate the deploy to Firebase you need to provide the Firebase CI token. You can get the token by running:\n\n```shell\nnode_modules/.bin/firebase login:ci\n```\n\nIn the application folder. It will open a browser window and ask you to authorize the application. Once successful, copy the token and enter it when prompted by the [travis-deploy-to-firebase](https://github.com/donejs/donejs-travis-deploy-to-firebase) generator.\n\nRun the following command:\n\n\n```shell\ndonejs add travis-deploy-to-firebase\n```\n\nConfirm your GitHub username and application name, then enter the Firebase CI Token from the previous step:\n\n```shell\n? What's your GitHub username? <your-username>\n? What's your GitHub application name? place-my-order\n? What's your Firebase CI Token? <your-firebase-ci-token>\n```\n\nAnd press the Enter key to update the `.travis.yml` file which should now look like this:\n\n```yaml\nlanguage: node_js\nnode_js: node\naddons:\n firefox: latest\nbefore_install:\n - 'export DISPLAY=:99.0'\n - sh -e /etc/init.d/xvfb start\ndeploy:\n skip_cleanup: true\n provider: heroku\n app: <heroku-appname>\n api_key: <encrypted-heroku-api-key>\nbefore_deploy:\n - git config --global user.email \"me@example.com\"\n - git config --global user.name \"deploy bot\"\n - node build\n - git add dist/ --force\n - git commit -m \"Updating build.\"\n - 'npm run deploy:ci'\nenv:\n global:\n - secure: <encrypted-firebase-ci-token>\n```\n<div line-highlight='19-22,only'></div>\n\nNow any time a build succeeds when pushing to `master` the application will be deployed to Heroku and static assets to Firebase's CDN.\n\nTo test this out checkout a new branch:\n\n```shell\ngit checkout -b continuous\ngit add -A\ngit commit -m \"Trying out continuous deployment\"\ngit push origin continuous\n```\n\nVisit your GitHub page, create a pull-request, wait for tests to pass and then merge. Visit your Travis CI build page at [https://travis-ci.org/<your-username>/place-my-order](https://travis-ci.org/<your-username>/place-my-order) to see the deployment happening in real time like this:\n\n![The Travis CI deploy](static/img/guide-travis-deploy.png)\n\n## What's next?\n\nIn this final short chapter, let's quickly look at what we did in this guide and where to follow up for any questions.\n\n### Recap\n\nIn this in-depth guide we created and deployed a fully tested restaurant menu ordering application called [place-my-order](http://www.place-my-order.com/) with DoneJS. We learned how to set up a DoneJS project, create custom elements and retrieve data from the server. Then we implemented a unit-tested view-model, ran those tests automatically from the command line and on a continuous integration server.\n\nWe went into more detail on how to create nested routes and importing other projects from npm. Then we created new orders and made it real-time, added and built documentation and made a production build. Finally we turned that same application into a desktop and mobile application and deployed it to a CDN and the web.\n\n### Following up\n\nYou can learn more about each of the individual projects that DoneJS includes at:\n\n- [StealJS](https://stealjs.com) - ES6, CJS, and AMD module loader and builder\n- [CanJS](https://canjs.com) - Custom elements and Model-View-ViewModel utilities\n- [jQuery](https://jquery.com) - DOM helpers\n- [jQuery++](https://jquerypp.com) - Extended DOM helpers\n- [QUnit](https://qunitjs.com/) or Mocha - Assertion library\n- [FuncUnit](https://funcunit.com) - Functional tests\n- [Testee](https://github.com/bitovi/testee) - Test runner\n- [DocumentJS](https://documentjs.com) - Documentation\n\nIf you have any questions, do not hesitate to ask us on [Slack](https://www.bitovi.com/community/slack) ([#donejs channel](https://bitovi-community.slack.com/messages/CFC80DU5B)) or the [forums](https://forums.bitovi.com)!\n\n",
"description": "In this guide you will learn about all of [DoneJS' features](./Features.html) by creating, testing, documenting, building and deploying [place-my-order.com](http://www.place-my-order.com), a restaurant menu and ordering application. The final result will look like this: \n\n<img src=\"static/img/place-my-order.png\" srcset=\"static/img/place-my-order.png 1x, static/img/place-my-order-2x.png 2x\">\n\n\nAfter the initial application setup, which includes a server that hosts and pre-renders the application, we will create several custom elements and bring them together using the application state and routes. Then we will learn how to retrieve data from the server using a RESTful API.\n\nAfter that we will talk about what a view model is and how to identify, implement and test its functionality. Once we have unit tests running in the browser, we will automate running them locally from the command line and also on a continuous integration server. In the subsequent chapters, we will show how to easily import other modules into our application and how to set up a real-time connection.\n\nFinally, we will describe how to build and deploy our application to the web, as a desktop application with Electron, and as a mobile app with Cordova.\n\n\n",
"name": "place-my-order",
"title": "In-depth guide",
"type": "page",
"parent": "Guides",
"hideSidebar": true,
"outline": {
"depth": 2,
"tag": "ol"
},
"comment": " "
},
"ssr-react": {
"src": {
"path": "docs/guides/react-ssr.md"
},
"body": "\n## Setting up\n\nThis app uses [create-react-app](https://github.com/facebookincubator/create-react-app) to scaffold a React application and for client development. We'll be swapping out the server for our own, to enable server-side rendering.\n\nIf you haven't already, install create-react-app:\n\n> **_note: if you are a `yarn` user, replace all the following npm commands with the appropriate yarn command_** \n> _if you are having any trouble with packages not appearing to have been installed, sometimes deleting your `node_modules` directory and running `npm install` can sort things out, this generally only happens if you have yarn installed globally, but are using npm_\n\n```\nnpm install -g create-react-app\n```\n\nThen, create the application:\n\n```\ncreate-react-app my-react-app\n```\n\nThis will install the dependencies to a new folder `my-react-app/`. Once done you can cd into the folder and start the development server:\n\n```\ncd my-react-app/\nnpm start\n```\n\nThis will start a development server and launch the browser. It looks like:\n\n![react app dev server](https://user-images.githubusercontent.com/361671/31185277-92a89bfc-a8f9-11e7-9b02-d2899173ae4b.png)\n\n## Adding a server\n\nIn order to use done-ssr for server-side rendering, we need to first set up a server. We'll use [Express](https://expressjs.com/) as our server framework. Install a few dependencies we need:\n\n```shell\nnpm install express can-zone-jsdom done-ssr --save\n```\n\nCreate a folder to put our server code:\n\n```shell\nmkdir server\n```\n\nCreate `server/index.js`:\n\n```js\nconst Zone = require('can-zone');\nconst express = require('express');\nconst app = express();\n\nconst dom = require('can-zone-jsdom');\nconst requests = require('done-ssr/zones/requests');\n\nconst PORT = process.env.PORT || 3000;\n\napp.use(express.static('build', { index: false }));\napp.use(express.static('.'));\n\napp.get('*', async (request, response) => {\n var zone = new Zone([\n // Overrides XHR, fetch\n requests(request),\n\n // Sets up a DOM\n dom(request, {\n root: __dirname + '/../build',\n html: 'index.html'\n })\n ]);\n\n const { html } = await zone.run();\n response.end(html);\n});\n\nrequire('http')\n .createServer(app)\n .listen(PORT);\n\nconsole.error(`Server running at http://localhost:${PORT}`);\n```\n\nTo run it, you need to add a `NODE_ENV` environment variable. For convenience add this to your package.json *scripts*:\n\n```json\n\"scripts\": {\n \"server\": \"NODE_ENV=development node server/index.js\"\n}\n```\n\nThen run the build step for your React app:\n\n```\nnpm run build\n```\n\nAnd then launch it with:\n\n```\nnpm run server\n```\n\nAnd navigate to [http://localhost:3000](http://localhost:3000).\n\nLet's break down the interesting parts of this server.\n\n### React\n\n__[can-zone-jsdom](https://github.com/canjs/can-zone-jsdom)__ is the project that we use to provide a DOM environment for the app. This plugin allows you to load an HTML file for each request.\n\nThis server directly uses the entry point `build/index.html` in the Node application. This is an HTML file that is created when `npm run build` is ran. You can see the use here:\n\n```js\n// Sets up a DOM\ndom(request, {\n root: __dirname + '/../build',\n html: 'index.html'\n})\n```\n\nThis says that the [document.baseURI](https://developer.mozilla.org/en-US/docs/Web/API/Node/baseURI) is the *build* folder, and to use *index.html* to load into the DOM.\n\nFor each request the HTML file is loaded and its scripts are executed.\n\n### Routing\n\nWe are using [Express](https://expressjs.com/) to provide routing for this application. In addition, it handles server static files:\n\n```js\napp.use(express.static('build'));\napp.use(express.static('.'));\n```\n\nThere is only one route defined:\n\n```js\napp.get('*', (request, response) => {\n // Stuff here\n});\n```\n\nThis means that the server will first check for a static file in either `build/` or `.`, and if not available, it will go to the wildcard route.\n\nThis allows us to handle routing for our app the same way as we would in the browser. We are only handling the `/` route in this application, but there are many choices for routing in React such as React-Route or [page.js](https://github.com/visionmedia/page.js).\n\n### Zones\n\nThe rest of this guide will focus on the code contained within the `*` route. This uses [can-zone](https://github.com/canjs/can-zone) to act as a common context when calling into the client-side components (starting with `src/App.js`). You can read more about can-zone [here](https://davidwalsh.name/can-zone).\n\n**done-ssr** provides a set of zone plugins (referred to hereafter as *zones*) that provide various capabilities. Right now we are using only 2 zones:\n\n* **done-ssr/zones/requests**:\n * Provides polyfills for `XMLHttpRequest`, `fetch`, and `WebSocket`.\n * Allows domain-relative URLs like `/api/todos`.\n* **can-zone-jsdom**: Provides a DOM implementation, including `document`, `window`, and `location` objects. Serializes the document (when the zone is complete) as `zone.data.html`.\n\nLater in the guide we'll add a couple of more, for HTTP/2 support.\n\nBreaking down the steps here, first we have:\n\n```js\nvar zone = new Zone([\n // Overrides XHR, fetch\n requests(request),\n\n // Sets up a DOM\n dom(request, {\n root: __dirname + '/../build',\n html: 'index.html'\n })\n]);\n```\n\nThis creates a new can-zone using the previously mentioned zone plugins.\n\n```js\nconst { html } = await zone.run();\nresponse.end(html);\n```\n\nRuns the contents of `index.html` within the zone and waits for it to asynchronously complete. Once completed extracts the `html` string and ends the `response` with that as the value.\n\nRemember that the **index.html** is run every time a request is rendered, and a new `document` is set for each request (by **can-zone-jsdom**).\n\n## HTTP/2\n\nUsing done-ssr makes it very simple to support HTTP/1 applications, but we can do even better using HTTP/2 and [incremental rendering](https://www.bitovi.com/blog/utilizing-http2-push-in-a-single-page-application).\n\nUsing the **done-ssr/zones/push-mutations** zone, we can add incremental rendering to this application.\n\n### Setup\n\nFirst, we need to install an HTTP/2 server. While HTTP/2 support is in Node 8.6.0 behind a flag, I've found it to be too buggy to use today. So use *donejs-spdy* instead:\n\n```\nnpm install donejs-spdy --save\n```\n\nAt this point you'll need to create a private key and certificate, as HTTP/2 requires SSL. If using a Unix operating system, you can use *openssl* for this:\n\n```\nopenssl req -nodes -new -x509 -keyout server.key -out server.cert\n```\n\nThis will create *server.key* and *server.cert* files. I like to copy those to another folder so that they can be reused in other applications.\n\n```shell\nmkdir -p ~/.localhost-ssl\nmv server.key server.cert ~/.localhost-ssl\n```\n\nLastly, update your *package.json* so these files are available to use:\n\n```js\n\"scripts\": {\n \"server\": \"NODE_ENV=development KEY=~/.localhost-ssl/server.key CERT=~/.localhost-ssl/server.cert node server/index.js\"\n}\n```\n\n### Update server\n\nNow that you have SSL and an HTTP/2 server installed, update your `server/index.js` script to:\n\n```js\nconst Zone = require('can-zone');\nconst express = require('express');\nconst fs = require('fs');\nconst app = express();\n\nconst dom = require('can-zone-jsdom');\nconst requests = require('done-ssr/zones/requests');\nconst pushFetch = require('done-ssr/zones/push-fetch');\nconst pushMutations = require('done-ssr/zones/push-mutations');\n\nconst PORT = process.env.PORT || 8080;\n\napp.use(express.static('build', { index: false }));\napp.use(express.static('.'));\n\napp.get('*', async (request, response) => {\n var zone = new Zone([\n // Overrides XHR, fetch\n requests(request),\n\n // Sets up a DOM\n dom(request, {\n root: __dirname + '/../build',\n html: 'index.html'\n }),\n\n // H2 push\n pushFetch(response),\n pushMutations(response)\n ]);\n\n const zonePromise = zone.run();\n\n response.write(zone.data.html);\n\n await zonePromise;\n response.end();\n});\n\nrequire('donejs-spdy')\n .createServer(\n {\n key: fs.readFileSync(process.env.KEY),\n cert: fs.readFileSync(process.env.CERT),\n spdy: {\n protocols: ['h2', 'http/1.1']\n }\n },\n app\n )\n .listen(PORT);\n\nconsole.error(`Server running at https://localhost:${PORT}`);\n```\n<div line-highlight='3,8-9,27-29,32-37,40-50,54,only'></div>\n\nThis adds two new zones to our arsenal:\n\n* **done-ssr/zones/push-fetch**: Traps calls to the [fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) and uses H2 PUSH to start pushing them to the browser. This way when the browser JavaScript tries to fetch this resource it's already available in the browser cache.\n* **done-ssr/zones/push-mutations**: This is the zone that handles incremental rendering. It does a few things interesting:\n\n 1. Listens to mutations in the document and serializes a *patch* that can be applied in the browser document.\n 1. Adds a script to the `<head>` that will attach to a special URL where the mutations are being streamed. When this script runs in the browser it will fetch that URL and start applying the mutation patches as they come in.\n\nIf you start your server again with `npm run server`, you should be able to see the application running.\n\n## Adding an API\n\nEven though we have incremental server-side rendering set up, since we're not doing any `fetch` requests, there are no mutations to be applied. So let's add an API route and have our client code make a request.\n\n### List component\n\nTo make this even better, we'll use *ReadableStream*, the advanced feature of `fetch` that allows you to stream in the request in chunks. When streaming in API requests, it's good to use the [ndjson](http://ndjson.org/) format.\n\nndjson is just JSON that is separated by newline characters. It looks like this:\n\n```\n{\"item\": \"One\"}\n{\"item\": \"Two\"}\n```\n\nWe'll use [can-ndjson-stream](https://github.com/canjs/can-ndjson-stream) to make it easier to work with this format. So install that first:\n\n```js\nnpm install can-ndjson-stream --save\n```\n\nWe'll use this in our client code. Create `src/List.js`:\n\n```js\nimport React, { Component } from 'react';\nimport ndjsonStream from 'can-ndjson-stream';\n\nexport default class extends Component {\n constructor() {\n super();\n this.state = { items: [] };\n\n fetch('/api/items').then(resp => {\n return ndjsonStream(resp.body);\n }).then(stream => {\n let reader = stream.getReader();\n\n let read = result => {\n if (result.done) return;\n this.setState({\n items: this.state.items.concat(result.value)\n });\n return reader.read().then(read);\n }\n\n return reader.read().then(read);\n });\n }\n\n render() {\n let { items } = this.state;\n\n return (\n <section>\n <h2>List of stuff</h2>\n <ul>\n {items.map(item => (\n <li key={item.item}>\n {item.item}\n </li>\n ))}\n </ul>\n </section>\n\n );\n }\n}\n```\n\nAnd then use it within *src/App.js*:\n\n\n```js\nimport React, { Component } from 'react';\nimport logo from './logo.svg';\nimport './App.css';\nimport List from './List.js';\n\nclass App extends Component {\n render() {\n return (\n <div className=\"App\">\n <header className=\"App-header\">\n <img src={logo} className=\"App-logo\" alt=\"logo\" />\n <h1 className=\"App-title\">Welcome to React</h1>\n </header>\n <List />\n </div>\n );\n }\n}\n\nexport default App;\n```\n<div line-highlight='4,14'></div>\n\nWhat is happening in *src/List.js*:\n\n1. A component is created with an `items` Array in the state.\n2. A *fetch* request is made to `/api/items`.\n3. `can-ndjson-stream` is called with the response body.\n4. Each item comes through the stream as a JavaScript object and appended to `this.state.items`.\n5. `render()` is recalled and a new `<li>` is created for each item.\n\n### API route\n\nNow that we have the client code we need to set up the route to handle it. Create *server/api.js* with the following:\n\n```js\nconst Readable = require('stream').Readable;\n\nmodule.exports = function(app){\n app.get('/api/items', (request, response) => {\n response.writeHead(200, { 'Content-Type': 'text/plain' })\n\n var chunks = [\n {item:'One'},\n {item:'Two'},\n {item:'Three'},\n {item:'Four'},\n {item:'Five'},\n {item:'Six'},\n {item:'Seven'},\n {item:'Eight'},\n {item:'Nine'},\n {item:'Ten'}\n ];\n\n var r = new Readable({\n read() {\n setTimeout(() => {\n var item = chunks.shift();\n if(item) {\n this.push(`${JSON.stringify(item)}\\n`);\n } else {\n this.push(null);\n }\n }, 500);\n }\n });\n\n r.pipe(response);\n });\n};\n```\n\nThis route is very simple, it returns an ndjson stream that emits a row every *500* milliseconds. Since there are 10 rows it takes 5 seconds for this to complete. This is just enough time to see incremental rendering in action.\n\nTo use it, update *server/index.js*:\n\n```js\nconst Zone = require('can-zone');\nconst express = require('express');\nconst fs = require('fs');\nconst app = express();\n\nconst dom = require('can-zone-jsdom');\nconst requests = require('done-ssr/zones/requests');\nconst pushFetch = require('done-ssr/zones/push-fetch');\nconst pushMutations = require('done-ssr/zones/push-mutations');\n\nconst PORT = process.env.PORT || 8080;\n\napp.use(express.static('build', { index: false }));\napp.use(express.static('.'));\nrequire('./api')(app);\n\napp.get('*', async (request, response) => {\n var zone = new Zone([\n // Overrides XHR, fetch\n requests(request),\n\n // Sets up a DOM\n dom(request, {\n root: __dirname + '/../build',\n html: 'index.html'\n }),\n\n // H2 push\n pushFetch(response),\n pushMutations(response)\n ]);\n\n const zonePromise = zone.run();\n\n response.write(zone.data.html);\n\n await zonePromise;\n response.end();\n});\n\nrequire('donejs-spdy')\n .createServer(\n {\n key: fs.readFileSync(process.env.KEY),\n cert: fs.readFileSync(process.env.CERT),\n spdy: {\n protocols: ['h2', 'http/1.1']\n }\n },\n app\n )\n .listen(PORT);\n\nconsole.error(`Server running at https://localhost:${PORT}`);\n```\n<div line-highlight='15,only'></div>\n\nAnd then run the build:\n\n```js\nnpm run build\n```\n\nNow, if you restart your server you should see the list incrementally updating.\n\n![rendering gif](https://user-images.githubusercontent.com/361671/31230099-f3ada73c-a9b0-11e7-85f6-2ac9a4cf0a9f.gif)\n\n## Conclusion\n\nIn this guide we've discussed:\n\n* Using [can-zone](https://github.com/canjs/can-zone) to provide context to rendering a React application.\n* Setting up an HTTP/2 server.\n* Enabling incremental rendering, so that the application can be updated as changes occur on the server.\n\nTo see this guide as a fully working example, check out the [done-ssr-react-example](https://github.com/donejs/done-ssr-react-example) repository.\n\n",
"description": " \nIn this guide you'll learn about using [done-ssr](https://github.com/donejs/done-ssr) to server render a React application. This guide walks through the technologies that make DoneJS server rendering special:\n\n- Using [Zones](https://github.com/canjs/can-zone) to isolate rendering, allowing multiple requests to be served from the same application\n- Server-side virtual DOM with common APIs, allowing you to use the same code that runs on the client, for rendering on the server\n- HTTP/2 support, and H/2 PUSH, to PUSH out API requests as they are fulfilled on the server\n- Incremental rendering using HTTP/2 PUSH and the [fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API).\n\n",
"name": "ssr-react",
"title": "Server rendering",
"type": "page",
"parent": "Guides",
"hideSidebar": true,
"outline": {
"depth": 2,
"tag": "ol"
},
"comment": " "
},
"SettingUp": {
"src": {
"path": "docs/guides/setting-up.md"
},
"body": "\n## Windows\n\n### Prerequisites\n\nThis will help you get set up with DoneJS on Windows. To use DoneJS you need a C++ compiler (for native dependencies). First you need a recent version of [Node.js](https://nodejs.org/en/).\n\n#### Node.js\n\nTo download Node.js visit [https://nodejs.org](https://nodejs.org). There will be two big green buttons for the two recommended downloads. Choose the one on the right, which says **Current**. This will give you the most recent version of Node.js.\n\nOnce downloaded, double-click the installer and go through the installation process. Once complete you should be able to open up a terminal and type:\n\n```shell\nnode -v\n```\n\nWhich should then print out the version of Node.js that is installed.\n\n#### Package Management\n\nIn this guide we'll use [chocolatey](https://chocolatey.org/) to install packages needed. You don't have to use chocolatey if you don't want, and can instead search for the dependencies and install them with a Windows installer, but we'll use chocolately because it makes things a bit easier.\n\nAfter you've installed chocolatey by following the instructions [on the homepage](https://chocolatey.org/) **open an administrative console** and proceed to the next step.\n\n#### Python 2.x\n\nNative dependencies in Node.js are installed with [node-gyp](https://github.com/nodejs/node-gyp) which uses Python as a build tool. It expects Python 2.x:\n\n```shell\nchoco install python2 -y\n```\n\n#### Windows SDK\n\nNext we need the Windows SDK. We're going to assume Windows 7, but adjust this command to the version of Windows you use (for Windows 10 it is windows-sdk-10.0):\n\n```shell\nchoco install windows-sdk-7.1 -y\n```\n\n#### Visual Studio Express\n\nInstalling Visual Studio Express gives us the C++ compiler we need. If you are using Windows 10 or get an error with this command you can also download Visual Studio Express [here](https://www.visualstudio.com/en-us/products/visual-studio-express-vs.aspx):\n\n```shell\nchoco install visualstudioexpress2013windowsdesktop -y\n```\n\n#### OpenSSL\n\nIf you plan on using Continuous Deployment with Travis CI, the [OpenSSL](https://slproweb.com/products/Win32OpenSSL.html) software is needed to encrypt your CDN API key.\n\n### Environmental Variables\n\nIn order to switch to production mode you need to set the environmental variable `NODE_ENV`. Depending on which console you use this can be done in one of two ways:\n\n**Command Prompt**\n\n```\nset NODE_ENV=production\n```\n\n**Powershell**\n\n```\n$env:NODE_ENV=\"production\"\n```\n\nTo later remove these environment variables:\n\n**Command Prompt**\n\n```\nset NODE_ENV=\n```\n\n**Powershell**\n\n```\n$env:NODE_ENV=\"\"\n```\n\n\n### Android Development\n\nIn order to develop an Android application you need to install the [Android Studio](https://developer.android.com/sdk/index.html). The installer will prompt you to also install Java if you don't already have it.\n\n<img src=\"static/img/wiz-1.png\" alt=\"Android Studio installation\" style=\"width: 100%;\" class=\"alignnone size-full wp-image-2665\" />\n\nWhen you start Android Studio for the first time it will go through the installation of the SDK and related tools. If prompted select to install:\n\n* Android 7.x\n* Android SDK\n* Performance (this will improve the emulator start time)\n* Android Virtual Device (this will create an optimized emulator)\n\nOnce this is complete you should have everything you need for Android development. You can close Android Studio as you won't need it for DoneJS development.\n\n<a id=\"mac-os-x\"></a>\n## macOS\n\n### Node.js\n\nTo download Node.js visit [https://nodejs.org](https://nodejs.org). There will be two big green buttons for the two recommended downloads. Choose the one on the right, which says **Current**. This will give you the most recent version of Node.js.\n\nOnce downloaded, double-click the installer and go through the installation process. Once complete you should be able to open up a terminal and type:\n\n```shell\nnode -v\n```\n\nWhich should then print out the version of Node.js that is installed.\n\n### Prerequisites\n\nTo get DoneJS working on macOS you need Xcode command line tools which you can get by typing:\n\n```shell\nxcode-select --install\n```\n\nAnd to build iOS apps, after installing Node, install the `ios-sim` package with:\n\n```\nnpm install -g ios-sim\n```\n\n## Debian / Ubuntu\n\nInstalling in a Debian / Ubuntu environment takes a little extra work because the version of Node shipped is older than what is supported by DoneJS (and most other Node-based software).\n\n### Prerequisites\n\nInstead of installing Node.js from the repository we recommend using a PPA (a repository maintained by a 3rd party). First get a copy of `curl` if you don't already have it:\n\n```\nsudo apt-get install curl\n```\n\nThen add the PPA to your source list:\n\n```\ncurl -sL https://deb.nodesource.com/setup_10.x | sudo bash -\n```\n\nInstall Node.js:\n\n```\nsudo apt-get install nodejs\n```\n\nIt's important to also install the `build-essential` package afterwards. This will provide you the C++ compiler needed to build the native dependencies:\n\n```\nsudo apt-get install build-essential\n```\n\n### Android Development\n\nIn order to develop an Android application you need to install the [Android Studio](https://developer.android.com/sdk/index.html). Once download untar/gzip it:\n\n```\ntar xvf android-sdk.X-linux.tgz\n```\n\nThis will create an `android-sdk-linux` folder. At this point you might want to move it somewhere else, `$HOME/lib/android-sdk-linux` is a good place.\n\nAdd the android-sdk-linux/tools folder to your `PATH` with: `export PATH=\"path/to/android-sdk-linux/tools`. Add this to your `~/.bashrc` or `~/.zshrc` config so it will persist.\n\nAdditionally the `ANDROID_HOME` environmental variable needs to be set. Set it with:\n\n```\nexport ANDROID_HOME=\"/home/name/lib/android-sdk-linux\"\n```\n\nThis too should be added to your `~/.bashrc` or `~/.zshrc`.\n\n#### Java\n\nIf you don't already have a Java JDK installed you can do so with:\n\n```\nsudo apt-get install default-jdk\n```\n\n#### Platform and Build Tools\n\nOnce you've installed Android Studio you still have a few things to do. You need to install the Android SDK Platform and Build tools. From the command-line run:\n\n```\n$ANDROID_HOME/tools/android\n```\n\nThis starts the Android SDK Manager. From this screen you can select:\n\n* Android 6.0\n* Android SDK Build-tools (23+)\n* Intel x86 Emulator Accelerator (this will improve the emulator start time)\n\nClick all of these and anything else you need and click Install packages.\n\n#### Virtual Device Manager\n\nFrom the command-line run:\n\n```\n$ANDROID_HOME/tools/android avd\n```\n\nThis starts the Android Virtual Device (AVD) Manager. This is used to manager virtual devices that will run in the emulator.\n\nClick **Create** and make sure to fill out:\n\n* AVD Name (this can be whatever you want)\n* Device\n* Target (the API level you installed)\n* CPU (try an Intel CPU if possible)\n\nThen click **OK** to create the device.\n\nClose the AVD Manager and you should have everything you need for Android development.\n\n\n## Vagrant & VirtualBox\n\n### Prerequisites\n\nFirst at all, download and install [**VirtualBox**](https://www.virtualbox.org/) and [**Vagrant**](https://www.vagrantup.com/). Once VirtualBox and Vagrant have been installed, you should add the DoneJS box to your Vagrant installation.\n\n### Installing the DoneJS Vagrant Box\nOpen your command prompt and type\n```\nvagrant --version\n```\nto see if Vagrant is available in your terminal.\n\nWithin your terminal change to the folder you would like to install the Vagrant Box. Using the following command for adding the box:\n```\nvagrant box add Juke/DoneJS\n```\n\nVagrant will ask you for which provider you will adding the box. Choose: **Virtualbox**\nVagrant will now downloading the latest version of the DoneJS development environment. It will take a few minutes, depending on your Internet connection speed.\n\nOnce Vagrant has successfully finished downloading all the file, you can now initialize the DoneJS Box by typing\n```\nvagrant init Juke/DoneJS\n```\n\nVagrant is creating a **Vagrantfile** in your folder. Your custom configuration for the machine can be done in this file.\nFor more information check out https://www.vagrantup.com/docs/vagrantfile/\n\n\n### Configure your shared folders\nBefore you start the Vagrant Box, you have to specify which folder you would like to sync from your local machine to the virtual machine.\nFor that, open the **Vagrantfile** in that folder you initialized Vagrant. Scroll down to:\n\n```\n# Share an additional folder to the guest VM. The first argument is\n# the path on the host to the actual folder. The second argument is\n# the path on the guest to mount the folder. And the optional third\n# argument is a set of non-required options.\n# config.vm.synced_folder \"../data\", \"/vagrant_data\"\n```\n\nadd a new Synced Folder configuration below that may look like this\n\n```\nconfig.vm.synced_folder \"C:/www/donejs\", \"/home/vagrant/donejs\"\n```\n\nMake sure that `C:/www/donejs` is a valid directory.\n\nFor more information check the [documentation](https://www.vagrantup.com/docs/synced-folders/basic_usage.html).\n\n### Launching the Vagrant Box\nOnce you have done all the configuration run\n\n```\nvagrant up\n```\n\ncommand from your DoneJS Vagrant Box directory\n\n### Connecting via SSH\nTo connect to your DoneJS environment via SSH, enter the\n\n```\nvagrant ssh\n```\n\ncommand in your terminal.\n\n### Further information\nFor further information about what is pre-installed on the Vagrant Box and which ports are forwarding to your host please check out the Github repository [DoneJS Vagrant](https://github.com/donejs/donejs-vagrant)\n\n",
"description": "This page contains information on setting up DoneJS. It will walk you through getting prerequisites needed before you ever install DoneJS and includes platform-specific pieces of information not covered in the Quick Start or In Depth guides.\n\nDoneJS officially supports:\n\n - [Node](https://nodejs.org) 10 and up\n - [npm](https://www.npmjs.com/) 6.x and up\n\n",
"name": "SettingUp",
"title": "Setting Up DoneJS",
"type": "page",
"parent": "Guides",
"hideSidebar": true,
"outline": {
"depth": 2,
"tag": "ol"
},
"comment": " "
},
"updating-deps": {
"src": {
"path": "docs/guides/updating-deps.md"
},
"body": "\nAvoiding duplicate versions of dependencies is a necessary evil in front-end applications. When using the `package-lock.json` file, dependencies versions are ___locked___ on each of your dependencies. If you update one dependency, but not another, it is possible for you to encounter version conflicts.\n\nWe recommend one of two solutions for this.\n\n## Encountering conflicts\n\nAs part of your normal development flow you might update dependencies when you see there is a new version via `npm outdated`. We recommend always creating a new branch to do updates:\n\n```shell\ngit checkout -b updates\n\nnpm update can\n```\n\nWhich will update to the latest version of `can`. Then continue with your normal development:\n\n```shell\ndonejs develop\n```\n\nIf you encounter errors or bugs (often you will get a `you cannot have multiple versions of...` error). then you can fix these by doing:\n\n```shell\nrm -rf node_modules package-lock.json\nnpm install\n```\n\nDeleting the `package-lock.json` file forces a new version to be generated. This new version will have dependencies ordered correctly. Then retest and most likely the problem will be resolved.\n\nIf you encounter an error you cannot resolve then rollback the change by removing the branch:\n\n```shell\ngit checkout master\ngit branch -D updates\n```\n\nA future release of `can` will likely fix this problem.\n\n## Turning off package-lock\n\nAnother option is to remove the `package-lock.json` file. This prevents you from having __locked__ dependencies but also ensures that you always have the latest version of every package.\n\nYou can disable package-lock in your repo by adding a `.npmrc` file in your root project folder with the following:\n\n```\npackage-lock=false\n```\n\nIf you have an existing `package-lock.json` file you'll need to remove it (including from git) and then reinstall:\n\n```shell\nrm -rf node_modules package-lock.json\nnpm install\n```\n\n",
"description": "How to update dependencies in DoneJS applications. \n",
"name": "updating-deps",
"title": "Updating Dependencies",
"type": "page",
"parent": "Guides",
"hideSidebar": true,
"outline": {
"depth": 2,
"tag": "ol"
},
"comment": " "
},
"About-ru": {
"src": {
"path": "docs/ru/about-ru.md"
},
"body": "\n## Цели\n\nDoneJS имеет 3 основных цели:\n\n1. Позволить разработчикам легко создавать высоко производительные, очень удобные, легко сопровождаемые (замечательные) приложения.\n2. Постоянно развиваться с новыми технологиями и средствами.\n3. Поддерживать технологии сообщества.\n\n### Удивительные приложения\n\nПостроение современного приложения очень сложная задача. Ваше приложение должно выглядить хорошо и работать быстро на всех платформах и браузерах.\n\nМы поможем вам получить высокую производительность. Сделать быстро это основная задача DoneJS, вот почему наш логотип\nэто браузер, который выглядит как клетчатый флаг.\n\nМы нацелены на решение 3 главных задач:\n\n#### 1. Решение сложных технических проблем\n\nDoneJS идеален для:\n\n - [Сборка под мобильный девайс и десктоп](#section=section_iOS_Android_andDesktopBuilds)\n - [Рендеринг на сервере](#section=section_Server_SideRendered)\n - [Автоматические апдейты в реальном времени](#section=section_RealTimeConnected)\n - [Быстрая загрузка](##section=section_ProgressiveLoading)\n\nВот несколько примеров на [странице возможностей](/Features.html). Если вы сталкиваетесь с трудностями, мы хотим их решить.\n\n#### 2. Обеспечение комплексного решения\n\nСлишком много доступных вариантов может быть трудным для принятия решения. DoneJS упрощает процесс, предоставляя полный стек разработки. [Страница возможностей](/Features.html) даст более подробное представление.\n\n_Примечание: Несмотря на комплексное решение, вы можете заменить части DoneJS альтернативами._\n\n\n#### 3. Делать правильные вещи\n\nНаписание тестов и документации, создание непрерывной интеграции и развертывания не весело или просто. DoneJS пытается облегчить сложный барьер для `правильных вещей`, чтобы это было частью нормального цикла разработки.\n\nПосмотрите что может DoneJS:\n\n- [Тесты](#section=section_ComprehensiveTesting)\n- [Документация](#section=section_Documentation)\n- [Гайды для CI и CD](#section=section_ContinuousIntegration_Deployment)\n- [Модлеты](#section=section_Modlets)\n- [Генераторы](#section=section_Generators)\n\n### Развитие\n\nРазработка приложений и техническое обслуживание часто\nдлится много лет. Стабильность необходима для сложных приложений. Однако,\nновые методы и наилучшие практики постоянно развиваются.\n\nЦелью DoneJS является баланс между стабильностью и прогрессом. Мы делаем это с помощью частых обновлений, в то же время поддерживаем обратную совместимость между основными выпусками.\n\nЭто может быть ухабистая дорога с большим количеством маленьких изменений, но это предотвращает перезапись, что приводит к большей производительности:\n\n<img src=\"http://blog.bitovi.com/wp-content/uploads/2015/10/mountain-climb1.jpg\"/>\n\nDoneJS является преемником JavaScriptMVC. Если ваш проект выбрал JavaScriptMVC в 2007 году, вы сделали мудрое решение для применения самых современных технологий в течение последних 8 лет.\n\nМы надеемся продолжить эту тенденцию пока программы не начали писать себя сами.\n\n### Сообщество\n\nС друзьями лучше всего заниматься программным обеспечением. Наша цель заключается в создании большого мирового\nсообщества с людьми из всех слоев и уровней квалификации, для обучения, исследования и инноваций.\n\n#### Обучение\n\nТехнология не стоит ничего, если люди не знают, как ее использовать. Мы хотим создать не только замечательный учебный материал, но и создать условия где люди чувствуют себя комфортно для решения вопросов и получения помощи.\n\nОсновная команда разработчиков всегда доступна через [Slack](https://www.bitovi.com/community/slack)\nи проводит [еженедельные тренинги](http://blog.bitovi.com/free-weekly-online-javascript-training/). Регистрируйтесь на [встречу](/community.html) и мы приедем в ваш город и научим DoneJS!\n\n\n#### Исследование\n\n\nDoneJS развивается с помощью других проектов и технологий. Следует увеличивать развитие с другими сообществами.\n\nВы можете использовать многие технологии из DoneJS с другими проектами:\n\n - StealJS отлично совместим с ReactJS. \n - CanJS совместим с RequireJS или Browserify. \n - can-connect может работать сам по себе. \n\nМы постоянно ищем развитие с другими проектами.\n\n#### Привлечение\n\nЕсли у вас есть отличная JS идея, мы хотим привлечь вас, чтобы вы использовали DoneJS. Вы можете найти единомышленников для реализации своей идеи. Обратитесь к нам через [Slack](https://www.bitovi.com/community/slack).\n\n\n## История\n\nИстория DoneJS продолжается уже 8 лет! Изучите как начинался JavaScriptMVC, и как он перешел в DoneJS.\n\n### Начальные шаги\n\n_Эта секция будет заполнена 1 ноября. Следите за обновлениями._\n\n### Планы на будущее\n\nНиже приведены наши наивысшиe приоритеты, не баг фиксинги:\n\n- [can-set поддержка сортировки](https://github.com/canjs/can-set/pull/10)\n- [documentjs конфигурирование в package.json](https://github.com/bitovi/documentjs/issues/202)\n- [StealJS dependency injection](https://github.com/stealjs/steal/issues/509)\n- [can-connect поддержка других фреймворков](https://github.com/canjs/can-connect/issues/42)\n- [Animation utilities](https://github.com/canjs/can-animate)\n- [O(log n) derived list modification](https://github.com/canjs/can-derive)\n\n## Разработчики\n\nDoneJS разрабатывается с помощью более чем 100 участников:\n\n### Основные разработчики\n\nДля того чтобы стать участником DoneJS или его подпроектов, вы просто должны:\n\n- отправить [email](mailto:contact@bitovi.com) интересующей вас основной команде разработчиков.\n- участвовать в еженедельной встрече, по крайней мере два раза в месяц.\n- сделать один небольшой вклад в проект в месяц, подойдет даже проверка правописания.\n\nОсновные разработчики:\n\n<div class=\"core-team-member\">\n<img class=\"member-avatar\" src=\"https://avatars3.githubusercontent.com/u/4830283?v=3&s=300\"/>\n<h4>Прашант Шарма</h4>\n<p>\nПрашант живет в Бангалоре, Индия. Он любит элегантность CanJS. Верит, что DoneJS замечательный фреймворк для создания приложений, так как он предоставляет разработчикам технологию все в одном.\n</p>\n<a href=\"https://github.com/prashantsharmain\" target=\"_blank\">github</a>\n</div>\n\n\n\n### Фуллтайм разработчики\n\nНа данный момент над DoneJS и подпроектами работают 3 фуллтайм разработчика:\n\n<div class=\"core-team-member\">\n<img class=\"member-avatar\" src=\"https://avatars3.githubusercontent.com/u/78602?v=3&s=300\"/>\n<h4>Джастин Майер</h4>\n<p>\nДжастин танцует и играет в баскетбол в Чикаго. Он является создателем JavascriptMVC и руководит проектом DoneJS.\n</p>\n<a href=\"https://twitter.com/justinbmeyer\" target=\"_blank\">@justinbmeyer</a>\n<a href=\"https://github.com/justinbmeyer\" target=\"_blank\">github</a>\n</div>\n\n<div class=\"core-team-member\">\n<img class=\"member-avatar\" src=\"https://avatars3.githubusercontent.com/u/338316?v=3&s=300\"/>\n<h4>Дэвид Люка</h4>\n<p>\nДэвид немец живущий в канаде. Он занимается разработкой CanJS и тестированием DoneJS.\n</p>\n<a href=\"https://twitter.com/daffl\" target=\"_blank\">@daffl</a>\n<a href=\"https://github.com/daffl\" target=\"_blank\">github</a>\n</div>\n\n<div class=\"core-team-member\">\n<img class=\"member-avatar\" src=\"https://avatars2.githubusercontent.com/u/361671?v=3&s=300\"/>\n<h4>Мэттью Филлипс</h4>\n<p>\nМэттью, хранитель бороды, является ведущим разработчиком StealJS и связанных с ним инструментов.\n</p>\n<a href=\"https://twitter.com/matthewcp\" target=\"_blank\">@matthewcp</a>\n<a href=\"https://github.com/matthewp\" target=\"_blank\">github</a>\n</div>\n\n\n### Bitovi\n\nBitovi, консалтинговая JavaScript компания, является основным спонсором DoneJS. Если вы бы\nхотели спонсировать разработку, пожалуйста, [свяжитесь](mailto:contact@bitovi.com).\n\n",
"description": " \n<img src=\"http://blog.bitovi.com/wp-content/uploads/2015/10/donejs-logo-ie.png\"/>\n\nЦель DoneJS - помочь сообществу JavaScript получить удивительные приложения максимально быстро.\nЛучшие приложения быстры, просты в использовании, и легки в сопровождении.\n\nНо времена меняются, и появляются новые технологии. Мы стремимся принять эти технологии, улучшить стек, и обеспечить простую модернизацию.\n\nМы являемся частью сообщества, которое помогает разработчикам всех уровней и\nпомогаем узнать технологию, преуспеть в ней, и выполнить их цели.\n\nИзучите цели, историю, планы, и команду разработчиков DoneJS.\n\n",
"name": "About-ru",
"type": "page",
"parent": "DoneJS",
"hideSidebar": true,
"outline": {
"depth": 2,
"tag": "ol"
},
"comment": " "
},
"SettingUp-ru": {
"src": {
"path": "docs/ru/setting-up-ru.md"
},
"body": "\n## Windows\n\n### Предустановки\n\nЭто поможет вам установить DoneJS на Windows. Чтобы использовать DoneJS вам понадобится C++ компилятор (для нативных приложений). Для начала вам нужна последняя версия [Node.js](https://nodejs.org/en/). DoneJS официально поддерживает Node 0.10.x, 0.12.x, and IOjs, но другие версии должны также работать.\n\n#### Управление пакетами\n\nВ этом гайде мы будем использовать [chocolatey](https://chocolatey.org/) для установки нужных пакетов. Вы можете не использовать chocolatey, и установить все зависимости с помощью Windows установщиков, но мы будем использовать потому что это облегчает многие вещи.\n\nПосле установки chocolatey, следуя инструкциям [на главной странице](https://chocolatey.org/) **откройте административную консоль** и переходите к следующему шагу.\n\n#### Python 2.x\n\nНативные зависимости Node.js устанавливаются с помощью [node-gyp](https://github.com/nodejs/node-gyp) который использует Python. Он ожидает Python 2.x:\n\n```shell\nchoco install python2 -y\n```\n\n#### Windows SDK\n\nТеперь нам нужен Windows SDK. Мы будем использовать Windows 7, но вы можете изменить версию Windows которую вы используете:\n\n```shell\nchoco install windows-sdk-7.1 -y\n```\n\n#### Visual Studio Express\n\nУстановка Visual Studio Express даст нам C++ компилятор:\n\n```shell\nchoco install visualstudioexpress2013windowsdesktop -y\n```\n\n### Переменные среды\n\nЧтобы включить режим production вам нужно установить переменную среду `NODE_ENV`. В зависимости от той консоли которую вы используете, вы можете сделать это двумя способами:\n\n**Command Prompt**\n\n```\nset NODE_ENV=production\n```\n\n**Powershell**\n\n```\n$env:NODE_ENV=\"production\"\n```\n\n## macOS\n\n### Предустановки\n\nЧтобы DoneJS работал на macOS вам понадобится Xcode command line tools которую вы можете получить набрав:\n\n```shell\nxcode-select --install\n```\n\nЧтобы создавать iOS приложения, после установки Node, установите `ios-sim` пакет:\n\n```\nnpm install -g ios-sim\n```\n\n## Debian / Ubuntu\n\nУстановка на Debian / Ubuntu занимает немного больше времени потому что версия Node меньше, чем версия поддерживаемая DoneJS (как и все приложения основанные на Node).\n\n### Предустановки\n\nВместо установки Node.js из репозитория мы рекомендуем использовать PPA. Для начала установите `curl` если у вас он еще не установлен:\n\n```\nsudo apt-get install curl\n```\n\nДобавьте PPA в ваш source list:\n\n```\ncurl -sL https://deb.nodesource.com/setup_0.12 | sudo bash -\n```\n\nУстановка Node.js:\n\n```\nsudo apt-get install nodejs\n```\n\nВажно также установить `build-essential` пакеты. Это позволит вам использовать C++ для компиляции нативных приложений:\n\n```\nsudo apt-get install build-essential\n```\n\n",
"description": "На этой странице содержится информация о настройке DoneJS. Вы настроите все необходимые зависимости перед установкой DoneJS, эта информация не содержится в быстром старте или более подробном гайде. \nDoneJS официально поддерживает:\n\n - [Node](https://nodejs.org) 0.10.x, 0.12.x, and IOjs\n - [npm](https://www.npmjs.com/) 2.x\n\nМы сделаем поддержку [Node 4.0 and npm 3.0 version](https://github.com/donejs/donejs/issues/376) максимально скоро.\n\n",
"name": "SettingUp-ru",
"title": "Setting Up DoneJS",
"type": "page",
"parent": "Guides",
"hideSidebar": true,
"outline": {
"depth": 2,
"tag": "ol"
},
"comment": " "
}
}