導航
[深入01] 執(zhí)行上下文
[深入02] 原型鏈
[深入03] 繼承
[深入04] 事件循環(huán)
[深入05] 柯里化 偏函數(shù) 函數(shù)記憶
[深入06] 隱式轉(zhuǎn)換 和 運算符
[深入07] 瀏覽器緩存機制(http緩存機制)
[深入08] 前端安全
[深入09] 深淺拷貝
[深入10] Debounce Throttle
[深入11] 前端路由
[深入12] 前端模塊化
[深入13] 觀察者模式 發(fā)布訂閱模式 雙向數(shù)據(jù)綁定
[深入14] canvas
[深入15] webSocket
[深入16] webpack
[深入17] http 和 https
[深入18] CSS-interview
[深入19] 手寫Promise
[深入20] 手寫函數(shù)
[部署01] Nginx
[部署02] Docker 部署vue項目
[部署03] gitlab-CI
[源碼-webpack01-前置知識] AST抽象語法樹
[源碼-webpack02-前置知識] Tapable
[源碼-webpack03] 手寫webpack - compiler簡單編譯流程
[源碼] Redux React-Redux01
[源碼] axios
[源碼] vuex
[源碼-vue01] data響應(yīng)式 和 初始化渲染
[源碼-vue02] computed 響應(yīng)式 - 初始化,訪問,更新過程
前置知識
一些單詞
proposal:提議,建議
decorator:修飾
expose:暴露
license:執(zhí)照,許可
compress:壓縮
determine:確定,查明
wildcard:通配符
collapse:塌方,瓦解
quote:引用
extract:抽離,提取
optimization:最佳優(yōu)化
plug:插頭,插座 (pluggable:可插拔)
complete:完成
represents:代表
package.json
name
- 定義包的名稱,是發(fā)布到npm注冊表時,軟件包顯示的名稱
- 必須是小寫,允許( 連字符和下劃線 ),不允許 ( 空格和其他字符 )
- name: 'webpack-learning'
- 注意:如果要發(fā)布到npm上,包的名稱必須是唯一的
main !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- 定義項目的入口點
- 默認是index.js
version
- 軟件的當前版本
license
- 代碼許可證
- MIT
- ISC
author 和 contributors
- author:一個人
- contributors:多個人
- "author": "...",
- "contributors": [{
"name": "...",
"email": "...",
"url": "..."
}],
keywords
- 搜索索引
- "keywords": ["server", "osiolabs", "express", "compression"]
path.resolve 和 path.join 和 __dirname變量
-
<font color=blue>path.resolve() --------------------------- 生成絕對路徑</font>
- path.resolve([...paths])
- <font color=red>將( 路徑或路徑片段 ) 的序列解析為 ( 絕對路徑 )</font>
- 參數(shù):路徑或路徑片段的序列
- 返回值:一個絕對路徑
- 注意:
- 不傳參數(shù)將返回當前工作目錄的絕對路徑
- 0長度的path片段將被忽略
-
<font color=blue>path.join()--------------------------------- 拼接路徑</font>
- path.join([...paths])
- 注意:
- 0長度的路徑將被忽略
- <font color=blue> __dirname -------------------------------- 當前模塊的目錄名,是一個絕對路徑</font>
process.env ---------------------------- 返回包含用戶環(huán)境的對象
- process.env 返回包含用戶環(huán)境的對象
- <font color=red>注意:process.env對象上分配的屬性,值會被隱式轉(zhuǎn)換為字符串,當值不是string,number,boolean時可能會報錯</font>
- 注意:可以修改此對象,但這些修改不會反映到 Node.js 進程之外
- <font color=red>刪除屬性:delete </font>
- delete process.env.xxxx
- 注意:在windows系統(tǒng)上,環(huán)境變量不區(qū)分大小寫
- <font color=red>process.env.NODE_ENV不是process.env對象的原有屬性,是自定義的</font>
- 原因:在window和mac有差異
- 所以:一般通過 ( cross-env ) 插件來設(shè)置
npm install --save-dev cross-env
- cross-env
(1) 生效
process.env.foo = 'bar';
console.log(process.env.foo);
(2) process.env的屬性會隱式轉(zhuǎn)換為字符串
process.env.test = null;
console.log(process.env.test);
// => 'null'
process.env.test = undefined;
console.log(process.env.test);
// => 'undefined'
(3) delete 刪除屬性
process.env.TEST = 1;
delete process.env.TEST;
console.log(process.env.TEST);
// => undefined
(4) window上 ( 環(huán)境變量 ) 不區(qū)分大小寫
process.env.TEST = 1;
console.log(process.env.test);
// => 1
---
cross-env
{
"scripts": {
"build": "cross-env NODE_ENV=production webpack --config build/webpack.config.js"
}
}
會用到的依賴
- webpack webpack-cli
- html-webpack-plugin
- webpack-dev-server
css相關(guān)
- style-loader
- css-loader
- less-loader
- 抽離css
- mini-css-extract-plugin
- 前綴
- postcss-loader
- autoprefixer
- 壓縮css
- (注意:用于生產(chǎn)環(huán)境才去壓縮css,因為影響打包速度)
- optimize-css-assets-webpack-plugin
- uglifyjs-webpack-plugin
js相關(guān)
- babel-loader
- @babel/core
- @babel/preset-env
- @babel/plugin-proposal-decorators
- @babel/plugin-proposal-class-properties
- @babel/plugin-transform-runtime
- @babel/runtime
- @babel/polyfill
- eslint ellint-loader babel-eslint
- expose-loader
圖片相關(guān)
- file-loader
- url-loader
- html-withimg-loader
- 2021/01/11 更新
源碼倉庫
代碼分割 webpack.DllPlugin 和 optimization.splitChunks 的區(qū)別
- <font color=red>(webpack.DllPlugin,webpack.DllReferencePlugin) 和 optimization.splitChunks 都能實現(xiàn)代碼分割</font>
- 優(yōu)先使用 optimization.splitChunks.cacheGoup
- SplitChunksPlugin
SplitChunksPlugin
默認配置:
module.exports = {
//...
optimization: {
// -------------- 默認配置,該段配置的效果和 optimization: {splitChunks: {}} 效果一樣
// -------------- 即 splitChunks 配一個空對象和下面的代碼等價
splitChunks: {
chunks: 'async',
// -------------- chunks: 'async' 只對異步引入的代碼就行代碼分割,比如 import().then()語法動態(tài)引入的包或者路由組件
// -------------- chunks: 'all' 對同步引入和異步引入的代碼都做代碼分割,還需后續(xù)配置cacheGroups
// -------------- chunks: 'initial' 對同步代碼進行分割
minSize: 30000,
// -------------- minSize: 30 000 表示當包大于( 30KB )時,就進行代碼分割
maxSize: 0,
// -------------- maxSize表示對打包后的庫進行二次拆分,可配可不配
minChunks: 1,
// -------------- minChunks 表示當一個模塊至少使用多少次時才進行代碼分割
maxAsyncRequests: 5,
maxInitialRequests: 3,
automaticNameDelimiter: '~', // 文件命名之間的連接符,比如name和入口文件名之間的連接
name: true,
cacheGroups: { // 一個可能包含多個包的組
vendors: {
// ----------------- 表示如果滿足chunks設(shè)置項,并且在node_modules文件夾下,就打包成 vendors~main.js
// ----------------- vendors~main.js 中的 main 表示入口文件打包后的文件名是 main.js
// ----------------- 如果要修改滿足chunks的配置引入的包打包的名字用:filename 去配置
// ----------------- cacheGroups 和 chunks 是配合來用的
test: /[\\/]node_modules[\\/]/,
//---------------- 從node_modules文件夾中引入的,實際上就是第三方組件庫,依賴庫
priority: -10,
// --------------- priority表示當同時滿足vendors和default時, piroity越大優(yōu)先級越高,(優(yōu)先級)
filename: 'vendors', // ------------- 打包后滿足chunks和以上各個條件的引入的包會被打包到名為 vendors.js 的文件中
},
default: { // 不滿足vendors但是又滿足chunks等以上的一些條件,說明需要做代碼分割,但不是vendors,則會走default
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
// reuseExistingChunk表示一個包如果打包過了,在別的包中又引用了,打包別的包時就不再打包了,直接引用
filename: 'common'
}
}
}
}
};
webpack基礎(chǔ)
- webpack是一個 ( <font color=red>模塊打包</font> ) 工具,最基本的就是一個js模塊打包工具,如果添加了loader則可以打包任何相應(yīng)的資源
- 可以 0 配置,但是為了符合項目需求,一般都會自己配置
0配置下
默認配置運行:-------------------------------------- npx webpack xxx.js
打包后生成的 ( 文件夾 ) 名稱:---------------------- dist
打包后生成的 ( 文件 ) 名稱:------------------------ main.js
(2)
webpack默認配置文件
默認的webpack配置文件名稱:------------------------- webpack.config.js || webpackfile.js
(3)
如何用命令行指定webpack的配置文件,并執(zhí)行這個文件
---------------------------------------------------- npx webpack --config xxxxx
webpack webpack-cli
npm install -D webpack-cli webpack
- 注意是開發(fā)時依賴,線上使用打包后的文件
webpack-dev-server
npm install -D webpack-dev-server
- webpack-dev-server可以啟一個簡單的web服務(wù),并且具有 live-reloading 實時重新加載
- 配置項:
- contentBase:啟動的服務(wù)從哪個目錄中加載資源
- port:服務(wù)端口號
- <font color=red>publicPath:設(shè)置公共路徑,此路徑下的打包文件,可以在瀏覽器中訪問</font>
- <font color=red>比如部署到CDN上,html的所有引入資源都需要加上CDN的地址作為公共路徑,這時需要設(shè)置publciPath</font>
- <font color=red>proxy:設(shè)置代理</font> ,使用的是 http-proxy-middleware
- <font color=red>compress:是否開啟 gzip 壓縮</font>
- hot:是否開啟熱更新 ( 模塊熱替換 )
- open:是否在啟動服務(wù)后打開瀏覽器
- host:指定host
- color:控制臺彩色輸出,boolean,注意只用于命令行
- proxy
proxy
var apiProxy = proxy('/api', { target: 'http://www.example.org' });
// \____/ \_____________________________/
// | |
// context options
(1)
proxy: {
'/api': 'http://www.baidu.com'
}
請求:'/api/user'
會被代理到:'http://www.baidu.com/api/user'
(2)
需求:如何在真實的請求路徑中去掉 '/api'
解決:重寫路徑
proxy: {
'/api': {
target: 'http://www.baidu.com',
pathRewrite: {
'^/api': '' //------------------------------------- remove path 即刪除 '/api'
}
}
}
請求:'/api/user'
會被代理到:'http://www.baidu.com/user'
---
webpack-dev-server
devServer: { // --------------------------------------------- webpack-dev-server配置項
contentBase: path.join(__dirname, 'dist'), // ------------- 啟動服務(wù)加載的靜態(tài)資源
port: '5000', // ------------------------------------------ 端口號
compress: true, // ---------------------------------------- 是否開啟 gzip 壓縮
open: true, // -------------------------------------------- 是否打開瀏覽器標簽,在服務(wù)啟動后
proxy: { // ----------------------------------------------- 代理
'/api': { // -------------------------------------------- context,需要代理的路徑
target: 'http://yapi.wxb.com.cn', // ------------------ 目標地址
pathRewrite: { // ------------------------------------- 路徑重寫
'^/api': '' // -------------------------------------- remove path 相當于把 '/api' 用 '' 代替
}
}
}
},
<font color=red>proxy 實例</font>
(1)
index.js
const api = new XMLHttpRequest()
api.open('GET', '/api/name', true) // --------------------------------- 請求路徑 ( '/api/name' )
api.onload = function() {
const res = api.response
console.log(res, 'res')
}
api.send()
(2)
devServer: {
contentBase: path.join(__dirname, 'dist'),
port: '5000',
compress: true,
open: true,
proxy: {
'/api': {
target: 'http://localhost:7000', // ----------------------- 服務(wù)代理到http://localhost:7000
pathRewrite: {
'^/api': ''
// ------------------------------------------------------ 重寫'/api'
// ------------------------------------------------------ '/api/name' 將代理到 'http://localhost:7000/name'
}
}
}
},
(3)
server => index.js
var express = require('express')
var app = express()
app.get('/name', (req, res) => { // ----------------------------- 服務(wù)端啟動在:'http://localhost:7000/name'
res.json({
name: 'woow_wu7'
})
})
app.listen(7000, () => console.log('the server is running on port 7000'))
html-webpack-plugin
npm install html-webpack-plugin -D
- 配置項:
- template:模板html文件
- filename:打包后的文件名
- <font color=red>hash:在html引用js時是否使用hash戳</font>
- <font color=red>minify:用于 ( 生產(chǎn)環(huán)境 ) 即mode=production中,是一個 ( 布爾值 ) 或者 ( 對象 )</font>
- removeAttributeQuotes:去除html屬性值的雙引號
- collapseWhitespace:折疊空行,即只有一行代碼
html-webpack-plugin
const HtmlWebpackPlugin = require('html-webpack-plugin')
plugins: [ // ------------------------------------------------- plugins是一個插件數(shù)組
new HtmlWebpackPlugin({
template: './src/index.html', // -------------------------- 模板html
filename: 'index.html', // -------------------------------- 打包后的html的文件名
hash: true, // -------------------------------------------- html引用的js是否帶有hash戳
minify: { // ---------------------------------------------- 壓縮優(yōu)化
removeAttributeQuotes: true, // ------------------------- 刪除html標簽屬性值的雙引號
collapseWhitespace: true, // ---------------------------- 折疊空行為一行
}
})
]
loader
- <font color=red>loader加載順序: 從右往左,從下往上</font>
- loader文檔
css相關(guān)
( css-loader ) ( style-loader ) ( less-loader )
npm install style-loader css-loader less less-loader -D
- css-loader
- 主要用來支持 @import 語法的css引入
- style-loader
- 主要作用是把css以 ( style標簽的 ) 形式嵌入到html的head標簽中
- 注意順序是:先css-loader處理完css后,再style-loader插入到head標簽中
- 配置項 options
- <font color=red>insert: 'body' 將style標簽插入到body標簽中,默認是插入到head標簽中</font>
style-loader
css-loader
less-loader 還得安裝 less
sass-loader 還得安裝 node-sass
module: { // 模塊
rules: [ // 規(guī)則
{
test: /\.css$/, // ------------------------ 處理css
// ----------------------------------------- 正則匹配,注意loader的順序是從右往左,從下往上
use: [
{
loader: 'style-loader',
options: {
// insert: 'body' // ----------------- style標簽?zāi)J插入到header標簽中,這里可以插入到body標簽中
}
},
{
loader: 'css-loader',
},
]
},{
test: /\.less$/, // ------------------------ 處理less
use: [
{loader: 'style-loader'},
{loader: 'css-loader'},
{loader: 'less-loader'}
]
}
]
},
mini-css-extract-plugin ------ 抽離css
npm install mini-css-extract-plugin -D
- <table bgcolor=orange><tr><td>默認情況下:style-loader是把css文件轉(zhuǎn)換成 style 標簽內(nèi)嵌在html中,我們希望的是用 link 標簽外部引入css,所以用mini-css-extract-plugin來抽離css,通過link標簽把css引入html</td></tr></table>
- extract:抽離的意思
- mini-css-extract-plugin官網(wǎng)
const MiniCssExtractPlugin = require('mini-css-extract-plugin') // ---------------- 引入
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader, // -------------------------------------------- loader
{
loader: 'css-loader',
},
]
},{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
{loader: 'css-loader'},
{loader: 'less-loader'}
]
}
]
},
plugins: [
new MiniCssExtractPlugin({ // ---------------------------------------------------- plugin
filename: 'main.css' // -------------------------------------------------------- 抽離出來的css文件名
// filename: 'css/main.css' // ----------------- 這樣會在打包后生成css文件夾,里面是所有css都在main.css文件中
})
]
postcss-loader 和 autoprefixer ------ 生成瀏覽器前綴
- postcss-loader
- <table bgcolor=orange><tr><td>用來解決瀏覽器前綴,兼容性處理,需要單獨的配置文件 postcss.config.js</td></tr></table>
- 解決瀏覽器前綴:(1) 單獨配置postcss.config.js (2) 還需配合插件 autoprefixer
- <font color=blue>注意loader間的順序:比如需要處理完less => 加上前綴后 => 識別@import => 再抽離css</font>
- 即先 less-loader => postcss-loader => css-loader => MiniCssExtractPlugin.loader
- autoprefixer
- <font color=red>autoprefixer需要給出瀏覽器的一些信息,所以要在 package.json 中添加 browserslist 配置 </font>
postcss-loader 和 autoprefixer 解決瀏覽器前綴問題
(1) loader間的順序
(2) postcss-loader需要單獨配置postcss.config.js
(3) autoprefixer需要給出瀏覽器的一些信息,需要在 package.json 中配置 browserslist 屬性
---
package.json中
"browserslist": [
"defaults",
"not ie < 9",
"last 3 version",
">1%",
"ios 7",
"last 3 iOS versions"
]
---
postcss.config.js中
const autoprefixer = require('autoprefixer')
module.exports = {
plugins: [autoprefixer]
}
---
webpack.config.js中
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
{ loader: 'css-loader'},
{ loader: 'postcss-loader'}, //----------------- postcss-loader,注意順序
]
},{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
{loader: 'css-loader'},
{ loader: 'postcss-loader'},
{loader: 'less-loader'}
]
}
]
optimize-css-assets-webpack-plugin 和 uglifyjs-webpack-plugin ------ 壓縮css 和 js
npm install optimize-css-assets-webpack-plugin uglifyjs-webpack-plugin -D
- <table bgcolor=orange><tr><td>注意壓縮css是用于 ( 生產(chǎn)環(huán)境 ) 才去壓縮css,因為會影響打包速度</td></tr></table>
- <table bgcolor=yellow><tr><td>注意:( html-webpack-plugin ) 通 過minify => removeAttribureQuote, collapseWhitespace 來壓縮html也是用在 ( 生產(chǎn)環(huán)境 )</td></tr></table>
- optimize-css-assets-webpack-plugin
- 注意:
- 問題:
使用 optimize-css-assets-webpack-plugin 插件后,單獨抽離的css會被壓縮,但是打包的js文件又沒有被壓縮了
- 解決:
使用 uglifyjs-webpack-plugin 插件來解決js沒有被壓縮的問題
- 問題:
- 注意:
- uglifyjs-webpack-plugin
optimization: { // -------------------------------- 優(yōu)化項 (optimization:是最佳優(yōu)化的意思)
// ---------------------------------------------- 注意:壓縮css和js要在mode=production中才能看到效果,和 html的優(yōu)化一樣
minimizer: [
new OptimizeCssAssetsWebpackPlugin(), // ------ optimize-css-assets-webpack-plugin 壓縮單獨抽離的css
new UglifyjsWebpackPlugin({ // ---------------- 壓縮js
cache: true,
parallel: true, // 平行,并行的意思
sourceMap: true, // 調(diào)試映射
})
]
}
js相關(guān)
- babel-loader
- @babel/core
- @babel/preset-env
- @babel/plugin-proposal-decorators // -------------------- 裝飾器語法
- @babel/plugin-proposal-class-properties // -------------- class語法
- @babel/plugin-transform-runtime
- @babel/runtime // ---------------------------注意是該依賴是 dependencies 而不是 devDependencies
- @babel/polyfill
npm install babel-loader @babel/core @babel/preset-env -D
npm install @babel/plugin-proposal-class-properties @babel/plugin-proposal-decorators -D
npm install @babel/plugin-transform-runtime -D
-
npm install @babel/runtime -S
注意是-S -
npm install @babel/polyfill -S
注意是-S - babel官網(wǎng)
- 注意點:
- babel的配置:
- <font color=red>(1)可以新建.babelrc文件單獨配置</font>
- <font color=red>(2)可以在webpack的loader配置的babel-loader的options中配置</font>
- @babel/plugin-proposal-decorators 和 @babel/plugin-proposal-class-properties的順序
- @babel/plugin-proposal-decorators --------------在前
- @babel/plugin-proposal-class-properties---------在后
- babel的配置:
.babelrc文件
{
"presets": [
["@babel/preset-env", {
"modules": false
}]
],
"plugins": [
["@babel/plugin-proposal-decorators", {"legacy": true}],
["@babel/plugin-proposal-class-properties", {"loose": true}],
["@babel/plugin-transform-runtime"]
]
}
----
@babel/polyfill 插件是直接引入到入口js文件中
require('@babel/polyfill')
加入eslint校驗 (eslint) (eslint-loader) (babel-eslint)
npm install eslint eslint-loader babel-eslint -D
- eslint
- eslint-loader
- babel-eslint
- 注意點:
- <table bgcolor=orange><tr><td>(1) 需要單獨配置 ( .eslintrc.json ) 文件,或者直接在 ( package.json ) 文件的 ( eslintConfig ) 字段中配置rule規(guī)則</table></tr></td>
- <font color=red>(2) 注意eslint-loader和babel-loader的順序</font>
- 順序:先校驗再處理
- 是要先校驗eslint-loader,然后在babel-loader轉(zhuǎn)換
- 在eslint-loader的options選中,可以使用 enforce: 'pre' 來優(yōu)先執(zhí)行,即使順序是eslint-loader在上面或前面
- <font color=red>(3) 需要安裝bebel-eslint插件 Cannot find module 'babel-eslint'</font>
.eslintrc
{
"parser": "babel-eslint", // 這里必須設(shè)置
"parserOptions": {
"sourceType": "module",
"allowImportExportEverywhere": true
},
"rules": {
"indent": "off",
"no-console": 2 // 不允許console.log()
},
"env": {}
}
------------
webpack.config.js
{
test: /\.js$/,
use: [ // ----------------------------------------------- use可以是數(shù)組 或者 對象
{
loader: 'babel-loader',
options: { // ---------------------------------- 除了在這里配置外,還可以單獨設(shè)置 .babelrc 文件配置babel
presets: [
['@babel/preset-env']
],
plugins: [
['@babel/plugin-proposal-decorators', {'legacy': true}],
['@babel/plugin-proposal-class-properties', {'loose': true}],
['@babel/plugin-transform-runtime']
]
}
},
{
loader: 'eslint-loader', // -------------------------- eslint-loader
options: {
enforce: 'pre'
}
}
],
include: path.resolve(__dirname, 'src'),
exclude: path.resolve(__dirname, 'node_modules'),
},
// {
// test: /\.js$/,
// use: { // --------------------------------------- use是對象
// loader: 'eslint-loader',
// options: {
// enforce: 'pre'
// },
// },
// include: path.resolve(__dirname, 'src'),
// exclude: path.resolve(__dirname, 'node_modules'),
// },
loader的類型
- pre ----------------------- 前置loader
- post ---------------------- 后置loader
- normal ------------------- 普通loader
- inline --------------------- 內(nèi)聯(lián)loader,即可以直接寫在js代碼中的loader
expose-loader 和 wepback.ProvidePlugin()
npm install expose-loader -D
- expose-loader暴露全局的loader
- expose:暴露
- expose-loader的三種用法
expose-loader的三種用法
(1)
直接在js中引入:---------------- import $ from 'expose-loader?$!jquery'
上面的操作可以把:$掛載到window上,即可以通過 ( window.$ ) 訪問到j(luò)query
(2)
在webpack.config.js中 module => rules 中配置
{
test: require.resolve('jquery'),
// require.resolve()是nodejs中的函數(shù),只要require了jquery就進行匹配
// require.resolve():使用內(nèi)部的 require() 機制查詢模塊的位置,此操作只返回解析后的文件名,不會加載該模塊。
use: [
{
loader: 'expose-loader',
options: 'jquery' // 暴露成window.jquery
},
{
loader: 'expose-loader',
options: '$' // 暴露成window.$
}
]
},
(3)
在每個模塊中注入$,不需要在每個模塊中再引入,可以使用 webpack.ProvidePlugin插件,再plugins中加入
new webpack.ProvidePlugin({ // ----------------- webpack.ProvidePlugin()
$: 'jquery' // ----------------------------- 在每個模塊中都注入$符
})
使用:直接在模塊中就可以使用 $ , 并不需要在頭部引入
圖片處理
npm install file-loader url-loader html-withimg-loader -D
- file-loader
- 會生成一張圖片到build的目錄下,并將圖片的名稱返回回來
- url-loader
- <font color=red>可以設(shè)置大小限制,小于時,url-loader會將圖片轉(zhuǎn)成base64,大于時,使用file-loader加載圖片</font>
- 在options: {limit: 200 * 1024}來設(shè)置,200k,通過 ( <font color=red>limit</font> ) 來設(shè)置
- <font color=red>options: {outputPath: 'img/'} ----- 將圖片打包到img文件夾下</font>
- <table bgcolor=orange><tr><td>注意:(1)css所有文件單獨抽離成一個文件放到一個文件夾中是使用 mini-css-extract-plugin (2) 圖片單獨抽離到文件夾中是url-loader中配置options的outputPath</td></tr></table>
- html-withimg-loader
- <font color=red>注意:使用該插件時可能報錯,需要在url-loader的options中設(shè)置 esModule: false </font>
- 圖片的引入方式
- 在js中引入,可以通過new Image().src等
- 在css中,通過 background-iamge來引入
- 在html中,通過 img 標簽來引入
file-loader
url-loader
html-withimg-loader
webpack.config.js
{
test: /\.(png|jpg|jpeg|gif)$/,
use: [
{
// loader: 'file-loader',
loader: 'url-loader',
options: {
limit: 200 * 1024, // ----------------- 小于200k,使用base64編碼圖片,大于使用file-loader加載圖片
esModule: false, // ------------------- 用于html-withimg-plugin生效
outputPath: 'img/', // ---------------- 輸出到 img 文件夾中
publicPath: 'www.baidu.com/' // ------- 單獨配置img的公共路徑,而不是在output中全部配置
}
}
]
},
{
test: /\.html$/, // ----------------- html-withimg-loader
use: 'html-withimg-loader'
}
使用:
js中
import one from './images/1.jpg'
const imgx = new Image(100, 100)
imgx.src = one
if (imgx.complete) {
addChild()
} else {
imgx.onload = addChild
}
function addChild() {
document.body.appendChild(imgx)
}
css中
#div-image {
width: 200px;
height: 200px;
background: url('./images/1.jpg');
}
html中
<img src="./images/1.jpg" alt="" width="300" height="300">
靜態(tài)資源分類
- 圖片
- url-loader => options => outputPath: 'img/'
- css
- mini-css-extract-plugin => filename: 'css/main.css'
- 公共路徑
- <font color=red>在 output => publicPath 中設(shè)置公共路徑,當打包后html加載資源時,都會加上公共路徑 </font>
- 比如:不是放在本地,放在CDN上,就要在所有路徑上服務(wù)器的地址
如果只是想給圖片加載公共路徑,而其他資源不加的話,就要在url-loader中單獨設(shè)置,同時output的publicPath不用設(shè)置
靜態(tài)資源分類
圖片
{
test: /\.(png|jpg|jpeg|gif)$/,
use: [
{
// loader: 'file-loader',
loader: 'url-loader',
options: {
limit: 200 * 1024,
esModule: false,
outputPath: 'img/' // ----------------------------- 所有圖片將放到打包后的 ( img文件夾中 )
}
}
]
},
css
plugins: [
new MiniCssExtractPlugin({
filename: 'css/main.css' // ---------------------------- 所有css將放入到打包后的 ( css文件夾的main.css中 )
}),
],
公共路徑:所有路徑都加
output: {
filename: 'index.[hash:8].js',
path: path.resolve(__dirname, 'dist'),
publicPath: 'www.baidu.com/' // -------------------------- 設(shè)置公共路徑,打包后html中引入的資源都會加上這個前綴路徑
},
公共路徑:只是圖片加
{
test: /\.(png|jpg|jpeg|gif)$/,
use: [
{
// loader: 'file-loader',
loader: 'url-loader',
options: {
limit: 200 * 1024,
esModule: false,
outputPath: 'img/',
publicPath: 'www.baidu.com/' // ---------------------- 只給圖片設(shè)置publicPath
}
}
]
},
打包多頁應(yīng)用
- entry:可以是一個對象
- output:'[name].js' =>
[]是占位符
=>[name]的值就是entry對象中的key
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode: 'development',
entry: {
home: './src/home.js',
other: './src/other.js',
},
output: {
filename: '[name].js', // ---------------------------- 占位符,name表示entry對象中的 key
path: path.resolve(__dirname, 'dist')
},
devServer: {
contentBase: path.resolve(__dirname, 'dist'),
port: 5000,
open: true,
compress: true,
},
plugins: [
new HtmlWebpackPlugin({ // ---------------------------- html-webpack-plugin可以new多個
template: './src/index.html',
filename: 'home.html',
chunks: ['home'] // --------------------------------- 每個chunk對應(yīng)加載哪些打包后的 js 文件,即 output指定的輸出js文件
}),
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'other.html',
chunks: ['other']
}),
]
}
source-map 源碼映射
-
devtool: 'source-map'
// 顯示行數(shù),產(chǎn)生map文件 -
devtool: 'eval-source-map'
// 顯示行數(shù),不產(chǎn)生map文件
watch 實時打包
watch: true,
watchOptions: {
aggregateTimeout: 300, // 防抖
poll: 1000, // 每秒詢問1000次
ignored: /node_modules/
},
aggregate: 總計,合計的意思
poll:是輪詢的意思
clean-webpack-plugin ---------- 刪除打包后的文件夾,默認是刪除 output.paht 指定的文件夾
npm install --save-dev clean-webpack-plugin
- clean-webpack-plugin
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
plugins: [
new CleanWebpackPlugin() //---------- 默認是刪除 output.path 指定的文件夾
],
copy-webpack-plugin ---------- 復(fù)制文件
npm install copy-webpack-plugin -D
const CopyWebpackPlugin = require('copy-webpack-plugin')
plugins: [
new CopyWebpackPlugin([{
from: './src/copywebpackplugin', // -------- 將該文件夾中的內(nèi)容拷貝到dist文件夾中
to: './' // -------------------------------- 默認是輸出到 output.path 指定的文件夾中
}])
],
BannerPlugin ---------------- webpack自帶的plugin,用于在js文件開頭注釋一些說明內(nèi)容
new webpack.BannerPlugin({ banner: ' by woow_wu7'})
對比:webpack自帶插件還有 webpack.ProvidePlugin ------- 將jquery暴露到每個模塊,為$符號
// 在每個模塊中注入$,不需要在每個模塊中再引入,可以使用 webpack.ProvidePlugin插件,再plugins中加入
new webpack.ProvidePlugin({
$: 'jquery'
}),
webpack-dev-server => before(app) => 實現(xiàn)mock數(shù)據(jù)
devServer: {
contentBase: path.join(__dirname, 'dist'),
port: '5000',
compress: true,
open: true,
// proxy: {
// '/api': {
// target: 'http://localhost:7000',
// pathRewrite: {
// '^/api': ''
// }
// }
// },
before(app) { // ------------------------------ before鉤子函數(shù),app即express()
app.get('/api/user', (req, res) => {
res.json({
user: 'woow_wu7'
})
})
}
},
const api = new XMLHttpRequest()
api.open('GET', '/api/user', true)
// -------------------------------------- 在webpack-dev-sesrver的bofore(app)中已經(jīng)提供了服務(wù)路由并返回數(shù)據(jù)
// -------------------------------------- 所以這里可以直接訪問
api.onload = function() {
const res = api.response
console.log(res, 'res')
}
api.send()
resolve 解析 -------------------- alias 和 extensions
- <font color=red>resolve.alias :創(chuàng)建 import 或者 export 的別名</font>
- <font color=blue>resolve.extensions : 自動解析確定的擴展</font>
- 注意:<font color=blue>( resolve.extenstions ) 是一個 ( 數(shù)組 ),成員是 ( .后綴的字符串 )</font>
- 注意:
import SomeFile from "./somefile.ext",要想正確的解析,一個包含“*”的字符串必須包含在數(shù)組中。
- 應(yīng)用:在引入文件時,省略后綴 ( 優(yōu)先級是從左往右 )
resolve.alias
resolve.extensions
設(shè)置:
resolve: {
alias: {
Imageff: path.resolve(__dirname, 'src/images'), // 用 Imageff 代替 images文件夾的絕對路徑
},
extensions: ['.js', '.css', '.less', '*']
// ------------------------------------------------- import時省略后綴時,先找.js文件,再找.css文件
// ------------------------------------------------- 注意:'*' 表示所有類型的文件
},
使用:
import imagex from 'Imageff/1.jpg'
webpack.DefinePlugin ---------- 定義環(huán)境變量,即創(chuàng)建一個在編譯時可以全局配置的常量
(1)
new webpack.DefinePlugin({ // ----------------------- new webpack.DefinePlugin()
DEV: JSON.stringify('DEV'), // -------------------- ( JSON.stringify('DEV') === "'DEV'" )
BOOLEAN1: true,
BOOLEAN2: JSON.stringify(true) // ----------------- 這里BOOLEAN2和上面BOOLEAN1等價
}),
// -------------------------------------------------- 所以數(shù)據(jù)可以用JSON.stringify()來操作,傳入什么類型就返回什么類型
(2) webpack的插件常有的有:
new webpack.DefinePlugin({ // ----------------------- webpack.definePlugin
DEV: JSON.stringify('DEV'),
BOOLEAN1: true,
BOOLEAN2: JSON.stringify(true)
}),
new webpack.ProvidePlugin({ // ---------------------- webpack.ProvidePlugin
$: 'jquery'
}),
new webpack.BannerPlugin({ // ----------------------- webpacck.BannerPlugin
banner: 'by woow_wu7'
})
webapck-merge ------------ 區(qū)分不同環(huán)境
npm install webapck-merge -D
- webpack-merge
const merge = require('webpack-merge'); // --------------- webpack-merge
const base = require('./webpack.base.js')
module.exports = merge(base, {
mode: 'developmen',
devServer: {
contentBase: './dist',
port: 8000,
open: true,
compress: true
}
})
noParse
- <font color=red>module.noParse 如果包沒有其他的依賴項,則可以通過noParse使webpack不去解析該包的依賴關(guān)系,提高構(gòu)建速度</font>
- 所以該包中:不能含有import,require,define等任何的導入機制
- module.noParse
module: {
noParse: /jquery|lodash/, // ------ 不去解析jquery或lodash的依賴關(guān)系,因為它們倆都沒有依賴其他庫,從而提高構(gòu)建速度
rules: []
}
webpack.IgnorePlugin
- resourceRegExp:匹配(test)資源請求路徑的正則表達式。
- contextRegExp:(可選)匹配(test)資源上下文(目錄)的正則表達式。
- webpack自帶的插件
webpack.IgnorePlugin--------- 忽略引入
webpack.DefinePlugin--------- 定義全局常量
webpack.ProvidePlugin-------- 暴露包的名字改名
webpack.BannerPlugin--------- 打包的js的最前面注入一寫信息字符串
----
webpack.config.js => plugins
new webpack.IgnorePlugin({
// ------------------------------- 表示從 ( moment ) 中引入 ( ./local ) 文件時,將不去引入./local文件夾中的文件
// ------------------------------- 但是需要使用中文包,所以忽略后,再 ( 手動引入 )
resourceRegExp: /^\.\/locale$/,
contextRegExp: /moment$/
});
-----
index.js
import moment from 'moment'
import 'moment/locale/zh-cn'; // ------------------------------------ 手動引入包
moment.locale('zh-cn')
const d = moment("20111031", "YYYYMMDD").fromNow();
console.log(d, 'd')
webpack.DllPlugin 和 webpack.DllReferencePlugin -------- 動態(tài)鏈接庫,單獨打包一些庫
- webpack.DllPlugin:=> name,path
- webpack.DllReferencePlugin:=> manifest
- manifest:清單
------
webpack.config.react.js // ------------------------------------- 專門用來打包react和react-dom
(1)
const path = require('path')
const webpack = require('webpack')
module.exports = {
mode: 'development',
entry: {
react: ['react', 'react-dom']
},
output: {
filename: '_dll_[name].js', // ---------------------------- 打包后是 ( _dll_react.js )
path: path.resolve(__dirname, 'dist'),
library: '_dll_[name]', // 打包后,把打包的文件賦值給_dll_[name]變量,全局變量的名稱
libraryTarget: 'var', // 變量的類型
},
plugins: [
new webpack.DllPlugin({ // -------------------------------- webpack.DllPlugin 用于生成任務(wù)清單,即manifest.json文件
name: '_dll_[name]',
// name 表示暴露到全局的庫的名稱
// 注意: name 和 output.librry 要一致
// 注意:name代表的就是打包后生成在dist目錄下的 manifest.json 中的變量值
path: path.resolve(__dirname, 'dist', '[name].manifest.json')
})
]
}
(2)
打包:使用命令打包:npx webpack --config webpack.config.react.js
生成:
(1) _dll_react.js // ----------------------------------------- 文件的內(nèi)容會賦值給一個變量 ( _dll_react )
(2) manifest.json文件
------
(3)
webpack.config.js
plugins: [
new webpack.DllReferencePlugin({ //----------------------------- 引用清單
manifest: path.resolve(__dirname, 'dist', 'react.manifest.json') //- 引用上面打包生成的 manifest.json 文件
})
],
-----
(4)
index.js
import react from 'react'
import {render} from 'react-dom'
render(<h1>jsx</h1>, document.getElementById('root'))
(5)
效果:打包main.js從( 1.4M => 500KB )
happypack ------------------------- 多線程打包
module.rules:
{
test: /\.js$/,
use: 'happypack/loader?id=js',
},
}
plugins:
new HappyPack({
id: 'js',
use: [{
loader: 'babel-loader'
}]
})
代碼分割 optimization.splitChunks
- 抽離公共組件和第三方組件,可以緩存,則不需要重復(fù)加載
- optimization => splitChunks => cacheGroups => vendors和commons
- priority: 是優(yōu)先的意思
- optimization: {
minimizer: {}, // 壓縮css和js的配置項
splitChunks: {
cacheGroups: {
commons: {
name: 'commons',
chunks: 'initial',
minChunks: 1,
priority: 10,
minSize: 0,
},
vendors: { // vendor是小販的意思
test: /node_modules/, // 范圍是node_modules中的第三方依賴,注意zhe
name: 'vendors', // 抽離出來的包的名字
chunks: 'initial', // 初始化加載的時候就抽離公共代碼
minChunks: 1, // 被引用的次數(shù)
priority: 11, // priority: 是優(yōu)先級的意思,數(shù)字越大表示優(yōu)先級越高
minSize: 0,
}
}
}
}
@babel/plugin-syntax-dynamic-import --------------------- 實現(xiàn)懶加載
-
npm install @babel/plugin-syntax-dynamic-import
語法動態(tài)導入 - syntax:語法
- dynamic:動態(tài)
(1) 在webpack.config.js中配置,或者在.babelrc中配置
module: {
rules: [
{
test: /\.js$/,
use: [
{
loader: 'babel-loader',
options: {
presets: {
['@babel/preset-env'],
['@babel/preset-react'],
},
plugins: {
['@babel/plugin-proposal-decorators', {'legacy': true}],
['@babel/plugin-proposal-class-properties', {'loose': true],
['@babel/plugin-transform-runtime'],
['@babel/plugin-syntax-dynamic-import']
}
}
},
{
loader: 'eslint-loader',
options: {
enforce: 'pre'
}
}
]
}
]
}
(2) index.js
const button = document.createElement('button')
button.innerHTML = 'button'
button.addEventListener('click', () => {
console.log('button clicked')
import('./dynamic.js').then(res => console.log(res.default, 'res')) // ----------- 語法動態(tài)導入,使用jsonp實現(xiàn)
})
document.body.appendChild(button)
(3)
- import只能用在頂部報錯:解決需要安裝 babel-eslint 插件
- 安裝,babel-eslint插件,并且在 .eslintrc.json中做如下配置
- {
"parser": "babel-eslint",
"parserOptions": {
"sourceType": "module",
"allowImportExportEverywhere": true, // ---------------------- 在所有地方都能import和export
},
"rules": {
"indent": "off"
},
"env": {}
}
- https://stackoverflow.com/questions/39158552/ignore-eslint-error-import-and-export-may-only-appear-at-the-top-level
webpack.HotModuleReplacementPlugin 和 webpack.NameModulesPlugin --------- 熱更新
- 熱更新
- new webpack.HotModuleReplacementPlugin() // 熱更新
- new webpack.NameModulesPlugin() // 打印熱更新模塊的路徑
- 1. 首先在 devServer 配置中增加 hot: true,表示開啟熱更新
- 2. 在plugins數(shù)組中 new webpack.HotModuleReplacementPlugin() 和 new webpack.NameModulesPlugin()
- 3. 在入口js文件中:
(1)
devServer: {
contentBase: path.join(__dirname, 'dist'),
port: '5000',
compress: true,
open: true,
hot: true, //-------------------------------------------------------- hot: true 開啟熱更新模式
// proxy: {
// '/api': {
// target: 'http://localhost:7000',
// pathRewrite: {
// '^/api': ''
// }
// }
// },
before(app) {
app.get('/api/user', (req, res) => {
res.json({
user: 'woow_wu7'
})
})
}
},
(2)
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
hash: true,
minify: {
removeAttributeQuotes: true,
collapseWhitespace: true,
}
}),
new MiniCssExtractPlugin({
filename: 'css/main.css'
}),
// new CleanWebpackPlugin(),
new CopyWebpackPlugin([{
from: './src/copywebpackplugin',
to: './'
}]),
new webpack.DefinePlugin({
DEV: JSON.stringify('DEV'),
BOOLEAN1: true,
BOOLEAN2: JSON.stringify(true)
}),
new webpack.IgnorePlugin({
resourceRegExp: /^\.\/local$/,
contextRegExp: /moment$/,
}),
new webpack.ProvidePlugin({
$: 'jquery'
}),
new webpack.BannerPlugin({
banner: 'by woow_wu7'
}),
new webpack.NamedModulesPlugin(), // --------------------- webpack.NameModulesPlugin 打印更新的模塊路徑
new webpack.HotModuleReplacementPlugin() // -------------- webpack.HotModuleReplacePlugin 熱更新插件
// new webpack.DllReferencePlugin({
// manifest: path.resolve(__dirname, 'dist', 'manifest.json')
// })
],
(3) index.js
import hotNow from './hot';
console.log(hotNow)
if (module.hot) { // ----------------------------------------- 如果hot.module存在,開啟了熱更新
module.hot.accept('./hot.js', function(){ // --------------- 監(jiān)聽 './hot.js'的改變,如果改變,執(zhí)行回調(diào)
const res = require('./hot.js') // ----------------------- 重新加載,并打印最新值
console.log(res, '熱更新后新的返回值')
})
}
編寫一個loader
- loader就是一個 ( <font color=red>函數(shù)</font> ),第一個參數(shù)表示 ( <font color=red>該loader匹配的文件的源代碼</font> )
- 不能寫成箭頭函數(shù),因為需要通過 this 獲取更多 api
-
this.query
- 如何獲取loader中的配置參數(shù):( <font color=red>options對象</font> )
this.query指向的就是options對象
-
如果 loader 中沒有 options,而是以 query 字符串作為參數(shù)調(diào)用時,this.query 就是一個以 ? 開頭的字符
- 注意:this.query已經(jīng)廢棄,使用 <font color=red>loader-utils</font> 中的 <font color=red>getOptions</font> 來獲取 options 對象
- 如何獲取loader中的配置參數(shù):( <font color=red>options對象</font> )
-
loader-utils
npm install loader-utils -D
- 通過loader-utils中的 getOptions 獲取 loader的options配置對象
-
this.callback
- 參數(shù)
- 第一個參數(shù):err // Error 或者 null
- 第二個參數(shù):content // string或者buffer,即處理過后的源代碼
- 第三個參數(shù):sourceMap // 可選,必須是一個可以被這個模塊解析的 source map
- 第四個參數(shù):meta //可選,即元數(shù)據(jù)
- // https://www.webpackjs.com/api/loaders/#this-callback
- 參數(shù)
-
this.async
- <font color=red>處理loader中的異步操作</font>
- <font color=red>this.async()方法返回 this.callback</font>
- <font size=6 >resolveLoader</font>
- webpack配置項
- resolveLoader的配置項
- 代碼:modules: ['node_modules', './src/loaders']
- 表示:在尋找loader的時候,先去node_modules文件夾中共尋找,沒找到再去'./src/loaders'文件夾中找
- loader API
最簡單的replace-loader
replace-loader
---
目錄:src/loaders/replace-loader.js
module.exports = function(source) { // --------------------- loader就是一個函數(shù),參數(shù)是源碼
return source.replace('hello', 'hi!')
}
目錄:webpack.config.js
module: {
rules: [{
test: /\.js$/,
use: [path.resolve(__dirname, './src/loaders/replace-loader.js')]
}]
}
升級版
目錄:webpack.config.js
(1)
module.exports = {
resolveLoader: { // ---------------------------- resolveLoader
modules: ['node_modules', './src/loaders/'] // 表示在尋找loader時,先去node_modules中找,再去loaders文件夾中找
},
]
(2)
{
loader: 'replace-loader', // -------------------- 加載replace-loader,即文件名
options: {
name: 'hi!!!!!!!!@!!!!!!' // ---------------------- options的name屬性
}
}
目錄:src/loaders/replace-loader
const loaderUtils = require('loader-utils') // ---------------- loader-utils
module.exports = function(source) {
console.log(this.query) // options配置對象
const options = loaderUtils.getOptions(this) // ------------- loaderUtils.getOptions(this) 獲取 options
const callback = this.async() // ---------------------------- 處理異步loader, this.async()返回this.callback
setTimeout(function() {
const result = source.replace('hello', options.name)
callback(null, result)
}, 1000)
}
資料
我的簡書:http://www.lxweimin.com/p/1fc4640f4538
webpack優(yōu)化:https://juejin.im/post/6844903782581534727#heading-7
process.env http://www.lxweimin.com/p/c8f9c61c2f20