Webpack 進階用法

Webpack 進階用法

當前構建時的問題

  • 每次構建的時候不會清理目錄,造成構建的輸出目錄output文件越來越多

通過npm script清理構建目錄(並不優雅的處理方式)

  • rm -rf ./dist && webpack
  • rimraf ./dist && webpack

自動清理構建目錄

  • 避免構建前每次都需要手動刪除dist

  • 使用clean-webpack-plugin

    • 默認會刪除output指定的輸出目錄
  • plugins:[
    	new CleanWebpackPlugin()
    ]
    

CSS增強

CSS兼容添加前綴
  • IE ==> Trident(-ms)
  • Geko(-moz) 火狐
  • WebKit(-webkit) 谷歌
  • Presto(-0)歐鵬

使用PostCSS插件autoprefixer自動補齊CSS3前綴

  • npm i postcss-loader autoprefixer -D

  • 使用autoprefixer插件

  • 根據Can I Use規則 https://caniuse.com/

  • module :{
            rules:[           
                {
                    test:/.less$/,
                    use:[
                        'style-loader',
                        'css-loader',
                        'less-loader',
                        {
                        	loader:'postcss-loader',
                        	  //參數
                        	  options:{
                        	 	plugins:()=>{
                        	 	//引入
                        	 		require('autoprefixer')({
    					//可以設置 autoprefixer  兼容瀏覽器版本
    					//>1% 使用人數佔比
    					//ios7 兼容ios7版本以上 版本
                        browsers:['last 2 version','>1%,'ios7']
                        	 		})
                        	 	}
                        	}
                        }
                    ]
                },
             
    
            ]
        }
    

將移動端CSS px自動轉換成rem

CSS媒體查詢實現 響應式佈局

  • 缺陷:需要寫多套適配樣式代碼

使用px2rem-loader

  • 頁面渲染時計算根元素的font-size
    • 可以使用手淘的lib-flexible
    • github.com/amfe/lib-flexible
module :{
        rules:[           
            {
                test:/.less$/,
                use:[
                    'style-loader',
                    'css-loader',
                    'less-loader',
                    {
                    	loader:'postcss-loader',
                    	  //參數
                    	  options:{
                   			remUnit:75,
                            remPrecision:8//轉換成rem 後面的小數點位數
                    	}
                    }
                ]
            },        
        ]
    }

資源內聯的意義

  • 代碼層面
    • 頁面框架的初始化腳本
    • 上報相關打點
    • css內聯避免頁面閃動

請求層面:減少http網絡請求數

  • 小圖片或者字體內聯(url-loader

HTML 和 JS內聯

css內聯

  • 方案一:藉助style-loader
  • 方案二:html-inline-css-webpack-pulugin
module :{
        rules:[           
            {
                test:/.less$/,
                use:[                    
                    {
                    loader:'style-loader',
                    //參數
                        options:{
                            inserAt:'top',//樣式插入到`<head>`
                            singleton:true,//將所有的`style`標籤合併成一個
                        }
                    }
                    'css-loader',
                    'less-loader',
                ]
            },        
        ]
    }

多頁面應用(MPA)概念

每一次頁面跳轉得時候,後臺服務器都會返回一個新的html文檔,這種類型得網站也就是多頁網站,也叫做多頁應用

多頁面打包基本思路

每個頁面對應一個entry,一個html-webpack-plugin

缺點:每次新增或刪除頁面需要修改webpack配置

module.exports = {
	entry :{
		index:'./src/index.js',
		search:'./src/search.js'
	}
}

動態獲取entry和設置 html-webpack-plugin數量

利用 glob.sync

  • entry:glob.sync(path.join(_dirname,'./src/*/index.js'))
module.exports = {
	entry :{
		index:'./src/index/index.js',
		search:'./src/search/index.js'
	}
}

//約定:把所有得頁面都放在 src 目錄下面,每個頁面得人口文件都命名爲index.js文件
  • 通過glob多頁面打包
npm i glob
const glob = require('glob')

const setMPA = () =>{
	const entry = {};
	const htmlWebpackPlugins = [];
	const entryFiles = glob.sync(path.join(__dirname,'./src/*/'));//匹配src目錄下所有頁面內容
	Object.keys(entryFiles).map(index=>{
		const entryFire = entryFiles[index];
		const match = entryFiles.mach(/src\(.*)\/index\.js/)
		const pageName = match && match[1]
		entryFiles[pageName] = entryFiles;
		htmlWebpackPlugins.push(
            new HtmlWebpackPlugin({
            template:path.join(_dirname,`src/${pageName}/index.html`),
            filename:`${pageName}.html`, //指定打包出來之後得文件名稱
            chunks:['search'],
            inject:true,
            minify:{
                html:true,
                collapseWhitespace:true,
                preserveLineBreaks:false,
                minifyCSS:true,
                minifyJS:true,
                removeComments:false
            }
        })
	})
	return {
		entry,
		htmlWebpackPlugins
	}
}

使用source map

作用:通過source map定位到源代碼

開發環境開啓,線上環境關閉

  • 線上排查問題得時候可以將sourcemap上傳到錯誤監控系統

source map關鍵字

  • eval:使用eval包裹模塊代碼
  • source map:產生.map文件
  • cheap:不包含列信息
  • inline:將.map作爲DataURL嵌入,不單獨生成.map文件
  • module:包含loadersourcemap

提取頁面公共資源

基礎庫基礎
思路:將react 、 react-dom基礎包通過引入cdn引入,不打入bundle
方法:使用html-webpack-externals-plugin

利用SplitChunksPlugin進行公共腳本分離

  • Webpack4內置的,替代CommonsChunkPlugin插件
  • chunks參數說明:
    • async異步引入的庫進行分離(默認)
    • initial:同步引入的庫進行分離
    • all:所有引入的庫進行分離(推薦)
module.exports = {
	optimization:{
		splitChunks:{
			chunks:'async',
			minSize:30000,
			maxSize:0,
			minChunks:1,
			maxAsyncRequests:5,
			maxInitialRequests:3,
			automaticNameDelimiter:'~',
			name:true,
			cacheGroups:{
				vendors:{
					test:/[\\/]node_modules[\\/]/,
					priority:-10
				}
			}
		}
	}
}

利用**SplitChunksPlugin**分離基礎包

test:匹配出需要分離的包

module.exports = {
  //...
  optimization: {
    splitChunks: {
      cacheGroups: {
        commons: {
          test: /[\\/]node_modules[\\/]/,
   		  name:'vendors',
          chunks: 'all'
        }
      }
    }
  }
};

tree shaking(搖樹優化)

概念:1個模塊可能有多個方法,只要把其中的某個方法使用到了,則整個文件都會被達到bundle裏面去,tree shaking 就是隻把用到的方法打入bundle,沒用到的方法會在uglify階段被擦除掉

使用:webpack默認支持,在.babelrc裏設置modules:false即可.production mode的情況下默認開啓

要求:必須是ES6的語法,CJS的方式不支持

DCE (Elimination)

代碼不會被執行,不可到達

代碼執行的結果不會被用到

代碼只會影響死變量(只寫不讀)

tree shaking原理

利用ES6模塊的特點:

  • 只能作爲模塊頂層的語句出現
  • import模塊名只能是字符串常量
  • import bindingimmutable

代碼擦除:ugkify階段刪除無用代碼

ScopeHoisting使用和原理分析

現象:構建後代碼存在大量閉包代碼

模塊轉換分析

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-eoaFSTUg-1586446111477)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200408234303736.png)]

結論:

  • webpack轉換後的模塊會帶上一層包裹
  • import會被轉換成__webpack_require
進一步分析webpack的模塊機制

分析:

  • 打包出來的是一個llFE(匿名閉包)
  • modules是一個數組,每一項是一個模塊初始化函數
  • __webpack_require用來加載模塊,返回module.exports
  • 通過WEBPACK_REQUIRE_METHOD(0)啓動程序

scope hoisting原理

原理:將所有模塊的代碼按照引用順序放在一個函數作用域裏,然後適當的重命名一些變量以防止變量名衝突

對比:通過scope hoisting可以減少函數聲明代碼和內存開銷

scope hoisting

webpack modeproduction默認開啓

必須是ES6語法,CJS不支持

代碼分割得意義

對於大得web應用來說,將所有的代碼都放在一個文件中顯然是不夠有效的,特別是當你的某些代碼塊實在某些特殊的時候纔會被用到,webpack有有一個功能就是將你的代碼庫分割成chunks(語塊),當代碼運行到需要它們的時候在在加載

適用的場景:

  • 抽離相同代碼到一個共享塊
  • 腳本懶加載,是的初始下載的代碼更小
懶加載JS腳本的方式

ComonJS:require.ensure

ES6:動態import(目前還沒有原生支持,需要babel轉換)

如何使用動態import
安裝babel插件

npm install @babel/plugin-syntax-dynamic-import --save-dev

{
	"plugins":["@babel/plugin-syntax-dynamic-import"]
}

webpackESLint結合

安裝husky

npm i husky --seve-dev

增加npm script,通過lint-staged增量檢查修改的文件

"script":{
	"precommit":"lint-staged"	
},
"lint-staged":{
	"linters":{
		"*.{js.scss}":["eslint--fix","git add"]
	}
}

新建項目 時候 webpackESLint集成

  • 使用eslint-loader,構建時檢查JS規範
module.exports = {
  //...
  module: {
    rules: {
  	 {
  	 	test:/\.js$/,
  	 	exclude:/node_modules/,
  	 	use:[
  	 		"babel-loader",
  	 		"eslint-loader"
  	 	]
  	 }
    }
  }
};

webpack打包庫和組件

webpack除了可以用來打包應用,也可以用來打包JS

實現一個大整數加法庫的打包
  • 需要打包壓縮版和非壓縮版本
  • 支持AMD / CJS / ESM模塊引入
    • ESM=>import * as test from 'test'
    • CJS =>const test = require('test')
    • AMD =>require(['test'],function(test){ // ...})

如何將庫暴露出去

  • library:指定庫的全局變量
  • libraryTarget:支持庫引入的方式
module.exports = {
	mode:'none',
	entry :{
		"large-number":'./src/index/index.js',
		"large-number.min":'./src/search/index.js'
	},
	output:{
		filename:"[name].js",
		library:'largeNumber',
		libraryExport:'default',
		libraryTarget:'umd'
	},
	optimization:{
		minimize:true,
		minimizer:[
			new TerserPlugin({
				include:/\.min\.js$/  //通過include 設置只壓縮 min.js 結尾的文件
			})
		]
	}
}
設置人口文件

package.json 的 main字段爲 index.js main:index.js

if(process.env.NODE_ENV === "production"){
	module.exports = require("./dist/large-number.min.js")
}else{
	module.exports = require("./dist/large-number.js")
}

webpack實現ssr打包

服務端渲染ssr是什麼

渲染:HTML + CSS + JS +Data==>渲染後的HTML

服務端:

  • 所有模板等資源都存儲在服務端
  • 內網機器拉取數據更快
  • 一個HTML返回所有數據

瀏覽器和服務器交互流程

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-lqQvoiaX-1586446111479)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200409222304222.png)]

客戶端渲染 vs服務端渲染

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-oMGMtNN9-1586446111480)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200409222548020.png)]

總結:服務端渲染(SSR)的核心是減少請求

ssr的優勢
  • 減少白屏的時間
  • 對於SEO友好

SSR代碼實現思路

  • 服務端
    • 使用react-dom / serverrenderToString方法將React組件渲染成字符串,因爲在服務端是沒有window這些對象
    • 服務端路由返回對應的模板
  • 客戶端
    • 打包出針對服務端的組件

webpack ssr打包存在的問題

瀏覽器的全局變量(Node.js中沒有document,window

  • 組件適配:將不兼容的組件根據打包環境進行適配
  • 請求適配:將fetch或者ajax發送請求的寫法改成isomorphic-fetch或者axios

樣式問題(Node.js無法解析css

  • 方案一:服務端打包通過ignore-loader忽略掉css的解析
  • 方案二:將style-loader替換成isomorphic-style-loader

如何解決SSR打包之後樣式不顯示的問題

使用打包出來的瀏覽器端html爲模板

設置佔位符,動態插入組件

比如 iview table 在查看網頁源代碼之後會出現很多<!---->,就是佔位從而顯示樣式

首屏數據如何處理

服務端獲取數據

替換佔位符

優化構建時命令行的顯示日誌

統計信息 stats

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-g0kvygEF-1586446111481)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200409230846573.png)]

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Q84SZkaE-1586446111482)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200409231203671.png)]

如何判斷構建是否成功

CI / CDpipline 或者發佈系統需要知道當前構建狀態

每次構建完成後輸入echo $ 獲取錯誤嗎

構建異常和中斷處理

webpack4之前的版本構建失敗不會拋出錯誤碼(error code

Node.js中的process.exit規範

  • 0 表示成功完成,回調函數中,err爲null

  • 非0 表示執行失敗,回調函數中,err 不爲nullerr.code就是傳給exit的數字

如何主動捕獲並處理構建錯誤

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-OPuMUzFL-1586446111483)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200409232612853.png)]

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章