Plugin Creation Tutorial
Backstage plugins and functionality extensions should be writen in TypeScript/Node.js because backstage is written in those languages
General Algorithm for Adding a Plugin in Backstage
Create the Plugin
To create a plugin in the project structure, you need to run the following command at the root of Backstage:yarn new --select pluginThe wizard will ask you for the plugin ID, which will be its name. After that, a template for the plugin will be automatically created in the directory
plugins/{plugin id}. After this install all needed dependencies. After this install required dependencies. In example case this is"axios"for API requests
Emaple:yarn add axiosDefine the Plugin’s Functionality
In the newly created plugin directory, focus on defining the plugin’s core functionality. This is where you will create components that handle the logic and user interface (UI) of the plugin. Place these components in theplugins/{plugin_id}/src/components/folder, and if your plugin interacts with external data or APIs, manage those interactions within these components.Set Up Routes
In the main configuration file of your plugin (typicallyplugins/{plugin_id}/src/routs.ts), set up the routes. UsecreateRouteRef()to define route references, and link them to the appropriate components in yourplugins/{plugin_id}/src/components/folder. Each route will determine which component renders for specific parts of the plugin.Register the Plugin
Navigate to thepackages/appfolder and import your plugin into the main application. Register your plugin in theroutsarray withinpackages/app/src/App.tsxto integrate it into the Backstage system. It will create a rout for your’s plugin pageAdd Plugin to the Sidebar Menu
To make the plugin accessible through the Backstage sidebar, modify the sidebar component inpackages/app/src/components/Root.tsx. Add a new sidebar item linked to your plugin’s route reference, allowing users to easily access the plugin through the menu.Test the Plugin
Run the Backstage development server usingyarn devand navigate to your plugin’s route via the sidebar or directly through its URL. Ensure that the plugin’s functionality works as expected.
Example
All steps will be demonstrated using a simple example plugin, which will request JSON files from the API of jsonplaceholder.typicode.com and display them on a page.
Creating test-plugin:
yarn new --select pluginAdding required dependencies. In this case only “axios” is needed for API requests
yarn add axiosImplement code of the plugin component in
plugins/{plugin-id}/src/{Component name}/{filename}.tsximport React, { useState } from 'react'; import axios from 'axios'; import { Typography, Grid } from '@material-ui/core'; import { InfoCard, Header, Page, Content, ContentHeader, SupportButton, } from '@backstage/core-components'; export const TestComponent = () => { const [posts, setPosts] = useState<any[]>([]); const [loading, setLoading] = useState(false); const [error, setError] = useState<string | null>(null); const fetchPosts = async () => { setLoading(true); setError(null); try { const response = await axios.get('https://jsonplaceholder.typicode.com/posts'); setPosts(response.data); } catch (err) { setError('Ошибка при получении постов'); } finally { setLoading(false); } }; return ( <Page themeId="tool"> <Header title="Welcome to the Test Plugin!" subtitle="This is a subtitle"> <SupportButton>A description of your plugin goes here.</SupportButton> </Header> <Content> <ContentHeader title="Posts Section"> <SupportButton> Click to load posts from the API. </SupportButton> </ContentHeader> <Grid container spacing={3} direction="column"> <Grid item> <InfoCard title="Information Card"> <Typography variant="body1"> This card contains information about the posts fetched from the API. </Typography> {loading && <Typography>Загрузка...</Typography>} {error && <Typography color="error">{error}</Typography>} {!loading && !posts.length && ( <button onClick={fetchPosts}>Request Posts</button> )} </InfoCard> </Grid> <Grid item> {posts.length > 0 && ( <InfoCard title="Fetched Posts"> <ul> {posts.map(post => ( <li key={post.id}> <Typography variant="h6">{post.title}</Typography> <Typography>{post.body}</Typography> </li> ))} </ul> </InfoCard> )} </Grid> </Grid> </Content> </Page> ); };Setup routs in plugins/{plugin_id}/src/routs.ts
import { createRouteRef } from '@backstage/core-plugin-api';
export const rootRouteRef = createRouteRef({
id: 'test-plugin',
});
- Register the plugin in
packages/app/src/App.tsxin routes Import of the plugin:
import { TestPluginPage } from '@internal/backstage-plugin-test-plugin';
Adding route:
const routes = (
<FlatRoutes>
... //{Other Routs}
<Route path="/test-plugin" element={<TestPluginPage />} />
</FlatRoutes>
)
- Add Item to sidebar menu of the backstage in
packages/app/src/components/Root/Root.tsx. This should be added in to Root object as another SidebarItem
export const Root = ({ children }: PropsWithChildren<{}>) => (
<SidebarPage>
<Sidebar>
... //{Other sidebar items}
<SidebarItem icon={ExtensionIcon} to="/test-plugin" text="Test Plugin" />
</Sidebar>
{children}
</SidebarPage>
);
- Plugin is ready. Run the application
yarn dev
