webpack-2

構建配置抽離成npm包的意義

通用性
  • 業務開發和無需關注構建配置
  • 統一團隊構建腳本
可維護性
  • 構建配置合理的拆分
  • README文檔、changeLog文檔等
質量
  • 冒煙測試、單元測試、測試覆蓋率
  • 持續集成

構建配置管理的可選方案

  • 經過多個配置文件管理不一樣的環境,webpack --config參數進行控制
  • 將構建配置設計成一個庫,好比 hjs-webpackNeutrinowebpack-blocks
  • 抽成一個工具進行管理,好比 create-react-app,kyt,nwb
  • 將全部的配置放在一個文件,經過 --env參數控制分支選擇
構建配置包設計
  1. 經過多個配置文件管理不一樣環境的webpack配置。
  • 基礎配置 webpack.base.config.js
  • 開發環境 webpack.dev.config.js
  • 生產環境 webpack.prod.config.js
  • SSR環境 webpack.ssr.config.js

經過 webpack-merge組合配置css

  1. 抽離成一個npm包統一管理
  • 規範: git commit 日誌、README、 ESlint規範、 Semver規範
  • 質量: 冒煙測試、單元測試、測試覆蓋率和 CLI

冒煙測試

冒煙測試是指對提交測試的軟件在進行詳細深刻的測試以前而進行的預測試,這種預測試的主要目的 是暴露致使軟件需從新發布的基本功能失效等嚴重問題。html

執行

  1. 構建是否成功
  2. 每次構建完成build目錄是否有內容輸出
  • 是否有JS、CSS等靜態資源文件
  • 是否有HTML文件

git提交

  1. 提交格式要求
<type>(<scope>):<subject>
<blank line>
<body>
<blank line>
<footer>

type表明每次提交的類型。全部type類型以下:node

  • feat: 新增feature
  • fix :修復bug
  • docs:僅僅修改了文檔, 好比README,CHANGELOG,CONTRIBUTE等等
  • style: 僅僅修改了空格、格式縮進、逗號等等,不改變代碼邏輯
  • refactor: 代碼重構,沒有加新功能或者修復bug
  • perf: 優化相關,好比提高性能、體驗
  • test: 測試用例, 包括單元測試、集成測試等
  • chore: 改變構建流程或者增長依賴庫 工具等
  • revert: 回滾到上一個版本

版本規範

  1. 遵照semver規範的優點react

    • 避免出現循環依賴
    • 依賴衝突減小
  2. 語義化版本規範格式webpack

    1. 主版本號: 作了不兼容的api修改
    2. 次版本號:作了向下兼容的功能性新增
    3. 修訂號: 作了向下兼容的問題修正
  3. 先行版本號
    先行版本號能夠做爲發佈正式版以前的版本,格式是在修訂版本號後面加上一個鏈接號(-),再加上一連串以(.)分割的標識符,
    標識符能夠由英文、數字和鏈接號[0-9A-Za-z-]組成。git

    • alpha: 是內部測試版,通常不向外部發布,會有不少bug。通常只有測試人員使用。
    • beta : 也是測試版,這個階段的版本會一直加入新的功能。 在alpha版以後推出。
    • rc : Release Candidate系統平臺上就是發行候選版本。RC版不會再 加入新的功能了,主要着重於除錯。

webpack構建速度和體積優化策略

stats
  1. 初級分析: 使用webpack內置的 stats:構建的統計信息web

  2. package.json中使用stats。正則表達式

    "scripts":{
     "build:stats":"webpack  --env production  --json > stats.json",
        ...
    }
  3. nodejs中使用算法

const webpack = require("webpack");
const congfig = require("./webpack.config.js")("production");

webpack(config,(err,stats)=> {
    if(err){
   	 return console.error(err)
    }
    if(stats.hasErrors()){
   	 return console.error(stats.toString("errors-only"));
    }
    console.log(stats);
})
  1. 缺點:顆粒度太粗,看不出問題所在。
speed-measure-webpack-plugin:速度分析
  1. 代碼示例:
const SpeedMeasureWebpackPlugin = require("speed-measure-webpack-plugin");
const smp = new SpeedMeasureWebpackPlugin();
const webpackConfig = smp.wrap({
    plugins:[
   	 new MyPlugin(),
   	 new MyOtherPlugin()
    ]
})
//能夠看到每一個loader和插件執行耗時
webpack-bundle-analyzer:分析體積
  1. 代碼示例:
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
	plugins:[
		new BundleAnalyzerPlugin()
	]
}
//構建完成後會在8888端口展現大小
  1. 能夠分析哪些問題?
  • 依賴的第三方模塊的大小
  • 業務裏面組件代碼的大小
使用高版本的webpack和nodejs。
  1. 高版本的webpack和nodejs, 構建時間下降了 60%- 98%。
  2. 使用webpack4:優化緣由
  • v8帶來的優化(for...of代替forEach, Map和 Set替代Object、includes替代indexOf)
  • 默認使用更快的md4 hash算法
  • webpack AST 能夠直接從 loader傳遞給 AST,減小解析時間
  • 使用字符串方法代替正則表達式
多進程/多實例構建
  1. 資源並行解析可選方案
  • thread-loader :官方
  • parallel-webpack
  • HappyPack
  1. 使用HappyPack解析資源
  • 原理:每次webpack解析一個模塊,HappyPack會將它及它的依賴分配給worker線程中
  • 代碼示例
exports.plugins = {
	new HappyPack({
		id:'jsx',
		threads:4,
		loaders:['babel-loader']
	}),
	new HappyPack({
		id:'styles',
		threads:2,
		loaders: ['style-loader','css-loader','less-loader'] 
	})
}
  1. 使用thread-loader解析資源
  • 每次webpack解析一個模塊,thread-loader會將它及它的依賴分配給worker線程中
  • 代碼示例
module.exports = {
	...,
	module:{
		rules:[
			{
				test:/.js$/,
				use:[
					{
						loader:'thread-loader',
						options:{
							workers:3
						}
					},
					'babel-loader'
				]
			}
		]
	}
}
並行壓縮
  1. 使用 parallel-uglify-plugin插件
  • 代碼示例
const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
module.exports = {
	plugins:[
		new ParallelUglifyPlugin({
			uglifyJS:{
				output:{
					beautify:false,
					comments:false
				},
				compress:{
					warning: false,
					drop_console: true,
					collapse_vars: true,
					reduce_vars: true
				}
			}
		})
	]
}
  1. 使用uglify-webpack-plugin開啓 parallele參數。
  • 代碼示例:
const UglifyPlugin = require('uglify-webpack-plugin');
module.exports = {
	plugins:[
		new UglifyPlugin({
			uglifyOptions:{
				warning:false,
				parse:{},
				compress:{},
				mangle:true,
				output:null,
				toplevel: false,
				nameCache:null,
				ie8:false,
				keep_fnames: false
			},
			parallel:true
		})
	]
}
  1. terser-webpack-plugin開啓parallel參數。
  • 代碼示例
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
	optimization:{
		minimizer:[
			new TerserPlugin({
				parallel:4
			})
		]
	}
}

分包:設置externals

  1. 思路:將react,react-dom基礎包經過cdn引入,不打入bundle中。
  2. 方法:使用 html-webpack-externals-plugin
  3. 代碼示例:
const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin');
plugins:[
	new HtmlWebpackExternalsPlugin({
		externals:[
			{
				module:'react',
				entry:'//11.url.cn/now/lib/15.1.0/react-width-addons.min.js?_bid=3123',
				global:'React'
			},	
			{
				module:'react-dom',
				entry:'//11.url.cn/now/lib/15.1.0/react-dom.min.js?_bid=3123',
				global:'ReactDOM'
			}
		]
	})
]
進一步分包:預編譯資源模塊
  1. 思路:將react,react-dom,redux, react-redux基礎包和業務基礎包打包成一個文件
  2. 方法:使用DLLOPlugin 進行分包,DllReferencePlugin對 manifest.json引用。
  3. 使用DLLPlugin進行分包
const path = reqire('path');
const webpack = require('webpack');
module.exports = {
	context:process.cwd(),
	resolve:{
		extensions:['.js','.jsx','.json','.less','.css'],
		modules:[__dirname,'node_modules']
	},
	entry:{
		library:[
			'react',
			'react-dom',
			'redux',
			'react-redux'
		]
	},
	output:{
		filename:'[name].dll.js',
		path:path.resolve(__dirname,'./build/library'),
		library:'[name]'
	},
	plugins:[
		new webpack.DllPlugin({
			name:'[name]',
			path:'./build/library/[name].json'
		})
	]
}
  1. 使用DllReferencePlugin引用manifest.json【在webpack.config.js中使用】
module.exports = {
	plugins:[
		new webpack.DllReferencePlugin({
			manifest:require('./build/library/manifest.json')
		})
	]
}
相關文章
相關標籤/搜索