引子:
別的復(fù)雜前端開(kāi)發(fā)技術(shù)不會(huì)浆熔,用得多的還是手寫(xiě)代碼吴攒,手動(dòng)處理。
3年前手寫(xiě)合并壓縮js和css文件的asp腳本代碼目前還能正常運(yùn)行孤页,也就沒(méi)有多大使用別的技術(shù)的動(dòng)力。
直到近期被一個(gè)問(wèn)題糾結(jié)著涩馆,今天花了一天時(shí)間摸索完成了一個(gè)后端構(gòu)建功能行施。
目前接觸到的項(xiàng)目前端開(kāi)發(fā)模式基本上是一樣的
- 項(xiàng)目不會(huì)很大
- 通用css、js魂那、第三方庫(kù)會(huì)獨(dú)立成單個(gè)文件
- 頁(yè)面依賴(lài)的多個(gè)文件會(huì)合并成一個(gè)css或js文件蛾号,并進(jìn)行自定義語(yǔ)法編譯和壓縮混淆
- 多個(gè)頁(yè)面會(huì)用到的但不夠通用的會(huì)獨(dú)立成一個(gè)html文件,內(nèi)嵌style涯雅、script標(biāo)簽鲜结,服務(wù)器端后端運(yùn)行時(shí)包含進(jìn)來(lái)
- 頁(yè)面使用的js、css完全內(nèi)嵌style斩芭、script標(biāo)簽(無(wú)法抗拒的優(yōu)點(diǎn):打開(kāi)一個(gè)文件就能看到所有源代碼)
- 曉得這種模式很low轻腺,不過(guò)好用
了解到的前端構(gòu)建方式
針對(duì)2、3項(xiàng)划乖,跟目前看到的前端自動(dòng)化構(gòu)建工具贬养,比如:webpack、gulp琴庵,其實(shí)處理思想上還是比較吻合误算,壓縮混淆實(shí)現(xiàn)是調(diào)用的一個(gè)壓縮js和css網(wǎng)站的接口tool.css-js.com/compressor.html
。
針對(duì)4迷殿、5項(xiàng)這種內(nèi)嵌的style和script儿礼,以前是沒(méi)有任何處理,一個(gè)月前特意加上了壓縮混淆功能庆寺。實(shí)現(xiàn)方式是開(kāi)發(fā)階段完成相關(guān)文件的壓縮混淆:壓縮混淆是只要頁(yè)面一運(yùn)行蚊夫,相關(guān)前端代碼后端會(huì)自動(dòng)化處理;然后手動(dòng)上傳結(jié)果到服務(wù)器懦尝。如果源碼有改動(dòng)知纷,必須重新壓縮混淆和上傳文件(自己寫(xiě)的后臺(tái)工具是這樣的規(guī)則)。
最近就是被如果源碼有改動(dòng)陵霉,必須重新壓縮混淆和上傳文件
這個(gè)問(wèn)題困擾著琅轧,一個(gè)是操作復(fù)雜,致命的是:如果漏上傳了混淆后的文件踊挠。乍桂。。
好,現(xiàn)在知道目前采用的壓縮混淆方式了:編寫(xiě)前端代碼睹酌,后端代碼自動(dòng)處理生成新的壓縮混淆后的代碼权谁。
前奏
既然后端已經(jīng)有壓縮混淆功能了,那么還要這么復(fù)雜的操作流程就多余了忍疾。為什么不扔到服務(wù)器上自動(dòng)處理闯传?是考慮到第三方網(wǎng)站接口的穩(wěn)定性,如果他們掛了卤妒,至少不影響線上功能(他們確實(shí)經(jīng)常掛)。
問(wèn)題出在第三方壓縮混淆接口上字币,那把功能本地化不就穩(wěn)定了则披,沒(méi)毛病是這個(gè)邏輯。
昨天想了一下洗出,如果要本地實(shí)現(xiàn)壓縮混淆css和js士复,涉及的代碼有點(diǎn)多,就放棄了翩活。
今天上午又想了一下阱洪,如果不提前搞好,光生成出來(lái)的文件就一大堆菠镇,而且本質(zhì)是次要的生成文件冗荸,提交svn的時(shí)候還要特殊對(duì)待,不提交又會(huì)導(dǎo)致新檢出項(xiàng)目可能丟失文件利耍,提交的話(huà)又算是垃圾文件蚌本。還要上傳,如果是差異更新就有的對(duì)比了隘梨。必須動(dòng)手了程癌。
進(jìn)行時(shí)
要壓縮css,有很多辦法:正則替換空白
轴猎,不過(guò)復(fù)雜css格式去掉空白后語(yǔ)義是不是一致就難說(shuō)了嵌莉;用現(xiàn)成的工具,甚至可以帶來(lái)更好的開(kāi)發(fā)方式的less
捻脖、sass
锐峭,最終采用了less,看別人說(shuō)的sass比less更好郎仆,不過(guò)要額外學(xué)和安裝Ruby起點(diǎn)比less高了許多只祠;最終采用less方案。
壓縮js扰肌,uglifyjs
不二選擇抛寝。
安裝node模塊
cnpm install -g ing...
目前最新版本less 3.0.1壓縮css遇到問(wèn)題:The compress option has been deprecated
-x
新版本選項(xiàng)不能用了,得知裝上less-plugin-clean-css
用--clean-css
命令可以進(jìn)行壓縮。
好吧裝上less-plugin-clean-css 1.5.1盗舰,Unable to load plugin clean-css please make sure that it is installed
識(shí)別不到么晶府,到less-plugin-clean-css
看到一個(gè)issusehttps://github.com/less/less-plugin-clean-css/issues/24
說(shuō)是要降級(jí)到2.x。
cnpm show less versions
查詢(xún)到less 2.x最高版本2.7.3钻趋,裝上壓縮成功川陆。
uglifyjs 3.3.16最新版,裝上就能壓縮混淆蛮位,研究了一下參數(shù)较沪,提供-m -c
兩個(gè)參數(shù)就足夠了,-m
混淆變量名失仁,-c
壓縮優(yōu)化代碼尸曼。
后端代碼接入和運(yùn)行測(cè)試
后端接入方式和控制臺(tái)敲命令行是一樣的,通過(guò)cmd調(diào)用less 或 uglifyjs進(jìn)行處理文件代碼萄焦,接入進(jìn)來(lái)很快的控轿。
測(cè)試?yán)玻簑in7環(huán)境
測(cè)試打開(kāi)新頁(yè)面速度:
比以前慢5、6倍
測(cè)試壓縮一個(gè)23k js:
調(diào)用tool.css-js.com/compressor.html
接口大概要270毫秒
后臺(tái)代碼壓縮需要580毫秒
測(cè)試后臺(tái)代碼執(zhí)行uglifyjs -V
:需要350多毫秒
測(cè)試后臺(tái)代碼執(zhí)行echo 123
:需要0毫秒
測(cè)試分析:
實(shí)際壓縮混淆速度580-350=230毫秒拂封,和第三方接口出入不大茬射。
cmd調(diào)用速度0毫秒也可以忽略。
那就是啟動(dòng)uglifyjs而外占用了350毫秒冒签,猜了一下在抛,每次啟動(dòng)壓縮混淆都會(huì)重新啟動(dòng)node,然后初始化uglifyjs镣衡,所以導(dǎo)致巨慢霜定,大文件還好,小文件就不得了廊鸥,調(diào)用第三方接口40毫秒搞定的時(shí)望浩,后臺(tái)代碼至少要400毫秒起步。從而導(dǎo)致了頁(yè)面打開(kāi)速度變慢很多倍惰说。
基本上頁(yè)面上的script和style都是小的片段磨德,這個(gè)速度不能接受。
優(yōu)化
雖然已經(jīng)能夠?qū)崿F(xiàn)壓縮混淆了吆视,但是壓縮必須經(jīng)過(guò)啟動(dòng)速度巨慢這個(gè)問(wèn)題不能接受典挑。
既然是node和模塊啟動(dòng)的問(wèn)題導(dǎo)致的,那么將所有的壓縮混淆共用一次啟動(dòng)過(guò)程不就解決了啦吧?是這樣的您觉。
怎么共用?用cmd肯定復(fù)雜了授滓,直接上node琳水,啟動(dòng)和初始化所有模塊后等著命令的輸入肆糕,然后進(jìn)行壓縮混淆,然后繼續(xù)接受命令在孝,往復(fù)循環(huán)诚啃。
如此方式用http server最合適不過(guò)了,啟動(dòng)和初始化所有模塊私沮,等待http請(qǐng)求始赎,一有請(qǐng)求就馬上處理并返回結(jié)果。
上code:
package.json里面的模塊依賴(lài):
{
"name": "node_server",
"version": "1.0.0",
"main": "server.js",
"dependencies": {
"uglify-js": "3.3.16",
"less": "2.7.3",
"less-plugin-clean-css": "1.5.1"
}
}
server.js node程序啟動(dòng)代碼仔燕,特意只監(jiān)聽(tīng)127.0.0.1省的配置防火墻
var http = require('http');
var querystring = require('querystring');
var UglifyJS = require("uglify-js");
var less = require('less');
var cleanCss = require("less-plugin-clean-css");
http.createServer(function (req, rep) {
var ctx={c:0,m:"",v:""};
var post = '';
req.on('data', function(chunk){
post += chunk;
});
req.on('end', function(){
(async function(){
try{
var params = querystring.parse(post);
var path0=(/^\/([^\/]+)/.exec(req.url)||[])[1]||"";
if(path0=="test"){
ctx.v="test";
}else if(path0=="buildcss"){
ctx.v=await BuildCss(params);
}else if(path0=="buildjs"){
ctx.v=await BuildJs(params);
};
}catch(e){
ctx.c=1;
ctx.m="執(zhí)行出錯(cuò):"+e.stack;
};
try{
var sendData=JSON.stringify(ctx);
}catch(e){
ctx={c:1,m:"返回?cái)?shù)據(jù)失斣於狻:"+e.stack};
sendData=JSON.stringify(ctx);
}
rep.writeHead(200, {'Content-Type': 'text/json; charset=utf-8'});
rep.end(sendData);
})();
});
}).listen(8004,"127.0.0.1");
function BuildCss(params){
return new Promise(function (resolve, reject) {
less.render(params.code||"", { plugins: [new cleanCss({advanced: true})] })
.then(function(output) {
resolve(output.css);
},function(e) {
reject(new Error(e.message));
});
});
};
function BuildJs(params){
return new Promise(function (resolve, reject) {
var res=UglifyJS.minify(params.code||"");
if(res.error){
reject(res.error);
}else{
resolve(res.code);
};
});
};
提供接口地址:
http://127.0.0.1:8004/test
程序運(yùn)行狀態(tài)測(cè)試
http://127.0.0.1:8004/buildcss
post
code=css代碼
編譯css
http://127.0.0.1:8004/buildjs
post
code=js代碼
編譯js
接口返回結(jié)果
{c:0,m"錯(cuò)誤消息",v:"沒(méi)有錯(cuò)誤時(shí)返回的結(jié)果"}
,c為狀態(tài)碼涨享,如果出錯(cuò)c!=0筋搏,并提供錯(cuò)誤消息,沒(méi)有錯(cuò)誤時(shí)v有值厕隧。
如何運(yùn)行
沒(méi)有怎么用node和npm,經(jīng)驗(yàn)不足俄周,不過(guò)還是能跑起來(lái):
- 安裝node
- 安裝cnpm
npm install -g cnpm --registry=https://registry.npm.taobao.org
npm太慢了 - 文件夾內(nèi)新建package.json吁讨,把代碼copy進(jìn)去
- 文件夾內(nèi)新建server.js,把代碼copy進(jìn)去
- 文件夾這個(gè)目錄上下文內(nèi)執(zhí)行cmd命令
cnpm install
峦朗,自動(dòng)下載依賴(lài)模塊 -
npm start
啟動(dòng) - 瀏覽器內(nèi)輸入
http://127.0.0.1:8004/test
測(cè)試運(yùn)行狀態(tài)
最終
再次測(cè)試壓縮一個(gè)23k js:
調(diào)用tool.css-js.com/compressor.html
接口大概要270毫秒
后臺(tái)代碼壓縮需要140毫秒
比第三方接口還要快,估計(jì)是新版本的原因吧厅克,(不要看網(wǎng)速影響笆檀,最多影響10ms就不錯(cuò)了)