Express 教程第二部分:建立一個骨架網站
這是我們Express 教程的第二篇文章,它展示瞭如何建立一個“骨架”網站專案,然後你可以用特定於網站的路由、模板/檢視和資料庫呼叫來填充它。
| 預備知識 | 設定 Node 開發環境。複習 Express 教程。 |
|---|---|
| 目標 | 能夠使用 Express 應用程式生成器啟動你自己的新網站專案。 |
概述
本文展示瞭如何使用 Express 應用程式生成器工具建立一個“骨架”網站,然後你可以用特定於網站的路由、檢視/模板和資料庫呼叫來填充它。在這種情況下,我們將使用該工具為我們的本地圖書館網站建立框架,稍後我們將為該網站新增所有其他所需的程式碼。這個過程非常簡單,只需要你在命令列中呼叫生成器並指定一個新的專案名稱,還可以選擇指定網站的模板引擎和 CSS 生成器。
以下部分將向你展示如何呼叫應用程式生成器,並對不同的檢視/CSS 選項進行一些解釋。我們還將解釋骨架網站的結構。最後,我們將展示如何執行網站以驗證其是否正常工作。
備註
- Express 應用程式生成器並不是 Express 應用程式的唯一生成器,生成的專案也不是組織檔案和目錄的唯一可行方式。然而,生成的網站確實有一個模組化結構,易於擴充套件和理解。有關最小 Express 應用程式的資訊,請參閱Hello world 示例(Express 文件)。
- Express 應用程式生成器使用
var聲明瞭大多數變數。我們在教程中將其中大部分更改為const(少數更改為let),因為我們希望演示現代 JavaScript 實踐。 - 本教程使用 Express 和其他依賴項的版本,這些版本在 Express 應用程式生成器建立的 package.json 中定義。這些版本不一定是最新版本,在將實際應用程式部署到生產環境時,你應該更新它們。
使用應用程式生成器
你已經應該在設定 Node 開發環境時安裝了生成器。快速回顧一下,你可以使用 npm 包管理器在全站範圍內安裝生成器工具,如下所示
npm install express-generator -g
生成器有許多選項,你可以使用 --help(或 -h)命令在命令列中檢視它們。
> express --help
Usage: express [options] [dir]
Options:
--version output the version number
-e, --ejs add ejs engine support
--pug add pug engine support
--hbs add handlebars engine support
-H, --hogan add hogan.js engine support
-v, --view <engine> add view <engine> support (dust|ejs|hbs|hjs|jade|pug|twig|vash) (defaults to jade)
--no-view use static html instead of view engine
-c, --css <engine> add stylesheet <engine> support (less|stylus|compass|sass) (defaults to plain CSS)
--git add .gitignore
-f, --force force on non-empty directory
-h, --help output usage information
你可以指定 Express 在當前目錄中建立專案,使用 Jade 檢視引擎和純 CSS(如果你指定目錄名,則專案將在該名稱的子資料夾中建立)。
express
你還可以使用 --view 選擇一個檢視(模板)引擎,和/或使用 --css 選擇一個 CSS 生成引擎。
注意:選擇模板引擎的其他選項(例如,--hogan、--ejs、--hbs 等)已棄用。請使用 --view(或 -v)。
我應該使用哪個檢視引擎?
Express 應用程式生成器允許你配置許多流行的檢視/模板引擎,包括 EJS、Hbs、Pug (Jade)、Twig 和 Vash,儘管如果你不指定檢視選項,它預設選擇 Jade。Express 本身也可以開箱即用地支援大量其他模板語言。
注意:如果你想使用生成器不支援的模板引擎,請參閱 將模板引擎與 Express 一起使用 (Express 文件) 和你的目標檢視引擎的文件。
一般來說,你應該選擇一個能夠提供你所需所有功能並讓你更快地提高生產力的模板引擎——換句話說,就像你選擇任何其他元件一樣!在比較模板引擎時需要考慮的一些因素:
- 生產力時間 — 如果你的團隊已經有使用某種模板語言的經驗,那麼他們使用該語言可能會更快地提高生產力。如果沒有,那麼你應該考慮候選模板引擎的相對學習曲線。
- 流行度和活躍度 — 檢視引擎的流行度以及它是否有一個活躍的社群。在網站的整個生命週期中出現問題時,能夠獲得支援是很重要的。
- 樣式 — 有些模板引擎使用特定的標記來指示“普通”HTML 中插入的內容,而另一些則使用不同的語法(例如,使用縮排和塊名稱)來構建 HTML。
- 效能/渲染時間。
- 功能——你應該考慮你所檢視的引擎是否具有以下可用功能:
- 佈局繼承:允許您定義一個基本模板,然後只繼承您希望特定頁面不同的部分。這通常比透過包含多個所需元件或每次從頭構建模板來構建模板更好。
- “包含”支援:允許您透過包含其他模板來構建模板。
- 簡潔的變數和迴圈控制語法。
- 能夠在模板級別過濾變數值,例如將變數轉換為大寫,或格式化日期值。
- 能夠生成除 HTML 之外的其他輸出格式,例如 JSON 或 XML。
- 支援非同步操作和流式傳輸。
- 客戶端功能。如果模板引擎可以在客戶端使用,則可以實現所有或大部分渲染在客戶端完成。
注意:網際網路上有很多資源可以幫助你比較不同的選項!
對於這個專案,我們將使用 Pug 模板引擎(以前稱為“Jade”),因為它是最流行的 Express/JavaScript 模板語言之一,並且生成器開箱即用就支援它。
我應該使用哪個 CSS 樣式表引擎?
Express 應用程式生成器允許你建立一個配置為使用最常見的 CSS 樣式表引擎的專案:LESS、SASS、Stylus。
注意:CSS 存在一些限制,使得某些任務變得困難。CSS 樣式表引擎允許你使用更強大的語法來定義你的 CSS,然後將定義編譯成瀏覽器使用的純舊 CSS。
與模板引擎一樣,你應該使用能讓你的團隊最高效的樣式表引擎。對於這個專案,我們將使用普通的 CSS(預設),因為我們的 CSS 需求不夠複雜,不需要使用其他任何東西。
我應該使用哪個資料庫?
生成的程式碼不使用/包含任何資料庫。Express 應用程式可以使用 Node 支援的任何資料庫機制(Express 本身不定義任何特定的資料庫管理附加行為/要求)。
我們將在後續文章中討論如何與資料庫整合。
建立專案
對於我們將要構建的示例 Local Library 應用程式,我們將使用 Pug 模板庫和無 CSS 引擎建立一個名為 express-locallibrary-tutorial 的專案。
首先,導航到你想要建立專案的位置,然後在命令提示符下執行 Express 應用程式生成器,如下所示
express express-locallibrary-tutorial --view=pug
生成器將建立(並列出)專案檔案。
create : express-locallibrary-tutorial\
create : express-locallibrary-tutorial\public\
create : express-locallibrary-tutorial\public\javascripts\
create : express-locallibrary-tutorial\public\images\
create : express-locallibrary-tutorial\public\stylesheets\
create : express-locallibrary-tutorial\public\stylesheets\style.css
create : express-locallibrary-tutorial\routes\
create : express-locallibrary-tutorial\routes\index.js
create : express-locallibrary-tutorial\routes\users.js
create : express-locallibrary-tutorial\views\
create : express-locallibrary-tutorial\views\error.pug
create : express-locallibrary-tutorial\views\index.pug
create : express-locallibrary-tutorial\views\layout.pug
create : express-locallibrary-tutorial\app.js
create : express-locallibrary-tutorial\package.json
create : express-locallibrary-tutorial\bin\
create : express-locallibrary-tutorial\bin\www
change directory:
> cd express-locallibrary-tutorial
install dependencies:
> npm install
run the app (Bash (Linux or macOS))
> DEBUG=express-locallibrary-tutorial:* npm start
run the app (PowerShell (Windows))
> $env:DEBUG = "express-locallibrary-tutorial:*"; npm start
run the app (Command Prompt (Windows)):
> SET DEBUG=express-locallibrary-tutorial:* & npm start
在輸出的末尾,生成器提供了有關如何安裝依賴項(如 package.json 檔案中列出的)以及如何在不同作業系統上執行應用程式的說明。
注意:生成器建立的檔案將所有變數定義為 var。在繼續之前,開啟所有生成的檔案,並將 var 宣告更改為 const(本教程的其餘部分假定你已完成此操作)。
執行骨架網站
至此,我們有了一個完整的骨架專案。這個網站實際上還沒有做很多事情,但值得執行一下來證明它能工作。
-
首先,安裝依賴項(
install命令將獲取專案 package.json 檔案中列出的所有依賴包)。bashcd express-locallibrary-tutorial npm install -
然後執行應用程式。
-
在 Windows CMD 提示符下,使用此命令
批處理SET DEBUG=express-locallibrary-tutorial:* & npm start -
在 Windows PowerShell 中,使用此命令
powershell$env:DEBUG = "express-locallibrary-tutorial:*"; npm start注意:本教程不涉及 PowerShell 命令(所提供的“Windows”命令假定您使用的是 Windows CMD 提示符)。
-
在 macOS 或 Linux 上,使用此命令
bashDEBUG=express-locallibrary-tutorial:* npm start
-
-
然後,在瀏覽器中載入
https://:3000/訪問應用程式。
你應該會看到一個如下所示的瀏覽器頁面

恭喜!你現在擁有一個可工作的 Express 應用程式,可以透過埠 3000 訪問。
注意:你也可以只使用 npm start 命令啟動應用程式。如所示指定 DEBUG 變數可以啟用控制檯日誌/除錯。例如,當你訪問上面頁面時,你將看到如下除錯輸出
SET DEBUG=express-locallibrary-tutorial:* & npm start
> express-locallibrary-tutorial@0.0.0 start D:\github\mdn\test\exprgen\express-locallibrary-tutorial > node ./bin/www express-locallibrary-tutorial:server Listening on port 3000 +0ms GET / 304 490.296 ms - - GET /stylesheets/style.css 200 4.886 ms - 111
啟用檔案更改時伺服器重啟
你對 Express 網站所做的任何更改目前都不可見,直到你重新啟動伺服器。每次進行更改時都必須停止和重新啟動伺服器很快就會變得非常煩人,因此值得花時間在需要時自動化伺服器重新啟動。
為此目的,一個方便的工具是 nodemon。它通常全域性安裝(因為它是一個“工具”),但在這裡我們將它作為開發依賴在本地安裝和使用,這樣任何使用該專案的開發人員在安裝應用程式時都會自動獲得它。在骨架專案的根目錄中使用以下命令
npm install --save-dev nodemon
如果你仍然選擇將 nodemon 全域性安裝到你的機器上,而不僅僅是安裝到你專案的 package.json 檔案中
npm install -g nodemon
如果你開啟專案的 package.json 檔案,你現在會看到一個包含此依賴項的新部分
{
"devDependencies": {
"nodemon": "^3.1.10"
}
}
由於該工具不是全域性安裝的,我們不能從命令列啟動它(除非我們將其新增到路徑中)。但是,我們可以從 npm 指令碼呼叫它,因為 npm 知道哪些包已安裝。找到 package.json 檔案中的 scripts 部分。最初,它將包含一行,以 "start" 開頭。透過在該行末尾新增逗號,並新增 "devstart" 和 "serverstart" 行來更新它
-
在 Linux 和 macOS 上,指令碼部分將如下所示
json{ "scripts": { "start": "node ./bin/www", "devstart": "nodemon ./bin/www", "serverstart": "DEBUG=express-locallibrary-tutorial:* npm run devstart" } } -
在 Windows 上,“serverstart”的值將如下所示(如果使用命令提示符)
bash"serverstart": "SET DEBUG=express-locallibrary-tutorial:* & npm run devstart"
我們現在可以用幾乎與以前完全相同的方式啟動伺服器,但是使用 devstart 命令。
注意:現在,如果你修改專案中的任何檔案,伺服器將重新啟動(或者你可以在命令提示符下隨時鍵入 rs 來重新啟動它)。你仍然需要重新載入瀏覽器以重新整理頁面。
我們現在必須呼叫 npm run <script-name> 而不是僅僅呼叫 npm start,因為“start”實際上是一個 npm 命令,它對映到命名的指令碼。我們可以替換 start 指令碼中的命令,但我們只想在開發過程中使用 nodemon,因此建立新的指令碼命令是有意義的。
上面新增到 package.json 指令碼中的 serverstart 命令是一個很好的例子。使用這種方法意味著你不再需要輸入一個長命令來啟動伺服器。請注意,新增到指令碼中的特定命令僅適用於 macOS 或 Linux。
生成的專案
現在我們來看看剛剛建立的專案。我們將對其進行一些小的修改。
目錄結構
現在你已經安裝了依賴項,生成的專案具有以下檔案結構(檔案是不以“/”為字首的項)。package.json 檔案定義了應用程式的依賴項和其他資訊。它還定義了一個啟動指令碼,該指令碼將呼叫應用程式的入口點,即 JavaScript 檔案 /bin/www。該檔案設定了一些應用程式錯誤處理,然後載入 app.js 來完成其餘的工作。應用程式路由儲存在 routes/ 目錄下的單獨模組中。模板儲存在 /views 目錄下。
express-locallibrary-tutorial
app.js
/bin
www
package.json
package-lock.json
/node_modules
[about 6700 subdirectories and files]
/public
/images
/javascripts
/stylesheets
style.css
/routes
index.js
users.js
/views
error.pug
index.pug
layout.pug
以下部分將更詳細地描述這些檔案。
package.json
package.json 檔案定義了應用程式的依賴項和其他資訊
{
"name": "express-locallibrary-tutorial",
"version": "0.0.0",
"private": true,
"scripts": {
"start": "node ./bin/www"
},
"dependencies": {
"cookie-parser": "~1.4.4",
"debug": "~2.6.9",
"express": "~4.16.1",
"http-errors": "~1.6.3",
"morgan": "~1.9.1",
"pug": "2.0.0-beta11"
},
"devDependencies": {
"nodemon": "^3.1.10"
}
}
指令碼部分首先定義了一個“start”指令碼,當我們呼叫 npm start 來啟動伺服器時,我們就是呼叫這個指令碼(這個指令碼是由 Express 應用程式生成器新增的)。從指令碼定義中,你可以看到它實際上是用 node 啟動了 JavaScript 檔案 ./bin/www。
我們已經在啟用檔案更改時伺服器重啟中修改了這一部分,添加了 devstart 和 serverstart 指令碼。這些指令碼可以用來用 nodemon 而不是 node 啟動相同的 ./bin/www 檔案(如上所述,這些指令碼版本適用於 Linux 和 macOS)。
{
"scripts": {
"start": "node ./bin/www",
"devstart": "nodemon ./bin/www",
"serverstart": "DEBUG=express-locallibrary-tutorial:* npm run devstart"
}
}
依賴項包括 express 包和我們選擇的檢視引擎 (pug) 的包。此外,我們還有以下在許多 Web 應用程式中都有用的包
- cookie-parser:用於解析 cookie 頭並填充
req.cookies(本質上提供了一種方便的訪問 cookie 資訊的方法)。 - debug:一個微小的 Node 除錯工具,仿照 Node 核心的除錯技術。
- morgan:Node 的 HTTP 請求日誌中介軟體。
- http-errors:在需要時建立 HTTP 錯誤(用於 Express 錯誤處理)。
生成專案中的預設版本有點過時了。用以下文字替換 package.json 檔案的依賴項部分,該文字指定了撰寫本文時這些庫的最新版本
{
"dependencies": {
"cookie-parser": "^1.4.7",
"debug": "^4.4.1",
"express": "^5.1.0",
"http-errors": "~2.0.0",
"morgan": "^1.10.0",
"pug": "3.0.3"
}
}
然後使用以下命令更新已安裝的依賴項
npm install
注意:定期更新到依賴庫的最新相容版本是一個好主意——這甚至可以透過持續整合設定自動或半自動完成。
通常,次要版本和補丁版本的庫更新會保持相容。我們上面在每個版本前加上 ^,這樣我們就可以透過執行以下命令自動更新到最新的 minor.patch 版本
npm update --save
主要版本會改變相容性。對於這些更新,我們需要手動更新 package.json 和使用該庫的程式碼,並對專案進行全面的重新測試。
www 檔案
檔案 /bin/www 是應用程式的入口點!它做的第一件事是 require() “真正的”應用程式入口點(app.js,在專案根目錄),它設定並返回 express() 應用程式物件。require() 是 CommonJS 方式,用於將 JavaScript 程式碼、JSON 和其他檔案匯入到當前檔案中。這裡我們使用相對路徑指定 app.js 模組,並省略可選的 (.js) 副檔名。
#!/usr/bin/env node
/**
* Module dependencies.
*/
const app = require("../app");
注意:Node.js 14 及更高版本支援 ES6 import 語句來匯入 JavaScript (ECMAScript) 模組。要使用此功能,你必須在 Express 的 package.json 檔案中新增 "type": "module",應用程式中的所有模組都必須使用 import 而不是 require(),並且對於相對匯入,你必須包含副檔名(有關更多資訊,請參閱 Node 文件)。雖然使用 import 有好處,但本教程使用 require() 以與 Express 文件保持一致。
該檔案中其餘的程式碼設定了一個 Node HTTP 伺服器,將 app 設定為特定埠(在環境變數中定義,如果未定義則為 3000),並開始監聽和報告伺服器錯誤和連線。目前你不需要了解程式碼的其他任何內容(該檔案中的所有內容都是“樣板檔案”),但如果你感興趣,可以隨意檢視它。
app.js
此檔案建立一個 express 應用程式物件(按照約定命名為 app),使用各種設定和中介軟體配置應用程式,然後從模組中匯出該應用程式。下面的程式碼僅顯示建立和匯出應用程式物件的檔案部分
const express = require("express");
const app = express();
// …
module.exports = app;
回到上面的 www 入口檔案,當這個檔案被匯入時,這個 module.exports 物件被提供給呼叫者。
讓我們詳細地看看 app.js 檔案。首先,我們使用 require() 將一些有用的 Node 庫匯入到檔案中,包括我們之前使用 npm 為應用程式下載的 http-errors、express、morgan 和 cookie-parser;以及 path,這是一個用於解析檔案和目錄路徑的核心 Node 庫。
const createError = require("http-errors");
const express = require("express");
const path = require("path");
const cookieParser = require("cookie-parser");
const logger = require("morgan");
然後我們 require() 來自我們路由目錄的模組。這些模組/檔案包含處理特定相關“路由”(URL 路徑)的程式碼。當我們擴充套件骨架應用程式時,例如列出圖書館中的所有書籍,我們將新增一個新檔案來處理與書籍相關的路由。
const indexRouter = require("./routes/index");
const usersRouter = require("./routes/users");
注意:此時,我們只是匯入了模組;我們實際上還沒有使用它的路由(這在檔案稍後發生)。
接下來,我們使用匯入的 express 模組建立 app 物件,然後使用它來設定檢視(模板)引擎。設定引擎分為兩部分。首先,我們設定 "views" 值來指定模板將儲存的資料夾(在這種情況下是子資料夾 /views)。然後我們設定 "view engine" 值來指定模板庫(在這種情況下是 "pug")。
const app = express();
// view engine setup
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "pug");
接下來的一組函式呼叫 app.use() 將我們上面匯入的中介軟體庫新增到請求處理鏈中。例如,express.json() 和 express.urlencoded() 需要用於用表單欄位填充 req.body。在這些庫之後,我們還使用 express.static 中介軟體,它使 Express 服務專案根目錄中 /public 目錄中的所有靜態檔案。
app.use(logger("dev"));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, "public")));
現在所有其他中介軟體都已設定好,我們將我們(之前匯入的)路由處理程式碼新增到請求處理鏈中。匯入的程式碼將為網站的不同部分定義特定的路由
app.use("/", indexRouter);
app.use("/users", usersRouter);
注意:上面指定的路徑 ("/" 和 "/users") 被視為匯入檔案中定義的路由的字首。因此,例如,如果匯入的 users 模組定義了 /profile 的路由,你將透過 /users/profile 訪問該路由。我們將在後續文章中討論更多關於路由的內容。
檔案中的最後一箇中間件添加了錯誤和 HTTP 404 響應的處理方法。
// catch 404 and forward to error handler
app.use((req, res, next) => {
next(createError(404));
});
// error handler
app.use((err, req, res, next) => {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get("env") === "development" ? err : {};
// render the error page
res.status(err.status || 500);
res.render("error");
});
Express 應用程式物件(app)現在已完全配置。最後一步是將其新增到模組匯出中(這就是它允許被 /bin/www 匯入的原因)。
module.exports = app;
路由
路由檔案 /routes/users.js 如下所示(路由檔案結構相似,因此我們無需再展示 index.js)。首先,它載入 express 模組並使用它獲取 express.Router 物件。然後,它在該物件上指定一個路由,最後從模組中匯出路由器(這就是檔案可以匯入到 app.js 中的原因)。
const express = require("express");
const router = express.Router();
/* GET users listing. */
router.get("/", (req, res, next) => {
res.send("respond with a resource");
});
module.exports = router;
該路由定義了一個回撥函式,當檢測到具有正確模式的 HTTP GET 請求時,該回調函式將被呼叫。匹配模式是模組匯入時指定的路由 ("/users") 加上此檔案中定義的任何內容 ("/")。換句話說,當收到 /users/ 的 URL 時,將使用此路由。
注意:透過使用 Node 執行伺服器並在瀏覽器中訪問 URL:https://:3000/users/ 來嘗試此操作。你應該會看到一條訊息:“respond with a resource”。
上面一個有趣的地方是回撥函式有第三個引數 next,因此它是一箇中間件函式而不是簡單的路由回撥。雖然程式碼目前沒有使用 next 引數,但如果你想為 '/' 路由路徑新增多個路由處理程式,它將來可能會很有用。
檢視(模板)
檢視(模板)儲存在 /views 目錄中(如 app.js 中指定),並使用 .pug 副檔名。方法 Response.render() 用於渲染指定的模板以及以物件形式傳遞的命名變數值,然後將結果作為響應傳送。在下面來自 /routes/index.js 的程式碼中,你可以看到該路由如何使用模板“index”並傳遞模板變數“title”來渲染響應。
/* GET home page. */
router.get("/", (req, res, next) => {
res.render("index", { title: "Express" });
});
上述路由對應的模板如下(index.pug)。我們稍後將詳細討論語法。現在你只需知道 title 變數(值為 'Express')會插入到模板中指定的位置。
extends layout
block content
h1= title
p Welcome to #{title}
挑戰自我
在 /routes/users.js 中建立一個新路由,該路由將在 URL /users/cool/ 顯示文字“You're so cool”。透過執行伺服器並在瀏覽器中訪問 https://:3000/users/cool/ 來測試它
總結
你現在已經為本地圖書館建立了一個骨架網站專案,並驗證它可以使用 node 執行。最重要的是,你還了解了專案的結構,因此你清楚地知道我們需要在哪裡進行更改以新增本地圖書館的路由和檢視。
接下來,我們將開始修改骨架,使其作為圖書館網站執行。
另見
- Express 應用程式生成器(Express 文件)
- 將模板引擎與 Express 一起使用(Express 文件)