webpack進階構建項目(一)
閱讀目錄
- 1.理解webpack加載器
- 2.html-webpack-plugin學習
- 3.壓縮js與css
- 4.理解less-loader加載器的使用
- 5.理解babel-loader加載器
- 6.理解 extract-text-webpack-plugin(獨立打包樣式文件)
- 7.webpack打包多個資源文件
- 8.webpack對圖片的打包
- 9.學習web-dev-server 創建服務器及動態監聽css及js文件的改變;
- 10.assets-webpack-plugin插件解決html文件的版本號的問題;
- 11.webpack關於同步加載和異步加載的問題
1.理解webpack加載器
webpack的設計理念,所有資源都是“模塊”,webpack內部實現了一套資源加載機制,這與Requirejs、Sea.js、Browserify等實現有所不同.
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 是插件項;
2.html-webpack-plugin學習
首先來看看項目的目錄結構如下:

package.json 如下:
{ "name": "html-webpack-plugin", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC", "devDependencies": { "html-webpack-plugin": "^2.19.0", "webpack": "^1.13.1" } }
運行命令 npm install 把依賴包加載出來;
接着在 webpack.config.js配置如下:
var path = require('path'); var HtmlwebpackPlugin = require('html-webpack-plugin'); //定義了一些文件夾的路徑 var ROOT_PATH = path.resolve(__dirname); var SRC_PATH = path.resolve(ROOT_PATH, 'src'); var BUILD_PATH = path.resolve(ROOT_PATH, 'build'); console.log(SRC_PATH) module.exports = { entry: SRC_PATH + "/js/index.js", //輸出的文件名 合並以后的js會命名為index.js output: { path: BUILD_PATH, filename: 'index.js' }, //添加我們的插件 會自動生成一個html文件 plugins: [ new HtmlwebpackPlugin({ title: 'Hello World app' }) ] };
在項目中的根目錄下 運行 webpack 就能生成buid文件夾了,里面會自動生成 兩個文件 index.html和index.js文件;
index.html代碼如下:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Hello World app</title> </head> <body> <script type="text/javascript" src="index.js"></script></body> </html>
標題title就是我們配置上的;
且合並了依賴的js文件;我們可以直接在本地訪問index.html 可以看到能打印出依賴的文件js代碼了;可以看到可以解決依賴的問題;
html-webpack-plugin 還支持如下配置:
title: 用於生成的HTML文件的標題。
filename: 用於生成的HTML文件的名稱,默認是index.html。你可以在這里指定子目錄。
template: 模板文件路徑,支持加載器,比如 html!./index.html
inject: true | 'head' | 'body' | false ,注入所有的資源到特定的 template 或者 templateContent 中,如果設置為 true
或者 body,所有的 javascript 資源將被放置到 body 元素的底部,'head' 將放置到 head 元素中。
favicon: 添加特定的 favicon 路徑到輸出的 HTML 文件中。
minify:{ //壓縮HTML文件
removeComments:true, //移除HTML中的注釋
collapseWhitespace:true //刪除空白符與換行符
}
hash: true | false, 如果為 true, 將添加一個唯一的 webpack 編譯 hash 到所有包含的腳本和 CSS 文件,對於解除 cache 很有用。
cache: true | false,如果為 true, 這是默認值,僅僅在文件修改之后才會發布文件。
showErrors: true | false, 如果為 true, 這是默認值,錯誤信息會寫入到 HTML 頁面中
chunks: 允許只添加某些塊 (比如,僅僅 unit test 塊)
chunksSortMode: 允許控制塊在添加到頁面之前的排序方式,支持的值:'none' | 'default' | {function}-default:'auto'
excludeChunks: 允許跳過某些塊,(比如,跳過單元測試的塊)
比如我現在webpack.config.js配置改為如下:
var path = require('path'); var HtmlwebpackPlugin = require('html-webpack-plugin'); //定義了一些文件夾的路徑 var ROOT_PATH = path.resolve(__dirname); var SRC_PATH = path.resolve(ROOT_PATH, 'src'); var BUILD_PATH = path.resolve(ROOT_PATH, 'build'); console.log(SRC_PATH) module.exports = { entry: SRC_PATH + "/js/index.js", //輸出的文件名 合並以后的js會命名為index.js output: { path: BUILD_PATH, filename: 'index.js' }, //添加我們的插件 會自動生成一個html文件 plugins: [ new HtmlwebpackPlugin({ title: 'Hello World app', filename: '1.0.0/home.html', inject: true, hash: true }) ] };
然后再在命令行中繼續運行webpack命令,可以看到在build下會生成2個目錄 第一個是build/1.0.1/home.html; 第二個是 build/index.js
再來看下home.html代碼如下:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Hello World app</title> </head> <body> <script type="text/javascript" src="../index.js?d03211ff5e0251af224d"></script></body> </html>
可以看到設置 hash為true js的后綴會自動加一個hash編碼,對於頁面解決緩存很有用;
生成多個 HTML 文件
通過在配置文件中添加多次這個插件,來生成多個 HTML 文件。
webpack.config.js代碼如下:
var path = require('path'); var HtmlwebpackPlugin = require('html-webpack-plugin'); //定義了一些文件夾的路徑 var ROOT_PATH = path.resolve(__dirname); var SRC_PATH = path.resolve(ROOT_PATH, 'src'); var BUILD_PATH = path.resolve(ROOT_PATH, 'build'); console.log(SRC_PATH) module.exports = { entry: SRC_PATH + "/js/index.js", //輸出的文件名 合並以后的js會命名為index.js output: { path: BUILD_PATH, filename: 'index.js' }, //添加我們的插件 會自動生成一個html文件 plugins: [ new HtmlwebpackPlugin(), new HtmlwebpackPlugin({ title: 'Hello World app', filename: 'app1/home.html', template: 'src/html/index.html', inject: true, hash: true }) ] };
官網可以看這里 https://www.npmjs.com/package/html-webpack-plugin
也可以在配置項 加上minify選項 壓縮HTML文件;代碼如下:
var path = require('path'); var HtmlwebpackPlugin = require('html-webpack-plugin'); //定義了一些文件夾的路徑 var ROOT_PATH = path.resolve(__dirname); var SRC_PATH = path.resolve(ROOT_PATH, 'src'); var BUILD_PATH = path.resolve(ROOT_PATH, 'build'); console.log(SRC_PATH) module.exports = { entry: SRC_PATH + "/js/index.js", //輸出的文件名 合並以后的js會命名為index.js output: { path: BUILD_PATH, filename: 'index.js' }, //添加我們的插件 會自動生成一個html文件 plugins: [ new HtmlwebpackPlugin({ title: 'Hello World app', minify:{ //壓縮HTML文件 removeComments:true, //移除HTML中的注釋 collapseWhitespace:true //刪除空白符與換行符 } }) ] };
查看html生成后的文件可以看到已經被壓縮了;
3.壓縮js與css
webpack已經內嵌了uglifyJS來完成對JS與CSS的壓縮混淆,無需引用額外的插件。
壓縮代碼如下:
new webpack.optimize.UglifyJsPlugin({ //壓縮代碼 compress: { warnings: false }, except: ['$super', '$', 'exports', 'require'] //排除關鍵字 })
這里需要注意的是壓縮的時候需要排除一些關鍵字,不能混淆,比如$或者require,如果混淆的話就會影響到代碼的正常運行。
webpack.config.js代碼改為如下:
var path = require('path'); var HtmlwebpackPlugin = require('html-webpack-plugin'); var webpack = require("webpack"); //定義了一些文件夾的路徑 var ROOT_PATH = path.resolve(__dirname); var SRC_PATH = path.resolve(ROOT_PATH, 'src'); var BUILD_PATH = path.resolve(ROOT_PATH, 'build'); console.log(SRC_PATH) module.exports = { entry: { 'index' : SRC_PATH + "/js/index.js" }, //輸出的文件名 合並以后的js會命名為index.js output: { path: BUILD_PATH + '/js/', filename: '[name].js' }, //添加我們的插件 會自動生成一個html文件 plugins: [ new HtmlwebpackPlugin({ title: 'Hello World app', minify:{ //壓縮HTML文件 removeComments:true, //移除HTML中的注釋 collapseWhitespace:true //刪除空白符與換行符 } }), new webpack.optimize.UglifyJsPlugin({ //壓縮代碼 compress: { warnings: false }, except: ['$super', '$', 'exports', 'require'] //排除關鍵字 }) ] };
繼續運行下webpack可以看到js已經被壓縮了;注意:但是貌似對es6的語法不能壓縮~
4.理解less-loader加載器的使用
我們先來理解下less-loader加載器,其他的sass-loader也是一個意思,less-loader加載器是把css代碼轉化到style標簽內,
動態插入到head標簽內;我們先來看看我項目的結構如下:

src/html/index.html代碼如下:
<!DOCTYPE html> <html> <head> <meta http-equiv="content-type" content="text/html;charset=utf-8" /> <meta content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport"/> <meta content="yes" name="apple-mobile-web-app-capable" /> <meta content="black" name="apple-mobile-web-app-status-bar-style" /> <meta content="telephone=no" name="format-detection" /> <meta content="email=no" name="format-detection" /> <meta name="description" content="基於webpack的前端工程化開發解決方案探索"/> <title>動態生成html的實踐</title> </head> <body> <div>hello webpack</div> </body> </html>
現在我想通過html-webpack-plugin插件動態生成 html頁面及引入index.js 和 生成 index.js文件;
webpack.config.js代碼配置如下:
var path = require('path'); var HtmlwebpackPlugin = require('html-webpack-plugin'); //定義了一些文件夾的路徑 var ROOT_PATH = path.resolve(__dirname); var SRC_PATH = path.resolve(ROOT_PATH, 'src'); var BUILD_PATH = path.resolve(ROOT_PATH, 'build'); module.exports = { entry: SRC_PATH + "/js/index.js", output: { filename: "build.js", path: BUILD_PATH }, module: { loaders: [ //.css 文件使用 style-loader 和 css-loader 來處理 { test: /\.less$/, loader: "style!css!less" } ] }, resolve: { extensions: ['', '.js', '.jsx'] }, plugins: [ new HtmlwebpackPlugin({ title: 'Hello World app', filename: 'index.html', template: 'src/html/index.html', inject: true, hash: true }) ] };
在項目的根目錄運行webpack,即可動態生成html文件和js文件,打開生成后的index.html即可看到css生效了,且css被動態內鏈到head標簽內了;

其中less/main.less 文件如下代碼:
@color: red;
body {
background:@color;
}
如上可以看到less文件得到編譯,且動態插入到head標簽內;
5.理解babel-loader加載器
babel-loader加載器能將ES6的代碼轉換成ES5代碼,我們需要安裝babel-loader
執行命令:npm install babel-loader --save-dev
因此現在需要在webpack.config.js 加入babel-loader的加載器即可;如下:
var path = require('path'); var HtmlwebpackPlugin = require('html-webpack-plugin'); //定義了一些文件夾的路徑 var ROOT_PATH = path.resolve(__dirname); var SRC_PATH = path.resolve(ROOT_PATH, 'src'); var BUILD_PATH = path.resolve(ROOT_PATH, 'build'); module.exports = { entry: SRC_PATH + "/js/index.js", output: { filename: "build.js", path: BUILD_PATH }, module: { loaders: [ //.css 文件使用 style-loader 和 css-loader 來處理 { test: /\.less$/, loader: "style!css!less" }, { test: /\.js$/, loader: 'babel' } ] }, resolve: { extensions: ['', '.js', '.jsx'] }, plugins: [ new HtmlwebpackPlugin({ title: 'Hello World app', filename: 'index.html', template: 'src/html/index.html', inject: true, hash: true }) ] };
a.js 假如是ES6的語法;比如如下一句代碼:
// es6的語法
let LOADER = true;
module.exports = LOADER;
現在在index.js代碼如下:
var aModule = require('../less/main.less');
console.log(aModule);
// es6的語法
var aMoudle = require('./a');
console.log(aMoudle);
可以看到打印 aMoudle的值為true;說明可以正確的解析了;
6.理解 extract-text-webpack-plugin(獨立打包樣式文件)
執行安裝命令:
sudo npm install extract-text-webpack-plugin
然后再webpack.config.js 加入加載器配置項如下代碼:
var path = require('path'); var HtmlwebpackPlugin = require('html-webpack-plugin'); var ExtractTextPlugin = require('extract-text-webpack-plugin'); //定義了一些文件夾的路徑 var ROOT_PATH = path.resolve(__dirname); var SRC_PATH = path.resolve(ROOT_PATH, 'src'); var BUILD_PATH = path.resolve(ROOT_PATH, 'build'); module.exports = { entry: SRC_PATH + "/js/index.js", output: { filename: "build.js", path: BUILD_PATH }, module: { loaders: [ //.css 文件使用 style-loader 和 css-loader 來處理 { test: /\.less$/, loader: ExtractTextPlugin.extract( 'css?sourceMap!' + 'less?sourceMap' ) }, { test: /\.js$/, loader: 'babel' } ] }, resolve: { extensions: ['', '.js', '.jsx'] }, plugins: [ // 內聯css提取到單獨的styles的css new ExtractTextPlugin("index.css"), new HtmlwebpackPlugin({ title: 'Hello World app', filename: 'index.html', template: 'src/html/index.html', inject: true, hash: true }) ] };
在項目的根目錄運行 webpack 即可生效;會在build目錄下 生成 index.css文件,且在打包后的index.html會自動引入link標簽的css;
如下所示:

如果頁面上有多個less文件或者css文件的話,也可以通過 @import 動態導入;如下在main.less 引入 a.less代碼如下:
@import './a.less';
a.less 是和main.less 同級目錄下的;
7.webpack打包多個資源文件
我們在開發頁面的時候,有時候需要有多個入口文件,做到文件是按需加載,這樣就可以使用緩存提升性能;
只需要像如下編碼即可:
module.exports = { entry: { "main": "./src/a.js", "index": "./src/index.js" }, output: { filename: "[name].js" } };
webpack.config.js代碼如下:
var path = require('path'); var HtmlwebpackPlugin = require('html-webpack-plugin'); var ExtractTextPlugin = require('extract-text-webpack-plugin'); var webpack = require("webpack"); //定義了一些文件夾的路徑 var ROOT_PATH = path.resolve(__dirname); var SRC_PATH = path.resolve(ROOT_PATH, 'src'); var BUILD_PATH = path.resolve(ROOT_PATH, 'build'); module.exports = { entry: { "a": SRC_PATH + "/js/a.js", "index": SRC_PATH + "/js/index.js", }, output: { filename: "[name].js", path: BUILD_PATH }, module: { loaders: [ //.css 文件使用 style-loader 和 css-loader 來處理 { test: /\.less$/, loader: ExtractTextPlugin.extract( 'css?sourceMap!' + 'less?sourceMap' ) }, { test: /\.js$/, loader: 'babel' } ] }, resolve: { extensions: ['', '.js', '.jsx'] }, plugins: [ // 內聯css提取到單獨的styles的css new ExtractTextPlugin("index.css"), new HtmlwebpackPlugin({ title: 'Hello World app', filename: 'index.html', template: 'src/html/index.html', inject: true, hash: true }), new webpack.optimize.UglifyJsPlugin({ //壓縮代碼 compress: { warnings: false }, except: ['$super', '$', 'exports', 'require'] //排除關鍵字 }) ] };
8.webpack對圖片的打包
圖片是 url-loader來加載的,我們既可以在css文件里url的屬性;
首先先安裝 url-loader插件;
sudo npm install --save-dev url-loader
首先在less文件里面加入如下代碼:
@color: red;
body {
background:@color;
background:url('../images/1.png') no-repeat;
}
在index.js里面加入如下代碼:
var aModule = require('../less/main.less');
console.log(aModule);
在webpack.config.js代碼配置加入如下:
{
test: /.(png|jpg)$/,
loader: 'url?limit=8192'
}
webpack.config.js所有代碼如下:
var path = require('path'); var HtmlwebpackPlugin = require('html-webpack-plugin'); var ExtractTextPlugin = require('extract-text-webpack-plugin'); var webpack = require("webpack"); //定義了一些文件夾的路徑 var ROOT_PATH = path.resolve(__dirname); var SRC_PATH = path.resolve(ROOT_PATH, 'src'); var BUILD_PATH = path.resolve(ROOT_PATH, 'build'); module.exports = { entry: { "a": SRC_PATH + "/js/a.js", "index": SRC_PATH + "/js/index.js", }, output: { filename: "[name].js", path: BUILD_PATH }, module: { loaders: [ //.css 文件使用 style-loader 和 css-loader 來處理 { test: /\.less$/, loader: ExtractTextPlugin.extract( 'css?sourceMap!' + 'less?sourceMap' ) }, { test: /\.js$/, loader: 'babel' }, { test: /.(png|jpg)$/, loader: 'url?limit=8192&name=img/[hash:8].[name].[ext]' } ] }, resolve: { extensions: ['', '.js', '.jsx'] }, plugins: [ // 內聯css提取到單獨的styles的css new ExtractTextPlugin("index.css"), new HtmlwebpackPlugin({ title: 'Hello World app', filename: 'index.html', template: 'src/html/index.html', inject: true, hash: true }), new webpack.optimize.UglifyJsPlugin({ //壓縮代碼 compress: { warnings: false }, except: ['$super', '$', 'exports', 'require'] //排除關鍵字 }) ] };
因此在項目的根目錄運行webpack后,即可,然后會生成index.css文件代碼如下:
body{background:red;background:url(8eaebaa98ed1fe64bbf9f0f954b2b230.png) no-repeat}
因此可以看到會動態轉換成base64編碼;
9.學習web-dev-server 創建服務器及動態監聽css及js文件的改變;
在webpack中,我們經常使用webpack-dev-server作為開發服務器,用於實時監聽和打包編譯靜態資源,這樣每當我們修改js、css等等文件時,客戶端(如瀏覽器等)能夠自動刷新頁面,展示實時的頁面效果。
webpack-dev-server只監聽webpack.config.js中entry入口下文件(如js、css等等)的變動,
只有這些文件的變動才會觸發實時編譯打包與頁面刷新,但是html文件更改后保存不能監聽新內容到,但是對於開發影響不大,我們在編寫css文件
或者js文件的時候保存后,會自動刷新頁面,所以html頁面也會自動更新到;
首先需要進入我們的項目的根目錄下需要安裝webpack-dev-server 安裝命令如下:
sudo npm install --save-dev webpack-dev-server
首先我項目的目錄如下:

安裝完成后,需要在webpack.config.js文件配置下;如下代碼:
var path = require('path'); var HtmlwebpackPlugin = require('html-webpack-plugin'); var ExtractTextPlugin = require('extract-text-webpack-plugin'); var webpack = require("webpack"); //定義了一些文件夾的路徑 var ROOT_PATH = path.resolve(__dirname); var SRC_PATH = path.resolve(ROOT_PATH, 'src'); var BUILD_PATH = path.resolve(ROOT_PATH, 'build'); module.exports = { entry: { "a": SRC_PATH + "/js/a.js", "index": SRC_PATH + "/js/index.js" }, output: { filename: "/js/[name].js", path: BUILD_PATH }, module: { loaders: [ //.css 文件使用 style-loader 和 css-loader 來處理 { test: /\.less$/, loader: ExtractTextPlugin.extract( 'css?sourceMap!' + 'less?sourceMap' ) }, { test: /\.js$/, loader: 'babel' }, { test: /.(png|jpg)$/, loader: 'url?limit=8192&name=images/[hash:8].[name].[ext]' } ] }, resolve: { extensions: ['', '.js', '.jsx'] }, plugins: [ // 內聯css提取到單獨的styles的css new ExtractTextPlugin("/css/index.css"), new HtmlwebpackPlugin({ title: 'Hello World app', filename: 'html/index.html', template: 'src/html/index.html', inject: true, hash: true }), new webpack.optimize.UglifyJsPlugin({ //壓縮代碼 compress: { warnings: false }, except: ['$super', '$', 'exports', 'require'] //排除關鍵字 }) ] };
接着需要創建一個webpack-config-dev.js文件,該文件的作用是創建本地服務器,及實時監聽css及js文件的改變;代碼如下:
var path = require('path') var webpack = require('webpack'); var HtmlwebpackPlugin = require('html-webpack-plugin'); var ExtractTextPlugin = require('extract-text-webpack-plugin'); module.exports = { devtool: 'cheap-eval-source-map', entry: [ 'webpack-dev-server/client?http://127.0.0.1:8080', 'webpack/hot/dev-server', './src/js/index', './src/js/a', './src/less/main.less' ], output: { path: path.join(__dirname, 'build'), filename: '/js/[name].js' }, plugins: [ new webpack.HotModuleReplacementPlugin(), new HtmlwebpackPlugin({ title: 'Hello World app', filename: 'html/index.html', template: 'src/html/index.html', inject: true, hash: true }), new ExtractTextPlugin("index.css") ], module: { loaders: [ //.css 文件使用 style-loader 和 css-loader 來處理 { test: /\.less$/, loader: ExtractTextPlugin.extract( 'css?sourceMap!' + 'less?sourceMap' ) }, { test: /\.js$/, loader: 'babel' }, { test: /.(png|jpg)$/, loader: 'url?limit=8192&name=images/[hash:8].[name].[ext]' } ] }, devServer: { contentBase: './dist', hot: true } }
上面只是在開發環境配置的;我們還需要一個線上環境,進行打包,我們還需要使用一個線上環境打包的配置;我們可以新建一個叫webpack.config.prod.js文件; 該文件的配置用於在生產環境的打包;配置代碼如下:
var path = require('path') var webpack = require('webpack'); var HtmlwebpackPlugin = require('html-webpack-plugin'); var ExtractTextPlugin = require('extract-text-webpack-plugin'); module.exports = { devtool: 'source-map', entry: ['./src/js/index','./src/js/a'], output: { path: path.join(__dirname, 'build'), filename: '/js/[name].js' }, plugins: [ new webpack.HotModuleReplacementPlugin(), new HtmlwebpackPlugin({ title: 'Hello World app', filename: 'html/index.html', template: 'src/html/index.html', inject: true, hash: true }), new ExtractTextPlugin("index.css") ], module: { loaders: [ //.css 文件使用 style-loader 和 css-loader 來處理 { test: /\.less$/, loader: ExtractTextPlugin.extract( 'css?sourceMap!' + 'less?sourceMap' ) }, { test: /\.js$/, loader: 'babel' }, { test: /.(png|jpg)$/, loader: 'url?limit=8192&name=images/[hash:8].[name].[ext]' } ] } }
package.json文件代碼如下:
{ "name": "html-webpack-plugin", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "build": "webpack --config webpack.config.prod.js", "dev": "webpack-dev-server --config webpack.config.dev.js" }, "author": "", "license": "ISC", "devDependencies": { "babel-core": "^6.9.1", "babel-loader": "^6.2.4", "css-loader": "^0.23.1", "file-loader": "^0.8.5", "html-webpack-plugin": "^2.19.0", "http-server": "^0.9.0", "less": "^2.7.1", "less-loader": "^2.2.3", "react-hot-loader": "^1.3.0", "style-loader": "^0.13.1", "url-loader": "^0.5.7", "webpack": "^1.13.1", "webpack-dev-server": "^1.14.1" } }
接着我們先運行webpack,就可以在項目的根目錄下生成build文件夾了;
如下圖所示:

為了更方便運行我們在package.json添加如下代碼:
"scripts": {
"build": "webpack --config webpack.config.prod.js",
"dev": "webpack-dev-server --config webpack.config.dev.js"
}
因此如果在開發環境的話,可以運行 npm run dec; 如果是線上的環境,可以運行 npm run build 即可;
但是當我們運行 npm run dev的時候 會出現如下錯誤:

這是因為 默認centos的 hosts 會把本地 127.0.0.1 localhost 注釋掉; 我們可以在我們hosts文件夾下 多加一句
127.0.0.1 localhost
即可;
我們可以參考 https://github.com/Unitech/pm2/issues/324
webpack-dev-server git上的地址: https://github.com/tugenhua0707/webpack-dev-server
10.assets-webpack-plugin插件解決html文件的版本號的問題;
我們上面學習過 html-webpack-plugin 這個插件,它可以自動添加版本號,但是對於很多前端開發的時候,我們的html頁面是放在服務器端那邊的部署,架構是前后端分離,因為html是在后台的,所以根本操作不了html,也不應該耦合。
我們可以通過webpack的 assets-webpack-plugin 插件生成一個記錄了版本號的文件;詳細的可以看官網地址是: https://www.npmjs.com/package/assets-webpack-plugin;
首先我們需要在我們的項目下安裝該插件:安裝命令如下:
npm install assets-webpack-plugin --save-dev
只需要在webpack.config.json添加如下代碼:
// 部分代碼 var AssetsPlugin = require('assets-webpack-plugin'); new AssetsPlugin({ filename: 'build/webpack.assets.js', processOutput: function (assets) { return 'window.WEBPACK_ASSETS = ' + JSON.stringify(assets); } })
我們現在來在webpack.config.js配置項如下
var path = require('path'); var HtmlwebpackPlugin = require('html-webpack-plugin'); var ExtractTextPlugin = require('extract-text-webpack-plugin'); //定義了一些文件夾的路徑 var ROOT_PATH = path.resolve(__dirname); var SRC_PATH = path.resolve(ROOT_PATH, 'src'); var BUILD_PATH = path.resolve(ROOT_PATH, 'build'); var AssetsPlugin = require('assets-webpack-plugin'); module.exports = { entry: { "a": SRC_PATH + "/js/a.js", "index": SRC_PATH + "/js/index.js" }, output: { path: path.join(__dirname, "build"), filename: "js/[name]-[chunkhash:8].js", }, module: { loaders: [ //.css 文件使用 style-loader 和 css-loader 來處理 { test: /\.less$/, loader: ExtractTextPlugin.extract( 'css?sourceMap!' + 'less?sourceMap' ) }, { test: /\.js$/, loader: 'babel' } ] }, resolve: { extensions: ['', '.js', '.jsx'] }, plugins: [ // 內聯css提取到單獨的styles的css new ExtractTextPlugin("css/index.css"), new HtmlwebpackPlugin({ title: 'Hello World app', filename: 'html/index.html', template: 'src/html/index.html', inject: true }), new AssetsPlugin({ filename: 'build/webpack.assets.js', processOutput: function (assets) { return 'window.WEBPACK_ASSETS = ' + JSON.stringify(assets); } }) ] };
然后運行webpack命令進行打包后 如下圖所示:

可以看到在我們的build目錄下的js文件生成a和index帶有版本號的js文件,在build目錄下還生成了一個 webpack.assets.js文件;該文件
代碼如下:
window.WEBPACK_ASSETS = {"a":{"js":"js/a-a7cbb4daad866656445a.js"},
"index":{"js":"js/index-a7cbb4daad866656445a.js"}}
因此我們可以把該webpack.assets.js文件讓開發在頁面上引入即可;
<script src="build/webpack.assets.js?v=' + Math.random() + '"></script>
<script src="' + window.WEBPACK_ASSETS['a'].js + '"></script>
<script src="' + window.WEBPACK_ASSETS['index'].js + '"></script>
我們繼續看 chunkhash:8 的含義:其中8是指hash長度為8,默認是16。加上chunkhash就可以緩存文件;因為每次打包的時候都會自動生成
版本號,但是有些文件並沒有修改的話,我們不需要更改版本號,我們想直接從緩存里面讀取,對於更改的文件我們需要從服務器下載,對於
這樣的 chunkhash 可以解決;比如如下兩次的版本號:
window.WEBPACK_ASSETS = {"a":{"js":"js/a-ac4c0d24.js"},"index":{"js":"js/index-7c5ec642.js"}}
當我更改index.js代碼的時候 a.js代碼沒有更改的話;變成如下:
window.WEBPACK_ASSETS = {"a":{"js":"js/a-ac4c0d24.js"},"index":{"js":"js/index-9a2fec25.js"}}
11.webpack關於同步加載和異步加載的問題
使用webpack打包,直接使用require模塊可以解決模塊的依賴的問題,
對於直接require模塊,WebPack的做法是把依賴的文件都打包在一起,造成文件很臃腫。即是同步加載,同步的代碼會被合成並且打包在一起;
而 異步加載的代碼會被分片成一個個chunk,在需要該模塊時再加載,即按需加載,同步加載過多代碼會造成文件過大影響加載速度;
異步過多則文件太碎,造成過多的Http請求,同樣影響加載速度。這要看開發者自己權衡下;
同步加載的寫法如下:
var aModule = require('./a');
而異步加載的寫法如下:
require.ensure(['./a'],function(require){
var aModule = require('./a');
},'tips');
使用 require.ensure 可以解決異步加載模塊的文件;如上代碼,如果ensure不指定第三個參數的話(tips),那么webpack會隨機生成一個數字
作為模塊名,我們指定第三個參數為tips;那說明生成后的模塊名叫tips.js;
這時候我們需要使用到webpack.config.js中的output選項需要加一個配置項:chunkFilename: "[name].min.js"
下面可以先來理解下 webpack中的output.filename 和output.chunkFilename
比如如下配置代碼:
{ entry: { "index": "pages/index.jsx" }, output: { filename: "[name].min.js", chunkFilename: "[name].min.js" } }
filename應該比較好理解,就是對應於entry里面生成出來的文件名;即會生成 index.min.js文件名;
chunkname的理解是在按需加載(異步)模塊的時候,這樣的文件是沒有被列在entry中的,如使用CommonJS的方式異步加載模塊時候會使用到;
比如如上這要異步加載一個a.js模塊,代碼如下:
require.ensure(['./a'],function(require){
var aModule = require('./a');
},'tips');
指定第三個參數為tips,因此配合output中的 chunkFilename, 即會生成 tips.min.js了;
比如如下所示:

tips.js代碼如下:
webpackJsonp([1],[ /* 0 */, /* 1 */ /***/ function(module, exports) { /* // es6的語法 let LOADER = true; module.exports = LOADER; */ function a() { console.log("a"); console.log(11); console.log(222444); } a(); /***/ } ]);
會通過 webpackJsonp 模塊包裝一下;接着我們在index.js代碼看下,它使如何被調用的;如下片段代碼:
__webpack_require__.e/* nsure */(1, function (require) {
var aModule = __webpack_require__(1);
});
即可引用的到;也就是說如果a.js模塊有1000+行代碼,不會被包含到index.js代碼內,但是index.js代碼有a.js代碼模塊的引用;
可以加載到a.js代碼的內容;
下面是我的webpack.config.js代碼配置如下:
var path = require('path'); var HtmlwebpackPlugin = require('html-webpack-plugin'); var ExtractTextPlugin = require('extract-text-webpack-plugin'); //定義了一些文件夾的路徑 var ROOT_PATH = path.resolve(__dirname); var SRC_PATH = path.resolve(ROOT_PATH, 'src'); var BUILD_PATH = path.resolve(ROOT_PATH, 'build'); var AssetsPlugin = require('assets-webpack-plugin'); module.exports = { entry: { "index": SRC_PATH + "/js/index.js" }, output: { path: path.join(__dirname, "build"), filename: "js/[name]-[chunkhash:8].js", chunkFilename: "js/[name]-[chunkhash:8].js" }, module: { loaders: [ //.css 文件使用 style-loader 和 css-loader 來處理 { test: /\.less$/, loader: ExtractTextPlugin.extract( 'css?sourceMap!' + 'less?sourceMap' ) }, { test: /\.js$/, loader: 'babel' } ] }, resolve: { extensions: ['', '.js', '.jsx'] }, plugins: [ // 內聯css提取到單獨的styles的css new ExtractTextPlugin("css/index.css"), new HtmlwebpackPlugin({ title: 'Hello World app', filename: 'html/index.html', template: 'src/html/index.html', inject: true }), new AssetsPlugin({ filename: 'build/webpack.assets.js', processOutput: function (assets) { return 'window.WEBPACK_ASSETS = ' + JSON.stringify(assets); } }) ] };
index.js代碼異步調用a.js模塊的代碼如下:
require.ensure(['./a'],function(require){
var aModule = require('./a');
},'tips');
更多的配置項 看官網 http://webpack.github.io/docs/code-splitting.html
