宣告:以此文寫給摸索和學習使用webpack的初級使用者,因為官方文件只給出了關鍵點的解讀,對於入門的初學者看的可謂是一頭霧水,現在好多的文章也是隻是介紹了自己的想法和案例,沒有講明白基礎點
我所接觸的前端模組化變更
兩年前實習所在的一家創業公司在前端工程化方面還很傳統,幾乎稱不上是前端工程化,因為我們通過使用Ant這個構建工具,在一個build.xml中配置將所有的js都打包成一個js檔案,css也是,可想而知專案小的時候,前期很順利,後來專案越來越大,新需求新邏輯越來越多,這種方法即將被淘汰掉。
後半年我們開始接觸grunt+sea.js,將以前的專案全部重構,效能上有了很大的改善,但是慢慢地就會發現需要配置的task越來越多等問題,那時候jquery+bootstrap還是我們的主要開發框架。
一年後我畢業了離開創業公司,來到了現在的公司,見識到了真正的前端工程化專案,目前我們還處在使用webpack+gulp的階段,今年即將全面使用webpack 去掉gulp
來一段廢話
如今的Webpack已經是一個出色的前端自動化構建工具、模組化工具、資源管理工具。至於Webpack是什麼?為什麼使用Webpack?gulp,grant,webpack 什麼關係和區別這些在此不做贅述,太多的文件和文章了大家去了解一下
走進webpack 基本例項(翻譯2.0官方例子)
先不要考慮把每一個點和知識都瞭解和懂了再動手,我一般都是直接看官方的英文文件的Getting Started,相信我這絕對是最快最正確的學習方式
一步步開始吧
- 基礎需求:先裝好node,因為webpack是一個基於node的專案
- 初始化一個webpack專案根據以下命令
//cd 到你的一個目錄下可以是documents or desktop一步步輸入命令
mkdir webpack-demo && cd webpack-demo
npm init -y
npm install --save-dev webpack複製程式碼
這時候開啟你的專案檔案你會發現webpack-demo資料夾下多了兩個檔案
- package.json
- node_modules
然後我們在編輯器中開啟webpack-demo資料夾,手動建立下列目錄檔案
- app資料夾/index.js(用來寫js邏輯)
- index.html(例項的入口頁面)
- webpack.config.js(webpack的配置檔案)
上程式碼示例(貼上到你的檔案中用吧)app/index.js
function component () {
var element = document.createElement('div');
/* lodash is required for the next line to work */
element.innerHTML = _.join(['Hello','webpack'], ' ');
return element;
}
document.body.appendChild(component());複製程式碼
由於在這個js中依賴lodash(這是一個具有一致介面、模組化、高效能等特性的 JavaScript 工具庫),所以在我們的專案中需要加入這個依賴到我們的node_modules中,執行以下命令即可
npm install --save lodash複製程式碼
以上命令只是將lodash這個依賴庫新增進去,然而我們要使用還得通過import 將它引入到具體的js檔案中,所以修改我們的app/index.js,新增一行,然後將它以 _ 的別名繫結(不會造成全域性範圍變數名汙染)
import _ from 'lodash';
function component () {
var element = document.createElement('div');
element.innerHTML = _.join(['Hello','webpack'], ' ');
return element;
}
document.body.appendChild(component());複製程式碼
下面來寫index.html
<html>
<head>
<title>webpack 2 demo</title>
</head>
<body>
<script src="dist/bundle.js"></script>
</body>
</html>複製程式碼
你肯定會問?dist目錄沒有啊?更別說bundle.js了,彆著急繼續往下看webpack.config.js
var path = require('path');
module.exports = {
entry: './app/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
};複製程式碼
然後在執行webpack 命令(如果存在 webpack.config.js,webpack 命令將預設選擇使用它)
webpack --config webpack.config.js複製程式碼
命令列的結果
Hash: ff6c1d39b26f89b3b7bb
Version: webpack 2.2.0
Time: 390ms
Asset Size Chunks Chunk Names
bundle.js 544 kB 0 [emitted] [big] main
[0] ./~/lodash/lodash.js 540 kB {0} [built]
[1] (webpack)/buildin/global.js 509 bytes {0} [built]
[2] (webpack)/buildin/module.js 517 bytes {0} [built]
[3] ./app/index.js 278 bytes {0} [built]複製程式碼
此時我們的專案目錄中已經成功建立 dist/bundle.js 檔案,開啟瀏覽器執行你的index.html頁面會顯示'Hello webpack'
讓我門帶著疑問我們開始講下面的內容
webpack配置檔案詳解
webpack的配置檔案是一個node.js的module,它沒有固定的命名,我們看到的例子都是webpack.config.js,一開始我以為這是約定成俗的固定名字,就例如gulpfile.js,它也沒有固定的路徑要求,如果你直接用webpack來執行編譯,那麼webpack預設讀取的將是當前目錄下的webpack.config.js
webpack.config.js用CommonJS風格來書寫,形如:
module.exports = {
entry: "./entry",
output: {
path: __dirname + "/dist",
filename: "bundle.js"
}
}複製程式碼
如果你有其它命名的需要或是你有多份配置檔案,可以使用--config引數傳入路徑來執行:
$ webpack --config ./webpackConfig/dev.config.js複製程式碼
一些常用基本概念
- 入口檔案配置:entry引數
entry可以是字串形式的單個檔案入口,也可以是物件形式的多入口,如果是多個單頁應用程式,那麼則使用多入口的方式來獨立每個應用
entry: './app/index.js',複製程式碼
entry: {
pageOne: './src/pageOne/index.js',
pageTwo: './src/pageTwo/index.js',
pageThree: './src/pageThree/index.js'
}複製程式碼
- 輸出檔案:output引數
output引數告訴webpack以什麼方式來生成/輸出檔案,值得注意的是,與entry不同,output相當於一套規則,所有的入口都必須使用這一套規則,不能針對某一個特定的入口來制定output規則,於此同時output有很多options,這裡介紹比較常用的:
path、publicPath、filename、chunkFilename
所有的opitons
webpack中output配置項必須要包含的兩個引數是path和filename
const config = {
output: {
filename: 'bundle.js',
path: '/home/proj/public/assets'
}
};
module.exports = config;複製程式碼
path
path參數列示生成檔案的根目錄,需要傳入一個絕對路徑。path引數和後面的filename引數共同組成入口檔案的完整路徑
filename
filename指定每個輸出檔案在最終生成目錄上的名稱。
1.單個入口檔案的output配置
{
entry: './src/app.js',
output: {
filename: 'bundle.js',
path: __dirname + '/build'
}
}
// writes to disk: ./build/bundle.js複製程式碼
2.多入口檔案的output配置,有以下三種規則
{
entry: {
app: './src/app.js',
search: './src/search.js'
},
output: {
filename: '[name].js',
path: __dirname + '/build'
}
}
// writes to disk: ./build/app.js, ./build/search.js複製程式碼
- [name],指代入口檔案的name,也就是上面提到的entry引數的key,因此,我們可以在name裡利用/,即可達到控制檔案目錄結構的效果。
- [hash],指代本次編譯的一個hash版本,值得注意的是,只要是在同一次編譯過程中生成的檔案,這個[hash]的值就是一樣的;在快取的層面來說,相當於一次全量的替換。
- [chunkhash],指代的是當前chunk的一個hash版本,也就是說,在同一次編譯中,每一個chunk的hash都是不一樣的;而在兩次編譯中,如果某個chunk根本沒有發生變化,那麼該chunk的hash也就不會發生變化。這在快取的層面上來說,就是把快取的粒度精細到具體某個chunk,只要chunk不變,該chunk的瀏覽器快取就可以繼續使用。
publicPath
publicPath參數列示的是一個URL路徑(指向生成檔案的根目錄),用於生成css/js/圖片/字型檔案等資源的路徑,以確保網頁能正確地載入到這些資源。 publicPath引數跟path引數的區別是:path引數其實是針對本地檔案系統的,而publicPath則針對的是瀏覽器;因此,publicPath既可以是一個相對路徑,如示例中的'../../../../build/',也可以是一個絕對路徑如http形式的網頁連結。
chunkFilename
chunkFilename引數與filename引數類似,都是用來定義生成檔案的命名方式的,只不過,chunkFilename引數指定的是除入口檔案外的chunk
現在來說說我們最開始的案例中用到的path變數是什麼,在最開始講到webpack的配置檔案是一個node.js的module,所以這裡的path其實也是node.js的一個模組,使用來處理路徑的模組,它提供了很多方法比如獲取絕對路徑的path.resolve()等,可以去搜尋資料學習
var path = require('path');
module.exports = {
entry: './app/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
};複製程式碼
- 各種Loader配置:module引數
webpack一直號稱能夠打包任何資源,採用的就是Loader,loader是對應用程式中資原始檔進行轉換。它們是(執行在Node.js中的)函式,可以將資原始檔作為引數的來源,然後返回新的資原始檔
這裡距舉一個打包css的例子,要通過webpack打包CSS,像任何其他模組一樣將CSS匯入JavaScript程式碼,並使用css-loader(它輸出CSS作為JS模組)
- 首先,安裝相對應的 loader
- 像JavaScript模組一樣匯入CSS檔案,例如在index.js中
- 其次,配置 webpack.config.js,對每個 .css 檔案使用 css-loader
$ npm install --save-dev css-loader
建立一個index.css在index.js中
import './index.css';
配置CSS和JavaScript打包在一起
module.exports = {
module: {
rules: [{
test: /\.css$/,
use: 'css-loader'
}]
}
}複製程式碼
- 更多的內容例如外掛 模組 熱替換等內容請自行學習
寫在最後的總結
看完這篇文章,如果按照我的步驟一步步實現,肯定對webpack(2.0)已經入門了,下面需要的就是你花費時間學習官方文件並且結合自己的專案來實際操作了,附上官網的文件,2.0的文件寫的很清楚和詳細webpack2.0
Cayley 一個不斷努力學習的女程式設計師