17
Build a Link Shortener with Cloudflare Workers: The front-end
In this part of the tutorial, we'll build a front-end atop our back-end to let users input a long link and get a short link back. Our front-end will be a simple Vue application that just interfaces with our POST /links
endpoint, and will be served up using Workers Sites.
If you haven't gone through the back-end part of this tutorial yet to set up the routes this front-end depends on, head back to that part first!
In the back-end part of this tutorial, we used Workers KV to store key-value pairs of slugs for long URLs. What Workers Sites allows you to do is automatically upload your site's static content to a KV namespace as well, where it can be retrieved and displayed by your Worker.
These assets are stored in another namespace that Wrangler can create for you, and your Worker can retrieve using the kv-asset-handler package. In our Worker code, we can grab the correct asset depending on the request it receives.
To get started, in your project directory, install the kv-asset-handler package: npm i @cloudflare/kv-asset-handler
To make this work, we'll need to re-structure our project folder a bit:
Move the
index.js
,package.json
andpackage-lock.json
from the project root into their own folder, which we'll callworkers-site
.Create a
public
directory in your project root, with astatic
subdirectory in it.Modify your
wrangler.toml
file to add this section at the bottom:
[site]
bucket = "./public"
entry-point = "workers-site"
Going forward, Wrangler will now upload your static assets in public
to their own KV namespace.
At the end of these steps, your folder structure should look something like this (assuming the project root is called redirect
):
redirect
| wrangler.toml
└───public
└───static
└───workers-site
└───index.js
└───package.json
└───package-lock.json
First, copy the stylesheet from the finished project into your public/static
directory.
Afterwards, copy the index.html
file from the finished project directly into the public
folder. This tutorial won't focus on the specifics of Vue too much, but let's explore what the code is doing. Looking at this section of the code (line 16-32):
<form @submit.prevent="handleUrlSubmit">
<input
type="text"
id="input-url"
name="url"
size="40"
placeholder="https://google.com"
required
v-model="longUrl"
/>
<input type="submit" id="input-submit" value="Shorten" />
</form>
<div class="message" v-if="shortUrl">
<p>Your new shortened URL is:</p>
<h2>{{ shortUrl }}</h2>
</div>
First, we've created a data binding on our form inputs using the v-model
directive. Whenever the input box for the URL is updated, the longUrl
data property will be updated.
We register an event listener for the submit
event on this form. The handleUrlSubmit
method we define will take care of interacting with the endpoint we defined before, and will update the shortUrl
data property. Once this is available, the URL will be displayed to the user (visibility toggled by the v-if
directive).
Taking a look at the handleUrlSubmit
method on the Vue app:
methods: {
handleUrlSubmit() {
fetch('/links', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
url: this.longUrl,
}),
})
.then((response) => {
if (response.status == 200) {
this.error = false;
return response.json();
} else {
throw new Error('Issue saving URL');
}
})
.then((data) => {
this.shortUrl = data.shortened;
})
.catch((error) => {
this.error = true;
});
},
}
Here we're doing a fetch
request (with very little error handling) to our /links
endpoint, and retrieving the shortened
value from the API response. The shortUrl
data property gets set to this value, and the shortened URL is displayed to the user.
There are two scenarios where we'd want to render static assets:
- A user visits the homepage (i.e. the path is
/
) - A static asset is requested (e.g
/static/style.css
)
To intercept these requests, while still responding to requests to our API endpoints, we can define a middleware function. This would either pass the fetch event to the router or kv-asset-handler
's getAssetFromKV
function, which consumes a FetchEvent
and returns a Response
based on what's stored in the KV namespace for static assets.
Open up index.js
. First, import the getAssetFromKV
function:
import { getAssetFromKV } from '@cloudflare/kv-asset-handler';
Then, let's write our function to pass the event/request around:
async function handleEvent(event) {
let requestUrl = new URL(event.request.url);
if (requestUrl.pathname === '/' || requestUrl.pathname.includes('static')) {
return await getAssetFromKV(event);
} else {
return await router.handle(event.request);
}
}
Note that our route handlers currently take in a Request
object, while the getAssetFromKV
function takes in the whole FetchEvent
. Next, let's hook into this function on our fetch event listener. Modify the listener from:
addEventListener('fetch', event => {
event.respondWith(router.handle(event.request))
})
to:
addEventListener('fetch', event => {
event.respondWith(handleEvent(event));
});
With these changes made, it's time to take the Worker for a test spin! Run wrangler dev
. Notice you'll get a bit of extra output as your static assets get populated into their own KV namespace:
$ wrangler dev
🌀 Using namespace for Workers Site "__redirect-workers_sites_assets_preview"
✨ Success
👂 Listening on http://127.0.0.1:8787
And, you should be able to see it in action:
Note your URL might look a little different. If you now take this key and append it to the URL in your address bar (e.g 127.0.0.1:8787/nFXAau
for me), it should redirect! Our routing has been set up properly.
If you peek at your KV namespace for the static assets in your dashboard, you should see them listed:
The front-end is ready to go and now it's time to deploy our application with Wrangler. In the next part of this tutorial we'll deploy the link shortener -- we're almost there!
17