引言 我們來看看主要作用: 為html文件中引入的外部資源如script、link動態添加每次compile後的hash,防止引用緩存的外部文件問題 可以生成創建html入口文件,比如單頁面可以生成一個html文件入口,配置N個html-webpack-plugin可以生成N個頁面入口 html-w ...
引言
我們來看看主要作用:
為html文件中引入的外部資源如script
、link
動態添加每次compile後的hash,防止引用緩存的外部文件問題
可以生成創建html入口文件,比如單頁面可以生成一個html文件入口,配置N個html-webpack-plugin
可以生成N個頁面入口
html-webpack-plugin
插件的基本作用就是生成html文件。原理很簡單:
將 webpack中
`entry`配置的相關入口chunk 和
`extract-text-webpack-plugin`抽取的css樣式 插入到該插件提供的
`template`或者
`templateContent`配置項指定的內容基礎上生成一個html文件,具體插入方式是將樣式
`link`插入到
`head`元素中,
`script`插入到
`head`或者
`body`中。
實例化該插件時可以不配置任何參數,例如下麵這樣:
var HtmlWebpackPlugin = require('html-webpack-plugin') webpackconfig = { plugins: [ new HtmlWebpackPlugin() ] }
不配置任何選項的html-webpack-plugin
插件,他會預設將webpack中的entry
配置所有入口thunk和extract-text-webpack-plugin
抽取的css樣式都插入到文件指定的位置。例如上面生成的html文件內容如下:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Webpack App</title> <link href="index-af150e90583a89775c77.css" rel="stylesheet"></head> <body> <script type="text/javascript" src="common-26a14e7d42a7c7bbc4c2.js"></script> <script type="text/javascript" src="index-af150e90583a89775c77.js"></script></body> </html>
當然可以使用具體的配置項來定製化一些特殊的需求,那麼插件有哪些配置項呢?
html-webpack-plugin配置項
插件提供的配置項比較多,通過源碼可以看出具體的配置項如下:
1 this.options = _.extend({ 2 template: path.join(__dirname, 'default_index.ejs'), 3 templateParameters: templateParametersGenerator, 4 filename: 'index.html', 5 hash: false, 6 inject: true, 7 compile: true, 8 favicon: false, 9 minify: false, 10 cache: true, 11 showErrors: true, 12 chunks: 'all', 13 excludeChunks: [], 14 chunksSortMode: 'auto', 15 meta: {}, 16 title: 'Webpack App', 17 xhtml: false 18 }, options);
title
: 生成的html文檔的標題。配置該項,它並不會替換指定模板文件中的title元素的內容,除非html模板文件中使用了模板引擎語法來獲取該配置項值,如下ejs模板語法形式:
<title>{%= o.htmlWebpackPlugin.options.title %}
</title>
filename
:輸出文件的文件名稱,預設為index.html,不配置就是該文件名;此外,還可以為輸出文件指定目錄位置(例如'html/index.html')
關於filename補充兩點:
1、filename配置的html文件目錄是相對於webpackConfig.output.path路徑而言的,不是相對於當前項目目錄結構的。
2、指定生成的html文件內容中的link
和script
路徑是相對於生成目錄下的,寫路徑的時候請寫生成目錄下的相對路徑。
template
: 本地模板文件的位置,支持載入器(如handlebars、ejs、undersore、html等),如比如 handlebars!src/index.hbs
;
關於template補充幾點:
1、template配置項在html文件使用file-loader
時,其所指定的位置找不到,導致生成的html文件內容不是期望的內容。
2、為template指定的模板文件沒有指定任何loader的話,預設使用ejs-loader
。如template:
'./index.html'
,若沒有為.html
指定任何loader就使用ejs-loader
templateContent: string|function,可以指定模板的內容,不能與template共存。配置值為function時,可以直接返回html字元串,也可以非同步調用返回html字元串。
inject
:向template或者templateContent中註入所有靜態資源,不同的配置值註入的位置不經相同。
1、true或者body:所有JavaScript資源插入到body元素的底部
2、head:
所有JavaScript資源插入到head元素中
3、false: 所有靜態資源css和JavaScript都不會註入到模板文件中
favicon
: 添加特定favicon路徑到輸出的html文檔中,這個同title
配置項,需要在模板中動態獲取其路徑值
hash
:true|false,是否為所有註入的靜態資源添加webpack每次編譯產生的唯一hash值,添加hash形式如下所示:
html <script
type="text/javascript"
src="common.js?a3e1396b501cdd9041be"></script>
chunks
:允許插入到模板中的一些chunk,不配置此項預設會將entry
中所有的thunk註入到模板中。在配置多個頁面時,每個頁面註入的thunk應該是不相同的,需要通過該配置為不同頁面註入不同的thunk;
excludeChunks
: 這個與chunks
配置項正好相反,用來配置不允許註入的thunk。
chunksSortMode
: none |
auto| function,預設auto; 允許指定的thunk在插入到html文檔前進行排序。
>function值可以指定具體排序規則;auto基於thunk的id進行排序; none就是不排序
xhtml
: true|fasle, 預設false;是否渲染link
為自閉合的標簽,true則為自閉合標簽
cache
: true|fasle, 預設true; 如果為true表示在對應的thunk文件修改後就會emit文件
showErrors
:
true|false,預設true;是否將錯誤信息輸出到html頁面中。這個很有用,在生成html文件的過程中有錯誤信息,輸出到頁面就能看到錯誤相關信息便於調試。
minify
:
{....}|false;傳遞
html-minifier 選項給 minify 輸出,false就是不使用html壓縮,minify具體配置參數請點擊html-minifier
下麵的是一個用於配置這些屬性的一個例子:
new HtmlWebpackPlugin({ title:'rd平臺', template: 'src/index.html', // 源模板文件 filename: './index.html', // 輸出文件【註意:這裡的根路徑是module.exports.output.path】 showErrors: true, inject: 'body', chunks: ["common",'index'] })
配置多個html頁面
html-webpack-plugin
的一個實例生成一個html文件,如果單頁應用中需要多個頁面入口,或者多頁應用時配置多個html時,那麼就需要實例化該插件多次;
即有幾個頁面就需要在webpack的plugins數組中配置幾個該插件實例:
…… plugins: [ new HtmlWebpackPlugin({ template: 'src/html/index.html', excludeChunks: ['list', 'detail'] }), new HtmlWebpackPlugin({ filename: 'list.html', template: 'src/html/list.html', thunks: ['common', 'list'] }), new HtmlWebpackPlugin({ filename: 'detail.html', template: 'src/html/detail.html', thunks: ['common', 'detail'] }) ] ...
如上例應用中配置了三個入口頁面:index.html、list.html、detail.html;並且每個頁面註入的thunk不盡相同;類似如果多頁面應用,就需要為每個頁面配置一個;
配置自定義的模板
不帶參數的html-webpack-plugin
預設生成的html文件只是將thunk和css樣式插入到文檔中,可能不能滿足我們的需求;
另外,如上面所述,三個頁面指定了三個不同html模板文件;在項目中,可能所有頁面的模板文件可以共用一個,因為html-webpack-plugin
插件支持不同的模板loader,所以結合模板引擎來共用一個模板文件有了可能。
所以,配置自定義模板就派上用場了。具體的做法,藉助於模板引擎來實現,例如插件沒有配置loader時預設支持的ejs模板引擎,下麵就以ejs模板引擎為例來說明;
例如項目中有2個入口html頁面,它們可以共用一個模板文件,利用ejs模板的語法來動態插入各自頁面的thunk和css樣式,代碼可以這樣:
<!DOCTYPE html> <html style="font-size:20px"> <head> <meta charset="utf-8"> <title><%= htmlWebpackPlugin.options.title %></title> <% for (var css in htmlWebpackPlugin.files.css) { %> <link href="<%=htmlWebpackPlugin.files.css[css] %>" rel="stylesheet"> <% } %> </head> <body> <div id="app"></div> <% for (var chunk in htmlWebpackPlugin.files.chunks) { %> <script type="text/javascript" src="<%=htmlWebpackPlugin.files.chunks[chunk].entry %>"></script> <% } %> </body> </html>
你可能會對代碼中的上下文htmlWebpackPlugin
數據感到迷惑,這是啥東東?其實這是html-webpack-plugin
插件在生成html文件過程中產生的數據,這些數據對html模板文件是可用的,並且我們看<%%>是不是給java裡面的jsp差不多了。
自定義模板上下文數據
html-webpack-plugin
在生成html文件的過程中,插件會根據配置生成一個對當前模板可用的特定數據,模板語法可以根據這些數據來動態生成html文件的內容。
那麼,插件生成的特殊數據格式是什麼,生成的哪些數據呢?從源碼或者其官網都給出了答案。從源碼中可以看出模板引擎具體可以訪問的數據如下:
var templateParams = { compilation: compilation, webpack: compilation.getStats().toJson(), webpackConfig: compilation.options, htmlWebpackPlugin: files: assets, options: self.options } };
從中可以看出,有四個主要的對像數據。其中compilation
為所有webpack插件提供的都可以訪問的一個編譯對象,此處就不太做介紹,具體可以自己查資料。下麵就對剩下的三個對象數據進行說明。
webpack
webpack的stats對象
;註意一點:
這個可以訪問的stats
對象是htm文件生成時所對應的stats
對象,而不是webpack運行完成後所對應的整個stats
對象。
webpackConfig
webpack的配置項
;通過這個屬性可以獲取webpack的相關配置項,如通過webpackConfig.output.publicPath
來獲取publicPath
配置。當然還可以獲取其他配置內容。
htmlWebpackPlugin
html-webpack-plugin
插件對應的數據。它包括兩部分:
htmlWebpackPlugin.files
: 此次html-webpack-plugin插件配置的chunk和抽取的css樣式該files值其實是webpack的stats對象的assetsByChunkName
屬性代表的值,該值是插件配置的chunk塊對應的按照webpackConfig.output.filename
映射的值。例如對應上面配置插件各個屬性配置項例子中生成的數據格式如下:
"htmlWebpackPlugin": {
"files": {
"css": [ "inex.css" ],
"js": [ "common.js", "index.js"],
"chunks": {
"common": {
"entry": "common.js",
"css": [ "index.css" ]
},
"index": {
"entry": "index.js",
"css": ["index.css"]
}
}
}
}
這樣,就可以是用如下模板引擎來動態輸出script腳本
<% for (var chunk in htmlWebpackPlugin.files.chunks) { %> <script type="text/javascript" src="<%=htmlWebpackPlugin.files.chunks[chunk].entry %>"></script> <% } %>
htmlWebpackPlugin.options
: 傳遞給插件的配置項,具體的配置項如上面插件配置項小節所描述的。
插件事件
不知道你發現沒有,html-webpack-plugin插件在插入靜態資源時存在一些問題:
- 在插入js資源只能插入head或者body元素中,不能一些插入head中,另一些插入body中
- 不支持在html中文件內聯*,例如在文件的某個地方用
<script src="xxx.js?__inline"></script>
來內聯外部腳本
為此,有人專門給插件作者提問了這個問題;對此插件作者提供了插件事件,允許其他插件來改變html文件內容。具體的事件如下:
Async(非同步事件):
* html-webpack-plugin-
before-html-generation
* html-webpack-plugin-
before-html-processing
* html-webpack-plugin-alter-asset-tags
* html-webpack-plugin-after-html-processing
* html-webpack-plugin-after-emit
Sync(同步事件):
* html-webpack-plugin-alter-chunks
這些事件是提供給其他插件使用的,用於改變html的內容。因此,要用這些事件需要提供一個webpack插件。例如下麵定義的MyPlugin
插件。
function MyPlugin(options) { // Configure your plugin with options... } MyPlugin.prototype.apply = function(compiler) { // ... compiler.plugin('compilation', function(compilation) { console.log('The compiler is starting a new compilation...'); compilation.plugin('html-webpack-plugin-before-html-processing', function(htmlPluginData, callback) { htmlPluginData.html += 'The magic footer'; callback(null, htmlPluginData); }); }); };
module.exports = MyPlugin;
然後,在webpack.config.js
文件中配置Myplugin
信息:
plugins: [ new MyPlugin({options: ''}) ]