Webpack 介紹:第一部分
Webpack 是近段時間非常流行的前端流程處理工具,用于實時執行構建任務和預處理你的文件。
你也許會使用 Grunt 或者 Gulp 來做類似的事情。首先建立一個編譯鏈,然后在上面定義從何處讀取代碼,將壓縮處理好的 CSS 和 JavaScript 等靜態資源輸出到什么地方。
這些工具都非常流行和好用,然而我卻要向你安利另一種實現此類需求的方法,那就是使用 Webpack 。 新技能Get!
什么是 Webpack?
Webpack 常被人們定義為“模塊打包工具”(module bundler),它讀取 JavaScript 模塊,分析它們之間的依賴關系,然后用盡可能高效的方式將它們組織在一起,最后生成一個獨立的 JS 文件。似乎看起來并沒有什么牛逼的技術,像 RequireJS 在多少年前就能實現相似的功能了。
當然,如果是這樣子我就沒必要安利你了,相比 RequireJS 之流它還是有自己的特色的。Webpack 能讀取的不光是原生的 JavaScript 文件,模塊加載器的設計使得它能支持更豐富的格式。
例如,它能分析出你的 JavaScript 模塊需要一個 CSS 文件,甚至能分析出這個 CSS 文件需要的圖片資源。然后,處理過的資源文件只包含最精簡的必須文件。不信?讓我們現在來實戰體驗。
安裝
首先必須要安裝的是 Node.js ,在這里我們假定你已經正確安裝并且配置完畢。那么安裝 Webpack 所需要做的事,就只剩下輸入下面的這條命令:
npm install webpack -g
這條命令將全局安裝 Webpack,并能在系統的任何路徑下執行 webpack 命令。下面我們新建一個文件夾,在里面新建一個基本的 HTML 文件,名為 index.html ,內容如下:
<!doctype html> <html> <head> <meta charset="utf-8"> <title>Webpack fun</title> </head> <body> <h2></h2> <script src="bundle.js"></script> </body> </html>
需要注意的是,這里定義的 bundle.js 暫時還不存在,稍后將由 Webpack 幫我們創建。另外,那個空的 H2 標簽稍后我們將會使用到。
接下來,在上面文件夾里創建兩個 JS 文件,分別叫做: main.js 、 say-hello.js 。 main.js 你可以理解為 main 方法,也就是我們代碼主要的執行入口。 say-hello.js 是一個簡單的模塊,它接收一個人名和 DOM 元素,然后在這個 DOM 元素上顯示一條包含人名的歡迎信息。
// say-hello.js module.exports = function (name, element) { element.textContent = 'Hello ' + name + '!'; };
定義完 say-hello.js 這個模塊后,我們在 main.js 里引用它,引用方法十分簡單,只需要下面這兩行代碼:
// main.js var sayHello = require('./say-hello'); sayHello('Guybrush', document.querySelector('h2'));
如果現在我們打開前面創建的那個 HTML 文件,你們發現頁面上沒有顯示任何內容。因為我們既沒有引用 main.js ,也沒有將其處理成瀏覽器可執行的代碼。接下來,我們使用 Webpack 讀取 main.js 。如果能成功分析它的依賴,將會創建一個名為 bundle.js 的文件,并能在瀏覽器中執行。
回到命令行里執行 Webpack,只需簡單輸入如下命令:
webpack main.js bundle.js
第一個參數定義了 Webpack 分析依賴的起始文件。首先,它查看起始文件里是否定義了相關的依賴。如果有,它將讀入依賴的文件,看看這個文件是否也有其他的依賴。通過這種方式,遞歸讀取完整個程式依賴的全部文件。一旦閱讀完畢,它將整個依賴打包為一個文件,名為 bundle.js 。
在這個例子里,當你按下回車后,你會看到類似下面的輸出:
Hash: 3d7d7339a68244b03c68 Version: webpack 1.12.12 Time: 55ms Asset Size Chunks Chunk Names bundle.js 1.65 kB 0 [emitted] main [0] ./main.js 90 bytes {0} [built] [1] ./say-hello.js 94 bytes {0} [built]
現在,打開 index.html ,瀏覽器將會顯示 Hello Guybrush!
配置
如果每次運行 Webpack 都要指定輸入和輸出文件的話就太讓人討厭了。當然,開發者早就替我們想好了。其實和 Gulp 、 Grunt 類似,Webpack 需要在我們的項目根目錄下創建一個名為 webpack.config.js 的文件,就可以簡化大量重復的命令參數。
在本例中,內容如下:
module.exports = { entry: './main.js', output: { filename: 'bundle.js' } };
現在,我們只需要輸入 webpack 這個命令,就能實現和之前一樣的操作。
開發服務器
首先提個問題:每次你做了一些改動,如果都要手動去執行 webpack 命令來看結果的話,是不是特傻逼?要知道, Gulp 在很早之前就支持定義 watch 這種監視文件修改的任務了。所以,Webpack也不例外,甚至它還更進一步,提供了一個基于Node.js Express框架的開發服務器。
npm install webpack-dev-server -g
首先運行上面的命令安裝開發服務器,然后運行命令 webpack-dev-server 。這個命令將會啟動一個簡單的 Web 服務器,以命令執行的路徑為靜態資源根目錄。下面我們打開瀏覽器,輸入 http://localhost:8080/webpack-dev-server/ 。如果一切正常,你將看到類似下面的內容:
現在,我們不僅有了一個超贊的輕量級 Web 服務器,我們還有了一個孜孜不倦地監聽代碼變更的觀察者。如果 Webpack 發現我們修改了一個文件,它會自動運行 webpack 命令打包我們的代碼并刷新頁面。
假想一下,我們可以雙屏寫代碼,一個屏幕放瀏覽器,一個屏幕開編輯器。瀏覽器實時刷新結果,無需我們做任何配置和操作,是不是很酷?
現在你可以自己感受一下:修改 main.js 里面傳給 sayHello 方法的姓名參數,然后保存文件,看看瀏覽器里面的實時變化。
加載器(Loaders)
對于 Webpack 而言,最重要的特性就是 加載器 。加載器和 Gulp Grunt 上的“任務”(tasks)類似。基本上都是讀取文件,然后通過某種方式處理文件,最后打包為我們所需的代碼。
本文中,我們想在代碼中用一些 ES2015 的語法。因為 ES2015 是當前最新的 JavaScript 版本,所以并沒有被所有的瀏覽器支持。可是淫家就想寫最新的代碼裝逼怎么辦?那只好先寫,寫完后將 ES2016 版本的代碼轉換為老的 ES5 代碼。
為了實現這個需求,我們需要使用當下最流行的 Babel Loader 來進行轉換。根據官網的教程,我們使用下面的命令進行安裝:
npm install babel-loader babel-core babel-preset-es2015 --save-dev
這條命令不僅安裝了 Babel 加載器,還包含了它支持 ES2015 時所需要的依賴。
安裝完加載器,我們需要告訴 Webpack 使用什么加載器,參考下面的實例更新 webpack.config.js 文件:
module.exports = { entry: './main.js', output: { filename: 'bundle.js' }, module: { loaders: [ { test: /\.js$/, exclude: /node_modules/, loader: 'babel', query: { presets: ['es2015'] } } ], } };
在這個配置示例里,我們需要注意幾個地方。首先, test: /\.js$/ 這行是一個正則表達式,表示文件名滿足此正則表達式的文件將會被此加載器處理。這里,我們的定義是全部的JS文件。類似的, exclude: /node_modules/ 則是告訴 Webpack 忽略 node_modules 文件夾。 loader 和 query 我覺得十分好理解,就是使用Babel loader加載器處理ES2015語法的文件。
重啟開發服務器,在命令行里按下 ctrl+c ,重新輸入 webpack-dev-server 。現在我們來測試一下 ES6 的代碼是否能被正確翻譯呢?不如試試看將 sayHello 變量定義為一個常量。
const sayHello = require('./say-hello')
保存后,Webpack應該自動重新編譯我們的代碼并刷新瀏覽器,你會發現代碼正常執行,什么都沒有變。我們用編輯器打開 bundle.js 文件,你會發現沒有 const 這個單詞。
Webpack就是這么叼!
第二部分預告
在這篇教程的第二部分,我們將學習使用 Webpack 加載 CSS 和 圖片文件,同時讓你的網站為部署做好準備。