Gravitywell UK
Published in

Gravitywell UK

Gatsby, automating builds with AWS Amplify

What is Gatsby?

Gatsby is a static site generator that uses React as main underlying technology. It has attracted the attention of many people very quickly because its main characteristic: performance.

And Gatsby is snappy, really fast. Just need to navigate through the Gatsby website to check it by yourself. Since it works as a PWA, it loads just the files needed to render the current page and prefetches the ones around so that you have to wait so little for their load.

Though I consider the main aim of Gatsby would be building blogs (for now), its use could be extended to almost any other type of websites and apps because it is managed by React.

As we are looking for alternatives to rewrite and migrate our blog section and website eventually, we’ve given it a go.

Decoupled by nature

This representant of the (relatively new) known like JAMStack provides out the box the tools needed to interact with your backend app through GraphQL.

It didn’t take me long to build a Drupal 8 site in Pantheon that I would use to write my blog posts making use of a Wysiwyg editor and excellent tools like Paragraphs to work as data source of my Gatsby app!

Another great point about Gatsby it is the amazing work they’ve done to offer literally hundreds of plugins of any type that makes really easy any integration and the creation of code examples to use them.

So, at this point, and after a few hours I had finished my blog prototype with…

…and some blog posts!

Blogs section prototype with Gatsby
Blogs article prototype with Gatsby

As any other client app the deploy will just involve the upload of the files to a Static web host. In our case, we used a S3 bucket and AWS amplify.

Automating build with Amplify

But… performance comes at a price. The JAMStack is based in markup prebuilding at deploy time. That means, once your Gatsby site has been built, any new article or change in an existing one won’t be reflected unless you deploy your app again…

What can we do?

  • Using a plugin or standard React components and routing to create dynamically rendered pages. This would mean jumping to a different approach (hybrid apps) and losing some of the benefits of the stack (performance).
  • Manual builds and deploys after any change in the content we want publish. Probably the worst option, especially if the content builders don’t have easy access to the tools to build and deploy (or they shouldn’t).
  • Using a Continuous Delivery tool (eg. Jenkins) to automate the build and deploy of the app when updated content is detected. This way, we can keep the advantages explained so far without having to involve further resources other than writing posts. Our choice ;)

Finally, we opted for AWS Amplify Console, another tool part of the AWS world ecosystem, to set our automation plan as it is really easy to configure and use and it met perfectly our requirements. Amplify Console is a CD and hosting service specially designed for JAMStack (and in general any modern) apps. You just need to connect to your app through your repo (hosted in Bitbucket, GitHub, etc) and it will automatically detect your app settings, previously configured with the Amplify CLI. Besides, it provides other cool features like atomic deployments and screenshots of your app in different devices to make sure everything works as intented. Another advantage of this approach is you don’t need to keep constantly running an server to host a CD tool like Jenkins for sporadic deployments.

Once, we’ve connected our app with the Amplify Console we just need a clic to build and deploy the latest version of our blog with up to date content. Now, we can programatically trigger the job to build our app in the Amplify console making use of a Lambda function and the AWS SDK:

const AmplifyClient = require('aws-sdk/clients/amplify');module.exports.runAmplifyDeploy = async (event, context) => {
try {
await amplifyStartJob({
appId: "gatsby-blog-id",
branchName: "master",
jobType: "RELEASE"
});
} catch (error) {
return {
statusCode: 500,
body: JSON.stringify(error)
};
}
return {
statusCode: 200,
body: "Job started successfully."
};
};
const amplifyStartJob = async (params) => {
const amplify = new AmplifyClient({
endpoint: 'https://amplify.eu-west-1.amazonaws.com',
region: "eu-west-1"
});
return new Promise((resolve, reject) => {
amplify.startJob(params, function(error, data) {
if (error) {
reject(error);
return;
} else {
resolve(data);
}
});
});
}

Though the lambda function isn’t intrinsically needed, it will give us more control over the process (e.g. we’ll be able to check when the last job was run and avoid carrying out multiple deploys in a too short period of time) and it could be used as a gateway for any of our Amplify apps in the future.

Build & Deploy with Amplify console

Now, in our Drupal backend, we can create a small custom module to call our the lambda function when a blog content update takes place. We’ll be able to whether request the function as an API endpoint with an API Gateway or directly invoking it with the SDK again:

/**
* Implements hook_ENTITY_TYPE_update().
*/
function gatsbybuild_node_update(Drupal\node\NodeInterface $node) {
try {
$lambda_client = LambdaClient::factory([
'version' => 'latest',
'region' => $aws_region,
'credentials' => [
'key' => $aws_iam_key,
'secret' => $aws_iam_secret
]
]);
$result = $lambda_client->invoke([
'FunctionName' => 'amplify-deploy-gatsby',
'InvocationType' => 'RequestResponse',
'LogType' => 'Tail',
]);
...
}
catch (RequestException $e) {
...

When finished the job triggered by our Drupal site, the content will be updated in our Gatsby site :)

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Jesus Larrubia

Jesus Larrubia

Senior Full Stack Engineer at @clevertech