打包並壓縮seajs代碼


背景

  seajs是一款優秀的模塊開發插件,但是當我們使用它來進行模塊化開發的時候,由於它的每個模塊的加載都會進行一次http請求,那么當模塊數量倍增的時候,會拖慢頁面的加載速度。

  通常我們為了能加快頁面的加載速度,都會對js進行壓縮並把關聯的模塊打包為一個獨立的js文件,這樣可以大大減少js的文件大小並且減少http請求的次數,這樣可以提升到頁面的加載速度。

  我們可以是用spm來對js文件進行打包、壓縮(使用spm-build),但是當我們編寫兼容多種環境的js的時候(既可以直接用script引用又可以使用seajs來引用),那么我們就沒辦法使用前面的方法來對js進行打包和壓縮了。

  其次就是使用spm-build還要先了解package.json文件配置,還是有少許麻煩的,為了減輕上手的難度和簡化功能,這里我們將介紹另類的使用nodejs來對js腳本進行壓縮。

實現

  http://tool.css-js.com/站點提供了多種腳本壓縮,通過使用YUI壓縮,我們發現它實際上是使用http的POST來實現代碼壓縮的,如圖:

  

   接着我們使用ajax來進行測試,代碼如下:

$.post('http://tool.css-js.com/!java/?type=js&munge=true&preserveAllSemiColons=false&disableOptimizations=false', {
	code: 'var x = (function() { var foo = 1,  bar = 2; return (foo + bar) }())'
}, function(res){
	console.log(res);
});

  結果跟截圖的效果是相同的,接下來使用nodejs來編寫一個用於讀取js文件並發起http然后把壓縮的拼接到一個獨立的js文件中去。

  使用原生的nodejs的http來發起post的代碼如下:

var m_http = require('http');
var m_qs = require('querystring');
 
var options = {
	host: 'tool.css-js.com',
	port: 80,
	method: 'POST',
	path: '/!java/?type=js&munge=true&preserveAllSemiColons=false&disableOptimizations=false',
	headers: {
		'Content-Type':'application/x-www-form-urlencoded'
	}
};

exports.compress = function (str, callback){
	var req = m_http.request(options, function(res) {
		res.setEncoding('utf-8');

		var compressed = '';
		res.on('data', function(chunk){
			compressed += chunk;
		});
		res.on('end', function(){
			callback(compressed)
		});
	});

	req.write(m_qs.stringify({ code: str }));
	req.end();
};

   有了壓縮的方法,接下來我們需要提供一個可以循環讀取文件夾內的所有js文件並壓縮合並到獨立的js文件的函數,代碼大致如下:

var m_fs = require('fs');
var m_path = require('path');

//其他代碼略

exports.combineDir = function (dir, output){
	var self = this;
	m_fs.readdirSync(dir).forEach(function (filename) {
		if (filename.indexOf('.') === -1) {
			self.compressDir(m_path.join(dir, filename));
			return;
		}

		var path = m_path.join(dir, filename);
		m_fs.readFile(path, 'utf8', function (err, content){
			if (err) {
				return;
			}

			self.compress(content, function (compressed){
				var id = filename.substr(0, filename.indexOf('.'));
				compressed = compressed.replace('this.define(', ['this.define(\'', id, '\','].join(''));
				m_fs.appendFileSync(output, compressed);
			});
		});
    });
};                                                                                                       

   以上代碼之所以要替換'this.define'字符串是因為我們編寫的兼容腳本中,會使用閉包將腳本包含在內部,並在內部對this.define進行判斷,當this.define存在的情況下,才會將編碼的模塊賦值給module.exports來完成模塊,示例代碼如下:

//a.js
(function(){
	var a = (function() { var foo = 1,  bar = 2; return (foo + bar) }())

	if (this.define) {
		this.define(function (require, exports, module) {
			'require:nomunge,exports:nomunge,module:nomunge';
			module.exports = a;
		});
	}
}).call(this);

//b.js
(function(){
	var b = (function() { var foo = 1,  bar = 2; return (foo + bar) }())

	if (this.define) {
		this.define(function (require, exports, module) {
			'require:nomunge,exports:nomunge,module:nomunge';
			module.exports = a;
		});
	}
}).call(this);

   使用編碼好的函數來進行合並后,結果如下:

(function(){var b=(function(){var c=1,a=2;return(c+a)}());if(this.define){this.define('a',function(require,exports,module){module.exports=b})}}).call(this);
(function(){var c=(function(){var d=1,b=2;return(d+b)}());if(this.define){this.define('b',function(require,exports,module){module.exports=a})}}).call(this);

擴展

   對於創建請求,我們可以使用nodegrass來完成我們的功能,它內部封裝了http和https的get、post的函數,簡化了調用,大家可以使用看看。

  其次對於循環文件夾內的js文件,當存在多層嵌套的時候,由於沒有將父級文件夾添加到seajs定義的id內,因此調用合並后的js文件的時候,會出現錯誤,這里就不詳細解說如何解決了,這個問題就留給大家去解決啦。

  對於以上代碼由於使用了異步方法,造成了多層文件嵌套,如果大家覺得嵌套太多導致代碼難看、難以閱讀,可以使用wind.js或者eventproxy.js或者其他的異步js來解決多層嵌套的問題。

結尾

  這次的文章就到這里了,內容中有任何問題不吝賜教,謝謝各位!

  另外感謝http://tool.css-js.com/站點提供的功能.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM