初探 Node.js 框架:eggjs (環境搭配篇)
eggjs 是一個優秀的 Node.js 框架
概述:為什麼標題上說 eggjs 是一個優秀的 Node.js 框架(可跳過)?
換言之,我們為什麼選擇 eggjs 進行開發而不是之前初學時使用的 Express 框架呢?
Express 是最著名的 Node.js 框架,它甚至是官方唯一推薦過的(目前)
但是根據實際開發,我覺得它的配置相當冗長,比方說:它可以一句 app.use() 佈滿長達數十行
這一點,我沒法繼續使用下去,所以就停止對它的學習。
就配置方面來說: eggjs 做得很好,它通過開發約束,將所有的配置檔案放置在 config 檔案中。
起初載入時便進行逐一對伺服器進行設定,後設置的將會覆蓋之前的。配置則是基於 類似 json 一樣的寫法,這使得我們容易定位某一處配置並進行修改(因為 key 不能重複,檢索一下就知道在哪了)
同樣的,eggjs 擁有大量的外掛,開發者需要怎樣的功能,在官方外掛上幾乎都可以找到。
如果沒有找到所需外掛,eggjs 也支援定製。
在這裡可以找到官方 API 以及使用文件:https://eggjs.org/zh-cn/
不再進行多說了,讓我們開始進行一個 eggjs 框架工程吧(跟官方的有些不同,按照官方的快速入門,總是遇到莫名其妙的錯誤)
官方的錯誤,配置讓我耗費了三四個小時才得以真正明白框架的使用方法,希望你看完這篇文章,只需半小時就能寫出一個高質量的專案
1.1 使用 腳手架 進行初步的工程目錄建立
這一步也是所有基於 Node.js 工程所必備的環節之一:當然,你也可以手動建立。
開啟 DOS / 終端 ,使用以下命令轉到你需要存放的專案位置(這裡是我的專案存放位置):
cd C:\Users\chong\Documents\NodeJS
我是在 Windows 系統下的 “文件” 中建立了一個 NodeJS 目錄,它將是我用於所有 Node 專案的根目錄。
建立一個專案資料夾並進入( project 是專案名稱,可更改):
mkdir project && cd project
在這裡,開始進行 腳手架 的初始化和安裝依賴並進行啟動:
# 初始化目錄(會建立必備的資料夾和JS,package.json 檔案)
npm init egg --type=simple
# 安裝依賴 npm i
執行初始化目錄的時候,需要你填寫一些資訊,這些資訊最終都會匯入 package.json 配置檔案中。
紅框是 eggjs 初始化時建立的檔案以及資料夾,後續我們再來了解它們的作用【重要】
而箭頭所指的則是需要填寫的資訊,例如專案名稱,描述資訊,作者以及 Cookie 金鑰
現在,你已經得到了一個較為完整的目錄結構(我已經執行過幾次,比剛建立的還多了一些檔案,不必在意):
好了,再啟動專案,這裡有幾種啟動方式:
# 啟動專案
npm run dev
npm start
npm start 屬於生產環境中使用,使用這種方式的話,需要列印資訊輸出到控制檯就看不到了。
而 npm run dev 是開發中所推薦的啟動方式,當你修改程式碼時,則不必手動重啟伺服器,eggjs 會自己重啟,你只需要等待一會就可以在瀏覽器看到相對應的修改。
重要的是:你隨時可以在程式碼中寫上 console.log ,控制檯也會有相應的顯示。
下方是多種啟動或測試的命令( package.json ),均在前方加入 npm 即可使用。
也可以修改它們,如果你需要換個埠,例如 dev,修改為 egg-bin dev --port 8081 (注意:兩個 - 符號)
啟動完成後,在瀏覽器中訪問 DOS / 終端 顯示的路徑(紅色箭頭):
黃色部分是被修改的檔案,在這裡不必理會。
到這裡,你的初始化工作已經做完,不妨休息會,再繼續往下閱讀。
1.2 瞭解各個目錄、檔案的作用以及 eggjs 如何處理它們
相信你已經成功初始化了吧,現在讓我們來了解 eggjs 的目錄結構,各個檔案的作用:
重新回到之前的一張圖,我們可以清晰地看見 eggjs 到底建立了什麼。
前一些以 . 開頭的檔案我們不必理會,從 package.json 檔案開始(我們已經知道這是配置檔案),往下看:
它建立了兩個資料夾,分別是: app、config (test 屬於測試,如單元測試等,我們也不必理會)
app 是網站處理使用者請求,以及瀏覽器請求伺服器資源的應用資料夾
它包含:router(路由檔案)、controller(處理器)
是的,初始化就這麼兩個,所以我建議在 app 目錄下再手動建立以下幾個資料夾:
public(存放靜態資源,如 css、js、img)
view (存放檢視檔案)
service(處理資料等業務操作)
先來詳細說說路由檔案,所有的網站都會有一個訪問地址,路由則是客戶端首先進入位置:
客戶端(瀏覽器)會發送一個請求,這個請求將會首先進入路由分發檔案,匹配成功到某一個 處理器(Controller)後
這個處理器將會去進行相關業務操作(Service)拿到資料,之後 view 渲染一個頁面成功後一層層返還回去。
controller 資料夾下則放置著我們所有核心的網站程式碼(後續解釋)
任何一個網站都需要進行配置,而所有的 Web伺服器 都應該自身有建立環境的能力,而不是人為去為這個伺服器配置好環境。
那麼 config 資料夾就是為此而生。
由前面得知:eggjs 有著豐富的外掛,所以必然有一個外掛的管理、配置檔案,它就是 plugin.js
後續我們將知道一個外掛應該怎樣啟用,關閉,安裝,這裡先不說明;
eggjs 最重要的配置檔案則是 :config.default.js,它管理著整個 Node伺服器 的所有配置,包括外掛、Cookie安全金鑰、檢視渲染等等配置。
好了,看到這裡你已經對生成的 eggjs 專案工程有了一個大致的瞭解(我昨天才接觸 node.js ,若有不對,望在評論中指出,我會進行修改,多謝)
1.3 瞭解一個請求是如何被處理的【重要】
讀完前面,你已經明白:eggjs 工程中的目錄,檔案的作用(只介紹了部分),現在讓我們來深入瞭解程式碼層次上,eggjs 如何處理使用者請求(不解析原始碼,從生成的檔案來看):
先來了解路由檔案怎樣工作(建議所有的路由設計都放在一個檔案中):
'use strict'; /** * @param {Egg.Application} app - egg application */ module.exports = app => { const { router, controller } = app; router.get('/', controller.main.index); };
router.get() 方法指的是 GET 請求。
第一個引數表示 URL,例如 www.cnblogs.com 是域名,那麼 www.cnblogs.com/index 中的 / 開始,則都是該網站下的‘路由’
第二個引數表示 controller 資料夾下的 main.js 中的 index 方法【重要】,如下:
'use strict'; const Controller = require('egg').Controller; class MainController extends Controller { async index() { this.ctx.body = '<h1>Hello world</h1>'; } } module.exports = MainController;
所以,你會在瀏覽器的視窗中看見:
看,你已經知道它的請求過程了!先在 router.js 檔案中找到使用者請求的位置,而網站進入預設是 /
所以我們已經捕獲到了這次請求,之後根據路由檔案的描述找到 controller 資料夾下的 main 檔案,在從中檢索到 index 方法
這個方法設定了body,讓它輸出一個 h1 標籤,寫上 Hello world 。
即 router -> controller.main.index()
但是這樣的網站根本不具備使用能力,留不住使用者,我們還需要根據不同使用者資料,渲染一個好看的頁面給使用者。
這時,我們就可以知道 eggjs 外掛的強大之處了(再緩緩,梳理下閱讀到的知識,準備好了再繼續瞭解吧)。
1.4 通過模板引擎渲染頁面
eggjs 強大的外掛足以使你在 Node伺服器 上做到與其它Web伺服器不同的體驗
先述說模板引擎,之後,讓我們瞭解一下網站多語言一鍵配置。
以 Nunjucks 模板引擎為例:
首先引入兩個外掛:egg-view、egg-view-nunjucks
npm i egg-view -save npm i egg-view-nunjucks -save
之後開啟 config/config.default.js 檔案:
'use strict'; const path = require('path'); module.exports = appInfo => { return { // Cookie 安全金鑰 keys: "_skfhj8546542354.16554", // 專案日誌存放資料夾 logger: { dir: path.join(appInfo.baseDir, 'logs'), }, // 渲染模板配置 view: { // 配置檢視根路徑 root: path.join(appInfo.baseDir, 'app/view'), // 是否快取路徑 cache: true, // 配置檔案預設副檔名 defaultExtension: '.nj', // 預設渲染模板引擎 defaultViewEngine: 'nunjucks', // 檔案對映配置 mapping: { '.nj': 'nunjucks' } } }; };
我已經註明了各個屬性的作用,可複製到你的檔案中。
之後啟用外掛:egg-view-nunjucks,開啟 config/plugin.js 檔案
'use strict'; /** * 模板引擎:用於渲染頁面資料 */ exports.nunjucks = { enable: true, package: 'egg-view-nunjucks', };
配置方面已經準備完畢,之後需要在 app/view 目錄下建立一個 index.nj 模板檔案
<html> <head> <title>{{ page_title }}</title> </head> <body> <h1>{{ page_content }}</h1> </body> </html>
雙括號是模板引擎的語法之一,還有迴圈等(是不是覺得跟 jsp 差不多)
好了,讓我們修改 controller/main.js 檔案
'use strict'; const Controller = require('egg').Controller; class MainController extends Controller { async index() { const { ctx } = this; await ctx.render('index',{ page_title : "標題", page_content : "模板引擎所渲染的頁面" }); } } module.exports = MainController;
注意:請加上 await 關鍵字,它表示等待一個 Promise 物件,如果不加上,會出現 404 錯誤,
因為在渲染過程中,處理器卻返回了結果(沒資料的結果),自然客戶端也會認為伺服器沒有找到資源。
現在已經跟我們所想的一致,那麼到這裡,你已經具備了開發一個專案的能力;
之後會逐步介紹資料庫連線,資料處理等方法。敬請期待。
1.4.1 多語言配置(將會引用一些官方例子)
多語言顯示(按需配置),很簡單,基於外掛擴充套件能力,我們首先在 config.default.js 中增加配置,完整看起來是這個樣子的:
'use strict'; const path = require('path'); module.exports = appInfo => { return { // Cookie 安全金鑰 keys: "_tourism_2650159865482545.265", // 專案日誌存放資料夾 logger: { dir: path.join(appInfo.baseDir, 'logs'), }, // 渲染模板配置 view: { // 配置檢視根路徑 root: path.join(appInfo.baseDir, 'app/view'), // 是否快取路徑 cache: true, // 配置檔案預設副檔名 defaultExtension: '.qyml', // 預設渲染模板引擎 defaultViewEngine: 'nunjucks', // 檔案對映配置 mapping: { '.qyml': 'nunjucks' } }, // 多語言配置 i18n: { // 預設語言,預設 "en_US" defaultLocale: 'zh-CN', // URL 引數,預設 "locale" queryField: 'locale', // Cookie 記錄的 key, 預設:"locale" cookieField: 'locale', // Cookie 的 domain 配置,預設為空,代表當前域名有效 cookieDomain: '', // Cookie 預設 `1y` 一年後過期, 如果設定為 Number,則單位為 ms cookieMaxAge: '1y', } }; };
最新版的 eggjs 中預設開啟多語言外掛,所以我們不必手動啟用。
之後在 config 目錄下建立一個 locale 資料夾【重要:拼寫一定要正確】
在 locale 資料夾中建立所需配置的語言檔案(圖僅示例兩種),可以是 JSON 檔案,也可以是 JS 檔案,大概是這樣的(我的是 JS 格式):
所有的多語言開發都會基於一種語言,我以英語為例(國際化也都是英語):
zh-CN.js 是這樣配置的(用官方的例子):
module.exports = { "Email": "郵箱", "Welcome back, %s!": "歡迎回來,%s!" };
如果你是基於 JSON 檔案,也就是 zh-CN.json ,那麼編寫是這個樣子的:
{ "Email": "郵箱", "Welcome back, %s!": "歡迎回來,%s!" }
就算是英語也需要配置:
en_US.js 會是這樣編寫的:
module.exports = { "Email": "Email", "Welcome back, %s!": "Welcome back,%s!" };
至於 %s %d 之類的 format 標識,它們的作用是這樣的(引用官方例子):
// config/locale/zh-CN.js module.exports = { 'Welcome back, %s!': '歡迎回來,%s!', }; ctx.__('Welcome back, %s!', 'Shawn'); // zh-CN => 歡迎回來,Shawn! // en-US => Welcome back, Shawn!
好了,一切準備就緒,如果需要在 Controller 中直接輸出,需要呼叫 __ 方法進行轉義,注意是兩個下斜槓,不是讓你填空...
class HomeController extends Controller { async index() { const ctx = this.ctx; ctx.body = { message: ctx.__('Welcome back, %s!', ctx.user.name) // 或者使用 gettext,gettext 是 __ 函式的 alias // message: ctx.gettext('Welcome back', ctx.user.name) user: ctx.user, }; } }
在檢視模板中這樣使用,假設你是 nunjucks 模板引擎:
<html> <head> <title>{{ page_title }}</title> </head> <body> <h1>{{ __('Welcome back, %s!', page_content) }}</h1> </body> </html>
經過處理後,我們將得到這樣的頁面效果:
現在你也可以開發一個支援多語言的網站了,我所示例的都是基礎程式碼,關於多語言支援請參考以下網址:
https://eggjs.org/zh-cn/core/i18n.html
今天就到這裡了,後續會出一些外掛使用,或者是可以快速開發的方法。
2020-2-11 寫於揭陽
轉載請附上本部落格地址:https://www.cnblogs.com/chongsaid/ 或當前文章連結,否則視為侵犯著作