Skip to content
This repository has been archived by the owner on Dec 5, 2021. It is now read-only.

Commit

Permalink
feat[#56]: create tag Canonical
Browse files Browse the repository at this point in the history
  • Loading branch information
TiagoDanin committed Sep 25, 2020
1 parent 4349332 commit b02b4d3
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 19 deletions.
39 changes: 28 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@

SEO / HTML Meta Tags Module for Nuxt.js

## Features

- Easy to use
- Canonical tag automatically generated
- Implementation of Open Graph Protocol (ogp)
- Compatible with npm package: debug

## Installation

Module available through the [npm registry](https://www.npmjs.com/). It can be installed using the [`npm`](https://docs.npmjs.com/getting-started/installing-npm-packages-locally) or [`yarn`](https://yarnpkg.com/en/) command line tool.
Expand All @@ -28,6 +35,7 @@ npm install nuxt-seo --save
],
seo: {
// Module options
baseUrl: 'https://myWebSite',
name: '<name of site>',
title: '<title default>',
templateTitle: '%name% - %title%',
Expand All @@ -43,6 +51,10 @@ npm install nuxt-seo --save
- Default: `utf-8`
- Type: String

### `baseUrl`
- Default: ``
- Type: String

#### `name`
- Default: `false`
- Type: String
Expand All @@ -67,6 +79,11 @@ npm install nuxt-seo --save
- Default: `English`
- Type: String

#### `canonical`
The `auto` this will automatically generate according to the route, or put the route manually.
- Default: `auto`
- Type: String

#### `image`
- Default: `false`
- Type: URL String
Expand All @@ -75,16 +92,16 @@ npm install nuxt-seo --save
- Default: `false`
- Type: Array[name, email || site] || String

#### `openGraph.type`
- Default: `false`
#### `openGraph[type]`
- Types: [ogp.me/#types](http://ogp.me/#types)

#### `url`
- Default: `false`
- Type: URL String

### `{...all}`
`charset`, `lang`, `language`, `copyright`, `name`, `title`, `subtitle`, `author`, `replyTo`, `description`, `keywords`, `url`, `noindex.ids.0`, `noindex.ids.1`, `noindex.ids`, `noindex.value.0`, `noindex.value.1`, `noindex.value`, `noindex`, `robots.ids.0`, `robots.ids.1`, `robots.ids`, `robots`, `openGraph.name`, `openGraph.title`, `openGraph.description`, `openGraph.locale`, `openGraph.url`, `openGraph.type`, `openGraph.profile.firstName`, `openGraph.profile.lastName`, `openGraph.profile.username`, `openGraph.profile.gender`, `openGraph.profile`, `openGraph.article.publishedTime`, `openGraph.article.modifiedTime`, `openGraph.article.expirationTime`, `openGraph.article.author.multi`, `openGraph.article.author`, `openGraph.article.section`, `openGraph.article.tag.multi`, `openGraph.article.tag`, `openGraph.article.authors.multi`, `openGraph.article.authors`, `openGraph.article.tags.multi`, `openGraph.article.tags`, `openGraph.article`, `openGraph.image.multi`, `openGraph.image.url`, `openGraph.image.width`, `openGraph.image.height`, `openGraph.image.alt`, `openGraph.image`, `openGraph.book.author.multi`, `openGraph.book.author`, `openGraph.book.isbn`, `openGraph.book.releaseDate`, `openGraph.book.tag.multi`, `openGraph.book.tag`, `openGraph.book.authors.multi`, `openGraph.book.authors`, `openGraph.book.tags.multi`, `openGraph.book.tags`, `openGraph.book`, `openGraph.price.currency`, `openGraph.price.amount`, `openGraph.price`, `openGraph.images.multi`, `openGraph.images.url`, `openGraph.images.width`, `openGraph.images.height`, `openGraph.images.alt`, `openGraph.images`, `openGraph`, `facebook.appId`, `facebook.pageId`, `facebook`, `twitter.title`, `twitter.description`, `twitter.card`, `twitter.type`, `twitter.site`, `twitter.creator`, `twitter`, `article.publishedTime`, `article.modifiedTime`, `article.expirationTime`, `article.author.multi`, `article.author`, `article.section`, `article.tag.multi`, `article.tag`, `article.authors.multi`, `article.authors`, `article.tags.multi`, `article.tags`, `article`, `book.author.multi`, `book.author`, `book.isbn`, `book.releaseDate`, `book.tag.multi`, `book.tag`, `book.authors.multi`, `book.authors`, `book.tags.multi`, `book.tags`, `book`, `image.multi`, `image.url`, `image.width`, `image.height`, `image.alt`, `image`, `images.multi`, `images.url`, `images.width`, `images.height`, `images.alt`, `images`, `og.name`, `og.title`, `og.description`, `og.locale`, `og.url`, `og.type`, `og.profile.firstName`, `og.profile.lastName`, `og.profile.username`, `og.profile.gender`, `og.profile`, `og.article.publishedTime`, `og.article.modifiedTime`, `og.article.expirationTime`, `og.article.author.multi`, `og.article.author`, `og.article.section`, `og.article.tag.multi`, `og.article.tag`, `og.article.authors.multi`, `og.article.authors`, `og.article.tags.multi`, `og.article.tags`, `og.article`, `og.image.multi`, `og.image.url`, `og.image.width`, `og.image.height`, `og.image.alt`, `og.image`, `og.book.author.multi`, `og.book.author`, `og.book.isbn`, `og.book.releaseDate`, `og.book.tag.multi`, `og.book.tag`, `og.book.authors.multi`, `og.book.authors`, `og.book.tags.multi`, `og.book.tags`, `og.book`, `og.price.currency`, `og.price.amount`, `og.price`, `og.images.multi`, `og.images.url`, `og.images.width`, `og.images.height`, `og.images.alt`, `og.images`, `og`, `fb.appId`, `fb.pageId`, `fb`
`charset`, `lang`, `language`, `copyright`, `name`, `subtitle`, `author`, `replyTo`, `description`, `keywords`, `url`, `noindex.ids.0`, `noindex.ids.1`, `noindex.ids`, `noindex.value.0`, `noindex.value.1`, `noindex.value`, `noindex`, `robots.ids.0`, `robots.ids.1`, `robots.ids`, `robots`, `openGraph.name`, `openGraph.title`, `openGraph.description`, `openGraph.locale`, `openGraph.url`, `openGraph.type`, `openGraph.profile.firstName`, `openGraph.profile.lastName`, `openGraph.profile.username`, `openGraph.profile.gender`, `openGraph.profile`, `openGraph.article.publishedTime`, `openGraph.article.modifiedTime`, `openGraph.article.expirationTime`, `openGraph.article.author.multi`, `openGraph.article.author`, `openGraph.article.section`, `openGraph.article.tag.multi`, `openGraph.article.tag`, `openGraph.article.authors.multi`, `openGraph.article.authors`, `openGraph.article.tags.multi`, `openGraph.article.tags`, `openGraph.article`, `openGraph.image.multi`, `openGraph.image.url`, `openGraph.image.width`, `openGraph.image.height`, `openGraph.image.alt`, `openGraph.image`, `openGraph.book.author.multi`, `openGraph.book.author`, `openGraph.book.isbn`, `openGraph.book.releaseDate`, `openGraph.book.tag.multi`, `openGraph.book.tag`, `openGraph.book.authors.multi`, `openGraph.book.authors`, `openGraph.book.tags.multi`, `openGraph.book.tags`, `openGraph.book`, `openGraph.price.currency`, `openGraph.price.amount`, `openGraph.price`, `openGraph.images.multi`, `openGraph.images.url`, `openGraph.images.width`, `openGraph.images.height`, `openGraph.images.alt`, `openGraph.images`, `openGraph`, `facebook.appId`, `facebook.pageId`, `facebook`, `twitter.title`, `twitter.description`, `twitter.card`, `twitter.type`, `twitter.site`, `twitter.creator`, `twitter`, `article.publishedTime`, `article.modifiedTime`, `article.expirationTime`, `article.author.multi`, `article.author`, `article.section`, `article.tag.multi`, `article.tag`, `article.authors.multi`, `article.authors`, `article.tags.multi`, `article.tags`, `article`, `book.author.multi`, `book.author`, `book.isbn`, `book.releaseDate`, `book.tag.multi`, `book.tag`, `book.authors.multi`, `book.authors`,
`book.tags.multi`, `book.tags`, `book`, `image.multi`, `image.url`, `image.width`, `image.height`, `image.alt`, `image`, `images.multi`, `images.url`, `images.width`, `images.height`, `images.alt`, `images`, `og.name`, `og.title`, `og.description`, `og.locale`, `og.url`, `og.type`, `og.profile.firstName`, `og.profile.lastName`, `og.profile.username`, `og.profile.gender`, `og.profile`, `og.article.publishedTime`, `og.article.modifiedTime`, `og.article.expirationTime`, `og.article.author.multi`, `og.article.author`, `og.article.section`, `og.article.tag.multi`, `og.article.tag`, `og.article.authors.multi`, `og.article.authors`, `og.article.tags.multi`, `og.article.tags`, `og.article`, `og.image.multi`, `og.image.url`, `og.image.width`, `og.image.height`, `og.image.alt`, `og.image`, `og.book.author.multi`, `og.book.author`, `og.book.isbn`, `og.book.releaseDate`, `og.book.tag.multi`, `og.book.tag`, `og.book.authors.multi`, `og.book.authors`, `og.book.tags.multi`, `og.book.tags`, `og.book`, `og.price.currency`, `og.price.amount`, `og.price`, `og.images.multi`, `og.images.url`, `og.images.width`, `og.images.height`, `og.images.alt`, `og.images`, `og`, `fb.appId`, `fb.pageId`, `fb`

### Vue Context
- `asyncData: function({ seo }) { seo(options) }`
Expand Down Expand Up @@ -117,13 +134,13 @@ To run the test suite, first install the dependencies, then run `test`:
yarn test
```

## Dependencies
## Dependency

<details>
<summary><a href="https://ghub.io/debug">debug</a>: small debugging utility</summary>
<b>Author</b>: TJ Holowaychuk</br>
<b>License</b>: MIT</br>
<b>Version</b>: ^4.1.1
<b>Version</b>: ^4.2.0
</details>

## Dev Dependencies
Expand All @@ -132,31 +149,31 @@ yarn test
<summary><a href="https://ghub.io/ava">ava</a>: Node.js test runner that lets you develop with confidence.</summary>
<b>Author</b>: novemberborn, sindresorhus, vdemedes</br>
<b>License</b>: MIT</br>
<b>Version</b>: ^3.8.2
<b>Version</b>: ^3.12.1
</details>
<details>
<summary><a href="https://ghub.io/got">got</a>: Human-friendly and powerful HTTP request library for Node.js</summary>
<b>Author</b>: sindresorhus, szmarczak</br>
<b>License</b>: MIT</br>
<b>Version</b>: ^11.1.4
<b>Version</b>: ^11.7.0
</details>
<details>
<summary><a href="https://ghub.io/nuxt">nuxt</a>: A minimalistic framework for server-rendered Vue.js applications (inspired by Next.js)</summary>
<b>Author</b>: atinux, pi0</br>
<b>Author</b>: atinux, pi0, clarkdo</br>
<b>License</b>: MIT</br>
<b>Version</b>: ^2.12.2
<b>Version</b>: ^2.14.6
</details>
<details>
<summary><a href="https://ghub.io/vue">vue</a>: Reactive, component-oriented view layer for modern web interfaces.</summary>
<b>Author</b>: Evan You</br>
<b>License</b>: MIT</br>
<b>Version</b>: ^2.6.11
<b>Version</b>: ^2.6.12
</details>
<details>
<summary><a href="https://ghub.io/xo">xo</a>: JavaScript/TypeScript linter with great defaults</summary>
<b>Author</b>: Sindre Sorhus</br>
<b>License</b>: MIT</br>
<b>Version</b>: ^0.30.0
<b>Version</b>: ^0.33.1
</details>

## Contributors
Expand Down
16 changes: 13 additions & 3 deletions docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
],
seo: {
// Module options
baseUrl: 'https://myWebSite',
name: '<name of site>',
title: '<title default>',
templateTitle: '%name% - %title%',
Expand All @@ -24,6 +25,10 @@
- Default: `utf-8`
- Type: String

### `baseUrl`
- Default: ``
- Type: String

#### `name`
- Default: `false`
- Type: String
Expand All @@ -48,6 +53,11 @@
- Default: `English`
- Type: String

#### `canonical`
The `auto` this will automatically generate according to the route, or put the route manually.
- Default: `auto`
- Type: String

#### `image`
- Default: `false`
- Type: URL String
Expand All @@ -56,16 +66,16 @@
- Default: `false`
- Type: Array[name, email || site] || String

#### `openGraph.type`
- Default: `false`
#### `openGraph[type]`
- Types: [ogp.me/#types](http://ogp.me/#types)

#### `url`
- Default: `false`
- Type: URL String

### `{...all}`
`charset`, `lang`, `language`, `copyright`, `name`, `title`, `subtitle`, `author`, `replyTo`, `description`, `keywords`, `url`, `noindex.ids.0`, `noindex.ids.1`, `noindex.ids`, `noindex.value.0`, `noindex.value.1`, `noindex.value`, `noindex`, `robots.ids.0`, `robots.ids.1`, `robots.ids`, `robots`, `openGraph.name`, `openGraph.title`, `openGraph.description`, `openGraph.locale`, `openGraph.url`, `openGraph.type`, `openGraph.profile.firstName`, `openGraph.profile.lastName`, `openGraph.profile.username`, `openGraph.profile.gender`, `openGraph.profile`, `openGraph.article.publishedTime`, `openGraph.article.modifiedTime`, `openGraph.article.expirationTime`, `openGraph.article.author.multi`, `openGraph.article.author`, `openGraph.article.section`, `openGraph.article.tag.multi`, `openGraph.article.tag`, `openGraph.article.authors.multi`, `openGraph.article.authors`, `openGraph.article.tags.multi`, `openGraph.article.tags`, `openGraph.article`, `openGraph.image.multi`, `openGraph.image.url`, `openGraph.image.width`, `openGraph.image.height`, `openGraph.image.alt`, `openGraph.image`, `openGraph.book.author.multi`, `openGraph.book.author`, `openGraph.book.isbn`, `openGraph.book.releaseDate`, `openGraph.book.tag.multi`, `openGraph.book.tag`, `openGraph.book.authors.multi`, `openGraph.book.authors`, `openGraph.book.tags.multi`, `openGraph.book.tags`, `openGraph.book`, `openGraph.price.currency`, `openGraph.price.amount`, `openGraph.price`, `openGraph.images.multi`, `openGraph.images.url`, `openGraph.images.width`, `openGraph.images.height`, `openGraph.images.alt`, `openGraph.images`, `openGraph`, `facebook.appId`, `facebook.pageId`, `facebook`, `twitter.title`, `twitter.description`, `twitter.card`, `twitter.type`, `twitter.site`, `twitter.creator`, `twitter`, `article.publishedTime`, `article.modifiedTime`, `article.expirationTime`, `article.author.multi`, `article.author`, `article.section`, `article.tag.multi`, `article.tag`, `article.authors.multi`, `article.authors`, `article.tags.multi`, `article.tags`, `article`, `book.author.multi`, `book.author`, `book.isbn`, `book.releaseDate`, `book.tag.multi`, `book.tag`, `book.authors.multi`, `book.authors`, `book.tags.multi`, `book.tags`, `book`, `image.multi`, `image.url`, `image.width`, `image.height`, `image.alt`, `image`, `images.multi`, `images.url`, `images.width`, `images.height`, `images.alt`, `images`, `og.name`, `og.title`, `og.description`, `og.locale`, `og.url`, `og.type`, `og.profile.firstName`, `og.profile.lastName`, `og.profile.username`, `og.profile.gender`, `og.profile`, `og.article.publishedTime`, `og.article.modifiedTime`, `og.article.expirationTime`, `og.article.author.multi`, `og.article.author`, `og.article.section`, `og.article.tag.multi`, `og.article.tag`, `og.article.authors.multi`, `og.article.authors`, `og.article.tags.multi`, `og.article.tags`, `og.article`, `og.image.multi`, `og.image.url`, `og.image.width`, `og.image.height`, `og.image.alt`, `og.image`, `og.book.author.multi`, `og.book.author`, `og.book.isbn`, `og.book.releaseDate`, `og.book.tag.multi`, `og.book.tag`, `og.book.authors.multi`, `og.book.authors`, `og.book.tags.multi`, `og.book.tags`, `og.book`, `og.price.currency`, `og.price.amount`, `og.price`, `og.images.multi`, `og.images.url`, `og.images.width`, `og.images.height`, `og.images.alt`, `og.images`, `og`, `fb.appId`, `fb.pageId`, `fb`
`charset`, `lang`, `language`, `copyright`, `name`, `subtitle`, `author`, `replyTo`, `description`, `keywords`, `url`, `noindex.ids.0`, `noindex.ids.1`, `noindex.ids`, `noindex.value.0`, `noindex.value.1`, `noindex.value`, `noindex`, `robots.ids.0`, `robots.ids.1`, `robots.ids`, `robots`, `openGraph.name`, `openGraph.title`, `openGraph.description`, `openGraph.locale`, `openGraph.url`, `openGraph.type`, `openGraph.profile.firstName`, `openGraph.profile.lastName`, `openGraph.profile.username`, `openGraph.profile.gender`, `openGraph.profile`, `openGraph.article.publishedTime`, `openGraph.article.modifiedTime`, `openGraph.article.expirationTime`, `openGraph.article.author.multi`, `openGraph.article.author`, `openGraph.article.section`, `openGraph.article.tag.multi`, `openGraph.article.tag`, `openGraph.article.authors.multi`, `openGraph.article.authors`, `openGraph.article.tags.multi`, `openGraph.article.tags`, `openGraph.article`, `openGraph.image.multi`, `openGraph.image.url`, `openGraph.image.width`, `openGraph.image.height`, `openGraph.image.alt`, `openGraph.image`, `openGraph.book.author.multi`, `openGraph.book.author`, `openGraph.book.isbn`, `openGraph.book.releaseDate`, `openGraph.book.tag.multi`, `openGraph.book.tag`, `openGraph.book.authors.multi`, `openGraph.book.authors`, `openGraph.book.tags.multi`, `openGraph.book.tags`, `openGraph.book`, `openGraph.price.currency`, `openGraph.price.amount`, `openGraph.price`, `openGraph.images.multi`, `openGraph.images.url`, `openGraph.images.width`, `openGraph.images.height`, `openGraph.images.alt`, `openGraph.images`, `openGraph`, `facebook.appId`, `facebook.pageId`, `facebook`, `twitter.title`, `twitter.description`, `twitter.card`, `twitter.type`, `twitter.site`, `twitter.creator`, `twitter`, `article.publishedTime`, `article.modifiedTime`, `article.expirationTime`, `article.author.multi`, `article.author`, `article.section`, `article.tag.multi`, `article.tag`, `article.authors.multi`, `article.authors`, `article.tags.multi`, `article.tags`, `article`, `book.author.multi`, `book.author`, `book.isbn`, `book.releaseDate`, `book.tag.multi`, `book.tag`, `book.authors.multi`, `book.authors`,
`book.tags.multi`, `book.tags`, `book`, `image.multi`, `image.url`, `image.width`, `image.height`, `image.alt`, `image`, `images.multi`, `images.url`, `images.width`, `images.height`, `images.alt`, `images`, `og.name`, `og.title`, `og.description`, `og.locale`, `og.url`, `og.type`, `og.profile.firstName`, `og.profile.lastName`, `og.profile.username`, `og.profile.gender`, `og.profile`, `og.article.publishedTime`, `og.article.modifiedTime`, `og.article.expirationTime`, `og.article.author.multi`, `og.article.author`, `og.article.section`, `og.article.tag.multi`, `og.article.tag`, `og.article.authors.multi`, `og.article.authors`, `og.article.tags.multi`, `og.article.tags`, `og.article`, `og.image.multi`, `og.image.url`, `og.image.width`, `og.image.height`, `og.image.alt`, `og.image`, `og.book.author.multi`, `og.book.author`, `og.book.isbn`, `og.book.releaseDate`, `og.book.tag.multi`, `og.book.tag`, `og.book.authors.multi`, `og.book.authors`, `og.book.tags.multi`, `og.book.tags`, `og.book`, `og.price.currency`, `og.price.amount`, `og.price`, `og.images.multi`, `og.images.url`, `og.images.width`, `og.images.height`, `og.images.alt`, `og.images`, `og`, `fb.appId`, `fb.pageId`, `fb`

### Vue Context
- `asyncData: function({ seo }) { seo(options) }`
Expand Down
1 change: 1 addition & 0 deletions example/nuxt.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ module.exports = {
require('../lib/module')
],
seo: {
baseUrl: 'http://localhost:3000',
name: 'App name',
description: 'Example app with Nuxt Seo'
}
Expand Down
23 changes: 21 additions & 2 deletions lib/module.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ const log = debug('nuxt:seo:log')
const deb = debug('nuxt:seo:debug')

const defaults = {
baseUrl: '',
charset: 'utf-8',
lang: 'en',
language: 'English',
templateTitle: '%title%',
title: 'Title',
name: false,
description: false
description: false,
canonical: 'auto'
}

const allMetas = {
Expand Down Expand Up @@ -248,6 +250,20 @@ const createMeta = (options = {}, inputMeta = [], template = {}) => {
return [...inputMeta, ...outputMeta]
}

const createCanonical = (options, path) => {
let canonicalUrl = options.baseUrl.replace(/\/$/, '')
if (options.canonical === 'auto') {
canonicalUrl += path
} else {
canonicalUrl = options.canonical.startsWith('http') ? options.canonical : canonicalUrl + options.canonical
}

canonicalUrl = canonicalUrl.replace(/\/$/, '') + '/' // Force end /
return [
{rel: 'canonical', href: canonicalUrl}
]
}

module.exports = function (moduleOptions) {
if (!moduleOptions.meta) {
moduleOptions.meta = {}
Expand All @@ -273,13 +289,15 @@ module.exports = function (moduleOptions) {

this.options.head.title = createTitle(options)
this.options.head.meta = createMeta(options, this.options.head.meta, template)
this.options.head.link = createCanonical(options, '/')

const pluginOptions = {
moduleOptions: options,
template,
func: {
createMeta,
createTitle
createTitle,
createCanonical
}
}

Expand All @@ -298,4 +316,5 @@ module.exports.meta = require('../package.json')
module.exports.defaults = defaults
module.exports.createTitle = createTitle
module.exports.createMeta = createMeta
module.exports.createCanonical = createCanonical
module.exports.template = allMetas
6 changes: 5 additions & 1 deletion lib/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ export default function (ctx, inject) {
}
ctx.app.head.title = nuxtSeo.createTitle(options)
ctx.app.head.meta = nuxtSeo.createMeta(options, ctx.app.head.meta, template)
if (Vue.prototype && Vue.prototype.$meta) {
if (ctx.route && ctx.route.path) {
ctx.app.head.link = nuxtSeo.createCanonical(options, ctx.route.path)
}

if (Vue.prototype && Vue.prototype.$meta) { // Vue-meta is enabled
if (Vue.prototype.$nuxt && Vue.prototype.$nuxt.$options && Vue.prototype.$nuxt.$options.head) {
Vue.prototype.$nuxt.$options.head = ctx.app.head
}
Expand Down
Loading

0 comments on commit b02b4d3

Please sign in to comment.