Taiyi dev

鉅亨網新聞專案改版

目錄

改版原因

鉅亨網新聞網站大約是 2017 做了一次改版,當時使用的相關技術是 Node8, React15, Redux 與前人找了一個使用 Express 實作 Server Side Render 的樣板作為基底。六年後的 2023,目前 Node 穩定版本已經來到 18, React18,也陸續出現實作 SSR 的框架例如 Nextjs, Remix。

React16.8 推出 React hooks 寫法後, 寫 Class Component 的人就越來越少, 前人一開始建立的 MVC 架構與 Redux 也隨著經手的人越來越多漸漸的遠離一開始的規劃, 現在能在看見 View 層呼叫 API, 所有的實作邏輯都集中在一個檔案, 一個檔案有 1700 多行, 當 state, props 改變時會造成多餘的畫面重新渲染, 後續接手的人也越來越改不動。

Node 版本過舊,一些新的 JavaScript 語法不支援,相關套件只安裝較舊的版本或是不能使用。

Tech Stack

在考慮 SEO 情況下勢必是要選擇 SSR, Next 在處理 SSR 與 CSR 之間已經處理掉很多問題, 加上 Next13 已由 beta 版本變為穩定版本。新的Server Component應該也解決了很多 Client 與 Server 間的問題。

Linaria 是一個 CSS 的框件,主打是 Zero-runtime CSS in JS, 業界標竿 Airbnb 也導入了這個 CSS libraryAirbnb’s Trip to Linaria

Nx 則是希望未來能夠整合推版流程, 目前鉅亨網的專案是一個項目就開一個 gitlab repository, 目前大約有接近 10 個 repository, 會造成一個相同的功能在 A,B,C 專案都要用到, 就必須要推 3 次版, 如果是動到 Header 全部專案都有用到就必須每個專案都各別推版。Nx 是其中一個 monorepo 架構的實作,未來如果專案都整合到 monorepo 中能夠改善推很多次版的問題。

建立專案

  1. 建立 nx monorepo 結構(先切換至 node18)
npx create-nx-workspace@latest --preset=next --packageManager=pnpm
# 輸入workspace名稱/組織名稱 e.g. org
# 輸入next專案名稱 e.g. news
# 產生的目錄結構:
# org
#  - apps
#    - news
#  - libs
  1. 啟動專案
pnpm nx serve news
# 在app/news/prject.json會定義專案的指令,例如serve
# 就可以從workspace來控制所有專案指令,例如啟動,新增,刪除等等
# 預設是localhost:4200
  1. 建立 ui 共用元件庫到 libs 資料夾下
pnpm nx g @nx/react:lib ui
# org
#   - libs
#     - ui

nx 提供一些程式碼模板可以產生各種範例,例如這裡產生 lib,是使用@nx/react:lib 模板, g 是 generate 縮寫

  1. 生成共用元件到 lib/ui, 如 header
pnpm nx g @nx/react:component header --project=ui
# CREATE libs/ui/src/lib/header/header.spec.tsx
# CREATE libs/ui/src/lib/header/header.tsx
# UPDATE libs/ui/src/index.ts
  1. 在 news 中使用共用元件
// apps/news/app/layout.tsx
import { Header } from '@org/ui';
...
return (
    <html lang="en">
      <body>
        <Header />
        {children}
      </body>
    </html>
  );
...

next-with-header

  1. 安裝Linaria
pnpm i next-with-linaria @linaria/babel-preset @linaria/core @linaria/react

next13 和 linaria 整合還有點問題, next-with-linaria提出了解法,但是在 readme 中也寫到正在開發中不要用到 prod 中,需要再持續看之後有什麼新的整合方式。

// next.config.ts
const withLinaria = require("next-with-linaria");
const plugins = [withNx, withLinaria];
import { styled } from "@linaria/react";
const Title = styled.h1`
  color: red;
  font-size: 36px;
`;
<div id="welcome">
  <Title>
    <span> Hello there, </span>
    Welcome news 👋
  </Title>
</div>

linaria-title

Next13

Next.js App Router: Routing, Data Fetching, Caching - Vercel

結論