使用 Next.js 的 Github 包搜索应用程序

作为开发的一部分,我们每天使用 google 在 Github 中搜索开源包。这将是一个耗时的过程,因为我们需要搜索关键字,进入每个 Github 存储库以检查以下项目以选择包:

更改它或用于商业应用程序是完全开源的吗?
是没有存档还是有一些活跃的 区在为它工作?
它有很多问题吗?
此存储库中使用的语言是什么?
包的大小是多少,所以它不会使我的项目变得更笨重?
最近的更新是什么时候发生的?
我想开发一个简单的搜索应用程序,我们可以在其中一次性获得选择包所需的所有信息。它还将帮助任何开发团队作为选择 Github 包的便捷工具。

Github 提供了一个搜索 API来搜索存储库中的搜索词,并为每个存储库获取详细信息,例如分支、标签和贡献者,并将其显示为单个视图。我们选择Next.js,因此我们可以在后端搜索并仅在客户端呈现内容。它提供了一个免费的部署工具来进行部署,并且可以公开使用。

Next.js 的领导者
Next.js 是 react.js 框架的服务端渲染,它支持我们创建单页 Web 应用程序。它拥有开发生产就绪型 Web 应用程序所需的一切——生产型SSR Web UI 应用程序:混合静态和服务器渲染、TypeScript 支持、智能捆绑、路由预取等。要了解有关 Next.js 的更多信息,请查看其官方 站。

项目设置
先决条件是拥有 node.js 12.2.0 或更高版本。

我们可以通过一个简单的命令创建下一个支持 TypeScript的应用程序:

npx create-next-app@latest –ts

要开始现有项目,请在根文件夹中创建一个空的 tsconfig.json 文件:

touch tsconfig.json

项目启动
然后,运行 next(通常是 npm run dev 或 yarn dev),Next.js 将引导您安装所需的包以完成设置:

npm run dev

安装Chakra UI

我使用Chakra UI来准备更快地使用组件来构建 UI。它提供了 Box 和 Stack 布局组件,通过 props 可以很容易地为你的组件设置样式。

npm i @chakra-ui/react @emotion/react@^11 @emotion/styled@^11 framer-motion@^6

搜索应用:

目的是提供搜索关键字并获取 Github 中可用的存储库列表,其中包含所有基本信息,如下所示:

Next.js 应用程序以 index.tsx 页面开头。在那里,我创建了服务器端 props 函数,该函数将负责在页面到达客户端之前服务器调用以获取页面的数据。在这个函数中,我们使用了Github 搜索存储库 API。在 UI 中提供搜索文本,并将响应与所需信息一起提取到 repoItem 模型中。

export const getServerSideProps = async ({
query,
}: GetServerSidePropsContext<QueryParams>): Promise<GetStaticPropsResult<ContentPageProps>> => {
console.log(“context.query :>> “, query);

if (!query || !query?.q) {
return { props: { repos: [], searchText: “”, count: 0 } };
}
const searchText: string = `${query.q}`;
const url = `https://api.github.com/search/repositories?q=${query?.q}`;
const token: RequestInit = {
headers: [
[“Authorization”, `${process.env.token}`],
[“Accept”, “application/vnd.github.v3+json”]
],
method: “GET”,
};
const res = await fetch(url, token);
const data = await res.json();
// console.log(‘data :>> ‘, data);
const repos: RepoItem[] = data.items.map((item: any) => {
const repo = {
id: item.id,
language: item.language,
name: item.name,
full_name: item.full_name,
description: item.description,
stars: item.stargazers_count,
watchers: item.watchers_count,
forks: item.forks,
homepage: item.homepage,
topics: item.topics,
tags: item.tags_url,
size:item.size,
issue: item.open_issues_count,
contributors: item.contributors_url,
archived: item.archived,
visibility: item.visibility,
updated_at: item.updated_at,
license: item.license,
owner: item.owner,
has_wiki: item.has_wiki
};
return repo;
});
const results = { repos: repos, searchText: searchText, count: data.total_count || 0 };
return { props: results };
};
搜索框是一个表单组件,我们允许用户输入搜索文本,并在提交表单时,它会使用查询字符串到达后端。后端是 serversideprops,它反过来会触发 Github API 来获取搜索关键字的匹配存储库(如上所述)。

需要注意的一件事是我没有使用 onchange 因为它会在每次按键时触发。相反,我在提交按钮时使用了 useRef 来获取输入值。

搜索结果将使用自定义组件显示 – RepoContainer 用于 VStack 布局 组件下的每个 RepoItem 数据。

<VStack>
<Spacer />
{repos && repos.map((repoItem: RepoItem) => <RepoContainer key={repoItem.id} repo={repoItem} />)}
</VStack>

每个 RepoItem 由以下代码片段中的注释标记的四个堆栈组件组成。第一个堆栈组件由存储库名称、全名和语言详细信息组成。在第二个堆栈中,保留了标记、分支、包大小、许可证和所有者等元数据。第三个堆栈,存储库如何稳定和积极更新,第四个堆栈显示存储库 区的受欢迎程度。

<Box
color={useColorModeValue(“gray.700”, “gray.200”)}
w={“100%”}
borderRadius={10}
bg=”#B1F1F3″
>
<Container as={Stack} maxW={“9xl”} py={10}>
<SimpleGrid templateColumns={{ sm: “1fr 1fr”, md: “2fr 2fr 2fr 2fr” }} spacing={3}>
<Stack>{/* First stack component */}
<ListHeader>{repo?.name}</ListHeader>
<Text fontSize={“sm”}>
<NextLink href={`https://github.com/${repo?.full_name}`} passHref>
<Link color=”blue”>{repo?.full_name}</Link>
</NextLink>
</Text>
<Stack direction={“row”} mt={10}>
<Text fontSize={“sm”}>
Language:{” “}
<Badge colorScheme=”red” variant=”solid”>
{repo.language}
</Badge>
</Text>
</Stack>
<Stack direction={“row”}>frameworks :</Stack>
</Stack>

<Stack align={“flex-start”} fontSize={“sm”}>{/* Second stack component */}
<Stack direction={“row”} align={“center”}>
{/* <Text>Releases </Text> */}
<GoTag /> <Tags url={repo.tags} />
<GoGitBranch /> <Branches repo={repoName} />
</Stack>
<Text>Size of the package : {Math.round((repo.size / 32768) * 100) / 100} MB </Text>
<Text>License : {repo.license?.name ? repo.license?.name:”None”} </Text>
<Text>Owner : <Avatar src={repo?.owner?.avatar_url} size=’xs’ /> {repo?.owner?.login}</Text>
</Stack>
<Stack align={“flex-start”} fontSize={“sm”}>{/* Third stack component */}
<Stack direction={“row”} align={“center”}>
<GoIssueOpened /> <Text>Issues :{repo.issue} |</Text>
<GoOrganization /> <Contributors url={repo.contributors} icon={<GoOrganization />} />
</Stack>
<Stack direction={“row”} align={“center”}>
<GoArchive />
<Text style={{ color: repo.archived ? ‘red’: ‘black’}}> IsArchived: {repo.archived ? “true” : “false”} |</Text>
<GoEye />
<Text> Visibility: {repo.visibility}</Text>
</Stack>
<Stack direction={“row”} align={“center”}>
<GoWatch /> <Text>Last Updated : {updatedTime}</Text>
</Stack>
<Stack direction={“row”} align={“center”}>
<GoGitPullRequest /> <PR repo={repoName} />
</Stack>
</Stack>
<Stack align={“flex-start”}>{/* Fourth stack component */}
<Stack direction={“row”} align={“center”}>
<GoStar /> <Text>{repo.stars} |</Text> <GoRepoForked /> <Text>{repo.forks} |</Text>
<GoEye /> <Text>{repo.watchers} </Text>
</Stack>
<NextLink href={`${repo.homepage}`} passHref>
<Link color=”blue”>Homepage</Link>
</NextLink>
{/* <Text>Examples</Text> */}
{repo.has_wiki ? (
<NextLink href={`https://github.com/${repo?.full_name}/wiki`} passHref>
<Link color=”blue”>Wiki Link</Link>
</NextLink>
): “”}
</Stack>
</SimpleGrid>
<SimpleGrid>{/* Repo description */}
<Text>Description :{repo.description}</Text>
</SimpleGrid>
<SimpleGrid>{/* Repo Topics */}
<Stack direction={“row”} align={“center”}>
<Wrap>
{repo.topics &&
repo.topics.map((res: string) => (
<>
<WrapItem key={res}>
<Badge variant=”solid” colorScheme=”messenger” >
{res}
</Badge>
</WrapItem>
</>
))}
</Wrap>
</Stack>
</SimpleGrid>
</Container>
</Box>

最后,保留描述和Github主题,以了解项目。

如果你敏锐地注意到,有像 Branches 和 Prs 这样的组件,它们会对自定义组件做出反应。加载 repo 容器后,它将异步呈现。

让我们仔细看看 PR 组件;它返回一个带有 pr 计数的 div 标签。PR 计数在搜索存储库调用中不直接可用。还要进行一次调用来获取 pr 计数,因此我们使用API 路由。反过来,此 API 路由使用令牌调用 Github API 并获取拉取请求的计数。此计数计算负载已委托给后端。

这里 reponame 通过 props 传递给组件,在 fetch API 调用后解析计数状态。
interface propTypes {
repo: string;
}

function PR(props: propTypes) {
const { repo } = props;
const [count, setCount] = useState(0);
useEffect(() => {
if (repo) {
fetch(`/api/prcounts?repo=${repo}`).then((res) => res.json()).then(res => {
const prcount = res.data;
setCount(prcount);
});
} else {
setCount(0);
}
}, [repo])
return (
<div className=’center’> Pull Request : {count}</div>
)
}

export default PR

在 pages/api/pr.ts 文件中,我们调用 Github API 调用,获取拉取请求,并找到拉取请求的计数。然后将拉取请求值以 JSON 格式(如 {data:prcount})返回到前端。

type ResponseData = {
data: string
}

export default function handler(
req: NextApiRequest,
res: NextApiResponse<ResponseData>
) {
const repoName: string = `${req.query.repo}`;
const url = new URL(`https://api.github.com/repos/${repoName}/pulls`);
const options = { ‘headers’ : {
‘Authorization’: process.env.token,
‘Accept’: “application/vnd.github.v3+json”,
‘User-Agent’: ‘Mozilla/5.0’
},
‘method’: ‘GET’,
};

const clientreq: ClientRequest = https.request(url, options, (apiresponse: IncomingMessage) => {
let respJson: string = “”;

apiresponse.on(‘data’, (chunk: string) => {
respJson += chunk;
});

apiresponse.on(‘end’, () => {
if (apiresponse.statusCode === 200) {
let prResponses = JSON.parse(respJson);
const prCounts = prResponses.length;
res.status(200).json({‘data’: prCounts});
}
})
});

clientreq.on(‘error’, (e: Error) => {
console.error(‘error message’, e.message);
});
clientreq.end();
}

我为分支和贡献者制作了相同的模式,例如调用 API 路由以从 Github API 获取数据的反应组件。

完整的源代码可供参考。

部署使用。

我的计划是扩展这个应用程序并获取更多信息,如测试构建状态、演示页面,并在搜索结果中删除分叉重复项。也渴望从您那里获得反馈,例如您是否需要在搜索包方面查看更多信息或更多选项。请放在下面的评论部分。

谢谢大家阅读,喜欢的朋友请关注,评论,点赞。转发,带你了解最新技术趋势。

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2022年7月27日
下一篇 2022年7月27日

相关推荐