Next.js 安裝注意事項

本篇文章是鴨血習慣的Next.js安裝流程,可能會跟官方文件有些微不同,再請斟酌查看。

安裝最新版的Next.js在目前的目錄

想要新建一個Next.js專案,在終端機運行以下命令:

npx create-next-app@latest ./

注意,目錄(專案)名稱不能有大寫。
如果沒在後方加上 ./ 來代表安裝在目前目錄下,則會另外建立新的專案資料夾。接著terminal會問是否要進行下一步,然後問一連串的問題,就按照情況選填。

Next.js的metadata設定方式

剛安裝完,app目錄下會出現初始首頁以及初始框架文件,點開layout.tsx,會看見是這樣引用的

import type { Metadata } from "next";

export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

新增components目錄,並創建Header與Footer

在src目錄下,創建components目錄,才能跟tailwindCSS的config文件位置對應

tailwindCSS_config文件指定的目錄位置
tailwindCSS_config文件指定的目錄位置
Next.js 是基於 React 的全端框架,擴展了 React 的功能來實現伺服器端渲染(SSR)和靜態網站生成(SSG)。建立元件時,可以使用rafce快捷鍵,來快速生成函式型元件的基本結構。

四、匯入常用組件

4-1. Link模組

import Link from "next/link"

Link是Next.js十分好用的模組,此框架會針對使用者有『可能前往的站內頁面』進行預載入,prefetch屬性預設為true,可以將它改為false;反過來說,站外連結用a標籤就好。

4-2. Image模組

import Image from "next/image"

Image模組在效能優化上十分優秀,使用此模組取代<img>顯示圖片,能把圖片自動轉為webP格式並壓縮至75%,也能預設不同螢幕寬度範圍下的圖片渲染尺寸。若不想讓圖片被壓縮、不想轉webp,這些屬性也能個別設定。

4-3. Head模組

顧名思義,就是Html架構中<head>標籤內的內容,每一頁的Meta描述都未必會跟layout一樣,有可能是關於我們、聯絡我們等等的頁面,就會使用到Head模組。

也可以直接使用export const metadata = {title: "ABOUT"};

import Head from "next/head"

function Page() {
  return (
    <div>
      <Head>
        <title>ABOUT</title>
      </Head>
      <p>Hello world!</p>
    </div>
  )
}
 
export default Page

在Next.js中使用google font或local font等自定義字型

先安裝next/font,於終端機輸入npm i @next/font

若覺得要安裝其他外掛,開開關關很麻煩,可以按右側的『+』號,再開另一個終端機分頁來負責安裝模組。

import { 字型名稱 } from “@next/font/google”

import { Inter } from “next/font/google”

const inter = Inter({ subsets: [‘latin’], display: ‘swap’,})

如果你使用的『字型名稱』是由兩個單字以上組成,請用底線連結兩個單字,例如Roboto_Mono

善用Next.js的Image組件來優化圖片

Next.js的Image組件必須要設定寬(w)、高(h)及圖片替代文字(alt)屬性,缺一不可,少了一項就會出現錯誤提示。這個組件有什麼好處呢?

自動轉webP格式、以你設定的寬、高為基準來縮減圖片大小,這些特性對圖片載入速度相當有幫助。

【MERN】佈署注意事項:記得分離前後端路由

在佈署前,把React.js建立的前端build目錄上傳到主機後,後端API可能會不見,因為路徑被前端覆蓋了。要怎麼解決呢?你需要在Node.js的啟動檔中設定前後端的路徑,將前後端分離。

一、建立前端頁面

1-1. 建立前端頁面之前的所需設定

在MERN專案中,伺服器端(server)與客戶端(client)是分離的,它們都有各自的目錄與package.json檔,第一步需要找到客戶端的package.json,並對 homepage 屬性填入即將佈署的網域,例如:

{
  "name": "mobuyashea",
  "version": "0.1.0",
  "private": true,
  "homepage": "https://mobuyashea.club/",
  "dependencies": {
   //下略

1-2. 生成build資料夾

接著,你需要幫客戶端的內容建立靜態頁面,確定位於client目錄下,於終端機輸入:

npm run build

按下確認鍵後,npm會於client目錄建立一個build資料夾,裡面的內容為前端靜態頁面。

二、MERN佈署時的目錄結構

MERN專案的佈署目錄結構大概如下,外面根目錄放伺服器端的內容,包括啟動檔、伺服器端的package.json、資料表或路由等;build則是客戶端的內容,就是把第一步建立的目錄整包上傳:

/root
|– /build(前端)
|– /models
|– /public
|– /routes
|– server.js (啟動檔)
|– package.json
|– package-lock.json

也可以把伺服器端跟客戶端的目錄完全分開,不過要注意下一步路由的設定,根據路由文件與首頁相對位置的不同,可能會變成“/../client/build”

/root
|– /client/build(前端)
|– /server
|–– server.js (啟動檔)

三、分離MERN專案的前後端路由

打開你的啟動檔(假設文件叫server.js),引入path模組:

const path = require('path');

‘ * ‘ 將所有路由通通歸類於前端頁面,不管訪問哪個路由都返回build目錄下的index.html:

app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
app.get('*', (req, res) => {
  res.sendFile(path.resolve(__dirname, 'build', 'index.html'));
});

用path.join() 簡單的規範路徑,或用path.resolve() 返回絕對路徑,兩者在此範例下返回的是相同的路徑__dirname 是目前文件所處的位置。

四、注意先後順序

撰寫API時,定位前端靜態目錄的程式碼必須位於後端路由之後,後端路由都發配完後才輪到'*'。順序不能優先於其他後端路徑,否則會把其他路徑給覆蓋掉。

Node.js 網站佈署 – 共享主機可以安裝Node.js嗎?

Node.js 是 JavaScript 框架愛好者的福音,它實現了用 JavaScript 撰寫後端程式碼的需求。但要如何將 Node.js 放到主機上運作呢?你可能已經嘗試過靜態網站部署,但還不知道將自己製作的 API 放到主機上的方法。這篇文章將為你詳細介紹相關操作。

1.共享主機可以安裝Node.js

共享主機可以安裝Node.js,但在安裝之前,你需要於檔案管理員(File Manager)建立一個空的文件夾,用於安裝Node App。這個資料夾的名稱會根據網域名稱有所不同,主要有以下兩種狀況:

-狀況1. 安裝於主網域,於根目錄建立與主網域同名的文件夾

找到File Manager按鈕,並點選。

node.js安裝第一步-先找到file manager

進入主機檔案管理畫面,按左上角的『+Folder』 於根目錄新增文件夾,若主網域為domain.com,該文件夾命名為domain.com(關於命名方式,請看下方Tips)。

node.js安裝第二步-進入file manager後,新增folder文件夾
維持App URI和 App Root Directory的一致性是約定俗成的慣例,沒有硬性規定。目錄名稱和App URI可以不同,但可能會導致其他人在查找時混淆。

-狀況2. 安裝於子網域,同步建立子網域的同名文件夾

在cPenal建立子網域,並同步建立子網域的同名文件夾。
找到Domains按鈕,並點選進入網域管理頁。

想安裝在子網域,點選進入domain頁面

點選右上角Create A New Domain按鈕,建立新的子網域,並在欄位上填入子網域名稱,例如:test.domain.com,Document root會自動填入子網域的名稱。

進入domain頁面後,按下新增按鈕
輸入你想使用的子網域名稱,此情況不用手動創建,當子網域建立時,file manager會自動創建根目錄
此情況不用手動創建,當子網域建立時,file manager會自動創建根目錄
你可以在網域管理頁面(Domains)新增其他的主網域,把其他主網域指向此主機的某個目錄文件夾。

2.把網站打包上傳至File Manager

把.env、node modules目錄、.git排除在外,選擇其餘必要檔案並壓縮成zip,上傳到第一步建立好的目錄文件夾,並在裡面解壓縮。
不管你使用什麼框架,裡面至少要有:

  1. node.js啟動文件(名稱可能為server.js、app.js或index.js)
  2. 紀錄npm套件的package.json檔案

Node.js才能依據這份依賴清單(package.json)去安裝npm套件,並透過啟動文件進行啟動。

node.js網站的npm依賴文件
網站的npm依賴文件

3.安裝Node.js


登入主機的cPanal後台,找到Setup Node.js App選項,並點選進入。

找到node.js app按鈕並點選進入

進入Node.js App管理頁面,如果你曾經在這個主機建立過Node.js App,下方會有一串列表顯示目前Node.js App的狀態。

要創建新的Node.js App,請點選右上角的『Create Application』按鈕。

按右上角的創建新App按鈕
  1. 選擇需要Node.js的版本
  2. App mode選Production
  3. App root如果位於根目錄,直接填寫目錄文件夾的名稱(例如:domain.com或test.domain.com)
  4. App URL可點選更換網域,如果設在子目錄下再去填空白的欄位,沒有則略過
  5. 填寫啟動文件名稱(通常是server.js)
  6. 新增環境變數,例如資料庫的URI
  7. 按下右上角Create按鈕
確定填完所有node.js的設定項目後,按下Create創建按鈕
確定填完所有node.js的設定項目後,按下Create創建按鈕

創建完成後,先暫時停止App,執行Run npm install安裝套件,再重新啟動Node App。

先停止運行,再安裝npm套件,安裝完再啟動
在Node.js運作的狀態下,點選安裝npm套件,可能會導致安裝不成功,變更選項時盡量按部就班操作,先關閉node.js,安裝完之後再啟動。

【SMTP】如何用Emil信箱收到網站訪客填表的內容

這篇文章記錄了如何使用Resend服務,及網域主機商提供的Email來接收網站上的訪客填表訊息

什麼是SMTP?

SMTP(Simple Mail Transfer Protocol)是一種用於傳送電子郵件的網路協定,它定義了電子郵件如何在網絡中傳輸並進行交換。SMTP 服務提供了一個標準的方式,讓電子郵件客戶端(如電子郵件應用程式、網站等)能夠發送郵件到郵件伺服器,並由伺服器負責將郵件傳遞到接收者的郵件伺服器。

流程及概念

  1. 註冊Resend
  2. 更改網域的DNS並進行驗證
  3. 新增API
  4. 撰寫程式碼

1. 註冊Resend

首先,前往 Resend 官網進行註冊,並登入管理介面。

點選右上角的 Docs↗ 按鈕,可以選擇不同框架的應用說明文件,或繼續閱讀本篇 Node.js 框架的操作說明。

在左側邊欄中點選 Domains,然後按下 + Add Domain 以新增網域。

SMTP-RESEND-新增網域
新增網域時不能填寫 localhost 或免費供使用者部署的域名(例如:github.io、vercel.app)。 必須使用你自己付費註冊的網域,因為寄信時需要使用『實際存在的信箱』,而你購買的網域能提供這個服務。

不知道如何自行創建信箱嗎?
請參考【主機管理】如何在C-panel管理介面新增信箱

填入你購買的網域,並按下新增按鈕。
成功新增後,畫面上會顯示三串文字,分別為一個 MX 記錄和兩個 TXT 記錄。

SMTP-RESEND-記錄三個record並驗證

接著往下看,我們將要把這三個紀錄,新增到DNS當中。

2. 更改網域的DNS並進行驗證

以下以Namecheap的介面為例,若網域管理仍為預設值『Namecheap Web Hosting DNS』,改成『Namecheap BasicDNS』後打勾存檔,進階管理分頁才會出現可填寫Record的欄位。

SMTP-DNS要改成Basic才能自行設定

更改完成後,點選上方的Advanced DNS(進階DNS)分頁,會看到HOST RECORDS欄位,新增兩個TXT Record類型並從Record把Value(值)複製貼上。

SMTP-設定DNS紀錄的位置

剩下的MX Record填寫位至於下方MAIL SETTINGS欄位,選擇CUSTOM MX,一樣新增並將值複製貼上。

SMTP-MX RECORD位於EMAIL的位置

回到Resend的網域管理畫面並按下驗證按鈕,如果有偵測到3個Record,過一段時間就會轉為綠色,DNS設定就大功告成。

改用Namecheap BasicDNS時,DNS設定有可能是空的,這會導致網頁沒辦法出現,記得新增一個A record類型,Host name為@,值為主機的IP位址,然後新增Cname record類型,Host name為www,值填寫你的購買的網域。

3.新增API

再次回到Resend後台的左側側邊欄,找到API Keys並點選進入管理畫面。

SMTP-RESEND-創建新的API Key
SMTP-RESEND-按下創建按鈕

按下右上角『創建API Key(+Create API key)』按鈕。
只填寫第一欄API名稱,剩下欄位維持預設值,按下新增(Add)。

最後,出現寫著API Key的彈窗,立刻按下右邊複製按鈕,把這串API Key儲存下來。

API Key生成後只有一次複製機會,若忘了複製又關掉彈窗,只能刪除舊的再重新建立。
SMTP-RESEND-API Key只會出現一次立刻複製

於環境變數文件(.env)新增一個名為『RESEND_API_KEYS』的變數,並將剛剛複製的API Key貼上,作為『RESEND_API_KEYS』的值。

SMTP-RESEND-把API Key貼到環境變數文件

完成上述步驟後,就可以把API Key的彈窗關掉了。

4.撰寫程式碼

首先,打開專案目錄,並用 npm 安裝 Resend:

npm install resend

安裝完成後,打開路由管理文件,引入 Resend 模組:

const { Resend } = require("resend");
const resend = new Resend(process.env.RESEND_API_KEYS);

預計在 /contact 路徑進行發送新表單時(POST)使用 Resend,程式碼如下:

app.post("/contact", async (req, res) => {
  try {  
  const { data, error } = await resend.emails.send({
    from: "網站名稱 <填寫你註冊的網域的email,例如support@domain.com>",
    to: ["<填寫你希望收到信的信箱,例如youraccount@gmail.com>"],
    subject: "信件主旨",
    html: "信件內容",
  });  
    req.flash("success_msg", "已寄出!");
    console.log({ data });
  } catch (error) {
    req.flash("error_msg", "發生錯誤,無法寄出!");
    console.log({ error });
  }  
});

如果你想在信件中顯示網站訪客的填表訊息,請看以下範例:

app.post("/contact", async (req, res) => {
  try {
  let { name, phone, email, content } = req.body;
  const { data, error } = await resend.emails.send({
    from: "網站名稱 <填寫你註冊的網域的email,例如support@domain.com>",
    to: ["<填寫你希望收到信的信箱,例如youraccount@gmail.com>"],
    subject: `聯絡表單|來自${name}的問題`,
    html: `<h3>稱呼:${name}</h3>
    <h3>聯絡電話:${phone}</h3>
    <h3>聯絡信箱:${email}</h3>    
    <h3>洽詢內容:</h3><p>${content}</p>
    `,
  });  
    req.flash("success_msg", "已寄出!");
    console.log({ data });
  } catch (error) {
    req.flash("error_msg", "發生錯誤,無法寄出!");
    console.log({ error });
  }  
});

req.body 中取得 namephoneemailcontent 欄位的值,並用反引號(模板字符串)及 ${} 代入變數,即可在信件中直接顯示訪客的填表訊息。