{
    "componentChunkName": "component---src-templates-post-js",
    "path": "/gatsby-on-rails",
    "result": {"data":{"site":{"siteMetadata":{"title":"your friend Joel's digital garden","description":"Articles and notes from a collaborator at egghead.io. Musings on software, business, and life from a skilled virtual assistant.","author":{"name":"Joel Hooks"},"keywords":["Video Blogger"]}},"mdx":{"excerpt":"We've got a robust Rails app that does a lot of heavy lifting for us. We've crafted a full hateos REST api with a delightful GraphQL layer over the top. We started using React as our primary UI a few years ago, and we do SSR via React on…","fields":{"github":"https://github.com/joelhooks/joelhooks-com/tree/master/content/blog/2019-11-17--using-aws-cloudfront-to-serve-a-gatsby-app-on-netlify-as-an-authenticated-sub-route-of-a-rails-app-on-heroku~~b_5x964Og/index.mdx"},"body":"var _excluded = [\"components\"];\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nvar _frontmatter = {\n  \"id\": \"b_5x964Og\",\n  \"slug\": \"gatsby-on-rails\",\n  \"date\": \"2019-11-17T00:00:00.000Z\",\n  \"description\": \"Using AWS Cloudfront to serve a Gatsby app on Netlify as an authenticated sub-route of a Rails app on Heroku\",\n  \"title\": \"🤠 Gatsby on Rails\",\n  \"published\": false\n};\nvar layoutProps = {\n  _frontmatter: _frontmatter\n};\nvar MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  var components = _ref.components,\n      props = _objectWithoutProperties(_ref, _excluded);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"p\", null, \"We've got a robust Rails app that does a lot of heavy lifting for us. We've crafted a full hateos REST api with a delightful GraphQL layer over the top.\"), mdx(\"p\", null, \"We started using React as our primary UI a few years ago, and we do SSR via React on Rails. It's a great project and our pages are pretty fast. They are rendered by running a little node server sidecar with our Rails app. There's some caching involved and it is \\\"fine\\\"\"), mdx(\"p\", null, mdx(\"span\", {\n    parentName: \"p\",\n    \"className\": \"gatsby-resp-image-wrapper\",\n    \"style\": {\n      \"position\": \"relative\",\n      \"display\": \"block\",\n      \"marginLeft\": \"auto\",\n      \"marginRight\": \"auto\",\n      \"maxWidth\": \"1035px\"\n    }\n  }, \"\\n      \", mdx(\"a\", {\n    parentName: \"span\",\n    \"className\": \"gatsby-resp-image-link\",\n    \"href\": \"/static/6b91b4ad2f058a2e43d2d3e69beb5f49/ee258/this-is-fine.jpg\",\n    \"style\": {\n      \"display\": \"block\"\n    },\n    \"target\": \"_blank\",\n    \"rel\": \"noopener\"\n  }, \"\\n    \", mdx(\"span\", {\n    parentName: \"a\",\n    \"className\": \"gatsby-resp-image-background-image\",\n    \"style\": {\n      \"paddingBottom\": \"47.490347490347496%\",\n      \"position\": \"relative\",\n      \"bottom\": \"0\",\n      \"left\": \"0\",\n      \"backgroundImage\": \"url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAJABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAMC/8QAFgEBAQEAAAAAAAAAAAAAAAAAAwAE/9oADAMBAAIQAxAAAAGmjA1Uy3//xAAaEAEAAgMBAAAAAAAAAAAAAAABAhIAAzMi/9oACAEBAAEFAkLkqbJe16vRz//EABYRAQEBAAAAAAAAAAAAAAAAAAAREv/aAAgBAwEBPwHKP//EABgRAAMBAQAAAAAAAAAAAAAAAAACEQFR/9oACAECAQE/AcaFbp//xAAZEAACAwEAAAAAAAAAAAAAAAAAAQIQIRH/2gAIAQEABj8CcTEdeEb/AP/EABsQAAIDAQEBAAAAAAAAAAAAAAABETFRIXGh/9oACAEBAAE/IUeDVolk+cFUi2im6PmL/UXP/9oADAMBAAIAAwAAABAkz//EABcRAQEBAQAAAAAAAAAAAAAAAAEAESH/2gAIAQMBAT8QCuWTl//EABcRAQEBAQAAAAAAAAAAAAAAAAEAEVH/2gAIAQIBAT8QfKchjZ//xAAgEAACAQMEAwAAAAAAAAAAAAABEQAhQVExYbHBcaHw/9oACAEBAAE/EDpAsBGjIGcQ7iBAhc6hO47gYqFI7lTzPXcz6m07eTP/2Q==')\",\n      \"backgroundSize\": \"cover\",\n      \"display\": \"block\"\n    }\n  }), \"\\n  \", mdx(\"img\", {\n    parentName: \"a\",\n    \"className\": \"gatsby-resp-image-image\",\n    \"alt\": \"a dog in a bowler cap in a burning room with a cup of tea and the caption this is fine\",\n    \"title\": \"a dog in a bowler cap in a burning room with a cup of tea and the caption this is fine\",\n    \"src\": \"/static/6b91b4ad2f058a2e43d2d3e69beb5f49/af659/this-is-fine.jpg\",\n    \"srcSet\": [\"/static/6b91b4ad2f058a2e43d2d3e69beb5f49/8356d/this-is-fine.jpg 259w\", \"/static/6b91b4ad2f058a2e43d2d3e69beb5f49/bc760/this-is-fine.jpg 518w\", \"/static/6b91b4ad2f058a2e43d2d3e69beb5f49/af659/this-is-fine.jpg 1035w\", \"/static/6b91b4ad2f058a2e43d2d3e69beb5f49/51eb8/this-is-fine.jpg 1553w\", \"/static/6b91b4ad2f058a2e43d2d3e69beb5f49/ee258/this-is-fine.jpg 1630w\"],\n    \"sizes\": \"(max-width: 1035px) 100vw, 1035px\",\n    \"style\": {\n      \"width\": \"100%\",\n      \"height\": \"100%\",\n      \"margin\": \"0\",\n      \"verticalAlign\": \"middle\",\n      \"position\": \"absolute\",\n      \"top\": \"0\",\n      \"left\": \"0\"\n    },\n    \"loading\": \"lazy\",\n    \"decoding\": \"async\"\n  }), \"\\n  \"), \"\\n    \")), mdx(\"p\", null, \"The experiment is running here: \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://egghead.io/learn\"\n  }, \"https://egghead.io/learn\")), mdx(\"p\", null, \"Our Rails app is private, but you can see the Gatsby app \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://github.com/eggheadio/egghead-static\"\n  }, \"here\"), \". This app has our entire catalog as JSON files. Eventually it'd make more sense to have these generated at build time or by the server and saved to an S3 bucket.\"), mdx(\"p\", null, \"Cloudfront Behaviors are the secret sauce. We already use Cloudfront to cache our entire site, and behaviors let define specific route paths and point them to any origin server we like. It works essentially like a CNAME in DNS, but also reminds me of a proxy with nginx or Apache.\"), mdx(\"p\", null, \"Since we use Heroku primary for our primary app and are pretty happy with it, using the proxy approach wasn't as sensible. You can to fun nginx \\u2728tricks\\u2728 on heroku too with buildpacks, but Cloudfront behaviors felt lighter and just kind of worked so I went with it.\"), mdx(\"p\", null, \"On the netlify side everything is relatively normal in terms of configuration. We pointed the Cloudfront Behavior to an origin that is the netlify sub-domain.\"), mdx(\"p\", null, \"This threw a wrench in the works. Gatsby doesn't allow configurable build directories and \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://github.com/gatsbyjs/gatsby/issues/1878#issuecomment-419614298\"\n  }, \"Kyle says it will \", mdx(\"strong\", {\n    parentName: \"a\"\n  }, \"never\"), \" allow us to configure build directories\"), \" so we needed to use a different solution. A painful sad solution \\uD83D\\uDE2D\"), mdx(\"p\", null, mdx(\"span\", {\n    parentName: \"p\",\n    \"className\": \"gatsby-resp-image-wrapper\",\n    \"style\": {\n      \"position\": \"relative\",\n      \"display\": \"block\",\n      \"marginLeft\": \"auto\",\n      \"marginRight\": \"auto\",\n      \"maxWidth\": \"1035px\"\n    }\n  }, \"\\n      \", mdx(\"a\", {\n    parentName: \"span\",\n    \"className\": \"gatsby-resp-image-link\",\n    \"href\": \"/static/4a02974ce410aea23c551f6b4c65d556/7f15f/kyle-says-no.png\",\n    \"style\": {\n      \"display\": \"block\"\n    },\n    \"target\": \"_blank\",\n    \"rel\": \"noopener\"\n  }, \"\\n    \", mdx(\"span\", {\n    parentName: \"a\",\n    \"className\": \"gatsby-resp-image-background-image\",\n    \"style\": {\n      \"paddingBottom\": \"29.343629343629342%\",\n      \"position\": \"relative\",\n      \"bottom\": \"0\",\n      \"left\": \"0\",\n      \"backgroundImage\": \"url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAABYlAAAWJQFJUiTwAAAA/UlEQVQY032Qy0oEMRBF5/+/yIXiwo0LNyJuBnEYBsZ+mKQqSXc6/ToyaVEENXCom9TlUpXd08M9r6cKGzKVCbxrKtr4XOrlLt1EGFZ8Wr4IaUH7GeOHb18/s7u7vuLxec9b49i/HDiezpyrtlA1puA04GOPD5/EDdFYfK0RnHgkjuwA+hG8WpxzqDqstagKIoL3HhGHMab0rTWIczhny9vFG2O8xJCnlR3rSswLXVeX4CEcCBmmdWNcfurfyDMM01q+pUw4pYyvDRI6RAMaE7HPhS5NxDSS8lwm+JMZxpktcGlaqptbXo8H6rqhbVtUFVEt6/gQGMfMdtZ/+QB0rs4jkiGRgAAAAABJRU5ErkJggg==')\",\n      \"backgroundSize\": \"cover\",\n      \"display\": \"block\"\n    }\n  }), \"\\n  \", mdx(\"img\", {\n    parentName: \"a\",\n    \"className\": \"gatsby-resp-image-image\",\n    \"alt\": \"screenshot of a quote from Kyle Matthews saying that configurable output directories will never be part of Gatsby\",\n    \"title\": \"screenshot of a quote from Kyle Matthews saying that configurable output directories will never be part of Gatsby\",\n    \"src\": \"/static/4a02974ce410aea23c551f6b4c65d556/e3189/kyle-says-no.png\",\n    \"srcSet\": [\"/static/4a02974ce410aea23c551f6b4c65d556/a2ead/kyle-says-no.png 259w\", \"/static/4a02974ce410aea23c551f6b4c65d556/6b9fd/kyle-says-no.png 518w\", \"/static/4a02974ce410aea23c551f6b4c65d556/e3189/kyle-says-no.png 1035w\", \"/static/4a02974ce410aea23c551f6b4c65d556/7f15f/kyle-says-no.png 1530w\"],\n    \"sizes\": \"(max-width: 1035px) 100vw, 1035px\",\n    \"style\": {\n      \"width\": \"100%\",\n      \"height\": \"100%\",\n      \"margin\": \"0\",\n      \"verticalAlign\": \"middle\",\n      \"position\": \"absolute\",\n      \"top\": \"0\",\n      \"left\": \"0\"\n    },\n    \"loading\": \"lazy\",\n    \"decoding\": \"async\"\n  }), \"\\n  \"), \"\\n    \")), mdx(\"p\", null, \"I agree. We are at the margins here, but at the same time this feels like a powerful use case that could sell Gatsby as a powerful modern tool that fits nicely and plays well in existing legacy application infrastructures.\"), mdx(\"p\", null, \"Hacks are fine though \\uD83D\\uDE02\"), mdx(\"p\", null, \"We just configured an npm script in our \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"package.json\"), \" to clear the build folder, build the app, create a sub-folder, and move the whole fuckin build manually into the sub-folder.\"), mdx(\"p\", null, \"This step took the most debugging to get the clearing and recursive moving working properly, but configurable Gatsby output folders are very hard and marginally useful so here we are!\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-json\"\n  }, \"\\\"build\\\": \\\"rm -rf public && gatsby build --prefix-paths && yarn move\\\",\\n\\\"move\\\": \\\"cd public && mkdir learn | mv * learn\\\",\\n\")), mdx(\"p\", null, \"This isn't the worst config code I've ever written, but the Gatsby build is a predictable linux environment and this works. We also need the Gatsby \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"pathPrefix\"), \" option set in out config set to \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"learn\")), mdx(\"p\", null, \"The whole setup is flimsy, but the result is super interesting. Now we have a blazing fast Gatsby app that has full and complete authenticated access via a Rails session to our API.\"), mdx(\"p\", null, \"It opens a lot of questions, but also opens up a huge pile of potential.Our catalog doesn't change rapidly so we can deal with build times required for static approach. The vast majority of the metadata for our entire catalog can be static. As far as protected content, it's mostly related to media access and that's a small percentage of the overall data and very fast to load async.\"), mdx(\"p\", null, \"React concurrent mode and Suspense is going to be a huge win for this approach, since each page on the site will be 90% static with the rest being filled in.\"));\n}\n;\nMDXContent.isMDXComponent = true;","frontmatter":{"title":"🤠 Gatsby on Rails","date":"November 17, 2019","banner":null,"slug":"gatsby-on-rails","keywords":null}}},"pageContext":{"id":"4a83ba90-59f9-524f-9d85-91cea0c44a50","prev":{"id":"052c4d36-17d0-5147-92f5-daa90d0a32f5","parent":{"name":"index","sourceInstanceName":"blog"},"excerpt":"Have you ever experienced the crippling fear of choosing a frontend framework to go deep on, to use for your next project, or to specialize in? We've got sparse time to spend learning, and how we choose to specialize is a critical aspect of being a…","fields":{"title":"How do You Choose a Front-End Framework?","slug":"how-to-choose-a-framework","date":"2019-11-19T00:00:00.000Z"}},"next":{"id":"a79327ce-96eb-5e4a-ae76-3ac4ae6f634d","parent":{"name":"index","sourceInstanceName":"blog"},"excerpt":"This is a question that comes up a lot: \"Should I use a framework?\" It's a good question, and something that I've both asked myself and thought about quite a lot over the years. Here's the thing... If you aren't using a framework there is a good…","fields":{"title":"🤔 \"Should I use a framework?\"","slug":"should-i-use-a-framework","date":"2019-11-14T00:00:00.000Z"}}}},
    "staticQueryHashes": ["1045846374"]}