JavaScript開發工具簡明歷史
譯者按: JavaScript開發要用到的工具越來越多,越來越複雜,為什麼呢?你真的弄明白了嗎?
為了保證可讀性,本文采用意譯而非直譯。另外,本文版權歸原作者所有,翻譯僅用於學習。
如果你不是老司機,面對眾多JavaScript開發工具,也許會有些搞不清楚狀況。因為,JavaScript的生態系統在迅速的變化,新手很難理解這些工具的功能以及它們所解決的問題。對此,我深有體會。
我是1998開始程式設計的,但是我直到2014才開始學習JavaScript。當我第一次接觸Browserify時,有這樣一句介紹:
通過將依賴打包,Browserify讓你可以在瀏覽器中使用require(‘modules’)
當時,我完全無法理解這句話,也不知道Browserify到底有什麼用。
這篇部落格將從歷史演進的角度,告訴大家今天的JavaScript開發工具是怎樣發展而來,以及它們到底有什麼作用。首先,我們將介紹一個非常簡單的網頁示例,它是由最原始的HTML與JavaScript寫的。然後,我們會逐步介紹不同的工具,它們可以解決不同的問題。
原始的JavaScript使用方式
最原始的網頁,是用HTML和JavaScript編寫的,沒有那麼多么蛾子。不過,我們需要手動下載並載入依賴的JavaScript檔案。如下,index.html中載入1個JavaScript檔案:
<!-- index.html -->
<!DOCTYPE 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檔案:
// index.js
console.log("Hello from JavaScript!");
這樣,一個簡單的網頁就寫好了!
現在,假設你需要使用一個第三方庫比如moment.js,這個庫可以幫助我們處理時間資料。比如:
moment().startOf(`day`).fromNow(); // 20 hours ago
我們需要在的官網下載moment.min.js,放到同一個目錄中,然後在index.html中載入:
<!-- index.html -->
<!DOCTYPE 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庫更新時,我們需要手動下載並載入新版本,這樣確實很煩…
npm:包管理工具
大概2010開始,數個JavaScript包管理工具誕生了,它們旨在通過一箇中央倉庫,使得下載和更新JavaScript庫更加自動化。2013年時,Bower可能是最流行的;到了2015年, npm逐漸佔據統治地位;而2016年,yarn開始逐漸引起關注,但是它的底層是基於npm的。還有一點,npm最初是為node.js開發的,並不是為了前端。因此,使用npm管理前端的依賴庫顯得有點奇怪。
現在,我們來看看如何使用npm安裝moment.js吧。
如果你已經安裝了nodejs,則npm也應該安裝好了。這時,進入index.html所在目錄,執行以下命令:
$ npm init
終端會出現數個問題,僅需使用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:
$ npm install moment --save
這個命令會做兩件事情:首先,它會下載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 -->
<!DOCTYPE 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!
webpack – 打包工具
大多數程式語言都提供了模組管理功能,可以在一個檔案中匯入另一個檔案的程式碼。然而,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:
$ npm install webpack --save-dev
--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:
$ ./node_modules/.bin/webpack index.js bundle.js
bundle.js為生成的打包檔案,可以直接在瀏覽器中使用:
<!-- index.html -->
<!DOCTYPE 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,而不需要指定任何配置選項,就可以進行打包了:
$ ./node_modules/.bin/webpack
總結: 使用打包工具之後,對於第三方JS庫,我們不再需要在HTML中使用<script>
載入,也不需要定義全域性變數了,而是直接在JS程式碼中使用require語句。另外,將多個JS檔案打包成為一個單獨的檔案也有利於提高網頁效能。然而,每次更新程式碼時,我們都需要手動執行webpack,這很不方便。
Babel – 新語法特性轉碼器
轉碼器可以將程式碼由一個語言轉換為另一個語言,它對於前端開發來說非常重要。瀏覽器對於語言的新特性支援通常很慢,我們使用新語言特性編寫的程式碼需要轉換為相容的程式碼才能正常執行。
對於CSS,轉碼器有Sass,Less,以及Stylus。對於JavaScript,CoffeeScript 曾經是最流行的,而現在用的最多的是babel和TypeScript。CoffeeScript是一門可以編譯到JavaScript的語言,旨在優化JavaScript。Typescript也是一門語言,支援最新的ECMAScript,並且支援靜態型別檢查。而Babel並非一門語言,而只是一個轉碼器,可以將ES6以及更高版本的JavaScript程式碼轉為ES5程式碼,從而相容各個瀏覽器。很多人選擇babel,因為它最接近原生的JavaScript。
現在,我們來看看如何使用Babel。
首先,我們需要安裝babel:
$ npm install babel-core babel-preset-env babel-loader --save-dev
我們一共安裝了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重新構建程式碼:
$ ./node_modules/.bin/webpack
其實,現在大多數瀏覽器都支援了ES2015特性,所以你可以測試一下IE9。在bundle.js中,我們可以看到轉碼後的程式碼:
// bundle.js
// ...
console.log(`Hello ` + name + `, how are you ` + time + `?`);
// ...
總結: 有了Babel,我們就可以放心地使用最新的JavaScript語法了。但是使用模板字串這樣簡單的語法顯然沒什麼意思,所以不妨試試async/await。不過,現在我們還有兩個問題需要解決:bundle.js應該需要壓縮,這樣才能提高效能,這一點很簡單;每次修改程式碼,都需要手動執行webpack,這樣很不方便,下一步我們來解決這個問題。
npm scripts – 任務管理工具
任務管理工具可以將一些重複性的任務自動化,比如合併檔案、壓縮程式碼、優化圖片以及執行測試等。
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選項可以壓縮程式碼):
$ npm run build
執行watch,則一旦javascript修改了,就會自動重新執行wepback,這樣開發就方便多了:
$ npm run watch
還有,我們可以webpack-dev-server,它可以提供一個網頁伺服器,而且能夠自動過載頁面:
$ npm install webpack-dev-server --save-dev
修改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"
}
}
執行:
$ npm run server
這時,瀏覽器會自動開啟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/
相關文章
- chrome devtool 開發者工具 控制檯歷史、斷點歷史 匯出全部、儲存Chromedev斷點
- 《程式設計時間簡史系列》JavaScript 模組化的歷史程式程式設計JavaScript
- SDRAM簡要歷史
- 把握前端開發歷史脈絡前端
- iOS歷史(iOS系統發展歷史)iOS
- 還原JavaScript的真實歷史~JavaScript
- 從事程式設計那些年經歷的跨平臺開發工具框架演變歷史程式設計框架
- Linux發展歷史Linux
- GTA開發歷史(四):噩夢降臨
- GTA開發歷史:親爸爸的時代
- JavaScript開發工具:WebStorm for MacJavaScriptWebORMMac
- WebStorm for Mac(JavaScript開發工具)WebORMMacJavaScript
- Kubernetes 發行版本歷史
- 程式碼家:簡明資料庫史資料庫
- [譯]JS 模組化歷史簡介JS
- git簡略形式檢視提交歷史Git
- 北京-求職(=_=!)-PHP開發簡歷求職PHP
- 2022年的JavaScript開發工具JavaScript
- 學javascript有哪些開發工具JavaScript
- 深度學習發展歷史深度學習
- 人工智慧發展歷史人工智慧
- PDF規範發展歷史
- JavaScript 微觀效能測試、歷史和侷限性JavaScript
- 使用 JavaScript 操作瀏覽器歷史記錄 APIJavaScript瀏覽器API
- 純淨搭建簡歷工具
- 【工具】火狐瀏覽器歷史版本下載瀏覽器
- odoo 開發入門教程系列-QWeb簡史OdooWeb
- ebpf發展簡史eBPF
- GTA開發歷史(三) :從自由城到罪惡都市
- JavaScript工具函式助力高效開發JavaScript函式
- HarmonyOS系統的發展歷史
- 人工智慧發展的歷史人工智慧
- 資料中心的發展歷史
- MySQL版本發展歷史介紹MySql
- JavaScript 模組的發展史JavaScript
- 歷史背景
- tcpdump歷史TCP
- 容器歷史
- OAuth歷史OAuth