做者 zhangljavascript
webpack是一個模塊打包工具,將每一個資源文件看作是一個個模塊,webpack依據打包規則將全部資源處理後打包到指定文件css
// 導入
import 模塊名 from 模塊路徑;
// 導出
export default 模塊名;
export const 模塊名 = 模塊內容;
複製代碼
// 導入
var 模塊名 = required(模塊路徑);
// 導出
module.exports = 模塊名;
複製代碼
{
"name": "webpack-demo",
"version": "1.0.0",
"private": true, // 是一個私有項目,不會上傳到npm線上
"description": "",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
複製代碼
npm install webpack webpack-cli -g
webpack -v 查看全局webpack版本號
npm install webpack webpack-cli
npx webpack -v 查看版本號 npx查找的是當前目錄下的webpack
npm uninstall webpack webpack-cli
npm info webpack
const path = require('path'); // 導入node的path模塊
module.exports = {
entry: './src/index.js', // 打包入口文件
output: {
filename: 'bundle.js', // 打包出的文件名
path: path.resolve(__dirname, 'dist') // 存放打包出的文件路徑(絕對路徑)
}
};
複製代碼
// global
webpack 文件名
// local
npx webpack 文件名
複製代碼
// package.json文件
"scripts": {
"bundle": "webpack"
// 執行npm run bundle命令,
// webpack會執行package.json文件下script字段裏bundle對應的映射命令
}
複製代碼
Hash: 178b79cd0f5fd66a90e5
Version: webpack 4.34.0 -- webpack版本
Time: 380ms -- 打包耗時
Built at: 06/18/2019 7:59:32 PM
// 文件名 大小 每個打包的js文件id 每個打包的js文件名
Asset Size Chunks Chunk Names
bundle.js 1.17 KiB 0 [emitted] main
Entrypoint main = bundle.js // 入口文件名(mian)
[0] ./src/index.js 203 bytes {0} [built] // 文件索引 文件路徑 文件體積
[1] ./src/Footer.js 79 bytes {0} [built]
[2] ./src/Header.js 79 bytes {0} [built]
[3] ./src/Slider.js 79 bytes {0} [built]
複製代碼
打包方案,告訴webpack如何處理特定的文件html
// package.json
module: { // 打包的模塊
// 打包規則
rules: [{
test: /\.jpg$/, // 正則匹配使用loader解析的模塊後綴名
use: {
loader: 'file-loader' // 用於解析該模塊的loader
}
}]
}
複製代碼
{
test: /\.(jpg|png|gif)$/,
use: {
loader: 'file-loader',
options: {
// 佔位符 placeholder
name: '[name]_[hash].[ext]',
outputPath: 'images/' // 處理後的文件存放位置: dist/images/xxx.png
}
}
}
複製代碼
{
test: /\.(jpg|png|gif)$/,
use: {
loader: 'url-loader',
options: {
name: '[name]_[hash].[ext]',
outputPath: 'images/', // 處理後的文件存放位置: dist/images/xxx.png,
// size > 2.048kb 效果與file-loader一致
// size < 2.048kb 轉換爲base64字符串放入bundle.js中
limit: 2048
}
}
}
複製代碼
{
test: /\.(c|le)ss/,
use: ['less-loader']
}
複製代碼
// webpack配置
{ // 樣式處理
test: /\.(c|le)ss/,
use: ['postcss-loader', 'less-loader']
}
複製代碼
// postcss.config.js配置
module.exports = {
plugins: [
require('autoprefixer'), // 自動添加屬性前綴(後編譯器)
]
};
複製代碼
{
test: /\.(c|le)ss/,
use: ['css-loader', 'postcss-loader', 'less-loader']
}
複製代碼
{ // loader執行順序爲從上到下,從右到左
test: /\.(c|le)ss/,
use: ['style-loader', 'css-loader', 'postcss-loader', 'less-loader']
}
複製代碼
{ // 字體處理
test: /\.(eot|svg|ttf|woff|woff2)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name]_[hash].[ext]',
outputPath: 'assets/font/',
}
}
]
}
複製代碼
一段能擴展webpack功能的代碼,能夠在webpack運行到某個時刻的時候,幫助webpack作一些事情java
// 導入
const HtmlWebpackPlugin = require('html-webpack-plugin');
plugins: [
new HtmlWebpackPlugin({ // 根據模板html, 生成新html文件
template: 'src/index.html', // html模板
})
]
複製代碼
// 導入(新版本寫法)
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
plugins: [
new CleanWebpackPlugin(), // 刪除當前目錄dist文件夾
]
複製代碼
打包代碼與源碼之間的一種映射關係,可以讓開發人員快速的定位錯誤發生的位置node
module.exports = {
devtool: 'source-map',
};
複製代碼
module.exports = {
devtool: 'inline-source-map',
};
複製代碼
module.exports = {
devtool: 'cheap-source-map',
};
複製代碼
module.exports = {
devtool: 'eval',
};
複製代碼
// development:cheap-module-eval-source-map(推薦)
// production:cheap-module-source-map(推薦)
複製代碼
點擊查看devtool配置項react
npm install webpack-dev-server --save-dev
複製代碼
"scripts": {
"start": "webpack-dev-server"
}
複製代碼
devServer: { // 設置開發服務
contentBase: './dist', // 根目錄
open: true, // 自動打開瀏覽器
port: 8080, // 端口號
proxy: { // 設置接口代理(解決跨域)
'/api': 'https://localhost:3000'
}
}
複製代碼
npm install express --save-dev
複製代碼
npm install webpack-middleware --save-dev
複製代碼
const express = require('express');
const webpack = require('webpack');
const WebpackMiddleWare = require('webpack-middleware');
const config = require('./webpack.config');
// 生成express實例(服務器)
const app = express();
// 建立webpack編譯器(可以進行webpack打包)
const complier = webpack(config);
// 使用webpack-middleware插件監聽webpack打包的文件變化
app.use(WebpackMiddleWare(complier, {}));
// 開啓監聽
app.listen(3000, () => {
console.log('server is running at 3000');
});
複製代碼
"scripts": {
"server": "node server.js"
}
複製代碼
實現局部更新,而非瀏覽器頁面刷新webpack
devServer: {
hot: true, // 開啓HMR
hotOnly: true, // 不更新瀏覽器
},
plugins: [
new webpack.HotModuleReplacementPlugin()
]
// entery文件末尾添加
if (module.hot) {
module.hot.accept();
}
複製代碼
babel:只能解析ES的語法,而不能解析對象的API,Promise等; @babel/polyfill:解析babel不能解析的部分git
npm install babel-loader @babel/preset-env @babel/core @babel/polyfill
複製代碼
module: {
rules: [
{ // babel處理
test: /.js$/,
exclude: /node_modules/, // 排除文件
loader: 'babel-loader'
}
]
}
複製代碼
// .babelrc文件
{
"presets": [
[
"@babel/preset-env", // 將ES5以上的語法轉換爲ES5版本
{
"useBuiltIns": "usage" // 按需使用polyfill
}
]
]
}
複製代碼
// index.js
import '@babel/polyfill';
複製代碼
使用babel-polyfill可能會形成全局變量名污染,若是有使用babel打包第三方包,則使用transform-runtime方案github
npm install react react-dom --save
複製代碼
npm install @babel/preset-react --save-dev
複製代碼
{
"presets": [
["@babel/preset-react"]
]
}
複製代碼
刪除模塊中未使用的內容,減少打包體積(只支持ES Module的引入方式)web
module.exports = {
mode: 'development'
optimization: {
usedExports: true, // 打包被引用的模塊
}
};
複製代碼
{
"sideEffects": false // 全部模塊都進行tree sharking
}
複製代碼
module.exports = {
mode: 'production'
};
複製代碼
{
"sideEffects": false // 全部模塊都進行tree sharking
}
複製代碼
npm install webpack-merge --save-dev
複製代碼
const path = require('path'); // 導入node的path模塊
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
entry: {
main: './src/index.js', // 打包入口文件
},
output: {
filename: 'script/[name].js', // 打包出的文件名
path: path.join(__dirname, '../', 'dist'), // 存放打包出的文件路徑(絕對路徑)
// publicPath: './', // 公共路徑
},
module: { // 打包模塊
// 打包規則
rules: [
{ // babel處理
test: /.js$/,
exclude: /node_modules/, // 排除文件
loader: 'babel-loader'
},
{ // 圖片處理
test: /\.(jpg|png|gif)$/,
use: {
loader: 'url-loader',
options: {
name: '[name]_[hash].[ext]',
outputPath: 'images/', // 處理後的文件存放位置: dist/images/xxx.png
limit: 10240, // 當處理的文件大小大於2048kb,效果與file-loader一致;小於時,轉換爲base64字符串放入bundle.js中
}
}
}, { // 字體處理
test: /\.(eot|svg|ttf|woff|woff2)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name]_[hash].[ext]',
outputPath: 'font/',
}
}
]
}, { // csv文件處理
test: /\.(csv|tsv)$/,
use: ['csv-loader']
}, { // xml文件處理
test: /\.xml$/,
use: ['xml-loader']
}, { // 樣式處理
test: /\.less/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 2, // 讓less文件裏引入的其餘文件也通過後面兩個loader處理
// modules: true, // css模塊化(css文件只在當前模塊有效)
}
},
'postcss-loader',
'less-loader'
]
}, {
test: /\.css$/,
use: ['style-loader', 'css-loader', 'postcss-loader']
}
]
},
plugins: [
new HtmlWebpackPlugin({ // 根據模板html, 生成新html文件
template: 'src/index.html'
}),
new CleanWebpackPlugin({ // 清除文件夾
dry: false
})
]
};
複製代碼
const webpackMerge = require('webpack-merge'); // 合併webpack配置文件
const commonConfig = require('./webpack.comm');
const prodConfig = {
mode: 'production', // 打包環境
// development:cheap-module-eval-source-map(推薦)
// production:cheap-module-source-map(推薦)
devtool: 'none', // 設置源文件與打包文件的映射關係
};
module.exports = webpackMerge(commonConfig, prodConfig);
複製代碼
const webpack = require('webpack');
const webpackMerge = require('webpack-merge'); // 合併webpack配置文件
const commonConfig = require('./webpack.comm');
const devConfig = {
mode: 'development', // 打包環境
// development:cheap-module-eval-source-map(推薦)
// production:cheap-module-source-map(推薦)
devtool: 'cheap-module-eval-source-map', // 設置源文件與打包文件的映射關係
devServer: { // 設置開發服務
contentBase: './dist', // 根目錄
open: true, // 自動打開瀏覽器
port: 8080, // 端口號
hot: true, // 開啓HMR
hotOnly: true, // 不更新瀏覽器
proxy: { // 設置接口代理(解決跨域)
'/api': 'https://localhost:3000'
}
},
optimization: {
usedExports: true, // 打包被引用的模塊
},
plugins: [
new webpack.HotModuleReplacementPlugin()
]
};
module.exports = webpackMerge(commonConfig, devConfig);
複製代碼
"scripts": {
"start": "webpack-dev-server --config ./build/webpack.dev.js",
"build": "webpack --config ./build/webpack.prod.js",
"server": "node server.js"
},
複製代碼
將重複代碼抽離出來造成單獨的chunk,避免單個文件過大,而形成文件請求時間過長
optimization: {
splitChunks: { // 代碼分割
chunks: 'all', // 自動檢測應該分離的代碼
}
}
複製代碼
webpack會自動將異步代碼打包到單獨的文件中,但webpack在打包時,沒法識別動態異步引入語法,因此咱們須要安裝@babel/plugin-syntax-dynamic-import來支持動態異步引入語法
# 支持動態異步引入模塊
npm install --save-dev @babel/plugin-syntax-dynamic-import --save-dev
複製代碼
{
"plugins": [
"@babel/plugin-syntax-dynamic-import"
]
}
複製代碼
splitChunks: {
chunks: "async",
minSize: 30000,
minChunks: 1,
maxAsyncRequests: 5,
maxInitialRequests: 3,
automaticNameDelimiter: '~',
name: true,
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
}
複製代碼
splitChunks: {
chunks: 'all', // 代碼分割目標:async(異步代碼) all(異步和同步代碼) initial(同步代碼)
minSize: 30000, // 模塊size > minSize(30KB)進行代碼分割
// maxSize: 50000, // 分割出的模塊size > maxSize(50KB)進行二次分割
minChunks: 1, // 模塊使用次數 > minChunks進行代碼分割
maxAsyncRequests: 5, // 異步模塊內部最大並行請求數
maxInitialRequests: 3, // 入口並行加載的最大請求數(入口文件最多能拆分3個文件被http請求)
automaticNameDelimiter: '~', // 文件名鏈接符
name: true, // 自動生成文件名
cacheGroups: { // 分割代碼緩存組(同步代碼分割有效)
vendors: { // vendors組,入口文件:main.js
test: /[\\/]node_modules[\\/]/, // 分割nodule_modules下的代碼
priority: -10, // 分割優先級(當模塊符合多個組時,放在優先級高的組中)
filename: 'vendors.js' // 打包文件名
},
default: { // default組,入口文件:main.js
priority: -20,
reuseExistingChunk: true, // 忽略已打包過的模塊
filename: 'common.js'
}
}
}
複製代碼
npm install --save-dev webpack-bundle-analyzer
複製代碼
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
plugins: [
new BundleAnalyzerPlugin()
]
};
複製代碼
與核心js文件一塊兒下載(不推薦)
等待覈心js文件下載完畢,網絡帶寬空閒了,再去下載其餘模塊資源(推薦)
# 將css從js文件中抽離出來
npm install --save-dev mini-css-extract-plugin
複製代碼
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
module: {
rules: [{ // 樣式處理
test: /\.(le|c)ss/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../', // 提取出來的css文件裏都會添加公共路徑
hmr: process.env.NODE_ENV === 'development'
}
}, {
loader: 'css-loader',
options: {
importLoaders: 2, // 讓less文件裏引入的其餘文件也通過後面兩個loader處理
// modules: true, // css模塊化(css文件只在當前模塊有效)
}
},
'postcss-loader',
'less-loader'
]
}]
},
plugins: [
new MiniCssExtractPlugin({ // 抽離js文件裏的css
filename: 'static/css/[name].[hash].css', // html直接引入的css文件
chunkFilename: 'static/css/[id].[hash].css' // 間接引入的css文件
})
],
};
複製代碼
# 進行css壓縮
npm install --save-dev optimize-css-assets-webpack-plugin
複製代碼
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
module.exports = {
optimization: {
minimizer: [
new OptimizeCSSAssetsPlugin({ // css代碼壓縮
})
]
}
};
複製代碼