摘要:項(xiàng)目地址腳手架使用過(guò),的同學(xué)都清楚,官方推薦的安裝方式是通過(guò)專用的來(lái)快速搭建一個(gè)由編譯打包的項(xiàng)目框架。用在層的模塊化,在中間層實(shí)現(xiàn)了模塊化。這樣,從中間層到前端都實(shí)現(xiàn)了熱加載。
版權(quán)聲明:更多文章請(qǐng)?jiān)L問(wèn)我的個(gè)人站Keyon Y,轉(zhuǎn)載請(qǐng)注明出處。
項(xiàng)目地址:https://github.com/KeyonY/NodeMiddle
腳手架?使用過(guò)angular2,vue2的同學(xué)都清楚,官方推薦的安裝方式是通過(guò)專用的angular-cli、vue-cli來(lái)快速搭建一個(gè)由webpack編譯、打包的項(xiàng)目框架。
受這兩個(gè)工具的啟發(fā),我在項(xiàng)目之初開(kāi)發(fā)一個(gè)基于webpack的項(xiàng)目框架:
使用express搭載webpack-dev-middleware和webpack-hot-middleware進(jìn)行熱加載
內(nèi)置dev(開(kāi)發(fā)環(huán)境)和 production(生產(chǎn)環(huán)境)兩種啟動(dòng)方式
技術(shù)選型 node開(kāi)發(fā)框架express和koa二選一。
express的更貼近Web Framework這一概念;
express功能極簡(jiǎn),完全是由路由和中間件構(gòu)成一個(gè)的 web 開(kāi)發(fā)框架:從本質(zhì)上來(lái)說(shuō),一個(gè) Express 應(yīng)用就是在調(diào)用各種中間件;
koa使用co作為底層運(yùn)行框架,使用它完全忘記了什么時(shí)候回調(diào)函數(shù)或者callbackshell;
express歷史更久,裝機(jī)量大,文檔完整,第三方的中間件也很多;
我選擇了express作為node開(kāi)發(fā)框架。
模板引擎由于之前用node寫過(guò)restFul的網(wǎng)站(詳見(jiàn)我的博客-NodeJS開(kāi)發(fā)個(gè)人博客網(wǎng)站),比較熟悉jade,所以這次直接選擇了pug作為服務(wù)器端模板引擎。
pug是一個(gè)比較靈活的服務(wù)器端模板,express配置起來(lái)也很簡(jiǎn)單,在根目錄的app.js文件中配置
// 設(shè)置模板引擎的類型
app.set("view engine", "pug");
// 設(shè)置模板文件路徑
app.set("views", path.resolve(__dirname, "src/Views"));
這樣,在express渲染時(shí)候使用 res.render("Home/index", {}),指定對(duì)應(yīng)的頁(yè)面模板路徑就行了,第二個(gè)參數(shù) 是要在pug頁(yè)面使用的數(shù)據(jù)內(nèi)容,json格式。
中間層與后端的異步通信其實(shí)就是個(gè)ajax庫(kù),所以我選擇了axios,vue2官方推薦的ajax庫(kù),內(nèi)置的axios.all(),可以在中間層代理多個(gè)后端請(qǐng)求一并返回,輕松實(shí)現(xiàn)Bigpipe。
模塊化因?yàn)槭蔷W(wǎng)站前臺(tái)頁(yè)面,需要考慮SEO,無(wú)法使用前端框架,所以換個(gè)思路,使用webpack+es6/AMD來(lái)實(shí)現(xiàn)模塊化。
于是,使用webpack作為打包機(jī)+View層的模塊化,從前端層面實(shí)現(xiàn)了模塊化和組件化。
es6用在Contorl層的模塊化,在node中間層實(shí)現(xiàn)了模塊化。
app.js作為項(xiàng)目的啟動(dòng)文件,是express的配置文件,同時(shí)也是運(yùn)行開(kāi)發(fā)環(huán)境 / 生產(chǎn)環(huán)境的配置文件。
通過(guò)node啟動(dòng)時(shí)配置的命令參數(shù),由app.js接收參數(shù),然后運(yùn)行對(duì)應(yīng)的環(huán)境
我們需要安裝cross-env這個(gè)插件
npm i --save-dev cross-env
在package.json的scripts中配置:
... "scripts": { "start": "cross-env NODE_ENV=production node app.js", "dev": "cross-env NODE_ENV=dev supervisor -w app.js app", "build": "webpack --config build/webpack.prod.config.js" } ...
這樣,使用 process.env.NODE_ENV 就可以獲取node啟動(dòng)的環(huán)境參數(shù)。
這里我配置了 開(kāi)發(fā)環(huán)境(dev) 和 生產(chǎn)環(huán)境(production)
開(kāi)發(fā)環(huán)境: 不壓縮代碼,開(kāi)啟devtool生成source-map,便于調(diào)試代碼;
生產(chǎn)環(huán)境: 是用webpack進(jìn)行打包、壓縮、混淆操作,將最終完整的代碼(應(yīng)用)輸出至dist目錄中,然后再啟動(dòng)node服務(wù)器,運(yùn)行應(yīng)用;
上述代碼中還用到了 supervisor插件,這是監(jiān)聽(tīng)node配置文件(app.js)的更改,并自動(dòng)重啟node的。
npm i --save-dev supervisor
前端層面使用webpack-dev-middleware和webpack-hot-middleware,實(shí)現(xiàn)了熱加載。
這樣,從中間層到前端都實(shí)現(xiàn)了熱加載。
node中間層配置在根目錄下新建了config文件夾,將一些常用的配置/參數(shù)、方法抽出來(lái),寫在了config/config.js 和 config/common.js中。
例如,中間層啟動(dòng)的端口號(hào)、應(yīng)用的根目錄(path.resolve(__dirname,"../"))、后端服務(wù)器的ip、前端SEO的description和keywords等參數(shù),都放在了config.js中,通過(guò)AMD規(guī)范在所有使用的文件中統(tǒng)一引入,修改起來(lái)也方便。
app.js
var express = require("express"); var cookieParser = require("cookie-parser"); var path = require("path"); var localOptions = require("./build/localOptions"); var config = require("./config/config"); var bodyParser = require("body-parser"); var auth = require("./middleware/auth"); var log4js = require("./config/log4js"); process.env.NODE_ENV = process.env.NODE_ENV ? process.env.NODE_ENV : "production"; var isDev = process.env.NODE_ENV === "dev"; var app = express(); var port = config.port; app.set("view engine", "pug"); // 設(shè)置模板文件路徑 if (isDev){ app.set("views", path.resolve(__dirname, "src/Views")); }else { app.set("views", path.resolve(__dirname, "dist/Views")); } // app.locals定義的鍵值對(duì)能在模板中直接訪問(wèn) app.locals.env = process.env.NODE_ENV || "dev"; app.locals.reload = true; app.use(cookieParser()); app.use(bodyParser.urlencoded({extended: false})); if (isDev) { // app.locals.pretty = true; // 開(kāi)發(fā)環(huán)境,靜態(tài)文件使用熱插拔 var webpack = require("webpack"); var webpackDevMiddleware = require("webpack-dev-middleware"); var webpackHotMiddleware = require("webpack-hot-middleware"); var webpackDevConfig = require("./build/webpack.dev.config.js"); var compiler = webpack(webpackDevConfig); // 熱插拔 app.use(webpackDevMiddleware(compiler, { publicPath: webpackDevConfig.output.publicPath, noInfo: true, stats: "errors-only" })) app.use(webpackHotMiddleware(compiler, { heartbeat: 1000, noInfo: true, })); // 不能熱插拔的往下執(zhí)行 var reload = require("reload"); var http = require("http"); var server = http.createServer(app); // reload(server, app); reload(app); server.listen(port, () => { console.log("App【dev】 is now running on port " + port + "!"); }); // 靜態(tài)目錄設(shè)置必須有,開(kāi)發(fā)環(huán)境讀取的vendor.js不是內(nèi)存文件; // 靜態(tài)目錄設(shè)置必須放在reload后面,避免頁(yè)面引入reload.js報(bào)錯(cuò) app.use(express.static(path.join(config.root, "src"))); app.use("/", require(path.join(config.configRoot,"/routes"))); }else { // 線上環(huán)境不需要監(jiān)聽(tīng),只需開(kāi)啟node服務(wù)即可 // 設(shè)置node的靜態(tài)文件目錄 app.use(express.static(path.join(config.root, "dist"))); app.use("/",require(path.join(config.configRoot,"/routes"))); // app.listen(process.env.PORT, () => { app.listen(port, () => { console.log("App【production】 is now running on port " + port + "!"); }) } // 捕捉 404錯(cuò)誤 傳給 error路由 app.use("*", auth, (req, res, next) => { let err = new Error("Not Found"); err.status = 404; next(err); }); // 捕獲 error,跳轉(zhuǎn)至error頁(yè)面 app.use((err, req, res, next) => { const sc = err.status || 500; if(err.status == 405){ res.redirect(config.cndesignOrigin + "/Home/GuideAuthentication"); return; } res.status(sc); // 此處需寫入日志 log4js.error(" Status: "+ sc + " Message: " + err.message + " Href: " + localOptions.baseUrl + req.originalUrl + " User-agent: " + req.headers["user-agent"]); res.render("Error/404", { error: err, status: sc, message: err.message, userInfo: req.userInfo_ || { hasLogin: false } }); });
注意Error Handle的掛載的順序,一般掛載到app.use()下,且放在最后。
因?yàn)镋rror Handle的參數(shù)為4個(gè),第一個(gè)參數(shù)err可以通過(guò)路由中的next(err)拋出,這樣所有的路由都可以隨時(shí)拋出error,讓Error Handle來(lái)捕獲。
來(lái)看一下目錄結(jié)構(gòu):
App ├─ .babelrc // babel的配置 ├─ ReadMe ├─ app.js // 啟動(dòng)文件 ├─ build // webpack的配置文件 │ ├─ entrys.js // webpack打包js和css的入口文件 │ ├─ localOptions.js // 前端開(kāi)發(fā)者本地配置文件,本地ip等站點(diǎn)配置 │ ├─ postcss.config.js // postcss的配置文件 │ ├─ webpack.dev.config.js // 開(kāi)發(fā)環(huán)境的webpack打包配置 │ ├─ webpack.dll.config.js // webpack.DllReferencePlugin插件的配置文件 │ └─ webpack.prod.config.js // 生產(chǎn)環(huán)境的webpack打包配置 ├─ config // Model層文件:包括node服務(wù)器的配置、路由和代理接口 │ ├─ common.js // 中間層邏輯處理的公用方法 │ ├─ config.js // node服務(wù)器的配置 │ └─ routes // 路由和代理接口配置 │ ├─ default.js │ ├─ designers.js │ ├─ home.js │ └─ index.js // 路由和接口配置的入口文件 ├─ package.json └─ src // View層文件 ├─ Components // 公用組件 │ ├─ base │ ├─ home │ ├─ index │ ├─ message │ ├─ modals │ ├─ page ├─ Views // 頁(yè)面 │ ├─ Default │ ├─ Error │ ├─ Home │ ├─ Include │ ├─ Messages │ └─ Shared └─ assets // 靜態(tài)文件目錄 ├─ Jcrop ├─ es5-shim-master ├─ images ├─ jquery-1.10.2.min.js ├─ jquery-ui-1.8.24.min.js └─ layui
歡迎繼續(xù)關(guān)注本博的更新
Node中間層實(shí)踐(一)——基于NodeJS的全棧式開(kāi)發(fā)
Node中間層實(shí)踐(二)——搭建項(xiàng)目框架
Node中間層實(shí)踐(三)——webpack配置
Node中間層實(shí)踐(四)——模板引擎pug
Node中間層實(shí)踐(五)——express-中間層的邏輯處理
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/92710.html
摘要:的最后一個(gè)大招就是替換一些傳統(tǒng)的服務(wù)端語(yǔ)言,例如,,等,在業(yè)務(wù)層上面使用來(lái)開(kāi)發(fā)服務(wù)端完全不成問(wèn)題。更多的的使用細(xì)節(jié)和技巧建議關(guān)注美團(tuán)博客大搜車論壇下一篇我們開(kāi)啟如何結(jié)合和搭建一個(gè)開(kāi)發(fā)環(huán)境和項(xiàng)目目錄 往期回顧 前面2期都講得是瀏覽器端的東西比較多,包括Webpack,雖然是Node處理的,但是還是瀏覽器端用的多,對(duì)于現(xiàn)在的前端開(kāi)發(fā)來(lái)說(shuō),不懂一點(diǎn)服務(wù)端的東西,簡(jiǎn)直沒(méi)辦法活,一般的招聘要求都...
摘要:總結(jié)我覺(jué)得,以后基于的全棧式開(kāi)發(fā)的模式將會(huì)越來(lái)越流行,這也會(huì)引領(lǐng)前端步入工程化時(shí)代。歡迎繼續(xù)關(guān)注本博的更新中間層實(shí)踐一基于的全棧式開(kāi)發(fā)中間層實(shí)踐二搭建項(xiàng)目框架中間層實(shí)踐三配置中間層實(shí)踐四模板引擎中間層實(shí)踐五中間層的邏輯處理 版權(quán)聲明:更多文章請(qǐng)?jiān)L問(wèn)我的個(gè)人站Keyon Y,轉(zhuǎn)載請(qǐng)注明出處。 前言 近期公司有個(gè)新項(xiàng)目,由于后端人手不足,我果斷的提議用node中間層的方案,得到了老大的支持...
摘要:的意思是,如果碰到不能的情況,就整頁(yè)刷新首頁(yè)路由開(kāi)發(fā)環(huán)境中使用了,需要將每一個(gè)的配置中寫上歡迎繼續(xù)關(guān)注本博的更新中間層實(shí)踐一基于的全棧式開(kāi)發(fā)中間層實(shí)踐二搭建項(xiàng)目框架中間層實(shí)踐三配置中間層實(shí)踐四模板引擎中間層實(shí)踐五中間層的邏輯處理 版權(quán)聲明:更多文章請(qǐng)?jiān)L問(wèn)我的個(gè)人站Keyon Y,轉(zhuǎn)載請(qǐng)注明出處。 這里沒(méi)什么可說(shuō)的,webpack的配置和插件實(shí)在太多了,用的時(shí)候查文檔就行了。 項(xiàng)目地...
摘要:解決思路服務(wù)器端渲染服務(wù)器端和前端公用同一個(gè)應(yīng)用,然后通過(guò)構(gòu)建工具及配置,確定哪些組件需要再服務(wù)器端渲染,那些組件需要再客戶端渲染。服務(wù)器端渲染,由框架與構(gòu)建工具配合,并依據(jù)一定的項(xiàng)目結(jié)構(gòu)和編碼方式,共同運(yùn)行。 分離 為什么需要 前后端分離、web服務(wù)器與static服務(wù)器分離: 前端與后端耦合 (需求) 自動(dòng)化、工程化的構(gòu)建前端的代碼 (基礎(chǔ)條件) 模塊化、組件化,項(xiàng)目共享代碼 (...
閱讀 2042·2023-04-26 01:33
閱讀 1669·2023-04-26 00:52
閱讀 1052·2021-11-18 13:14
閱讀 5466·2021-09-26 10:18
閱讀 2919·2021-09-22 15:52
閱讀 1498·2019-08-29 17:15
閱讀 3028·2019-08-29 16:11
閱讀 1046·2019-08-29 16:11