Sea.js模塊打包工具spm

平臺(tái):Windows 7

版本:1.7.7


簡(jiǎn)介

Sea.js實(shí)現(xiàn)了對(duì)JS代碼的模塊化組織,大大提高了前端開(kāi)發(fā)效率。然而在實(shí)際項(xiàng)目中,大量的細(xì)分模塊卻導(dǎo)致大量的腳本請(qǐng)求,拖慢了頁(yè)面加載速度,也給服務(wù)器造成不小的壓力。針對(duì)這一情況,spm(static package manager)因運(yùn)而生,專門(mén)用于打包、壓縮Sea.js模塊以及CSS文件。

Sea.js遵循CMD(Common Module Definition)模塊定義規(guī)范,一個(gè)文件一個(gè)模塊,清清爽爽。CMD模塊定義形如:

define(function(require, exports, module) {

? ? //使用require表達(dá)對(duì)其他CMD模塊的依賴

? ? //使用exports或module.exports或return向外拋出接口

});

spm的打包原理很簡(jiǎn)單,就是將這一形式(Modules/Wrappings)的CMD模塊轉(zhuǎn)換為Modules/Transport形式:

define("id", ["dep-1", "dep-2"], function(require, exports, module) {

? ? //源碼

});

這一過(guò)程僅僅是給模塊換了個(gè)框框,spm需要完成的工作當(dāng)然不止于此,主要可以概括如下:

1、如上述那樣按照Modules/Transport格式在模塊定義中加入標(biāo)識(shí)和依賴,并把多個(gè)模塊合并到一個(gè)文件中(包括CSS);

2、將源碼中的變量名、函數(shù)名等標(biāo)識(shí)符簡(jiǎn)化為a、b、c這樣的單字母,并刪除空格、縮進(jìn)、換行等空白符(所以最終你看到的是一長(zhǎng)串擁擠的、可讀性極低的代碼);

3、識(shí)別無(wú)用代碼后將其刪除,還有其他一些優(yōu)化措施。

這些步驟在本地完成,都是靜態(tài)的文本處理,過(guò)程并不復(fù)雜,如果用起來(lái)不滿意,完全可以自己實(shí)現(xiàn)一個(gè),甚至可以用C語(yǔ)言寫(xiě)。

安裝

首先我們需要Node.js,到官網(wǎng)下載安裝即可,完后記得把安裝路徑(如C:\Program Files\nodejs)加到環(huán)境變量Path里,在cmd中運(yùn)行node -v查看版本以確定是否安裝成功:

接著使用Node.js的包管理工具npm(node package manager)安裝spm。spm版本已更新到3.9,但是從第3版開(kāi)始轉(zhuǎn)向了CommonJS規(guī)范,在打包前需要扒掉所有模塊的define封裝,項(xiàng)目中幾十個(gè)乃至幾百個(gè)文件都需要手動(dòng)處理,實(shí)在犯不著。于是我們轉(zhuǎn)投低版本——spm@2.x或spm@1.x,經(jīng)過(guò)多次測(cè)試,spm@2.x的各個(gè)版本在安裝或使用過(guò)程中總出現(xiàn)莫名其妙的報(bào)錯(cuò),也許是與Windows兼容不佳(具體未能考證),只好拿spm@1.x將就將就——當(dāng)然,spm@1.x已經(jīng)可以滿足所需。

安裝spm前,如果Node.js裝在了C盤(pán),最好通過(guò)以下兩行命令先修改一下npm的全局路徑,否則spm的相關(guān)文件可能會(huì)無(wú)法正常寫(xiě)入磁盤(pán):

npm config set prefix "D:\nodejs\node_global"

npm config set cache "D:\nodejs\node_cache"

(這里以D盤(pán)的一個(gè)路徑為例,當(dāng)然你得先新建好這兩個(gè)文件夾。)

將spm@1.x安裝到全局路徑:

npm install spm@1.x -g

安裝過(guò)程(很不友好,目測(cè)就開(kāi)發(fā)者自己看得懂)

完成后,在剛才設(shè)置的node_global文件夾下可以看到spm的相關(guān)文件,其中spm.cmd就是主程序,將D:\nodejs\node_global添加到環(huán)境變量Path,執(zhí)行spm查看版本和可用指令:

我們需要使用的就是第一個(gè)build指令

如未能順利安裝或安裝后使用有問(wèn)題可以執(zhí)行如下命令卸載spm,而后嘗試重裝(其他版本):

npm uninstall spm -g

使用示例

編寫(xiě)一個(gè)簡(jiǎn)單的示例,功能模塊demo(位于modules目錄下)包含a.js、b.js、c.js三個(gè)CMD模塊,b和c放在subModules文件夾下,a作為入口調(diào)用b,b調(diào)用c:

通過(guò)seajs.use()在頁(yè)面中調(diào)用a模塊:

seajs.use(['modules/demo/a'], function(a) {

? ? a();

});

下面我們使用spm將a、b、c進(jìn)行打包。首先需要一個(gè)工作目錄,比如D:\spmworkspace,將整個(gè)功能模塊(本例中就是demo文件夾)放在這里,而后需要一個(gè)package.json文件,用于編輯spm build的配置信息:

package.json的配置項(xiàng)有很多,這里只用到了一些主要的

"root":功能模塊的根目錄名,這取決于它在整個(gè)項(xiàng)目中處于哪個(gè)位置。

"name":功能模塊的名稱。默認(rèn)情況下,打包后的Modules/Transport模塊標(biāo)識(shí)是對(duì)"root"、"name"和CMD模塊文件名的拼接,如在本例中模塊a的id就是modules/name/a。

"src":源文件夾(要求與package.json在同級(jí)目錄下),存放需要打包的JS文件們。

"to":目標(biāo)文件夾,用于存放打包后生成的文件。該文件夾會(huì)自動(dòng)生成,也與package.json在同級(jí)目錄下。

"output":配置文件合并規(guī)則,這里配置的"a.js"要求在demo文件夾下必須存在相應(yīng)的a.js文件。

配置好后,在cmd中來(lái)到工作目錄D:\spmworkspace下,執(zhí)行spm build:

不要在意那個(gè)血紅的[ERROR],它對(duì)最終結(jié)果并無(wú)影響

此時(shí)在D:\spmworkspace下就出現(xiàn)了一個(gè)dist文件夾,里頭包含a.js和a-debug.js兩個(gè)文件,其中a.js是最終打包結(jié)果:

代碼被擠到一行里,能簡(jiǎn)化的都簡(jiǎn)化了

這是在項(xiàng)目上線時(shí)用的,在開(kāi)發(fā)調(diào)試時(shí),我們可以使用a-debug.js:

換了define封裝,模塊合并至一個(gè)文件中,此外沒(méi)有進(jìn)行任何壓縮,因此保有與打包前相同的可讀性

部署時(shí)直接將a.js替換原本的a.js即可,subModules下的b.js和c.js不再需要,完美運(yùn)行:

可以看到,只加載了壓縮后的a.js,文件總體大小和加載時(shí)間都大大縮減,在實(shí)際項(xiàng)目中打包的CMD模塊越多,表現(xiàn)就越好,這就是spm的價(jià)值所在。

幾點(diǎn)補(bǔ)充

require的路徑問(wèn)題

通常在項(xiàng)目開(kāi)發(fā)中,require主要使用兩種形式的路徑載入其他CMD模塊:

一種是相對(duì)路徑,以./或../開(kāi)頭,這種形式用于同一功能模塊之內(nèi)JS文件之間的相互引用;

一種是全局base尋址形式,直接以文件或文件夾名打頭,形如xxx/xxx,Sea.js會(huì)根據(jù)SeaConfig.js中配置的base路徑來(lái)拼接出絕對(duì)路徑,這種形式用于功能模塊之間JS文件的相互引用,比如有個(gè)實(shí)現(xiàn)通用功能的util模塊,其他功能模塊中的JS通常會(huì)以require(util/utilA)的形式引用。

spm打包是針對(duì)單個(gè)功能模塊的,無(wú)法找到以上述第二種路徑形式require的文件,因此不會(huì)將它們打包進(jìn)來(lái)。確實(shí)對(duì)于其他功能模塊里的東西,也沒(méi)必要都?jí)嚎s進(jìn)來(lái)。

如果一定要將它們一齊打包,就需要用到spm提供的C/S模式的源服務(wù)。使用spm server指令可以在本地構(gòu)建一個(gè)源服務(wù)器,局域網(wǎng)內(nèi)的開(kāi)發(fā)者可以將打包好的各個(gè)功能模塊部署上去,通過(guò)在C:\Users\Administrator\.spm\config.json中增加源服務(wù)器、在package.json中增加"dependencies"配置、"output"中的"."改為"*",在打包時(shí)就可以加入在源服務(wù)中的其他功能模塊。如此倒是提供了協(xié)同開(kāi)發(fā)的可能性,但操作起來(lái)挺不方便,我也沒(méi)有進(jìn)行驗(yàn)證,如有不對(duì)之處,還望路過(guò)的大神不吝賜教。

多個(gè)入口文件的打包

在本文的demo示例中,整個(gè)功能模塊只有a.js一個(gè)入口,它把其他CMD模塊都牽扯到了,如果入口文件不止一個(gè),或者說(shuō)一些文件與另一些文件相互獨(dú)立怎么辦呢?比如在util下,有負(fù)責(zé)加法的add.js和負(fù)責(zé)減法的sub.js,它們之間互不引用,package.json可以這樣配置:

"output": {

? ? "add.js": ".",

? ? "sub.js": "."

}

最終生成兩個(gè)壓縮后的JS,或者將它們強(qiáng)行合并:

"output": {

? ? "util.js": ["add.js", "sub.js"]

}

圖片的相對(duì)路徑問(wèn)題

比如在CSS中使用相對(duì)路徑引用圖片,在打包前表現(xiàn)正常,但打包后CSS內(nèi)容并入JS中,被載入JSP或HTML頁(yè)面,相對(duì)路徑將以頁(yè)面文件位置為基準(zhǔn),此時(shí)就需要調(diào)整圖片文件的位置,在開(kāi)發(fā)時(shí)使用絕對(duì)路徑可避免這一情況。

CSS載入問(wèn)題

實(shí)測(cè)表明,只有在入口JS中載入CSS才能正常打包,如果其他CMD模塊require了CSS,spm將提示無(wú)法找到該CSS文件,這一現(xiàn)象很奇特,目前尚未弄明原因。

開(kāi)發(fā)約束/建議(僅針對(duì)1.7.7版)

1、確保所有JS文件符合CMD規(guī)范;

2、入口JS文件(可以有多個(gè))應(yīng)放在功能模塊根目錄下;

3、避免使用相對(duì)路徑require其他功能模塊里的JS;

4、CSS的require放在入口JS文件中;

5、使用絕對(duì)路徑引用圖片。

學(xué)習(xí)資料

關(guān)于Sea.js

Sea.js文檔

使用SeaJS實(shí)現(xiàn)模塊化JavaScript開(kāi)發(fā)

關(guān)于spm

spm@1.x文檔

為什么 SeaJS 模塊的合并這么麻煩

seajs使用心得

我的前端之旅第一彈--SeaJs基礎(chǔ)和spm編譯工具運(yùn)用


2016年2月22日 無(wú)錫

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 模塊通常是指編程語(yǔ)言所提供的代碼組織機(jī)制,利用此機(jī)制可將程序拆解為獨(dú)立且通用的代碼單元。所謂模塊化主要是解決代碼分...
    MapleLeafFall閱讀 1,255評(píng)論 0 0
  • 前言 SeaJS是一個(gè)遵循CommonJS規(guī)范的JavaScript模塊加載框架,可以實(shí)現(xiàn)JavaScript的模...
    郭子web閱讀 573評(píng)論 0 2
  • 33、JS中的本地存儲(chǔ) 把一些信息存儲(chǔ)在當(dāng)前瀏覽器指定域下的某一個(gè)地方(存儲(chǔ)到物理硬盤(pán)中)1、不能跨瀏覽器傳輸:在...
    萌妹撒閱讀 2,246評(píng)論 0 2
  • 前端集成解決方案要求: 模塊化開(kāi)發(fā)。最好能像寫(xiě)nodejs一樣寫(xiě)js,很舒服。css最好也能來(lái)個(gè)模塊化管理! 性能...
    Www劉閱讀 3,234評(píng)論 1 20
  • 在我的推薦中,英文歌曲和英文原作的中文版本占了很大的一部分。這是非常無(wú)奈的一件事情,在兒童的語(yǔ)言學(xué)習(xí)上,我個(gè)人是非...
    RiverDuan閱讀 375評(píng)論 0 0

友情鏈接更多精彩內(nèi)容