Webpack使用指南

Webpack 是當下最熱門的前端資源模塊化管理和打包工具。css

什麼是webpack

Webpack 是當下最熱門的前端資源模塊化管理和打包工具。它能夠將許多鬆散的模塊按照依賴和規則打包成符合生產環境部署的前端資源。還能夠將按需加載的模塊進行代碼分隔,等到實際須要的時候再異步加載。經過 loader 的轉換,任何形式的資源均可以視做模塊,好比 CommonJs 模塊、 AMD 模塊、 ES6 模塊、CSS、圖片、 JSON、Coffeescript、 LESS 等。html

Webpack 的特色

Webpack 和其餘模塊化工具備什麼區別呢?前端

  • 代碼拆分
    Webpack 有兩種組織模塊依賴的方式,同步和異步。異步依賴做爲分割點,造成一個新的塊。在優化了依賴樹後,每個異步區塊都做爲一個文件被打包。
  • Loader
    Webpack 自己只能處理原生的 JavaScript 模塊,可是 loader 轉換器能夠將各類類型的資源轉換成 JavaScript 模塊。這樣,任何資源均可以成爲 Webpack 能夠處理的模塊。
  • 智能解析
    Webpack 有一個智能解析器,幾乎能夠處理任何第三方庫,不管它們的模塊形式是 CommonJS、 AMD 仍是普通的 JS 文件。甚至在加載依賴的時候,容許使用動態表達式 require("./templates/" + name + ".jade")。
  • 插件系統
    Webpack 還有一個功能豐富的插件系統。大多數內容功能都是基於這個插件系統運行的,還能夠開發和使用開源的 Webpack 插件,來知足各式各樣的需求。
  • 快速運行
    Webpack 使用異步 I/O 和多級緩存提升運行效率,這使得 Webpack 可以以使人難以置信的速度快速增量編譯。

開始使用

安裝

首先要安裝 Node.js, Node.js 自帶了軟件包管理器 npm,Webpack能夠經過npm去安裝。node

用 npm 安裝 Webpack:react

$ npm install webpack -g

此時 Webpack 已經安裝到了全局環境下,能夠經過命令行 webpack -h 試試。jquery

一般咱們會將 Webpack 安裝到項目的依賴中,這樣就可使用項目本地版本的 Webpack。webpack

# 進入項目目錄
# 肯定已經有 package.json,沒有就經過 npm init 建立
# 安裝 webpack 依賴
$ npm install webpack --save-dev

查看webpackgit

# 查看 webpack 版本信息
$ npm info webpack

安裝指定版本的 webpackes6

$ npm install webpack@1.12.x --save-dev

若是須要使用 Webpack 開發工具,要單獨安裝:github

$ npm install webpack-dev-server --save-dev

使用

首先建立一個靜態頁面 index.html 和一個 JS 入口文件 entry.js:

<!-- index.html -->
<html>
<head>
  <meta charset="utf-8">
</head>
<body>
  <script src="bundle.js"></script>
</body>
</html>
// entry.js
document.write('It works.')

而後編譯 entry.js 並打包到 bundle.js:

$ webpack entry.js bundle.js

打包過程會顯示日誌:

Hash: e964f90ec65eb2c29bb9
Version: webpack 1.12.2
Time: 54ms
    Asset     Size  Chunks             Chunk Names
bundle.js  1.42 kB       0  [emitted]  main
   [0] ./entry.js 27 bytes {0} [built]

用瀏覽器打開 index.html 將會看到 It works. 。 接下來添加一個模塊 module.js 並修改入口 entry.js:

// module.js
module.exports = 'It works from module.js.'
// entry.js
document.write('It works.')
document.write(require('./module.js')) // 添加模塊

從新打包 webpack entry.js bundle.js 後刷新頁面看到變化

It works.It works from module.js.
Hash: 279c7601d5d08396e751
Version: webpack 1.12.2
Time: 63ms
    Asset     Size  Chunks             Chunk Names
bundle.js  1.57 kB       0  [emitted]  main
   [0] ./entry.js 66 bytes {0} [built]
   [1] ./module.js 43 bytes {0} [built]

Webpack 會分析入口文件,解析包含依賴關係的各個文件。這些文件(模塊)都打包到 bundle.js 。Webpack 會給每一個模塊分配一個惟一的 id 並經過這個 id 索引和訪問模塊。在頁面啓動時,會先執行 entry.js 中的代碼,其它模塊會在運行 require 的時候再執行。

Loader

Webpack 自己只能處理 JavaScript 模塊,若是要處理其餘類型的文件,就須要使用 loader 進行轉換。

Loader 能夠理解爲是模塊和資源的轉換器,它自己是一個函數,接受源文件做爲參數,返回轉換的結果。這樣,咱們就能夠經過 require 來加載任何類型的模塊或文件,好比 CoffeeScript、 JSX、 LESS 或圖片。

先來看看 loader 有哪些特性?

  • Loader 能夠經過管道方式鏈式調用,每一個 loader 能夠把資源轉換成任意格式並傳遞給下一個 loader ,可是最後一個 loader 必須返回 JavaScript。
  • Loader 能夠同步或異步執行。
  • Loader 運行在 node.js 環境中,因此能夠作任何可能的事情。
  • Loader 能夠接受參數,以此來傳遞配置項給 loader。
  • Loader 能夠經過文件擴展名(或正則表達式)綁定給不一樣類型的文件。
  • Loader 能夠經過 npm 發佈和安裝。
  • 除了經過 package.json 的 main 指定,一般的模塊也能夠導出一個 loader 來使用。
  • Loader 能夠訪問配置。
  • 插件可讓 loader 擁有更多特性。
  • Loader 能夠分發出附加的任意文件。

loader 通常以 xxx-loader 的方式命名,xxx 表明了這個 loader 要作的轉換功能,好比 json-loader

Loader 能夠在 require() 引用模塊的時候添加,也能夠在 webpack 全局配置中進行綁定,還能夠經過命令行的方式使用。

接上一節的例子,咱們要在頁面中引入一個 CSS 文件 style.css,首頁將 style.css 也當作是一個模塊,而後用 css-loader 來讀取它,再用 style-loader 把它插入到頁面中。

/* style.css */
body { background: yellow; }

修改 entry.js:

require("!style-loader!css-loader!./style.css") // 載入 style.css
document.write('It works.')
document.write(require('./module.js'))

安裝 loader:

npm install css-loader style-loader

從新編譯打包,刷新頁面,就能夠看到黃色的頁面背景了。

若是每次 require CSS 文件的時候都要寫 loader 前綴,是一件很繁瑣的事情。咱們能夠根據模塊類型(擴展名)來自動綁定須要的 loader。

將 entry.js 中的 require("!style-loader!css-loader!./style.css") 修改成 require("./style.css") ,而後執行:

$ webpack entry.js bundle.js --module-bind 'css=style!css'
# 有些環境下可能須要使用雙引號
$ webpack entry.js bundle.js --module-bind "css=style!css"

顯然,這兩種使用 loader 的方式,效果是同樣的。

配置文件

Webpack 在執行的時候,除了在命令行傳入參數,還能夠經過指定的配置文件來執行。默認狀況下,會搜索當前目錄的 webpack.config.js 文件,這個文件是一個 node.js 模塊,返回一個 json 格式的配置信息對象,或者經過 --config 選項來指定配置文件。

示例

建立一個配置文件 webpack.config.js:

var webpack = require('webpack')

module.exports = {
  entry: './entry.js',
  output: {
    path: __dirname,
    filename: 'bundle.js'
  },
  module: {
    loaders: [
     {test: /\.css$/,loader: 'style-loader!css-loader'}]
  }
}

webpack.config.js參數詳解

webpack.config.js文件一般放在項目的根目錄中,它自己也是一個標準的Commonjs規範的模塊。在導出的配置對象中有幾個關鍵的參數:

entry

entry參數定義了打包後的入口文件,有三種寫法,每一個入口稱爲一個chunk:

類型 示例 解釋
字符串 entry: "./index/index.js" 配置模塊會被解析爲模塊,並在啓動時加載。
chunk名爲默認爲main, 具體打包文件名視output配置而定。 
數組 entry: ['./src/mod1.js', [...,] './src/index.js'] 全部的模塊會在啓動時 按照配置順序 
加載,合併到最後一個模塊會被導出。chunk名默認爲main
對象 entry:{index: '...', login : [...]} 若是傳入Object,則會生成多個入口打包文件
keychunk名,value能夠是字符串,也但是數組。
{
    entry: {
        page1: "./page1",

        //支持數組形式,將加載數組中的全部模塊,但以最後一個模塊做爲輸出
        page2: ["./entry1", "./entry2"]
    },
    output: {
        path: "dist/js/page",
        publicPath: "/output/",
        filename: "[name].bundle.js"
    }
}

該段代碼最終會生成一個 page1.bundle.js 和 page2.bundle.js,並存放到 ./dist/js/page 文件夾下

output

output參數是個對象,定義了輸出文件的位置及名字:

output: {
        path: "dist/js/page",
        publicPath: "/output/",
        filename: "[name].bundle.js"
    }
  • path: 打包文件存放的絕對路徑
  • publicPath: 網站運行時的訪問路徑
  • filename:打包後的文件名

當咱們在entry中定義構建多個文件時,filename能夠對應的更改成[name].js用於定義不一樣文件構建後的名字。

module

在webpack中JavaScript,CSS,LESS,TypeScript,JSX,CoffeeScript,圖片等靜態文件都是模塊,不一樣模塊的加載是經過模塊加載器(webpack-loader)來統一管理的。loaders之間是能夠串聯的,一個加載器的輸出能夠做爲下一個加載器的輸入,最終返回到JavaScript上: loader使用須要先安裝再加入到配置下中。

Loaders須要單獨安裝而且須要在webpack.config.js下的modules關鍵字下進行配置,Loaders的配置選項包括如下幾方面:

  • test:一個匹配loaders所處理的文件的拓展名的正則表達式(必須)
  • loader:loader的名稱(必須)
  • include/exclude:手動添加必須處理的文件(文件夾)或屏蔽不須要處理的文件(文件夾)(可選);
  • query:爲loaders提供額外的設置選項(可選)
loaders之 預處理
  • css-loader 處理css中路徑引用等問題
  • style-loader 動態把樣式寫入css
  • sass-loader scss編譯器
  • less-loader less編譯器
  • postcss-loader scss再處理

module: {
        //加載器配置
        loaders: [
            //.css 文件使用 style-loader 和 css-loader 來處理
            { test: /\.css$/, loader: 'style-loader!css-loader' },
            //.less 文件使用 less-loader、cssloader來編譯
            { test:/\.less$/, loader: 'style!less'}
            //.scss 文件使用 style-loader、css-loader 和 sass-loader 來編譯處理
            { test: /\.scss$/, loader: 'style!css!sass?sourceMap'},

        ]
    }
loaders之 react處理

babel-loader babel官網

// npm一次性安裝多個依賴模塊,模塊之間用空格隔開
npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react
module: {
  loaders: [
    {
    	test:/\.jsx?$/,
    	exclude:/node_modules/,
    	loader:'babel',
    	query:{presets:['react','es2015']}
    }
  ]
}
loaders之 es6轉化處理
  • babel-loader 以及 babel-preset-es2015
  • 安裝 以上兩個插件
    npm install babel-loader --save-dev
     npm install babel-preset-es2015 --save-dev
  • 建立bable的配置文件
{
  "presets": ["es2015"]
}
loaders之 圖片處理
  • url-loader
npm install --save-dev url-loadr
module: {
  loaders: [
    {
      test: /\.(png|jpg|gif)$/,
      loader: 'url-loader?limit=10000&name=build/images/[name].[ext]'
    }
  ]
}

對於上面的配置,若是圖片資源小於10kb就會轉化成 base64 格式的 dataUrl,其餘的圖片會存放在build/images文件夾下。

loaders之 文件處理
  • file-loader

npm install --save-dev file-loader
module: {
  loaders: [
    {
      test: /\.(png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot)$/,
      loader: 'file'
      },
  ]
}

示例

module: {
        //加載器配置
        loaders: [
            //.css 文件使用 style-loader 和 css-loader 來處理
            { test: /\.css$/, loader: 'style-loader!css-loader' },


            //.scss 文件使用 style-loader、css-loader 和 sass-loader 來編譯處理
            { test: /\.scss$/, loader: 'style!css!sass?sourceMap'},

            //圖片文件使用 url-loader 來處理,小於8kb的直接轉爲base64
            { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192'}
        ]
    }

插件(Plugins)

插件(Plugins)是用來拓展Webpack功能的,它們會在整個構建過程當中生效,執行相關的任務。

Webpack有不少內置插件,同時也有不少第三方插件,可讓咱們完成更加豐富的功能。

使用插件的方法

要使用某個插件,咱們須要經過npm安裝它,而後要作的就是在webpack配置中的plugins關鍵字部分添加該插件的一個實例(plugins是一個數組)繼續看例子,咱們添加了一個實現版權聲明的插件。

module.exports = {
  plugins: [
    new webpack.BannerPlugin("Copyright Nico inc.")
    //在這個數組中new一個就能夠了
  ]
}

HtmlWebpackPlugin

這個插件的做用是依據一個簡單的模板,幫你生成最終的HTML5文件,這個文件中自動引用了你打包後的JS文件。每次編譯都在文件名中插入一個不一樣的哈希值。

安裝

npm install --save-dev html-webpack-plugin

這個插件自動完成了咱們以前手動作的一些事情,在正式使用以前須要對一直以來的項目結構作一些改變:

在app目錄下,建立一個Html文件模板,這個模板包含title等其它你須要的元素,在編譯過程當中,本插件會依據此模板生成最終的html頁面,會自動添加所依賴的 css, js,favicon等文件,在本例中咱們命名模板文件名稱爲index.tmpl.html,模板源代碼以下

index.tmpl.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Webpack</title>
  </head>
  <body>
    <div id='box'>
    </div>
  </body>
</html>

webpack.config.js

var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
	plugins: [
    new HtmlWebpackPlugin({
      template: __dirname + "/app/index.tmpl.html"//new 一個這個插件的實例,並傳入相關的參數
    })
  ]
}

ExtractTextPlugin

分離CSS和JS文件

安裝

npm install --save-dev extract-text-webpack-plugin

webpack.config.js

var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
	...
  plugins: [
    new HtmlWebpackPlugin({
      template: __dirname + "/app/index.tmpl.html"
    }),
    new webpack.optimize.OccurenceOrderPlugin(),
    new webpack.optimize.UglifyJsPlugin(),
    new ExtractTextPlugin("style.css")
  ]
}

合併公共代碼

項目中,對於一些經常使用的組件,站點公用模塊常常須要與其餘邏輯分開,而後合併到同一個文件,以便於長時間的緩存。要實現這一功能,配置參照:

var webpack = require('webpack');
var CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin;
 
···
entry: {
   a: './index/a.js',
   b: './idnex/b.js',
   c: './index/c.js',
   d: './index/d.js'
},
···
plugins: [
   new CommonsChunkPlugin('part.js', ['a', 'b']),
   new CommonsChunkPlugin('common.js', ['part1', 'c'])
]
···

代碼壓縮

webpack 自帶了一個壓縮插件 UglifyJsPlugin,只須要在配置文件中引入便可。

{
  plugins: [
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      }
    })
  ]
}

加入了這個插件以後,編譯的速度會明顯變慢,因此通常只在生產環境啓用。

其餘用法

緩存

緩存無處不在,使用緩存的最好方法是保證你的文件名和文件內容是匹配的(內容改變,名稱相應改變) webpack能夠把一個哈希值添加到打包的文件名中,使用方法以下,添加特殊的字符串混合體([name], [id] and [hash])到輸出文件名前

var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
  entry: __dirname + "/app/main.js",
  output: {
    path: __dirname + "/build",
    filename: "[name]-[hash].js"
  },
  module: {},
  plugins: [
    new HtmlWebpackPlugin({
      template: __dirname + "/app/index.tmpl.html"
    }),
    new webpack.optimize.OccurenceOrderPlugin(),
    new webpack.optimize.UglifyJsPlugin(),
    new ExtractTextPlugin("[name]-[hash].css")
  ]
}

去除多個文件中的頻繁依賴

當咱們常用React、jQuery等外部第三方庫的時候,一般在每一個業務邏輯JS中都會遇到這些庫。
 如咱們須要在各個文件中都是有jQuery的$對象,所以咱們須要在每一個用到jQuery的JS文件的頭部經過require('jquery')來依賴jQuery。 這樣作很是繁瑣且重複,所以webpack提供了咱們一種比較高效的方法,咱們能夠經過在配置文件中配置使用到的變量名,那麼webpack會自動分析,而且在編譯時幫咱們完成這些依賴的引入。

webpack.config.js中

var webpack = require('webpack');
 
...
plugins: [
   new webpack.ProvidePlugin({
       'Moment': 'moment',
       "$": "jquery",
       "jQuery": "jquery",
       "window.jQuery": "jquery",
       "React": "react"
   })
]
...

設置環境命令

要告訴webpack咱們但願當前是什麼環境,只須要在命令中寫入 BUILD_DEV=1 webpck 那麼webpack經過配置,就會將全部咱們引用到的__DEV__變量設置爲true。

咱們能夠在package.json中事先定義好命令:

"scripts": {
    "dev": "BUILD_DEV=1 webpack-dev-server --progress --colors",
    "build": "BUILD_PRERELEASE=1 webpack -p"
}

那麼就能夠避免輸入冗長的命令了:

開發時輸入:

npm run dev

發佈時輸入:

npm run build

經常使用命令


webpack的使用和browserify有些相似,下面列舉幾個經常使用命令:

webpack 最基本的啓動webpack命令
webpack -w 提供watch方法,實時進行打包更新
webpack -p 對打包後的文件進行壓縮
webpack -d 提供SourceMaps,方便調試
webpack --colors 輸出結果帶彩色,好比:會用紅色顯示耗時較長的步驟
webpack --profile 輸出性能數據,能夠看到每一步的耗時
webpack --display-modules 默認狀況下 node_modules 下的模塊會被隱藏,加上這個參數能夠顯示這些被隱藏的模塊

目錄結構

/
 ├── shell/ 腳本
 │
 ├── conf/ 工程配置
 │
 ├── src/ 開發目錄
 │      ├── components/ 組件
 │      ├── pages/ 頁面
 │      ├──
 ├── dist/ 自動生成
 │
 ├── test/ 測試
 │
 ├── node_modules/ 自動生成,包含.Node 依賴以及開發依賴
 │
 ├── static/ 庫文件等,不會被webpack的loader處理,手動管理
 │
 └── etc

完整的目錄結構:

projectTemplate/  
    ├── shell/    node腳本    
    │    ├──
    │    ├── dev-server.js  本地開發服務器
    │    ├── build.js  打包腳本
    │    ├── utils.js  工具函數
    │    ├──        
    ├── conf/     工程配置  
    │    ├──
    │    ├── index.js  基礎配置文件,在此可簡單的修改webpack相關配置
    │    ├── webpack.base.js  webpack的基礎配置,主要是loader、resolve的配置
    │    ├── webpack.dev.js  webpack開發配置,主要是eslint、livereload、hot module replacement及相關的插件
    │    ├── webpack.prod.js  webpack生產配置,主要是代碼的壓縮混淆,圖片壓縮,加hash
    │    ├── karma.conf.js  測試配置
    │    ├──
    ├── src/   開發目錄
    │     ├── components/   組件
    │     ├── pages/        頁面(頁面下的項目目錄須要遵循必定的規範以便建立webpack的入口文件,不過這些規範是能夠調整的;如下只是推薦)
    │           ├── index/   首頁
    │                ├── images/  圖片資源
    │                ├── page.css 樣式文件,文件名稱能夠按照本身意願命名
    │                ├── page.js  腳本文件及webpack的入口文件,文件名稱能夠在/conf/index.js配置
    │                ├── template.html 模板文件及要撰寫的html文件,文件名稱能夠在/conf/index.js配置
    │                ├──
    │              
    ├── dist/      自動生成
    │      
    ├── test/      測試(目錄能夠意願來建立,可是測試文件名稱必須遵循*_test.js的命名規範,可在/conf/karma.conf.js修改配置)
    │  
    ├── node_modules/     自動生成,包含node依賴以及開發依賴
    │  
    ├── static/           庫文件等,不會被webpack的loader處理,手動管理
    │     
    └── etc

使用webpack構建本地服務器

想不想讓你的瀏覽器監測你都代碼的修改,並自動刷新修改後的結果,其實Webpack提供一個可選的本地開發服務器,這個本地服務器基於node.js構建,能夠實現你想要的這些功能,不過它是一個單獨的組件,在webpack中進行配置以前須要單獨安裝它做爲項目依賴

npm install --save-dev webpack-dev-server

devserver做爲webpack配置選項中的一項,具備如下配置選項

devserver配置選項 功能描述
contentBase 默認webpack-dev-server會爲根文件夾提供本地服務器,
若是想爲另一個目錄下的文件提供本地服務器,
應該在這裏設置其所在目錄(本例設置到「public"目錄)
port 設置默認監聽端口,若是省略,默認爲」8080「
inline 設置爲true,當源文件改變時會自動刷新頁面
colors 設置爲true,使終端輸出的文件爲彩色的
historyApiFallback 在開發單頁應用時很是有用,它依賴於HTML5 history API,
若是設置爲true,全部的跳轉將指向index.html

以下配置:

module.exports = {
	...
	devServer: {
    contentBase: "./public",//本地服務器所加載的頁面所在的目錄
    colors: true,//終端中輸出結果爲彩色
    historyApiFallback: true,//不跳轉
    inline: true//實時刷新
  }
}
相關文章
相關標籤/搜索