Webpack現今流行的前端打包工具,今兒本人也來分享下自己學習體驗。
一、html-webpack-plugin
實現html模板文件的解析與生成
- 在plugins加入HtmlWebpackPlugin的配置,如果是多個入口文件,則需要對應加入多個HtmlWebpackPlugin功能。
var HtmlWebpackPlugin = require('html-webpack-plugin'); entry:{ ma: './src/ma', /** .:必須要,表示運行時的根目錄,否則找不到文件,且不報錯 */ mb: './src/mb' }, output: { path: './dist', filename: '[name].js' }, plugins: [ new HtmlWebpackPlugin({ //可以模板,直接引用files對象,是webpack中state對象 title: '模板A', chunks: ['ma'] }), new HtmlWebpackPlugin({ filename: 'mb.html', title: '模板B', chunks: ['mb'] }) ]
如上代碼所示:
- 兩個入口文件,ma與mb,所以配置了兩個HtmlWebpackPlugin實例
- HtmlWebpackPlugin實例配置項:
- title:模板title
- filename:輸出的html文件名稱
- chunks:包含的文件,可以entry和其他模塊chunk的模塊,插件導入到 模板時 沒有排序,但都是。
- excludeChunks:被排除的模塊
- chunksSortMode:添加到頁面時模塊的排序 none|default|function
- template:模板文件路徑所在位置
- templateContent:一個函數,使用編程語言創建模板
- inject:js插入位置:body, head
- 模板可以訪問的配置項
- files:為webpack的stats項,可以在模板文件中使用或者
- webpackConfig:webpackConfig的配置項
- options:在模板文件中可以獲取的webpack配置項。
- HtmlWebpackPlugin的事件使用:
事件名稱 | 時機 | 同步/異步 |
html-webapck-plugin-before-html-generation | 生成htmlPluginData之前觸發 | async |
html-webpack-plugin-before-html-processing | htmlPluginData插入到html模板之前觸發 | async |
html-webpack-plugin-alert-asset-tags | 驗證資源,以及為資源做標記時觸發 | async |
html-webpack-plugin-after-html-processing | htmlPluginData插入到html模板之后觸發 | async |
html-webpack-plugin-after-emit | 生成html目標文件后觸發 | async |
html-webpack-plugin-alert-chunks | 驗證資源塊信息 | sync |
var compile = webpack(config); compile.plugin('compilation', function( compilation, callbak) { console.log('compilation'); compilation.plugin('html-webpack-plugin-before-html-processing', function (htmlPluginData, callbak) { console.log(htmlPluginData) callbak() }) })
注意:
- 必須要監測compile的compilation事件
- 然后在回調compilation事件時,對compilation參數進行plugin的事件的注冊 。
二、webpack.optimize.CommonsChunkPlugin
抽取公共模塊為一個獨立的文件,一是指定的多個模塊打成一個包;二是在指定的chunks中抽取公共模塊
參數名稱 | 說明 |
name | 可以是字符串,或者是數組,如果指定為entry中一個名稱,則只產生此vendor,也可以是一個入口文件列表 |
filename | 輸出文件名 |
minChunks | 單獨文件最小引用數,如設置3,表示同一個模塊只有被3個以外的頁面引用時才打包 |
children | 返回,把第三方的vendor包,分解到業務包中 |
chunks | 數組,從指定的源模塊提供共用vendor包 |
1. vendor打成一個包:
entry:{ vendor: ['./src/vendor-jquery', 'bootstrap'] }, plugins: [ new webpack.optimize.CommonsChunkPlugin({ name: 'vendor' }) ]
2. CommonsChunkPlugin正確的引入方式
3. 用manifest實現js庫的增量更新
如果輸出文件名包含hash值,需要引入以下兩個插件:
- HashedModuleIdsPlugin:算hash值
- 利用CommonsChunkPlugin配置,他是manifest配置模塊所有的依賴抽象,如果mainfest不更新,則html會找不到js文件。
new webpack.optimize.CommonsChunkPlugin({ name: 'manifest', chunks: ['vendor'] })
三、webpack 樣式打包
這其中就包含對css文件、靜態資源以及css所包含的資源文件等處理。
- css-loader:解析css代碼
- style-loader:css代碼寫入到js文件中
- 配置代碼如下:
loaders:[ { test:/\.css$/, /*不能加引號*/ loader: 'style-loader!css-loader' } ]
注意:test后面不能加引號,因這個是正則式
1. 樣式文件單獨存在,但不能處理靜態資源
extract-text-webpack-plugin:抽取樣式為單獨的文件
- 參數配置說明
- ExtractTextPlugin.extract(arg1,arg2,arg3)
- arg1: 可選參數,傳入一個loader,當css沒有被抽取的時候可以使用該loader
- arg2:必填參數,用於編譯解析css文件的loader
- arg3:額外選,暫只可傳publicPath,表示當前loader的路徑
- ExtactTextPlugin在Plugins中構造時,至少需要傳入一個文件名參數
filename文件名,可以指定一個固定的,也可用[name].[id].[contenthash]來指定文件名,[name]:與entry中的chunk名稱一致,[id]:將entry的chunk的id一致;[contenthash]:根據內容生成hash值
參數名稱 | 說明 |
id | 可先參數,插件實例的惟一標識,缺省會自動生成 |
filename |
文件名,可以指定一個固定的,也可用[name].[id].[contenthash]來指定文件名,[name]:與entry中的chunk名稱一致,[id]:將entry的chunk的id一致;[contenthash]:根據內容生成hash值 |
options | allchunks:是否將所有額外的chunk都壓縮一個文件;disable:禁止使用此插件 |
代碼如下(webpack2.x):
var ExtractTextPlugin = require('extract-text-webpack-plugin'); module:{ loaders:[ { test:/\.css$/, loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader' }) } ] }, plugins: [ new ExtractTextPlugin('[name].css') ]
2. file-loader實現css中圖片或web字體文件打包
var ExtractTextPlugin = require('extract-text-webpack-plugin'); module:{ loaders:[ { test:/\.css$/, loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: ['css-loader','postcss-loader'] }) }, { test: /\.(eot|svg|ttf|woff|woff2)$/, loader: 'file-loader?name=fonts/[name].[ext]' } ] }
參數說明:
參數名稱 | 說明 |
name | 配置輸出文件名,例如:name=[name].[hash].[ext] |
name子節點配置說明 | |
[ext] | 擴展名 |
[name] | 文件名 |
[path] | 相對於上下文的路徑 |
[hash] | hash值 |
輸出配置參數 | |
publicPath | 公共資源路徑(也可以說是靜態資源,就是不參與打包的編譯過程的資源) |
outputPath | 輸出資源路徑(也可以說是靜態資源,就是不參與打包的編譯過程的資源) |
publicPath和outputPath使用示例代碼:
use: "file-loader?name=[name].[ext]&publicPath=assets/foo/&outputPath=app/images/"
3. postcss實現瀏覽器兼容
代碼如下(webpack2.x):
var autoprefixer = require('autoprefixer'); module:{ loaders:[ { test:/\.css$/, loader: ExtractTextPlugin.extract({ use: ['css-loader','postcss-loader'] }) } ] }, plugins: [ new webpack.LoaderOptionsPlugin({ options:{ postcss:[autoprefixer()] } }) ]
- webpack2.x不支持自定義配置節點,需要用webpack.LoaderOptionsPlugin加入自定義的插件配置節點。
- autoprefixer:一個postcss的插件,用於css3的兼容前端處理
-
- browsers:配置瀏覽器的版本,如:browsers:['last 2 versions']
四、熱更新
- 安裝 webpack-dev-server
- 熱更新的概念
利用websocket實現,websocket-server識別到html、css和js的改變,就向websocket-client發送一個消息,websocket-client判斷如果是html和css就操作dom,實現局部刷新,如果是js就整體刷新。
- 配置:
var config = require('./webpack.base.conf'); var webpack = require("webpack"); var WebpackDevServer = require('webpack-dev-server'); var compile = webpack(config); compile.plugin('compilation', function( compilation, callbak) { compilation.plugin('html-webpack-plugin-before-html-processing', function (htmlPluginData, callbak) { callbak() }) }) var isProc = true; if(isProc){ compile.run(function(err,state){ console.log(err); }) }else{ var server = new WebpackDevServer(compile,{ contentBase: './build', hot: true, inline: true, /*無效*/ historyApiFallback: true }); server.listen(8080); }
說明:
- hot:啟動熱更新
- inline:是不會自動刷新網頁的,因為此參數只能在cli環境下用
- 在cli下實現頁面自動刷新
webapck-dev-server --hot --inline --config=配置文件
無--inline時,只能在iframe模式下自動刷新:http://localhost:8080/webpack-dev-server/index.html
有--inline時,可以直接訪問http://localhost:8080/index.html
進行自動刷新
五、cross-env
實現環境變量的定義
"prod": "cross-env NODE_ENV=prod node ./build/dev-server.js",
"dev": "cross-env NODE_ENV=dev node ./build/dev-server.js"
六、示例代碼結構說明
前五節說了這么多,也許讓你聽得雲里霧里的。沒有代碼來說明程序是多么枯燥啊(聲明:此代碼還包含后一章節的單元測試和e2e測試的配置)。代碼結構圖以及源碼下載地址:
- build:打包配置文件
- dev-server.js:打包運行入口
- webpack.base.conf.js:打包plugins節點的配置
- webpack.core.conf.js:打包module以及entry的基本配置
- src:源碼目錄
- test:測試目錄
- e2e:點到點測試
- unit:單元測試
- mocks:mockjs模擬數據