在JS沒有提出來模塊化的時候,開發JS項目比較簡單,同時也比較雜亂,第一個問題就是全局變量的管理,爲了解決這個問題基本上都使用了命名空間和閉包兩個主流的解決方式,可是隨着硬件基礎和網絡環境的改善,前端開發也愈來愈複雜,須要協同合做,代碼複用的需求愈來愈多,複雜性帶來的第一個問題就是命名管理問題再次遇到挑戰,而後就是協同開發也被正式提上了議題,模塊化正式走入臺前。javascript
1 var a = 1; 2 //函數 3 function bindeEvent(){} 4 function addClass(){} 5 //命名空間 6 var obj1 = { 7 a:2, 8 foo:function(){} 9 } 10 var obj = { 11 a:2, 12 foo:function(){} 13 } 14 //閉包 15 (function($){ 16 var a = 123; 17 function foo(){} 18 return {foo:foo} 19 })(jQuery);
模塊化的在很大程度上與閉包的實現模式很是相似,傳入閉包的參數能夠看做是模塊的引用,返回值能夠看做是模塊定義的接口,整個閉包就能夠理解爲一個模塊,有差異的地方就是模塊化是一個模塊單獨在一個js文件中實現、模塊中使用的模塊自身之外的參數和屬性都必須依賴引入。html
有了單獨js文件和各類規範的標準接口,就能很好的實現了協同開發這問題,解決了前端開發愈來愈麻煩的複雜性,同時命名衝突問題也在模塊的私有變量特性中迎刃而解。前端
在commonjs官網的最上方有一句這樣的描述:javascript: not just for browsers any more!翻譯:javascript:不只僅是針對瀏覽器了!最近兩年在前端很火的nodejs就是commonjs規範的實現,而webpack是基於nodejs實現的,天然而然就是commonjs規範的實現。雖然咱們後期在js的開發中不必定使用commonjs規範,可是咱們須要使用webpack做爲前端工程化的實現工具,還有基於nodejs的模塊、插件、庫,因此對於咱們理解和應用其餘技術頗有幫助,因此對於commonjs的理解是有必要的。java
可能說到這裏,咱們還不清除commonjs是個什麼東西,這麼來講,javascript官方定義的api只能構建基礎的瀏覽器應用,也就是說javascript官方只實現了在瀏覽器環境中的api,若是來那javascript來作服務端應用程序,又或者是圖形界面應用程序,還有命令行工具等就有些力不從心,2009年程序員Ryan Dahl創造了node,js項目,將javascript用於服務器端編程,這標誌這javascript模塊化開發的誕生,而commonjs就是這個模塊的規範。node
commonjs都有哪些規範呢?webpack
1.commonjs的出發點:js沒有模塊系統、標準庫較少、缺少包管理工具;爲了讓javascript能夠在任何地方運行,以達到JAVA、C#、PHP這些後臺語言的開發能力。程序員
2.commonjs規範的具體內容:web
一個文件就是一個模塊;npm
普通方式定義的變量、函數、對象都屬於該模塊內;編程
經過require來加載模塊;
經過exports和modul.exports來暴露模塊中的內容(接口);
3.全部代碼都運行在模塊做用域,不會污染全局做用域;模塊能夠屢次加載,但只會在第一次加載的時候運行,而後運行結果就被緩存了,之後再加載就讀取緩存裏面的結果;模塊的加載順序按照代碼的出現順序同步加載。
4._dirname表明當前模塊文件所在的文件夾路徑,_filename表明當前模塊文件所在文件夾路徑+文件名。
5.require(同步加載基本功能):讀取並執行一個js文件,而後返回該模塊的exports對象,若是沒有發現指定模塊會報錯。
6.模塊內的exports:nodejs爲每一個模塊提供了一個exposrts變量,其指向module.exports,至關於再模塊頭部加了這句代碼:var exports = module.exports;在對外輸出時,能夠給exports對象添加方法,但不能直接賦值,由於這樣會切斷exports與module.exports的聯繫。
7.npm root -g 查看全局包安裝位置,建議nvm目錄下npm\node_modules目錄,而後設置npm全局包安裝位置npm config set prefix "",而後將該路徑添加到環境變量中;
8.npm init -y 初始化package.json文件,加上-y就會默認生成該文件;npm docs 包名:查看包的文檔;npm install:安裝package.json中dependencies屬性中因此來的包。
9.因爲npm服務器是國外的,下載慢或者不能下載成功常常出現,建議使用淘寶NPM鏡像http://npm.taobao.org/,與官方NPM同步頻率爲10分鐘一次,安裝命令:npm install -g cnpm --registry=https://registry.npm.taobao.org,安裝包:cnpm install 包名(其它命令基本一致);
10.若是你不想下載cnpm,npm還提供了一個鏡像源管理工具:npm install -g nrm,經過:nrm ls,查看鏡像源列表 ,經過:npm use 鏡像源,來切換;
十一、NPM的模塊加載機制:
若是require的是絕對路徑文件,查找不會去遍歷每一個node_modules目錄,其速度最快
1).從module.paths數組中(由當前執行文件目錄到磁盤根目錄)取出第一個目錄做爲查找基準
2).直接從目錄中查找該文件,若是存在則結束查找,若是不存在則進行下一條查找
3).嘗試添加.js、.json、.node後綴以後查找,若是存在文件則結束查找,若是不存在則進行下一條查找
4).嘗試將require的參數做爲一個包來進行查找,讀取目錄下的package.json文件,取得Main參數指定的文件
5).嘗試查找該文件,若是存在則結束查找,若是不存在則進行第3條查找
6).若是繼續失敗,則取出module.paths數組中的下一目錄做爲基準查找,循環第1-5個步驟
7).若是繼續失敗,循環第1-6個步驟,直到module.paths中的最後一個值
8).若是繼續失敗,則拋出異常
Commonjs規範最開始就是爲了將javascript運行在服務器環境下,因此採用了同步加載不一樣模塊文件,適用於服務端。由於模塊文件都存放在服務器的各個硬盤上,讀取速度塊,適合服務器,不適應瀏覽器。
並且瀏覽器不兼容Commonjs,緣由是瀏覽器缺乏module、exports、require、global是個環境變量。若是要使用的化須要工具轉換,有時候還會用到global這個nodejs中的全局變量,至關於dom中的window變量。
在前端開發中使用Commonjs模塊化規範:
1.定義文件結構:
//工做區間 -->modules//依賴模塊 -->m1.js -->m2.js -->m3.js -->demo.html//結構文本 -->index.js//主入口文件
依賴模塊代碼(m1.js):
1 module.exports = { 2 msg:'m1', 3 foo:function(){ 4 return this.msg; 5 } 6 }
依賴模塊代碼(m2.js):
1 module.exports = function(){ 2 return 'm2'; 3 }
依賴模塊代碼(m3.js):
1 // var exports = module.exports;在第博客二部分:commonjs規範中第六小點由說明 2 exports.foo = function(){ 3 return 'ms'; 4 }
主入口文件(index.js):
1 var m1 = require('./modules/m1'); 2 var m2 = require('./modules/m2'); 3 var m3 = require('./modules/m3'); 4 5 console.log(m1.foo()); 6 console.log(m2()); 7 console.log(m3.foo());
前面規範中說過在瀏覽器並不支持commonjs規範,主入口文件index.js確定不能直接被demo.html結構文本使用,直接使用的話會報錯;因此在要前端開發中使用commonjs規範的話就必須使用插件將commonjs模塊化規範轉換成瀏覽器識別的代碼結構,在這以前系統上必須安裝nodejs環境,這時候咱們能夠先在控制檯中測試看看index.js的依賴是否成功:
1 node -v //測試node環境是否安裝成功,若是成功的話會在控制檯打印出node的版本號 2 node index.js
打印結果:
這是在node環境下可以編譯執行index.js,前面說過要想將commonjs模塊化結構代碼在瀏覽器中編譯執行,得須要使用工具轉換成瀏覽器可以編譯執行的代碼結構,這個工具就是Browserify,工具的官網:http://browserify.org/
下載安裝成功是這樣的:
在Browserify官網首頁的使用介紹中有這樣一句命令說明:
意思是將commonjs規範的main.js文件經過browserify轉換成瀏覽器可以執行的bundle.js文件;那麼咱們就可使用這個命令來將示例中的index.js轉換成一個能夠在瀏覽器使用的js文件(下面這句命令是要在命令窗口執行):
browserify index.js -o bundle.js
這行命令執行完成後會在咱們的工做區間生成一個bendle.js文件,這個文件就是經過browserify工具將基於commonjs規範的index.js入口文件及其依賴的m1.js、m2.js、m3.js轉換生成的瀏覽器能夠執行的js代碼。
這時候咱們能夠將bundle.js引入到demo.html結構文件中進行執行:
<script src="bundle.js"></script>
打開頁面-查看瀏覽器控制檯:
在前端使用commonjs規範而後使用browserify轉換成瀏覽器能執行的文件,所有過程演示完成;值得咱們關注的是生成的bundle.js是什麼?
從生成的代碼來看,本質上就是將依賴的文件合併到了一個文件中,而後一樣是採用閉包加對象屬性實現的命名空間的代碼管理方式,只不過這個過程咱們交給了工具來實現,在咱們的平常開發中,咱們只須要關注咱們本身的模塊開發,再也不須要去考慮全局命名衝突,代碼管理問題。並且經過模塊化開發帶來的最大的好處就是代碼的複用性特別方便,採用依賴模式而後使用工具轉換,也解決了原來在結構文件中引入大量插件和庫的問題,給代碼瘦身的同時也下降了網絡請求壓力。特別是插件、庫、組件之間的相互依賴關係帶來的加載阻塞問題獲得了很好的解決。
而後,在Browserify的官方首頁使用介紹中有一個基於全局模塊uniq的示例:
下載安裝uniq模塊:
npm install uniq
下載安裝成功之後會在當前工做區間生成一個node_modules文件夾和一個packge-lock.json文件,各相關的原理在webpack博客中詳細解析。而後,官網給出的代碼放到咱們示例代碼中的index.js中:
1 var unique = require('uniq'); 2 var data = [1, 2, 2, 3, 4, 5, 5, 5, 6]; 3 console.log(unique(data));
而後,在控制檯中再次編譯一次index.js到bundle.js:
browserify index.js -o bundle.js
而後刷新demo.html,查看瀏覽器控制檯:
關於commonjs的實現原理等過段時間再來補充;
AMD、COM規範解析