This post deals with building a VS Code extension using React, Typescript and Tailwind CSS.
So, you've decided to build a VS Code extension. Great choice! You want to fetch and display content from an API, because, let's face it, hardcoding stuff is so 90s. Buckle up, because we're about to embark on a journey that will involve code, APIs, and probably a few cups of coffee. Let's keep it fun and functional, shall we?
PAGE CONTENT
- Prerequisites
- Getting Started
- Setting Up Your Workspace
- Fetching Data from an API
- Displaying API Content
- Conclusion
PREREQUISITES
Before we begin, make sure you have the following installed:
- Node.js (for running JavaScript/TypeScript)
- Visual Studio Code (your coding sanctuary)
STEP 1: GETTING STARTED
First things first, fire up VS Code and create a new project. If you're like me, you spend a good 10 minutes deciding on the project name - because naming things is the hardest part of programming, right?
Creating Your Project Directory
Create a folder and open it with VS Code.
mkdir my-vscode-extension
cd my-vscode-extension
You'll see the below:
Creating an Extension
Now open the VS Code terminal.
Install Yeoman
and VS Code Extension Generator:
If you haven't already installed Yeoman and the VS Code Extension Generator, do so globally using npm
:
npm install -g yo generator-code
Generate Your Extension:
Run the Yeoman generator to scaffold out your VS Code extension project:
yo code
Select Typescript and proceed.
Follow the prompts in the terminal:
This will create a basic structure for your VS Code extension project.
Now select 'Open with code' and jump to the next step.
Explore Your Extension Structure:
You should see something like the below:
The generator sets up a basic folder structure and files including:
-
src/extension.ts
: Entry point for your extension -
package.json
: Contains extension metadata and scripts -
tsconfig.json
: TypeScript configuration file -
.vscode/
: VS Code-specific configuration
For more details on what each file is about, go to anatomy.
Creating Your React App
For this and next step, I would highly recommend to go to BestAmazingPost
although I have given an overview.
Create a React app with typescript in the root directory (in my case Quotebee).
Give any name you want. In this case, it is bee
npx create-react-app bee --template typescript
cd bee
So now your final project structure should look something like this:
And yay! You are set to configure your workspace.
STEP 2: SET UP YOUR WORKSPACE
Now, let's configure our workspace. In this section, we will make necessary changes to the following files and install dependencies to make a basic working extension.
Set up Tailwind:
Inside react app bee, set up tailwindcss
npm i -D tailwindcss postcss
npx tailwindcss init
This will generate a file tailwind.config.js
file in your project directory.
Edit tailwind.config.js
module.exports = {
content: ['./src/**/*.{js,jsx,ts,tsx}'],
theme: {
extend: {},
},
plugins: [],
}
Edit bee/src/index.css
@tailwind base;
@tailwind components;
@tailwind utilities;
body {
@apply p-0;
}
Create postcss.config.js
file:
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};
Edit App.tsx
in bee/src/App.tsx
function App() {
return (
<div className="bg-gradient-to-r from-pink-700 to-blue-700 p-10">
<p className="text-white/80 text-xl font-semibold">
DEV
</p>
</div>
);
}
export default App;
Set up Parcel
You may use any bundler though!
npm i -D parcel
Edit package.json
of react app directory
//bee/package.json
{
"source": "src/index.tsx",
"scripts": {
"start": "parcel",
"build": "parcel build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
}
Run Parcel
npm start
Run npm run compile
in root directory.
This should create an out
folder.
npm run compile
Edit extension.ts
import * as vscode from 'vscode';
export function activate(context: vscode.ExtensionContext) {
let webview = vscode.commands.registerCommand('quotebee.helloWorld', () => {
let panel = vscode.window.createWebviewPanel("webview", "Quotebee", vscode.ViewColumn.Two, {
enableScripts: true
});
// Paths to resources
let scriptSrc = panel.webview.asWebviewUri(vscode.Uri.joinPath(context.extensionUri, "bee", "dist", "index.js"))
let cssSrc = panel.webview.asWebviewUri(vscode.Uri.joinPath(context.extensionUri, "bee", "dist", "index.css"))
const apiUrl = 'https://quotes-api-self.vercel.app/quote';
panel.webview.html = `<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="${cssSrc}" />
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root" data-api-url="${apiUrl}"</div>
<script src="${scriptSrc}"></script>
</body>
</html>
`;
});
context.subscriptions.push(webview);
}
export function deactivate() { }
NOTE: Make sure to edit your trigger command. In my case it is quotebee.helloWorld
. It should be consistent in package.json too!
NOTE AGAIN: Make sure VScode version is same in Help->About
, package.json and package-lock.json.
Woohoo! Now grab a bucket (of enthusiasm) and go fetching! (from API)
FETCHING DATA FROM API
In modern web development, dynamic content is often fetched from APIs. APIs, or Application Programming Interfaces, provide a way for different software applications to communicate with each other.
We'll use the https://quotes-api-self.vercel.app/quote API, which generates random quotes. This simple API returns a JSON response with a quote and its author. Let's break down how to fetch and display this data in a React component.
API Working Diagram
Before we charge ahead, let’s map out our journey with a simple diagram to understand how the API call works:
- The React component sends a request to the wise Quotes API.
- The Quotes API responds with a JSON scroll containing a random quote and its author.
- The React component processes this data and updates the UI to display the quote and author.
There are many functions used to fetch content from API and you can read them from here.
CODE OVERVIEW
- Setup React Component: We’ll use React's functional component and hooks (useState and useEffect) to manage the state and lifecycle of the component.
- State Management: We’ll define state variables to store the fetched quote and author.
- Fetch Data: We’ll use the fetch function inside a useEffect hook to make an API request when the component mounts.
- Display Data: We’ll display the fetched quote and author in the component's JSX.
BUILDING THE CODE
Imports: We import useState and useEffect from React to manage state and side effects.
import React, { useState, useEffect } from 'react';
Component Definition: We define a functional component App.
function App() {
State Variables: We declare state variables quote and author using the useState hook.
const [quote, setQuote] = useState('');
const [author, setAuthor] = useState('');
Fetching Data: Inside the useEffect hook, we define and call the fetchQuote function to fetch data from the API. The fetch function sends a GET request to the API, and we process the JSON response to update the state.
useEffect(() => {
const fetchQuote = async () => {
try {
const response = await fetch('https://quotes-api-self.vercel.app/quote');
const data = await response.json();
setQuote(data.quote); // Set the quote
setAuthor(data.author); // Set the author
} catch (error) {
console.error('Error fetching quote:', error);
}
};
fetchQuote();
}, []); // Empty dependency array means this effect runs once after the initial render
Rendering Data: We use JSX to display the quote and author. If the quote is not yet fetched, we show a loading message. The author's name is displayed conditionally only if it's available.
return (
<div className="bg-gradient-to-r from-pink-700 to-blue-700 p-10">
<p className="text-white/80 text-xl font-semibold">
{quote ? `"${quote}"` : 'Loading...'}
</p>
{author && (
<p className="text-white/60 text-lg font-medium">
- {author}
</p>
)}
</div>
);
Export Component: Finally, we export the App component.
export default App;
THE CODE
import React, { useState, useEffect } from 'react';
function App() {
const [quote, setQuote] = useState('');
const [author, setAuthor] = useState('');
useEffect(() => {
// Function to fetch data from the API
const fetchQuote = async () => {
try {
const response = await fetch('https://quotes-api-self.vercel.app/quote');
const data = await response.json();
setQuote(data.quote); // Set the quote
setAuthor(data.author); // Set the author
} catch (error) {
console.error('Error fetching quote:', error);
}
};
fetchQuote();
}, []); // Empty dependency array means this effect runs once after the initial render
return (
<div className="bg-gradient-to-r from-pink-700 to-blue-700 p-10">
<p className="text-white/80 text-xl font-semibold">
{quote ? `"${quote}"` : 'Loading...'}
</p>
{author && (
<p className="text-white/60 text-lg font-medium">
- {author}
</p>
)}
</div>
);
}
export default App;
DISPLAYING THE CONTENT
The output of what we have made so far is this:
Each time you open the extension, it will display a random quote.
Is this the best UI we can make? Absolutely not! That depends on how much of a UI wizard you are! Explore the various panes of VS Code from here and decide on what's good for your purpose!
CONCLUSION
You've made it to the end, and that's no small feat! It's been amazing to have you here, and I hope you've enjoyed this coding journey as much as I have.
In this blog, we learned how to fetch data from an API and display it in a React application. We used the fetch function to retrieve data from the Quotes API and employed React hooks to manage the state and lifecycle of our component. This approach can be extended to other APIs and data sources, making it a powerful tool for building dynamic, data-driven applications.
By mastering the art of fetching and displaying data in React, you can create more interactive and engaging user experiences. Now, go forth and may your code be ever bug-free and your APIs responsive! Happy coding!😀
Top comments (0)