打包優化策略
區分開發和生產環境
通常我們在開發網頁時需要區分構建環境
- 開發環境(development) 開發過程中方便開發除錯的環境
- 生產環境(production) 釋出到線上使用的執行環境
通過npm命令區分
通過cross-env模組設定環境變數
cross-env 跨平臺地設定及使用環境變數,而不必擔心為平臺正確設定或使用環境變數。
npm i cross-env -D
複製程式碼
Usage
npm scripts中:
{
"scripts": {
"build": "cross-env NODE_ENV=production webpack --mode production",
"dev": "cross-env NODE_ENV=development webpack-dev-server --mode development",
}
}
複製程式碼
執行npm命令切換環境
npm run build // 生產環境 process.env.NODE_ENV === 'production'
npm run dev // 開發環境 process.env.NODE_ENV === 'development'
複製程式碼
接下來我們就可以在webpack.config.js 通過process.env.NODE_ENV來得知當前環境標識
程式碼中區分環境
定義環境常量
webpack4以前都是通過DefinePlugin來定義NODE_ENV環境變數,以決定library中應該引用哪些內容。
NODE_ENV是一個由Node.js暴露給執行指令碼的環境變數。通常用於決定在開發環境與生產環境下,服務工具、構建指令碼和客戶端library的行為。
在webpack.config.js 中新增DefinePlugin外掛
const webpack = require('webpack');
plugins: [
new webpack.DefinePlugn({
'process.env': {
'NODE_ENV': JSON.stringify(process.env.NODE_ENV)
}
})
]
複製程式碼
在main.js中通過判斷process.env.NODE_ENV常量 來執行相應邏輯
mode模式配置
在webpack4 增加了mode模式配置 在瀏覽器環境下指定了 process.env.NODE_ENV 的值,預設是development,但node環境中還是需要cross-env來設定。 mode 是 webpack 4 中新增加的引數選項,其有兩個可選值:production 和 development。mode 不可預設,需要二選一:
production 模式:
- 1.生產環境預設開啟了很多程式碼優化(minify,splite等)
- 2.開發時開啟注視和驗證,並且自動加上了eval devtool
- 3.生產環境不支援watching,開發環境優化了重新打包的速度
- 4.預設開啟了Scope hoisting和Tree-shaking(原ModuleConcatenationPlugin)
- 5.自動設定process.env.NODE_ENV到不同環境,也就是不需要DefinePlugin來做這個了
- 6.如果你給mode設定為none,所有預設配置都去掉了
- 7.如果不加這個配置webpack會出現提醒,所以還是加上吧
development 模式:
-
1.主要優化了增量構建速度和開發體驗
-
2.process.env.NODE_ENV 的值不需要再定義,預設是 development
-
3.開發模式下支援註釋和提示,並且支援 eval 下的 source maps
const NODE_ENV = process.env.NODE_ENV;
if (NODE_ENV === 'development') { // 開發環境下執行下面程式碼
console.log('development', NODE_ENV);
} else { // 生產環境則執行以下環境
console.log('production', NODE_ENV);
}
複製程式碼
DefinePlugn
DefinePlugin 允許建立一個在編譯時可以配置的全域性常量。這可能會對開發模式和釋出模式的構建允許不同的行為非常有用。
webpack配置中區分環境
在專案目錄中新增webpack配置檔案
- webpack.base.config.js 儲存webpack基礎通用的配置的檔案
- webpack.dev.config.js 儲存webpack開發環境配置的檔案
- webpack.prod.config.js 儲存webpack生成環境配置的檔案
- webpack.config.js webpack執行配置檔案 儲存相應環境的配置和webpack基礎配置檔案合併後的配置
基礎配置 webpack.base.config.js
webpack一些loader配置
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const HappyPack = require('happypack');
const os = require('os'); // 系統操作函式
const happyThreadPool = HappyPack.ThreadPool({size: os.cpus().length}); // 指定執行緒池個數
function resolve(dir) {
return path.join(__dirname, dir);
}
module.exports = {
entry: {
app: './src/main.js'
},
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].js'
},
module: {
rules: [
{
test: /\.js$/,
// use: 'babel-loader?cacheDirectory'
use: 'happypack/loader?id=babel', // 快取loader執行結果
exclude: /node_modules/, // 排除不要載入的資料夾
include: path.resolve(__dirname, 'src') // 指定需要載入的資料夾
}
],
noParse: function(content) { // content 從入口開始解析的模組路徑
return /no-parser/.test(content); // 返回true則忽略對no-parser.js的解析
}
},
resolve: {
modules: [ // 優化模組查詢路徑
resolve('src'),
resolve('node_modules') // 指定node_modules所在位置 當你import第三方模組式 直接從這個路徑下搜尋
],
alias: {
funs$: resolve('src/util/funs.js')
},
extensions: ['.js', '.vue']
},
plugins: [
new webpack.DefinePlugin({ // 定義環境變數
"process.env": JSON.stringify(process.env.NODE_ENV)
}),
new HappyPack({
id: 'babel',
loaders: ['babel-loader?cacheDirectory'],
threadPool: happyThreadPool,
verbose: true
}),
new HtmlWebpackPlugin({
template: resolve('index.html'),
title: 'hello webpack!'
})
]
}
複製程式碼
開發配置webpack.dev.config.js
開發時的輸入輸出以及開發除錯配置 如 devServer devtool 配置
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify(process.env.NODE_ENV)
}
})
],
devServer: {
contentBase: resolve('dist'),
compress: true,
port: 9000
}
};
複製程式碼
生成環境webpack.prod.config.js
生成環境 進行壓縮 程式碼分離等程式碼優化 線上配置
const webpack = require('webpack');
const path = require('path');
const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const HtmlIncludeAssetsPlugin = require('html-webpack-include-assets-plugin');
module.exports = {
plugins: [
new webpack.DllReferencePlugin({
manifest: require(path.join(__dirname, 'dll', 'react.manifest.json'))
}),
new ParallelUglifyPlugin({
workerCount: 4, // 開啟幾個子程式去併發的執行壓縮,預設是當前電腦的cpu數量減1
uglifyJS: {
output: {
beautify: false, // 不需要格式化
comments: false // 保留註釋
},
compress: {
warnings: false, // Uglifyjs 刪除沒有程式碼時,不輸出警告
// drop_console: true, // 刪除所有console語句
collapse_vars: true,
reduce_vars: true
}
}
}),
new HtmlWebpackPlugin({
template: path.join(__dirname, 'index.html')
}),
new HtmlIncludeAssetsPlugin({
assets: ['/dll/react.dll.js'],
append: false
})
]
};
複製程式碼
webpack.config.js 配置合併
藉助webpack-merge 將base配置和相應環境配置 合併到'webpack.config.js'
npm i webpack-merge -D
複製程式碼
webpack.config.js
const base = require('./webpack.base.config');
const merge = require('webpack-merge');
let config;
if (process.env.NODE_ENV === 'production') {
config = require('./webpack.prod.config');
} else {
config = require('./webpack.dev.config');
}
module.exports = merge(base, config);
複製程式碼
執行生產配置
npm run build
複製程式碼
執行開發配置
npm run dev
複製程式碼
實時重新載入(live reloading) 和 模組熱替換(HMR)
webpack-dev-server 為你提供了一個簡單的 web 伺服器,並且能夠實時重新載入(live reloading)。
讓我們設定以下:
npm i webpack-dev-server -D
複製程式碼
配置webpack.dev.config.js
devServer: {
contentBase: path.join(__dirname, 'dist'), // 將 dist 目錄下的檔案,作為可訪問檔案。
compress: true, // 開啟Gzip壓縮
port: 9000, // 埠號
inline: true // 在打包後檔案裡注入一個websocket客戶端
}
複製程式碼
npm scripts
{
"scripts": {
"dev": "cross-env NODE_ENV=development webpack-dev-server --mode development"
}
}
複製程式碼
啟動server
npm run dev
複製程式碼
瀏覽器訪問localhost:9000 當修改程式碼ctrl+s 將自動重新整理瀏覽器
啟用HMR
模組熱替換(Hot Module Replacement 或 HMR)是 webpack 提供的最有用的功能之一。它允許在執行時更新各種模組,而無需進行完全重新整理。
配置webpack.dev.config.js
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true,
port: 9000,
inline: true,
hot: true // 開啟HMR
}
複製程式碼
注意 此外我們還需新增NamedModulesPlugin 和 HotModuleReplacementPlugin 外掛
webpack.dev.config.js
{
plugins: [
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin()
]
}
複製程式碼
其他程式碼和框架開啟熱替換
1.React Hot Loader(實時調整 react 元件)
Install
npm install react-hot-loader
複製程式碼
Getting started
1.1 Add react-hot-loader/babel to your .babelrc:
// .babelrc
{
"plugins": ["react-hot-loader/babel"]
}
複製程式碼
1.2 Mark your root component as hot-exported:
// App.js
import React from 'react'
import { hot } from 'react-hot-loader'
const App = () => <div>Hello World!</div>
export default hot(module)(App)
複製程式碼
2.Vue loader
vue-cli 已經整合 只需用vue-cli腳手架開發即可
HMR修改樣式表
藉助於style-loader的幫助,CSS的模組熱替換實際上是相當簡單的。
安裝如下loader:
npm i style-loader css-loader -D
複製程式碼