相關的源碼地址:https://github.com/zqdeveloper/webpack
1.打包樣式資源
- loader名稱: css-loader和style-loader、less、less-loader
- 安裝方式:
npm i css-loader style-loader less less-loader -D
- 配置方式:
{
//匹配哪些文件
test:/\.css$/,
//使用哪些loader進行處理
use:[
//use數(shù)組中l(wèi)oader執(zhí)行順序,從右到左 從下到上 依次執(zhí)行
//創(chuàng)建style標簽將js中的樣式資源插入進去,添加到head中生效
'style-loader',
//將css文件一字符串的形式變成一個commonjs模塊加載到js中,里面內(nèi)容是樣式字符串
'css-loader'
]
},
{
test:/\.less$/,
use:[
'style-loader',
'css-loader',
'less-loader'
]
},
2. 打包HTML資源
- 插件名稱:html-webpack-plugin
- 安裝命令:
npm i html-webpack-plugin -D
- 插件引入:
const HtmlWebpackPlugin = require('html-webpack-plugin')
- 插件配置:
new HtmlWebpackPlugin({
//復制‘./src/index.html’文件,并自動引入打包輸出的所有資源
template:'./src/index.html'
}),
3. 打包圖片資源
- 處理圖片
1.1 loader: url-loader和file-loader
1.2 安裝命令:npm i url-loader file-loader -D
1.2 配置方式:
{
test:/\.(jpg|png|gif)$/,
//下載url-loader file-loader
loader: 'url-loader',
options:{
//圖片大小小于8kb,就會被base64處理
//優(yōu)點:減少請求數(shù)量(減輕服務器壓力)
//缺點: 圖片體積會更大,(文件請求速度更慢)
limit:8*1024,
//問題:因為url-loader默認使用es6模塊化解析,而html-loader引入圖片是commonjs
//解析時會出問題:[object module]
//解決:關閉url-loader的es6模塊化,使用commonjs解析
esModel:false,
//[hash:10]取圖片的hash的前10位
//ext:取文件原來的擴展名
name:'[hash:10].[ext]'
}
},
- 處理html中的img引用的圖片資源
2.1 loader名稱:html-loader
2.2 安裝命令:npm i html-loader -D
2.2 配置方式:
{
test:/\.html$/,
//處理html文件的img圖片(負責引入img,從而能被url-loader進行處理)
loader:'html-loader'
}
4.打包其它資源
- loader名稱: file-loader
- 安裝命令:
npm i file-loader -D
- 配置方式:
{
//打包其它資源(除了html/js/css資源以外的資源)
exclude:/\.(css|js|html)$/,
loader:'file-loader',
options:{
name:'[hash:4].[ext]'
}
}
5. DevServer
- 插件: webpack-dev-server
- 安裝命令:
npm i webpack-dev-server -D
- 配置方式:
//開發(fā)服務器devServer:用來自動化(自動編譯,自動打開瀏覽器,自動刷新瀏覽器)
//特點:只會在內(nèi)存中編譯打包,不會有任何輸出
//啟動devServer指令為:npx webpack-dev-server
devServer:{
//項目路徑
contentBase:resolve(__dirname,'build'),
//啟動gzip壓縮
compress:true,
//端口號
port:3000,
//自動打開瀏覽器
open:true,
}
6. 開發(fā)環(huán)境配置:
const {resolve} = require('path')
const HtmlWebPackPlugin = require('html-webpack-plugin')
module.exports = {
entry:'./src/js/index.js',
output:{
filename:'js/built.js',
path:resolve(__dirname,'build'),
},
module:{
rules:[
{
test:/\.css$/,
use:[
'style-loader',
'css-loader'
]
},
{
test:/\.less$/,
use:[
'style-loader',
'css-loader',
'less-loader',
]
},
{
test:/\.(gif|png|jpg)$/,
loader:'url-loader',
options:{
limit:8*1024,
esModel:false,
name:'[hash:10].[ext]',
outputPath:"imgs"
}
},
{
test:/\.html$/,
loader:'html-loader'
},
{
exclude:/\.(less|gif|png|jpg|html|css|js)$/,
loader:'file-loader',
options:{
name:'[hash:10].[ext]',
outputPath:"media"
}
}
]
},
plugins:[
new HtmlWebPackPlugin({
template:'./src/index.html',
})
],
mode:'development',
devServer:{
contentBase:resolve(__dirname,'build'),
compress:true,
port:3000,
open:true
}
}
7. 提取css成單獨文件
- 插件名成: mini-css-extract-plugin
- 安裝命令:
npm i mini-css-extract-plugin
- 插件引入: const MiniCssExtractPlugin = require('mini-css-extract-plugin')
- 插件配置:
new MiniCssExtractPlugin({
//打包名稱和路徑
filename:'css/built.css'
}),
- 同時修改loader中的style為MiniCssExtractPlugin的loader,如下:
module:{
rules:[
{
test:/\.css$/,
use:[
MiniCssExtractPlugin.loader,
//'style-loader',
'css-loader'
]
},
{
test:/\.less$/,
use:[
//'style-loader',
MiniCssExtractPlugin.loader,
'css-loader',
'less-loader'
]
},
]
},
8. css兼容性處理
- loader名稱: postcss-loader
- 安裝命令:
npm i postcss-loader -D
- 需要結合css loader一起使用
- 配置方式:
{
test:/\.css$/,
use:[
MiniCssExtractPlugin.loader,
//'style-loader',
'css-loader',
/**
* css兼容性處理:postcss-->postcss-loader postcss-preset-env
*
* 幫助postcss找到package.json中brewlist里面的配置,通過配置加載指定的css兼容性樣式
*
* "browserslist":{
* //開發(fā)環(huán)境-->設置node環(huán)境變量:process.env.NODE_ENV = development
"development":[
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
"production":[
">0.2%",
"not dead",
"not_op_mini all"
]
}
*/
//使用loader的默認配置
//‘postcss-loader’
{
loader:'postcss-loader',
options:{
ident:'postcss',
plugins: () => [
//postcss的插件
require('postcss-preset-env')()
]
}
}
]
},
- 同時需要在packages.json中增加的配置如下:
"browserslist": {
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
"production": [
">0.2%",
"not dead",
"not op_mini all"
]
}
- 要使其在開發(fā)環(huán)境中生效,需要設置node環(huán)境為developement,在webpack.config.js中設置:
process.env.NODE_ENV = 'development'
9. 壓縮css
- 所用的插件: optimize-css-assets-webpack-plugin
- 安裝命令:
npm i optimize-css-assets-webpack-plugin -D
- 插件引入: const OptimizeCssAssetsWebpaclPlugin = require('optimize-css-assets-webpack-plugin')
- 配置方式::
new OptimizeCssAssetsWebpaclPlugin()
10. js語法檢查
- 插件名稱: eslint-loader、eslint 、eslint-config-airbnb-base 、 eslint-plugin-import
- 安裝命令:
npm i eslint eslint-loader eslint-config-airbnb-base eslint-plugin-import -D
- 配置:
3.1 規(guī)則中使用:
/**
* 語法檢查: eslint-loader ,eslint-loader依賴eslint
* 注意:只檢查自己寫的源代碼,第三庫是不用檢查的
* 設置檢查規(guī)則:
* package.json中eslintConfig中配置
* airbnb --> eslint-config-airbnb-base eseslint-plugin-import
*/
{
test: /\.js$/,
loader: 'eslint-loader',
exclude: /node_modules/,//排除node_modules
options: {
fix: true
}
}
3.2 在package.json中增加:
"eslintConfig": {
"extends": "airbnb-base",
"env": {
"browser": true
}
}
11.js 兼容性處理
- 所用的loader: babel-loader @babel/preset-env @babel/core
- 安裝命令:
npm i babel-loader @babel/preset-env @babel/core -D
- 配置:
/**
* js兼容性處理: babel-loader @babel/preset-env @babel/core
* 1. 基本js兼容性處理---> @bebel/preset-env
* 問題: 只能轉換基本語法,如promise不能轉換
* 2. 全部js兼容性處理--> @babel/polyfill
*/
{
test:/\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
//預設 :babel做怎么樣的兼容性處理
presets: ['@babel/preset-env']
}
}
- @babel/polyfill 的使用
- 下載:
npm i @babel/polyfill -D
- 引用: 在入口js源代碼里面使用import 引入:
import '@babel/polyfill'
問題: 我只需要解決部分兼容性問題,但是會把所有的兼容性處理全部引入,體積太大 - 按需加載 需要做兼容性處理的就做: 按需加載 ---> core-js
7.1 安裝:npm i core-js -D
7.2 配置:
{
test:/\.js$/,
loader: 'babel-loader',
exclude: /node_modules/,
options: {
//預設 :babel做怎么樣的兼容性處理
// 預設:指示babel做怎么樣的兼容性處理
presets: [
[
'@babel/preset-env',
{
// 按需加載
useBuiltIns: 'usage',
// 指定core-js版本
corejs: {
version: 3
},
// 指定兼容性做到哪個版本瀏覽器
targets: {
chrome: '60',
firefox: '60',
ie: '9',
safari: '10',
edge: '17'
}
}
]
]
}
}
12.js壓縮
只需要把mode修改為production即可
13.html壓縮
使用HtmlWebpackPlugin即可,如下:
new HtmlWebpackPlugin({
template: './src/index.html',
minify:{
//移出空格
collapseWhitespace: true,
//移除注釋
removeComments: true
}
})
14. 生產(chǎn)環(huán)境配置
const {resolve} = require('path')
const HtmlWebPackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpaclPlugin = require('optimize-css-assets-webpack-plugin')
//定義nodejs的環(huán)境變量:決定使用browserslist的哪個環(huán)境
process.env.NODE_ENV = 'development';
//復用loader
const commonCssLoader = [
MiniCssExtractPlugin.loader,
'css-lodaer',
{
//還需要在package.json中定義browserslist
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [
require('postcss-preset-env')()
]
}
}
]
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname,'build')
},
module: {
rules:[
{
test:/\.css$/,
use: [...commonCssLoader]
},
{
test: /\.less$/,
use: [...commonCssLoader,'less-loader']
},
//正常來講,一個文件只能被一個loader處理;
//當一個文件要被多個loader處理,那么一定要指定loader的執(zhí)行先后順序;
// 先執(zhí)行eslint再執(zhí)行babel
{
//在package.json中來添加eslintConfig --> airbnb
test:/\.js$/,
exclude: /node_modules/,
loader: 'eslint-loader',
//優(yōu)先執(zhí)行
enforce:'pre',
options: {
fix: true
}
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets:[
[
'@babel/preset-env',
{
useBuiltIns:'usage',
corejs: {version:3},
targets: {
chrome: '60',
firefox: '50'
}
}
]
]
}
},
{
test:/\.(jpg|png|gif)$/,
loader: 'url-loader',
options: {
limit: 8*1024,
//使用來html-loader一定要關閉url-loader的esModel
esModule: false,
name: '[hash:10].[ext]',
outputPath: 'imgs'
}
},
{
test: /\.html$/,
loader: 'html-loader',
},
{
exclude:/\.(js|css|less|html|jpg|png|gif)$/,
loader: 'file-loader',
options: {
outputPath: 'media'
}
}
]
},
plugins:[
new HtmlWebPackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
}),
new MiniCssExtractPlugin({
filename:'css/built.css'
}),
new OptimizeCssAssetsWebpaclPlugin()
],
mode: 'production'
}
15. 開發(fā)環(huán)境優(yōu)化
/**
* HMR: hot module replacement 熱模塊替換/模塊熱替換
* 作用: 一個模塊發(fā)生變化,只會重新打包這一個模塊(而不是打包所有模塊)
* 極大提升構建速度
*
* 樣式文件 :可以使用HMR功能:因為style-loader內(nèi)部實現(xiàn)了~
* js文件:默認沒有HMR功能--->需要修改js代碼,添加支持HMR功能的代碼
* 注意:HMR功能對js的處理,只能處理非入口js文件的其它文件
* HTML文件: 默認也不能使用HMR功能,同時導致HTML不能熱更新了~(不用做HMR功能)
* 解決: 修改entry入口,入口html也引入
*/
const {resolve} = require('path')
const HtmlWebPackPlugin = require('html-webpack-plugin')
module.exports = {
entry: ['./src/js/index.js','./src/index.html'],
output:{
filename:'js/built.js',
path:resolve(__dirname,'build'),
},
module:{
rules:[
{
test:/\.css$/,
use:[
'style-loader',
'css-loader'
]
},
{
test:/\.less$/,
use:[
'style-loader',
'css-loader',
'less-loader',
]
},
{
test:/\.(gif|png|jpg)$/,
loader:'url-loader',
options:{
limit:8*1024,
esModel:false,
name:'[hash:10].[ext]',
outputPath:"imgs"
}
},
{
test:/\.html$/,
loader:'html-loader'
},
{
exclude:/\.(less|gif|png|jpg|html|css|js)$/,
loader:'file-loader',
options:{
name:'[hash:10].[ext]',
outputPath:"media"
}
}
]
},
plugins:[
new HtmlWebPackPlugin({
template:'./src/index.html',
})
],
mode:'development',
devServer:{
contentBase:resolve(__dirname,'build'),
compress:true,
port:3000,
open:true,
//開啟HMR功能
//當修改了webpack配置,新配置要想生效,必須要重啟webpack服務
hot: true
}
}
16.source-map
source-map: 一種提供源代碼到構建后代碼映射技術(如構建后代碼出錯了,通過映射關系可以追蹤源代碼的錯誤)
[inline-|hidden-|eval-][nosources-][cheap-[module-]]souce-map
inline-source-map: 內(nèi)聯(lián)
只生成一個內(nèi)聯(lián)source-map
錯誤代碼準確信息和源代碼準確位置
hidden-source-map: 外部
能夠提示到錯誤的錯誤原因,但是沒有錯誤位置,不能追蹤到源代碼的錯誤,只能提示到構建后代碼的錯誤位置
eval-source-map: 內(nèi)聯(lián),
每一個文件都生成對應的source-map,都在eval
錯誤代碼準確信息和源代碼準確位置
多了一個hash值
nosources-source-map: 外部
能夠提示到錯誤的錯誤原因,但是沒有任何源代碼信息
cheap-source-map: 外部
錯誤代碼準確信息和源代碼準確位置,但是錯誤位置只精確到行,不精確到列
cheap-module-source-map: 外部
錯誤代碼準確信息和源代碼準確位置,但是錯誤位置只精確到行,不精確到列
會將loader和source map加入
source-map:外部
錯誤代碼準確信息和源代碼準確位置
內(nèi)聯(lián)和外部的區(qū)別:1.外部生成了文件,內(nèi)聯(lián)是沒有的;2.內(nèi)聯(lián)構建速度更快
開發(fā)環(huán)境:速度快,調(diào)試更友好
速度快(eval>inline>cheap>...)
eval-cheap-source-map
eval-source-map
調(diào)試更友好
source-map
cheap-module-source-map
cheap-source-map
-->eval-source-map /eval-cheap-module-sourcemap
生產(chǎn)環(huán)境:源代碼要不要隱藏?調(diào)試要不要更友好
內(nèi)聯(lián)會讓代碼體積非常大,所以再生產(chǎn)環(huán)境不用內(nèi)聯(lián)
nosources-source-map 全部隱藏
hidden-source-map 只隱藏源代碼,會提示構建后代碼錯誤
-->source-map /cheap-module-source-map
17. oneof
在roles種使用oneof,需要注意事項:
- 一下loader只會匹配一個
- 注意:不能讓兩個loader處理同一種類型的文件
- 正常來講,一個文件只能被一個loader處理;
- 當一個文件要被多個loader處理,那么一定要指定loader的執(zhí)行先后順序;
- 先執(zhí)行eslint再執(zhí)行babel
代碼如下:
rules:[
{
//在package.json中來添加eslintConfig --> airbnb
test:/\.js$/,
exclude: /node_modules/,
loader: 'eslint-loader',
//優(yōu)先執(zhí)行
enforce:'pre',
options: {
fix: true
}
},
{
//一下loader只會匹配一個
//注意:不能讓兩個loader處理同一種類型的文件
oneof: [
{
test:/\.css$/,
use: [...commonCssLoader]
},
{
test: /\.less$/,
use: [...commonCssLoader,'less-loader']
},
//正常來講,一個文件只能被一個loader處理;
/當一個文件要被多個loader處理,那么一定要指定loa 行先后順序;
// 先執(zhí)行eslint再執(zhí)行babel
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets:[
[
'@babel/preset-env',
{
useBuiltIns:'usage',
corejs: {version:3},
targets: {
chrome: '60',
firefox: '50'
}
}
]
]
}
},
{
test:/\.(jpg|png|gif)$/,
loader: 'url-loader',
options: {
limit: 8*1024,
/使用來html-loader一定要關閉url-loader的e l
esModule: false,
name: '[hash:10].[ext]',
outputPath: 'imgs'
}
},
{
test: /\.html$/,
loader: 'html-loader',
},
{
exclude:/\.(js|css|less|html|jpg|png|gif)$/,
loader: 'file-loader',
options: {
outputPath: 'media'
}
}
]
}
]
18.緩存
- 在babel-loader中開啟緩存
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets:[
[
'@babel/preset-env',
{
useBuiltIns:'usage',
corejs: {version:3},
targets: {
chrome: '60',
firefox: '50'
}
}
]
],
//開啟babel緩存
//第二次構建時,會讀取之前的緩存
cacheDirectory: true
}
},