
開發者作品集是一個工作樣本和專案的集合,展示你的技能和經驗。在尋找工作時,一個強大的作品集使你從其他候選人中脫穎而出。但不僅如此。作品集也可以是一個有用的工具,用於建立網路,跟蹤你的學習情況,並最終將自己打造成一個主題專家。
在本教程中,你將學習如何使用Next.js建立一個開發者作品集,並直接從你的GitHub倉庫部署到應用託管平臺。
要求/前提條件
這是一個 “跟隨 “型別的教程。如果你有的話,你會更容易跟著編碼:
- 具有HTML、CSS和JavaScript的基本知識
- 有一點React的知識,也許還有Next.js的知識
- 在你的電腦上安裝Node.js和npm(Node Package Manager)或yarn
文章目錄
- 為什麼選擇Next.js?
- 如何設定你的Next.js開發環境
- 如何使用Next.js構建一個響應式的開發者組合
- 如何將Next.js應用程式部署到伺服器
為什麼選擇Next.js?
Next.js是一個基於React的開源JavaScript庫框架,可用於廣泛的網路開發專案,因為它簡化了構建伺服器端渲染和靜態應用程式。它通過利用React的最佳功能和優化渲染效能來提高使用者體驗,從而簡化了這一過程。Next.js的一些最常見的用例包括:
- 構建靜態網站。Next.js可以構建快速、易於部署、需要最少維護的靜態網站,比如我們在本教程中要構建的開發者組合網站。
- 構建動態網站。Next.js允許你建立動態網站,可以根據使用者的互動或伺服器端的資料獲取來改變內容。
- 提高網站效能。使用伺服器端渲染,Next.js可以通過減少頁面載入的時間來提高網站效能。
- 構建電子商務網站。Next.js非常適用於構建需要伺服器端渲染的電子商務網站,以提高SEO和效能。
- 構建漸進式網路應用程式(PWA)。Next.js支援建立PWA,這是一種網路應用,其功能類似於本地應用,可以安裝在使用者的裝置上。
如何設定你的Next.js開發環境
要為Next.js建立一個開發環境,首先要在你的電腦上安裝Node.js,因為你將使用 npx
命令來執行npm包,而不必在你的系統上全域性安裝它們。處理好這些後,你就可以通過執行以下命令來建立Next.js專案了:
npx create-next-app@latest my-portfolio
npx create-next-app@latest my-portfolio
npx create-next-app@latest my-portfolio
會出現一個提示,要求你確認一些額外的依賴性。然後你可以執行 npm run dev
,使你的應用程式在localhost:3000上可用。

建立一個新的Next.js專案。
在使用 npx
命令建立Next.js專案時,它會自動建立一個包含以下主要目錄的資料夾結構:
- pages:這個資料夾包含了應用程式的頁面,這些頁面會根據其檔名自動進行路由。例如,pages/index.js是主頁,而pages/about.js則是關於頁面。
- public:這個資料夾包含可以直接提供的靜態檔案,如圖片、字型和其他資產。
- components:這個資料夾是可選的,包含可重複使用的UI元件,可以在整個應用程式中使用。
- styles:這個資料夾也是可選的,它包含可在整個應用程式中應用的全域性樣式。
其他目錄和檔案也可能根據具體的配置和功能生成,但這些是基本Next.js專案的核心目錄。
在本教程中,我們建立的一切都將出現在索引頁(我們的單頁網站)上,你將包括英雄、關於、專案等各個部分的元件。
如何使用Next.js構建一個響應式的開發者組合
一個作品集通常由這樣的部分組成:
- 導航欄元件
- Banner元件
- 關於元件
- 技能元件
- 專案元件
- 聯絡人元件
- 頁尾元件
如果作品集有一個以上的頁面,導航條和頁尾元件應該出現在所有的頁面上。這可以在Next.js中通過定義一個佈局來實現。
在Next.js中定義佈局
在Next.js中,佈局是為網站每個頁面上出現的元件定義一致結構的一種方式。佈局通常包括在所有網站頁面上顯示的標題、導航選單和頁尾等元素。
首先,在Next.js專案的src(源)目錄下建立一個元件資料夾。接下來,建立將在Layout元件中使用的Navbar和Footer元件。
下面是Navbar.jsx中的Navbar元件:
import Link from "next/link";
<div className="nav-container">
<a href="" className="cta-btn">Resume</a>
// components/Navbar.jsx
import Link from "next/link";
const Navbar = () => {
return (
<div className="nav-container">
<div className="logo">
<Link href="/">
Joe's Portfolio
</Link>
</div>
<a href="" className="cta-btn">Resume</a>
</div>
)
}
export default Navbar;
// components/Navbar.jsx
import Link from "next/link";
const Navbar = () => {
return (
<div className="nav-container">
<div className="logo">
<Link href="/">
Joe's Portfolio
</Link>
</div>
<a href="" className="cta-btn">Resume</a>
</div>
)
}
export default Navbar;
這裡是Footer.jsx中的Footer元件:
<div className="footer-container">
© {new Date().getFullYear()} Joel's Portfolio
<div className="social_icons">
href="https://twitter.com/olawanle_joel"
rel="noopener noreferrer"
<i className="fa-brands fa-twitter"></i>
href="https://github.com/olawanlejoel"
rel="noopener noreferrer"
<i className="fa-brands fa-github"></i>
href="https://www.linkedin.com/in/olawanlejoel/"
rel="noopener noreferrer"
<i className="fa-brands fa-linkedin"></i>
// components/Footer.jsx
const Footer = () => {
return (
<>
<hr/>
<div className="footer-container">
<p>
© {new Date().getFullYear()} Joel's Portfolio
</p>
<div className="social_icons">
<a
href="https://twitter.com/olawanle_joel"
aria-label="Twitter"
target="_blank"
rel="noopener noreferrer"
>
<i className="fa-brands fa-twitter"></i>
</a>
<a
href="https://github.com/olawanlejoel"
aria-label="GitHub"
target="_blank"
rel="noopener noreferrer"
>
<i className="fa-brands fa-github"></i>
</a>
<a
href="https://www.linkedin.com/in/olawanlejoel/"
aria-label="LinkedIn"
target="_blank"
rel="noopener noreferrer"
>
<i className="fa-brands fa-linkedin"></i>
</a>
</div>
</div>
</>
)
}
export default Footer;
// components/Footer.jsx
const Footer = () => {
return (
<>
<hr/>
<div className="footer-container">
<p>
© {new Date().getFullYear()} Joel's Portfolio
</p>
<div className="social_icons">
<a
href="https://twitter.com/olawanle_joel"
aria-label="Twitter"
target="_blank"
rel="noopener noreferrer"
>
<i className="fa-brands fa-twitter"></i>
</a>
<a
href="https://github.com/olawanlejoel"
aria-label="GitHub"
target="_blank"
rel="noopener noreferrer"
>
<i className="fa-brands fa-github"></i>
</a>
<a
href="https://www.linkedin.com/in/olawanlejoel/"
aria-label="LinkedIn"
target="_blank"
rel="noopener noreferrer"
>
<i className="fa-brands fa-linkedin"></i>
</a>
</div>
</div>
</>
)
}
export default Footer;
注意:為了讓Font Awesome圖示發揮作用,你必須將Font Awesome安裝到你的專案中或使用其CDN。你可以像這樣把CDN連結新增到你的_document.js檔案中:
import { Html, Head, Main, NextScript } from 'next/document';
export default function Document() {
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css"
integrity="sha512-MV7K8+y+gLIBoVD59lQIYicR65iaqukzvf/nwasF0nqhPay5w/9lJmVM2hMDcnK1OnMGCdVK+iQrJ7lzPJQd1w=="
referrerpolicy="no-referrer"
// pages/_document.js
import { Html, Head, Main, NextScript } from 'next/document';
export default function Document() {
return (
<Html lang="en">
<Head>
<meta charSet="utf-8" />
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css"
integrity="sha512-MV7K8+y+gLIBoVD59lQIYicR65iaqukzvf/nwasF0nqhPay5w/9lJmVM2hMDcnK1OnMGCdVK+iQrJ7lzPJQd1w=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
/>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
// pages/_document.js
import { Html, Head, Main, NextScript } from 'next/document';
export default function Document() {
return (
<Html lang="en">
<Head>
<meta charSet="utf-8" />
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css"
integrity="sha512-MV7K8+y+gLIBoVD59lQIYicR65iaqukzvf/nwasF0nqhPay5w/9lJmVM2hMDcnK1OnMGCdVK+iQrJ7lzPJQd1w=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
/>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
注意:如果你通過CDN連結了不同版本的Font Awesome,你將需要在該版本上面交換相應的 integrity
雜湊。
在為你的佈局建立了所有必要的元件後,你可以建立Layout元件本身,並通過將你的頁面內容包裹在其中,將這個元件新增到你的頁面中。
佈局元件將接受一個>code>children道具,允許你訪問Next.js頁面的內容。
import Navbar from './navbar';
import Footer from './footer';
const Layout = ({ children }) => {
// components/Layout.jsx
import Navbar from './navbar';
import Footer from './footer';
const Layout = ({ children }) => {
return (
<>
<Navbar />
<main>{children}</main>
<Footer />
</>
)
}
export default Layout;
// components/Layout.jsx
import Navbar from './navbar';
import Footer from './footer';
const Layout = ({ children }) => {
return (
<>
<Navbar />
<main>{children}</main>
<Footer />
</>
)
}
export default Layout;
在這一點上,你已經成功地建立了Layout元件,它將導航條和頁尾與子項道具一起正確定位。現在你可以通過將頁面內容包裹在Layout元件中,將其新增到你的頁面中。這將在_app.js檔案中完成。
import '@/styles/globals.css';
import Layout from '../components/layout';
export default function App({ Component, pageProps }) {
<Component {...pageProps} />
// pages/_app.js
import '@/styles/globals.css';
import Layout from '../components/layout';
export default function App({ Component, pageProps }) {
return (
<Layout>
<Component {...pageProps} />
</Layout>
);
}
// pages/_app.js
import '@/styles/globals.css';
import Layout from '../components/layout';
export default function App({ Component, pageProps }) {
return (
<Layout>
<Component {...pageProps} />
</Layout>
);
}
你現在已經成功地為你的開發者組合建立了一個佈局。對於這個作品集,我們更關注Next.js以及如何將你的網站部署到Kinsta。所以你可以把styles/globals.css檔案中的樣式複製到自己的專案中。如果你在開發模式下啟動你的作品集網站,你現在應該看到你的應用程式的佈局。

佈局元件
現在是時候給你的作品集網站提供適當的內容了。
構建作品集元件
你現在可以為你的開發者的作品集的每個部分建立單獨的元件。所有這些元件將被匯入你的Next.js專案的索引頁,所以當你用 npm run dev
啟動你的專案時,它們可以顯示出來。
Hero元件
Hero元件是導航條下面的第一個部分,其主要目的是吸引使用者的注意力,讓他們感覺到網站或應用程式是關於什麼的。
import Image from "next/image";
<div className="hero-container">
<Image src='/images/profile.jpeg' className="profile-img" width={300} height={300} alt="Joe's personal headshot" />
<div className="hero-text">
I'm a software developer based in Lagos, Nigeria. I specialize in building (and occasionally designing)
exceptional websites, applications, and everything in between.
<div className="social-icons">
href="https://twitter.com/olawanle_joel"
rel="noopener noreferrer"
<i className="fa-brands fa-twitter"></i>
href="https://github.com/olawanlejoel"
rel="noopener noreferrer"
<i className="fa-brands fa-github"></i>
href="https://www.linkedin.com/in/olawanlejoel/"
rel="noopener noreferrer"
<i className="fa-brands fa-linkedin"></i>
// components/Hero.jsx
import Image from "next/image";
const Hero = () => {
return (
<div className="hero-container">
<Image src='/images/profile.jpeg' className="profile-img" width={300} height={300} alt="Joe's personal headshot" />
<div className="hero-text">
<h1>Hey, I'm Joe 👋</h1>
<p>
I'm a software developer based in Lagos, Nigeria. I specialize in building (and occasionally designing)
exceptional websites, applications, and everything in between.
</p>
<div className="social-icons">
<a
href="https://twitter.com/olawanle_joel"
aria-label="Twitter"
target="_blank"
rel="noopener noreferrer"
>
<i className="fa-brands fa-twitter"></i>
</a>
<a
href="https://github.com/olawanlejoel"
aria-label="GitHub"
target="_blank"
rel="noopener noreferrer"
>
<i className="fa-brands fa-github"></i>
</a>
<a
href="https://www.linkedin.com/in/olawanlejoel/"
aria-label="LinkedIn"
target="_blank"
rel="noopener noreferrer"
>
<i className="fa-brands fa-linkedin"></i>
</a>
</div>
</div>
</div>
)
}
export default Hero;
// components/Hero.jsx
import Image from "next/image";
const Hero = () => {
return (
<div className="hero-container">
<Image src='/images/profile.jpeg' className="profile-img" width={300} height={300} alt="Joe's personal headshot" />
<div className="hero-text">
<h1>Hey, I'm Joe 👋</h1>
<p>
I'm a software developer based in Lagos, Nigeria. I specialize in building (and occasionally designing)
exceptional websites, applications, and everything in between.
</p>
<div className="social-icons">
<a
href="https://twitter.com/olawanle_joel"
aria-label="Twitter"
target="_blank"
rel="noopener noreferrer"
>
<i className="fa-brands fa-twitter"></i>
</a>
<a
href="https://github.com/olawanlejoel"
aria-label="GitHub"
target="_blank"
rel="noopener noreferrer"
>
<i className="fa-brands fa-github"></i>
</a>
<a
href="https://www.linkedin.com/in/olawanlejoel/"
aria-label="LinkedIn"
target="_blank"
rel="noopener noreferrer"
>
<i className="fa-brands fa-linkedin"></i>
</a>
</div>
</div>
</div>
)
}
export default Hero;
在上面的程式碼中,你會注意到,Next.js影象元件被用來代替HTML img
標籤來新增影象,因為它能夠自動優化影象,調整大小,以及更多。
在 “關於 “元件中,你還會注意到,在Font Awesome的一些社交圖示旁邊,新增了一個簡單的段落來介紹開發者的情況,以增加社交連結。
這就是Hero元件應該有的樣子:

Hero元件
你可以給Hero元件新增更多的內容,調整style/globals.css檔案中的樣式,甚至以你自己的方式重新建立這個部分。
About元件
關於部分是為了告訴讀者或訪問你的作品集的人更多關於你的資訊,可以有很多段落。如果你想更多地介紹你自己,你可以建立一個專門的 “關於我” 的頁面,並在這個部分新增一個按鈕來閱讀更多關於你的資訊。
import Image from "next/image";
<div className="about-container">
<div className="flex-about">
<div className="about-text">
As a developer, I have always been passionate about creating elegant and effective solutions to
complex problems. I have a strong foundation in software development, with a focus on web
technologies such as HTML, CSS, and JavaScript. I enjoy working on both the front-end and
back-end of applications, and I am always looking for ways to optimize performance, improve user
experience, and ensure the highest level of code quality.
<p>Throughout my career, I have worked on a wide range of projects, from simple static websites to
complex enterprise-level applications. I am experienced in working with a variety of development
tools and frameworks, including React, Angular, Vue.js, Node.js, and Laravel. I am always eager
to learn and explore new technologies, and I am constantly seeking out opportunities to improve
my skills and knowledge.</p>
<div className="about-img">
<Image src='/images/about.jpeg' className="profile-img" width={300} height={500}/>
// components/About.jsx
import Image from "next/image";
const About = () => {
return (
<div className="about-container">
<h2>About Me</h2>
<div className="flex-about">
<div className="about-text">
<p>
As a developer, I have always been passionate about creating elegant and effective solutions to
complex problems. I have a strong foundation in software development, with a focus on web
technologies such as HTML, CSS, and JavaScript. I enjoy working on both the front-end and
back-end of applications, and I am always looking for ways to optimize performance, improve user
experience, and ensure the highest level of code quality.
</p>
<p>Throughout my career, I have worked on a wide range of projects, from simple static websites to
complex enterprise-level applications. I am experienced in working with a variety of development
tools and frameworks, including React, Angular, Vue.js, Node.js, and Laravel. I am always eager
to learn and explore new technologies, and I am constantly seeking out opportunities to improve
my skills and knowledge.</p>
</div>
<div className="about-img">
<Image src='/images/about.jpeg' className="profile-img" width={300} height={500}/>
</div>
</div>
</div>
)
}
export default About;
// components/About.jsx
import Image from "next/image";
const About = () => {
return (
<div className="about-container">
<h2>About Me</h2>
<div className="flex-about">
<div className="about-text">
<p>
As a developer, I have always been passionate about creating elegant and effective solutions to
complex problems. I have a strong foundation in software development, with a focus on web
technologies such as HTML, CSS, and JavaScript. I enjoy working on both the front-end and
back-end of applications, and I am always looking for ways to optimize performance, improve user
experience, and ensure the highest level of code quality.
</p>
<p>Throughout my career, I have worked on a wide range of projects, from simple static websites to
complex enterprise-level applications. I am experienced in working with a variety of development
tools and frameworks, including React, Angular, Vue.js, Node.js, and Laravel. I am always eager
to learn and explore new technologies, and I am constantly seeking out opportunities to improve
my skills and knowledge.</p>
</div>
<div className="about-img">
<Image src='/images/about.jpeg' className="profile-img" width={300} height={500}/>
</div>
</div>
</div>
)
}
export default About;
上面的程式碼包含兩段關於開發者的文字和一張開發者的圖片。這就是 “關於” 部分預計的樣子:

About元件
你可以隨時調整樣式,增加更多的影象和很多東西。
技能元件
技能元件是為了顯示開發人員最常用的一些技術或開發人員過去使用過的技術。

技能元件
你可以通過在外部檔案中建立一個陣列,然後匯入到技能元件中,使之更容易維護,這樣你就可以迴圈瀏覽而不是重複類似的程式碼。
<div className="skills-container">
<div className="grid-skills">
<div className="skill-card html">
<i className="fa-brands fa-html5 html-icon"></i>
<div className="skill-card css">
<i className="fa-brands fa-css3-alt css-icon"></i>
<div className="skill-card js">
<i className="fa-brands fa-js-square js-icon"></i>
<div className="skill-card react">
<i className="fa-brands fa-react react-icon"></i>
<div className="skill-card node">
<i className="fa-brands fa-node-js node-icon"></i>
<div className="skill-card python">
<i className="fa-brands fa-python python-icon"></i>
// components/Skills.jsx
const Skills = () => {
return (
<div className="skills-container">
<h2>Skills</h2>
<div className="grid-skills">
<div className="skill-card html">
<i className="fa-brands fa-html5 html-icon"></i>
<p>HTML</p>
</div>
<div className="skill-card css">
<i className="fa-brands fa-css3-alt css-icon"></i>
<p>CSS</p>
</div>
<div className="skill-card js">
<i className="fa-brands fa-js-square js-icon"></i>
<p>JavaScript</p>
</div>
<div className="skill-card react">
<i className="fa-brands fa-react react-icon"></i>
<p>React</p>
</div>
<div className="skill-card node">
<i className="fa-brands fa-node-js node-icon"></i>
<p>Node</p>
</div>
<div className="skill-card python">
<i className="fa-brands fa-python python-icon"></i>
<p>Python</p>
</div>
</div>
</div>
)
}
export default Skills;
// components/Skills.jsx
const Skills = () => {
return (
<div className="skills-container">
<h2>Skills</h2>
<div className="grid-skills">
<div className="skill-card html">
<i className="fa-brands fa-html5 html-icon"></i>
<p>HTML</p>
</div>
<div className="skill-card css">
<i className="fa-brands fa-css3-alt css-icon"></i>
<p>CSS</p>
</div>
<div className="skill-card js">
<i className="fa-brands fa-js-square js-icon"></i>
<p>JavaScript</p>
</div>
<div className="skill-card react">
<i className="fa-brands fa-react react-icon"></i>
<p>React</p>
</div>
<div className="skill-card node">
<i className="fa-brands fa-node-js node-icon"></i>
<p>Node</p>
</div>
<div className="skill-card python">
<i className="fa-brands fa-python python-icon"></i>
<p>Python</p>
</div>
</div>
</div>
)
}
export default Skills;
在上面的程式碼中,為每個技能建立了一個卡片,每個卡片將持有來自font-awesome的技術圖示和技術名稱。你還可以新增更多的樣式,並調整程式碼,使其更有吸引力和獨特。
Projects元件
專案元件是開發者作品集的重要部分之一。專案為開發者的技能和能力提供了切實的證據,展示了他們將知識應用於現實世界問題的能力。
每個專案將包括專案的簡要描述,其原始碼的連結,以及任何其他你想新增的細節。

專案元件
你可以建立一個陣列來儲存每個專案的詳細資訊,然後將其匯入你的元件中,以避免硬編碼。
讓我們建立一個data.js檔案來儲存專案資料的陣列。你可以把這個檔案存放在元件資料夾或pages/api資料夾中。對於這個演示,我將把它儲存在元件資料夾中。這個陣列將為每個專案儲存一個物件,該物件將儲存專案名稱、描述和GitHub連結。
export const projectData = [
'A simple Todo List App built with JavaScript. All datas are stored in localstorage. It helps users check list out their plans and tick as they do them.',
gitHubLink: 'https://github.com/olawanlejoel/Todo-List-App',
title: 'Books Library App',
'A simple Book Library App built with JavaScript. It helps readers have a good list of books they are either currently reading or have finished reading.',
gitHubLink: 'https://github.com/olawanlejoel/Book-Library',
title: 'Quotes Generator',
'Helps you generate quotes from about 1600 quotes written by different authors . Quotes are automatically copied to your clipboards.',
gitHubLink: 'https://github.com/olawanlejoel/random-quote-generator',
title: 'Password Generator',
'Helps you generates random passwords, you can select what you want your password to entail and also you can copy generated password to clipboard.',
gitHubLink: 'https://github.com/olawanlejoel/Password-Generator',
title: 'Twitter UI Clone',
'Simple Twitter UI clone built with TailwindCSS and Vue Js. This covers only the homepage of Twitter UI. This is cool to get started with TailwindCSS as it helps understand basic concepts.',
gitHubLink: 'https://github.com/olawanlejoel/TwitterUI-clone',
// components/data.js
export const projectData = [
{
id: 1,
title: 'Todo List App',
description:
'A simple Todo List App built with JavaScript. All datas are stored in localstorage. It helps users check list out their plans and tick as they do them.',
gitHubLink: 'https://github.com/olawanlejoel/Todo-List-App',
},
{
id: 2,
title: 'Books Library App',
description:
'A simple Book Library App built with JavaScript. It helps readers have a good list of books they are either currently reading or have finished reading.',
gitHubLink: 'https://github.com/olawanlejoel/Book-Library',
},
{
id: 3,
title: 'Quotes Generator',
description:
'Helps you generate quotes from about 1600 quotes written by different authors . Quotes are automatically copied to your clipboards.',
gitHubLink: 'https://github.com/olawanlejoel/random-quote-generator',
},
{
id: 4,
title: 'Password Generator',
description:
'Helps you generates random passwords, you can select what you want your password to entail and also you can copy generated password to clipboard.',
gitHubLink: 'https://github.com/olawanlejoel/Password-Generator',
},
{
id: 5,
title: 'Twitter UI Clone',
description:
'Simple Twitter UI clone built with TailwindCSS and Vue Js. This covers only the homepage of Twitter UI. This is cool to get started with TailwindCSS as it helps understand basic concepts.',
gitHubLink: 'https://github.com/olawanlejoel/TwitterUI-clone',
},
];
// components/data.js
export const projectData = [
{
id: 1,
title: 'Todo List App',
description:
'A simple Todo List App built with JavaScript. All datas are stored in localstorage. It helps users check list out their plans and tick as they do them.',
gitHubLink: 'https://github.com/olawanlejoel/Todo-List-App',
},
{
id: 2,
title: 'Books Library App',
description:
'A simple Book Library App built with JavaScript. It helps readers have a good list of books they are either currently reading or have finished reading.',
gitHubLink: 'https://github.com/olawanlejoel/Book-Library',
},
{
id: 3,
title: 'Quotes Generator',
description:
'Helps you generate quotes from about 1600 quotes written by different authors . Quotes are automatically copied to your clipboards.',
gitHubLink: 'https://github.com/olawanlejoel/random-quote-generator',
},
{
id: 4,
title: 'Password Generator',
description:
'Helps you generates random passwords, you can select what you want your password to entail and also you can copy generated password to clipboard.',
gitHubLink: 'https://github.com/olawanlejoel/Password-Generator',
},
{
id: 5,
title: 'Twitter UI Clone',
description:
'Simple Twitter UI clone built with TailwindCSS and Vue Js. This covers only the homepage of Twitter UI. This is cool to get started with TailwindCSS as it helps understand basic concepts.',
gitHubLink: 'https://github.com/olawanlejoel/TwitterUI-clone',
},
];
現在你可以建立一個專案元件,通過輕鬆的迴圈來利用這些資料。你可以使用任何JavaScript迭代方法,但在本教程中,你可以使用JavaScript map()
陣列方法,在將資料匯入專案元件後檢視資料陣列。
// components/Projects.jsx
import { projectData } from './data.js';
<div className="projects-container">
<div className="projects-grid">
{projectData && projectData.map((project) => (
<div className="project-card" key={project.id}>
<div className="project-header">
<i className="fa-regular fa-folder-open folder-icon"></i>
<div className="small-icons">
<a href={project.gitHubLink}><i className="fa-brands fa-github"></i></a>
<p>{project.description}</p>
// components/Projects.jsx
import { projectData } from './data.js';
const Projects = () => {
return (
<div className="projects-container">
<h2>Projects</h2>
<div className="projects-grid">
{projectData && projectData.map((project) => (
<div className="project-card" key={project.id}>
<div className="project-header">
<i className="fa-regular fa-folder-open folder-icon"></i>
<div className="small-icons">
<a href={project.gitHubLink}><i className="fa-brands fa-github"></i></a>
</div>
</div>
<h3>{project.title}</h3>
<p>{project.description}</p>
</div>
))
}
</div>
</div>
)
}
export default Projects;
// components/Projects.jsx
import { projectData } from './data.js';
const Projects = () => {
return (
<div className="projects-container">
<h2>Projects</h2>
<div className="projects-grid">
{projectData && projectData.map((project) => (
<div className="project-card" key={project.id}>
<div className="project-header">
<i className="fa-regular fa-folder-open folder-icon"></i>
<div className="small-icons">
<a href={project.gitHubLink}><i className="fa-brands fa-github"></i></a>
</div>
</div>
<h3>{project.title}</h3>
<p>{project.description}</p>
</div>
))
}
</div>
</div>
)
}
export default Projects;
在上面的程式碼中,你已經成功地避免了重複,通過迴圈陣列將所有專案輸出到Projects元件中,使其易於維護和新增更多的專案。
Contact元件
建立開發者作品集的一個原因是,潛在客戶可以與你聯絡。一種方法是讓人們給你發電子郵件,這就是我們將在這個 “聯絡” 部分提供的便利。
// components/Contact.jsx
<div className="contact-container">
<p>If you want us to work together, have any questions or want me to speak at your event, my inbox is always open. Whether I just want to say hi, I'll try my best to get back to you! Cheers!</p>
<a href="mailto:example@kinsta.com" className='cta-btn'>Say Hello</a>
// components/Contact.jsx
const Contact = () => {
return (
<div className="contact-container">
<h2>Get In Touch</h2>
<p>If you want us to work together, have any questions or want me to speak at your event, my inbox is always open. Whether I just want to say hi, I'll try my best to get back to you! Cheers!</p>
<a href="mailto:example@kinsta.com" className='cta-btn'>Say Hello</a>
</div>
)
}
export default Contact;
// components/Contact.jsx
const Contact = () => {
return (
<div className="contact-container">
<h2>Get In Touch</h2>
<p>If you want us to work together, have any questions or want me to speak at your event, my inbox is always open. Whether I just want to say hi, I'll try my best to get back to you! Cheers!</p>
<a href="mailto:example@kinsta.com" className='cta-btn'>Say Hello</a>
</div>
)
}
export default Contact;
將你的電子郵件地址放在 a
標籤中,這樣,該按鈕就會啟動一個電子郵件應用程式,給你傳送訊息。

聯絡元件
你現在已經成功地為你的作品集應用程式建立了所有的元件。下一步將是把它們新增到你的索引頁面。導航到pages/index.js檔案–該檔案是預設建立的–並將其程式碼替換為以下內容。
import Hero from '@/components/Hero';
import About from '@/components/About';
import Skills from '@/components/Skills';
import Projects from '@/components/Projects';
import Contact from '@/components/Contact';
import Head from 'next/head';
<title>Joel's Portfolio</title>
<meta name="description" content="Joel's Portfolio" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
// pages/index.js
import Hero from '@/components/Hero';
import About from '@/components/About';
import Skills from '@/components/Skills';
import Projects from '@/components/Projects';
import Contact from '@/components/Contact';
import Head from 'next/head';
const Home = () => {
return (
<>
<Head>
<title>Joel's Portfolio</title>
<meta name="description" content="Joel's Portfolio" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
</Head>
<div>
<Hero />
<About />
<Skills />
<Projects />
<Contact />
</div>
</>
);
};
export default Home;
// pages/index.js
import Hero from '@/components/Hero';
import About from '@/components/About';
import Skills from '@/components/Skills';
import Projects from '@/components/Projects';
import Contact from '@/components/Contact';
import Head from 'next/head';
const Home = () => {
return (
<>
<Head>
<title>Joel's Portfolio</title>
<meta name="description" content="Joel's Portfolio" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
</Head>
<div>
<Hero />
<About />
<Skills />
<Projects />
<Contact />
</div>
</>
);
};
export default Home;
當你現在執行你的應用程式時,你會發現一個完整的作品集網站已經被建立。最後,在部署你的應用程式之前,讓我們來安裝一個依賴關係。使用Next.js的一個優勢是它帶來的許多功能,如基於檔案的路由、影象優化等。
影象優化是由Next.js的 Image
元件處理的。在將使用Next.js影象元件的應用程式部署到生產中之前,強烈建議你安裝sharp。你可以通過導航到你的終端,確保你在你的專案目錄中,然後執行以下命令來完成:
npm i sharp
現在你可以部署你的應用程式了,影象將在Next.js提供的全面優化下正常工作。
如何將Next.js應用程式部署到伺服器
一旦你對你的作品集展示了你最好的開發工作和關鍵資訊感到滿意,你很可能會想與其他人分享,對嗎?讓我們看看如何使用GitHub和應用託管平臺來做到這一點。
將你的程式碼推送到GitHub上
推送程式碼到GitHub有多種方式,但在本教程中,讓我們使用Git命令列介面。Git在軟體開發中被廣泛使用,因為它為管理程式碼變更、專案協作和維護版本歷史提供了一種可靠而有效的方式。
你可以通過以下步驟把你的程式碼上傳到GitHub。
首先,建立一個新的倉庫(就像一個本地資料夾來儲存你的程式碼)。你可以通過登入你的GitHub賬戶,點選螢幕右上角的+按鈕,從下拉選單中選擇New repository,如下圖所示。

建立一個新的GitHub倉庫。
下一步是給你的版本庫起個名字,新增描述(可選),並選擇你的版本庫是公開的還是私有的。然後點選Create repository。現在你可以把你的程式碼推送到新的 GitHub 倉庫。
用 Git 推送程式碼所需要的就是倉庫的 URL,你可以在倉庫的主頁上,在Clone or download按鈕下,或者在建立倉庫後出現的步驟中找到。

訪問你的GitHub倉庫的URL
你可以通過開啟終端或命令提示符,導航到包含你的專案的目錄來準備推送你的程式碼。使用下面的命令來初始化本地的 Git 倉庫。
git init
現在用下面的命令把你的程式碼新增到本地Git倉庫:
git add .
上述命令將當前目錄及其子目錄下的所有檔案新增到新的 Git 倉庫中。現在你可以用下面的命令提交你的修改:
git commit -m "my first commit"
git commit -m "my first commit"
git commit -m "my first commit"
注意:你可以用你自己的簡簡訊息代替“my first commit”,描述你所做的改動。
最後,用以下命令把你的程式碼推送到GitHub。
git remote add origin [repository URL]
git push -u origin master
git remote add origin [repository URL]
git push -u origin master
git remote add origin [repository URL]
git push -u origin master
注意:確保用你自己的 GitHub 倉庫的 URL 替換 “[repository URL]”。
完成這些步驟後,你的程式碼將被推送到GitHub,並可通過你的倉庫的URL訪問。現在你可以將你的倉庫部署到伺服器。
將您的作品集部署到伺服器
部署到廢棄只需幾分鐘。以Kinsta為例,從 “My Kinsta” 儀表盤開始,登入或建立你的賬戶。
接下來,你將通過這些快速步驟在GitHub上授權Kinsta。
- 點選左側邊欄的Applications
- 點選Add service
- 從下拉選單中點選Application。

建立一個應用程式專案
會出現一個模式,你可以通過它選擇你想部署的版本庫。
如果你的版本庫裡有多個分支,你可以選擇你想部署的分支。你還可以為這個應用程式指定一個名稱。確保在25個可用的資料中心位置中選擇一個,然後Kinsta會自動檢測一個啟動命令。

自動檢測啟動命令
在這一點上,你的應用程式將開始部署。在幾分鐘內,將提供一個連結來訪問你的應用程式的部署版本。在這種情況下,它是:https://kinsta-developer-portfolio-ir8w8.kinsta.app/

專案部署連結
注意:自動部署功能已經啟用,所以每當你對你的程式碼庫進行修改並推送到GitHub時,伺服器都會自動重新部署你的應用程式。
小結
開發人員應該考慮在其網路專案中使用Next.js的原因有很多。首先,它提供了開箱即用的優化效能,如預取和程式碼拆分等功能,有助於減少頁面載入時間。其次,它為React開發者提供了熟悉的開發體驗,支援流行的工具,如風格化元件和React鉤子。
Next.js還支援一系列的部署選項,從傳統的基於伺服器的託管到現代的無伺服器平臺。這使得開發者可以選擇最適合他們需求的部署方案,同時受益於該框架的效能優化和其他優勢。
評論留言