假如你烘焙過蛋糕(哪怕沒有親自作過,可是也應該據說過),除了基本的麪粉,雞蛋等原材料外,或許你還須要一個電動蛋白打發器,一個烤箱。這是現代的作法,那麼在打發器和烤箱發明以前,人們怎麼烤蛋糕呢?
沒有打發器,只能手動打發,這樣的弊端是不只花費時間長,並且你的手可能也要廢掉。沒有烤箱,用炭烤,這樣就會出現溫度很差掌握,或許還得有人一直盯着的問題。css
我一直愛把軟件開發想成作菜,原材料就是編程語言,菜單是算法邏輯,而作菜的這些工具也是咱們在軟件開發中使用的各類工具。作菜的工具備歷史演變的過程,咱們軟件開發的工具也是如此。html
只是有些工具,如今被你們普遍使用,而有些卻只能在一些老文章裏面見證他們曾經的輝煌。今天就從前端工具演變來聊聊前端的歷史發展。前端
摸魚警告:本篇沒有乾貨,純粹閒聊。java
1:沒有任何工具的純手工時代
最開始的前端開發,只須要掌握HTML + CSS + JavaScript就好,咱們要在一個頁面上使用js,除了經過<script>...</script>標籤外,還能夠把js代碼放到一個js文件,經過在HTML文件引用這個js文件的方式:node
<!-- index.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <script src="index.js"></script> </head> <body> </body> </html>
可是,當咱們的業務需求變複雜,項目變大,咱們一般會把邏輯相關的代碼都放同一個js文件裏面,這樣慢慢就造成了模塊的概念,例如你在作一個超市收銀系統,項目裏有一個(或者幾個)js文件是跟價格計算相關,有些js文件是跟時間格式化相關。如今你正在開發收銀小票功能模塊,毋庸置疑,這個模塊確定須要用到前面的價格計算和時間格式化模塊。這裏,就產生了模塊訪問模塊的需求。jquery
不少語言都自然地支持在A文件裏面引用B文件的功能,可是javaScript一開始卻不是這樣。由於javaScript一開始是被設計來只在瀏覽器(準確地說是用戶的瀏覽器)上運行的語言。處於安全性的考慮,它不被賦予訪問文件的權利和功能。算法
在這個階段咱們要作到在A文件使用B文件提供的功能,只能在HTML文件裏面引用相關的js文件,經過在全局暴露相關變量,而後這樣就能使用到了。npm
2:包管理(package management)工具
在上面第一點咱們提到了模塊。在一個稍大的項目中,通常會用到不少前端社區已經成熟的模塊和框架。好比,專門用來處理時間格式問題的moment.js,之前可能會用到jQuery等。咱們要在項目裏面使用他們,得先找到他們在網絡上的地址,把相應的文件下載下來,放到咱們本身的項目某個目錄,而後再在HTML文件裏面引用相應的文件路徑。編程
上面的作法很顯然是存在效率和不方便的問題,在這種狀況下前端的package management工具應運而生。
咱們先來了解一下包管理工具爲咱們作了什麼事:
1:幫咱們從網絡上下載依賴
2:管理依賴的版本
3:有的還具有task runner功能(npm)
這裏就要提到幾個包管理工具:json
bower和npm都是包管理工具,可是又有不一樣。如今你們聽得最多,用的的多是npm,yarn,bower已經差很少死掉了。
npm vs bower
npm(node package manager)本是nodejs用來管理node依賴的,可是後來也被用於前端的依賴管理。
bower是隻被用於管理前端的組件,例如html,css,js的工具,只用在前端。
在依賴結構上兩者也不相同。bower是扁平的依賴樹,須要用戶管理依賴的依賴。而npm採用的是嵌套的依賴樹,不須要用戶關心依賴的依賴。
bower
bower init //建立bower.json bower install jquery --save //安裝jquery依賴
安裝成功以後,bower會在當前目錄下建立一個名叫/bower_components的文件夾。全部經過bower安裝的依賴都會放到這個目錄下。例如上面的jquery安裝成功以後,咱們能在/bower_components目錄下獲得jquery相關文件,而後咱們就能夠在HTML文件裏面引用了:
<script src="bower_components/jquery/dist/jquery.min.js"></script>
npm也是相似的:
npm init //建立package.json文件 npm install jquery --save //安裝jquery依賴
安裝成功以後會,npm會在當前目錄下建立一個名叫node_modules/的文件夾。因此經過npm安裝的依賴都會放到這個目錄下。例如上面的jquery安裝成功以後,咱們能在node_modules/目錄下獲得jquery相關文件,而後咱們就能夠在HTML文件裏面引用了:
<script src="node_modules/jquery/dist/jquery.min.js"></script>
3:Module bundler工具
在上面的第二點裏面,咱們使用了包管理工具,已經再也不須要咱們本身手動去網上找依賴,下載到項目庫裏,可是想要使用,依然須要在HTML文件裏面一一引用。咱們要怎樣才能像別的語言同樣在一個js文件裏面引用另一個js文件(模塊)呢?
固然自從ES6(ES2015)開始,JavaScript已經有這個功能了,咱們能夠經過import來引入,export來導出。可是在這以前,咱們只能依賴Module bundler工具來作到這一點。
當時比較出名和流行的一下2大解決方案:
至今仍然有不少人沒有弄明白CommonJS和AMD都是一個協議標準,而不是一個具體的庫。CommonJs的核心就是module(模塊),定義了JavaScript代碼怎樣引用和導出代碼。實現了CommonJs的最出名的就是node.js和Browserify.js,而對應的實現了AMD的比較是Require.js
你們都知道node.js是運行在服務端的JavaScript,不屬於咱們本篇的範疇,這裏不講。接下來咱們來看看
Browserify.js
若是你打開Browserify的官網,能夠看到這樣一句話:
Browserify lets you require('modules') in the browser by bundling up
all of your dependencies.
Browserify提供require()方法在一個js文件裏面引入另一個js文件或者一個js文件export的變量。最終Browserify會根據依賴關係,把全部的js代碼都整合到一個js文件裏,也就是咱們常說的bundle文件。以後就只須要在HTML文件裏面引用這一個js bundle文件就好了。
接下來看看具體怎麼使用:
step1: 全局安裝browserify
npm install browserify -g //全局安卓browserify
step2: 在module/目錄下建立一個module.js,有以下示例代碼:
function getSum(a, b) { return a + b; } module.exports = getSum;
step3: 建立main.js文件,在這裏面使用module/module.js
var getSum = require('./module/module'); var sum = getSum(10, 10); console.log('10 + 10 = ', sum);
step4: 利用browserify建立bundle文件:
browserify main.js -o build/bundle.js -d
上面的命令就是:browserify以main.js爲源文件,生成bundle文件bundle.js,建立文件夾build/,並把bundle.js放到build/路徑下。-o(-output)表示後面跟上輸出文件路徑, -d表示生成source map.
step5: 在HTMl文件裏面引入上一步的bundle.js
<!doctype html> <html> <head> <meta charset="UTF-8"> <script src="build/bundle.js"></script> </head> <body></body> </html>
step6: 驗證結果
10 + 10 = 20 //控制檯獲得咱們正確地結果
4:task runner工具
前端的task可能會有:檢查代碼格式,預編譯,跑測試,壓縮代碼,起server等。Task Runner就是按照用戶自定義的任務流自動地完成一系列的task。
通常task runner工具自己並不具體具體執行某項任務的功能,而是每個任務都有相應的插件來完成。例如曾經流行過的grunt和gulp。
可是如今的前端項目也不會再用到grunt和gulp了。現現在,由於項目上通常會用到npm來作依賴管理,而npm本身的script就能夠用來run task, 這樣也不用額外再多下一個額外的工具了。