做者:Nicolas (滬江Web前端) 本文爲原創文章,轉載請註明做者及出處 本文的 webpack 代碼示例根據 webpack 2.7.0 編寫,並在 Mac 上正常運行。javascript
去年一篇《在 2016 年學 JavaScript 是一種什麼樣的體驗?》嚇壞了不少想要入行新同窗和入行好久的老司機,感受一會兒前端世界已經看不懂了,作個頁面要那麼麻煩?固然若是你只是想要一個簡單的靜態頁面,這麼玩兒就是殺雞用牛刀了。但若是你準備開發一個 Web App,以後會不斷的迭代,有一個溫馨的開發環境是及其重要的,那麼底怎麼樣的環境纔會是溫馨愉悅的呢?css
好比這樣的一個環境:資源依賴能夠安裝並模塊化引用、可使用很酷的 ES6 語法、可使用 SASS 預處理器寫 CSS、代碼可實時更新而不用一遍遍的手動刷新頁面,這樣的開發環境你會不會以爲很爽!好,咱們這就來配置一個這樣的環境!html
首先,你須要一個 Node.js,而後 NPM 也會隨着 Node.js 一塊兒裝上。前端
什麼是 NPM ?簡單的說 NPM 是用來下載安裝 Node.js 的第三方工具包的一個管理器。固然,如今也能夠安裝瀏覽器中使用的包。提到包管理器,就不得不說下 Bower,Bower 以前一直是前端庫管理工具,一開始 NPM 只能發佈和安裝 Node.js 的包,因此 Bower 盛行一時,隨着 CommonJS 的普及,以及 UMD 規範的出現,讓 NPM 安裝前端瀏覽器 js 包成爲了可能,隨着 NPM 生態的成熟,Bower 也就慢慢被人淡忘了~java
Node.js 安裝完成後,能夠執行如下命令驗證安裝是否成功:node
$ node -v
v6.11.0
$ npm -v
3.10.10
複製代碼
別急,Node.js 的部分還沒完,國內經過 NPM 的官方源安裝依賴好像很慢,動不動就要等上半天,如何解決?咱們能夠裝一個 nrm!nrm 是 npm registry 管理工具,能夠自由切換 npm registry,而後命令行使用時依然是 npm
,國內有不少 npm 的鏡像,好比淘寶的 cnpm ,然而不少公司都架設了本身的私庫。什麼是私庫?私庫就是隻能在公司內網訪問,不能發佈到 npm 共享平臺的 npm 包,好比咱們大公司私庫的 registry 的名稱就是 hnpm
。不細說了,咱們先裝一個試試:webpack
$ npm install -g nrm
複製代碼
而後根據官方教程咱們先切一個國內的 registry,好比大淘寶的:git
$ nrm use cnpm
複製代碼
而後用 NPM 隨便安裝個什麼,看看速度如何?是否是很快^_^es6
等等,Node.js 還有。有的開發依賴包是有 Node.js 版本依賴的,咱們知道 Node.js 不一樣大版本的功能仍是差異很大的,但咱們又不會一遍遍的卸載安裝吧?感受好蠢!好吧,咱們固然能夠裝一個nvm,nvm?好像和 nrm 很像!nvm 是 Node.js 的版本管理工具,能夠在多個終端切換和運行不一樣的 Node.js 版本,能夠到這裏參考具體的安裝教程。不過 nvm 在 windows 下不能使用,不要緊,這裏還有幾個替代工具:nvm-window,gnvm 供你選擇。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
,如今能夠看到頁面已經有了樣式。可是,咱們說過,咱們但願使用先進的武器:SASS。咱們修改下 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 的語法教程,儘管如此,仍是但願你經過本篇文章感覺到前端開發在工程化領域的發展帶來的驚喜。
iKcamp原創新書《移動Web前端高效開發實戰》已在亞馬遜、京東、噹噹開售。
2019年,iKcamp原創新書《Koa與Node.js開發實戰》已在京東、天貓、亞馬遜、噹噹開售啦!