30分鐘手把手教你學webpack實戰
閱讀目錄
- 一:什麼是webpack? 他有什麼優點?
- 二:如何安裝和配置
- 三:理解webpack載入器
- 四:理解less-loader載入器的使用
- 五:理解babel-loader載入器的含義
- 六:瞭解下webpack的幾個命令
- 七:webpack對多個模組依賴進行打包
- 八:如何獨立打包成樣式檔案
- 九:如何打包成多個資原始檔
- 十:關於對圖片的打包
- 十一:React開發神器:react-hot-loader
什麼是webpack? 他有什麼優點?
首先對於很多剛接觸webpack人來說,肯定會問webpack是什麼?它有什麼優點?我們為什麼要使用它?帶著這些問題,我們來總結下如下:
Webpack是前端一個工具,可以讓各個模組進行載入,預處理,再進行打包,它能有Grunt或Gulp所有基本功能。優點如下:
- 支援commonJS和AMD模組。
- 支援很多模組載入器的呼叫,可以使模組載入器靈活定製,比如babel-loader載入器,該載入器能使我們使用ES6的語法來編寫程式碼。
- 可以通過配置打包成多個檔案,有效的利用瀏覽器的快取功能提升效能。
- 使用模組載入器,可以支援sass,less等處理器進行打包且支援靜態資源樣式及圖片進行打包。
- 更多等等。。。帶著這些問題我們慢慢來學習webpack。
二:如何安裝和配置
首先我的專案目錄結構是:檔名叫webpack,裡面只有一個main.html,程式碼如下:
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="src/react.min.js"></script> </head> <body> <div id="content"></div> <script src="build/build.js"></script> </body> </html>
還有一個資料夾src,該資料夾存放了二個js檔案;react.min.js原始檔和main.js檔案,main.js原始碼如下:
/* 內容區模組程式碼 */ var ContentMode = React.createClass({ render: function(){ return ( <div className="ContentMode"> <div class="contents">{this.props.contents}</div> {this.props.children} </div> ) } }); /* 頁面div封裝 上面三個模組 */ var Page = React.createClass({ render: function(){ return ( <div className="homepage"> <ContentMode contents ="longen">this is one comment</ContentMode > <ContentMode contents ="longen2">this is two comment</ContentMode > </div> ) } }); /* 初始化到content容器內 */ React.render( React.createElement(Page,null),document.getElementById("content") );
該程式碼是React.js程式碼,是react.js入門學習一中的程式碼複製過來的 為了演示;
安裝步驟如下:
- 生成package.json檔案;
首先我們需要在根目錄下生成package.json檔案,需要進入專案檔案內根目錄下執行如下命令:npm init
如上通過一問一答的方式後會在根目錄下生成package.json檔案,如下所示:
2 . 通過全域性安裝webpack
執行命令如下:npm install -g webpack 如下所示:
在c盤下會生成node_modules資料夾中會包含webpack,此時此刻我們可以使用webpack命令了;
3. 配置webpack
每個目錄下都必須有一個webpack.config.js,它的作用就好比Gulpfile.js、或者 Gruntfile.js,就是一個專案配置,告訴webpack需要做什麼。
如下是我的webpack.config.js程式碼如下:
module.exports = { entry: "./src/main.js", output: { filename: "build/build.js" }, module: { loaders: [ //.css 檔案使用 style-loader 和 css-loader 來處理 { test: /\.css$/, loader: "style!css" }, //.js 檔案使用 jsx-loader 來編譯處理 { test: /\.js$/, loader: "jsx-loader" } ] }, resolve: { extensions: ['', '.js', '.jsx'] }, plugins: [] };
entry 是頁面中的入口檔案,比如我這邊的入口檔案時main.js
output: 是指頁面通過webpack打包後生成的目標檔案放在什麼地方去,我這邊是在根目錄下生成build資料夾,該資料夾內有一個build.js檔案;
resolve: 定義瞭解析模組路徑時的配置,常用的就是extensions; 可以用來指定模組的字尾,這樣在引入模組時就不需要寫字尾,會自動補全。
plugins: 定義了需要使用的外掛,比如commonsPlugin在打包多個入口檔案時會提取公用的部分,生成common.js;
module.loaders:是檔案的載入器,比如我們之前react需要在頁面中引入jsx的js原始碼到頁面上來,然後使用該語法,但是通過webpack打包後就不需要再引入JSXTransformer.js;看到上面的載入器;比如jsx-loader載入器就是代表JSXTransformer.js的,還有style-loader和css-loader載入器;因此在使用之前我們需要通過命令把它引入到專案上來;因此需要如下命令生成下;
jsx-loader載入器 npm install jsx-loader --save-dev 如下:
Style-loader載入器 npm install style-loader --save-dev 如下:
css-loader 載入器 npm install css-loader --save-dev 如下:
區域性安裝webpack 執行命令:npm install webpack --save-dev
我們這邊乾脆把gulp的全域性安裝和在專案中區域性安裝也安裝下,稍後有用~
Gulp全域性安裝 npm install -g gulp 如下:
在專案檔案內,gulp區域性安裝 使用命令 npm install gulp --save-dev 如下所示:
因此在我們資料夾node_modules下生成檔案如下:
現在我們來執行命令 webpack; 如下所示:
即可在根目錄下生成一個build資料夾中build.js 如下所示:
我們還可以使用如下命令:webpack --display-error-details 命令執行,這樣的話方便出錯的時候可以檢視更詳盡的資訊;比如如下:
現在我們再來重新整理下頁面;看到如下:
可以看到頁面渲染出來了,我們接著來看看頁面中的請求:
可以看到只有一個檔案react.min.js的原始檔和build.js 我們剛剛生成的build.js檔案了,因此我們通過webpack進行打包後,我們現在就不再需要和以前一樣引入JSXTransformer.js了。我們還可以看看build.js內生成了那些js,這裡就不貼程式碼了,自己可以看看了~
上面是使用webpack打包;現在我們再來看看使用第二種方案來打包~
使用gulp來進行打包
我們知道使用gulp來打包的話,那麼我們需要在根目錄下需要新建 Gulpfile.js;
因此我們這邊Gulpfile.js的原始碼如下:
var gulp = require('gulp'); var webpack = require("gulp-webpack"); var webpackConfig = require("./webpack.config.js"); gulp.task('webpack', function () { var myConfig = Object.create(webpackConfig); return gulp .src('./src/main.js') .pipe(webpack(myConfig)) .pipe(gulp.dest('./build')); }); // 註冊預設任務 gulp.task('default', ['webpack']);
然後webpack.config.js程式碼變為如下:
module.exports = { entry: "./src/main.js", output: { filename: "build.js" }, module: { loaders: [ //.css 檔案使用 style-loader 和 css-loader 來處理 { test: /\.css$/, loader: "style!css" }, //.js 檔案使用 jsx-loader 來編譯處理 { test: /\.js$/, loader: "jsx-loader" } ] }, resolve: { extensions: ['', '.js', '.jsx'] }, plugins: [] };
即可,然後再在命令列中輸入gulp即可生成build/build.js了;如下所示:
Github上的程式碼如下: https://github.com/tugenhua0707/webpack/ 自己可以把壓縮包下載下來執行下即可。
三:理解webpack載入器
Webpack提供了一套載入器,比如css-loader,less-loader,style-loader,url-loader等,用於將不同的檔案載入到js檔案中,比如url-loader用於在js中載入png/jpg格式的圖片檔案,css/style loader用於載入css檔案,less-loader載入器是將less編譯成css檔案;
配置載入器
module.exports = { entry: "./src/main.js", output: { filename: "build.js", path: __dirname + '/assets/', publicPath: "/assets/" }, module: { loaders: [ {test: /.css$/, loader: 'style!css'}, {test: /.(png|jpg)$/, loader: 'url-loader?limit=8192'} ] } resolve: { extensions: ['', '.js', '.jsx'], //模組別名定義,方便後續直接引用別名,無須多寫長長的地址 alias: { a : 'js/assets/a.js', // 後面直接引用 require(“a”)即可引用到模組 b : 'js/assets/b.js', c : 'js/assets/c.js' } }, plugins: [commonsPlugin, new ExtractTextPlugin("[name].css")] }
module.loader: 其中test是正規表示式,對符合的檔名使用相應的載入器.
/.css$/會匹配 xx.css檔案,但是並不適用於xx.sass或者xx.css.zip檔案.
url-loader 它會將樣式中引用到的圖片轉為模組來處理; 配置資訊的引數“?limit=8192”表示將所有小於8kb的圖片都轉為base64形式。
entry 模組的入口檔案。依賴項陣列中所有的檔案會按順序打包,每個檔案進行依賴的遞迴查詢,直到所有模組都被打成包;
output:模組的輸出檔案,其中有如下引數:
filename: 打包後的檔名
path: 打包檔案存放的絕對路徑。
publicPath: 網站執行時的訪問路徑。
relolve.extensions: 自動擴充套件檔案的字尾名,比如我們在require模組的時候,可以不用寫字尾名的。
relolve.alias: 模組別名定義,方便後續直接引用別名,無須多寫長長的地址
plugins 是外掛項;
四:理解less-loader載入器的使用
我們先來理解下less-loader載入器,其他的sass-loader也是一個意思,這邊不會對所有的預處理的css做講解,less-loader載入器是把css程式碼轉化到style標籤內,動態插入到head標籤內;我們先來看看我專案的結構如下:
我們現在css檔案下有一個main.less 程式碼如下:
@base: #f938ab;
html,body {
background:@base;
}
Src檔案下有一個main.js檔案 此js檔案時入口檔案;裡面的程式碼如下:
// css
require('../css/main.less');
webpack.config.js 程式碼配置如下:
module.exports = { entry: "./src/main.js", output: { filename: "build.js", path: __dirname }, module: { loaders: [ //.css 檔案使用 style-loader 和 css-loader 來處理 { test: /\.less$/, loader: "style!css!less" } ] }, resolve: { extensions: ['', '.js', '.jsx'] }, plugins: [] };
Gulpfile.js程式碼如下(注意:這邊既可以需要此檔案使用gulp進行執行打包,也可以不需要此檔案,直接使用webpack進行打包;二種方式任選其一)。
var gulp = require('gulp'); var webpack = require("gulp-webpack"); var webpackConfig = require("./webpack.config.js"); gulp.task('webpack', function () { var myConfig = Object.create(webpackConfig); return gulp .src('./src/main.js') .pipe(webpack(myConfig)) .pipe(gulp.dest('./build')); }); // 註冊預設任務 gulp.task('default', ['webpack']);
因此我們需要安裝 style-loader css-loader 和 less-loader 如下所示:
安裝完成後,我們檢視我們的專案的根目錄node_modules下多瞭如下幾個檔案:
如上配置後,我們進入專案後 執行下 gulp或者 webpack命令既可,在build資料夾內會生成build.js,此JS是動態生成style標籤並解釋正常的css插入到文件head標籤內;我們可以執行下頁面,檢視程式碼看下如下:
因此我們可以看到頁面生效了;為了更好的demo測試,我把程式碼放到如下github上,自己可以下載下來執行下既可: https://github.com/tugenhua0707/webpack-less-loader
五:理解babel-loader載入器的含義
babel-loader載入器能將ES6的程式碼轉換成ES5程式碼,這使我們現在可以使用ES6了;我們在使用之前,我們需要安裝babel-loader
執行命令:npm install babel-loader –save-dev 如下所示:
如上安裝完後,我們在根目錄node_modules會生成檔案,如下所示:
現在我們可以在webpack.config.js裡面moudle.loaders配置載入器了,如下程式碼:
{test: /\.js$/, loader: 'babel', exclude: '/node_modules/'}
因此webpack.config.js程式碼變成如下:
// 使用webpack打包 module.exports = { entry: "./src/main.js", output: { filename: "build.js", path: __dirname }, module: { loaders: [ {test: /\.js$/, loader: 'babel', exclude: '/node_modules/'} ] }, resolve: { extensions: ['', '.js', '.jsx'] }, plugins: [] };
下面我們再來看看我專案中的目錄結構如下:
我們在看看src原始檔有下面幾個檔案
React.min.js是react原始碼,這個不多說,bind.js的ES6的程式碼如下:
// es6的語法 let LOADER = true; module.exports = LOADER;
main.js 是頁面的入口檔案;程式碼如下:
let loader = require('./bind');
console.log(loader);
let是ES6的語法 相當於js中的var定義變數的含義; 接著列印下bind模組中 列印為true;
最後執行gulp如下:
在控制檯中列印true;我把原始碼放在github上,有需要的同學可以自己下載下來執行下即可;如下github(我2年沒有使用github,現在重新使用,為了更好的演示demo問題); https://github.com/tugenhua0707/webpack-babel-loader
六:瞭解下webpack的幾個命令
- webpack // 最基本的啟動webpack的方法
- webpack -w // 提供watch方法;實時進行打包更新
- webpack -p // 對打包後的檔案進行壓縮
- webpack -d // 提供source map,方便調式程式碼
我們下面來了解下 webpack -w
如下所示:
比如我在js檔案裡面隨便增加一點程式碼後,儲存後,再重新整理頁面即可可以看到程式碼生效了,無需重新執行webpack或者gulp,使用webpack -w 可以實時打包。 webpack -p 的含義是對進行打包後的檔案進行壓縮程式碼;比如我在之前使用chrome看打包後的程式碼如下:
如上可以看到,程式碼是未壓縮的,但是當我在控制檯命令列中執行 webpack -p 命令後,如下所示:
我們現在再到控制檯上看下程式碼變成已經壓縮後的程式碼了,如下所示:
webpack -d 是提供未壓縮之前的原始碼 方便程式碼中的調式;如下所示:
當我執行如上所示後,我們再來看看剛才已經壓縮後的程式碼變成什麼樣子呢?如下所示:
如上程式碼可以看到 我們進行壓縮後的程式碼,通過執行 webpack -d 命令後,即可還原未壓縮的程式碼,這樣的話就可以方便我們線上調式程式碼了。
我們再來看看目錄下 會生成map檔案,如下所示:
七:webpack對多個模組依賴進行打包
通過一剛開始我們瞭解到 webpack支援commonJS和AMD兩種模組機制進行打包,因此我們現在來針對程式碼中使用commonJS和AMD機制進行做一個demo;
Src原始檔增加module1.js module2.js module3.js 程式碼分別如下:
module1.js 程式碼: // module1.js require(["./module3"], function(){ console.log("Hello Webpack!"); }); Module2.js程式碼如下: // module2.js,使用的是CommonJs機制匯出包 module.exports = function(a, b){ return a + b; } Module3.js程式碼使用AMD機制 // module3.js,使用AMD模組機制 define(['./module2.js'], function(sum){ return console.log("1 + 2 = " + sum(1, 2)); }); // 入口檔案 main.js 程式碼如下: require("./module1");
我們可以執行下 webpack後 在根目錄下生成如下檔案:
其中1.build資料夾是commonJS生成的 裡面是commonJS的程式碼;我們再檢視頁面的程式碼如下可以看到:
我們繼續檢視控制檯輸出如下:
為止我們可以看到webpack打包可以支援commonJS模組和AMD模組。
具體的程式碼 可以檢視我的github上的原始碼:
https://github.com/tugenhua0707/webpack-multi-module-depend
八:如何獨立打包成樣式檔案
有時候我們不想把樣式打在指令碼中,而是想獨立css出來,然後在頁面上外鏈css,這時候我們需要 extract-text-webpack-plugin 來幫忙:我們首先需要安裝 extract-text-webpack-plugin:如下: npm install extract-text-webpack-plugin –save-dev 如下所示:
然後在目錄下會生成如下:
現在我們需要看看webpack.config.js 配置變成如下:
var ExtractTextPlugin = require("extract-text-webpack-plugin"); // 使用webpack打包 module.exports = { entry: "./src/main.js", output: { filename: "build.js" }, module: { loaders: [ //.css 檔案使用 style-loader 和 css-loader 來處理 { test: /\.less$/, loader: ExtractTextPlugin.extract( 'css?sourceMap!' + 'less?sourceMap' ) } ] }, resolve: { extensions: ['', '.js', '.jsx'] }, // 內聯css提取到單獨的styles的css plugins: [new ExtractTextPlugin('styles.css')] };
配置完成後 我們gulp執行下即可,在build資料夾內會生成2個檔案,一個是build.js 處理模組的檔案 另一個就是我們的styles.css了;我們檢視下如下所示:
接著在html檔案這樣引入即可:
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="src/react.min.js"></script> <link rel="stylesheet" href="build/styles.css"/> </head> <body> <div id="content"></div> </body> </html>
在頁面上執行以下;即可看到效果:我們可以看下請求數:
具體的程式碼demo可以看我的github 如下:
https://github.com/tugenhua0707/extract-text-webpack-plugin
注意:node_modules模組沒有上傳上去,git上傳不上去,老是提示Filename too long的錯誤,所以就沒有上傳,需要自己在本地安裝如下模組:
九:如何打包成多個資原始檔
我們在開發頁面的時候,有時候需要有多個入口檔案,做到檔案是按需載入,這樣就可以使用快取提升效能;那麼我們接下來需要如何配置呢?現在我們繼續做demo,現在比如我現在的專案檔案結構如下:
我們直接看 webpack.config.js配置程式碼變成如下:
module.exports = { entry: { "main": "./src/main.js", "index": "./src/index.js" }, output: { filename: "[name].bundle.js" } };
從上面的配置程式碼我們可以看到 entry現在變成了一個物件了,而物件名也就是key會作為下面output的filename屬性的[name]。當然entry也可以是一個陣列。
因此我們直接 gulp執行下即可 在build檔案下 生成2個入口檔案 如上面的截圖所示:github原始碼地址如下:
https://github.com/tugenhua0707/webpack-many-page
現在我們可以根據不同的頁面 引入不同的入口檔案,實現按需載入檔案。
十:關於對圖片的打包
我們知道圖片是使用url-loader來載入的,我們既可以在css檔案裡url的屬性;如下:
#content{ width:170px; height:60px; background:url('../images/1.jpg') no-repeat; }
我們還可以直接對元素的src屬性進行require賦值。如下程式碼:
var img = document.createElement("img"); img.src = require("../image/1.jpg"); document.body.appendChild(img);
我這邊直接來講第一種在css檔案裡的url屬性進行打包;
首先來看看我專案的目錄結構如下:
Css檔案 main.css程式碼如下:
#content{ width:170px; height:60px; background:url('../images/1.jpg') no-repeat; }
JS檔案main.js程式碼如下:
require('../css/main.css');
Webpack.config.js配置檔案程式碼如下:
// 使用webpack打包 module.exports = { entry: { "main": "./src/main.js" }, output: { path: './build/', filename: "build.js" }, module: { loaders: [ {test: /.css$/, loader: 'style!css'}, {test: /.(png|jpg)$/, loader: 'url?limit=8192'} ] } };
直接執行webpack 可以生成build目錄,build目錄下會生成2個檔案 一個是圖片打包後,另外一個是build.js。接著我們再在頁面執行下頁面,發現有一個問題,如下:
頁面呼叫圖片的url是根目錄下的,不是我打包後的 build資料夾下,所以會導致圖片路徑找不到的問題;因此這邊有一點點沒有完成的任務,希望有興趣的童靴可以幫助完成~ 不過圖片確實是已經打包好了,為了方便,我們還是提供github原始碼吧!如下所示:
https://github.com/tugenhua0707/webpack-url-loader
十一:React開發神器:react-hot-loader
待續..... 由於篇幅有限~~ 這個留給下篇文章講解。