Skip to content

Commit

Permalink
feat(gatsby-plugin-manifest): Update manifest on navigation (#17426)
Browse files Browse the repository at this point in the history
With the addition of the localize option in gatsby-plugin-manifest (#13471), multiple manifests can be generated and served depending on the path of the URL. While the correct manifest is served on initial page load, the link to the manifest is never updated even if the user navigates to a page that should include a different manifest.

Co-authored-by: Ward Peeters <ward@coding-tech.com>
  • Loading branch information
DK the Human and wardpeet committed Sep 26, 2019
1 parent be26f4e commit f88a9e2
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 24 deletions.
73 changes: 73 additions & 0 deletions packages/gatsby-plugin-manifest/src/__tests__/gatsby-browser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
describe(`gatsby-plugin-manifest`, () => {
const pluginOptions = {
name: `My Website`,
start_url: `/`,
localize: [
{
start_url: `/es/`,
lang: `es`,
},
],
}
let onRouteUpdate

beforeEach(() => {
global.__PATH_PREFIX__ = ``
global.__MANIFEST_PLUGIN_HAS_LOCALISATION__ = true
onRouteUpdate = require(`../gatsby-browser`).onRouteUpdate
document.head.innerHTML = `<link rel="manifest" href="/manifest.webmanifest">`
})

afterAll(() => {
delete global.__MANIFEST_PLUGIN_HAS_LOCALISATION__
})

test(`has manifest in head`, () => {
const location = {
pathname: `/`,
}
onRouteUpdate({ location }, pluginOptions)
expect(document.head).toMatchInlineSnapshot(`
<head>
<link
href="/manifest.webmanifest"
rel="manifest"
/>
</head>
`)
})

test(`changes href of manifest if navigating to a localized app`, () => {
const location = {
pathname: `/es/`,
}
// add default lang
pluginOptions.lang = `en`
onRouteUpdate({ location }, pluginOptions)
expect(document.head).toMatchInlineSnapshot(`
<head>
<link
href="/manifest_es.webmanifest"
rel="manifest"
/>
</head>
`)
})

test(`keeps default manifest if not navigating to a localized app`, () => {
const location = {
pathname: `/random-path/`,
}
// add default lang
pluginOptions.lang = `en`
onRouteUpdate({ location }, pluginOptions)
expect(document.head).toMatchInlineSnapshot(`
<head>
<link
href="/manifest.webmanifest"
rel="manifest"
/>
</head>
`)
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ describe(`gatsby-plugin-manifest`, () => {
it(testName, () => {
onRenderBody(args, {
start_url: `/`,
lang: `en`,
localize: [
{
start_url: `/de/`,
Expand Down
18 changes: 18 additions & 0 deletions packages/gatsby-plugin-manifest/src/gatsby-browser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/* global __MANIFEST_PLUGIN_HAS_LOCALISATION__ */
import { withPrefix as fallbackWithPrefix, withAssetPrefix } from "gatsby"
import getManifestForPathname from "./get-manifest-pathname"

// when we don't have localisation in our manifest, we tree shake everything away
if (__MANIFEST_PLUGIN_HAS_LOCALISATION__) {
const withPrefix = withAssetPrefix || fallbackWithPrefix

exports.onRouteUpdate = function({ location }, pluginOptions) {
const { localize } = pluginOptions
const manifestFilename = getManifestForPathname(location.pathname, localize)

const manifestEl = document.head.querySelector(`link[rel="manifest"]`)
if (manifestEl) {
manifestEl.setAttribute(`href`, withPrefix(manifestFilename))
}
}
}
31 changes: 24 additions & 7 deletions packages/gatsby-plugin-manifest/src/gatsby-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,20 +84,26 @@ exports.onPostBootstrap = async (
cacheModeOverride = { cache_busting_mode: `name` }
}

return makeManifest(cache, reporter, {
...manifest,
...locale,
...cacheModeOverride,
})
return makeManifest(
cache,
reporter,
{
...manifest,
...locale,
...cacheModeOverride,
},
true
)
})
)
}
activity.end()
}

const makeManifest = async (cache, reporter, pluginOptions) => {
const makeManifest = async (cache, reporter, pluginOptions, shouldLocalize) => {
const { icon, ...manifest } = pluginOptions
const suffix = pluginOptions.lang ? `_${pluginOptions.lang}` : ``
const suffix =
shouldLocalize && pluginOptions.lang ? `_${pluginOptions.lang}` : ``

// Delete options we won't pass to the manifest.webmanifest.
delete manifest.plugins
Expand Down Expand Up @@ -196,3 +202,14 @@ const makeManifest = async (cache, reporter, pluginOptions) => {
JSON.stringify(manifest)
)
}

exports.onCreateWebpackConfig = ({ actions, plugins }, pluginOptions) => {
actions.setWebpackConfig({
plugins: [
plugins.define({
__MANIFEST_PLUGIN_HAS_LOCALISATION__:
pluginOptions.localize && pluginOptions.localize.length,
}),
],
})
}
20 changes: 3 additions & 17 deletions packages/gatsby-plugin-manifest/src/gatsby-ssr.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import React from "react"
import { withPrefix as fallbackWithPrefix, withAssetPrefix } from "gatsby"
import fs from "fs"
import { createContentDigest } from "gatsby-core-utils"

import { defaultIcons, addDigestToPath } from "./common.js"
import getManifestForPathname from "./get-manifest-pathname"

// TODO: remove for v3
const withPrefix = withAssetPrefix || fallbackWithPrefix
Expand All @@ -14,20 +14,6 @@ exports.onRenderBody = (
{ setHeadComponents, pathname = `/` },
{ localize, ...pluginOptions }
) => {
if (Array.isArray(localize)) {
const locales = pluginOptions.start_url
? localize.concat(pluginOptions)
: localize
const manifest = locales.find(locale =>
RegExp(`^${locale.start_url}.*`, `i`).test(pathname)
)
pluginOptions = {
...pluginOptions,
...manifest,
}
if (!pluginOptions) return false
}

// We use this to build a final array to pass as the argument to setHeadComponents at the end of onRenderBody.
let headComponents = []

Expand Down Expand Up @@ -66,14 +52,14 @@ exports.onRenderBody = (
}
}

const suffix = pluginOptions.lang ? `_${pluginOptions.lang}` : ``
const manifestFileName = getManifestForPathname(pathname, localize)

// Add manifest link tag.
headComponents.push(
<link
key={`gatsby-plugin-manifest-link`}
rel="manifest"
href={withPrefix(`/manifest${suffix}.webmanifest`)}
href={withPrefix(`/${manifestFileName}`)}
crossOrigin={pluginOptions.crossOrigin}
/>
)
Expand Down
23 changes: 23 additions & 0 deletions packages/gatsby-plugin-manifest/src/get-manifest-pathname.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* Get a manifest filename depending on localized pathname
*
* @param {string} pathname
* @param {Array<{start_url: string, lang: string}>} localizedManifests
* @return string
*/
export default (pathname, localizedManifests) => {
const defaultFilename = `manifest.webmanifest`
if (!Array.isArray(localizedManifests)) {
return defaultFilename
}

const localizedManifest = localizedManifests.find(app =>
pathname.startsWith(app.start_url)
)

if (!localizedManifest) {
return defaultFilename
}

return `manifest_${localizedManifest.lang}.webmanifest`
}

0 comments on commit f88a9e2

Please sign in to comment.