30分鐘手把手教你學webpack實戰

龍恩0707發表於2015-09-08

30分鐘手把手教你學webpack實戰

閱讀目錄

什麼是webpack? 他有什麼優點?

    首先對於很多剛接觸webpack人來說,肯定會問webpack是什麼?它有什麼優點?我們為什麼要使用它?帶著這些問題,我們來總結下如下:

    Webpack是前端一個工具,可以讓各個模組進行載入,預處理,再進行打包,它能有Grunt或Gulp所有基本功能。優點如下:

  1. 支援commonJS和AMD模組。
  2. 支援很多模組載入器的呼叫,可以使模組載入器靈活定製,比如babel-loader載入器,該載入器能使我們使用ES6的語法來編寫程式碼。
  3. 可以通過配置打包成多個檔案,有效的利用瀏覽器的快取功能提升效能。
  4. 使用模組載入器,可以支援sass,less等處理器進行打包且支援靜態資源樣式及圖片進行打包。
  5. 更多等等。。。帶著這些問題我們慢慢來學習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入門學習一中的程式碼複製過來的 為了演示;

安裝步驟如下:

  1. 生成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的幾個命令

  1. webpack         // 最基本的啟動webpack的方法
  2. webpack -w      // 提供watch方法;實時進行打包更新
  3. webpack -p      // 對打包後的檔案進行壓縮
  4. 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

 待續..... 由於篇幅有限~~  這個留給下篇文章講解。

相關文章