上期文章:前端自動化測試
又一個連載來啦!這次我們將分四篇文章來介紹如何從0構建一個webpack開發環境,瞭解其內部機制和原理,從而讓我們更準確的掌握和使用webpack,下面開始我們的起步:
1.什麼是Webpack?
webpack
是一個現代 JavaScript 應用程序的靜態模塊打包器
(module bundler),當 webpack 處理應用程序時,它會遞歸地構建一個依賴關係圖
(dependency graph),其中包含應用程序需要的每個模塊
,然後將所有這些模塊打包成一個或多個 bundle
使用Webpack作爲前端構建工具:
- 代碼轉換:TypeScript 編譯成 JavaScript、SCSS 編譯成 CSS 等;
- 文件優化:壓縮 JavaScript、CSS、HTML 代碼,壓縮合並圖片等;
- 代碼分割:提取多個頁面的公共代碼、提取首屏不需要執行部分的代碼讓其異步加載;
- 模塊合併:在採用模塊化的項目裏會有很多個模塊和文件,需要構建功能把模塊分類合併成一個文件;
- 自動刷新:監聽本地源代碼的變化,自動重新構建、刷新瀏覽器;
- 代碼校驗:在代碼被提交到倉庫前需要校驗代碼是否符合規範,以及單元測試是否通過;
- 自動發佈:更新完代碼後,自動構建出線上發佈代碼並傳輸給發佈系統。
在webpack
應用中有兩個核心:
- 1)
模塊轉換器
,用於把模塊原內容按照需求轉換成新內容,可以加載非 JS 模塊; - 2)
擴展插件
,在 Webpack 構建流程中的特定時機注入擴展邏輯來改變構建結果或做你想要的事情。
2.初始化項目
├── src # 源碼目錄
│ ├── a-module.js
│ └── index.js
編寫 a-module.js
module.exports = 'hello';
編寫 index.js
let a = require('./a-module');
console.log(a);
這裏我們使用CommonJS
模塊的方式引入,這種方式默認在瀏覽器上是無法運行的,我們希望通過webpack
來進行打包!
3.webpack快速上手
3.1 安裝
npm init -y
npm install webpack webpack-cli --save-dev
webpack
默認支持0配置,配置scripts
腳本
"scripts": {
"build": "webpack"
}
執行npm run build
,默認會調用 node_modules/.bin
下的webpack
命令,內部會調用webpack-cli
解析用戶參數進行打包。默認會以 src/index.js
作爲入口文件。
這裏也可以使用npx webpack
,npx
是 5.2版本之後npm
提供的命令可以執行.bin
下的可執行文件
我們發現已經產生了dist
目錄,此目錄爲最終打包出的結果。main.js
可以在html中直接引用,這裏還提示我們默認mode
爲production
。
3.2 webpack.config.js
我們打包時一般不會採用0配置,webpack
在打包時默認會查找當前目錄下的 webpack.config.js or webpackfile.js
文件。
通過配置文件進行打包:
const path = require('path');
module.exports = {
entry:'./src/index.js',
output:{
filename:'bundle.js',
// 打包出的結果文件
path:path.resolve(__dirname,'dist')// 打包到dist目錄下
}
}
3.3 配置打包的mode
我們需要在打包時提供mode
屬性來區分是開發環境
還是生產環境
,來實現配置文件的拆分。
├── build
│ ├── webpack.base.js
│ ├── webpack.dev.js
│ └── webpack.prod.js
我們可以通過指定不同的文件來進行打包
配置scripts
腳本:
"scripts": {
"build": "webpack --config ./build/webpack.prod",
"dev": "webpack --config ./build/webpack.dev"
}
可以通過 config
參數指定,使用哪個配置文件來進行打包。
通過env參數區分
"scripts": {
"build": "webpack --env.production --config ./build/webpack.base",
"dev": "webpack --env.development --config ./build/webpack.base"
}
改造webpack.base
文件默認導出函數,會將環境變量傳入到函數的參數中。
module.exports = (env)=>{
console.log(env); // { development: true }
}
合併配置文件
我們可以判斷當前環境是否是開發環境來加載不同的配置,這裏我們需要做配置合併
安裝webpack-merge
:
npm install webpack-merge --save-dev
webpack.dev
配置
module.exports = {
mode:'development'
}
webpack.prod
配置
module.exports = {
mode:'production'
}
webpack.base
配置
const path = require('path');
const merge = require('webpack-merge');
// 開發環境
const dev = require('./webpack.dev');
// 生產環境
const prod = require('./webpack.prod');
const base = {
// 基礎配置
entry:'./src/index.js',
output:{
filename:'bundle.js',
path:path.resolve(__dirname,'../dist')
}
}
module.exports = (env) =>{
if(env.development){
return merge(base,dev);
}else{
return merge(base,prod);
}
}
後續開發中,我們會將公共的邏輯放到base
中,開發和生產中的配置也分別進行存放!
4.webpack-dev-server
配置開發服務器,可以在實現在內存中打包,並且自動啓動服務。
npm install webpack-dev-server --save-dev
"scripts": {
"build": "webpack --env.production --config ./build/webpack.base",
"dev": "webpack-dev-server --env.development --config ./build/webpack.base"
}
通過執行npm run dev
來啓啓動開發環境:
默認會在當前根目錄下啓動服務
配置開發服務的配置
const path = require('path')
module.exports = {
mode:'development',
devServer:{
// 更改靜態文件目錄位置
contentBase:path.resolve(__dirname,'../dist'),
compress:true, // 開啓gzip
port:3000, // 更改端口號
}
}
5.打包Html插件
5.1 單入口打包
自動產生html,並且引入打包後的文件
編輯webpack.base
文件
const HtmlWebpackPlugin = require('html-webpack-plugin');
plugins:[
new HtmlWebpackPlugin({
filename:'index.html', // 打包出來的文件名
template:path.resolve(__dirname,'../public/index.html'),
hash:true, // 在引用資源的後面增加hash戳
minify:{
removeAttributeQuotes:true // 刪除屬性雙引號
}
})
]
5.2 多入口打包
根據不同入口
生成多個js文件,引入到不同html中:
── src
├── entry-1.js
└── entry-2.js
多入口需要配置多個entry
entry:{
jquery:['jquery'], // 打包jquery
entry1:path.resolve(__dirname,'../src/entry-1.js'),
entry2:path.resolve(__dirname,'../src/entry-2.js')
},
output:{
filename:'[name].js',
path:path.resolve(__dirname,'../dist')
},
產生多個html文件
new HtmlWebpackPlugin({
filename:'index.html',
template:path.resolve(__dirname,'../public/template.html'),
hash:true,
minify:{
removeAttributeQuotes:true
},
chunks:['jquery','entry1'], // 引入的chunk 有jquery,entry
}),
new HtmlWebpackPlugin({
filename:'login.html',
template:path.resolve(__dirname,'../public/template.html'),
hash:true,
minify:{
removeAttributeQuotes:true
},
inject:false, // inject 爲false表示不注入js文件
chunksSortMode:'manual', // 手動配置代碼塊順序
chunks:['entry2','jquery']
})
以上的方式不是很優雅,每次都需要手動添加HtmlPlugin
應該動態產生html
文件,像這樣:
let htmlPlugins = [
{
entry: "entry1",
html: "index.html"
},
{
entry: "entry2",
html: "login.html"
}
].map(
item =>
new HtmlWebpackPlugin({
filename: item.html,
template: path.resolve(__dirname, "../public/template.html"),
hash: true,
minify: {
removeAttributeQuotes: true
},
chunks: ["jquery", item.entry]
})
);
plugins: [...htmlPlugins]
6.清空打包結果
可以使用clean-webpack-plugin
手動清除某個文件夾內容:
安裝
npm install --save-dev clean-webpack-plugin
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
new CleanWebpackPlugin({
// 清空匹配的路徑
cleanOnceBeforeBuildPatterns: [path.resolve('xxxx/*'),'**/*'],
})
這樣就可以清空指定的目錄了,我們可以看到webpack
插件的基本用法就是 new Plugin
並且放到plugins
中。
7.小結
現在是不是對webpack的使用有了初步印象或更多的想法了呢?大神們的大刀是不是快要按捺不住了呢?下期介紹webpack不得不會的各種配置,敬請期待!