知識點掃盲
構建
- 概念:把原始碼轉換成釋出線上可執行的
js
,css
,html
程式碼的過程 - 特點:
- 1.程式碼轉換(
ts
—>js
,less
/scss
—>css
等) - 2.檔案優化(壓縮
js
,css
,html
程式碼;壓縮合並圖片等) - 3.程式碼分割(提取多個頁面的公共程式碼,提取首屏不需要執行部分的程式碼讓其非同步載入)
- 4.模組合併(把多個模組檔案分類合併成一個檔案)
- 5.自動重新整理(在開發過程中監聽本地原始碼的變化,自動重新構建、重新整理瀏覽器)
- 6.程式碼校驗(在程式碼被提交到倉庫之前需要校驗程式碼是否符合規範,以及單元測試是否通過)
- 7.自動釋出(更新完程式碼後,自動構建出線上釋出程式碼並傳輸給釋出系統)
- 1.程式碼轉換(
怎麼用
注:如果你是初學者,希望你能跟著我的步驟操作一下
安裝
- 1、為了版本一直我們推薦使用本地安裝(
npm install webpack --save-dev
) - 2、安裝
webpack-cli
(npm install webpack-cli --save-dev
),以便解析使用者傳參(核心yargs
)
零配置打包
檔案目錄建立
- 根目錄建立
src
資料夾並在其中建立index.js
檔案
// index.js
console.log('hello webpack')
複製程式碼
簡單實現一(入口無依賴檔案)
- 執行
npx webpack
- 此時發現,根目錄下會出現一個包含
main.js
檔案的dist
資料夾;同時你也一定注意到瞭如上圖中紅框所圈出的WARNING
,是因為我們沒有指定mode
(模式:包含生產(production
)和開發(development
)兩種),不傳會預設production
模式
- 此時發現,根目錄下會出現一個包含
- 執行
npx webpack --mode development
- 此時不會出現上圖中的
WARNING
,比較一下此時main.js
和之前的區別
- 此時不會出現上圖中的
簡單實現二(入口有依賴檔案)
- 在
src
資料夾中再建立一個other.js
,在index.js
通過require
引入
// other.js
module.exports = 'hello webpack'
// index.js
const other = require('./other.js')
console.log(other)
複製程式碼
- 執行
npx webpack --mode development
- 在生成的
dist
資料夾下建立一個index.html
檔案並引入產生的main.js
檔案,在瀏覽器中檢視index.html
的console
- 再嘗試一下在
index.html
中直接引入src
資料夾下的index.js
,在瀏覽器中檢視index.html
的console
後者的原因是因為我們的瀏覽器不支援
coomonjs
,這裡我不做過多解釋;我們來分析一下前者是如何實現的
// 刪除掉冗餘部分的main.js檔案
(function (modules) {
var installedModules = {};
function __webpack_require__(moduleId) { // ./src/index.js ./src/other.js
if (installedModules[moduleId]) { // 類似Commonjs中的快取處理
return installedModules[moduleId].exports;
}
var module = installedModules[moduleId] = {
i: moduleId,
l: false,
exports: {}
};
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
module.l = true;
return module.exports;
}
return __webpack_require__("./src/index.js");
})
({
"./src/index.js":
(function (module, exports, __webpack_require__) {
// 預設會呼叫 require("./src/other.js")
eval("const other = __webpack_require__(\"./src/other.js\");console.log(other);");
}),
"./src/other.js":
(function (module, exports) {
eval("module.exports = 'hello webpack';");
})
});
/* webpack打包流程
* 1.找到入口檔案(index.js)
* 2.找到入口檔案中的依賴模組(other.js) ast解析載入依賴模組
* 3.從入口檔案開始執行 require方法改寫成 __webpack_require__
* 內部自己實現了一個Commonjs模組(需要找到入口,需要找到入口中的所有依賴,載入依賴 + 模板——>渲染後的結果)
*/
複製程式碼
增加配置打包
真正的開發中我們肯定不會零配置打包,肯定根據我們的需要來手動配置
webpack
配置入口檔案
- 在全域性建立
webpack.config.js
或webpackfile.js
檔案。(本文以webpack.config.js
為例) - 編輯
webpack.config.js
(採用coomonjs
規範)
// webpack.config.js
module.exports = { // 匯出一個物件;物件中放置配置;會呼叫這個配置進行構建
}
複製程式碼
- 修改
src
資料夾下index.js
檔名為guYan.js
,執行npx webpack --mode development
,報錯顯示找不到入口檔案 - 在
webpack.config.js
檔案中增加入口的位置,並執行npx webpack --mode development
;無報錯
// webpack.config.js
module.exports = {
entry: './src/guYan.js' //當前入口檔案的位置
}
複製程式碼
注:我們可以通過執行
npx webpack --mode development
時增加config
引數來實現修改預設配置檔案webpack.config.js
的名字。比如我們現在修改webpack.config.js
檔名為webpack.guYan.js
然後執行npx webpack --mode development --config webpack.guYan.js
效果和之前一樣
配置出口檔案
- 在
webpack.config.js
檔案中增加出口檔案的配置,並執行npx webpack --mode development
,效果如圖
// webpack.config.js
const path = require('path');
module.export = {
entry: './src/guYan.js',
output:{ // 配置當前出口檔案
filename: 'bundle.js', // 出口檔名
path: path.resolve(__dirname,'./build') // 出口目錄,該配置項必須是絕對路徑,預設dist目錄
}
}
複製程式碼
配置HTML
模板
- 在根目錄建立
public
目錄,並在其中建立index.html
檔案 - 下載
html-webpack-plugin
外掛(npm install html-webpack-plugin --save-dev
)- 作用:根據模板產生一個打包後的
html
- 作用:根據模板產生一個打包後的
- 在
webpack.config.js
檔案中增加HTML
模板的配置(使用html-webpack-plugin
外掛)
// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');// 1.引入外掛
module.exports = {
entry:'./src/guYan.js',
output:{
filename:'bundle.js',
path:path.resolve(__dirname,'./build')
},
plugins:[ // 2.在plugins中註冊外掛
new HtmlWebpackPlugin({
template:'./public/index.html', // 指定模板
filename:'gy.html' // 指定打包後的檔名,預設為index.html
})
]
}
複製程式碼
- 執行
npx webpack --mode development
,輸出檔案目錄如圖,並且你會發現在輸出的gy.html
中自動引入了打包後的bundle.js
- 上述雖然已經完成了動態引入,但是執行
npx webpack --mode production
會發現打包後的bundle.js
被壓縮,但是gy.html
沒有被壓縮,還有就是引用的檔案一直是一個我們不清楚會不會出現快取的問題,這上線肯定是不允許的啊,所以我們需要繼續配置
// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.export = {
entry:'./src/guYan.js',
output:{
filename:'bundle.js',
path:path.resolve(__dirname,'./build')
},
plugins:[
new HtmlWebpackPlugin({
template: './public/index.html',
filename:'gy.html',
minify:{ // 配置壓縮形式
removeAttributeQuotes: true, // 刪除所有屬性的引號
collapseWhitespace: true // 刪除所有空白
},
hash:true // 每次引用js檔案都加入雜湊戳
})
]
}
複製程式碼
- 執行
npx webpack --mode production
後對比之前的效果檢視
配置mode
(模式)
- 上文中我們執行打包命令的時候都會傳一個
mode
引數,其實沒有必要這麼麻煩,我們可以在webpack.config.js
中配置mode
;執行npx webpack
結果和上文一樣
// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports= {
mode: 'production', // 預設兩個引數 development production
entry: './src/guYan.js',
...
}
複製程式碼
配置clean-webpack-plugin
(清理資料夾)
在開發構建的過程中我們更希望在打包後的資料夾中一直是最新的打包檔案,即先刪除掉之前打包產生的資料夾及檔案
- 安裝
clean-webpack-plugin
(npm install clean-webpack-plugin --save-dev
) - 在
webpack.config.js
檔案中進行配置
// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clearn-webpack-plugin'); // 1.引入外掛
module.exports = {
mode:'development',
entry: './src/guYan.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname,'./build')
},
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html',
filename: 'gy.html',
minify: {
removeAttributeQuotes: true,
collapseWhitespace: true
},
hash:true
}),
/*清空檔案的外掛*/
new CleanWebpackPlugin({ // 2.註冊外掛
cleanOnceBeforeBuildPatterns:['**/*'], // 匹配目錄下的所有檔案清空,預設也是所有
})
]
}
複製程式碼
配置多入口打包
- 上述示例中所有
webpack.config.js
中的entry
的值都是一個路徑字串的格式('./src/guYan.js'
),當我們的入口只有一個的時候我們這樣寫ok,但是當我們需要同時打包多個檔案的時候呢?我們如何處理呢?對的,它的值還可以是個物件 - 首先我們準備再準備一個入口檔案
guYan2.js
// src/guYan2.js
console.log('I am GuYan');
複製程式碼
- 在
webpack.config.js
中修改我們的配置,並執行npx webpack
打包後的資料夾變化效果
// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
mode:'development',
entry:{ // 配置多入口
index:'./src/guYan.js',
other:'./src/guYan2.js'
},
output:{
filename: '[name].js',// 為了響應多入口出口檔名需要動態建立,保證每個入口都有輸出
path: path.resolve(__dirname,'./bundle')
},
plugins:[
new HtmlWebpackPlugin({
template:'./public/index.html',
filename:'index.html',
minify:{
removeAttributeQuotes:true,
collapseWhitespace:true
},
hash:true
}),
new CleanWebpackPlugin({
clearnOnceBeforeBuildPatterns:['**/*']
})
]
}
複製程式碼
- 在上文中我們為了打包後的
html
檔案引入打包後的js
檔案不出現快取給我們造成的困擾,我們在使用html-webpack-plugin
的時候配了一個hash
,我們也可以在出口檔名的位置加入[contentHash]
引數
// webpack.config.js
...
output:{
filenama:'[name].[contentHash:8].js' // :後面的是代表長度
}
...
複製程式碼
- 上文打包之後我們發現現在打包出兩個
js
檔案一個html
檔案中引用了兩個js
檔案,那如果我們想分別引用呢?怎麼處理?對的,再new
一次html-webpack-plugin
。所以我們寫一個迴圈來處理一個plugin
需要多次引用的問題
// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
let htmlPlugins = ['index','other'].map(chunkName=>(new HtmlWebpackPlugin({
filename:`${chunkName}.html`,
chunks:[chunkName] // 保證按需引入 即index.html檔案只引入index.js;other.html只引入other.js
})));
modeule.exports = {
mode:'development',
entry:{
index:'./src/guYan.js',
other:'./src/guYan2.js'
},
output:{
filename:'[name].[contentHash:8].js',
path:path.resolve(__dirname,'./build')
},
plugins:[
new CleanWebpackPlugin(),
...htmlPlugins
]
}
複製程式碼
配置devServer
(webpack-dev-server
)
在開發過程中我們更希望的是我們一邊修改內碼表面自動更新,當然這種處理我們有兩種方案一個是通過編譯的時候傳入
--watch
不推薦使用(所以我就不做介紹了),另一種就是通過webpack-dev-server
來啟動,這種方式不會產生構建好的檔案,並且會給我們啟動一個服務
注:本小節的例子我們採用單入口輸入,示例如下
// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
let htmlPlugins = ['index'].map(chunkName=>(new HtmlWebpackPlugin({
filename:`${chunkName}.html`,
chunks:[chunkName]
})));
module.exports = {
devServer:{
port:3000, //指定埠號
open:true, // 是否自動開啟瀏覽器
compress:true, // 是否啟用gzip壓縮
contentBase:'./dist' // 指定啟動靜態服務的檔案目錄
// 通過webpack-dev-server打包的結果放到記憶體中,而且目錄是當前的根目錄
},
mode: 'development',
entry: {
index: './src/guYan.js',
},
output: {
filename: '[name].js',
},
plugins: [
new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns: ['**/*']
}),
...htmlPlugins,
]
}
複製程式碼
- 通過
npx webpack-dev-sever
啟動來檢視結果
配置loader
- 作用:
webpack
只能理解JavaScript
和JSON
檔案。loader
讓webpack
能夠去處理其他型別的檔案,並將它們轉換為有效 模組,以供應用程式使用,以及被新增到依賴圖中。 - 特點
- 執行順序:從右向左,從下到上
- 分類:前置(
enforce:'pre'
)、普通(enforce:'normal'
)、後置(enforce:'post'
) - 引數型別:陣列,字串,物件
處理css
- 全域性建立一個
style
資料夾,並在其中建立一個index.css
檔案,並在src/guYan.js
中引入
/*index.css*/
body{
background:yellow;
}
複製程式碼
- 安裝
css-loader
,style-loader
(npm install css-loader style-loader --save-dev
)- 原理:通過
css-loader
將css
檔案處理成字元傳形式,通過style-loader
在html
中建立<style>
標籤並將css-loader
處理後的字串插入其中
- 原理:通過
- 在
webpack.config.js
中配置loader
// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
let htmlPlugins = ['index'].map(chunkName=>(new HtmlWebpackPlugin({
template:'./public/index.html',
filename:`${chunkName}.html`,
chunks:[chunkName],
minify:{
removeAttributeQuotes:true,
collapseWhitespace:true
},
hash:true
})))
module.exports = {
mode:'development',
devServer:{
port:3000,
open:true,
compress:ture,
contentBase:'./dist'
},
entry:{
index:'./src/guYan.js'
},
output:{
filename:'[name].js'
},
plugins:[
new CleanWebpackPlugin(),
...htmlPlugins
],
module:{
rules:[
{
test:/\.css$/,
use:['style-loader','css-loader']
}
]
}
}
複製程式碼
- 執行
npx webpack-dev-server
結果如下
CSS
相關
配置css-modules
- 在日常的開發中我們通常會將一些公共的樣式抽離到一個
common.css
檔案中,然後在我們js
檔案中按需引入;這樣我們就會遇到css
模組化的問題(css-modules
),我們舉例說明如何配置解決這個問題 - 修改
src/guYan.js
,在style
目錄下建立一個common.css
檔案
// guYan.js
import { other } from './other';
import '../style/index.css';
import commonStyle from '../style/common.css';
let div = document.createElement('div');
div.className = commonStyle.guYan;
div.innerHTML = 'GuYan';
document.body.appendChild(div);
console.log(other);
複製程式碼
/*common.css*/
.guYan{
color:red;
}
複製程式碼
- 配置
webpack.config.js
// webpack.config.js
...
module:{
rules:[
{
test:/\.css$/,
use:['style-loader',
{
loader:'css-loader',
options:{
modules:true
}
}
]
}
]
}
...
複製程式碼
- 執行
npx webapck-dev-server
特殊注意:
loader
的順序一定要特別注意,如果就想把style-loader
寫在後面需要在其options
中增加enforce:'post'
引數或者在css-loader
的options
中增加enforce:'pre'
引數
配置css3
增加瀏覽器核心字首
- 修改
style/common.css
如下
/*common.css*/
.guYan{
color: red;
background: green;
transform: rotateY(180deg);
}
複製程式碼
- 安裝
postcss-loader
(npm install postcss-loader --save-dev
) postcss-loader
只是一個幹活的,它不知道幹什麼活,所以需要一個東西來告訴它,它需要做的是增加字首,這個東西就是autoprefixer
,所以我們安裝autoprefixer
(npm install autoprefixer --save-dev
)- 現在我們幹活的(
postcss-loader
)有了,指揮幹活的(autoprefixer
)也有了,但是呢這個幹活的(postcss-loader
)比較裝X,它要求這個指揮幹活的(autoprefixer
)不能像其他loader
那樣你隨隨便便在options
物件中指揮我,你必須專門在我的配置檔案(postcss.config.js
)中指揮我幹活,所以我們需要在根目錄下建立一個postcss.config.js
檔案
- 配置
postcss.config.js
檔案
// postcss.config.js
module.exports = {
plugins:[
require('autoprefixer')
]
}
複製程式碼
- 配置
webpack.config.js
// webpack.config.js
...
module:{
rules:[
{
test:/\.css$/,
use:[
'style-loader',
{
loader:'css-loader',
options:{
modules:true
}
},
'postcss-loader'
]
}
]
}
...
複製程式碼
- 執行
npx webpack-dev-server
配置css
前處理器
- 前處理器分類
less
,sass
(node-sass
),stylus
- 前處理器對應
loader
less-loader
,sass-loader
,stylus-loader
- 引入前處理器檔案的位置
js
檔案- 配置對應的
loader
(以less
為例)// webpack.config.js ... module:{ rules:[ { test:/\.less$/, use:[ 'style-loader', { loader:'css-loader', options:{ modules:true } }, 'postcss-loader', 'less-loader' ] } ] } ... 複製程式碼
- 配置對應的
css
檔案- 配置對應的
loader
(以less
為例)// webpack.config.js ... module:{ rules:[ { test:/\.css$/, use:[ 'style-loader', { loader:'css-loader', options:{ modules:true } }, 'postcss-loader', 'less-loader' ] } ] } ... 複製程式碼
- 配置對應的
配置抽離css
樣式
上文中提到的樣式,不難發現都是巢狀在
html
檔案中的head
裡的<style>
標籤中的,但是在日常的開發中我們一般都是單獨在xxx.css
檔案中寫樣式,然後通過<link>
引入,所以我們接下來抽離css
樣式吧
- 安裝
mini-css-extract-plugin
(npm install mini-css-extract-plugin --save-dev
) - 配置
webpack.config.js
,需要注意的是:- 1.這個外掛做的工作是將
css-loader
處理後的字串寫到一個指定的檔案中,想要使其以<link>
標籤的形式引入,需要配合其自帶的loader
使用,即下文的MiniCssExtractPlugin.loader
- 2.官方建議生產模式下使用
MiniCssExtractPlugin.loader
,開發模式使用style-loader
// webpack.config.js const MiniCssExtractPlugin = require('mini-css-extract-plugin');// 引入外掛 ... module.exports = { ... plugins:[ new CleanWebpackPlugin(), ...htmlPlugins, new MiniCssExtractPlugin({ // 註冊外掛 filename:'index.css'//指定抽離的檔名 }) ... ], module:{ rules:[ { test:/\.css$/, use:[ // 'style-loader' MiniCssExtractPlugin.loader, // 配合外掛自身loader使用 ... ] } ] } } 複製程式碼
- 1.這個外掛做的工作是將
- 執行
npx webpack-dev-server
結果如下
配置壓縮抽離的css
樣式檔案
- 上述程式碼執行
npx webpack --mode production
,檢視打包後的檔案,你會發現我們抽離的css
檔案並沒有像js
,html
檔案一樣被壓縮,這在我們上線的時候肯定是不允許的,所以我們需要壓縮它 - 安裝
optimize-css-assets-webpack-plugin
(npm install optimize-css-assets-webpack-plugin --save-dev
) - 配置
webpack.config.js
檔案// webpack.config.js const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin'); ... module.exports = { ... optimization:{ // 配置優化項 minimizer:[ // 手動指定壓縮項 new OptimizeCssAssetsWebpackPlugin({}) ] } mode:'production' ... } 複製程式碼
- 執行
npx webpack
檢視結果,發現我們提取的css
檔案已經實現壓縮 - 但是你再看
js
檔案沒有壓縮,這是因為當我們沒有手動配置壓縮項的時候webpack
內部自己實現了配置其自帶的terser-webpack-plugin
外掛進行壓縮,而我們配置後覆蓋掉了它內部自己的配置,所以我們需要手動將terser-webpack-plugin
配置到minimizer
中
// webpack.config,js
const TerserJSPlugin = require('terser-webpack-plugin'); //webpack的內部外掛
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
...
module.exports = {
...
optimization:{
minimizer:[
new TerserJSPlugin({}),// 手動加上壓縮js
new OptimizeCssAssetsWebpackPlugin({})
]
}
mode:'production'
...
}
複製程式碼
- 執行
npx webpack
檢視結果
圖片相關
配置圖片引入
- 在根目錄下建立
image
資料夾並準備一張guYan.jpg
圖片放入其中 - 在
src/guYan.js
中引入guYan.jpg
// guYan.js
import url from '../image/guYan.jpg';
...
let img = new Image();
img.src = url;
documnt.body.appendChild(img)
複製程式碼
- 安裝
file-loader
(npm install file-loader --save-dev
)- 作用:
- 1.拷貝一個檔案放到打包後的檔案中
- 2.返回拷貝的路徑
- 作用:
- 配置
webpack.config.js
//webpack.config.js
...
module.exports={
...
module:{
rules:[
...,
{
test:/\.(jpg|png|gif)$/,
use:'file-loader'
}
]
}
}
複製程式碼
- 執行
npx webpack --mode production
檢視打包後的檔案,會發現生成一個拷貝的圖片
配置圖片壓縮
- 在上一小節我們實現了圖片的引入,但是在我們的開發過程中有一些
Icon
之類的我們更希望它可以轉化為base64
的格式壓縮,所以這就需要我們配置另一個可以處理圖片的loader
,url-loader
- 安裝
url-loader
(npm install url-loader --save-dev
) - 配置
webpack.config.js
// webpack.config.js
...
module.exports={
...
module:{
rules:[
...,
{
test:/\.(jpg|png|gif)$/,
use:{
loader:'url-loader',
options:{
limit:100*1024 // 指定壓縮檔案的最大位元組,超過最大限制會自動呼叫file-loader處理
}
}
}
]
}
}
複製程式碼
- 執行
npx webpack --mode production
,檢視打包後的檔案目錄並沒有生成拷貝的檔案(嘗試修改limit
引數的大下感受一下變化)
特殊注意:字型圖示(
xxx.eot
,xxx.svg
,xxx.ttf
,xxx.woff
,xxx.woff2
)只能用file-loader
如果你給的
limit
過大,也就是說會將大的圖片也會轉成base64
的格式會導致打包的時候會有一個效能的警告提示你檔案過大,這樣的時候你可以給一個performance:false
屬性來使打包的時候忽略效能問題的提示,但是一般我們上線肯定考慮效能的問題的,也就是說我們一般不會將limit
的值設定過大
- 上面我們只舉例了在
js
檔案中引用圖片的例子,其實在開發中我們也有可能直接在html
檔案中引用圖片,安裝我們之前的打包方式你會發現會出現找不到圖片,因為路徑變了,解決這個問題我們需要配置一個html-withimg-loader
// webpack.config.js
...
{
test:/\.html$/,
use:'html-withimg-loader'
}
...
複製程式碼
配置輸出的圖片增加公共字首比如需要加域名
- 給
url-loader
的options
增加publicPath
屬性即可
//webpack.config.js
...
options:{
limit:2*1024,
publicPath:'https://juejin.im/user/5b685661e51d4517df153771'
}
...
複製程式碼
同理
css``js
增加字首一個套路
配置分類打包
- 圖片
- 在
options
中增加outputPath
屬性
- 在
css
- 在抽離外掛的
filename
引數屬性前面配置資料夾的名字
- 在抽離外掛的
html
- 在
html-webpack-plugin
外掛的filename
屬性前面配置資料夾的名字
- 在
js
- 在出口引數(
output
)裡的filename
屬性前面配置資料夾的名字
- 在出口引數(
- 執行
npx webpack --mode production
檢視打包後的檔案變化吧
JS
相關
配置JS
高階語法降級(通過babel
一系列包)
- 修改
guYan.js
檔案如下
// guYan.js
class Animal{
constructor(type){
this.type = type;
}
getType(){
return this.type
}
}
let animal = new Animal('哺乳類');
console.log(animal.type);
複製程式碼
- 安裝
babel-loader
,@babel/core
,@babel/preset-env
(npm install babel-loader @babel/core @babel/preset-env --save-dev
) - 配置
webpack.config.js
// webpack.config.js
...
module.exports={
...,
module:{
rules:[
...,
{
test:/\.js$/,
use:{
loader:'babel-loader',
options:{
presets:['@babel/preset-env'],// 起指揮loader怎麼幹活的作用
}
},
exclude:/node_module/, // 忽略掉不想用loader處理的檔案
include:path.resolve(__dirname,'./src') // 指定需要loader處理的檔案
}
]
}
}
複製程式碼
- 執行
npx webpack --mode development
,檢視打包後的js
檔案,我們發現,他內部實現了一個_classCallCheck
,來作為轉化我們的class
類。
// 刪除後冗餘的程式碼後的打包檔案
(function(modules) {
var installedModules = {};
function __webpack_require__(moduleId) {
if(installedModules[moduleId]) {
return installedModules[moduleId].exports;
}
var module = installedModules[moduleId] = {
i: moduleId,
l: false,
exports: {}
};
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
module.l = true;
return module.exports;
}
return __webpack_require__(__webpack_require__.s = "./src/guYan.js");
})
({
"./src/guYan.js":
(function(module, exports) {
eval(`function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError(\"Cannot call a class as a function\");
}
}
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if (\"value\" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
var Animal =function () {
function Animal(type) {
_classCallCheck(this, Animal);
this.type = type;
}
_createClass(Animal, [{
key: \"getType\",
value: function getType() {
return this.type;
}
}]);
return Animal;
}();
var animal = new Animal('哺乳類');
console.log(animal.type);`);
})
});
複製程式碼
- 新建一個
src/otherEs6.js
檔案,在其中再用class
定義一個類匯出,在src/guYan.js
中引入這個檔案,再執行編譯。你會發現他內部實現這個公共的_classCallCheck
程式碼,實現了兩次,所以我們需要提取這個公共的程式碼 - 安裝
@babel/runtime
,@babel/plugin-transform-runtime
(npm install @babel/runtime @bebel/plugin-transform-runtime --save-dev
) - 配置
webpack.config.js
檔案
// webapack.config.js
...
test:/\.js$/,
use:{
loader:'babel-loader',
options:{
presets:['@babel/preset-env'],
plugins:['@babel/plugin-transform-runtime']
}
}
...
複製程式碼
- 執行
npx webpack --mode development
,檢視打包後的js
檔案,比較兩次有什麼不同
配置JS
的一些API
降級處理,如promise
(為了相容IE
)
- 方案一,通過
@babel/preset-env
+core-js@3
- 安裝
core-js@3
(npm install core-js@3 --save
) - 配置
webpack.config.js
// webpack.config.js ... test:/\.js$/, use:{ loader:'babel-loader', options:{ preset:[ [ '@babel/preset-env', { useBuiltIns:'usage',// 只轉化使用的API corejs:{version:3} } ] ] } } ... 複製程式碼
- 安裝
- 方案二在入口檔案中引入
@babel/polyfill
- 方案三,通過
@babel/plugin-transform-runtime
+@babel/runtime-corejs3
- 安裝
@babel/runtime-corejs3
(npm install @babel/runtime-corejs3
) - 配置
webpack.config.js
// webapck.config.js ... test:/\.js$/, use:{ loader:'babel-loader', options:{ presets:['@babel/preset-env'], plugins:[ [ '@babel/plugin-transform-runtime', { "absoluteRuntime": false, "corejs": {version:3}, "helpers": true, "regenerator": true, "useESModules": false } ] ] } } ... 複製程式碼
- 安裝
像裝飾器和類的屬性這些更高階的需要再去配外掛去處理,這裡我就不一一舉例了(
@babel/plugin-proposal-decorators
,@babel/plugin-proposal-class-properties
)
ESlint
相關
- 安裝
eslint
,eslint-loader
(npm install eslint eslint-loader --save-dev
) - 配置
webpack.config.js
// webpack.config.js
...
test:/\.js$/,
use:'eslint-loader',
enforce:'pre' // 強制在編譯之前執行
...
複製程式碼
- 配置
eslint
- 方案一,在eslint中去選擇自動生成然後引入專案列表
- 方案二,自己手動配置
- 執行
npx eslint --init
- 執行
- 配置
webpack.config.js
// we
複製程式碼
配置TS
ts-loader
tsconfig.json
配置代理
優化策略
常見plugin
和loader
的原理及實現
基於create-react-app
實現一個簡單的腳手架
注: 參考文件