自從出現模塊化之後,你們能夠將本來一坨代碼分離到個個模塊中,可是由此引起了一個問題。每一個 JS 文件都須要從服務器去拿,由此會致使加載速度變慢。Webpack 最主要的目的就是爲了解決這個問題,將全部小文件打包成一個或多個大文件,官網的圖片很好的詮釋了這個事情,除此以外,Webpack 也是一個能讓你使用各類前端新技術的工具。css
webpack一共經歷了4個版本,分別是一、二、三、4,最新版本是4,如下案例是基於4實踐的html
——自來《深刻淺出webpack》前端
全局安裝webpackvue
npm install -g webpack
複製代碼
局部安裝webpacknode
npm install --save-dev webpack
複製代碼
webpack -p 執行一次生成環境的編譯(壓縮)
webpack --watch 在開發時持續監控增量編譯(很快)
webpack -d 讓他生成SourceMaps
webpack --progress 顯示編譯進度
webpack --colors 顯示靜態資源的顏色
webpack --sort-modules-by, --sort-chunks-by, --sort-assets-by 將modules/chunks/assets進行列表排序
webpack --display-chunks 展現編譯後的分塊
webpack --display-reasons 顯示更多引用模塊緣由
webapck --display-error-details 顯示更多報錯信息
複製代碼
配置模塊的入口jquery
Entry參數說明,類型能夠是如下三種中的一種或者相互組合webpack
類型 | 例子 | 含義 |
---|---|---|
string | './app/entry' | 入口模塊的文件路徑,能夠相對路徑 |
array | ['./app/entry1','./app/entry2'] | 入口模塊的文件路徑,能夠是相對路徑 |
object | {a:['./app/entry-a'],b:['./app/entry-b1','./app/entry-b2']} | 配置多個入口,每一個入口生成一個chunk |
配置如何輸出最終想要的代碼git
output是一個object,裏面包含一系列配置項
output.filename:'[name].js' //輸出文件的名稱
也可使用hash、chunkhash、contenthash來命名,關於hash、chunkhash、contenthash區別能夠參考https://www.cnblogs.com/tugenhua0707/p/9615822.html#_labe1_2
output.chunkFilename://chunkFilename 和上面的 filename 很是相似,但 chunkFilename 只用於指定在運行過程當中生成的 Chunk 在輸出時的文件名稱,vue按需加載就可使用這個參數
output.path:path .resolve( dirname, ’ dist [hash]’) //path 配置輸出文件存放在本地的目錄
output.publicPath:'https://cdn.example.com/assets/' //配置發佈到線上資源的 URL 前綴
output.libraryTarget://配置以何種方式導出庫,可選值var、commonjs、commonjs二、this、window、global
output.library://配置導出庫的名稱。
output.libraryExport: 配置要導出的模塊中哪些子模塊須要被導出
複製代碼
3.1 rulesgithub
rules 配置模塊的讀取和解析規則,一般用來配置 Loader。大體能夠經過如下方式來完成web
條件匹配:經過 test、 include、 exclude 三個配置項來選中 Loader 要應用 規則的文件。
應用規則:對選中的文件經過 use 配置項來應用 Loader,能夠只應用一個 Loader或者按照從後往前的順序應用一組 Loader,同時能夠分別向 Loader傳入參數。
重置順序:一組 Loader 的執行順序默認是從右到左執行的,經過 enforce 選項能夠將其中 一個 Loader 的執行順序放到最前或者最後 。
具體方法:
module:{
rules:[
{
//命中 JavaScript 文件
test: /\.js$/,
//用 babel-loader 轉換 JavaScript 文件
//?cacheDirectory 表示傳給 babel-loader 的參數,用於緩存 babel 的編譯結果,
use : [’ babel-loader?cacheDirectory ’],
//只命中 src 目錄裏的 JavaScript 文件,加快 Webpack 的搜索速度
include: path.resolve( dirname, ’ src ’)
},
{
//命中scss文件
test:/\.scss$/,
//使用一組loader去處理scss文件
//處理順序爲從後到前,即先交給 sass-loader處理,再將結果交給 css-loader,最後交給 style-loader
use:['style-loader','css-loader','sass-loader'],
//排除node_modules目錄下的文件
exclude: path.resolve( dirname, ’ node modules ’)
},
{
//對非文件採用file-loader加載
test:/\.(gif|png|jpe?g|eot|woff|ttf|svg|pdf)$/,
use:['file-loader']
}
]
}
複製代碼
3.2 noParse
配置項可讓Webpack忽略對部分沒采用模塊化的文件的遞歸解析和處理,這樣作的好處能提升構建性能。
//使用正則表達式
noParse: /jquerylchartjs/
複製代碼
注意,被忽略的文件裏不該該包含 import、 require、 define 等模塊化 語句,不 然會致使在構建出的代碼中包含沒法在瀏覽器環境下執行的模塊化語句 。
3.3. parse
parser 屬性能夠更細粒度地配置 哪些模塊語法被解析、哪些不被解析。同 noParse 配置項的區別在於, parser 能夠精確到 語法層 面,而 noParse 只能控制哪些文件不被解析。
parser 的使用方法以下:
module: {
rules : [
{
test: /\.js♀/,
use: [ ’ babel-loader ’],
parser: {
amd: false, //禁用AMD
commonjs : false , //禁用 CommonJS
system : false, //禁用 SystemJS
harmony: false, //禁用 ES6 import/export
requireinclude:false, //禁用require.include
requireEnsure: false, //禁用require.ensure
requireContext:false, //禁用require.context
browserify: false, //禁用 browserify requireJs : false, //禁用 requirejs:false
requireJs : false, //禁用 requirejs
}
}
]
}
複製代碼
配置尋找模塊的規則
4.1. alias
配置項經過別名來將原導入路徑映射成一個新的導入路徑
resolve:{
alias:{
components:'./src/components/'
}
}
複製代碼
4.2. mainFields
會根據 mainFields 的配 置去決定 優先採用哪份代碼,
mainFields : [’jsnext:main’,’browser’,’main’]
複製代碼
4.3. extensions
Webpack 會自動帶上後綴後去嘗試訪問文件是否存在。 resolve.extensions 用於配置在嘗試過程當中用到的後綴列表
extensions:[’.ts’,’.j5 ’,’.json’]
複製代碼
配置擴展插件
plugins配置項接收一個數組,數組裏的每一項都是一個要使用 的 Plugin 的實例, Plugin 須要的參數經過構造函數傳入,mini-css-extract-plugin、clean-webpack-plugin、DllReferencePlugin、html-webpack-plugin、happyPack、webpack-parallel-uglify-plugin
const ClearWebpackPlugin = require('clean-webpack-plugin');
module.exports=[
plugins:[
new ClearWebpackPlugin(['dist'])
]
];
複製代碼
hot,開啓模塊熱替換功能後,將在不刷新整個頁面的狀況下經過用新模塊替換老模塊來作到實時預覽
inline,依賴一個注入頁面裏的代理客戶端,去接收來自 DevServer的 命令並負責刷新網頁的工做。
contentBase,配置 DevServerHTTP服務器的文件根目錄
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const ClearWebpackPlugin = require('clean-webpack-plugin');
const DllReferencePlugin = require('webpack/lib/DllReferencePlugin');
const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
const HappyPack = require('happypack');
module.exports = {
entry: './app/index/app.js', //支持多個參數,string|array|object
output: {
filename: ' [name].js', //輸出文件名稱
path: path.resolve(__dirname, './dist'), //輸出文件的目標路徑
publicPath: '/' //構建文件的輸出目錄
},
devServer: { //DevServer相關的配置
contentBase: path.join(__dirname, 'dist'),
compress: true, //壓縮
port: 8888, //端口號
open: true, //第一次打開瀏覽器
hot: true, //是否監聽
publicPath: "/" //訪問的目錄
},
module: {
rules: [{
test: /\.js$/,
use: [' babel-loader'],
parser: {
amd: true, //禁用AMD
commonjs: true, //禁用 CommonJS
system: false, //禁用 SystemJS
harmony: true, //禁用 ES6 import/export
requireinclude: false, //禁用require.include
requireEnsure: false, //禁用require.ensure
requireContext: false, //禁用require.context
browserify: false, //禁用 browserify requireJs : false, //禁用 requirejs:false
requireJs: false, //禁用 requirejs
}
},
{
// 用正則去匹配要用該 loader 轉換的 CSS 文件
test: /\.css$/,
use: [{
loader: MiniCssExtractPlugin.loader,
}, {
loader: path.resolve('./loaders.js'),
options: {
test: 1
}
}, {
loader: 'css-loader?minimize',
}, {
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: [
require('postcss-cssnext')(),
require('cssnano')(),
require('postcss-sprites')()
]
}
}],
}, {
//圖片處理
test: /\.(png|svg|jpg|gif)$/,
use: [{
loader: 'url-loader',
options: {
limit: 10000,
name: '[name].[ext]'
}
}]
}
]
},
resolve: {
modules: [
// 模塊的查找目錄
"node_modules",
path.resolve(__dirname, "app")
],
extensions: ['.js', '.json', '.vue', '.css'],
alias: { //模塊別名列表
'module': 'new-module'
}
},
devtool: 'source-map', //sourcemap
plugins: [ //插件部分
new ClearWebpackPlugin(['dist']),
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
filename: `[name]_[contenthash:8].css`,
chunkFilename: '[name]_[contenthash:8].css'
}),
// 告訴webpack使用了哪些第三方庫代碼
new DllReferencePlugin({
// jquery 映射到json文件上去
manifest: require('./dill/jquery.manifest.json')
}),
new ParallelUglifyPlugin({
// 傳遞給 UglifyJS的參數以下:
uglifyJS: {
output: {
/*
是否輸出可讀性較強的代碼,即會保留空格和製表符,默認爲輸出,爲了達到更好的壓縮效果,
能夠設置爲false
*/
beautify: false,
/*
是否保留代碼中的註釋,默認爲保留,爲了達到更好的壓縮效果,能夠設置爲false
*/
comments: false
},
compress: {
/*
是否在UglifyJS刪除沒有用到的代碼時輸出警告信息,默認爲輸出,能夠設置爲false關閉這些做用
不大的警告
*/
warnings: false,
/*
是否刪除代碼中全部的console語句,默認爲不刪除,開啓後,會刪除全部的console語句
*/
drop_console: true,
/*
是否內嵌雖然已經定義了,可是隻用到一次的變量,好比將 var x = 1; y = x, 轉換成 y = 5, 默認爲不
轉換,爲了達到更好的壓縮效果,能夠設置爲false
*/
collapse_vars: true,
/*
是否提取出現了屢次可是沒有定義成變量去引用的靜態值,好比將 x = 'xxx'; y = 'xxx' 轉換成
var a = 'xxxx'; x = a; y = a; 默認爲不轉換,爲了達到更好的壓縮效果,能夠設置爲false
*/
reduce_vars: true
}
}
}),
//將js自動插入到html裏
new HtmlWebpackPlugin({
template: './views/index.html',
filename: 'index.html',
}),
new webpack.HotModuleReplacementPlugin() //引入熱更新插件
]
};
複製代碼
優化主要是針對打包速度跟打包大小優化,主要包含如下方面
threads:開啓幾個子進程去處理這一類型的文件,默認是3個,必須整數
verbose:是否容許happypack輸出日誌,默認是true
threadpool:表明共享進程池,即多個happypack實例都使用同一個共享進程池中的子進程去處理任務,以防止資源佔用過多
複製代碼
介紹DllPlugin插件跟DllReferencePlugin插件
DllPlugin插件 : 用於打包出一個個單獨的動態連接庫文件 。 DllReferencePlugin 插件:用於在主要的配置文件中引入 DllP!ugin 插件打包好的動態連接庫文件。
具體配置以下:
webpack.dll.config.js配置
const path = require('path');
const DllPlugin = require('webpack/lib/DllPlugin');
module.exports = {
// 入口文件
entry: {
// 項目中用到該兩個依賴庫文件
jquery: ['./libs/jquery'],
// echarts: ['echarts']
},
// 輸出文件
output: {
// 文件名稱
filename: '[name].dll.js',
// 將輸出的文件放到dist目錄下
path: path.resolve(__dirname, 'dill'),
/*
存放相關的dll文件的全局變量名稱,好比對於jquery來講的話就是 _dll_jquery, 在前面加 _dll
是爲了防止全局變量衝突。
*/
library: '_dll_[name]'
},
plugins:[
// 使用插件 DllPlugin
new DllPlugin({
/*
該插件的name屬性值須要和 output.library保存一致,該字段值,也就是輸出的 manifest.json文件中name字段的值。
好比在jquery.manifest文件中有 name: '_dll_jquery'
*/
name: '_dll_[name]',
/* 生成manifest文件輸出的位置和文件名稱 */
path: path.join(__dirname, 'dill', '[name].manifest.json')
})
]
};
複製代碼
webpack.config.js配置
const DllReferencePlugin = require('webpack/lib/DllReferencePlugin');
{
plugins:
[
// 告訴webpack使用了哪些第三方庫代碼
new DllReferencePlugin({
// jquery 映射到json文件上去
manifest: require('./dill/jquery.manifest.json')
})
]
}
複製代碼
1.1 webpack事件流
Webpack 就像一條生產線,要通過一系列處理流程後才能將源文件轉換成輸出結果。 這條生產線上的每一個處理流程的職責都是單一的,多個流程之間有存在依賴關係,只有完成當前處理後才能交給下一個流程去處理。 插件就像是一個插入到生產線中的一個功能,在特定的時機對生產線上的資源作處理。 Webpack 經過 Tapable 來組織這條複雜的生產線。 Webpack 在運行過程當中會廣播事件,插件只須要監聽它所關心的事件,就能加入到這條生產線中,去改變生產線的運做。 Webpack 的事件流機制保證了插件的有序性,使得整個系統擴展性很好。
1.2 webpack運行流程詳解
Webpack 的運行流程是一個串行的過程,從啓動到結束會依次執行如下流程。
流程圖:
2.3 抽象語法樹(AST)
在計算機科學中,抽象語法樹(Abstract Syntax Tree,AST),或簡稱語法樹(Syntax tree),是源代碼語法結構的一種抽象表示。它以樹狀的形式表現編程語言的語法結構,樹上的每一個節點都表示源代碼中的一種結構。之因此說語法是「抽象」的,是由於這裏的語法並不會表示出真實語法中出現的每一個細節。好比,嵌套括號被隱含在樹的結構中,並無以節點的形式呈現;而相似於 if-condition-then 這樣的條件跳轉語句,可使用帶有兩個分支的節點來表示。
實際上一段代碼通過編譯器的詞分析、語法分析等階段以後,會生成一個樹狀結構的「抽象語法樹(AST)」,該語法樹的每個節點都對應着代碼當中不一樣含義片斷。
解釋器是將AST翻譯成目標語言並運行的工具。
插件代碼
//@file: plugins/myplugin.js
class myPlugin {
constructor(options){
//用戶自定義配置
this.options = options
console.log(this.options)
}
apply(compiler) {
console.log("This is my first plugin.")
}
}
module.exports = myPlugin
複製代碼
webpack代碼
const MyPlugin = require('./plugins/myplugin-4.js')
module.exports = {
......,
plugins: [
new MyPlugin("Plugin is instancing.")
]
}
複製代碼
具體參數能夠參考《深刻淺出webpack》
require (’ loader-utils ’);
callback
具體參數能夠參考《深刻淺出webpack》
const loaderUtils = require('loader-utils');
module.exports = function (content) {
// 獲取用戶配置的options 同步
const options=loaderUtils.getOptions(this);
console.log('***options***',options);
this.callback(null,'{}'+content);
return '{};'+content;
}
複製代碼
{
test: /\.js$/,
exclude: /node_modules/,
use: {
//這裏是個人自定義loader的存放路徑
loader: path.resolve('./loaders/index.js'),
options: {
test: 1
}
}
}
複製代碼
webpack打包配置相對比較複雜,目前介紹應該能夠滿常規需求。
參考資料:
《深刻淺出webpack》
歡迎關注github