From 6abcc845d9cd0a960ec07ea57b5fadcdaea2fc34 Mon Sep 17 00:00:00 2001 From: Sashko Stubailo Date: Mon, 5 Oct 2015 15:26:02 -0700 Subject: [PATCH 0001/1474] Initial commit --- README.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000000..4a02cff0fb --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# guide +How do I do X in Meteor? From 0b387ae084408149f5c0710bf1a7682729fe3ddf Mon Sep 17 00:00:00 2001 From: Sashko Stubailo Date: Mon, 5 Oct 2015 15:33:31 -0700 Subject: [PATCH 0002/1474] Initial content --- README.md | 73 ++++++++++++++++++++- outlines.md | 185 ++++++++++++++++++++++++++++++++++++++++++++++++++++ research.md | 96 +++++++++++++++++++++++++++ 3 files changed, 352 insertions(+), 2 deletions(-) create mode 100644 outlines.md create mode 100644 research.md diff --git a/README.md b/README.md index 4a02cff0fb..91a0ab59d3 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,71 @@ -# guide -How do I do X in Meteor? +# Meteor Guide + +We're getting started building a Meteor Guide. TL;DR, like the [Rails Guide](http://guides.rubyonrails.org/), but for Meteor. + +- Current status: Initial planning and community feedback. + +### Action items for community + +1. Read the charter below and the [outlines](outlines.md). +2. Ask questions on the [forum thread](#). +2. Submit pull requests on the outlines to add things that are missing. +3. File issues here for serious problems or discussion. + +## Meteor Guide “Charter” + +### **Vision** + +Let's get on the path to having a “Meteor Guide” – the most authoritative, honest, up-to-date, and reliable source of best practices for Meteor. This is not the docs page that describes the technology components of Meteor and their APIs. Instead, the idea is to eventually answer all questions of the form: “How do I do X in Meteor?” + +### **Values** + +1. Honesty - the content in the guide should be the same advice you would give a trusted friend. +2. Community - the guide should represent the aggregate experience of the Meteor community when it comes to the best way to build an app with Meteor, weighted by the vision of the platform as set by MDG. +3. Comprehensiveness - anything belongs in the guide as long as it's a reasonable thing for people to want to do with the platform. Running in Electron - yes; running on FreeBSD - no. +4. Content-focused - the guide should be in the format best optimized for general consumption, and it should be easy to access the information you want quickly and efficiently. Focus on content over technology. +5. Curation - every guide bakes in a certain set of opinions. There's no way to get around this, so MDG needs to be comfortable taking a clear and well-supported stand on certain issues. +6. Up-to-date - it should be easy to update so that we don't drag our feet on deploying new changes. +7. Realistic - the guide should address real-life use-cases and developer goals first, and avoid contrived examples. It's not about demonstrating how to use technology, it's about showing people how to get their work done. +8. Focus on the intermediate developer - the guide is not for beginners who are writing their first app, and it's not for the super hackers that can code their way out of anything. The guide is for normal developers trying to get the job done. + +### **Methods** + +1. Put the guide in a new repository so that it can be discussed and contributed to independently of the Meteor framework. +2. Set up a standard static site generator, Jekyll, that will be easy for people to understand and contribute to. +3. Set up a continuous deployment system using Jekyll-hook to automatically deploy changes from GitHub, so that we can't forget to deploy a new version. +4. Build in support for versioning docs via branches so that people can easily access documentation for previous Meteor releases. +5. Ensure great SEO so that people can find documentation items through Google or other search engines. +6. Don't put guide-appropriate information anywhere else, like the GitHub Wiki, READMEs, or similar, so that people don't have to guess where information might be hidden. +7. Make contributing to the guide the easiest way to contribute to the Meteor project, by adding “edit this page” buttons everywhere. +8. Be proactive in evaluating and accepting community contributions. +9. Be clear about why contributions are and are not accepted, and write these down in a living document about how to craft a great contribution to the guide. +10. Hire a technical writer to help efficiently produce great content and ensure everything is nice to read, consistent in style, and free of grammatical errors or stylistic issues. +11. Organize guide content by developer goals rather than API methods. It's possible that some sections will lack Meteor API information entirely, if the Meteor API doesn't help with any of those goals. API documentation is a separate app we'll need to built some other time. +12. Put community packages and MDG packages on a more even footing by sometimes endorsing the community solution over the MDG one when it's better. +13. Figure out a way to user test the guide to see if it helps developers achieve their goals. +14. Loop in every framework developer to get input on the parts of the framework with which they are most familiar. +15. Add a section to each article that has related links that people can submit - for example links to packages that people have written to help with a certain task, or how-to articles on someone's blog. Heading could be “other articles on the web”. + +### **Obstacles** + +1. Historical reluctance to endorse community packages +2. Changes to the Meteor API can make large parts of the guide outdated quickly +3. Large amount of existing source material in random locations - GitHub Wiki, etc +4. Maintaining high quality and cohesion in the face of numerous authors and contributions +5. Getting engineers to write docs/guides as part of our process and culture +6. Lack of clear guidance from the framework on many topics, such as testing and app architecture + +### **Goals** + +1. Develop a skeleton for a guide app in Jekyll, with nice styles and a clear path to adding more content [firm] +2. Have continuous deployment set up for at least two branches of the new guide repository [firm] +3. Migrate all existing content onto the guide website from docs.meteor.com, GitHub Wiki, and READMEs (I'm looking at you, Spacebars) [firm] +4. Hire one technical writer +5. Have an “edit on GitHub” button on every single page +6. Review every guide contribution within one week of submission and give a conclusive response +7. Accept 50 community pull requests +8. Write and publish three of the sections outlined in [Meteor guide outlines](outlines.md) + +### Some more planning information + +For some prior art research, see [the sketchy research doc](research.md). diff --git a/outlines.md b/outlines.md new file mode 100644 index 0000000000..c905062c80 --- /dev/null +++ b/outlines.md @@ -0,0 +1,185 @@ +# Meteor guide outlines + +This is an attempt to write a comprehensive outline of all of the guides one would need to read to build a professional-quality application with Meteor. Each guide has a title, a tagline that explains why this concept is important in Meteor, and 5-10 sections which are named in the format: “After reading this guide, you'll know...” + +### Meteor guide: Application structure + +Since everything is JavaScript and code can be shared between all parts of your app, Meteor presents new opportunities for code organization. But with great power comes great responsibility. + +1. What are the different parts of a Meteor app +2. How to build your app around features instead of stack layers +3. How to split your code into the right number of files and how to organize those files in directories, in a way that will scale as your project grows +4. Best practices for making your app modular so that you can work on one part of the codebase without fear that some other part will break unexpectedly +5. How to split your app into smaller apps that each have a smaller surface area while sharing code and data +6. The Meteor style guide + +### Meteor guide: Collections and models + +We'll explain how to deal with collections across client and server. Then we'll reduce code repetition by extending database documents with model classes. + +1. How to define and use MongoDB collections in Meteor +2. The distinctions between collections on the client and collections on the server +3. How to define a model with schemas and validations for a collection +4. How to add setters and getters to your model to centralize your database logic +5. How to design a schema that works well with Meteor's data system and can be extended over time +6. How to migrate data when you want to change the structure or schema of your collections +7. How to model relational data, even when your database is not relational + +### Meteor guide: Data loading and management + +Meteor lets you write your UI as if the database is present on the client while maintaining security and the ability to have a decoupled data model. Sound like a contradiction? We'll explain how to use all of the tools together to get the best balance of fast development and maintainability. + +1. How to load and use data from the database over DDP +2. How to load just enough data to display your UI while using caching to make sure the UI is as fast as possible +3. When to use local component state and when to have a global store +4. How to build your own client-side reactive data stores with ReactiveVar, ReactiveDict, and Tracker +5. Modifying data stores using Methods +6. How to use data from external APIs on the client and server + 1. HTTP + 2. DDP + 3. Webhooks +7. How to publish and use relational data +8. How to do pagination or infinite scroll so that you can load data incrementally as the user needs it + +### Meteor guide: UI/UX + +Meteor supports many different UI frameworks in addition to having its own default framework, Blaze. While all of these frameworks have their own documentation, there's a lot to learn about building a UI for a large app that is UI-framework-agnostic. + +1. When to build reusable components and when not to +2. Optimizing event handling for realtime input by throttling effectively +3. Good patterns for revealing new data without startling the user +4. Using animations effectively for a great user experience +5. Designing a responsive application that works across different devices +6. Make your app appeal to a wider user base with internationalization +7. How to make your app more accessible to people with disabilities + +### Meteor guide: Accounts + +Meteor's login system works pretty well out of the box, but there are a few tips and tricks to set things up just the way you want them. + +1. Picking an accounts UI package +2. Setting up password reset, email verification, and enrollment emails +3. Setting up OAuth login services +4. Adding custom fields to the users collection and using them + +### Meteor guide: Security + +Meteor apps can be very easy to secure if you follow a few simple principles, and there are some packages that streamline the process for you. + +1. The security surface area of a Meteor app + 1. Methods + 2. Publications + 3. Served files +2. How to set up roles and permissions for user accounts +3. How and why to use SSL +4. How to manage sensitive API keys and configuration +5. Common mistakes and misconceptions + +### Meteor guide: Forms, user input, and methods + +How to build your C~~R~~UD with a stellar user experience, with no extra effort. + +1. How to define a method with optimistic UI and validation +2. How to wire up a button or single UI control to a method +3. How to wire up a form to a method +4. Error handling +5. Realtime validation +6. Optimistic UI and when to use it +7. Saving intermediate inputs in case the user closes the tab accidentally +8. How to use a method to write data to external APIs +9. How to enable users to upload files + +### Meteor guide: Routing + +What do URLs mean in a mobile and client-rendering world, and how does one use them properly? + +1. What role URLs play in a client-rendered app, and how it's different from a traditional server-rendered app +2. How to define client and server routes for your app using Flow Router +3. How to have your app display different content depending on the URL +4. How to construct links to routes and go to routes programmatically +5. How to handle URLs in your app that should only be accessible to certain users +6. How and why to use a UI framework native router, like Angular router or React Router + +### Meteor guide: Testing + +Write some extra code now to make sure you don't break your code when you add more code later. Add features and refactor your app with no fear. + +1. How to test: + 1. Methods + 2. Publications + 3. Models + 4. Routes + 5. UI components +2. How to structure your code with modules so that it can be tested more easily +3. How to stub parts of the Meteor framework so that you can test a small part of your app at a time +4. How to mock data in a realistic way +5. How to set up continuous integration so that you can't forget to run the tests + +### Meteor guide: Mobile + +Build a really good mobile experience with just a little bit of extra effort. + +1. How to set up your development environment for Android and iOS +2. How to enable mobile debugging, logging, testing +3. How to optimize your user experience on mobile to make your app feel smooth and usable +4. How to use native mobile features through Cordova plugins +5. How to add push notifications, intents, and other mobile operating system integrations +6. How to use hot code push effectively to update your app outside of the normal app store review process while maintaining a great user experience + +### Meteor guide: The build tool + +Meteor brings sane, zero-configuration defaults to the previously tedious tasks of compiling, concatenating, minifying, and transforming assets. + +1. How to use popular transpiled languages in Meteor out of the box: + 1. ES2015+ + 2. LESS + 3. SASS + 4. Coffee + 5. TypeScript +2. How to use packages from other packaging systems: + 1. Compatibility directory and 'bare' files + 2. Bower + 3. NPM + +### Blaze guide: The Tracker-based reactive templating system + +Write “HTML with holes” just like you're used to, and get a fast, fine-grained, reactively updating page with no sweat. + +1. Spacebars syntax, and how to use the built-in helpers +2. Building reusable components with Blaze by avoiding global data +3. How to use reactivity in a principled way +4. Writing maintainable helpers and event handlers that aren't tightly coupled to HTML +5. Reusing logic and HTML snippets between templates + + + +## Advanced + +### Meteor production guide: Deployment, monitoring, and analytics + +Now that you've built a sweet app, give it to the world. It can be hard to run a production app, that's where Galaxy comes in. + +1. Integrating with popular analytics platforms to track method calls, publications, and URL hits +2. Profiling and monitoring your app to find out where it is slow +3. Escape hatches for performance issues +4. Staging and testing +5. Rolling updates with hot code push +6. Galaxy + +### Meteor guide: Building a great package + +The Meteor package ecosystem is a unique place where many of the packages are designed to work together around a standard, well-defined stack. Learn how you can easily and effectively contribute! + +1. Creating a simple package and publishing it +2. How to deliver different code for different platforms and architectures +3. How to integrate an existing Cordova plugin or write your own +4. How to use monkey-patching to add new features to existing APIs +5. Biting off what you can chew - what's the perfect size for a package? +6. How to test your package and set up CI +7. How to document your package +8. How to publicize your package and become famous in the Meteor community +9. How to deal with pull requests and issues +10. How to pick a license for your package +11. How make a build plugin + 1. Compiling single files into other single files + 2. Compiling many files at once that can be inter-related diff --git a/research.md b/research.md new file mode 100644 index 0000000000..0ce6301047 --- /dev/null +++ b/research.md @@ -0,0 +1,96 @@ +# Meteor Guide Plan + +This is focusing on the guide chrome and structure, not text style or content. Also it does a good deal of assuming that popular means it's pretty good. Either way, we should probably catch up to the state of the art before we try to surpass it. + +## Examples + +* React: https://facebook.github.io/react/docs/getting-started.html +* Rails: http://guides.rubyonrails.org/ +* Django: https://docs.djangoproject.com/en/1.8/ +* Ember.js: http://guides.emberjs.com/v2.0.0/templates/conditionals/ +* Angular's website is *terrible*. +* Firebase has a great design/navigation structure. I think the three-level nav is pretty great: https://www.firebase.com/docs/android/guide/understanding-data.html +* Stripe: https://stripe.com/docs + +## Observations + +1. Split into pages - the fact that you can't infinitely scroll makes the information seem more digestible +2. Search isn't necessary - React and Rails don't have it. Presumably SEO is much more important. +3. There are introductory landing pages + 1. Some summarize the different parts of the framework + 2. React has a super quick getting started guide +4. Tables of contents are by theme/activity/section, not sorted by API methods. Although there is also a place to get an API reference, it's de-emphasized + 1. “Forms” + 2. “Layouts and Rendering in Rails” + 3. “Introduction to Migrations” +5. React has an “edit on GitHub” button +6. React's docs are built with Jekyll: https://github.com/facebook/react/blob/master/docs/README.md + 1. I feel like if React's docs aren't built with React, we can stomach not building our docs in Meteor + 2. Hosted on GitHub pages +7. Django and Rails have ways to get at docs for different versions, React doesn't +8. Don't really differentiate tutorials and guide articles + +## Properties we want + +1. Make this guide the most authoritative, honest, and reliable source of best practices for Meteor. This should be exactly the same as what you would tell a trusted friend or paying customer to do in their app. +2. Super easy to add content - there should never be a good reason to *not* put something in the guides/docs. There should be an infinite black hole of content, such that adding more content doesn't detract from what we already have. +3. Has all of the content - We should be able to replace basically all of our READMEs, wiki pages, external docs sites, tutorials, etc. with one website that has all of the MDG-produced educational content that's out there. Blog posts and similar are fine for temporary content. +4. Great SEO - Everyone just searches on Google to figure out how to do stuff. They should land on our docs if that is the best resource. +5. Versioning - There are lots of benefits to having versioned docs, in particular that we don't have to keep backcompat with the old URLs etc. This can be as simple as deploying a new site for each release of Meteor. +6. Encourage contributions - if someone got stuck on something, they should be able to suggest changes to the docs and we need a mechanism for accepting them. Also, contributing to the docs is the easiest path to starting out as an open source contributor. +7. Don't be afraid of endorsing community packages that are part of the current best practice. +8. Don't be afraid of writing down sketchy workarounds because they are embarrassing. +9. Actually user test the guide on people we consider to be in our target audience. We could partner with an existing education provider to teach a class with it. + +## Things we can compromise on + +1. Backwards compatibility with [docs.meteor.com](http://docs.meteor.com/) - This constraint has stopped us from innovating on the docs before. We shouldn't have to keep backcompat with all of the URLs, etc. If we figure out a way to properly version the docs such that all of the URLs are also versioned, we can avoid this problem in the future. +2. Built-in search. SEO is more important, and we should have good organization so that people can use the nav to find stuff. +3. Using Meteor. We should take the shortest path to a great experience, and we know that Meteor isn't optimized for sites with huge amounts of static content. +4. Fancy features. Most guides are just plain text, organized in pages with a table of contents. If Rails can get by with that, we can too. Let's focus on writing great content over creating a fancy UX, at least to start with. + +## Questions + +1. Is it better to have the docs/guides in the same repository as the code? + 1. Benefits + 1. Can be versioned together + 2. A single pull request can contain docs and code for a feature + 2. Drawbacks + 1. Only works if the entire framework is in one repo - won't scale if we have separate repos anyway + 2. Harder for people to maintain translations + 3. Harder to discover where the docs live - a lot of people don't even know they are in meteor/meteor/docs + 3. Current decision + 1. Looks like separate repo is winning! + +## Technology options + +1. GitHub pages + 1. Benefits + 1. Built-in continuous integration + 2. Guaranteed to load super fast and not have server-side dynamics + 3. Fairly standard for a wide variety of GitHub documentation + 4. Built for large websites with lots of markdown content + 5. Hosted by GitHub for free + 6. Restricted features mean it's easier for people to contribute + 2. Drawbacks + 1. Not JavaScript + 2. No easy way to look at versions, you only get one github pages site per repo/organization +2. Custom site + 1. Benefits + 1. We can build appropriate abstractions + 2. JavaScript + 3. Could build versioning mechanism + 2. Disadvantages + 1. Custom stack could make it harder for people to contribute (although this could be mitigated by separating the complex code from the markdown content) +3. Custom Jekyll setup + 1. Do continuous integration ourselves, with branches for different versions +4. ReadTheDocs + 1. Not an option - the existing templates are terrible +5. Readme.io + 1. Not an option - docs live online and not in the repo + +## Action items + +1. Sashko will figure out where we can host a continuously deployed basic Jekyll site, where we can have different versions built from different branches. + 1. Deliverable: proof of concept simple site deployed from two branches + 2. Stretch: deploy examples from pull requests From 490ddbaf2957384e033a202d74d94d4c3d6fab06 Mon Sep 17 00:00:00 2001 From: Sashko Stubailo Date: Mon, 5 Oct 2015 15:35:01 -0700 Subject: [PATCH 0003/1474] Add action items --- README.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 91a0ab59d3..289c3668fe 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,16 @@ We're getting started building a Meteor Guide. TL;DR, like the [Rails Guide](htt ### Action items for community -1. Read the charter below and the [outlines](outlines.md). -2. Ask questions on the [forum thread](#). -2. Submit pull requests on the outlines to add things that are missing. -3. File issues here for serious problems or discussion. +1. Read the charter below and the [outlines](outlines.md) +2. Ask questions on the [forum thread](#) +2. Submit pull requests on the outlines to add things that are missing +3. File issues here for serious problems or discussion + +### Action items for MDG + +1. Consider and respond to all community feedback +2. Set up GitHub pages site with basic theme and structure +2. Set up hooks to deploy PRs and branches ## Meteor Guide “Charter” From 8e18602c58c2995c5bf5696025f9d276ac202ff6 Mon Sep 17 00:00:00 2001 From: Sashko Stubailo Date: Mon, 5 Oct 2015 15:35:51 -0700 Subject: [PATCH 0004/1474] Wording --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 289c3668fe..d9206f3cc8 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # Meteor Guide -We're getting started building a Meteor Guide. TL;DR, like the [Rails Guide](http://guides.rubyonrails.org/), but for Meteor. +We're getting started building a Meteor Guide. Like the [Rails Guide](http://guides.rubyonrails.org/), but for Meteor. - Current status: Initial planning and community feedback. ### Action items for community -1. Read the charter below and the [outlines](outlines.md) +1. Read the charter below and the [proposed outlines for guide articles](outlines.md) 2. Ask questions on the [forum thread](#) 2. Submit pull requests on the outlines to add things that are missing 3. File issues here for serious problems or discussion From 95d68540ab63ca623a18271a59d6cf72f2a06a3b Mon Sep 17 00:00:00 2001 From: Sashko Stubailo Date: Mon, 5 Oct 2015 15:36:55 -0700 Subject: [PATCH 0005/1474] Emphasize community --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index d9206f3cc8..597d7608b2 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ We're getting started building a Meteor Guide. Like the [Rails Guide](http://guides.rubyonrails.org/), but for Meteor. +We're going to do this totally out in the open, and we can't do it without the community. + - Current status: Initial planning and community feedback. ### Action items for community From ba8cba2e6816d9d7ec2733a095df497cb2191f10 Mon Sep 17 00:00:00 2001 From: Sashko Stubailo Date: Mon, 5 Oct 2015 15:37:22 -0700 Subject: [PATCH 0006/1474] Formatting --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 597d7608b2..f0ca01d807 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ # Meteor Guide -We're getting started building a Meteor Guide. Like the [Rails Guide](http://guides.rubyonrails.org/), but for Meteor. - -We're going to do this totally out in the open, and we can't do it without the community. +We're getting started building a Meteor Guide. Like the [Rails Guide](http://guides.rubyonrails.org/), but for Meteor. We're going to do this totally out in the open, and we can't do it without the community. - Current status: Initial planning and community feedback. From 81f30dbdfc373c2385d761a9b56dfd5ed6a77277 Mon Sep 17 00:00:00 2001 From: Sashko Stubailo Date: Mon, 5 Oct 2015 15:42:23 -0700 Subject: [PATCH 0007/1474] Add link to forum thread --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f0ca01d807..7b624adb1e 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ We're getting started building a Meteor Guide. Like the [Rails Guide](http://gui ### Action items for community 1. Read the charter below and the [proposed outlines for guide articles](outlines.md) -2. Ask questions on the [forum thread](#) +2. Ask questions on the [forum thread](https://forums.meteor.com/t/new-mdg-project-the-meteor-guide/10873) 2. Submit pull requests on the outlines to add things that are missing 3. File issues here for serious problems or discussion From 331c8106f18bfa5303386029b9a91a7c29b13317 Mon Sep 17 00:00:00 2001 From: Sashko Stubailo Date: Mon, 5 Oct 2015 15:42:54 -0700 Subject: [PATCH 0008/1474] Soften --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7b624adb1e..ebc05c3ce6 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ We're getting started building a Meteor Guide. Like the [Rails Guide](http://gui 1. Read the charter below and the [proposed outlines for guide articles](outlines.md) 2. Ask questions on the [forum thread](https://forums.meteor.com/t/new-mdg-project-the-meteor-guide/10873) 2. Submit pull requests on the outlines to add things that are missing -3. File issues here for serious problems or discussion +3. File issues here for discussion ### Action items for MDG From 1e1cdfe6e33f143b0cd03a7556a9ccb4bfddc1d0 Mon Sep 17 00:00:00 2001 From: Sashko Stubailo Date: Mon, 5 Oct 2015 18:25:49 -0700 Subject: [PATCH 0009/1474] Update research.md --- research.md | 1 - 1 file changed, 1 deletion(-) diff --git a/research.md b/research.md index 0ce6301047..8bfd87a1bb 100644 --- a/research.md +++ b/research.md @@ -8,7 +8,6 @@ This is focusing on the guide chrome and structure, not text style or content. A * Rails: http://guides.rubyonrails.org/ * Django: https://docs.djangoproject.com/en/1.8/ * Ember.js: http://guides.emberjs.com/v2.0.0/templates/conditionals/ -* Angular's website is *terrible*. * Firebase has a great design/navigation structure. I think the three-level nav is pretty great: https://www.firebase.com/docs/android/guide/understanding-data.html * Stripe: https://stripe.com/docs From 4014239d5e8b259c0594826787a69cd043dfcf30 Mon Sep 17 00:00:00 2001 From: Sashko Stubailo Date: Mon, 5 Oct 2015 18:43:02 -0700 Subject: [PATCH 0010/1474] Add index.html --- index.html | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 index.html diff --git a/index.html b/index.html new file mode 100644 index 0000000000..2489be59ff --- /dev/null +++ b/index.html @@ -0,0 +1,3 @@ +

Meteor Guide

+ +

Hello world!

From f7725a88fc827537ba7e361e72862fe4f9f8118e Mon Sep 17 00:00:00 2001 From: Sashko Stubailo Date: Wed, 7 Oct 2015 11:55:12 -0700 Subject: [PATCH 0011/1474] Add initial routing sketch --- articles/routing.md | 442 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 442 insertions(+) create mode 100644 articles/routing.md diff --git a/articles/routing.md b/articles/routing.md new file mode 100644 index 0000000000..c202d14f45 --- /dev/null +++ b/articles/routing.md @@ -0,0 +1,442 @@ +# Meteor Guide: Routing + +After reading this guide, you'll know: + +1. What role URLs play in a client-rendered app, and how it's different from a traditional server-rendered app +2. How to define client and server routes for your app using Flow Router +3. How to have your app display different content depending on the URL +4. How to construct links to routes and go to routes programmatically +5. How to handle URLs in your app that should only be accessible to certain users + +This guide will refer to code samples from the Todos example app, which has been carefully constructed to demonstrate all of these concepts. + +## 1. Routing and the role it plays in a client-rendered app + +In a web application, _Routing_ is the process of using URLs to drive the user interface (UI). URLs are a prominent feature in every single web browser, and have several main functions from the user's point of view: + +1. **Bookmarking **- Users can bookmark URLs in their web browser to save content they want to come back to later +2. **Sharing** - Users can share content with others by sending a link to a certain page +3. **Navigation** - URLs are used to drive the web browser's back/forward functions + + In a traditional web application stack, where the server renders HTML one page at a time, the URL is the fundamental entry point for the user to access the application. Users navigate an application by clicking through URLs, which are sent to the server via HTTP, and the server responds appropriately via a server-side router. + +In contrast, Meteor operates on the principle of _data on the wire_, where the server doesn’t think in terms of URLs or HTML pages. The client application communicates with the server over DDP. Typically as an application loads, it boots up with a series of _subscriptions_ which fetch the data required to render the application. As the user interacts with the application, different subscriptions may load, but there’s no technical need for URLs to be involved in this process. + +However, most of the user-facing features of URLs listed above are still relevant for typical Meteor applications. Now that the server is not URL-driven, the URL just becomes a useful *serialization* of the client-side state the user is currently looking at. However, unlike a server-rendered application, it does not need to serialize the entirety of the user’s current state, simply the parts that you want to be linkable. For example, the URL should contain any search filters applied on a page, but not necessarily the state of a dropdown menu or popup. + +## 2. Installing Flow Router 2 + +To add routing to your app, install the `kadira:flow-router` package: + +``` +meteor add kadira:flow-router +``` + +*Snippet 2.1: Adding the Flow Router package* + +At the time of writing this guide, Flow Router is at version 2.x. + +*Community packages: Flow Router is one of several popular routing packages for Meteor. Another is iron:router. You can search for router on Atmosphere to find more. Hopefully, the concepts in this routing guide will be relevant no matter which router you use, as long as it provides basic functions for URL management.* + +## 3. Defining a simple route + +The basic purpose of a router is to match certain URLs and perform actions as a result. This all happens on the client side, in the app user's browser. + +``` +FlowRouter.route('/blog/:postId', { + name: "blog-post", + action(urlParams, queryParams) { + console.log("Got the postId from the URL:", urlParams.postId); + console.log("Query parameters:", queryParams); + } +}); +``` + +*Snippet 3.1: Defining a basic route with Flow Router* + +This route handler will run in two situations: if the page loads initially at a URL that matches the URL pattern, and if the URL changes to one that matches the pattern while the page is open. Note that, unlike in a server-side-rendered app, the URL can change without any additional requests to the server. + +When the route is matched, the `action` method executes, and you can perform any actions you need to. + +The `name` property of the route is optional, but will let us refer to this route more conveniently later on. + +### 3.1 URL pattern matching + +The above code snippet will match certain URLs. You may notice that one of the segments is prefixed by `:` - this means that it is a *url parameter*, and will match any string that is present in that segment of the path. Here are some example URLs and the resulting `urlParams` and `queryParams`: + +URL action() called? urlParams queryParams +/ no +/about no +/blog/ no +/blog/eMtGij5AFESbTKfkT yes { postId: "eMtGij5AFESbTKfkT"} { } +/blog/1 yes { postId: "1"} { } +/blog/1?commentSort=top yes { postId: "1"} { commentSort: "top" } + +*Table 3.1: Example URLs and the resulting parameters* + +Note that all of the values in `urlParams` and `queryParams` are always strings since URLs don't have any way of encoding a data type, so you might need to use `parseInt(value, 10)` to convert them into numbers. + +## 4. Displaying different views based on the URL and defining layouts + +*This section is UI-framework specific, and is written assuming you are using Blaze as your UI engine. If you are building your app with React or Angular, you will end up with similar concepts but the code will not be exactly the same.* + +Now we know how to define a function that is called when we reach a particular URL. But URLs are most often used not to call plain functions, but to display some UI. This is why navigating to a URL is often referred to as “going to a page” - you expect the app to display certain content as if it were a page in a book or magazine. + +When using Flow Router, the simplest way to display different views on the page for different URLs is to use Blaze Layout. First, make sure you have the Blaze Layout package installed: + +``` +meteor add kadira:blaze-layout +``` + +*Snippet 4.1: Add the Blaze Layout package* + +To use this package, we need to define a layout template in our HTML: + +``` + + + +``` + +*Snippet 4.2: Defining a layout to use with Blaze Layout* + +Here, we are using a Blaze feature called `Template.dynamic` to render a template whose name is passed in from outside. We have defined two *regions* in our layout: `sidebar` and `page`. We have also included a `layout-navbar` template at the top, which will put a navbar at the top of every page. Let's define some of the templates that will display our actual content: + +``` + + + + + +``` + +*Snippet 4.3: Defining some templates that display content* + +These are some templates that we will render into the layout from our route action. Notice that these templates don't have any dynamic data. Right now, we are focusing on the layout aspect and we will get to filling in data in a later section. + +Now, let's define two routes that actually use our templates and layout to display some content! + +``` +FlowRouter.route('/blog/:postId', { + name: "blog-post", + action(urlParams, queryParams) { + BlazeLayout.render('layout-main', { + sidebar: "sidebar-recent-posts", + content: "page-blog-post" + }); + } +}); + +FlowRouter.route('/about', { + name: "about", + action(urlParams, queryParams) { + BlazeLayout.render('layout-main', { + sidebar: "sidebar-recent-posts", + content: "page-about" + }); + } +}); +``` + +*Snippet 4.4: Using our content templates and our layout inside the route action to display content* + +Now, if the user navigates to the different URLs, they will see the blog post template or the about page template. You can define as many templates or layouts as you want, and mix and match them inside your route handlers. + +### 4.1 Templates as PAges vs. Templates as reusable UI components + +In the code samples, we have decided to name the templates after the layout regions they will be rendered into. This is not necessary, but enables us to make it clear that those templates are expecting to be used in a certain place in the layout. It's explicitly stating that these templates are not meant to be reusable in different parts of the app - they are only useful for rendering a “page” of the app. + +If you have lots of pages that are similar, it would make sense to split up your app into a collection of reusable components, and a collection of single-purpose pages that mostly just mix-and-match the reusable components. Read more about this distinction in the section on _UI components_. + +## 5. Displaying and subscribing to data based on the URL + +In the previous section, we looked at how to display different templates based on the URL pattern. However, if we have a `page-blog-post` template that can display different posts, we need to be able to tell it which post to display. We already have the ability to get `urlParams.postId` inside the body of the `action` function on the `blog-post` route, but how do we give it to the template? + +### 5.1 Accessing URL Parameters in JAvaScript and Template Helpers + +Flow Router has some helpful functions that can be used to access data about the current URL from anywhere. Here are some of the most useful ones: + +* `FlowRouter.getRouteName()` gets the name of the route +* `FlowRouter.getParam(paramName)` returns the value of a single URL parameter +* `FlowRouter.getQueryParam(paramName)` returns the value of a single URL query parameter + +So let's say we wanted to display a blog post in our `content-blog-post` template based on the current URL. We could define a helper like this: + +``` +Template["page-blog-post"].helpers({ + blogPost() { + return BlogPosts.findOne(FlowRouter.getParam("postId")); + } +}); +``` + +*Snippet 5.1.1: Defining a helper to pass a blog post object to the blog post page template using a URL parameter* + +Now, we can use this helper in our HTML to display the post content: + +``` + +``` + +*Snippet 5.1.2: Using the new helper from snippet 5.1.1 to display a blog post's title and content* + +As mentioned in section 4.1, the `page-blog-post` template is coupled to a certain route and a certain layout. If you want to render blog posts in many different ways, it could be prudent to factor out the blog post display and formatting logic into a reusable component, in which case the template for the page would become simpler: + +``` + +``` + +*Snippet 5.1.3: A version of 5.1.2 that uses a reusable blog post component to do formatting, and only displays the parts that are page-specific itself* + +In this case, the function of the `page-blog-post` component is just to get the correct data using the URL parameter, and to display page-specific UI such as sharing buttons. The important part of rendering the blog post content itself is delegated to a reusable component that can be included on many different pages, independently of the URL logic and post data retrieval. + +**Reusable component tip:** be very careful about accessing URL parameters in any component you want to be reusable across different pages. + +### 5.2 Subscribing to data and displaying a loading indicator + +If you are experienced in Meteor, you know that in order for `BlogPosts.findOne(...)` in snippet 5.1.1 to return anything useful, you need to subscribe to that data from the server using `Meteor.subscribe`. The `page-blog-post` template would be a great place to do that: + +``` +Template["page-blog-post"].onCreated(function () { + this.autorun(() => { + this.subscribe("blog-post", FlowRouter.getParam("postId")); + }); +}); +``` + +*Snippet 5.2.1: Subscribing to data from the onCreated callback of a page template* + +Now, when we go to the blog post page in our app, when the `page-blog-post` template is initialized, we will subscribe to the data for this blog post, and the `blogPost` helper will return the post data once it arrives. But this won't happen instantly - it takes time for the data to arrive from the server to the client before it can be displayed. For this reason, Blaze has a helpful built-in helper: `Template.subscriptionsReady`. It works because we used `this.subscribe` instead of `Meteor.subscribe` when loading the data. Let's display a simple loading message: + +``` + +``` + +*Snippet 5.2.2: Displaying a loading indicator while data is loading from the server* + +Note that we don't need to block out the entire page while the data is loading! We can just block a small part of the page with a loading indicator. + +### 5.3 HIglighting the active route in the navigation + +One more place you might want to access the data from the URL is in your navigation component, to highlight the one that is currently active. A convenient package for this is `zimme:active-route`: + +``` +meteor add zimme:active-route +``` + +Now, let's create a navbar template that highlights the appropriate item based on the active route: + +``` + +``` + +Now, the link that corresponds to the active route (based on the `name` of the route) will get the `active` class, and you can style it differently using CSS. Read more about the different features of `zimme:active-route` in [its README](https://github.com/zimme/meteor-active-route). + +## 6. Redirecting + +Sometimes, your users will end up on a page that isn't the best place for them to be. Maybe the data they were looking for has moved, maybe they were on an admin panel page and logged out, or maybe they just created a new object and you want them to end up on the page for the thing they just created. + +You can go to a new URL programmatically by calling `FlowRouter.go(name, urlParams, queryParams)`. See the [FlowRouter docs](https://github.com/kadirahq/flow-router#flowroutergopathdef-params-queryparams) for more methods that accomplish similar things, like `FlowRouter.setParams` and `FlowRouter.setQueryParams`. + +You can also redirect to a different route from a route trigger. We'll discuss them in more detail in the _triggers section_, but here we'll include some example code specifically for redirection. + + +### 6.1 Redirecting for convenience + +Sometimes, you want to have a route that always redirects somewhere else. Maybe this is so that the user can type less, or bookmark a certain URL, or similar. For example, you may want a URL that always redirects to the most recent blog post published. In Flow Router, you do this using a trigger, which will be covered in more detail later in the guide: + +``` +// XXX how do you do this? +``` + +### 6.2 Redirecting when an asynchronous operation succeeds + +Often, you just want to go to a new route programmatically when a user has completed a certain action. In this case, we'll take the example of deleting a blog post. If you have deleted a blog post from its page, you probably want to leave the page you were on, since that resource no longer exists. Here's how you could do that: + +``` +Meteor.call("/blog-posts/delete", (err) => { + if (err) { + // Display error message + } else { + FlowRouter.go("home"); + } +}); +``` + +You will also want to show some kind of status while the method is working so that the user knows there is something going on between them clicking the button and the redirect happening. It's important that we only redirect if the method call on the server succeeds, because otherwise the redirect will make it look like the item was deleted when it actually wasn't. + +### 6.3 Redirecting when some data has been moved + +If some data in your app has been moved, you probably want to redirect people to the new object. For example, if we renamed a document and the name was part of the URL, we would want the user to end up at the new URL so that usage of the old one decreases gradually. Eventually, once our _analytics_ indicate that nobody is visiting the old URL anymore, we can remove the backwards compatibility code. + +``` +// XXX how do you do this? +``` + +### 6.4 Redirecting when a route has been changed + +As you maintain and develop new features for your app, you might discover that you need to change your URL structure. If there are already lots of links and bookmarks to your app floating around in the wild, it might be a good idea to redirect the old URLs for backwards compatibility. + +``` +// XXX write this +``` + +## 7. User permissions and URLs + +In a traditional server-side rendered app, it's common to restrict which URLs users are allowed to visit based on their ownership of certain data, or the role they have in the system (admin, moderator, etc). In Meteor, the router is not the correct place to manage permissions. Permissions about which users can read and write data belong in Meteor publications and methods, which deal with actually reading and writing data from the server. However, it's still useful to show people nice messages reminding them to log in to see certain content or reminding them that they don't have the right permissions. + +### 7.1 Displaying a reminder to Log in to see a certain page + +This is best done inside the page template itself. For example, imagine we had a page in our app to edit a blog post, and the template for that was called `page-blog-post-edit`. Here is what the template's HTML would look like if we wanted to remind people to log in to edit the blog post: + +``` + +``` + +However, in a multi-user system, this might not be good enough because only certain users are allowed to edit posts. + +### 7.2 Indicating that a logged in user doesn't have permission to be on a certain page + +There are several options for what the UI should do if a user is logged in but doesn't have permissions for a certain action. First of all, the app developer should minimize the opportunities for the user to end up on that page in the first place, as a courtesy. For example, don't display a button to edit the blog post if the user doesn't have permissions. But if the user has ended up on the page anyway, possibly by remembering the URL or similar, you should display a message on the page telling the user that they won't be able to accomplish their intended action. + +In the below code snippet, we use a helper `userCanEditPost` to check if the user is the owner of the blog post and display a helpful message. This can be a good option if the user's permissions are likely to change - for example, you could arrive at this page, note that you don't have permissions, ask the author to give you the permissions, and then the page will update to show the editor once the permissions are added. This workflow wouldn't be possible if you had instead redirected the user to a different URL entirely. + + +``` + +``` + +### 7.3 Redirecting a user away from a page they shouldn't be on + +XXX given that the user's data might not have loaded yet, this might actually be super hard! + +## 8. Displaying links to routes using helpers + +Once you have some routes defined in your app, you will probably want to add some links to your page to go to the different URLs. You can generate the URLs yourself using `FlowRouter.pathFor`, but it is more convenient to use a package that defines some helpers for you: + +``` +meteor add arillo:flow-router-helpers +``` + +Now that you have this package, you can use helpers in your templates to display a link to a certain route. For example, to link to a blog post: + +``` +Link to a post +``` + +Or to link to the `about` page which doesn't have any parameters: + +``` +Link to a post +``` + +## Analytics + +It's common to want to know which pages of your app are most commonly visited, and where users are coming from. Read more about analytics in general in the _Analytics/Monitoring guide_, but here's a simple setup that will get you URL tracking using Google Analytics. We'll be using the `okgrow:analytics` package. + +``` +meteor add okgrow:analytics +``` + +Now, we need to configure the package with our Google Analytics key (the package also supports a large variety of other providers, check out the documentation [on Atmosphere](https://atmospherejs.com/okgrow/analytics)). Pass it in as part of _Meteor settings_: + +``` +{ + "public": { + "analyticsSettings": { + // Add your analytics tracking id's here + "Google Analytics" : {"trackingId": "Your tracking ID"} + } + } +} +``` + +We're done! The analytics package hooks into Flow Router and records all of the page events for you. + +## Advanced features of Flow Router + +1. Nested routes + + +Root route + +When to use query parameters + +Analytics + +Displaying not found/404 page + + +## Notes/ideas from sashko + +1. Don't use redirects to display a login page; just display the login page instead of the content, and keep the URL the same. In server-side rendered apps the only way to show a login page is to redirect but that restriction doesn't exist on the client. +2. Similarly, don't encode temporary data in the URL, like `/stuff?alert="thanks for logging in"` because you can just use a variable in JS. If you want something to persist across tabs and actual page reloads, it should be in Mongo or localstorage. From a25da284fa54b9a4bd96dd5ad4cd62af2bd83225 Mon Sep 17 00:00:00 2001 From: Sashko Stubailo Date: Wed, 7 Oct 2015 11:59:18 -0700 Subject: [PATCH 0012/1474] Add front matter --- articles/routing.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/articles/routing.md b/articles/routing.md index c202d14f45..db29c04a1a 100644 --- a/articles/routing.md +++ b/articles/routing.md @@ -1,3 +1,8 @@ +--- +layout: article +title: Routing and URLs +--- + # Meteor Guide: Routing After reading this guide, you'll know: From 1dfd64670adb16b0d899b9fa176ddf05ae7584b5 Mon Sep 17 00:00:00 2001 From: Sashko Stubailo Date: Wed, 7 Oct 2015 12:07:02 -0700 Subject: [PATCH 0013/1474] Try some more stuff --- .gitignore | 1 + _config.yml | 3 +++ _layouts/article.html | 3 +++ articles/routing.md | 2 +- index.html | 7 +++++++ 5 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100644 _config.yml create mode 100644 _layouts/article.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..ca35be08d4 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +_site diff --git a/_config.yml b/_config.yml new file mode 100644 index 0000000000..63560ec924 --- /dev/null +++ b/_config.yml @@ -0,0 +1,3 @@ +encoding: 'utf8' +kramdown: + input: GFM diff --git a/_layouts/article.html b/_layouts/article.html new file mode 100644 index 0000000000..44583b5b81 --- /dev/null +++ b/_layouts/article.html @@ -0,0 +1,3 @@ +
+ {{content}} +
diff --git a/articles/routing.md b/articles/routing.md index db29c04a1a..f57b200c4a 100644 --- a/articles/routing.md +++ b/articles/routing.md @@ -19,7 +19,7 @@ This guide will refer to code samples from the Todos example app, which has been In a web application, _Routing_ is the process of using URLs to drive the user interface (UI). URLs are a prominent feature in every single web browser, and have several main functions from the user's point of view: -1. **Bookmarking **- Users can bookmark URLs in their web browser to save content they want to come back to later +1. **Bookmarking** - Users can bookmark URLs in their web browser to save content they want to come back to later 2. **Sharing** - Users can share content with others by sending a link to a certain page 3. **Navigation** - URLs are used to drive the web browser's back/forward functions diff --git a/index.html b/index.html index 2489be59ff..5dacbeff30 100644 --- a/index.html +++ b/index.html @@ -1,3 +1,10 @@ +--- +--- +

Meteor Guide

Hello world!

+ +{% for page in site.pages %} + [{{ page.title }}]({{ page.url }}) +{% endfor %} From 70b129b4b6e57eae68f9336c1a719b55af6d8bf6 Mon Sep 17 00:00:00 2001 From: Sashko Stubailo Date: Wed, 7 Oct 2015 12:09:45 -0700 Subject: [PATCH 0014/1474] I'm too lazy to set up local jekyll... --- articles/routing.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/articles/routing.md b/articles/routing.md index f57b200c4a..847d3e657b 100644 --- a/articles/routing.md +++ b/articles/routing.md @@ -3,6 +3,8 @@ layout: article title: Routing and URLs --- +{% raw %} + # Meteor Guide: Routing After reading this guide, you'll know: @@ -445,3 +447,5 @@ Displaying not found/404 page 1. Don't use redirects to display a login page; just display the login page instead of the content, and keep the URL the same. In server-side rendered apps the only way to show a login page is to redirect but that restriction doesn't exist on the client. 2. Similarly, don't encode temporary data in the URL, like `/stuff?alert="thanks for logging in"` because you can just use a variable in JS. If you want something to persist across tabs and actual page reloads, it should be in Mongo or localstorage. + +{% end raw %} From 114e9976a7aa99f912c927107802496b2a640d52 Mon Sep 17 00:00:00 2001 From: Sashko Stubailo Date: Wed, 7 Oct 2015 15:42:58 -0700 Subject: [PATCH 0015/1474] First real article --- Gemfile | 4 + Gemfile.lock | 133 +++++++++ _config.yml | 11 +- _layouts/article.html | 37 ++- articles/routing.md | 93 +++--- css/github.css | 651 ++++++++++++++++++++++++++++++++++++++++++ css/highlight.css | 62 ++++ index.html | 6 +- js/toc.js | 108 +++++++ 9 files changed, 1050 insertions(+), 55 deletions(-) create mode 100644 Gemfile create mode 100644 Gemfile.lock create mode 100644 css/github.css create mode 100644 css/highlight.css create mode 100644 js/toc.js diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000000..751963c857 --- /dev/null +++ b/Gemfile @@ -0,0 +1,4 @@ +source 'https://rubygems.org' + +gem 'github-pages' +gem 'kramdown' diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000000..b27fcdb930 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,133 @@ +GEM + remote: https://rubygems.org/ + specs: + RedCloth (4.2.9) + activesupport (4.2.4) + i18n (~> 0.7) + json (~> 1.7, >= 1.7.7) + minitest (~> 5.1) + thread_safe (~> 0.3, >= 0.3.4) + tzinfo (~> 1.1) + addressable (2.3.8) + blankslate (2.1.2.4) + classifier-reborn (2.0.3) + fast-stemmer (~> 1.0) + coffee-script (2.4.1) + coffee-script-source + execjs + coffee-script-source (1.9.1.1) + colorator (0.1) + ethon (0.8.0) + ffi (>= 1.3.0) + execjs (2.6.0) + fast-stemmer (1.0.2) + ffi (1.9.10) + gemoji (2.1.0) + github-pages (39) + RedCloth (= 4.2.9) + github-pages-health-check (~> 0.2) + jekyll (= 2.4.0) + jekyll-coffeescript (= 1.0.1) + jekyll-feed (= 0.3.1) + jekyll-mentions (= 0.2.1) + jekyll-redirect-from (= 0.8.0) + jekyll-sass-converter (= 1.3.0) + jekyll-sitemap (= 0.8.1) + jemoji (= 0.5.0) + kramdown (= 1.5.0) + liquid (= 2.6.2) + maruku (= 0.7.0) + mercenary (~> 0.3) + pygments.rb (= 0.6.3) + rdiscount (= 2.1.7) + redcarpet (= 3.3.2) + terminal-table (~> 1.4) + github-pages-health-check (0.5.3) + addressable (~> 2.3) + net-dns (~> 0.8) + public_suffix (~> 1.4) + typhoeus (~> 0.7) + html-pipeline (1.9.0) + activesupport (>= 2) + nokogiri (~> 1.4) + i18n (0.7.0) + jekyll (2.4.0) + classifier-reborn (~> 2.0) + colorator (~> 0.1) + jekyll-coffeescript (~> 1.0) + jekyll-gist (~> 1.0) + jekyll-paginate (~> 1.0) + jekyll-sass-converter (~> 1.0) + jekyll-watch (~> 1.1) + kramdown (~> 1.3) + liquid (~> 2.6.1) + mercenary (~> 0.3.3) + pygments.rb (~> 0.6.0) + redcarpet (~> 3.1) + safe_yaml (~> 1.0) + toml (~> 0.1.0) + jekyll-coffeescript (1.0.1) + coffee-script (~> 2.2) + jekyll-feed (0.3.1) + jekyll-gist (1.3.4) + jekyll-mentions (0.2.1) + html-pipeline (~> 1.9.0) + jekyll (~> 2.0) + jekyll-paginate (1.1.0) + jekyll-redirect-from (0.8.0) + jekyll (>= 2.0) + jekyll-sass-converter (1.3.0) + sass (~> 3.2) + jekyll-sitemap (0.8.1) + jekyll-watch (1.3.0) + listen (~> 3.0) + jemoji (0.5.0) + gemoji (~> 2.0) + html-pipeline (~> 1.9) + jekyll (>= 2.0) + json (1.8.3) + kramdown (1.5.0) + liquid (2.6.2) + listen (3.0.3) + rb-fsevent (>= 0.9.3) + rb-inotify (>= 0.9) + maruku (0.7.0) + mercenary (0.3.5) + mini_portile (0.6.2) + minitest (5.8.1) + net-dns (0.8.0) + nokogiri (1.6.6.2) + mini_portile (~> 0.6.0) + parslet (1.5.0) + blankslate (~> 2.0) + posix-spawn (0.3.11) + public_suffix (1.5.1) + pygments.rb (0.6.3) + posix-spawn (~> 0.3.6) + yajl-ruby (~> 1.2.0) + rb-fsevent (0.9.6) + rb-inotify (0.9.5) + ffi (>= 0.5.0) + rdiscount (2.1.7) + redcarpet (3.3.2) + safe_yaml (1.0.4) + sass (3.4.18) + terminal-table (1.5.2) + thread_safe (0.3.5) + toml (0.1.2) + parslet (~> 1.5.0) + typhoeus (0.8.0) + ethon (>= 0.8.0) + tzinfo (1.2.2) + thread_safe (~> 0.1) + yajl-ruby (1.2.1) + +PLATFORMS + ruby + +DEPENDENCIES + github-pages + kramdown + +BUNDLED WITH + 1.10.6 diff --git a/_config.yml b/_config.yml index 63560ec924..7dc53c58a4 100644 --- a/_config.yml +++ b/_config.yml @@ -1,3 +1,8 @@ -encoding: 'utf8' -kramdown: - input: GFM +encoding: utf-8 +markdown: redcarpet +markdown_ext: markdown,mkdown,mkdn,mkd,md + +redcarpet: + extensions: ["tables", "autolink", "strikethrough", "space_after_headers", "with_toc_data", "fenced_code_blocks", "no_intra_emphasis"] +safe: true +lsi: false diff --git a/_layouts/article.html b/_layouts/article.html index 44583b5b81..fbea340fed 100644 --- a/_layouts/article.html +++ b/_layouts/article.html @@ -1,3 +1,36 @@ -
- {{content}} + + + + + + + + + + + +
+

Placeholder table of contents below

+
+ + {{content}} +
+ + + + +
diff --git a/articles/routing.md b/articles/routing.md index 847d3e657b..a4061fb402 100644 --- a/articles/routing.md +++ b/articles/routing.md @@ -17,7 +17,7 @@ After reading this guide, you'll know: This guide will refer to code samples from the Todos example app, which has been carefully constructed to demonstrate all of these concepts. -## 1. Routing and the role it plays in a client-rendered app +## Routing and the role it plays in a client-rendered app In a web application, _Routing_ is the process of using URLs to drive the user interface (UI). URLs are a prominent feature in every single web browser, and have several main functions from the user's point of view: @@ -31,7 +31,7 @@ In contrast, Meteor operates on the principle of _data on the wire_, where the s However, most of the user-facing features of URLs listed above are still relevant for typical Meteor applications. Now that the server is not URL-driven, the URL just becomes a useful *serialization* of the client-side state the user is currently looking at. However, unlike a server-rendered application, it does not need to serialize the entirety of the user’s current state, simply the parts that you want to be linkable. For example, the URL should contain any search filters applied on a page, but not necessarily the state of a dropdown menu or popup. -## 2. Installing Flow Router 2 +## Installing Flow Router 2 To add routing to your app, install the `kadira:flow-router` package: @@ -45,11 +45,11 @@ At the time of writing this guide, Flow Router is at version 2.x. *Community packages: Flow Router is one of several popular routing packages for Meteor. Another is iron:router. You can search for router on Atmosphere to find more. Hopefully, the concepts in this routing guide will be relevant no matter which router you use, as long as it provides basic functions for URL management.* -## 3. Defining a simple route +## Defining a simple route The basic purpose of a router is to match certain URLs and perform actions as a result. This all happens on the client side, in the app user's browser. -``` +```js FlowRouter.route('/blog/:postId', { name: "blog-post", action(urlParams, queryParams) { @@ -67,23 +67,24 @@ When the route is matched, the `action` method executes, and you can perform any The `name` property of the route is optional, but will let us refer to this route more conveniently later on. -### 3.1 URL pattern matching +### URL pattern matching The above code snippet will match certain URLs. You may notice that one of the segments is prefixed by `:` - this means that it is a *url parameter*, and will match any string that is present in that segment of the path. Here are some example URLs and the resulting `urlParams` and `queryParams`: -URL action() called? urlParams queryParams -/ no -/about no -/blog/ no -/blog/eMtGij5AFESbTKfkT yes { postId: "eMtGij5AFESbTKfkT"} { } -/blog/1 yes { postId: "1"} { } -/blog/1?commentSort=top yes { postId: "1"} { commentSort: "top" } +| URL | action() called? | urlParams | queryParams +| ---- | ---- | ---- | ---- | +| / | no +| /about | no +| /blog/ | no +| /blog/eMtGij5AFESbTKfkT | yes | { postId: "eMtGij5AFESbTKfkT"} | { } +| /blog/1 | yes | { postId: "1"} | { } +| /blog/1?commentSort=top | yes | { postId: "1"} | { commentSort: "top" } *Table 3.1: Example URLs and the resulting parameters* Note that all of the values in `urlParams` and `queryParams` are always strings since URLs don't have any way of encoding a data type, so you might need to use `parseInt(value, 10)` to convert them into numbers. -## 4. Displaying different views based on the URL and defining layouts +## Displaying different views based on the URL and defining layouts *This section is UI-framework specific, and is written assuming you are using Blaze as your UI engine. If you are building your app with React or Angular, you will end up with similar concepts but the code will not be exactly the same.* @@ -99,7 +100,7 @@ meteor add kadira:blaze-layout To use this package, we need to define a layout template in our HTML: -``` +```html