Reactive meta tags, JavaScript and CSSs
Change meta tags on the fly within flow-router-extra
. This package can create meta
tags, script
and link
tags as well.
Features:
- 100% tests coverage;
- Per route, per group, and default (all routes)
meta
tags; - Per route, per group, and default (all routes)
script
s; - Per route, per group, and default (all routes)
link
, like CSS files.
Various ways to set meta
, script
and link
tags, ordered by prioritization:
FlowRouter.route()
[overrides all below]FlowRouter.group()
FlowRouter.globals
- Head template
<meta/>
,<link/>
,<script/>
tags [might be overridden by any above]
Note: this package implies ostrio:flow-router-title package.
ToC:
- Installation
- Demo application
- Set CSS and JS per route
- Set
application/ld+json
- Use function as value
- Use function's context
- Bootstrap configuration
- Other examples
- Support this project
Install:
meteor add ostrio:flow-router-meta
Demos / Tests:
ES6 Import:
1import { FlowRouterMeta } from 'meteor/ostrio:flow-router-meta'; 2// This library implies ostrio:flow-router-title package, and both can be imported in single line: 3import { FlowRouterMeta, FlowRouterTitle } from 'meteor/ostrio:flow-router-meta';
Usage:
You need to initialize FlowRouterMeta
and FlowRouterTitle
classes by passing FlowRouter
object. Right after creating all your routes:
1FlowRouter.route('/', { 2 action() { /* ... */ }, 3 title: "Title" 4 /* ... */ 5}); 6 7new FlowRouterMeta(FlowRouter); 8new FlowRouterTitle(FlowRouter);
Set CSS and JS per route:
1// Set default JS and CSS for all routes 2FlowRouter.globals.push({ 3 link: { 4 twbs: { 5 rel: 'stylesheet', 6 href: 'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css' 7 } 8 }, 9 script: { 10 twbs: 'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js' 11 } 12}); 13 14// Rewrite default JS and CSS, for second route, via controller: 15FlowRouter.route('/secondPage', { 16 name: 'secondPage', 17 action(params, query) { 18 return this.render('layout', 'secondPage'); 19 }, 20 link: { 21 twbs: { 22 rel: 'stylesheet', 23 href: 'https://maxcdn.bootstrapcdn.com/bootstrap/2.2.0/css/bootstrap.min.css' 24 } 25 }, 26 script: { 27 twbs: 'https://maxcdn.bootstrapcdn.com/bootstrap/2.2.0/js/bootstrap.min.js' 28 } 29}); 30 31// Unset defaults, via controller: 32FlowRouter.route('/secondPage', { 33 name: 'secondPage', 34 action(params, query) { 35 return this.render('layout', 'secondPage'); 36 }, 37 link: { 38 twbs: null 39 }, 40 script: { 41 twbs: null 42 } 43}); 44 45// Rewrite default JS and CSS, for route group: 46const group = FlowRouter.group({ 47 link: { 48 twbs: { 49 rel: 'stylesheet', 50 href: 'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha/css/bootstrap.min.css' 51 } 52 }, 53 script: { 54 twbs: 'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha/js/bootstrap.min.js' 55 } 56}); 57 58group.route('/groupPage1', { 59 name: 'groupPage1', 60 action(params, query) { 61 return this.render('layout', 'groupPage1'); 62 } 63});
ldjson:
This method uses special property named innerHTML
which set script's content instead of attribute. This method and property can be used in the any other case when you need to set script's contents.
1FlowRouter.route('/fourthPage', { 2 name: 'fourthPage', 3 title: 'Fourth Page title', 4 script: { 5 ldjson: { 6 type: 'application/ld+json', 7 innerHTML: JSON.stringify({ 8 "@context": "http://schema.org/", 9 "@type": "Recipe", 10 "name": "Grandma's Holiday Apple Pie", 11 "author": "Elaine Smith", 12 "image": "http://images.edge-generalmills.com/56459281-6fe6-4d9d-984f-385c9488d824.jpg", 13 "description": "A classic apple pie.", 14 "aggregateRating": { 15 "@type": "AggregateRating", 16 "ratingValue": "4", 17 "reviewCount": "276", 18 "bestRating": "5", 19 "worstRating": "1" 20 } 21 }) 22 } 23 }, 24 action() { /*...*/ } 25});
Use function as value:
1FlowRouter.route('/routePath', { 2 name: 'routeName', 3 meta: { 4 url: { 5 property: 'og:url', 6 itemprop: 'url', 7 content() { 8 return document.location.href; 9 } 10 } 11 }, 12 link: { 13 canonical() { 14 return document.location.href; 15 } 16 } 17});
Use function context:
Read about data
hook.
1FlowRouter.route('/post/:_id', { 2 name: 'post', 3 waitOn(params) { 4 return [Meteor.subscribe('post', params._id)]; 5 }, 6 data(params) { 7 return Collection.Posts.findOne(params._id); 8 }, 9 meta: { 10 keywords: { 11 name: 'keywords', 12 itemprop: 'keywords', 13 content(params, query, data) { 14 if (data == null) { 15 data = {}; 16 } 17 return data.keywords; 18 } 19 } 20 }, 21 title(params, query, data) { 22 if (data == null) { 23 data = {}; 24 } 25 if (data) { 26 return data.title; 27 } else { 28 return '404: Page not found'; 29 } 30 } 31});
Other examples:
Set only name
and content
attributes on meta
tag:
1FlowRouter.route('/routePath', { 2 name: 'routeName', 3 meta: { 4 name: 'content' 5 } 6});
Set only rel
and href
attributes on link
tag:
1FlowRouter.route('/routePath', { 2 name: 'routeName', 3 link: { 4 rel: 'http://example.com' 5 } 6});
Set multiple attributes on meta
tag:
1FlowRouter.route('/routePath', { 2 name: 'routeName', 3 meta: { 4 uniqueName: { 5 name: 'name', 6 content: 'value', 7 property: 'og:name', 8 itemprop: 'name' 9 } 10 } 11});
Set multiple attributes on link
tag:
1FlowRouter.route('/routePath', { 2 name: 'routeName', 3 link: { 4 uniqueName: { 5 rel: 'name', 6 sizes: 'value', 7 href: 'value', 8 type: 'value' 9 } 10 } 11});
Bootstrap configuration:
1FlowRouter.route('/routePath', { 2 name: 'routeName', 3 meta: { 4 // <meta charset="UTF-8"> 5 charset: { 6 charset: 'UTF-8' 7 }, 8 9 // <meta name="keywords" content="Awes.."> 10 keywords: { 11 name: 'keywords', 12 itemprop: 'keywords', 13 content: 'Awesome, Meteor, based, app' 14 }, 15 16 // <meta name="description" itemprop="description" property="og:description" content="Default desc.."> 17 description: { 18 name: 'description', 19 itemprop: 'description', 20 property: 'og:description', 21 content: 'Default description' 22 }, 23 image: { 24 name: 'twitter:image', 25 itemprop: 'image', 26 property: 'og:image', 27 content: 'http://example.com' 28 }, 29 'og:type': 'website', 30 'og:title'() { 31 return document.title; 32 }, 33 'og:site_name': 'My Awesome Site', 34 url: { 35 property: 'og:url', 36 itemprop: 'url', 37 content() { 38 return window.location.href; 39 } 40 }, 41 'twitter:card': 'summary', 42 'twitter:title'() { 43 return document.title; 44 }, 45 'twitter:description': 'Default description', 46 'twitter:site': { 47 name: 'twitter:site', 48 value: '@twitterAccountName' 49 }, 50 'twitter:creator': { 51 name: 'twitter:creator', 52 value: '@twitterAccountName' 53 }, 54 'http-equiv': { 55 'http-equiv': 'X-UA-Compatible', 56 content: 'IE=edge,chrome=1' 57 }, 58 robots: 'index, follow', 59 google: 'notranslate' 60 }, 61 link: { 62 // <link href="https://maxcdn.bootstrapcdn.com/..." rel="stylesheet"> 63 stylesheet: "https://maxcdn.bootstrapcdn.com/bootstrap/2.3.2/css/bootstrap.min.css", 64 65 // <link rel="canonical" href="http://example.com"> 66 canonical() { 67 return document.location.href; 68 }, 69 70 // <link rel="image" sizes="500x500" href="http://example.com"> 71 image: { 72 rel: 'image', 73 sizes: '500x500', 74 href: 'http://example.com' 75 }, 76 publisher: 'http://plus.google...', 77 'shortcut icon': { 78 rel: 'shortcut icon', 79 type: 'image/x-icon', 80 href: 'http://example.com' 81 }, 82 'icon': { 83 rel: 'icon', 84 type: 'image/png', 85 href: 'http://example.com' 86 }, 87 'apple-touch-icon-144': { 88 rel: 'apple-touch-icon', 89 sizes: '144x144', 90 href: 'http://example.com' 91 }, 92 'apple-touch-icon-114': { 93 rel: 'apple-touch-icon', 94 sizes: '114x114', 95 href: 'http://example.com' 96 }, 97 'apple-touch-icon-72': { 98 rel: 'apple-touch-icon', 99 sizes: '72x72', 100 href: 'http://example.com' 101 }, 102 'apple-touch-icon-57': { 103 rel: 'apple-touch-icon', 104 sizes: '57x57', 105 href: 'http://example.com' 106 } 107 }, 108 script: { 109 twbs: 'https://maxcdn.bootstrapcdn.com/bootstrap/2.3.2/js/bootstrap.min.js', 110 d3: { 111 src: 'https://d3js.org/d3.v3.min.js', 112 charset: 'utf-8' 113 } 114 } 115});
Support this project:
This project wouldn't be possible without ostr.io.
Using ostr.io you are not only protecting domain names, monitoring websites and servers, using Prerendering for better SEO of your JavaScript website, but support our Open Source activity, and great packages like this one could be available for free.