Skip to content

Commit

Permalink
Add support for client-side redirects in production (#2227)
Browse files Browse the repository at this point in the history
* Show default values for actions

* Add support for client-side redirects in browser
  • Loading branch information
KyleAMathews committed Sep 25, 2017
1 parent e739a59 commit 951af82
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 17 deletions.
4 changes: 2 additions & 2 deletions packages/gatsby-source-contentful/src/normalize.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ exports.getLocalizedField = getLocalizedField
// course :-))
const fixId = id => {
if (!_.isString(id)) {
id = id.toString();
id = id.toString()
}
if (!isNaN(id.slice(0, 1))) {
return `c${id}`
}
}
return id
}
exports.fixId = fixId
Expand Down
4 changes: 3 additions & 1 deletion packages/gatsby-source-wordpress/src/normalize.js
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,9 @@ exports.createNodesFromEntities = ({ entities, createNode }) => {
if (entity.acf) {
_.each(entity.acf, (value, key) => {
if (_.isArray(value) && value[0].acf_fc_layout) {
entity.acf[`${key}_${entity.type}___NODE`] = entity.acf[key].map((f, i) => {
entity.acf[`${key}_${entity.type}___NODE`] = entity.acf[
key
].map((f, i) => {
const type = `WordPressAcf_${f.acf_fc_layout}`
delete f.acf_fc_layout

Expand Down
2 changes: 1 addition & 1 deletion packages/gatsby-transformer-remark/src/extend-node-type.js
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ module.exports = (
return getAST(markdownNode).then(ast => {
const textNodes = []
visit(ast, `text`, textNode => textNodes.push(textNode.value))
return prune(textNodes.join(` `), pruneLength, '…')
return prune(textNodes.join(` `), pruneLength, `…`)
})
},
},
Expand Down
33 changes: 32 additions & 1 deletion packages/gatsby/cache-dir/production-app.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import domReady from "domready"
import emitter from "./emitter"
window.___emitter = emitter
import pages from "./pages.json"
import redirects from "./redirects.json"
import ComponentRenderer from "./component-renderer"
import asyncRequires from "./async-requires"
import loader from "./loader"
Expand All @@ -20,6 +21,15 @@ window.asyncRequires = asyncRequires
window.___loader = loader
window.matchPath = matchPath

// Convert to a map for faster lookup in maybeRedirect()
const redirectMap = redirects.reduce((map, redirect) => {
map[redirect.fromPath] = redirect
return map
}, {})

// Check for initial page-load redirect
maybeRedirect(location.pathname)

// Let the site/plugins run code very early.
apiRunnerAsync(`onClientEntry`).then(() => {
// Let plugins register a service worker. The plugin just needs
Expand Down Expand Up @@ -79,11 +89,32 @@ apiRunnerAsync(`onClientEntry`).then(() => {
window.___history = history

history.listen((location, action) => {
apiRunner(`onRouteUpdate`, { location, action })
if (!maybeRedirect(location.pathname)) {
apiRunner(`onRouteUpdate`, { location, action })
}
})
}
}

function maybeRedirect(pathname) {
const redirect = redirectMap[pathname]

if (redirect != null) {
const pageResources = loader.getResourcesForPathname(pathname)

if (pageResources != null) {
console.error(
`The route "${pathname}" matches both a page and a redirect; this is probably not intentional.`
)
}

history.replace(redirect.toPath)
return true
} else {
return false
}
}

function shouldUpdateScroll(prevRouterProps, { location: { pathname } }) {
const results = apiRunner(`shouldUpdateScroll`, {
prevRouterProps,
Expand Down
12 changes: 7 additions & 5 deletions packages/gatsby/cache-dir/root.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const redirectMap = redirects.reduce((map, redirect) => {
}, {})

// Check for initial page-load redirect
maybeRedirect(location.pathname);
maybeRedirect(location.pathname)

// Call onRouteUpdate on the initial page load.
apiRunner(`onRouteUpdate`, {
Expand All @@ -46,13 +46,15 @@ function maybeRedirect(pathname) {
const pageResources = loader.getResourcesForPathname(pathname)

if (pageResources != null) {
console.error(`The route "${pathname}" matches both a page and a redirect; this is probably not intentional.`)
console.error(
`The route "${pathname}" matches both a page and a redirect; this is probably not intentional.`
)
}

history.replace(redirect.toPath)
return true;
return true
} else {
return false;
return false
}
}

Expand Down Expand Up @@ -127,7 +129,7 @@ const Root = () =>
render: routeProps => {
const props = layoutProps ? layoutProps : routeProps
attachToHistory(props.history)
const {pathname} = props.location
const { pathname } = props.location
const pageResources = loader.getResourcesForPathname(pathname)
if (pageResources) {
return createElement(ComponentRenderer, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@ const writeRedirects = async () => {

let { program, redirects } = store.getState()

// Filter for redirects that are meant for the browser.
const browserRedirects = redirects.filter(r => r.redirectInBrowser)

await fs.writeFile(
joinPath(program.directory, `.cache/redirects.json`),
JSON.stringify(redirects, null, 2)
JSON.stringify(browserRedirects, null, 2)
)
}

Expand Down
23 changes: 17 additions & 6 deletions packages/gatsby/src/redux/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,9 @@ actions.deleteLayout = (layout, plugin = ``) => {
}

/**
* Create a layout.
* Create a layout. Generally layouts are created automatically by placing a
* React component in the `src/layouts/` directory. This action should be used
* if loading layouts from an NPM package or from a non-standard location.
* @param {Object} layout a layout object
* @param {string} layout.component The absolute path to the component for this layout
* @example
Expand Down Expand Up @@ -194,7 +196,7 @@ actions.deleteNodes = (nodes, plugin = ``) => {

const typeOwners = {}
/**
* Create a new node
* Create a new node.
* @param {Object} node a node object
* @param {string} node.id The node's ID. Must be globally unique.
* @param {string} node.parent The ID of the parent's node. If the node is
Expand All @@ -212,10 +214,10 @@ const typeOwners = {}
* transformer plugins that your node has raw content they can transform.
* Use either an official media type (we use mime-db as our source
* (https://www.npmjs.com/package/mime-db) or a made-up one if your data
* doesn't fit in any existing bucket. Transformer plugins node media types
* doesn't fit in any existing bucket. Transformer plugins use node media types
* for deciding if they should transform a node into a new one. E.g.
* markdown transformers look for media types of
* text/markdown.
* `text/markdown`.
* @param {string} node.internal.type An arbitrary globally unique type
* choosen by the plugin creating the node. Should be descriptive of the
* node as the type is used in forming GraphQL types so users will query
Expand Down Expand Up @@ -398,6 +400,8 @@ actions.touchNode = (nodeId, plugin = ``) => {
* directly. So to extend another node, use this.
* @param {Object} $0
* @param {Object} $0.node the target node object
* @param {string} $0.fieldName [deprecated] the name for the field
* @param {string} $0.fieldValue [deprecated] the value for the field
* @param {string} $0.name the name for the field
* @param {string} $0.value the value for the field
* @example
Expand Down Expand Up @@ -613,17 +617,24 @@ actions.setPluginStatus = (status, plugin) => {
* @param {Object} redirect Redirect data
* @param {string} redirect.fromPath Any valid URL. Must start with a forward slash
* @param {string} redirect.isPermanent This is a permanent redirect; defaults to temporary
* @param {Object} redirect.toPath URL of a created page (see `createPage`)
* @param {string} redirect.toPath URL of a created page (see `createPage`)
* @param {string} redirect.redirectInBrowser Redirects are generally for redirecting legacy URLs to their new configuration. If you can't update your UI for some reason, set `redirectInBrowser` to true and Gatsby will handle redirecting in the client as well.
* @example
* createRedirect({ fromPath: '/old-url', toPath: '/new-url', isPermanent: true })
*/
actions.createRedirect = ({ fromPath, isPermanent = false, toPath }) => {
actions.createRedirect = ({
fromPath,
isPermanent = false,
toPath,
redirectInBrowser = false,
}) => {
return {
type: `CREATE_REDIRECT`,
payload: {
fromPath,
isPermanent,
toPath,
redirectInBrowser,
},
}
}
Expand Down
4 changes: 4 additions & 0 deletions www/src/components/function-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ const Param = (param, depth = 0) => {
param.name !== `$0` && (
<span css={{ color: `#73725f` }}>{`{${param.type.name}}`}</span>
)}
{param.default && (
<span css={{ color: `#73725f` }}>[default={param.default}]</span>
)}
</h5>
{param.description && (
<div
Expand Down Expand Up @@ -125,6 +128,7 @@ export const pageQuery = graphql`
type {
name
}
default
description {
childMarkdownRemark {
html
Expand Down

0 comments on commit 951af82

Please sign in to comment.