個人博客搭建
個人博客搭建
經過 1 個月的咕咕咕,總算把博客初步搭建好了,按照慣例先丟個鏈接大家有興趣可以來逛逛: blog.mytyiluo.cn。
主要特點如下:
- Modernized - 基於 Gatsbyjs,React,Typescript 構建;
- Opinionated - 以約束優先,減少博客中的必需參數;
- Git-based - 基於 GitHub 以及 Netlify 的自動化構建/部署;
為什麽不使用現有的博客框架?
之前其實一直用的是 GitBook,但說實話,GitBook 還是更加適合書籍/教程等的寫作,對隨筆來說還是感覺少了點功能。而且官方也表示之後不再維護命令行程序了,因此決定慢慢的從這平臺遷移出來。
在這過程中,有考慮過使用 Hexo 作為博客引擎,想自己寫一套主題,但無奈不習慣它的模板語法,最終還是選擇了放棄。
然後,考慮到開發的難度和靈活性,決定使用基於 React 的靜態網頁引擎,也就是 GatsbyJS。
其中,最吸引我的便是它對多數據源的內建支持,並以 GrapQL 的形式統一提供數據,非常符合我對後期拓展的預期。此外,豐富的社區插件倒算是額外的驚喜,特別是支持 TypeScript 和 Less 對開發帶來了極大的方便,支持響應式圖片和 PWA 也省去了我大量的精力。
我希望的博客體驗
- 在本地用 VS Code 來編寫 Markdown,並將博客內容托管在 GitHub 上;
博客應該支持豐富的元信息,但大多數參數應該根據約定生成默認值;
例如,博客標題一般會和文件名相同; 同一文件夾下的博客應該為同一個主題;
博客對各類代碼應該有良好的展示,且支持插入多媒體內容,例如:Gist,B 站視頻等;
搭建過程
廢話了那麽多,還是得講些技術性的話題。
參考資料
關於 Gatsby 的參考資料其實並不需要太大,官方文檔再加官方教程已經足夠了。若涉及到插件的話,相應的文檔和源碼也都可以在 GitHub 找到。
GraphQL 數據的 TypeScript 支持
默認 GraphQL 執行的結果類型,不出意外都是 any 。但既然在使用 Ts 了,我還是希望它是強類型的變量。可問題是根據不同的查詢語句返回的類型也都不一樣,所以單獨為每一個查詢定義類型工程量太大(懶)。
解決方案就是采用現成的代碼生成器:
yarn add --dev @graphql-codegen/cli @graphql-codegen/typescript
在根目錄下添加配置文件 codegen.yml :
# 這裏端口為 gatsby develop 的端口
schema: http://localhost:8000/___graphql
generates:
src/types.ts:
plugins:
- typescript
# 默認類型為 T | null | undefined
# 這裏為了偷懶就直接改為了 T
config:
avoidOptionals: true
maybeValue: T
然後運行:
graphql-codegen --config codegen.yml
即可,我們可以在 src 文件夾中找到定義文件 types.ts 。
CSS Module 的 TypeScript 支持
CSS Module 是 Gatsby 所支持的一種樣式表導入方式,其優點是在獨立的 css/less 文件中編寫,可以獲得完美的 IDE 支持,且不同模塊之間的樣式不會相互幹擾。
但當其導入 ts 文件中後,會被提示無法解析類型。
我采用的解決方案相對暴力,在 src 文件夾下建立一個 global.d.ts 文件:
// 若你使用的不是less的話,改成相應的後綴就行
declare module "*.less" {
const content: { [className: string]: string };
export = content;
}
如果 IDE 還不能識別其類型,可以在根目錄的 tsconfig.json 中添加:
{
// ...
"typeAcquisition": {
"include": ["./src/global.d.ts"]
}
}
若還不行可以嘗試重啟下 IDE。
CSS Module 生成的樣式名過長
默認的情況下,CSS Module 生成的樣式名的格式為:
[path][name]__[local]--[hash:base64:5]
顯然在多級目錄鑲嵌之後,其長度會是非常嚇人的,而且會影響傳輸效率(即使用 Gzip)。
總之,我希望這樣式名在生產環境下短一些,解決方案如下:
在 gatsby-config.js 中配置 gatsby-plugin-less 選項:
{
resolve: `gatsby-plugin-less`,
options: {
cssLoaderOptions: {
minifyClassNames: true,
localIdentName:
process.env.NODE_ENV === "development"
? "[path][name]__[local]--[hash:base64:5]"
: "[hash:base64:5]",
},
},
}
依賴項 sharp 安裝太慢
sharp 是 gatsby-plugin-sharp 的依賴項,提供圖像編輯處理的能力。 通過分析其安裝過程和文檔,我們可以將問題定位到 libvips 上,sharp 在 build 階段會從 github 下載 libvips 的預編譯版本(大概 14MB),但由於國內網速的原因導致其加載時間過長甚至加載失敗。
那解決方案就是通過任意手段下載對應版本的 libvips 將其復制到對應的緩存目錄下,一般為:
C:\Users\[你的用戶名]\AppData\Roaming\npm-cache\_libvips
添加百度統計
考慮到 GA 在國內可能有些問題,這裏還是選用了百度統計作為統計分析平臺。同時,百度統計平臺還可以主動將站點信息提交到百度搜索引擎,提高站點收錄的效率。
在 Gatsby 的社區插件中已經有實現了添加百度統計的插件,但我看了下它的源碼感覺挺簡單的,且為了方便之後再更換其他統計平臺,這裏打算是自己實現一下。
首先,我們需要註冊一個百度統計的賬號,然後在管理界面中獲取對應的代碼:
根據文檔說明,我們需要將這段代碼添加到每個頁面的<head>
中。
這裏,就需要用到 gatsby-ssr.js 中的接口 onRenderBody ,具體信息可以查看文檔。 代碼如下:
// 因為在下方用到了JSX,所以需要導入React
var React = require("react");
exports.onRenderBody = ({ setHeadComponents }) => {
if (process.env.NODE_ENV === `production`) {
setHeadComponents([
// 這裏的形式是為了異步加載
<script
key="baidu-analytics-script"
dangerouslySetInnerHTML={{
__html: `
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?ff306397dbce7dab4357bd037fa286ca";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
`
}}
/>
]);
}
};
統計博客標簽
在我設置的字段中,每篇博客都會包含一個 tags,類型為 string[]。在首頁中,我希望根據標簽計數的降序顯示計數大於 2 的標簽。
其實,這個問題就相當於處理鑲嵌數組,處理難度並不高,但此前往往需要寫不少的代碼,這裏基於 lodash 的 chain 實現了一個相對“簡潔”的版本:
// data 就是根據 GraphQL 得到的數據
// const data = this.props.data.statistics.nodes;
//
// Scheme 定義如下:
// statistics: allMarkdownRemark(
// filter: { fields: { name: { ne: "README" }, posted: { ne: false } } }
// ) {
// nodes {
// fields {
// topic
// tags
// }
// }
// }
const tags = _
// 包裝為 chain 對象
.chain(data)
// 只需要 tags 字段
.map(e => e.fields.tags)
// 展開二維數組
.flatten()
// 對標簽計數
// 這裏返回的為對象 { tag: count }
.countBy()
// 篩選計數大於 2 的標簽
.pickBy((value, key) => value > 2)
// 將對象轉為數組
.map((value, key) => ({ tag: key, count: value }))
// 根據計數降序排列
.orderBy("count", "desc")
// 只需要 tag 字段
.map(e => e.tag)
// 解除 chain 包裝
.value();
小結
至此,主要記錄的是在開發階段遇到的一些坑和小技巧。下一篇,我想簡要敘述一下設計這個博客的思路,如果我還記得這個坑的話。
個人博客搭建