seajs的那些坑

seajs是what?

先看段代碼:
1 var loder = {};
2 var define = loder.define = function(id,deps,factory){
3       loader[id] = factory;
4 };
上述代碼幹了什麼?這就是一個最簡單的加載器,但離實際應用還有很大差距,須要添加不少功能,seajs就是一個成熟的方案。
 
當一個頁面集合了愈來愈多的js,這些js由不一樣的小組維護並且js包含了衆多的組件,因而相同的函數可能命名衝突,爲了解決命名衝突,你們可能會加上命名空間,記憶命名空間是一個負擔,另外各類組件之間的引用,形成了複雜的依賴的關係,如何管理好依賴文件的加載問題也是個煩惱的問題。
 
seajs很好地解決了命名空間,依賴等問題。簡單的說seajs是模塊加載器,它將命名空間、組件解釋爲模塊。按照seajs規則編寫的代碼符合CMD規範,使用它有兩個好處:二是讓模塊定義變得簡單,二是讓模塊發佈變得簡單。它是如何作到的這兩方面的?
  1. 首先模塊定義的方式,模塊源代碼中是這樣編寫模塊的define(factory),很是簡單,可是若是直接合併合並後多個define就會形成不知道如何引用具體的模塊,因而涉及到第二個部分,如何讓模塊發佈過程變得簡單。
  2. 模塊提取過程是,將源代碼轉換成seajs能正確解釋的代碼,即define(id,deps,factory)須要藉助於grunt-cmd-transport或spm-build工具。
讓這兩個方面變得簡單的祕訣在於seajs採用了路徑即模塊標識,因而在提取依賴過程當中,根據模塊標識找到依賴模塊的文件將其合併,而且將模塊定義轉換爲這種形式define(id,deps,factory)。上線後的代碼中define(id,deps,factory)的id和deps模塊標識用的是路徑,根據路徑即模塊標識,就能夠找到相應的完整模塊標識。
 

模塊標識

seajs的模塊定義方式很是simple,主要的難點在於不一樣項目有不一樣的部署要求,所以會由於模塊標識理解不夠形成進入各類坑。下面詳細分析下模塊標識!
模塊標識命名規則
  1. 一個模塊標識由斜線(/)分隔的多項組成。
  2. 每一項必須是小駝峯字符串、 . 或 .. 。
  3. 模塊標識能夠不包含文件後綴名,好比 .js 。
  4. 模塊標識能夠是 相對 或 頂級 標識。若是第一項是 . 或 ..,則該模塊標識是相對標識
解釋一下其中的幾種概念
  1. 相對路徑,以. 或 ..開頭
  2. 頂級路徑,不以.或 ..及斜線(/)開頭
  3. 普通路徑,除相對和頂級路徑外的,好比/(根路徑)開頭的,"http://""https://""file:///" 等協議標識開頭的
  4. 模塊命名空間是seajs所在文件的根路徑即所謂的base路徑,去除了seajs/x.y.z 字串,也能夠指定seajs.config({base:});
模塊依賴提取過程如何解析?
  1. 只提取相對標識
  2. 相對標識相對 require 所在模塊的標識來解析
上線後模塊標識解析規則?
  1. 頂級標識始終相對 base 基礎路徑解析。(頂級標識由字符串開頭)
  2. 絕對路徑和根路徑,即普通路徑,始終相對當前頁面解析,跟咱們平時用的其餘js和css路徑同樣,好比當前頁面是www.simple.com/user/index.html  ,路徑爲/js/hello.js,它解析後的地址爲www.simple.com/js/hello.js。
  3. 模塊定義中require 和 require.async 的相對路徑相對當前模塊路徑來解析。

 

若是咱們能理解其模塊標識解析設計的出發點,那麼就能夠輕易的理解這些而不用記憶這麼多:javascript

  1. 關注度分離。書寫模塊的時候咱們是不用指定模塊id的,require的模塊時候只要填入依賴模塊的相對路徑,因而咱們只要關注代碼的書寫而不是依賴,打包後工具會自動幫咱們處理好模塊id。
  2. 儘可能與瀏覽器的解析規則一致。上線後在瀏覽器中的代碼,模塊路徑的解析規則應該於平時用的css、js這些加載路徑規則同樣,普通路徑和相對路徑的都是相對當前頁面的。

 

 示例

目錄結構以下:css

www 
--app --blog index.html --sea-modules --seajs
--2.2.0
sea.js
--blog
--user
--1.0.0
main.js
--static
--user
--src
a.js
b.js
main.js
--dist
main.js
package.json
Makefile

 

//   /www/static/user/src/a.js
define(function(require,exports,module){
     module.exports = function(){
         //  ..........................
     };
});   
//   /www/static/user/src/b.js
define(function(require,exports,module){
     module.exports = function(){
         //  ..........................
     };
});   
//   /www/static/user/src/main.js
define(function(require,exports,module){
     var a = require('./a"); var b = require('./b");
// ..............
 }); 
//  /www/static/user/package.json
{
      family:"blog",
      name:"user",
      version:"1.0.0",
      spm:{
            output:["main.js"]
      }
}    
 
// /www/static/user/Makefile
build: @spm build deploy: @rm
-rf ../../sea-modules/blog/user @mkdir ../../sea-modules/blog/user @mkdir ../../sea-modules/blog/user/1.0.0 @cp dist/*.* ../../sea-modules/blog/user/1.0.0 @echo @echo " deploy to seajs-modules/blog/user/1.0.0" @echo

 

使用spm-build構建項目:
cd /www/static/user ; spm-build --encoding gbk
會在/www/static/user/dist 下生成 main.js 和 main-debug.js,main.js大概是這樣的
// /www/static/user/dist/main.js
define("blog/user/1.0.0/main",["./a","./b"],function(require){ var a = require('./a"); var b = require('./b"); }); define("blog/user/1.0.0/a",[],function(require,exports,module){ // ....................... }); define("blog/user/1.0.0/b",[],function(require,exports,module){ // ....................... });

而後運行make deployhtml

會將 ../dist/main 部署到 /www/sea-modules/blog/user/1.0.0/main.jsjava

在頁面中如何加載模塊呢?json

<!--    www.expample.com/app/blog/index.html     -->
<script src="/sea-modules/seajs/2.4.0/sea.js" id="seajson"></script>
<script>
     seajs.config({charset:"gbk"});
     seajs.use("blog/user/1.0.0/main");
</script>

 

 參考閱讀:

相關文章
相關標籤/搜索