最近和部門老大,一塊兒在研究團隊【EFT - 前端新手村】的建設,目的在於:幫助新人快速瞭解和融入公司團隊,幫助零基礎新人學習和入門前端開發而且達到公司業務開發水平。css
本文也是屬於【EFT - 前端新手村】的一部分,用來幫助新人快速入門 Webpack4
,內容偏基礎,固然也能夠做爲複習材料~~這裏分享給各位小夥伴啦!html
我將從最基礎的【項目初始化】開始介紹,到【處理 CSS / JS / 圖片】,到【熱更新,打包優化】等等,一一介紹和實踐。前端
文章共分爲 18 章,關於最基礎的四個核心概念,能夠到我整理的另外一篇文章 《Webpack4 的四個核心概念》 中學習。node
新建並進入文件夾 leo
:jquery
mkdir leo
cd leo
複製代碼
而後本地安裝 webpack
和 webpack-cli
(在 Webpack 4.0之後須要單獨安裝):webpack
npm install webpack webpack-cli --save-dev
複製代碼
初始化項目結構:git
+ ├─package.json
+ ├─dist // 存放最終打包的文件
+ │ └─index.html
+ ├─src // 存放入口文件等開發文件
+ │ └─index.js
+ ├─webpack.config.js // webpack的配置文件
複製代碼
安裝 lodash
:github
npm install lodash --save-dev
複製代碼
--save
能夠簡寫爲-S
, --save-dev
能夠簡寫爲-D
.web
開發 index.js
:正則表達式
import _ from 'lodash';
function createElement(){
let div = document.createElement('div');
div.innerHTML = _.join(['my', 'name', 'is', 'leo'], '');
return div;
}
document.body.appendChild(createElement());
複製代碼
開發 webpack.config.js
:
const path = require('path');
module.exports = {
entry: './src/index.js',
mode: 'development',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
}
}
複製代碼
開始第一次打包任務:
npx webpack
// 輸出:
Hash: 030b37b6b9a0b4344437
Version: webpack 4.39.1Time: 308ms
Built at: 2019-08-07 08:10:21
Asset Size Chunks Chunk Names
main.js 552 KiB main [emitted] main
Entrypoint main = main.js
[./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 472 bytes {main} [built]
[./node_modules/webpack/buildin/module.js] (webpack)/buildin/module.js 497 bytes {main} [built][./src/index.js] 225 bytes {main} [built]
+ 1 hidden module
複製代碼
打包成功後,生成的文件會保存在 dist
目錄中。
如今在 dist/index.html
中引入打包後的 main.js
,打開瀏覽器測試:
<script src="./main.js"></script>
複製代碼
這一部分,咱們開始學着使用 webpack
去處理 css
相關的模塊。
在項目 src
目錄中,新建 style
文件夾,並新建 index.css
文件:
├─package.json
├─dist // 存放最終打包的文件
│ └─index.html
├─src // 存放入口文件等開發文件
│ ├─index.js
+ │ └─style
+ │ └─index.css
├─webpack.config.js // webpack的配置文件
複製代碼
接着在 index.js
的新建元素方法中,添加 class
爲 box
,這樣新建的元素就帶有 box
的 class
屬性:
// src/index.js
import _ from 'lodash';
import './style/index.css';// 引入樣式文件
function createElement(){
let div = document.createElement('div');
div.innerHTML = _.join(['my', 'name', 'is', 'leo'], '');
+ div.className = 'box';
return div;
}
document.body.appendChild(createElement());
複製代碼
而後在 index.css
文件爲 box
:
// src/style/index.css
.box{
color: red;
}
複製代碼
注意:
這裏使用 import './style/index.css';
引入咱們的樣式文件,是沒辦法解析使用,這時咱們須要在 webpack
中使用到第三方 loader
插件,這裏咱們使用:
css-loader
: 用於處理 css
文件,使得能在 js 文件中引入使用;style-loader
: 用於將 css
文件注入到 index.html
中的 <style>
標籤上;安裝插件:
npm install --save-dev style-loader css-loader
複製代碼
再到 webpack.config.js
中添加 css
解析的 loader
配置:
// webpack.config.js
module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
}
]
}
複製代碼
參數介紹:
test
:須要匹配的模塊後綴名; use
:對應處理的 loader 插件名稱(處理順序是從右往左)。
npx webpack
// 輸出:
Hash: 28b3965aa1b6a0047536
Version: webpack 4.39.1
Time: 482msBuilt at: 2019-08-09 07:45:25 Asset Size Chunks Chunk Names
main.js 565 KiB main [emitted] main
Entrypoint main = main.js
[./node_modules/_css-loader@3.2.0@css-loader/dist/cjs.js!./src/style/index.css] 190 bytes {main} [built]
[./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 472 bytes {main} [built][./node_modules/webpack/buildin/module.js] (webpack)/buildin/module.js 497 bytes {main} [built][./src/index.js] 303 bytes {main} [built]
[./src/style/index.css] 447 bytes {main} [built]
+ 3 hidden modules
複製代碼
這時候能夠看見 index.html
中,文本已經變成紅色,而且 css
代碼已經添加到 <style>
標籤上。
在這一節中,咱們會介紹 webpack
中的模塊,而且介紹如何去處理 sass
文件。
這裏介紹的模塊(module)是指 webpack.config.js
文件中的 module
配置,它決定了如何處理項目中的不一樣類型模塊。
好比上一節介紹的,使用 style-loader
、 css-loader
兩個插件去處理 css
文件。
webpack
模塊支持以下語句:
import
語句;require()
語句;define
和 require
語句;css/sass/less
文件中 @import
語句;(url(...))
或者 HTML 文件 (<img src=...>)
中的圖片連接 (image url)
;這裏建議使用 ES2015
的引入方法,畢竟這是標準。
更多參數介紹,可訪問中文官網的介紹:
《webpack 配置選項》
值的類型:RegExp | [RegExp] | function
防止 webpack
解析那些符合匹配條件的文件,忽略的文件夾中不該該含有 import
、require
、define
的調用,或任何其餘導入機制,忽略的 library
能夠提升構建效率。
// webpack.config.js
module: {
noParse: function(content){
return /jquery|lodash/.test(content);
}
}
複製代碼
建立模塊時,匹配請求的規則數組。按照規則爲對應模塊使用對應的 loader
,或修改解析器(parser)。
// webpack.config.js
module: {
rules: [
{ test: /\.css$/, use: ['style-loader', 'css-loader']}
]
}
複製代碼
module.rules
參數有:use
:爲模塊使用指定 loader
,而且能夠傳入一個字符串數組,加載順序從右往左。
module.rules
匹配條件有:{test : Condition}
:匹配特定條件,非必傳,支持一個正則表達式或正則表達式數組;
{include : Condition}
:匹配特定條件,非必傳,支持一個字符串或字符串數組;
{exclude : Condition}
:排除特定條件,非必傳,支持一個字符串或字符串數組;
{and : [Condition]}
:必須匹配數組中的全部條件;
{or : [Condition]}
:匹配數組中任一條件;
{not : [Condition]}
:必須排除這個條件;
更多參數介紹,可訪問中文官網的介紹:
《Rule》
// webpack.config.js
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
include: [
path.resolve(__dirname, "app/style.css"),
path.resolve(__dirname, "vendor/style.css")
]
}
]
}
複製代碼
須要使用到 sass-loader
的插件,這裏先安裝:
npm install sass-loader node-sass --save-dev
複製代碼
在 src/style
目錄下添加 leo.scss
文件,並添加內容:
// leo.scss
$bg-color: #ee3;
.box{
background-color: $bg-color;
}
複製代碼
而後在 src/index.js
中引入 leo.scss
文件:
// src/index.js
import './style/leo.scss';
複製代碼
再 npx webpack
從新打包,並打開 dist/index.html
能夠看到背景顏色已經添加上去:
像 npx webpack
這個命令咱們須要常用,對於這種命令,咱們能夠把它寫成命令,方便每次使用。
咱們在 package.json
的 scripts
中添加一個命令爲 build
,之後打包只要執行 npm run build
便可:
"scripts": {
"build": "npx webpack --config webpack.config.js"
},
複製代碼
這裏的 --config webpack.config.js
中,--config
後面跟着的是 webpack
配置文件的文件名,默承認以不寫。
添加 SourceMap
是爲了方便打包以後,咱們在項目中調試樣式,定位到樣式在源文件的位置。
在 css-loader
和 sass-loader
均可以經過設置 options
選項啓用 sourceMap
。
// webpack.config.js
rules: [
{
test: /\.(sc|c|sa)ss$/,
use: [
"style-loader",
{
loader:"css-loader",
options:{ sourceMap: true }
},
{
loader:"sass-loader",
options:{ sourceMap: true }
},
]
}
]
複製代碼
再從新打包,看下 index.html
的樣式,樣式已經定位到源文件上了:
這樣咱們在開發過程當中,調試樣式就方便不少了。
這裏咱們用到 PostCSS
這個 loader
,它是一個 CSS 預處理工具,能夠爲 CSS3 的屬性添加前綴,樣式格式校驗(stylelint
),提早使用 CSS
新特性,實現 CSS
模塊化,防止 CSS
樣式衝突。
首先安裝 PostCSS
:
npm install postcss-loader autoprefixer --save-dev
複製代碼
另外還有:
postcss-cssnext
可讓咱們使用 CSS4
的樣式,並能配合 autoprefixer
進行瀏覽器部分兼容的補全,還支持嵌套語法。
precss
相似 scss
語法,若是咱們只須要使用嵌套,就能夠用它替換 scss
。
postcss-import
讓咱們能夠在@import
CSS文件的時 webpack
能監聽並編譯。
更多參數介紹,可訪問中文官網的介紹:
《postcss-loader》
開始添加 postcss-loader
並設置 autoprefixer
:
// webpack.config.js
rules: [
{
test: /\.(sc|c|sa)ss$/,
use: [
"style-loader",
{
loader:"css-loader",
options:{ sourceMap: true }
},
{
loader:"postcss-loader",
options: {
ident: "postcss",
sourceMap: true,
plugins: loader => [
require('autoprefixer')(),
// 這裏可使用更多配置,如上面提到的 postcss-cssnext 等
// require('postcss-cssnext')()
]
}
},
{
loader:"sass-loader",
options:{ sourceMap: true }
},
]
}
]
複製代碼
還須要在 package.json
中添加判斷瀏覽器版本:
// package.json
{
//...
"browserslist": [
"> 1%", // 全球瀏覽器使用率大於1%,最新兩個版本而且是IE8以上的瀏覽器,加前綴
"last 2 versions",
"not ie <= 8"
]
}
複製代碼
爲了作測試,咱們修改 src/style/leo.scss
中 .box
的樣式:
// src/style/leo.scss
.box{
background-color: $bg-color;
display: flex;
}
複製代碼
而後從新打包,能夠看見 CSS3 屬性的前綴已經添加上去了:
在以前學習中,CSS 樣式代碼都是寫到 index.html
的 <style>
標籤中,這樣樣式代碼多了之後,很不方便。
因而咱們須要將這些樣式打包成單獨的 CSS
文件。
webpack4 開始使用 mini-css-extract-plugin
插件,而在 1-3 版本使用 extract-text-webpack-plugin
。
注意:抽取樣式之後,就不能使用
style-loader
注入到 html 中。
安裝插件:
npm install mini-css-extract-plugin --save-dev
複製代碼
引入插件:
// webpack.config.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
複製代碼
而後修改 rules
,將 style-loader
,替換成 MiniCssExtractPlugin.loader
,而後添加 plugins
配置項:
// webpack.config.js
module: {
rules: [
{
test: /\.(sc|c|sa)ss$/,
use: [
MiniCssExtractPlugin.loader,
{
loader:"css-loader",
options:{ sourceMap: true }
},
{
loader:"postcss-loader",
options: {
ident: "postcss",
sourceMap: true,
plugins: loader => [require('autoprefixer')()]
}
},
{
loader:"sass-loader",
options:{ sourceMap: true }
},
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css', // 最終輸出的文件名
chunkFilename: '[id].css'
})
]
複製代碼
而後從新打包,這時候能夠看到咱們 dist
目錄下就多了個 main.css
文件:
由於如今已經將 CSS 都抽取成單獨文件,因此在 dist/index.html
中,咱們須要手動引入 main.css
了:
// index.html
<link rel="stylesheet" href="main.css">
複製代碼
爲了縮小打包後包的體積,咱們常常作優化的時候,將 CSS 和 JS 文件進行壓縮,這裏須要使用到不一樣的插件。
使用 optimize-css-assets-webpack-plugin
壓縮 CSS 的插件。
安裝插件:
npm install optimize-css-assets-webpack-plugin --save-dev
複製代碼
使用插件:
// webpack.config.js
// ... 省略
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
module.exports = {
// ... 省略
plugins: [
// ... 省略
new OptimizeCssAssetsPlugin({})
],
}
複製代碼
從新打包,能夠看到 main.css
已經被壓縮成一行代碼,即壓縮成功~
使用 uglifyjs-webpack-plugin
壓縮 JS 的插件。
安裝插件:
npm install uglifyjs-webpack-plugin --save-dev
複製代碼
引入插件:
// webpack.config.js
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
複製代碼
使用插件:
// webpack.config.js
// ... 省略
module.exports = {
// ... 省略
plugins: [
// ... 省略
new OptimizeCssAssetsPlugin({}),
new UglifyJsPlugin({
cache: true, parallel: true, sourceMap: true
})
],
}
複製代碼
其中 UglifyJsPlugin
的參數:
cache
:當 JS 沒有發生變化則不壓縮;
parallel
:是否啓用並行壓縮;
sourceMap
:是否啓用 sourceMap;
而後從新打包,查看 main.js
,已經被壓縮了:
因爲咱們打包出來的 css
、js
文件是靜態文件,就存在緩存問題,所以咱們能夠給文件名添加 hash
值,防止緩存。
直接在 webpack.config.js
中,爲須要添加 hash 值的文件名添加 [hash]
就能夠:
// webpack.config.js
module.exports = {
// ... 省略其餘
output: {
filename: 'main.[hash].js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[hash].css',
chunkFilename: '[id].[hash].css'
}),
],
}
複製代碼
配置完成後,從新打包,就能夠看到文件名中包含了 hash
值了:
因爲咱們前面給打包的文件名添加了 hash
值,會致使 index.html
引用文件錯誤,因此咱們須要讓它能動態引入打包後的文件。
這裏咱們使用 HtmlWebpackPlugin
插件,它能夠把打包後的 CSS 或者 JS 文件直接引用注入到 HTML 模版中,就不用每次手動修改。
安裝插件:
npm install html-webpack-plugin --save-dev
複製代碼
引入插件:
// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
複製代碼
使用插件:
// webpack.config.js
plugins: [
new HtmlWebpackPlugin({
title: "leo study!", // 生成的文件標題
filename: "main.html", // 最終生成的文件名
minify: { // 壓縮選項
collapseWhitespace: true, // 移除空格
removeComments: true, // 移除註釋
removeAttributeQuotes: true, // 移除雙引號
}
})
],
複製代碼
關於 html-webpack-plugin
更多介紹能夠《查看文檔》github.com/jantimon/ht…
接着咱們打包之後,能夠看見 dist
目錄下,多了 main.html
的文件,格式化之後,能夠看出,已經動態引入打包後的 CSS 文件和 JS 文件了:
在以前,咱們每次打包都會生成新的文件,而且在添加 hash
值之後,文件名不會出現重複的狀況,致使舊文件的冗餘。
爲了解決這個問題,咱們須要在每次打包以前,將 /dist
目錄清空,再進行打包。
這裏咱們使用 clean-webpack-plugin
插件來實現。
安裝插件:
npm install clean-webpack-plugin --save-dev
複製代碼
引入插件:
// webpack.config.js
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
複製代碼
使用插件:
// webpack.config.js
plugins: [
new CleanWebpackPlugin()
],
複製代碼
參數 cleanOnceBeforeBuildPatterns
是表示須要清除的文件夾。
這樣咱們每次打包以前,都會先將 /dist
目錄清空一次,再執行打包。
更多參數介紹,可訪問中文官網的介紹:
《clean-webpack-plugin》
在項目中引入圖片:
// src/style/leo.scss
.box{
background-color: $bg-color;
display: flex;
background: url('./../assets/logo.jpg')
}
複製代碼
這時候咱們若是直接打包,會報錯。
咱們須要使用 file-loader
插件來處理文件導入的問題。
安裝插件:
npm install file-loader --save-dev
複製代碼
使用插件:
// webpack.config.js
module: {
{
test: /\.(png|svg|jpg|jpeg|gif)$/,
use: ["file-loader"]
}]
},
複製代碼
從新打包之後,發現 dist
目錄下多了一個如 373e5e0e214390f8aa9e7abb4c7c635c.jpg
名稱的文件,這就是咱們打包後的圖片。
更進一步,咱們能夠對圖片進行壓縮和優化,這裏咱們用到 image-webpack-loader
插件來處理。
安裝插件:
npm install image-webpack-loader --save-dev
複製代碼
使用插件:
// webpack.config.js
module: {
{
test: /\.(png|svg|jpg|jpeg|gif)$/,
include: [path.resolve(__dirname, 'src/')],
use: ["file-loader",{
loader: "image-webpack-loader",
options: {
mozjpeg: { progressive: true, quality: 65 },
optipng: { enabled: false },
pngquant: { quality: '65-90', speed: 4 },
gifsicle: { interlaced: false },
webp: { quality: 75 }
}
},
]
}]
},
複製代碼
更多參數介紹,可訪問中文官網的介紹:
《image-webpack-loader》
再從新打包,咱們能夠看到圖片打包先後,壓縮了很大:
url-loader
功能相似於 file-loader
,能夠將 url 地址對應的文件,打包成 base64 的 DataURL,提升訪問效率。
安裝插件:
npm install url-loader --save-dev
複製代碼
使用插件:
注意:這裏須要將前面配置的
image-webpack-loader
先刪除掉,在使用url-loader
。
// webpack.config.js
module: {
{
test: /\.(png|svg|jpg|jpeg|gif)$/,
include: [path.resolve(__dirname, 'src/')],
use: [
{
loader: 'url-loader', // 根據圖片大小,把圖片轉換成 base64
options: { limit: 10000 },
},
{
loader: "image-webpack-loader",
options: {
mozjpeg: { progressive: true, quality: 65 },
optipng: { enabled: false },
pngquant: { quality: '65-90', speed: 4 },
gifsicle: { interlaced: false },
webp: { quality: 75 }
}
},
]
}]
},
複製代碼
更多參數介紹,可訪問中文官網的介紹:
《url-loader》
字體處理的方式和圖片處理方式是同樣的,只是咱們在配置 rules
時的 test
值不相同:
// webpack.config.js
module: {
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
include: [path.resolve(__dirname, 'src/')],
use: [ 'file-loader' ]
}
},
複製代碼
在開發環境(development)和生產環境(production)配置文件有不少不一樣,但也有部分相同,爲了避免每次更換環境的時候都修改配置,咱們就須要將配置文件作合併,和提取公共配置。
咱們使用 webpack-merge
工具,將兩份配置文件合併。
安裝插件:
npm install webpack-merge --save-dev
複製代碼
而後調整目錄結構,爲了方便,咱們將原來 webpack.config.js
文件修更名稱爲 webpack.commen.js
,並複製兩份相同的文件出來,分別修改文件名爲 webpack.prod.js
和 webpack.dev.js
。
├─package.json
├─dist
├─src
- ├─webpack.config.js
+ ├─webpack.common.js // webpack 公共配置文件
+ ├─webpack.prod.js // webpack 生產環境配置文件
+ ├─webpack.dev.js // webpack 開發環境配置文件
複製代碼
因爲咱們文件調整了,因此在 package.json
中,打包命令也須要調整,而且配置 mode
模式。
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
- "build": "npx webpack --config webpack.config.js",
+ "build": "npx webpack --config webpack.dev.js --mode development",
+ "dist": "npx webpack --config webpack.prod.js --mode production"
},
複製代碼
咱們先調整 webpack.common.js
文件,將通用的配置保留,不是通用的配置刪除,結果以下:
// webpack.common.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
entry: './src/index.js',
module: {
noParse: function (content) {return /jquery|lodash/.test(content);},
rules: [
{
test: /\.(png|svg|jpg|jpeg|gif)$/,
include: [path.resolve(__dirname, 'src/')],
use: [{
loader: 'url-loader', // 根據圖片大小,把圖片轉換成 base64
options: { limit: 10000 },
},{
loader: "image-webpack-loader",
options: {
mozjpeg: { progressive: true, quality: 65 },
optipng: { enabled: false },
pngquant: { quality: '65-90', speed: 4 },
gifsicle: { interlaced: false },
webp: { quality: 75 }
}
}]
},{
test: /\.(woff|woff2|eot|ttf|otf)$/,
include: [path.resolve(__dirname, 'src/')],
use: [ 'file-loader' ]
}]
},
plugins: [
new HtmlWebpackPlugin({
title: "leo study!",
filename: "main.html",
template: path.resolve(__dirname, 'src/index.html'),
minify: {
collapseWhitespace: true,
removeComments: true,
removeAttributeQuotes: true,
}
}),
new CleanWebpackPlugin()
],
}
複製代碼
安裝 babel-loader
是爲了將 ES6 及以上版本的 JS 代碼轉換成 ES5。
npm install babel-loader @babel/core @babel/preset-env --save-dev
複製代碼
使用插件:
// webpack.common.js
rules: [
// ... 省略其餘
{
test: /\.js$/,
use: [{
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}],
exclude: /(node_modules|bower_components)/,
}
]
複製代碼
關於 babel-loader
更多介紹能夠《查看文檔》webpack.js.org/loaders/bab…
這裏咱們就須要用到 merge-webpack
插件進行配置合併了:
// webpack.dev.js
const path = require('path');
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
let devConfig = {
mode: 'development',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [{
test: /\.(sc|c|sa)ss$/,
use: [
'style-loader', {
loader: "css-loader",
options: { sourceMap: true }
}, {
loader: "postcss-loader",
options: {
ident: "postcss", sourceMap: true,
plugins: loader => [ require('autoprefixer')() ]
}
}, {
loader: "sass-loader",
options: { sourceMap: true }
}
]
}]
}
}
module.exports = merge(common, devConfig)
複製代碼
一樣對於生產環境的配置,咱們也須要用 merge-webpack
插件進行配置合併:
// webpack.prod.js
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
let prodConfig = {
mode: 'production',
output: {
filename: 'main.[hash].js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [{
test: /\.(sc|c|sa)ss$/,
use: [
MiniCssExtractPlugin.loader, {
loader: "css-loader",
options: { sourceMap: true }
}, {
loader: "postcss-loader",
options: {
ident: "postcss", sourceMap: true,
plugins: loader => [ require('autoprefixer')() ]
}
}, {
loader: "sass-loader",
options: { sourceMap: true }
}
]
}]
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[hash].css',
chunkFilename: '[id].[hash].css'
}),
new OptimizeCssAssetsPlugin({}),
new UglifyJsPlugin({
cache: true, parallel: true, sourceMap: true
}),
],
}
module.exports = merge(common, prodConfig)
複製代碼
當 webpack 打包源代碼後,就很難追蹤到錯誤和警告在源代碼的位置。
如將三個源文件打包一個 bundle
中,其中一個文件的代碼報錯,那麼堆棧追中就會指向 bundle
。
爲了能方便定位錯誤,咱們使用 inline-source-map
選項,注意不要在生產環境中使用。
// webpack.dev.js
let devConfig = {
// ... 省略其餘
+ devtool: 'inline-source-map'
}
複製代碼
爲了測試是否成功,咱們將 src/index.js
代碼中,在第 12 行上,添加一句日誌打印。
// src/index.js
// ... 省略其餘
+ console.log(111)
複製代碼
對比下開啓 sourceMap
先後的區別:
若是每次咱們修改完代碼,都要手動編譯,那是多累的一件事。
爲此咱們使用 --watch
命令,讓咱們每次保存完,都會自動編譯。
爲此,咱們須要在 package.json
中的打包命令添加 --watch
命令:
// package.json
- "build": "npx webpack --config webpack.dev.js",
+ "build": "npx webpack --config webpack.dev.js --watch",
複製代碼
這裏僅對開發環境開啓,生產環境不須要使用。
上一節介紹監控自動編譯,當咱們保存文件後,會自動編譯文件,可是咱們仍是須要手動去刷新頁面,才能看到編譯後的結果。
因而爲了自動編譯以後,再自動從新加載,咱們就可使用 webpack-dev-server
來啓動一個簡單 web 服務器,實時從新加載。
插件安裝:
npm install webpack-dev-server --save-dev
複製代碼
使用插件:
// webpack.dev.js
const webpack = require('webpack');
const webpack = require('webpack');
let devConfig = {
// ... 省略其餘
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true,
hot: true,
overlay: true,
open:true,
publicPath: '/',
host: 'localhost',
port: '1200'
}
plugins: [
new webpack.NamedModulesPlugin(), // 更容易查看(patch)的以來
new webpack.HotModuleReplacementPlugin() // 替換插件
]
}
複製代碼
啓動熱更新:
npx webpack-dev-server --config webpack.dev.js
複製代碼
經常使用配置:
contentBase: path.join(__dirname, 'dist'), //本地服務器所加載的頁面所在的目錄
clinetLogLevel: 'warning', // 可能值有 none, error, warning 或者 info (默認值)
hot:true,//啓動熱更新替換特性,須要配合 webpack.HotModuleReplacementPlugin 插件
host:'0.0.0.0', // 啓動服務器的 host
port:7000, // 端口號
compress:true, // 爲全部服務啓用gzip壓縮
overlay: true, // 在瀏覽器中顯示全屏覆蓋
stats: "errors-only" ,// 只顯示包中的錯誤
open:true, // 啓用「打開」後,dev服務器將打開瀏覽器。
proxy: { // 設置代理
"/api": {
target: "http://localhost:3000",
pathRewrite: {"^/api" : ""}
}
}
複製代碼
這時候咱們訪問 http://localhost:1200/main.html
就能夠看到頁面,而且修改文件,頁面也會同時刷新。
咱們能夠將 npx webpack-dev-server --config webpack.dev.js
寫到 package.json
中做爲一個命令:
// package.json
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "npx webpack --config webpack.dev.js --watch",
"dist": "npx webpack --config webpack.prod.js",
+ "watch": "npx webpack-dev-server --config webpack.dev.js"
},
複製代碼
接着上一節,接下來給 webpack 設置代理服務器:
// webpack.dev.js
let devConfig = {
// ... 省略其餘
devServer: {
// ... 省略其餘
proxy: {
"/api": { // 以 '/api' 開頭的請求,會跳轉到下面的 target 配置
target: "http://192.168.30.33:8080",
pathRewrite: {
"^api": "/mock/api"
}
}
}
}
複製代碼
最後當咱們請求 /api/getuser
接口,就會轉發到 http://192.168.30.33:8080/mock/api
。
babel-loader
插件的安裝,已經提早介紹,在【11、 webpack 配置合併和提取公共配置】中。
這裏講一下 babel-loader
的優化。
babel-loader
能夠配置 cacheDirectory
來提升打包效率:
cacheDirectory
:默認值 false
,開啓後構建時會緩存文件夾,後續從緩存中讀取,將提升打包效率。安裝插件:
npm install eslint eslint-loader --save-dev
複製代碼
另外還須要安裝 eslint 解釋器、校驗規則等:
npm install babel-loader standard --save-dev
複製代碼
在項目根目錄建立 .eslintrc.js
,指定 eslint 規則。
這份配置內容有點多,能夠去 個人 gist 複製gist.github.com/pingan8787/… 。
在項目根目錄建立 .eslintignore
,指定 eslint 忽略一些文件不校驗,好比內容能夠是:
/dist/
/node_modules/
複製代碼
在 webpack 配置中,咱們使用 resolve
來配置模塊解析方式。
這是很是重要的,好比 import _ from 'lodash'
,實際上是加載解析了 lodash.js
文件。
該配置就是用來設置加載和解析的方式。
在解析過程當中,咱們能夠進行配置:
當咱們引入一些文件時,須要寫很長的路徑,這樣使得代碼更加複雜。
爲此咱們可使用 resolve.alias
,建立 import
或 require
的別名,使模塊引入更加簡單。
使用配置:
// webpack.common.js
module.exports = {
entry: './src/index.js',
+ resolve: {
+ alias: {
+ '@' : path.resolve(__dirname, 'src/')
+ }
+ }
// 省略其餘
}
複製代碼
alias
參數的含義:
使用 @
來替代 path.resolve(__dirname, 'src/')
這個路徑,接下來咱們測試看看。
咱們在 src/
目錄下新增 leo.js
:
// leo.js
export let name = 'pingan';
複製代碼
再到 src/index.js
中引入:
// index.js
import { name } from '@/leo.js';
複製代碼
這樣就能正常引入。
固然,咱們也能夠根據實際狀況,爲不一樣路徑設置不一樣別名:
// webpack.common.js
alias: {
'@' : path.resolve(__dirname, 'src/')
+ 'assets' : path.resolve(__dirname, 'src/assets/')
}
複製代碼
更多參數介紹,可訪問中文官網的介紹:
《resolve》
resolve.extensions
用來自動解析肯定的擴展,讓咱們在引入模塊的時候,能夠不用設置拓展名,默認值爲:
extensions: [".js", ".json"]
複製代碼
使用配置:
// webpack.common.js
import { name } from '@/leo';
複製代碼
當咱們使用 CDN 引入 jquery
時,咱們並不想把它也打包到項目中,咱們就能夠配置 externals
外部拓展的選項,來將這些不須要打包的模塊從輸出的 bundle 中排除:
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
複製代碼
配置 externals
:
// webpack.common.js
module.exports = {
// ... 省略其餘
+ externals: {
+ jquery: 'jQuery'
+ },
}
複製代碼
經過上面配置,咱們就不會把不須要打包的模塊打包進來。而且下面代碼正常運行:
import $ from 'jquery';
$('.leo').show();
複製代碼
更多參數介紹,可訪問中文官網的介紹:
《externals》
這裏咱們使用 webpack-bundle-analyzer
插件,來對打包後的文件進行數據分析,歷來找到項目優化的方向。
webpack-bundle-analyzer
使用交互式可縮放樹形圖可視化 webpack 輸出文件的大小。
安裝插件:
npm install webpack-bundle-analyzer --save-dev
複製代碼
這個咱們只有在開發環境中使用。
使用插件:
// webpack.dev.js
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
plugins: [
new BundleAnalyzerPlugin()
// ...
]
}
複製代碼
配置完成之後,咱們執行 npm run build
打包,打包完成後,會自動打開一個數據報表分析的頁面,地址是 http://127.0.0.1:8888/
:
webpack-bundle-analyzer
將幫助咱們:
咱們常常將報表中區域最大的模塊進行優化!
咱們能夠看出,打包後的項目中 lodash.js
佔了很是大的內存,咱們就針對 lodash.js
進行優化。
咱們將 lodash.js
改成 CDN 引入:
// index.html
<script src="https://cdn.bootcss.com/lodash.js/4.17.15/lodash.js"></script>
複製代碼
而後去設置上一節講到的 externals
:
// webpack.common.js
externals: {
jquery: 'jQuery',
+ lodash: '_'
},
複製代碼
再打包之後,能夠看到 lodash.js
已經不在包裏面了:
而且打包後的文件,也能正常運行:
更多參數介紹,可訪問中文官網的介紹:
《webpack-bundle-analyzer》
本文是根據 《2019最新Webpack4.0教程4.x 成仙之路》 學習總結下來的學習之路,適合入門,涉及範圍較多,內容比較長,須要能靜下心來學習。
內容若是有誤,歡迎留言指點,我會及時修改。
本文代碼最終託管在個人 github 上,點擊查看(github.com/pingan8787/…)。
但願本身的文章會對各位有所幫助,也歡迎各位大佬指點。
Author | 王平安 |
---|---|
pingan8787@qq.com | |
博 客 | www.pingan8787.com |
微 信 | pingan8787 |
每日文章推薦 | github.com/pingan8787/… |
ES小冊 | js.pingan8787.com |