譯者按: JavaScript開發要用到的工具愈來愈多,愈來愈複雜,爲何呢?你真的弄明白了嗎?javascript
爲了保證可讀性,本文采用意譯而非直譯。另外,本文版權歸原做者全部,翻譯僅用於學習。css
若是你不是老司機,面對衆多JavaScript開發工具,也許會有些搞不清楚情況。由於,JavaScript的生態系統在迅速的變化,新手很難理解這些工具的功能以及它們所解決的問題。對此,我深有體會。html
我是1998開始編程的,可是我直到2014纔開始學習JavaScript。當我第一次接觸Browserify時,有這樣一句介紹:前端
經過將依賴打包,Browserify讓你能夠在瀏覽器中使用require(‘modules’)vue
當時,我徹底沒法理解這句話,也不知道Browserify到底有什麼用。java
這篇博客將從歷史演進的角度,告訴你們今天的JavaScript開發工具是怎樣發展而來,以及它們到底有什麼做用。首先,咱們將介紹一個很是簡單的網頁示例,它是由最原始的HTML與JavaScript寫的。而後,咱們會逐步介紹不一樣的工具,它們能夠解決不一樣的問題。node
最原始的網頁,是用HTML和JavaScript編寫的,沒有那麼多幺蛾子。不過,咱們須要手動下載並載入依賴的JavaScript文件。以下,index.html中載入1個JavaScript文件:react
<!-- index.html -->
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JavaScript Example</title>
<script src="index.js"></script>
</head>
<body>
<h1>Hello from HTML!</h1>
</body>
</html>
|
<script src="index.js"></script>
載入了同目錄的index.js文件:webpack
// index.js
console.log("Hello from JavaScript!");
|
這樣,一個簡單的網頁就寫好了!git
如今,假設你須要使用一個第三方庫好比moment.js,這個庫能夠幫助咱們處理時間數據。好比:
moment().startOf(
'day').fromNow(); // 20 hours ago
|
咱們須要在的官網下載moment.min.js,放到同一個目錄中,而後在index.html中載入:
<!-- index.html -->
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Example</title>
<link rel="stylesheet" href="index.css">
<script src="moment.min.js"></script>
<script src="index.js"></script>
</head>
<body>
<h1>Hello from HTML!</h1>
</body>
</html>
|
可知,moment.min.js先於index.js載入,這樣咱們就能夠在index.js中調用moment了:
// index.js
console.log("Hello from JavaScript!");
console.log(moment().startOf('day').fromNow());
|
總結: 直接使用HTML和JavaScript庫編寫網頁很是簡單,也很容易理解;然而,當JavaScript庫更新時,咱們須要手動下載並載入新版本,這樣確實很煩…
大概2010開始,數個JavaScript包管理工具誕生了,它們旨在經過一箇中央倉庫,使得下載和更新JavaScript庫更加自動化。2013年時,Bower多是最流行的;到了2015年, npm逐漸佔據統治地位;而2016年,yarn開始逐漸引發關注,可是它的底層是基於npm的。還有一點,npm最初是爲node.js開發的,並非爲了前端。所以,使用npm管理前端的依賴庫顯得有點奇怪。
如今,咱們來看看如何使用npm安裝moment.js吧。
若是你已經安裝了nodejs,則npm也應該安裝好了。這時,進入index.html所在目錄,執行如下命令:
|
終端會出現數個問題,僅需使用enter鍵選擇默認配置就行了。命令執行以後,會生成一個package.json文件,npm使用這個文件保存全部的項目信息。默認的package.json是這樣的:
{
"name": "your-project-name",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
|
使用一下命令,便可安裝moment.js:
|
這個命令會作兩件事情:首先,它會下載moment.js,將其保存到node_modules目錄中;而後,它會更新package.json,保存moment安裝信息。
{
"name": "modern-javascript-example",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"moment": "^2.19.1"
}
}
|
這樣,當咱們須要與其餘人分享這個項目時,就不須要將node_modules發送給對方了,而只須要給它package.json文件,由於它可使用npm install
安裝全部依賴庫。
moment.min.js文件位於node_modules/moment/min目錄中,所以咱們能夠在index.html中直接載入moment.min.js:
<!-- index.html -->
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JavaScript Example</title>
<script src="node_modules/moment/min/moment.min.js"></script>
<script src="index.js"></script>
</head>
<body>
<h1>Hello from HTML!</h1>
</body>
</html>
|
總結: 如今,咱們不須要手動下載moment.js了,而能夠經過npm自動下載以及更新,這樣方便不少;可是,咱們須要在node_modules中找到對應的JS文件,而後將它載入HTML,這樣很不方便。
順便分享一個好東西: 若是你須要監控線上JavaScript代碼的錯誤的話,歡迎無償使用Fundebug!
大多數編程語言都提供了模塊管理功能,能夠在一個文件中導入另外一個文件的代碼。然而,JavaScript最初並無支持這種方式。很長時間以來,組織多個JavaScript文件的代碼時,須要使用全局變量。咱們在載入moment.min.js時,實際上也定義了一個moment全局變量,所以全部以後載入的JS文件,均可以使用它。
2009年,一個叫作CommenJS的項目出現了,它爲JavaScript模塊化定義了一個規範,從而容許JavaScript可以和其餘編程語言同樣在不一樣文件中引入模塊。Node.js是支持CommenJS規範的,它可使用require直接引用模塊:
// index.js
var moment = require('moment');
console.log("Hello from JavaScript!");
console.log(moment().startOf('day').fromNow());
|
這樣寫很是方便,然而,若是你在瀏覽器中執行上面的代碼,則會收到報錯,由於」require未定義」。
這時,咱們就須要打包工具了,它們能夠將源代碼構建成爲兼容瀏覽器的代碼,來避免上面提到的問題。簡單地說,打包工具能夠找到全部require語句,而後將它們替代爲各個JS文件中代碼,最終生成的一個單獨的JS文件。
Browserify是2011年發佈,曾經是最流行的打包工具;到了2015年, webpack逐漸成爲了最主流的打包工具。
如今,咱們來看看如何讓require('moment')
能夠在瀏覽器中執行。首先,咱們須要安裝webpack:
|
--save-dev
選項表示webpack模塊時開發環境中須要的依賴庫,而生產環境中並不須要。package.json更新以後是這樣的:
{
"name": "modern-javascript-example",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"moment": "^2.19.1"
},
"devDependencies": {
"webpack": "^3.7.1"
}
}
|
使用一下命令運行webpack:
|
bundle.js爲生成的打包文件,能夠直接在瀏覽器中使用:
<!-- index.html -->
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JavaScript Example</title>
<script src="bundle.js"></script>
</head>
<body>
<h1>Hello from HTML!</h1>
</body>
</html>
|
每次修改index.js以後,咱們都須要執行webpack。webpack的命令比較長,這樣很麻煩,尤爲是咱們須要使用一些高級選項時。這時,咱們能夠將webpack的配置選項寫入webpack.config.js文件:
// webpack.config.js
module.exports = {
entry:
'./index.js',
output: {
filename:
'bundle.js'
}
};
|
這樣,咱們直接運行wepack,而不須要指定任何配置選項,就能夠進行打包了:
|
總結: 使用打包工具以後,對於第三方JS庫,咱們再也不須要在HTML中使用<script>
載入,也不須要定義全局變量了,而是直接在JS代碼中使用require語句。另外,將多個JS文件打包成爲一個單獨的文件也有利於提升網頁性能。然而,每次更新代碼時,咱們都須要手動運行webpack,這很不方便。
轉碼器能夠將代碼由一個語言轉換爲另外一個語言,它對於前端開發來講很是重要。瀏覽器對於語言的新特性支持一般很慢,咱們使用新語言特性編寫的代碼須要轉換爲兼容的代碼才能正常運行。
對於CSS,轉碼器有Sass,Less,以及Stylus。對於JavaScript,CoffeeScript 曾經是最流行的,而如今用的最多的是babel和TypeScript。CoffeeScript是一門能夠編譯到JavaScript的語言,旨在優化JavaScript。Typescript也是一門語言,支持最新的ECMAScript,而且支持靜態類型檢查。而Babel並不是一門語言,而只是一個轉碼器,能夠將ES6以及更高版本的JavaScript代碼轉爲ES5代碼,從而兼容各個瀏覽器。不少人選擇babel,由於它最接近原生的JavaScript。
如今,咱們來看看如何使用Babel。
首先,咱們須要安裝babel:
|
咱們一共安裝了3個模塊:babel-core是Babel的核心部分;babel-preset-env定義了轉碼規則;babel-loader是Babel的webpack插件。
而後,在webpack.config.js中配置babel-loader便可:
// webpack.config.js
module.exports = {
entry:
'./index.js',
output: {
filename:
'bundle.js'
},
module: {
rules: [
{
test:
/\.js$/,
exclude:
/node_modules/,
use: {
loader:
'babel-loader',
options: {
presets: [
'env']
}
}
}
]
}
};
|
webpack的配置文件看着有點暈,大體含義是這樣的:告訴webpack找到全部js文件(除了node_modules目錄中的文件),根據babel-preset-env中的轉碼規則,使用babel-loader進行轉碼。至於webpack配置的細節,能夠查看文檔。
如今,咱們能夠開始使用ES2015特性編程了。index.js中使用了模板字符串:
// index.js
var moment = require('moment');
console.log("Hello from JavaScript!");
console.log(moment().startOf('day').fromNow());
var name = "Bob", time = "today";
console.log(`Hello ${name}, how are you ${time}?`);
|
咱們也可使用import來代替require :
// index.js
import moment from 'moment';
console.log("Hello from JavaScript!");
console.log(moment().startOf('day').fromNow());
var name = "Bob", time = "today";
console.log(`Hello ${name}, how are you ${time}?`);
|
修改index.js以後,運行webpack從新構建代碼:
|
其實,如今大多數瀏覽器都支持了ES2015特性,因此你能夠測試一下IE9。在bundle.js中,咱們能夠看到轉碼後的代碼:
// bundle.js
// ...
console.log('Hello ' + name + ', how are you ' + time + '?');
// ...
|
總結: 有了Babel,咱們就能夠放心地使用最新的JavaScript語法了。可是使用模板字符串這樣簡單的語法顯然沒什麼意思,因此不妨試試async/await。不過,如今咱們還有兩個問題須要解決:bundle.js應該須要壓縮,這樣才能提升性能,這一點很簡單;每次修改代碼,都須要手動運行webpack,這樣很不方便,下一步咱們來解決這個問題。
任務管理工具能夠將一些重複性的任務自動化,好比合並文件、壓縮代碼、優化圖片以及運行測試等。
2013年時,Grunt是最流行的任務管理工具,其次是Gulp。如今,直接使用npm的scripts功能的開發者彷佛愈來愈多了,這樣不須要安裝額外的插件。
修改package.json,便可配置npm scripts:
{
"name": "modern-javascript-example",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --progress -p",
"watch": "webpack --progress --watch"
},
"author": "",
"license": "ISC",
"dependencies": {
"moment": "^2.19.1"
},
"devDependencies": {
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-preset-env": "^1.6.1",
"webpack": "^3.7.1"
}
}
|
咱們定義了2個scripts,即build和watch。
運行build,便可構建代碼了(- -progress選項能夠顯示構建進程,-p選項能夠壓縮代碼):
|
運行watch,則一旦javascript修改了,就會自動從新運行wepback,這樣開發就方便多了:
|
還有,咱們能夠webpack-dev-server,它能夠提供一個網頁服務器,並且可以自動重載頁面:
|
修改package.json:
{
"name": "modern-javascript-example",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --progress -p",
"watch": "webpack --progress --watch",
"server": "webpack-dev-server --open"
},
"author": "",
"license": "ISC",
"dependencies": {
"moment": "^2.19.1"
},
"devDependencies": {
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-preset-env": "^1.6.1",
"webpack": "^3.7.1"
}
}
|
運行:
|
這時,瀏覽器會自動打開localhost:8080,並訪問index.html。當咱們修改index.js時,代碼會自動從新構建,而且頁面也會自動刷新。這樣咱們修改代碼以後,就能夠看到瀏覽器中的效果,而不須要任何額外的操做。
正如前文提到過,npm scripts或者其餘任務管理工具能夠作的事情還有不少,感興趣的話,能夠看看這個視頻。
簡單總結一下:剛開始咱們用HTML和JS寫代碼;後來咱們用包管理工具來安裝第三方庫;而後咱們用打包工具實現模塊化;再後來咱們用轉碼器從而使用最新語法;最後咱們用任務管理工具來自動化一些重複的任務。對於新手來講,這一切都顯得很是頭疼,更頭疼的是這一切還在不斷變化之中。
固然也有好消息,各個框架爲了方便初學者,都會提供工具,把全部配置都弄好: Ember有ember-cli,Angular有angular-cli, React有create-react-app, Vue有vue-cli。這樣,彷佛你什麼都不用管,只須要寫代碼就能夠了。然而,現實是殘酷的,總有一天你須要對Babel或者Webpack進行一些個性化配置。所以,理解每個工具的做用仍是很是有必要的,但願這篇博客能夠幫助你們。
版權聲明: 轉載時請註明做者Fundebug以及本文地址: https://blog.fundebug.com/2017/11/29/history-of-javascript-tools/