2016-04-06 32 views
4

可以說我正在編寫一個JavaScript模塊,可以在瀏覽器和服務器(使用節點)上使用。讓我們叫它模塊。並且可以說,模塊將受益於另一個模塊中的方法,稱爲依賴。這兩個模塊的已寫入瀏覽器和服務器都可以使用,點菜CommonJS的風格:打包瀏覽器/服務器CommonJS模塊與依賴

module.js

if (typeof module !== 'undefined' && module.exports) 
    module.exports = Module; /* server */ 
else 
    this.Module = Module; /* browser */ 

dependancy.js

if (typeof module !== 'undefined' && module.exports) 
    module.exports = Dependancy; /* server */ 
else 
    this.Dependancy = Dependancy; /* browser */ 

很明顯,依賴可以直接在瀏覽器中使用。但是,如果模塊包含var dependancy = require('dependency');指令,則更容易「維護」模塊。

我知道我可以模塊內爲執行全局檢查扶養,像這樣:

var dependancy = this.Dependancy || require('dependancy'); 

但是,這意味着我的模塊有瀏覽器安裝兩個添加的要求:

  • 用戶必須包含dependency.js文件作爲<script>我ñ他們的文檔
  • ,用戶必須做出之前module.js

添加這兩個要求,確保該腳本加載拋出像CommonJS的一個隨和的模塊化架構的想法。

對我來說,另一種選擇是,我包括第二,編譯腳本在我模塊包使用browserify捆綁dependency.js。然後,我指示在瀏覽器中使用該腳本的用戶包含此腳本,而服務器端用戶使用package.json中列出的未捆綁的條目腳本。這比第一種方式更可取,但它需要預編譯過程,我每次更改庫時都必須運行(例如,在上傳到GitHub之前)。

有沒有其他的方式來做到這一點,我沒有想到?

+0

這是一個可怕的想法,服務器和瀏覽器出於安全原因不應該共享相同的庫,這就是爲什麼我們首先需要這兩者。想象一下,你的一個依賴會暴露你的用戶的電子郵件或密碼或類似的東西。這將是災難性的。 – Val

+0

@Val在服務器端和瀏覽器端都可以使用很多通用的庫,這些庫不涉及安全性。例如,[異步](https://github.com/caolan/async)庫。此外,在這種情況下,** Module **和** Dependency **都是由我自己編寫的。 – shennan

回答

1

當然,您可以在兩邊都使用相同的模塊依賴關係。你只需要更好地指定它。這是我使用的方式:

(function (name, definition){ 
    if (typeof define === 'function'){ // AMD 
     define(definition); 
    } else if (typeof module !== 'undefined' && module.exports) { // Node.js 
     module.exports = definition(); 
    } else { // Browser 
     var theModule = definition(), global = this, old = global[name]; 
     theModule.noConflict = function() { 
      global[name] = old; 
      return theModule; 
     }; 

     global[name] = theModule; 
    } 
})('Dependency', function() { 
    // return the module's API 
    return { 
     'key': 'value' 
    }; 
}); 

這僅僅是一個非常基本的示例 - 您可以返回功能,實例化功能或做任何你喜歡的。在我的情況下,我返回一個對象。

現在我們假設這是Dependency類。你Module類應該看起來幾乎相同,它應該有一個依賴於Dependency,如:

function (require, exports, module) { 
    var dependency = require('Dependency'); 
} 

在RequireJS這就是所謂的簡化CommonJS的包裝:http://requirejs.org/docs/api.html#cjsmodule

因爲有在require聲明你的代碼的開始,它將被作爲一個依賴項進行匹配,因此它將被延遲加載或者如果你優化它 - 在早期標記爲依賴項(它將自動將define(definition)轉換爲define(['Dependency'], definition))。

這裏唯一的問題是保持與文件路徑相同。請記住,嵌套的需要(如果其他)將行不通的要求(閱讀文檔),所以我不得不做一些事情,如:

var dependency; 
try { 
    dependency = require('./Dependency'); // node module in the same folder 
} catch(err) { // it's not node 
    try { 
     dependency = require('Dependency'); // requirejs 
    } catch(err) { } 
} 

這非常適合我。這對所有這些路徑來說都有點棘手,但是在一天結束的時候,你會在不同的文件中獲得兩個單獨的模塊,這些模塊可以在兩端使用而不是任何類型的檢查或黑客 - 它們的所有依賴項都是工作的像一個魅力:)

+0

我看到[RequireJS](http://requirejs.org/)使用[AMD](https://en.wikipedia.org/wiki/Asynchronous_module_definition)。這不會與服務器端與Node使用香草CommonJS衝突嗎?我並不是暗示它會這樣做,但根據你的經驗,如果例如[Browserify](http://browserify.org/)也用於將模塊打包到某處線? – shennan

+0

如果您追蹤代碼,您會看到它執行所有檢查,以便AMD模塊使用'define'和節點聲明方式使用'module.exports'。因此,他們只是很好地工作:)我非常抱歉,我以某種方式決定你已經在客戶端使用'RequireJS',因爲你嘗試製作模塊,這就是它的作用!我的錯誤在這裏 –

+0

據說browserify使用commonjs所以它*應該*直接工作,希望:) –

1

看看webpack bundler。 您可以編寫模塊並通過模塊導出將其導出。然後你可以在服務器上使用你有module.export和webpack的瀏覽器。配置文件的使用將是最好的選擇

module.exports = { 
entry: "./myModule", 
output: { 
    path: "dist", 
    filename: "myModule.js", 
    library: "myModule", 
    libraryTarget: "var" 
} 
}; 

這將採取myModule並將其導出到myModule.js文件。內部模塊將被分配給名爲myModule(庫標誌)的var(libraryTarget標誌)。

它可以導出爲CommonJS的模塊,戰爭,這個,功能

由於捆綁爲節點的腳本,這個標誌值可以設置語法。

看看外部標誌。如果您希望對某些依賴關係有特殊行爲,則使用它。例如,您正在創建反應組件,並且在您希望需要的模塊中進行創建,但是當您爲Web進行捆綁時並非如此,因爲它已經存在。

希望這是你在找什麼。

+0

感謝您的回答。 [Webpack](http://webpack.github.io/docs/configuration.html)看起來像一個有趣的項目。對於這個常見問題,它看起來是一個很好的整體方法,但是,我敢說,對我的特殊用例來說似乎有點矯枉過正。 – shennan

2

目前給出的兩個答案都非常有用,並且幫助我達成了我目前的解決方案。但是,根據我的意見,它們並不能完全滿足我對便攜性和易用性(對客戶和模塊維護者而言)的特殊要求。

我發現最後是browserify命令行界面中的一個特殊標誌,它可以將這些模塊打包並將它們公開爲全局變量,並在RequireJS中使用(如果需要)。 Browserify(和其他人)稱之爲通用模塊定義(UMD)。更多關於那here

通過在browserify命令中傳遞--standalone標誌,我可以輕鬆地將我的模塊設置爲UMD。

所以...

這裏的package.js模塊

{ 
    "name": "module", 
    "version": "0.0.1", 
    "description": "My module that requires another module (dependancy)", 
    "main": "index.js", 
    "scripts": { 
    "bundle": "browserify --standalone module index.js > module.js" 
    }, 
    "author": "shennan", 
    "devDependencies": { 
    "dependancy": "*", 
    "browserify": "*" 
    } 
} 

所以,當我模塊的根,我可以在命令行中運行以下命令:

$ npm run-script bundle 

其中捆綁了依賴關係整合到一個文件中,並按照UMD方法進行公開。這意味着我可以引導模塊中的三種不同的方式:

的NodeJS

var Module = require('module'); 
/* use Module */ 

瀏覽器香草

<script src="module.js"></script> 
<script> 
    var Module = module; 
    /* use Module */ 
</script> 

瀏覽器RequireJS

<script src="require.js"></script> 
<script> 
    requirejs(['module.js'], function (Module) { 
    /* use Module */ 
    }); 
</script> 

再次感謝大家的意見。所有的答案都是有效的,我鼓勵每個人都嘗試它們,因爲不同的用例需要不同的解決方案。