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
待續..... 由於篇幅有限~~ 這個留給下篇文章講解。