Creating a Twitter module for your Nuxt app

This tutorial covers how to integrate a Twitter feed into a statically generated Nuxt site. We’ll be using Node to pull tweets from Twitter, and IFTTT to rebuild our statically generated site on Netlify every time we tweet.

A demo repo can be found here in case you have any issues following the tutorial: https://github.com/davidwarrington/nuxt-tweet

1. Setup

The modules we’ll be using are:

  • twitter - Which will make connecting to the Twitter API painless.
  • fs-extra - This is optional. You can use the built-in fs Node module, but fs-extra makes things a little easier, by removing the need to manually check for pre-existing files and other boring tasks. For this reason we’ll use it in this tutorial.
  • dotenv - This is used to inject API keys that we don’t want to expose publicly for use during the build process. If you’re already using the @nuxt/dotenv module, you can skip installing this.

If you’re using yarn, run:

yarn add --dev twitter fs-extra dotenv

Or if you’re using npm, run:

npm install --save-dev twitter fs-extra dotenv

Finally, this step is optional, but if you don’t want to fill you commit history with JSON files containing tweets, add tweets/ to your .gitignore.

2. Creating the Twitter Client

To begin with, we need to make sure that we can connect to Twitter. Sign in to developer.twitter.com and create an app. This will allow us to generate API keys, in turn allowing us to pull information from Twitter. Once you’ve created the app, open it and visit the Keys and Tokens tab. You will need both Consumer API keys and Access Tokens. So you will have to make sure both are generated.

Now onto the code: create a modules folder and a twitter.js file inside. This module is going to run every time we run either the generate or dev scripts. This means that when we’re developing locally, Nuxt will pull the latest tweets from our feed and they will be deployed to the live site each time it is rebuilt.

Before we make the Nuxt module itself, let’s build the Twitter client to ensure that we can pull the info from Twitter.

To begin with add the following lines of code to your modules/twitter.js:

const Twitter = require('twitter')
const fs = require('fs-extra')

const client = new Twitter({
  consumer_key: '[CONSUMER KEY]',
  consumer_secret: '[CONSUMER SECRET]',
  access_token_key: '[ACCESS TOKEN]',
  access_token_secret: '[ACCESS TOKEN SECRET]'
})

We’ve just imported the Twitter module, which will allow us to easily configure Node to connect to the Twitter API. We’ll use the fs-extra module, which we’ve named fs , to save the data we pull from Twitter in a JSON file.

Replace the string values in client with your API keys and the Twitter module will be able to connect to the API.

From here add the following code:

const endpoint = 'statuses/user_timeline'
const params = {
  screen_name: '[YOUR USERNAME]',
  include_rts: false
}
const callback = (error, tweets, response) => {
  if (!error) fs.outputJSON('./tweets.json', tweets.slice(0, 5), { spaces: 4 })
}

client.get(endpoint, params, callback)

The endpoint is the part of the API we want to connect to. Since in this tutorial we’re getting tweets from our own timeline, the endpoint we’re using is statuses/user_timeline.

The params are options we’re sending to configure the endpoint. Since we want our own tweets, the screen_name property is our own twitter handle (excluding the @) and include_rts just prevents it from including retweets.

The callback tells the client what to do with the tweets it pulls from the API. We only need to use the first two arguments in our module, however I like to include all that are available in case I want to change it later on. In the function we’re simply saying “if the API doesn’t respond with an error, write the tweets to ./tweets.json, using 4 spaces for indentation to make it nice and readable”. I’m slicing the response to only include the latest 5 tweets. If you want to show more, or even all of the tweets it returns, feel free to replace tweets.slice(0, 5) with whatever you need.

Now to test our API connection. In your terminal, navigate to your modules directory and run node twitter. This should run the script we’ve just created. If all has gone well, once the script finishes, you should have a tweets.json file which contains an array of your tweets, which you should delete to prevent committing them unnecessarily. If not, go back through the previous steps to make sure you’ve not missed anything.

3. Building the Nuxt module

From here, converting our Twitter script into a Nuxt module is relatively simple. At the end of your twitter.js module, write the following:

export default function NuxtTwitter(config) {
	this.nuxt.hook('build:before', generator => {
		client.get(endpoint, params, callback)
	})
}

Delete the client.get(endpoint, params, callback) line we’d previously added in the JS file, as we now only need it inside the module we’re exporting.

Similarly to before, we’re not making use of either the config or the generator arguments that are passed to the module, but they’ve been included anyway, in case we want to expand the module later.

In case you’re interested, config, in this example, is passed in via the modules array in your nuxt.config.js. When declaring which modules are to be used by Nuxt, the modules array can either accept strings, which are just the module names, or it can accept arrays. The first value in these arrays is the location of the module and the second value in these arrays is the data passed as our config argument.

The generator argument passed to our callback in the nuxt.hook contains a lot of information about the whole process. By accessing generator.options you can access your nuxt.config.js. It’s worth running the module and either logging generator to your console or printing it to a JSON file for a closer inspection. generator.options is the method used by a lot of modules to pass module options from within nuxt.config.js, but outside of the modules array.

By using this.nuxt.hook we are able to tell Nuxt to run a function when it hits a certain “hook”, which refers to a stage in its process. The first parameter: build:before, represents the stage at which to run the function. The build stage is used by both generate and dev command processes, so it covers both bases. We need to run this before we build the site, because we need to be able to import the JSON data in order to use it within our site.

Also change the first argument in your fs.outputJSON() method call from ./tweets.json to ./tweets/tweets.json.

4. Setting up Nuxt modules

Our nuxt.config.js should be exporting a config object. Find the modules property in this object. If you don’t have one, create it. The modules property is an array that tells Nuxt which modules to load when it runs. Add the file path and name to help Nuxt find your module. You can omit the .js extension in your module name. It should look like this:

module.exports = {
	// other config properties

	modules: [
		'modules/twitter'
		// any other modules used in your build
	]
}

So now, if we run yarn dev, yarn generate, npm run dev or npm run generate, depending on which package manager takes your fancy, we should find that Nuxt creates the JSON file for us. This allows us to import the data from this file into any pages/components we need.

5. Securing our API keys

Before we go pushing any of our code to public repos, let’s hide the API keys so that nobody else has access to them. If you’ve not already installed dotenv, do so now. In the root of our project, create a file called .env. By default, dotenv will take keys from this file and add them to Node’s process.env, which is part of any running Node process.

Your .env file should look something like this:

CONSUMER_KEY=
CONSUMER_SECRET=
ACCESS_TOKEN_KEY=
ACCESS_TOKEN_SECRET=

Now move the keys we added to our twitter.js client to this file, assigning them to the relevant variable. Once this is done, we’ll replace the client declaration in our twitter.js module with the following:

const client = new Twitter({
  consumer_key: process.env.CONSUMER_KEY,
  consumer_secret: process.env.CONSUMER_SECRET,
  access_token_key: process.env.ACCESS_TOKEN_KEY,
  access_token_secret: process.env.ACCESS_TOKEN_SECRET
})

We’ll also add the following beneath our Twitter and fs requires at the top of our module file:

const dotenv = require('dotenv')
dotenv.config()

By importing dotenv and calling it’s config() method, we’re adding the contents of .env into process.env, which can be accessed by Node.

Also, add .env to your .gitignore if it’s not already included. This will stop you committing the file to your repo.

6. Importing Tweets into Nuxt

With our API keys hidden away and our tweets being written to a JSON file correctly, we can now use them in our build. Just to demonstrate this, we’ll create a list of tweets on our index page. Open pages/index.vue and replace all code in the file with:

<template>
  <ul>
    <li
      v-for="tweet in tweets"
      :key="tweet.id"
    >
      {{ tweet.text }}
    </li>
  </ul>
</template>

<script>
import tweets from '@/tweets/tweets'

export default {
  data() {
    return {
      tweets
    }
  }
}
</script>

If you run yarn dev or npm run dev, you should find that the index page just lists your 5 latest tweets. Our template is importing them via the import tweets from @/tweets/tweets line in index.vue.

7. Deploying our site

In order to get our site live we need to use a deployment tool that can be triggered via webhooks and supports adding environment variables. For the purposes of this tutorial we’re going to use Netlify.

First of all, create a Netlify account if you don’t have one already. After this, choose New site from Git on Netlify App. From here we need to connect Netlify to our repository. Choose the Git provider and follow the set up process to launch your site. Netlify will deploy our site by pulling the git repository and serving our chosen folder.

In the build settings, set the build command to yarn generate and set the publish directory to dist.

Deploying from our site won’t work immediately because we need to add the API keys we hid with dotenv. In the site settings find Environment variables and add the same variables you have in your .env file.

Netlify Environment Variables

8. Setting up deployment webhooks with IFTTT

What’s the use in having a Twitter feed on our site if it doesn’t update when we tweet? We’re going to use IFTTT to solve this problem. For anyone who doesn’t know, IFTTT is a service that allows us to automate tasks with “recipes”. We’re going to have a recipe that says “When I tweet, send a request to a predetermined URL”. When Netlify receives this request, it will build the site again, causing our Nuxt module to update the list of tweets.

First of all add a build hook in the Continuous Deployment section of your Netlify site build settings, like so:

Netlify Build Hook

Now create an account on IFTTT. Once done, create a new applet by visiting IFTTT.com/create. We’ll use Twitter as our “this” trigger. Follow the process on IFTTT to connect it to our account and choose the “New Tweet by you” trigger. The “that” action should then be the webhooks service. Use the service to “make a web request”. Copy the URL for your Netlify build process, change the method to POST and then finish creating the applet.

Now, post a tweet to test that everything has worked. If it has, you should see a new deployment on the deploys page of your Netlify site.

Congratulations! You’ve now integrated a twitter feed into your statically generated Nuxt site and learned how to create your own Nuxt module.

You can see the result of this tutorial in the twitter feed at the bottom of each page of my site. I've sliced the tweets array to only show the 3 latest tweets though.

If you had any issues following this tutorial, please take a look at this demo Git repo. The commit history for which shows all of the steps taken in this tutorial.

Repo