1. 程式人生 > >seajs+spm之再研究

seajs+spm之再研究

好久沒有用seajs了,之前對spm也只是一知半解,這些天再次拿起來研究.談談我的認識與理解.

宣告:本文不適合對seajs完全不瞭解的同學閱讀.對於想知道seajs來龍去脈以及spm相關的同學"可能"有幫助.對於我自己也是個梳理的機會.

一.seajs部分

1.seajs由來:

傳統web前端的js開發,主要基於script標籤的引入,一個檔案一個script標籤,或者對他們進行簡單的壓縮與合併,以減少http請求.

沒錯,我們以前都是這麼幹的,甚至現在還有很多人這麼幹.

隨著這些年的發展,前端越來越被重視,邏輯越來越複雜,前端程式碼的維護變得越來越難.

2009年,nodejs誕生(nodejs是什麼東西,可以自行google),其模組化的程式設計思想,給攻城師牛人們(包括但不限於前端攻城師)帶來了很大的啟發.特別是它的模組化依賴管理系統.工程師們想把這個依賴管理機制移植到瀏覽器端.但是瀏覽器端目前還沒有高度統一的規範,更別說依賴管理機制了.於是工程師們絞盡腦汁,日思夜想.

不久後,requireJS誕生了,也的確火了,但它所堅持的原則規範並不被前面那些的大部分工程師們接受.

這時,我國的一位前端大牛也逐漸參與到模組化開發的研究中來.經過不斷的虛心學習,借鑑,摸索,seaJS誕生了.他的作者是玉伯(--仰視,尊敬).

2.seajs是什麼,能做什麼

它是模組載入器(也即js檔案載入器),所有模組都可以通過它載入,而且很重要的是,它可以幫你很好的管理模組依賴.當你的頁面上有十幾二十個js檔案的時候,用了seajs,你就會知道它有多麼美妙.

3.怎麼用

這裡只講個大概,教程隨便google就一打.

所有的模組幾乎(下面會講為什麼不是全部)都被define(function(require,exports,module){})這個全域性函式包圍,require引數用於表明被依賴模組,exports和module用於輸出介面,讓別的模組可以呼叫.對於開發者,按照它的規範寫程式碼,就能很好的管理依賴了.

現在來講,上面那個"幾乎".其實也是後來看aralejs(aralejs是基於seajs的元件庫,其開放程度可以用包羅永珍來形容,具體可自行google)上的模組才發現的(只是個別模組這樣做).

對於我們後來寫成的模組,seajs官網是推薦上面那種方式的,而且也沒有什麼問題.之前隨著requireJS的推出,一些開源的類庫或者框架(比如jquery,backbone等)都紛紛加入了requireJS的行列,後續的新版本預設支援AMD模組規範.這些開原始碼為了相容頁面上有無requireJS的情況,並沒有將所有程式碼都包在define函式中,而是判斷頁面中是否定義了define函式進行模組定義,類似於下面這樣

1 if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
2 
3  define( "jquery", [], function () { return jQuery; } );
4 
5 }

而arale或者說seajs官方的做法是,可能為了相容AMD,將其改成了

1 if ( typeof define === "function" ) {
2 
3  define("jquery/jquery/1.7.2/jquery-debug", [], function () { return jQuery; } );
4 
5 }

可能有其他更特殊的原因吧,還有json的模組更簡單,直接在最後追加

1 define("gallery/json/1.0.3/json-debug", [], function() {
2 
3     return window.JSON;
4 
5 });

而underscore和bockbone就是按照"標準",在最外層包上define.不是特別清楚為什麼有這麼些個做法.可以再看看其他被包裝過的模組的都是什麼樣子的.

4.seajs的原理

5.引出下一節

其實說到這裡,seajs以及它的模組都可以在瀏覽器里正常執行.那麼為什麼還要有spm呢? 且繼續往下看

二.spm部分

1.spm由來:

各個模組開發測試完畢後,為了進一步提升頁面效能,我們還要對程式碼進行壓縮,合併操作.

於是問題產生了.

為什麼壓縮後,被依賴的模組不載入了?

為什麼合併後的模組一個都不執行了?(新版本不執行任何操作,1.3.1及以前會只執行第一個模組)

對於第一個問題,這涉及到seajs模組依賴處理的原理,對於第一節中談到的模組組織方式define(factory),seajs尋找依賴是依靠正則判斷factory.toString()中的require關鍵字,如下程式碼片段

 1 var REQUIRE_RE = /"(?:\\"|[^"])*"|'(?:\\'|[^'])*'|\/\*[\S\s]*?\*\/|\/(?:\\\/|[^\/\r\n])+\/(?=[^\/])|\/\/.*|\.\s*require|(?:^|[^$])\brequire\s*\(\s*(["'])(.+?)\1\s*\)/g;
 2 
 3 ...
 4 
 5 function parseDependencies(code) {
 6 
 7   var ret = []
 8 
 9  
10 
11   code.replace(SLASH_RE, "")
12 
13       .replace(REQUIRE_RE, function(m, m1, m2) {
14 
15         if (m2) {
16 
17           ret.push(m2)
18 
19         }
20 
21       })
22 
23  
24 
25   return ret
26 
27 }
28 
29 30 
31 // Parse dependencies according to the module factory code
32 
33   if (!isArray(deps) && isFunction(factory)) {
34 
35     deps = parseDependencies(factory.toString())
36 
37   }

而程式碼經過壓縮後,require就不見了,自然就找不到依賴了.還有就是,這種依賴分析很消耗效能.

第二個問題,涉及到模組標識問題.其實上述的模組組織方式稱為"匿名模組".多個沒有名字的模組合併到一起後,各自都返回了輸出介面,那麼對於這個"大模組",應該返回哪一個介面呢?所以理想情況下每個模組都需要一個模組標識,這樣就可以任何合併了.

其實seajs支援兩種規範:

第一種就是第一節中的那種,叫做CMD規範,即define(factory)只傳入一個callback.

第二種是給define傳入三個引數define(id, deps, factory),id為模組標識,reps為依賴模組陣列,第三個factory同上面那個factory.

第二種方式下,seajs的工作原理略有不同.它不再對factory進行正則依賴分析,直接載入deps中的依賴模組(陣列中的字串即模組標識,要與被依賴模組的id相匹配,或者與seajs.config別名中的對映後相匹配),這樣一來,依賴處理的速度更快了,同時所有模組均可以任意壓縮合並.

所以呢,為了使CMD模組(也即匿名模組),更加便於管理,包括模組的壓縮,合併,打包,部署,甚至公用下載安裝,spm就應運而生了.

2.spm是什麼,能做什麼

spm是CMD模組管理器,就像npm,其實spm本身就是nodejs的一個模組,負責CMD模組的打包釋出刪除等操作.當然對外輸出的模組已經不是CMD模組了,是

接著要說的是spm的源,就像npm有個程式碼集中管理的地方,甚至svn的程式碼倉庫也有些類似.

然後我們就可以開發我們的模組了.個人認為,最終生成的模組不一定要釋出到源上.具有公共特性的元件類的模組才需要放到源上,業務模組放到專案中就好.只是build出來的id會看起來比較怪異,因為必須要與載入的路徑一致.

3.spm的主要功能

nodejs和spm及其外掛的安裝這裡就不說了,也是google一大把

我們從使用的角度,按開發順序走下來

A.如果是開發一個公用元件,將來是要上傳到spm源的模組,可以這麼幹(這種情況,除了源配置,我們暫時使用預設的配置資訊):

1)spm init

開啟終端,進入你將要開發元件的那個目錄,執行

spm init

然後,spm為你生成一個基本目錄結構,像下面這樣

{{newModuleName}}/                                                //這一層是你執行spm init前建立的

        src/

                {{newModuleName}}.js 

                {{newModuleName}}.css 

        examples/ 

                index.md 

        tests/

                {{newModuleName}}-spec.js        

        dist/                                //這一層現在不會有,後面build完會出現,輸出的檔案在這一層下 

        README.md 

        HISTORY.md 

        package.json  

然後你就可以在src下的js和css裡開發元件了,這兩個檔案初始化了一小部分程式碼,在src下你可以自由建立資料夾與其他js,css甚至模板檔案等,用於被依賴

2)spm build

元件開發完成後,在終端下,同樣是在上一步的目錄下,執行

spm build

然後,就生成了上一步看到的dist目錄,下面有打包好的具名模組,其中如果有依賴,預設是會被打包進來的

3)接著開始測試模組

官網說,spm test以及spm totoro都是支付寶內部才能使用的外掛,不推薦外部使用,我還沒有深入研究過.

所以呢,我們只能暫時自己建立測試環境,不過也不太麻煩啦

4)spm publish

測試通過後,我們就可以把它釋出到源上了,就像nodejs模組可以通過npm釋出一樣.

在終端,同樣的目錄下執行

spm login

按照提示,登陸你的源賬號,如果沒有賬號則按照提示建立賬號登陸

接著執行

spm publish

如果沒有意外,就可以釋出成功了

開啟瀏覽器,訪問你的源地址,就能看到你剛剛釋出的模組了

其他同學就可以通過spm install {{family}}/{{moduleName}} 安裝(即下載)你釋出的模組了

B.如果是開發業務模組,按照我個人的觀點,業務模組不需要被髮布到源上,或者說不需要和公用元件放在一塊

這裡我想起一個誤區,而且我之前就一直是這麼認為的:

"源上的模組是可以被http訪問到的"

走出誤區:簡單講,源只是一個儲存模組檔案的地方,不提供模組的web服務.於是就有了"部署"這件事情.但是spm deploy也是支付寶內部外掛,我也沒深入研究.

通常大型專案,靜態資原始檔與應用服務是分離的,也即模組檔案是存放在另一臺伺服器上的.

但是小型專案,放在一起也基本能夠滿足需求.

但好像沒有看到有人將公用模組與業務模組分離的.經過個人簡單試驗,這樣是行的通的,並打算應用在專案中.

之前一直在探索如何使用spm構建業務模組,但總找不到合適的資料,尤其是它要求的目錄結構以及生成的id讓我束手無策.後來看到有大牛使用grunt-cmd-transport構建模組,自己跟著試了一下,的確可行.但似乎有些問題,比如:依賴的css沒有被打包進來.在諮詢了官方的人員後,並沒有給出我這些問題的答案,而是建議我用spm,並給出了一些方案.我又重新拿起spm開始嘗試.終於研究出了可行的方案,相對公用元件的開發方式,只需要修改package.json中的一些配置即可,而grunt的配置實在太多,看的人眼花.再次感謝支付寶貫高(github @popomore)給我的建議

由於需要比較多的筆墨,我將在下一篇講述如何使用spm構建業務模組.

相關推薦

seajs+spm研究

好久沒有用seajs了,之前對spm也只是一知半解,這些天再次拿起來研究.談談我的認識與理解. 宣告:本文不適合對seajs完全不瞭解的同學閱讀.對於想知道seajs來龍去脈以及spm相關的同學"可能"有幫助.對於我自己也是個梳理的機會. 一.seajs部分 1.seajs由來: 傳統web前端的js

初識Scrapy續火影情緣

復雜 功能 splay 註意 回調函數 正則 理解 turn bject 前言Scrapy框架之初窺門徑1 Scrapy簡介2 Scrapy安裝3 Scrapy基礎31 創建項目32 Shell分析4 Scrapy程序編寫41 Spiders程序測試42 Items編寫43

Vijos CoVH破難關(搜索+hash)

ash pen inline src sed blog node 輸出 data 背景 在瞬間之下,明白所有真相只要開始,就不會停止... 揭開唯一事實,外表是小孩,頭腦卻是大人他的名字就叫...名偵探柯南! 描述 [CoVH07]OIBH組織派出的黃金十二人+青銅

python學習----簡單的列表(1)

cycle print gpo 組成 系列 letters 開始 mes 包含 print("today to learn the list")# 列表由一系列按特定順序排列的元素組成。你可以創建包含字母,0-9的數字,所有家庭成員的姓名的列表。# 鑒於列表一般都是包含很多

python學習----簡單的異常

lena input 直接 ase ber one rod can 跳過 # filename:python3.4.py# author:super# date:2018-03-04# try except 的時候 要把具體的except 內容打印出來# 如果不想做任何處理

AJAX升級版PJAX

很好 升級 博客 當前頁 後端 閃爍 缺點 nbsp 內容    前幾天在一個大神群裏提到ajax優化選項卡功能的方法上,有位低調的大神默默得打出:了解一下pjax,好奇心的驅使下,我具體查了一下pjax,不一般啊,ax結合pushState和ajax技術, 不需要重新加載

Echarts多任務可視化優化

兩個 con width data .get label font var flag 1.上次進程可視化由svg實現,本次改用echarts框架實現。Js文件:loadxmldoc.js(用於加載xml文檔)echarts.js(用來實現有向圖繪制)2.思路:Echarts

c++入門話內存和引用

占用 引入 方式 數值 參數傳遞 內存空間 struct 過程 原來 此處沒有代碼,僅僅討論一些這樣的問題:我們為何使用引用?在哪裏使用引用? 首先從函數的角度思考?:函數進行一般參數傳遞的時候,是怎麽樣傳遞的?普通類型的參數傳遞,是將傳遞的實參復制一份,到另一個內存空間,

c++入門話記憶體和引用

此處沒有程式碼,僅僅討論一些這樣的問題:我們為何使用引用?在哪裡使用引用? 首先從函式的角度思考?:函式進行一般引數傳遞的時候,是怎麼樣傳遞的?普通型別的引數傳遞,是將傳遞的實參複製一份,到另一個記憶體空間,這其中包含了int,char ,甚至struct。那麼從記憶體的角度講:如果我們傳遞的引數非常佔用記

Python正則學習與實踐

昨天做網頁爬取的時候,感覺自己對正則不熟悉的很,故今天再花上午時間認真整理下,不可懈怠。 1.常見正則表示式符號 [1].literal    匹配文字字串的字面值literal     [2].re1|re2  

jQuey動畫-研究

jQuery動畫通常使用動畫時長作為可選的第一個函式,如果省略時長,會得到 預設值400ms; “fast”-200ms, “slow” -600ms, 可以在jQuery.fx.speeds物件中檢視,修改,新增自己定義時長的名稱 console.log(jQuery.fx.spe

jQuery的Ajax--onload()方法 --研究

AJAX = 非同步 JavaScript 和 XML(Asynchronous JavaScript and XML)。 它使用HTTP指令碼來按需求載入資料,而不需要重新整理整個頁面. jQuery內建了Ajax工具來簡化使用. load()方法 load(url,dat

c++入門 話類

對於類,其結構並不難,但要理解其設計思想也並不容易,在此,我們可以通過下面的程式碼進一步理解和使用類: 1 # ifndef VECTOR_H_ 2 # define VECTOR_H_ 3 # include "iostream" 4 5 namespace VECTOR //注意,這裡

SpringMVC解url-pattern

配置詳解 關於SpringMVC的配置檔案web.xml中<url -pattern>應該怎麼寫的問題,相信許多初學的小夥伴會有疑惑,特此總結一下。 <!-- 註冊中央排程器 --> <servlet> <servlet-name>springmvc

條件與無窮小方法研究

(ε,δ)條件與無窮小方法之比研究 一、(ε,δ)條件: ∀ε∃δ∀Δx{… ⇒ … } Δx不是無窮小; 二、無窮小方法: ∀Δx{… ⇒ … } Δx是無窮小。 十分明顯的是:前者使用了三個量詞,而後者只需要一個量詞。理解與使用前者,較之後者,費解與困難得多。 1

(ε,δ)條件與無窮小方法研究

(ε,δ)條件與無窮小方法之比研究 一、(ε,δ)條件: ∀ε∃δ∀Δx{… ⇒ … } Δx不是無窮小; 二、無窮小方法: ∀Δx{… ⇒ … } Δx是無窮小。 十分明顯的是:前者使用了三個量詞,而後者只需要一個量詞。理解與使用前者,較之後者,費解與困難得多。 1

小程式專案填坑

簡訴   是的,真的,你沒有看錯,我就是上次那個加薪的,但是現在問題來了,最近又搞了個小程式的需求,又填了不少坑,其中的辛酸就不說了,說多了都是淚,此處省略三千字 ………^……,說重點吧,反正最後就是差點這讓老闆叫走人了,你說優秀不優秀~。   前段時間網上一直說的“<你可以罵那些中年人,尤其是

小程序項目填坑

來看 今天 ora 合成 ges 加油 畫出 one 解決 簡訴   是的,真的,你沒有看錯,我就是上次那個加薪的,但是現在問題來了,最近又搞了個小程序的需求,又填了不少坑,其中的辛酸就不說了,說多了都是淚,此處省略三千字 ………^……,說重點吧,反正最後就是差點這讓老板

jQuery的Ajax高階工具函式($getScript(),$getJSON()) --研究

jQuery的Ajax高階工具不是方法,而是函式,可以通過jQuery或$直接呼叫 //尼瑪,我認為他們是jQuery工廠函式上的靜態方法, //不需要建立jQuery物件,直接使用 ‘類名’ .方法名

Scala::的研究

一個很細節的問題,簡單總結一下。::在Scala裡有兩種含義,一種是List集合的一個方法,用於把一個元素新增到集合的前面;另一種表示一個非空的List集合,往往應用於模式匹配中。本文原文出處: http://blog.csdn.net/bluishglc/ar