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 的相對路徑相對當前模塊路徑來解析。

 

如果我們能理解其模塊標識解析設計的出發點,那么就可以輕易的理解這些而不用記憶這么多:

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

 

 示例

目錄結構如下:

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 deploy

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

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

<!--    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>

 

 參考閱讀:


免責聲明!

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



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