本文從屬於筆者的Web 前端入門與最佳實踐。javascript
Webpack的安裝很是簡單,直接使用npm i webpack --save-dev
命令安裝便可。通常來講,基於Webpack的項目的目錄結構以下:css
/app main.js component.js /build bundle.js (自動建立) index.html package.json webpack.config.js
webpack-dev-server --content-base build/
<script src="http://localhost:8080/webpack-dev-server.js"></script>
相似與Gulp中使用gulpfile.js配置Gulp編譯項目,Webpack中使用webpack.config.js來進行全局配置,一個基本的配置文件以下所示:html
var path = require('path'); module.exports = { entry: path.resolve(__dirname, 'assets/js/main.js'), output: { path: path.resolve(__dirname, 'dist'), publicPath: 'dist/', filename: 'game_bundle.js', }, module: { loaders: [ {test: /\.jsx$/,exclude:/libs/, loader: 'babel?stage=0'}, {test: /\.js$/, exclude:/libs/,loader: 'babel?stage=0'}, {test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192'} ,// inline base64 URLs for <=8k images, direct URLs for the rest { test: /\.css$/, loader: 'style-loader!css-loader!autoprefixer-loader?browsers=last 2 versions' } ], }, externals: { jquery: "jQuery", pageResponse:'pageResponse' }, resolve : { alias: { libs : path.resolve(__dirname, 'libs') } } };
本處以簡單的HelloWorld爲例演示如何經過Webpack將全部的JS、CSS以及資源文件打包到一塊兒。前端
app/component.jsjava
'use strict'; module.exports = function () { var element = document.createElement('h1'); element.innerHTML = 'Hello world'; return element; };
app/main.js*node
'use strict'; var component = require('./component.js'); document.body.appendChild(component());
如今在你的命令行運行 webpack
,而後你的應用會開始編譯,一個 bundle.js
文件就這樣出如今你的 /build
文件夾下,須要在 build/
下的 index.html 去啓動項目。jquery
build/index.htmlwebpack
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"/> </head> <body> <script src="bundle.js"></script> </body> </html>
package.json
npm
是一個很是好用的用來編譯的指令,經過 npm
你能夠不用去擔憂項目中使用了什麼技術,你只要調用這個指令就能夠了,只要你在 package.json
中設置 scripts
的值就能夠了。git
npm i webpack --save
- 若是你想要把 Webpack 做爲一個項目的開發依賴,就可使用 --save-dev
,這樣就很是方便地讓你在開發一個庫的時候,不會依賴工具(但不是個好方法!)。github
把下面的內容添加到 package.json
中。
"scripts": { "build": "webpack" }
上面的HelloWorld示例演示了Webpack最基本的用法,可是若是咱們有一個相對複雜的Button組件定義:
src/Components/Button.scss
.button { background: tomato; color: white; }
src/Components/Button.html
<a class="button" href="{{link}}">{{text}}</a>
src/Components/Button.js
import $ from 'jquery'; import template from './Button.html'; import Mustache from 'mustache'; import './Button.scss'; export default class Button { constructor(link) { this.link = link; } onClick(event) { event.preventDefault(); alert(this.link); } render(node) { const text = $(node).text(); // Render our button $(node).html( Mustache.render(template, {text}) ); // Attach our listeners $('.button').click(this.onClick.bind(this)); } }
按鈕最終呈現的樣式以下所示:
在主模塊中,這個Button不必定在初始加載時就用到,可能在部分頁面中須要用到該按鈕,可是在其餘頁面中則根本不須要它們。在這種狀況下,若是在一開始的時候就將全部Button的代碼以及樣式導入,無疑會加深初始時候的消耗。而Webpack的代碼分割功能的提出正是爲了解決這個問題,也就是所謂的"總體導入"與"無維持的手動導入"之間取得一個平衡。若是須要引入代碼分割的功能,便是須要在代碼中引入所謂的切割點,即動態地將整個代碼切分爲多個文件而且動態地按需加載。基本語法以下所示:
import $ from 'jquery'; // This is a split point require.ensure([], () => { // All the code in here, and everything that is imported // will be in a separate file const library = require('some-big-library'); $('foo').click(() => library.doSomething()); });
全部在require.ensure
中定義的文件會被切分爲多個大的獨立分塊,這些獨立的分塊會在須要被調用時被使用Ajax進行動態導入。使用Code Splitting以後整個文件目錄的佈局方式以下所示:
bundle.js |- jquery.js |- index.js // our main file chunk1.js |- some-big-libray.js |- index-chunk.js // the code in the callback
固然,開發者並不須要手動導入chunk1.js文件,Webpack打包的模塊加載器會按需自動加載。這就意味着對於開發者而言並不須要使用複雜的邏輯去手動控制按需加載,而只須要使用require.ensure方法便可。
src/index.js
if (document.querySelectorAll('a').length) { require.ensure([], () => { const Button = require('./Components/Button'); const button = new Button('google.com'); button.render('a'); }); }
若是在編譯時候使用以下參數:--display-chunks
,那麼能夠查看具體的被打包的狀況:
$ webpack --display-modules --display-chunks Hash: 432341dc518c06c9d8da Version: webpack 1.12.2 Time: 952ms Asset Size Chunks Chunk Names bundle.js 3.88 kB 0 [emitted] main 1.bundle.js 287 kB 1 [emitted] chunk {0} bundle.js (main) 294 bytes [rendered] [0] ./src/index.js 294 bytes {0} [built] chunk {1} 1.bundle.js 278 kB {0} [rendered] [1] ./src/Components/Button.js 2.02 kB {1} [built] [2] ./~/jquery/dist/jquery.js 248 kB {1} [built] [3] ./src/Components/Button.html 72 bytes {1} [built] [4] ./~/mustache/mustache.js 19.3 kB {1} [built] [5] ./src/Components/Button.scss 1.05 kB {1} [built] [6] ./~/css-loader!./~/sass-loader!./src/Components/Button.scss 212 bytes {1} [built] [7] ./~/css-loader/lib/css-base.js 1.51 kB {1} [built] [8] ./~/style-loader/addStyles.js 6.09 kB {1} [built]
如上所述,入口文件bundle.js
中只會包含部分Webpack的邏輯,其餘的譬如jQuery、Mustache、Button這樣的部分會被包含在1.bundle.js塊中,這些塊會在使用時被動態加載。
在發佈版本中,可能須要一些特殊的配置或者插件,譬如只有在NODE_ENV
環境變量等於production
的狀況下才會有邏輯配置須要添加在配置文件中,那麼在Webpack的配置文件中可使用以下定義:
var webpack = require('webpack'); var production = process.env.NODE_ENV === 'production'; var plugins = [ new webpack.optimize.CommonsChunkPlugin({ name: 'main', // Move dependencies to our main file children: true, // Look for common dependencies in all children, minChunks: 2, // How many times a dependency must come up before being extracted }), ]; if (production) { plugins = plugins.concat([ // Production plugins go here ]); } module.exports = { entry: './src', output: { path: 'builds', filename: 'bundle.js', publicPath: 'builds/', }, plugins: plugins, // ... };
在發佈版本中,Webpack的一些配置能夠被關閉,譬如:
module.exports = { debug: !production, devtool: production ? false : 'eval',