事情是這樣的
市面上的博客框架有很多,一開始用的WordPress艾栋,后來(lái)試過(guò)hexo、typecho 蛉顽,總想自己寫一個(gè)蝗砾,功能簡(jiǎn)簡(jiǎn)單單就好,只為平時(shí)記點(diǎn)東西用蜂林。再者現(xiàn)在前端那么多有趣的東西也可以搭車玩一下遥诉。比如node+express+webpack+react+mongodb?怕是要搞一下試試哦~
工具搭建
node+express+webpack+react+mongodb的結(jié)構(gòu)中噪叙,難點(diǎn)在于怎么將webpack與node串起來(lái)矮锈,前端工具最經(jīng)典的功能莫過(guò)于監(jiān)聽文件變化自動(dòng)刷新頁(yè)面,告別人肉F5睁蕾。而且苞笨,webpack有個(gè)逆天的熱插拔功能褪贵,不需要刷新頁(yè)面使變更生效营密,比如修改css樣式后姜凄,不需要刷新頁(yè)面就能看到樣式變更钦铁。如今結(jié)合了node,如果修改routes耻警、models和views文件后也能自動(dòng)刷新一下node服務(wù)叹放,想必也是極好的沐寺。本編主要講的就是搭建webpack的過(guò)程渴杆。
node與webpack
server端的express配合 webpack-dev-middleware(處理靜態(tài)資源) 和 webpack-hot-middleware(無(wú)刷新更新) 使client端實(shí)現(xiàn)熱插拔寥枝。而server端則需要通過(guò)重啟服務(wù)器使變更生效宪塔。
而重啟服務(wù)器自然會(huì)使服務(wù)器通知瀏覽器實(shí)現(xiàn)自動(dòng)刷新的web socket連接斷開,reload組件能夠在web socket斷開時(shí)囊拜,在瀏覽器端開啟一個(gè)稍長(zhǎng)于服務(wù)器重啟時(shí)間的定時(shí)任務(wù)某筐,等到服務(wù)器重啟完畢后,再進(jìn)行一次整頁(yè)刷新冠跷。
在reload的‘Using reload in Express’中說(shuō)到‘Reload can be used in conjunction with tools that allow for automatically restarting the server such as supervisor (recommended), nodemon, forever, etc.’所以我們使用 supervisor 來(lái)重啟服務(wù)器南誊。
所以刷新策略為server的變更則重啟node,而client端的變更則是刷新瀏覽器或者熱插拔蜜托。
//app.js
var webpack = require('webpack'),
webpackDevMiddleware = require('webpack-dev-middleware'),
webpackHotMiddleware = require('webpack-hot-middleware'),
webpackDevConfig = require('./webpack.config.js');
var dll = webpack(webpackDllConfig);
var compiler = webpack(webpackDevConfig);
app.use(webpackDevMiddleware(compiler, {
// publicPath與webpack.config.js保持一致
publicPath: webpackDevConfig.output.publicPath,
noInfo: true,
stats: {
colors: true
}
}));
app.use(webpackHotMiddleware(compiler));
var reload = require('reload');
var http = require('http');
var server = http.createServer(app);
reload(server, app);
server.listen(port, function(){
console.log('App (dev) is now running on port 13300!');
});
webpack優(yōu)化
最初的webpack.config.js依舊是require一下webpack和各種插件抄囚,配置entry、output盗冷,module里面scss編譯怠苔、babel編譯同廉、圖片壓縮或轉(zhuǎn)base64仪糖,plugins里面new一下熱插拔,最后把配置exports出來(lái)迫肖。好了锅劝,npm start一下...
webpack怎么沒(méi)跑?打開13300端口一直在轉(zhuǎn)菊花...黑人問(wèn)號(hào)蟆湖?故爵??好吧隅津,事情果然沒(méi)有那么簡(jiǎn)單诬垂。于是我決定去上個(gè)廁所÷兹裕回來(lái)發(fā)現(xiàn)...
webpack同學(xué)build了113s+...端口13300確實(shí)渲染出來(lái)了...第一次结窘,想必比較緊張...喏,不行就分喜歡就買多喝點(diǎn)水重啟試試充蓝,來(lái)隧枫,再來(lái)一發(fā)
25s+,貌似沒(méi)那么夸張了谓苟,修改文件確實(shí)可以自動(dòng)重啟node官脓。但每修改一下文件要等25s打包肯定不科學(xué)。
于是webpack --colors --profile --display-modules
看看怎么回事...
214個(gè)步驟......
jquery就不用打包了涝焙,配置externals卑笨,直接在html引入。webpack在watch模式下打包出來(lái)的文件是在內(nèi)存中而不是實(shí)體文件仑撞,每次文件修改后webpack只更改內(nèi)存文件赤兴,所以可以發(fā)現(xiàn)watch模式下webpack build的很快芭商。同時(shí)也可以發(fā)現(xiàn)像在view頁(yè)面引入打包后的a.js,但在public文件夾中發(fā)現(xiàn)根本沒(méi)有a.js這個(gè)東西搀缠。要直接引入jquery就需要public存在真實(shí)的jquery.js了铛楣。在app.js中把public設(shè)置為靜態(tài)目錄app.use(express.static(path.join(__dirname, 'public')));
,同時(shí)transfer-webpack-plugin
把jquery搬到public
externals: {
jquery: 'window.$'
}
...
new TransferWebpackPlugin([
{from: './client/lib', to: './lib'}
], path.resolve(__dirname)),
同時(shí)艺普,像react這種框架文件就不用參與打包了簸州,用dll方案先打包起來(lái)。dll做的事情就是將第三方庫(kù)比如react這種在開發(fā)中不會(huì)變更的文件打包起來(lái)已一個(gè)變量的形式暴露在全局中歧譬。同時(shí)將所包含的庫(kù)做一個(gè)索引寫在manifest.json中岸浑。
//webpack.dll.config.js
const webpack = require('webpack');
module.exports = {
output: {
path: "./public",
filename: '[name].js',
library: '[name]_library'
},
entry: {
vendor: ['react', 'react-dom']
},
plugins: [
new webpack.DllPlugin({
path: './manifest.json', // 本Dll文件中各模塊的索引,供DllReferencePlugin讀取使用
name: '[name]_library'
})
]
};
//webpack.config.js
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./manifest.json')
})
做了以上優(yōu)化之后發(fā)現(xiàn)瑰步,webpack的打包還是需要將近20s矢洲。其他的像給babel配置exclude也做了,并沒(méi)有什么效果缩焦。經(jīng)驗(yàn)表明读虏,當(dāng)一個(gè)問(wèn)題許久不能解決的時(shí)候就應(yīng)該去上個(gè)廁所。同一個(gè)問(wèn)題一個(gè)場(chǎng)景呆久了思維容易僵化圍著一棵樹吊死袁滥,連周圍的空氣都充滿了bug盖桥,走走換口氣是很有必要的。尿完回來(lái)重新看了一遍打包信息
像singlenote.js這些js题翻,在一開始測(cè)試的時(shí)候其實(shí)沒(méi)什么邏輯在里面但是building長(zhǎng)達(dá)15s揩徊。最后通過(guò)高中生物經(jīng)典的‘控制單一變量法’發(fā)現(xiàn)是babel打包在搞事情啊。嵌赠。塑荒。然鵝,我并沒(méi)有搜到有效的提高babel打包效率的方法姜挺。
退一步想齿税,其實(shí)server端頻繁重啟本來(lái)就不怎么科學(xué),像routes文件一般寫好了路由之后改動(dòng)較少初家,所以要不server端就不要自動(dòng)刷新了吧偎窘。。溜在。(狗子陌知!你忘了曾經(jīng)全棧刷新的誓言了嗎!狗子你變了R蠢摺)
當(dāng)然views只是頁(yè)面模板文件仆葡,還是可以刷新的,需要搶救一下,這時(shí)候需要引入browser-sync來(lái)監(jiān)控view頁(yè)面的修改沿盅。browser-sync這個(gè)插件早年在gulp時(shí)代就已經(jīng)名聲在外把篓,多終端自動(dòng)刷新,真正的change once refresh anywhere~重新寫個(gè)app_browsersync.js腰涧,把reload那一塊替換韧掩。
var bs = require('browser-sync').create();
app.listen(port, function(){
bs.init({
open: false,
ui: false,
notify: false,
proxy: 'localhost:13300',
files: ['./server/views/**'],
port: 8080
});
console.log('App (dev) is going to be running on port 8080 (by browsersync).');
});
線上打包
以上說(shuō)的都是開發(fā)環(huán)境,做的配置都是便于開發(fā)窖铡,線上的打包則沒(méi)有那么多幺蛾子疗锐。比如:熱插拔什么的就不用了;比如css文件要分開费彼,webpack能夠打包各種資源最后打成一個(gè)js滑臊,是的,css也在這個(gè)js里面箍铲,而這樣會(huì)導(dǎo)致css只能在這一整個(gè)js文件下載完畢后才開始渲染雇卷,大大延長(zhǎng)了白屏?xí)r間...
最后一發(fā)優(yōu)化
似乎整的差不多了,真是個(gè)愉快波折的旅程颠猴,于是我把整個(gè)項(xiàng)目都扔到了github上关划,因?yàn)橹岸际窃谖夷赀~的筆記本上敲的,既然放到github上就順便把它拉到開發(fā)機(jī)上玩玩芙粱,速度裝完git祭玉,mongodb后,npm start...
不到2s4号稀!岛都!電腦配置奥梢獭!硬件熬室摺择份!優(yōu)化不僅僅是軟件代碼層面啊烫堤!再算一下荣赶,4位數(shù)毫秒,2s沒(méi)錯(cuò)鸽斟,修整一下大概1s的打包拔创!淚流滿面啊,根本控制不住寄幾富蓄!狗子剩燥,當(dāng)年全棧刷新的誓言我一直記著...當(dāng)我低頭一看,胸前的工卡閃閃發(fā)光...
結(jié)語(yǔ)
如今立倍,這個(gè)簡(jiǎn)潔(簡(jiǎn)陋...)的站點(diǎn)已經(jīng)開始服役灭红。后面再繼續(xù)修整下界面侣滩。