Coder Social home page Coder Social logo

veliovgroup / meteor-flow-router-meta Goto Github PK

View Code? Open in Web Editor NEW
38.0 7.0 3.0 104 KB

Reactive meta tags, JavaScript links and CSS for meteor within flow-router-extra

Home Page: https://packosphere.com/ostrio/flow-router-meta

License: BSD 3-Clause "New" or "Revised" License

JavaScript 100.00%
seo seo-meta seo-middleware flow-router reactive-meta-tags meteorjs meteor-package metadata meta-tags css

meteor-flow-router-meta's Introduction

support support

Reactive meta tags, JavaScript and CSSs

Change meta tags on the fly in Meteor.js apps via flow-router-extra API. 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]

ToC:

Install:

meteor add ostrio:flow-router-meta

Note: this package implies ostrio:flow-router-title package.

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:

import { FlowRouter } from 'meteor/ostrio:flow-router-extra';
import { FlowRouterMeta, FlowRouterTitle } from 'meteor/ostrio:flow-router-meta';

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

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

Set CSS and JS per route:

import { FlowRouter } from 'meteor/ostrio:flow-router-extra';

// 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() {
    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() {
    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() {
    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.

import { FlowRouter } from 'meteor/ostrio:flow-router-extra';

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:

import { FlowRouter } from 'meteor/ostrio:flow-router-extra';

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.

import { FlowRouter } from 'meteor/ostrio:flow-router-extra';

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 = {}) {
        return data.keywords;
      }
    }
  },
  title(params, query, data = {}) {
    if (data) {
      return data.title;
    }
    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:

import { FlowRouter } from 'meteor/ostrio:flow-router-extra';

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'
    }
  }
});

Running Tests

  1. Clone this package
  2. In Terminal (Console) go to directory where package is cloned
  3. Then run:

Meteor/Tinytest

# Default
meteor test-packages ./

# With custom port
meteor test-packages ./ --port 8888

# With local MongoDB and custom port
MONGO_URL="mongodb://127.0.0.1:27017/flow-router-meta-tests" meteor test-packages ./ --port 8888

Support this project:

meteor-flow-router-meta's People

Contributors

dr-dimitru avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

meteor-flow-router-meta's Issues

[Question] Is the package production ready ?

I was searching from sometime for any package to add meta, title tags for flowRouter. Most of the packages I encounter was usually for Iron:router, and finally found this package. So the obv. question that raises, is this package production ready ?

FlowRouter: Redirect to subdomain w/o page refresh?

Anyone know if this is possible? Users are able to create pages on subdomains of my app's domain and my <a> tags cause the site to refresh. Any suggestions?

It's critical for my app, which has an audio player which can't be disrupted by transitioning from subdomain to subdomain.

Thanks for any help!

eslint complains about "Do not use 'new' for side effects"

ESLint doesn't like "new"

I initialize FlowRouterMeta:
new FlowRouterMeta(FlowRouter); new FlowRouterTitle(FlowRouter);

Then eslint complains about it:

error Do not use 'new' for side effects no-new

Is there an other way to do this?

Thank you!

Meta tags don't work for social sharing

I have a suggestion:

I just went and used the dynamic meta tags for the first time and realized they will never be used any social media since they are client side rendered.

Is there a way to get these tags to be used by social sharing sites?

route driven favicon

Thanks for your usefully job!
Is it right way to define different route based favicons?

FlowRouter.route('/admin/orders', {
  name: 'orders',
  title:'Orders',
    link: {
        favicon: {
            rel: 'shortcut icon',
            href: '/img/orders.png'
        }
    },

In my setup favicons don't changed with next routes and in view source i noticed same

<head>
<link rel="stylesheet" type="text/css" class="__meteor-css__" href="/merged-stylesheets.css?hash=8522f7d30d4fd02d7140d385c697b968bad9ac26">

Thanks in advance

FlowRouterMeta is not a function

I'm having an issue:

When i just install FlowRouterMeta

import { FlowRouterMeta, FlowRouterTitle } from 'meteor/ostrio:flow-router-meta';
console.log(FlowRouterMeta);
new FlowRouterMeta(FlowRouter);
new FlowRouterTitle(FlowRouter

Got the following message ...


I20180613-16:31:04.849(2)? undefined          
W20180613-16:31:06.419(2)? (STDERR) /home/joel/.meteor/packages/meteor-tool/.1.5.2_2.irtbc9++os.linux.x86_64+web.browser+web.cordova/mt-os.linux.x86_64/dev_bundle/server-lib/node_modules/fibers/future.js:280
W20180613-16:31:06.420(2)? (STDERR) 						throw(ex);
W20180613-16:31:06.420(2)? (STDERR) 						^
W20180613-16:31:06.421(2)? (STDERR) 
W20180613-16:31:06.421(2)? (STDERR) TypeError: FlowRouterMeta is not a function
W20180613-16:31:06.421(2)? (STDERR)     at meteorInstall.route.zzz_router.js (route/zzz_router.js:39:1)
W20180613-16:31:06.422(2)? (STDERR)     at fileEvaluate (packages/modules-runtime.js:333:9)
W20180613-16:31:06.422(2)? (STDERR)     at require (packages/modules-runtime.js:228:16)
W20180613-16:31:06.423(2)? (STDERR)     at /home/joel/project/c10po/beta/.meteor/local/build/programs/server/app/app.js:26001:1
W20180613-16:31:06.424(2)? (STDERR)     at /home/joel/project/c10po/beta/.meteor/local/build/programs/server/boot.js:339:34
W20180613-16:31:06.424(2)? (STDERR)     at Array.forEach (native)
W20180613-16:31:06.425(2)? (STDERR)     at Function._.each._.forEach (/home/joel/.meteor/packages/meteor-tool/.1.5.2_2.irtbc9++os.linux.x86_64+web.browser+web.cordova/mt-os.linux.x86_64/dev_bundle/server-lib/node_modules/underscore/underscore.js:79:11)
W20180613-16:31:06.426(2)? (STDERR)     at /home/joel/project/c10po/beta/.meteor/local/build/programs/server/boot.js:158:5
W20180613-16:31:06.426(2)? (STDERR)     at /home/joel/project/c10po/beta/.meteor/local/build/programs/server/boot.js:388:5
W20180613-16:31:06.427(2)? (STDERR)     at Function.run (/home/joel/project/c10po/beta/.meteor/local/build/programs/server/profile.js:510:12)
W20180613-16:31:06.428(2)? (STDERR)     at /home/joel/project/c10po/beta/.meteor/local/build/programs/server/boot.js:387:11

I'm on ubuntu 16.04 and Meteor 1.5.4.2

FlowRouterMeta is not defined

I initialised FlowRouterMeta and FlowRouterTitle like this:

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

at the end of my routes.js but still get a error log:

W20161019-03:57:57.510(2)? (STDERR)
W20161019-03:57:57.511(2)? (STDERR) ReferenceError: FlowRouterTitle is not defined
W20161019-03:57:57.511(2)? (STDERR)     at meteorInstall.lib.routes.js (lib/routes.js:96:5)
W20161019-03:57:57.511(2)? (STDERR)     at fileEvaluate (packages/modules-runtime/.npm/package/node_modules/install/install.js:153:1)

Packages:
[email protected]
[email protected]
[email protected]_1
[email protected]
[email protected]
[email protected]

[email protected]_1
[email protected]_1
[email protected]_1
[email protected]_1

[email protected]
aldeed:simple-schema
[email protected]
meteortoys:allthings

[email protected]

ostrio:files
ostrio:flow-router-extra
ostrio:flow-router-title
ostrio:flow-router-meta

kadira:blaze-layout
[email protected]
[email protected]

Rich snippets via <script type="application/ld+json">

Looks like the new preferred way to structure datas is to add a special script like this: https://developers.google.com/search/docs/guides/intro-structured-data

<script type="application/ld+json">
{
  "@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"
  }
}
</script>

Can't see anything in the docs that could do that. Any idea or workaround?

It seems that (deprecated?) package dochead had a way to do it by the way: https://github.com/kadirahq/meteor-dochead#docheadaddldjsonscriptjsonobj

Reactive content()

Following the discussion here: veliovgroup/Meteor-flow-router-title#9

Would be great to have content() reactive for metas too.

allRoutes.route('/:storyId', {
  meta: {
    'og:image': {
      property: 'og:image',
      content({storyId}) {
       // Not reactive
        const story = story && Stories.find(storyId).fetch()[0]    
        return story && story.title
      }
    },
  },
}

I also tried to use the data hook:

allRoutes.route('/:storyId', {
  data({username, storyId, storySlug, chapterId, chapterSlug}) {
    // Not reactive
    const story = story && Stories.find(storyId).fetch()[0]    
    return story
  },
  meta: {
    'og:image': {
      property: 'og:image',
      content(params, query, story) {
        // Runs only once
        return story && story.getPath()
      }
    },
  },
}

Actually my goal is to make all this routes compatible with https://github.com/VeliovGroup/jazeee-meteor-spiderable. I have to set Meteor.isReadyForSpiderable = true when all the metas are correctly set for crawlers from Google, Facebook, ... I might have missed something obvious to make all of this simpler, as I see that I'll have the same issue the new innerHTML feature: https://github.com/VeliovGroup/Meteor-flow-router-meta#ldjson.

Any advice? :)

Dynamic imports

Hi there, I've got one big router.js file that has a whole bunch of routes inside it. For example:

FlowRouter.route('/', {
    name: 'home',
    async action(params, queryParams) {
        const { default: Layout } = await import('/imports/client/layout')
        const {
            default: Home,
        } = await import('/imports/client/home')
        mount(Layout, {
            content: <Home tab='home' page={Number(queryParams.page)} />
        })
    }
})

I've now got 100+ such routes in this file -- many of which are only relevant for certain users (such as an admin). Is there a way to dynamically import that route, but ONLY if the user is an admin? It's easy enough to dynamically import a file containing all the admin routes, but unless I do that as part of the main package, the admin page I'm trying to visit will result in a 404.

Appreciate any guidance!

J

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.