Reactive meta tags, JavaScript links and CSS for meteor within flow-router-extra
Clone or download
dr-dimitru v2.0.14
 - πŸ—‘ Get rid of `underscore` package
 - πŸ‘·β€β™‚οΈ Update auto-tests, closing: #11
 - πŸ“¦ Update NPM and Atmosphere dependencies
 - 🀝 Compatibility with `meteor@1.7.0.3`
Latest commit 6b52a80 Jul 26, 2018
Permalink
Failed to load latest commit information.
.github Package meta update Jan 25, 2018
demo Move demo application Dec 19, 2016
.gitignore Move demo application Dec 19, 2016
.versions v2.0.14 Jul 26, 2018
CHANGELOG.md Docs update Apr 19, 2016
CODE_OF_CONDUCT.md meta Nov 10, 2017
CONTRIBUTING.md Package's meta update Jan 27, 2018
HISTORY.md Docs update Apr 19, 2016
LICENSE Year bump Jan 25, 2018
README.md typo Nov 10, 2017
flow-router-meta.js v2.0.14 Jul 26, 2018
package.js v2.0.14 Jul 26, 2018
tests.js v2.0.14 Jul 26, 2018

README.md

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) scripts;
  • 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:

Install:

meteor add ostrio:flow-router-meta

Demos / Tests:

ES6 Import:

import { FlowRouterMeta } from 'meteor/ostrio:flow-router-meta';
// This library implies ostrio:flow-router-title package, and both can be imported in single line:
import { FlowRouterMeta, FlowRouterTitle } from 'meteor/ostrio:flow-router-meta';

Related Packages:

Usage:

You need to initialize FlowRouterMeta and FlowRouterTitle classes by passing FlowRouter object. Right after creating all your routes:

FlowRouter.route('/', {
  action() { /* ... */ },
  title: "Title"
  /* ... */
});

new FlowRouterMeta(FlowRouter);
new FlowRouterTitle(FlowRouter);

Set CSS and JS per route:

// Set default JS and CSS for all routes
FlowRouter.globals.push({
  link: {
    twbs: {
      rel: 'stylesheet',
      href: 'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css'
    }
  },
  script: {
    twbs: 'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js'
  }
});

// Rewrite default JS and CSS, for second route, via controller:
FlowRouter.route('/secondPage', {
  name: 'secondPage',
  action(params, query) {
    return this.render('layout', 'secondPage');
  },
  link: {
    twbs: {
      rel: 'stylesheet',
      href: 'https://maxcdn.bootstrapcdn.com/bootstrap/2.2.0/css/bootstrap.min.css'
    }
  },
  script: {
    twbs: 'https://maxcdn.bootstrapcdn.com/bootstrap/2.2.0/js/bootstrap.min.js'
  }
});

// Unset defaults, via controller:
FlowRouter.route('/secondPage', {
  name: 'secondPage',
  action(params, query) {
    return this.render('layout', 'secondPage');
  },
  link: {
    twbs: null
  },
  script: {
    twbs: null
  }
});

// Rewrite default JS and CSS, for route group:
const group = FlowRouter.group({
  link: {
    twbs: {
      rel: 'stylesheet',
      href: 'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha/css/bootstrap.min.css'
    }
  },
  script: {
    twbs: 'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha/js/bootstrap.min.js'
  }
});

group.route('/groupPage1', {
  name: 'groupPage1',
  action(params, query) {
    return this.render('layout', 'groupPage1');
  }
});

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.

FlowRouter.route('/fourthPage', {
  name: 'fourthPage',
  title: 'Fourth Page title',
  script: {
    ldjson: {
      type: 'application/ld+json',
      innerHTML: JSON.stringify({
        "@context": "http://schema.org/",
        "@type": "Recipe",
        "name": "Grandma's Holiday Apple Pie",
        "author": "Elaine Smith",
        "image": "http://images.edge-generalmills.com/56459281-6fe6-4d9d-984f-385c9488d824.jpg",
        "description": "A classic apple pie.",
        "aggregateRating": {
          "@type": "AggregateRating",
          "ratingValue": "4",
          "reviewCount": "276",
          "bestRating": "5",
          "worstRating": "1"
        }
      })
    }
  },
  action() { /*...*/ }
});

Use function as value:

FlowRouter.route('/routePath', {
  name: 'routeName',
  meta: {
    url: {
      property: 'og:url',
      itemprop: 'url',
      content() {
        return document.location.href;
      }
    }
  },
  link: {
    canonical() {
      return document.location.href;
    }
  }
});

Use function context:

Read about data hook.

FlowRouter.route('/post/:_id', {
  name: 'post',
  waitOn(params) {
    return [Meteor.subscribe('post', params._id)];
  },
  data(params) {
    return Collection.Posts.findOne(params._id);
  },
  meta: {
    keywords: {
      name: 'keywords',
      itemprop: 'keywords',
      content(params, query, data) {
        if (data == null) {
          data = {};
        }
        return data.keywords;
      }
    }
  },
  title(params, query, data) {
    if (data == null) {
      data = {};
    }
    if (data) {
      return data.title;
    } else {
      return '404: Page not found';
    }
  }
});

Other examples:

Set only name and content attributes on meta tag:

FlowRouter.route('/routePath', {
  name: 'routeName',
  meta: {
    name: 'content'
  }
});

Set only rel and href attributes on link tag:

FlowRouter.route('/routePath', {
  name: 'routeName',
  link: {
    rel: 'http://example.com'
  }
});

Set multiple attributes on meta tag:

FlowRouter.route('/routePath', {
  name: 'routeName',
  meta: {
    uniqueName: {
      name: 'name',
      content: 'value',
      property: 'og:name',
      itemprop: 'name'
    }
  }
});

Set multiple attributes on link tag:

FlowRouter.route('/routePath', {
  name: 'routeName',
  link: {
    uniqueName: {
      rel: 'name',
      sizes: 'value',
      href: 'value',
      type: 'value'
    }
  }
});

Bootstrap configuration:

FlowRouter.route('/routePath', {
  name: 'routeName',
  meta: {
    // <meta charset="UTF-8">
    charset: {
      charset: 'UTF-8'
    },

    // <meta name="keywords" content="Awes..">
    keywords: {
      name: 'keywords',
      itemprop: 'keywords',
      content: 'Awesome, Meteor, based, app'
    },

    // <meta name="description" itemprop="description" property="og:description" content="Default desc..">
    description: {
      name: 'description',
      itemprop: 'description',
      property: 'og:description',
      content: 'Default description'
    },
    image: {
      name: 'twitter:image',
      itemprop: 'image',
      property: 'og:image',
      content: 'http://example.com'
    },
    'og:type': 'website',
    'og:title'() {
      return document.title;
    },
    'og:site_name': 'My Awesome Site',
    url: {
      property: 'og:url',
      itemprop: 'url',
      content() {
        return window.location.href;
      }
    },
    'twitter:card': 'summary',
    'twitter:title'() {
      return document.title;
    },
    'twitter:description': 'Default description',
    'twitter:site': {
      name: 'twitter:site',
      value: '@twitterAccountName'
    },
    'twitter:creator': {
      name: 'twitter:creator',
      value: '@twitterAccountName'
    },
    'http-equiv': {
      'http-equiv': 'X-UA-Compatible',
      content: 'IE=edge,chrome=1'
    },
    robots: 'index, follow',
    google: 'notranslate'
  },
  link: {
    // <link href="https://maxcdn.bootstrapcdn.com/..." rel="stylesheet">
    stylesheet: "https://maxcdn.bootstrapcdn.com/bootstrap/2.3.2/css/bootstrap.min.css",

    // <link rel="canonical" href="http://example.com">
    canonical() {
      return document.location.href;
    },

    // <link rel="image" sizes="500x500" href="http://example.com">
    image: {
      rel: 'image',
      sizes: '500x500',
      href: 'http://example.com'
    },
    publisher: 'http://plus.google...',
    'shortcut icon': {
      rel: 'shortcut icon',
      type: 'image/x-icon',
      href: 'http://example.com'
    },
    'icon': {
      rel: 'icon',
      type: 'image/png',
      href: 'http://example.com'
    },
    'apple-touch-icon-144': {
      rel: 'apple-touch-icon',
      sizes: '144x144',
      href: 'http://example.com'
    },
    'apple-touch-icon-114': {
      rel: 'apple-touch-icon',
      sizes: '114x114',
      href: 'http://example.com'
    },
    'apple-touch-icon-72': {
      rel: 'apple-touch-icon',
      sizes: '72x72',
      href: 'http://example.com'
    },
    'apple-touch-icon-57': {
      rel: 'apple-touch-icon',
      sizes: '57x57',
      href: 'http://example.com'
    }
  },
  script: {
    twbs: 'https://maxcdn.bootstrapcdn.com/bootstrap/2.3.2/js/bootstrap.min.js',
    d3: {
      src: 'https://d3js.org/d3.v3.min.js',
      charset: 'utf-8'
    }
  }
});

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.