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 developmentwebpack -p
– for building once for production (minification)webpack --watch
– for continuous incremental buildwebpack -d
– to include source mapswebpack --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" }, // ... }
// 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' } };
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-es2015 和 babel-preset-react 用來轉換 ES6 和 React。也可使用以下的query的方式來配置:
module: { loaders: [ { test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel', query: { presets: ['es2015', 'react'] } } ] }
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>
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">
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' } ] } };
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] } }) ] };
備註: UglifyJsPlugin還能夠對一些指定的變量不進行混淆
plugins: [ new webpack.optimize.UglifyJsPlugin({ mangle: { except: ['$super', '$', 'exports', 'require'] //以上變量‘$super’, ‘$’, ‘exports’ or ‘require’,不會被混淆 }, compress: { warnings: false } }) ]
下面來看如何加載第三方插件
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。
能夠經過一些配置來對開發環境和正式環境進行一些不一樣的操做;
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賦值。
對於大型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' } };
另外一個代碼分割的方法是使用 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的行爲將和上面相同。
當多個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 來分割提取出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>
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"}) ] };
若是你但願一個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" }) ] };
若是咱們想使用一些全局變量,但又不想把它們包含在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 );
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
.
new webpack.HotModuleReplacementPlugin()
to the plugins
fieldwebpack/hot/dev-server
and webpack-dev-server/client?http://localhost:8080
to the entry
fieldwebpack.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>
參考 React-router 官方示例
+---------------------------------------------------------+
| +---------+ +-------+ +--------+ |
| |Dashboard| | Inbox | |Calendar| Logged in as Jane |
| +---------+ +-------+ +--------+ |
+---------------------------------------------------------+
$ webpack-dev-server --history-api-fallback
參考鏈接:
Webpack 官方文檔 : http://webpack.github.io/docs/configuration.html