使用包的版本css
webpack ->4.3.0
babel-loader ->8.0.5
npm ->6.4.1
webpack-cli ->3.3.1
複製代碼
每一個章節對應一個demohtml
參考代碼 demo8
node
什麼是模塊化拆包。好比咱們在項目裏面須要引入echarts、xlsx、lodash等比較大的包的時候。若是不作代碼拆包,都會打包到一個js文件裏面。若是每次打包發版都會生成一個新的js打包文件,用戶從新請求頁面的時候會再次請求echarts、xlsx、lodash這些不變的代碼,就會下降用戶體驗。模塊化拆包將這些不變的依賴包打包成一個新的js文件,每次打包發版的時候用戶就不會再次請求echarts、xlsx、lodash這些不變的代碼了。react
webpack-bundle-analyzer 可視化顯示打包的JS引用的包webpack
npm i webpack-bundle-analyzer -D
複製代碼
在項目裏面引入echarts、xlsx、lodashnginx
npm i echarts xlsx lodash -S
複製代碼
app.jsgit
import "regenerator-runtime/runtime";
import _ from 'lodash';
import echarts from 'echarts';
import xlsx from 'xlsx';
console.log(echarts)
console.log(xlsx);
document.getElementById('app').innerHTML = _.ceil(2,3,4);
複製代碼
webpack.base.conf.js 配置可視化如今打包文件。github
var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
plugins:[
new BundleAnalyzerPlugin(),
new htmlWebpackPlugin({
filename:'index.html',
template:'./index.html',
inject:true,
minify: {
// 壓縮 HTML 文件
removeComments: isPord, // 移除 HTML 中的註釋
collapseWhitespace: isPord, // 刪除空白符與換行符
minifyCSS: isPord // 壓縮內聯 css
},
})
],
複製代碼
運行打包命令web
npm run build
複製代碼
打包提示代碼太大,須要進行拆包。
optimization.splitChunks是webpack4新的特性,默認進行代碼拆包。算法
上圖是默認配置。chunks:
minSize: 文件最小打包體積,單位byte,默認30000。
好比說某個項目下有三個入口文件,a.js和b.js和c.js都是100byte,當咱們將minSize設置爲301,那麼webpack就會將他們打包成一個包,不會將他們拆分紅爲多個包。
automaticNameDelimiter: 鏈接符。
假設咱們生成了一個公用文件名字叫vendor,a.js,和b.js都依賴他,而且咱們設置的鏈接符是"~"那麼,最終生成的就是 vendor~a~b.js
maxInitialRequests 入口點處的最大並行請求數,默認爲3。
若是咱們設置爲1,那麼每一個入口文件就只會打包成爲一個文件
maxAsyncRequests 最大異步請求數量,默認5
若是咱們設置爲1,那麼每一個入口文件就只會打包成爲一個文件
優先級關係。
maxInitialRequest / maxAsyncRequests <maxSize <minSize。
cacheGroups 定製分割包的規則列表
test能夠配置正則和寫入function做爲打包規則。其餘屬性都可繼承splitChunks。
minChunks
依賴最少引入多少次才能進行拆包。
複製默認配置,將chunks 改成'all'。
optimization: {
splitChunks: {
chunks: 'all',
minSize: 30000,
maxSize: 0,
minChunks: 1,
maxAsyncRequests: 5,
maxInitialRequests: 3,
automaticNameDelimiter: '~',
name: true,
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
}
},
複製代碼
運行打包命令
npm run build
複製代碼
多了一個vendors~app.js。這個js裏面儲層的就是須要拆分的代碼。
vendors~app.js是一個1.71mb的文件,太大了,繼續拆包。
添加一個新的拆包規則
cacheGroups: {
echarts:{ // 新增拆包規則
name:'echarts', // 規則名字
chunks:'all', // 同步引入和異步引入均可以使用該規則
priority:10,
// 該規則的優先級,好比 webpack中進行拆包的時候,
// echarts包會有先匹配priority高的規則,若是知足這個規則,
// 則將代碼導入到該規則裏面,不會將代碼導入到後面的規則裏面了。
test:/(echarts)/, // 正則匹配規則
minChunks:1 // 代碼裏面最少被引入1次就可使用該規則。
},
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
複製代碼
運行打包命令
npm run build
複製代碼
echarts包就被單獨拆出來了儲層在echarts.js。
參考代碼 demo9
這一節只使用splitChunks的默認配置來實現異步加載,理解異步加載的好處。
。 使用react做爲開發框架。
redux -> 16.8.6
react-dom -> 16.8.6
react-router-dom -> 5.0.0
複製代碼
安裝 react
npm i react react-router-dom react-dom -S
複製代碼
解析 jsx代碼還須要@babel/preset-react
npm i @babel/preset-react -D
複製代碼
詳細代碼請看demo9。
兩個路由分別對應不一樣的組件。
import About from './src/view/about';
import Inbox from './src/view/inbox';
// ....
<App>
<Route path="/about" component={About} />
<Route path="/inbox" component={Inbox} />
</App>
複製代碼
inbox.js引入了echarts而且使用了。
import React from 'react';
import echarts from 'echarts';
class Inbox extends React.Component {
componentDidMount() {
var myChart = echarts.init(document.getElementById('main'));
var option = {
tooltip: {
show: true
},
legend: {
data: ['銷量']
},
xAxis: [
{
type: 'category',
data: ["襯衫", "羊毛衫2", "雪紡衫222", "褲子111", "高跟鞋", "襪子"]
}
],
yAxis: [
{
type: 'value'
}
],
series: [
{
"name": "銷量",
"type": "bar",
"data": [5, 20, 40, 10, 10, 20]
}
]
};
// 爲echarts對象加載數據
myChart.setOption(option);
}
render() {
return (
<div>
<h2>Inbox</h2>
<div style={{ height: '400px' }} id="main"></div>
</div>
)
}
}
export default Inbox;
複製代碼
splitChunks 使用默認配置
splitChunks: {
chunks: 'async',
minSize: 30000,
maxSize: 0,
minChunks: 1,
maxAsyncRequests: 5,
maxInitialRequests: 3,
automaticNameDelimiter: '~',
name: true,
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
}
複製代碼
運行打包命令
npm run build
複製代碼
打包的時候已經提示了,打包的代碼太大影響性能。可使用import()或require來限制包的大小。確保延遲加載應用程序的某些部分。
WARNING in webpack performance recommendations:
You can limit the size of your bundles by using import() or require.ensure to lazy load some parts of your application.
For more info visit https://webpack.js.org/guides/code-splitting/
複製代碼
咱們在首頁的時候,並無/inbox路由,可是/inbox路由裏面的代碼都打包在了app.js這一個js裏面。首屏渲染變的很慢。按照官方提示須要作組件的動態引入,只有路由切換到/inbox的時候才加載對應組件的代碼。
異步引入組件須要用到babel的一個插件@babel/plugin-syntax-dynamic-impor。
{
test: /\.(js|jsx)?$/, // 正則匹配,全部的.js文件都使用這個規則進行編譯
exclude: /node_modules/, // 排除的文件夾。這個文件夾裏面的的文件不進行轉譯
loader: "babel-loader", // 轉譯的插件
options: { // 轉譯的規則
presets: [ //轉譯器配置
[
"@babel/preset-env", {
useBuiltIns: "usage",
corejs: 3
},
],
["@babel/preset-react"]
],
plugins: ["@babel/plugin-syntax-dynamic-import"] // 轉譯插件配置
}
},
複製代碼
新建AsyncComponent.js。
import React, { Component } from "react";
export default function asyncComponent(importComponent) {
class AsyncComponent extends Component {
constructor(props) {
super(props);
this.state = {
component: null
};
}
async componentDidMount() {
const { default: component } = await importComponent();
// 組件引入完成後渲染組件
this.setState({
component: component
});
}
render() {
const C = this.state.component;
return C ? <C {...this.props} /> : null;
}
}
return AsyncComponent;
}
複製代碼
更換引入模式
//import Inbox from './src/view/inbox';
const Inbox = asyncComponent(() => import('./src/view/inbox'));
複製代碼
運行打包命令
npm run build
複製代碼
echarts被引入到1.js裏面了。
npm run server
複製代碼
首頁並無加載1.js
路由跳轉後會引入。react的動態引入組件就OK了。 按照官方文檔,還能夠自定義chunk名稱
const Inbox = asyncComponent(() => import(/* webpackChunkName: "echarts" */ './src/view/inbox'));
複製代碼
其實還能夠異步引入依賴包
async componentDidMount() {
const {default:echarts}= await import('echarts');
var myChart = echarts.init(document.getElementById('main'));
}
複製代碼
參考代碼 demo10
樹抖動是JavaScript上下文中經常使用於消除死代碼的術語。 它依賴於ES2015模塊語法的靜態結構,即導入和導出。 名稱和概念已由ES2015模塊捆綁器彙總推廣。
搖樹的意思。在webpack4.0裏面會自動的把不須要的js在打包的時候剔除。固然須要開發進行配合:按需加載
咱們拿lodash爲例。 爲了清楚咱們搖掉了多少代碼,先將react的包拆出來單獨打包。
splitChunks: {
chunks: 'all',
minSize: 30000,
maxSize: 0,
minChunks: 1,
maxAsyncRequests: 5,
maxInitialRequests: 3,
automaticNameDelimiter: '~',
name: true,
cacheGroups: {
reactVendors: {
chunks: 'all',
test: /(react|react-dom|react-dom-router)/,
priority: 100,
name: 'react',
},
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
}
複製代碼
在about.js裏面使用lodash
import React from 'react';
import _ from 'lodash';
class About extends React.Component {
render() {
const s = _.concat([1],[2,3,1,2,3,4,6,78,41]);
return (
<h3>{s}</h3>
)
}
}
export default About;
複製代碼
運行打包命令
npm run build
複製代碼
合併引入的vendors有95kb。咱們只使用了lodash的concat方法,其餘的方法沒使用。 咱們使用lodash的模塊化包
lodash-es。
npm i lodash-es -S
複製代碼
改變about.js的代碼
import React from 'react';
//import _ from 'lodash';
import { concat } from 'lodash-es';
class About extends React.Component {
render() {
const s = concat([1],[2,3,1,2,3,4,6,78,41]);
return (
<h3>{s}</h3>
)
}
}
export default About;
複製代碼
運行打包命令
npm run build
複製代碼
如今只有28kb。縮小的部分就是loader的按需加載的部分。
打開掘金首頁。
隨便找一個js資源。
Response Headers 裏面的 content-encoding 表明着資源傳輸格式。說明這段資源使用的是Gzip文件。說明不少公司用的是Gzip進行資源傳輸,由於代碼打包成Gzip傳輸時須要的資源很小。
其實Gzip傳輸是服務器須要配置的。即便咱們上傳代碼沒有進行Gzip壓縮,服務器通過配置後會將資源進行Gzip壓縮而後傳輸。例如nginx的Gzip配置。
Gzip配置都是服務器配置的工做,咱們要作什麼呢?其實服務器會尋找資源對應的gzip文件,若是沒有則會進行Gzip壓縮而後傳輸資源。這就多出了壓縮的時間。若是咱們經過webpack生成gzip文件,能夠減小服務器生成gzip文件的時間,也減緩了服務器壓力。
這個屬性的屬性值能夠是布爾、數組。
在mode是prduction時,minimiz默認是true。自動使用terser-webpack-plugin進行壓縮。
默認的配置不用改,使用壓縮插件compression-webpack-plugin。
npm i compression-webpack-plugin -D
複製代碼
配置 optimization.minimiz
minimizer: [
new CompressionPlugin({
filename: '[path].gz[query]', // 生成資源的名字 [path].gz[query] 是默認名字
algorithm: 'gzip', // 壓縮算法
test: /\.(js|css|html|svg)$/, // 匹配的資源
compressionOptions: { level: 8 }, // 壓縮等級 默認9級
threshold: 10240, // 多大資源使用才壓縮 10kb
minRatio: 0.8,
//僅處理壓縮比此比率更好的資源(minRatio =壓縮尺寸/原始尺寸)。
//示例:您擁有1024b大小的image.png文件,壓縮版本的文件大小爲768b,
//所以minRatio等於0.75。換句話說,當壓縮大小/原始大小值小於minRatio值時,
//將處理資源。默認 0.8 。
deleteOriginalAssets: false, // 是否刪除原始資產。
}),
new TerserPlugin({
parallel: true,
}),
]
複製代碼
運行打包命令
npm run build
複製代碼
.zip 就是打包生成的gzip資源。對比原來的文件壓縮了 38/121≈0.3。壓縮了不少。