Webpack 配置示例

Webpack 做爲前端構建工具,對於大型網站開發,大大提高了開發效率。要使用webpack須要先安裝webpack工具;javascript

先來看一個最簡單的命令css

$ webpack main.js bundle.js

該命令將 main.js 輸出到 bundle.js 。html

一般,都不會這樣直接使用使用,而是在項目根目錄下進行打包配置,配置文件默認爲webpack.config.js。前端

// webpack.config.js
module.exports = {
  entry: './main.js',
  output: {
    filename: 'bundle.js'
  }
};

以後,直接在命令行中使用 webpack 就能進行打包了!java

除了直接使用 webpack 進行打包以外,還能夠對打包命令進行一些選擇性的配置:node

  • webpack – for building once for development
  • webpack -p – for building once for production (minification)
  • webpack --watch – for continuous incremental build
  • webpack -d – to include source maps
  • webpack --colors – for making things pretty

一樣,這些配置也能夠寫進 package.json 配置文件中react

// package.json
{
  // ...
  "scripts": {
    "dev": "webpack-dev-server --devtool eval --progress --colors",
    "deploy": "NODE_ENV=production webpack -p"
  },
  // ...
}

1. entry

// webpack.config.js
module.exports = {
  entry: './main.js',
  output: {
    filename: 'bundle.js'
  }
};

entry 除了使用一個單一的 js 文件以外,還可使用多個 js 文件;jquery

module.exports = {
  entry: {
    bundle1: './main1.js',
    bundle2: './main2.js'
  },
  output: {
    filename: '[name].js'
  }
};

2. Babel-loader

Loader 是源代碼轉換預處理器(more info). 例如, Babel-loader 能夠將 JSX/ES6 轉換成 JS 文件. 參見官方文檔:loaders.webpack

// main.jsx is a JSX file.

const React = require('react');
const ReactDOM = require('react-dom');

ReactDOM.render(
  <h1>Hello, world!</h1>,
  document.querySelector('#wrapper')
);

index.htmlgit

<html>
  <body>
    <div id="wrapper"></div>
    <script src="bundle.js"></script>
  </body>
</html>

webpack.config.js

module.exports = {
  entry: './main.jsx',
  output: {
    filename: 'bundle.js'
  },
  module: {
    loaders:[
      {
        test: /\.js[x]?$/,
        exclude: /node_modules/,
        loader: 'babel-loader?presets[]=es2015&presets[]=react'
      },
    ]
  }
};

module.loaders 用於指定 loaders. 上面的代碼片斷使用了 babel-loader,也用到了babel-preset-es2015babel-preset-react 用來轉換 ES6 和 React。也可使用以下的query的方式來配置:

module: {
  loaders: [
    {
      test: /\.jsx?$/,
      exclude: /node_modules/,
      loader: 'babel',
      query: {
        presets: ['es2015', 'react']
      }
    }
  ]
}

3. CSS-loader

Webpack 使咱們能夠經過 require 引用一個css文件並結合css-loader處理以後輸出成一個模塊。

main.js

require('./app.css');

app.css

body {
  background-color: blue;
}

index.html

<html>
  <head>
    <script type="text/javascript" src="bundle.js"></script>
  </head>
  <body>
    <h1>Hello World</h1>
  </body>
</html>

webpack.config.js

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

注意,這裏使用了兩個loader來轉換css文件。 CSS-loader 用來讀取CSS文件, Style-loader用來插入樣式到網頁中. 不一樣的loader用 ! 來鏈接.

在瀏覽器中瀏覽網頁,index.html中已經插入了樣式表。

<head>
  <script type="text/javascript" src="bundle.js"></script>
  <style type="text/css">
    body {
      background-color: blue;
    }
  </style>
</head>

4. Image loader

Webpack 還能夠經過 require 引用圖片文件。

main.js

var img1 = document.createElement("img");
img1.src = require("./small.png");
document.body.appendChild(img1);

var img2 = document.createElement("img");
img2.src = require("./big.png");
document.body.appendChild(img2);

index.html

<html>
  <body>
    <script type="text/javascript" src="bundle.js"></script>
  </body>
</html>

webpack.config.js

module.exports = {
  entry: './main.js',
  output: {
    filename: 'bundle.js'
  },
  module: {
    loaders:[
      { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192' }
    ]
  }
};

這裏使用了 url-loader 來轉換圖片文件. 若是圖片小於 8192 bytes 將會被轉換成 Data URL; 不然將會被轉換成普通的URL. ? 用來給url-loader傳入參數.

兩張不一樣大小的圖片會被轉換成不一樣的格式以下:

<img src="data:image/png;base64,iVBOR...uQmCC">
<img src="4853ca667a2b8b8844eb2693ac1b2578.png">

5. CSS Module

css-loader?modules 表示打開 CSS Modules 的功能。它表示module中定義的css樣式默認是局部做用域;若是須要轉換成全局做用域能夠經過 :global(.abc) (more info)

index.html

<html>
<body>
  <h1 class="h1">Hello World</h1>
  <h2 class="h2">Hello Webpack</h2>
  <div id="example"></div>
  <script src="./bundle.js"></script>
</body>
</html>

app.css

.h1 {
  color:red;
}

:global(.h2) {
  color: blue;
}

main.jsx

var React = require('react');
var ReactDOM = require('react-dom');
var style = require('./app.css');

ReactDOM.render(
  <div>
    <h1 className={style.h1}>Hello World</h1>
    <h2 className="h2">Hello Webpack</h2>
  </div>,
  document.getElementById('example')
);

webpack.config.js

module.exports = {
  entry: './main.jsx',
  output: {
    filename: 'bundle.js'
  },
  module: {
    loaders:[
      {
        test: /\.js[x]?$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
        query: {
          presets: ['es2015', 'react']
        }
      },
      {
        test: /\.css$/,
        loader: 'style-loader!css-loader?modules'
      }
    ]
  }
};

6. UglifyJs Plugin

Webpack 有插件支持用來擴展更多的需求。 UglifyJs Plugin 將會最小化輸出的js文件.

main.js

var longVariableName = 'Hello';
longVariableName += ' World';
document.write('<h1>' + longVariableName + '</h1>');

webpack.config.js

var webpack = require('webpack');
var uglifyJsPlugin = webpack.optimize.UglifyJsPlugin;
module.exports = {
  entry: './main.js',
  output: {
    filename: 'bundle.js'
  },
  plugins: [
    new uglifyJsPlugin({
      compress: {
        warnings: false
      }
    })
  ]
};

運行項目,main.js 將被輸出成以下格式:

var o="Hello";o+=" World",document.write("<h1>"+o+"</h1>")

注意:若是須要結合使用到postcss,webpack.config.js文件須要有一些小的修改以下:

var values = require("postcss-modules-values");
var webpack = require('webpack');
var uglifyJsPlugin = webpack.optimize.UglifyJsPlugin;

module.exports = {
    entry: __dirname + "/index.js",
    output: {
        path:"public",
        publicPath: "/",
        filename: "bundle.js"
    },
    module: {
        loaders:[
            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader:'babel-loader'
            },
            {
                test: /\.css$/,
                loader: "style-loader!css-loader?modules!postcss-loader"
            }
        ]
    },
    plugins:[
        new uglifyJsPlugin({
            compress:{
                warnings: false
            }
        }),
        new webpack.LoaderOptionsPlugin({
            test:/\.css$/,
            options: {
                postcss:[values]
            }
        })
    ]
};
View Code

備註: UglifyJsPlugin還能夠對一些指定的變量不進行混淆

plugins: [
  new webpack.optimize.UglifyJsPlugin({
    mangle: {
      except: ['$super', '$', 'exports', 'require']
      //以上變量‘$super’, ‘$’, ‘exports’ or ‘require’,不會被混淆
    },
    compress: {
      warnings: false
    }
  })
]

 

7. HTML Webpack Plugin and Open Browser Webpack Plugin

下面來看如何加載第三方插件

html-webpack-plugin 能夠建立index.html, open-browser-webpack-plugin 能夠打開一個瀏覽器窗口當 Webpack 加載完成以後。
npm install html-webpack-plugin open-browser-webpack-plugin webpack-dev-server --save

main.js

document.write('<h1>Hello World</h1>');

webpack.config.js

var HtmlwebpackPlugin = require('html-webpack-plugin');
var OpenBrowserPlugin = require('open-browser-webpack-plugin');

module.exports = {
  entry: './main.js',
  output: {
    filename: 'bundle.js'
  },
  plugins: [
    new HtmlwebpackPlugin({
      title: 'Webpack-demos',
      filename: 'index.html'
    }),
    new OpenBrowserPlugin({
      url: 'http://localhost:8080'
    })
  ]
};

運行 webpack-dev-server.

$ webpack-dev-server

如今不須要手動建立index.html文件,也不須要去打開瀏覽器窗口了,一切由webpack爲咱們包辦了!

可能遇到的錯誤: Error: Cannot find module 'webpack/lib/node/NodeTemplatePlugin' ,解決辦法:在項目中從新安裝webpack。

8. Environment flags

能夠經過一些配置來對開發環境和正式環境進行一些不一樣的操做;

main.js

document.write('<h1>Hello World</h1>');

if (__DEV__) {
  document.write(new Date());
}

webpack.config.js

var webpack = require('webpack');

var devFlagPlugin = new webpack.DefinePlugin({
  __DEV__: JSON.stringify(JSON.parse(process.env.DEBUG || 'false'))
});

module.exports = {
  entry: './main.js',
  output: {
    filename: 'bundle.js'
  },
  plugins: [devFlagPlugin]
};

運行webpack打包並輸入環境變量配置:

# Linux & Mac
$ env DEBUG=true webpack-dev-server

# Windows
$ set DEBUG=true
$ webpack-dev-server

process.env 默認爲一個空對象,經過 env DEBUG=true命令 爲env.DEBUG賦值。

9. Code splitting

對於大型web網站,不可能將全部的js文件都放到一個文件中一次性加載, Webpack 容許咱們將js文件進行分割。

首先,你須要使用 require.ensure 來定義分割點 (official document)

// main.js
require.ensure(['./a'], function(require) {
  var content = require('./a');
  document.open();
  document.write('<h1>' + content + '</h1>');
  document.close();
});

require.ensure 告訴 Webpack,./a.js 文件應該從bundle.js文件中分割出來並編譯到一個單獨的文件中。

// a.js
module.exports = 'Hello World';

如今webpack將會自動進行編譯打包,不須要再進行額外的配置。

webpack.config.js

module.exports = {
  entry: './main.js',
  output: {
    filename: 'bundle.js'
  }
};
從表象上看,沒有任區別,但實際上webpack將main.js和a.js編譯到兩個不一樣的文件中了,分別是bundle.js和1.bundle.js文件,當須要用到的時候再加載1.bundle.js文件;

10. Code splitting with bundle-loader

另外一個代碼分割的方法是使用 bundle-loader.

// main.js

// Now a.js is requested, it will be bundled into another file
var load = require('bundle-loader!./a.js');

// To wait until a.js is available (and get the exports)
//  you need to async wait for it.
load(function(file) {
  document.open();
  document.write('<h1>' + file + '</h1>');
  document.close();
});

require('bundle-loader!./a.js') 告訴 Webpack 須要從另外的js文件中去加載 a.js。webpack的行爲將和上面相同。

11. Common chunk

當多個script文件須要使用到相同的chunk的時候,能夠將這個公用的模塊經過CommonsChunkPlugin提取到單獨的文件中。

// JQ01.js
var $ = require("jquery");
$('#a').text("001");

// JQ02.js
var $ = require("jquery");
$('#b').text("002");

上面的兩個不一樣的組件中,都同時須要用到 JQuery,甚至會有更多的組件也會如此,此時能夠將 JQuery 提取出來,放置到一個公共的 js 文件中。

index.html

<html>
  <body>
    <div id="a"></div>
    <div id="b"></div>
    <script src="vendor.js"></script>
    <script src="bundle1.js"></script>
    <script src="bundle2.js"></script>
  </body>
</html>

webpack.config.js

var CommonsChunkPlugin = require("webpack/lib/optimize/CommonsChunkPlugin");

module.exports = {
    entry: {
        bundle1: "./JQ01.js",
        bundle2: "./JQ02.js",
        vendor: ["jquery"] // option
    },
    output: {
        filename: "[name].js"
    },
    plugins: [
        new CommonsChunkPlugin({
            name: 'vendor',
            filename: "vendor.js"
        })
    ]
};

隨着庫愈來愈大,vendor文件也變得愈來愈大,因而考慮打包成兩個vendor,把和react相關的庫打包成一個vendor,其餘的庫打包成另一個vendor。

...
entry: { 
    "vendor1": ["react", "react-dom", "react-router", "react-router-redux", "react-redux", "redux"], 
    "vendor2": ["jquery"],
    "app": "./js/index.js" 
},
...
plugins: [
    new webpack.optimize.CommonsChunkPlugin({
        names: ["vendor2", "vendor1"],
        minChunks: Infinity
    })
],
...

有兩個須要注意的地方:

  • 在CommonsChunkPlugin裏面,vender的順序要反着來,要和加載順序相反。好比你想按vendor1,vendor2的順序加載,entry裏面寫的是vendor1,vendor2,在CommonsChunkPlugin裏面要寫vendor2,vendor1。
  • output.filename必定不要寫死了,要配置成可替換的,相似filename: '[name].js'形式。

12. Vendor chunk

也能夠經過 CommonsChunkPlugin 來分割提取出js庫。

main.js

var $ = require('jquery');
$('h1').text('Hello World');

index.html

<html>
  <body>
    <h1></h1>
    <script src="vendor.js"></script>
    <script src="bundle.js"></script>
  </body>
</html>
View Code

webpack.config.js

var webpack = require('webpack');

module.exports = {
  entry: {
    app: './main.js',
    vendor: ['jquery'],
  },
  output: {
    filename: 'bundle.js'
  },
  plugins: [
    new CommonsChunkPlugin({
      name: 'vendor', 
      filename: "vendor.js"})
  ]
};
View Code

ProvidePlugin

 
     

若是你但願一個module能夠做爲一個變量使用到其它地方,好比使用jQuery的 $ ,咱們能夠在任何地方使用而不須要經過 require("jquery"),這就須要用到 ProvidePlugin (Official doc).

// main.js
$('h1').text('Hello World');

webpack.config.js

var webpack = require('webpack');

module.exports = {
  entry: {
    app: './main.js'
  },
  output: {
    filename: 'bundle.js'
  },
  plugins: [
    new webpack.ProvidePlugin({
      $: "jquery",
      jQuery: "jquery",
      "window.jQuery": "jquery"
    })
  ]
};

13. Exposing global variables

若是咱們想使用一些全局變量,但又不想把它們包含在webpack中,這時候能夠經過在webpack.config.js中 配置 externals 來實現 official document

data.js.

var data = 'Hello World';

將data數據暴露成全局變量

// webpack.config.js
module.exports = {
  entry: './main.jsx',
  output: {
    filename: 'bundle.js'
  },
  module: {
    loaders:[
      {
        test: /\.js[x]?$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
        query: {
          presets: ['es2015', 'react']
        }
      },
    ]
  },
  externals: {
    // require('data') is external and available
    //  on the global var data
    'data': 'data'
  }
};

如今,經過 var data = require('data') 能夠將data.js輸出到模塊變量中。但實際上data是一個全局變量。

// main.jsx
var data = require('data');
var React = require('react');
var ReactDOM = require('react-dom');

ReactDOM.render(
  <h1>{data}</h1>,
  document.body
);

14. Hot Module Replacement

Hot Module Replacement (HMR) 當網頁發生改變的時候,不須要手動刷新頁面。結合webpack-dev-server有兩種方式來打開 HMR。

(1) 在命令中指定 --hot 和 --inline

$ webpack-dev-server --hot --inline

Meaning of the options:

  • --hot: adds the HotModuleReplacementPlugin and switch the server to hot mode.
  • --inline: embed the webpack-dev-server runtime into the bundle.
  • --hot --inline: also adds the webpack/hot/dev-server entry.

(2) 配置 webpack.config.js.

  • add new webpack.HotModuleReplacementPlugin() to the plugins field
  • add webpack/hot/dev-server and webpack-dev-server/client?http://localhost:8080 to the entry field

webpack.config.js

var webpack = require('webpack');
var path = require('path');

module.exports = {
  entry: [
    'webpack/hot/dev-server',
    'webpack-dev-server/client?http://localhost:8080',
    './index.js'
  ],
  output: {
    filename: 'bundle.js',
    publicPath: '/static/'
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin()
  ],
  module: {
    loaders: [{
      test: /\.jsx?$/,
      exclude: /node_modules/,
      loader: 'babel-loader',
      query: {
        presets: ['es2015', 'react']
      },
      include: path.join(__dirname, '.')
    }]
  }
};
Now launch the dev server.
$ webpack-dev-server

在瀏覽器中打開 http://localhost:8080 查看網頁。保持網頁打開,對網頁修改一些內容,觀察瀏覽器是否發生改變;

App.js

import React, { Component } from 'react';

export default class App extends Component {
  render() {
    return (
      <h1>Hello World</h1>
    );
  }
}

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(<App />, document.getElementById('root'));

index.html

<html>
  <body>
    <div id='root'></div>
    <script src="/static/bundle.js"></script>
  </body>
</html>

15. React router

參考 React-router 官方示例

+---------------------------------------------------------+
| +---------+ +-------+ +--------+                        |
| |Dashboard| | Inbox | |Calendar|      Logged in as Jane |
| +---------+ +-------+ +--------+                        |
+---------------------------------------------------------+
$ webpack-dev-server --history-api-fallback 

 參考鏈接:

 Webpack 官方文檔 : http://webpack.github.io/docs/configuration.html

相關文章
相關標籤/搜索