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