去年一篇《在 2016 年學 JavaScript 是一種什麼樣的體驗?》嚇壞了不少想要入行新同窗和入行好久的老司機,感受一會兒前端世界已經看不懂了,作個頁面要那麼麻煩?固然若是你只是想要一個簡單的靜態頁面,這麼玩兒就是殺雞用牛刀了。但若是你準備開發一個web app,以後會不斷的迭代,有一個溫馨的開發環境是及其重要的,那麼底怎麼樣的環境纔會是溫馨愉悅的呢?javascript
好比這樣的一個環境:資源依賴能夠安裝並模塊化引用、可使用很酷的es6語法、可使用scss預處理器寫css、代碼可實時更新而不用一遍遍的手動刷新頁面,這樣的開發環境你會不會以爲很爽!好,咱們這就來配置一個這樣的環境!css
首先,你須要一個node,而後npm也會隨着node一塊兒裝上。html
什麼是npm?簡單的說npm是用來下載安裝nodejs的第三方工具包的一個管理器。固然,如今也能夠安裝瀏覽器中使用的包。提到包管理器,就不得不說下bower,bower以前一直是前端庫管理工具,一開始npm只能發佈和安裝nodejs的包,因此bower盛行一時,隨着commonjs的普及,以及umd規範的出現,讓npm安裝前端瀏覽器js包成爲了可能,隨着npm生態的成熟,bower也就慢慢被人淡忘了~前端
node安裝完成後,能夠執行如下命令驗證安裝是否成功:java
$ node -v v6.11.0 $ npm -v 3.10.10
別急,node的部分還沒完,國內經過npm的官方源安裝依賴好像很慢,動不動就要等上半天,如何解決?咱們能夠裝一個nrm!nrm是npm registry管理工具,能夠自由切換npm registry,而後命令行使用時依然是npm
,國內有不少npm的鏡像,好比淘寶的cnpm,然而不少公司都架設了本身的私庫。什麼是私庫?私庫就是隻能在公司內網訪問,不能發佈到npm共享平臺的npm包,好比咱們大公司私庫的registry的名稱就是hnpm
。不細說了,咱們先裝一個試試:node
$ npm install -g nrm
而後根據官方教程咱們先切一個國內的registry,好比大淘寶的:webpack
$ nrm use cnpm
而後用npm隨便安裝個什麼,看看速度如何?是否是很快^_^git
等等,node還有。有的開發依賴包是有node版本依賴的,咱們知道node不一樣大版本的功能仍是差異很大的,但咱們又不會一遍遍的卸載安裝吧?感受好蠢!好吧,咱們固然能夠裝一個nvm,nvm?好像和nrm很像!nvm是node的版本管理工具,能夠在多個終端切換和運行不一樣的node版本,能夠到這裏參考具體的安裝教程。不過nvm在windows下不能使用,不要緊,這裏還有幾個替代工具:nvm-window,gnvm供你選擇。es6
一樣,咱們執行下命令驗證安裝成果:github
$ nvm --version 0.33.0
有了上面的工具咱們就能夠開始建立一個項目了,咱們執行如下命令來開始一個項目:
mkdir my-app cd my-app npm init
執行npm init
後你會看到你須要輸入項目的一些信息,完成後回車確認,而後npm會在根目錄下建立一個叫package.json
的文件,你以後經過--save
或者--save-dev
安裝的依賴包都會出如今這個文件裏。
先無論那麼多,咱們在根目錄下建立一個src
目錄,而後在src
下建立index.js
、index.html
……,好吧,你能夠按照下面的結構新建文件:
. ├── package.json └── src ├── index.css ├── index.html └── index.js
在如下文件中輸入代碼:
index.js:
var el = document.createElement('div'), text = document.createTextNode('My App'); el.appendChild(text); document.body.appendChild(el);
index.html:
<!doctype html> <html> <head> <meta charset="utf-8" /> <title>My App</title> </head> <body> </body> </html>
咱們要想辦法讓這個頁面跑起來,what??? 就這麼簡單?,把js引入index.html
不就完事兒了嘛?固然沒那麼簡單,咱們但是要搞高大上的東西的呢!
哈~跑題了,咱們繼續。
首先咱們要裝一個叫webpack的東西,它是一個模塊打包器,也就是咱們俗稱的構建工具,以前的那些grunt,gulp也都是構建工具,可是這年頭流行webpack了!開個玩笑,webpack的可擴展性和可插件化,以及把任何文件都視爲模塊的概念獲得了前端社區的一致推崇,並且在打包效率和按需分割文件上都是其餘幾個構建工具沒法相比較的,固然webpack的配置太靈活,官方文檔寫的太太太難看懂,也致使了不少初學者無從下手。
接下來咱們就來配下這個神奇的工具吧。
咱們先安裝下webpack:
npm install --save-dev webpack
而後在根目錄下新建一個webpack.config.js
文件,輸入如下代碼:
let path = require('path'); module.exports = { entry: { app: path.resolve(__dirname, 'src', 'index.js') }, output: { filename: '[name].js', path: path.resolve(__dirname, 'dist') } };
但要想在瀏覽器中訪問還得有個本地服務器,好在webpack都幫咱們想到了,咱們能夠裝一個webpack-dev-server:
npm install --save-dev webpack-dev-server
咱們在package.json中增長個npm scripts:
"scripts": { "start": "webpack-dev-server --port 3003" },
ok!咱們執行下npm start
,在瀏覽器中訪問:http://localhost:3003。哎?好像哪裏不對!是的,你得告訴webpack,你的bundle(打包後的js)要插入到哪一個html模板,前面說過,webpack是插件化的,它把不少功能開放給了第三方來實現,他只是來負責拼裝的,好,如今咱們須要安裝一個html-webpack-plugin插件:
npm install --save-dev html-webpack-plugin
修改下webpack-config.js:
let HtmlWebpackPlugin = require('html-webpack-plugin'), path = require('path'); module.exports = { entry: { ... }, ... plugins: [ new HtmlWebpackPlugin({ template: path.resolve(__dirname, 'src', 'index.html') }) ] }
再次執行npm start
,頁面能夠正常訪問了。
可是,這樣彷佛有點low,咱們新增一個文件utils.js
,搞點es6語法:
. ├── package.json └── src ├── index.css ├── index.html ├── index.js + └── utils + └── utils.js
utils.js:
export function wordsToSentence(...words) { return words.join(' '); }
修改index.js
+ import { wordsToSentence } from './utils/utils'; let el = document.createElement('div'), - text = document.createTextNode('My App'); + text = document.createTextNode( + wordsToSentence('Welcome', 'to', 'my', 'app!') + ); el.appendChild(text); document.body.appendChild(el);
刷新頁面後好像也沒什麼異常(你確定用了chrome吧!),仔細看控制檯的source的app.js
(你的bundle)的代碼片斷:
"use strict"; /* harmony export (immutable) */ __webpack_exports__["a"] = wordsToSentence; function wordsToSentence(...words) { return words.join(' '); }
值得注意的是,使用es6時須要考慮那些沒有支持es6的舊瀏覽器,雖然在chrome或者其餘高級瀏覽器中沒有出現問題,但不能保證在其餘瀏覽器中能正常運行。爲了萬無一失,咱們須要將es6轉換爲es5,也就是js代碼轉換器,這類工具當今世界就屬babel最牛逼了:
npm install --save-dev babel-loader babel-core
稍等,裝了babel還無法用,還得搞個presets:
npm install --save-dev babel-preset-env
在根目錄下新建個.babelrc
,輸入配置:
{ "presets": ["env"] }
修改webpack.config.js,增長babel的支持:
... module.exports = { ... module: { rules: [ { test: /\.js$/, loader: 'babel-loader', include: path.resolve(__dirname, 'src') } ] }, ... };
執行npm start
,找到控制檯source下的app.js代碼片斷:
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.wordsToSentence = wordsToSentence; function wordsToSentence() { for (var _len = arguments.length, words = Array(_len), _key = 0; _key < _len; _key++) { words[_key] = arguments[_key]; } return words.join(' '); }
已經成功轉換成es5代碼。可是,目前es6 modules是由babel來轉的,你能夠對比先後2次的代碼片斷的模塊輸出部分。如今,webpack 2已經內4置了es6 modules的轉換,聽說效率和性能比babel高!^_^沒驗證過哦,咱們先試試,把babel的模塊轉換關了先:
.babelrc
{ "presets": [ ["env", { "modules": false }] ] }
執行npm start
再次查看輸出後的app.js的代碼片斷:
-Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.wordsToSentence = wordsToSentence; +/* harmony export (immutable) */ __webpack_exports__["a"] = wordsToSentence; function wordsToSentence() { ... }
模塊輸出方式又回到了使用babel前的代碼。
js的環境彷佛已經準備就緒,但css還沒上場,咱們來修改下index.css:
#app { color: #57af09; }
同時將css導入bundle入口,並修改下index.js:
import './index.css'; import { wordsToSentence } from './utils/utils'; let el = document.createElement('div'), ... el.id = 'app'; ...
有了樣式還不行,webpack還須要相應的loader來處理css的模塊:
npm i --save-dev style-loader css-loader
修改下webpack.config.js:
... module.exports = { ... module: { rules: [ ... { test: /\.css$/, loader: ['style-loader', 'css-loader'], include: path.resolve(__dirname, 'src') } ] }, ... };
執行npm start
,如今能夠看到頁面已經有了樣式。可是,咱們說過,咱們但願使用先進的武器:scss。咱們修改下index.css:
$app-color: #57af09; #app { color: $app-color; }
再修改下文件後綴:
. ├── package.json └── src - ├── index.css + ├── index.scss ...
修改index.js的入口:
-import './index.css'; +import './index.scss';
因爲文件(模塊)類型變了,咱們還須要一個sass的webpack loader:
npm install --save-dev sass-loader node-sass
再次修改webpack.config.js:
... module.exports = { ... module: { rules: [ ... { - test: /\.css$/, + test: /\.scss$/, - loader: ['style-loader', 'css-loader'], + loader: ['style-loader', 'css-loader', 'sass-loader'], include: path.resolve(__dirname, 'src') } ] }, ... };
執行npm start
,webpack編譯沒有報錯,頁面顯示一切正常!
若是你嘗試修改index.scss
的樣式,你有沒注意到一個問題:頁面會自動刷新。但有時候咱們在開發一個模塊,好比dialog,刷新會致使你須要反覆的在頁面上操做才能看到這個dialog的樣式更新。那咱們有沒有辦法不刷新頁面又能看到代碼的更新呢?
其實很簡單,由於webpack-dev-server已經內置了這樣的功能,咱們只要配置下package.json
的npm scripts:
"scripts": { "start": "webpack-dev-server --hot --inline --port 3003" },
注意到上面的代碼,咱們增長了--hot --inline
,讓開發環境有了熱更新的能力。咱們從新執行npm start
,而後將你的瀏覽器和編輯器並排放置,而後反覆修改index.scss,你會看到頁面不會刷新,但樣式在自動的推送更新,這就是傳說中的熱更新。
到這裏,簡單(簡陋)的、現代化的前端開發環境已經有了基本的雛形,可是,本篇文章不是webpack的使用指南,也不是es6的語法教程,儘管如此,仍是但願你經過本篇文章感覺到前端開發在工程化領域的發展帶來的驚喜。