一、專案說明
-
這是一個 極簡的前端專案,適合新手入門,簡述如下(有詳細說明)
-
啟動本地服務 webpack-dev-server
-
處理資源路徑
-
處理 css、scss、less
-
css3 屬性字首
-
分離css、壓縮分離後的css、淨化分離後的css
-
babel轉換(babel7.X)
-
二、專案初始化
-
新建專案根目錄 資料夾
webpack_demo_basic
-
進入終端執行
npm init -y
生成 package.json 檔案,如下
-
初始化專案檔案,目錄如下
src/css/index.css 檔案:css樣式檔案
src/less/less 檔案:less樣式檔案
src/scss/index.scss 檔案:scss樣式檔案
src/index.html 檔案:專案html
src/index.js 檔案:專案入口js
.babelrc 檔案:專案babel配置檔案
.gitignore 檔案:git忽略配置檔案(使用 Git 版本控制時,需要配置)
package.json 檔案:定義了專案所需的模組,以及專案的配置資訊
webpack.config.js 檔案:webpack配置檔案
-
安裝 webpack依賴
npm i webpack@4.28.3 webpack-cli@3.2.0 -D 複製程式碼
-
webpack 基礎配置
// webpack.config.js 檔案 const path = require('path'); module.exports = { mode: 'development', // 開發模式 entry: './src/index.js', // 打包後輸出的檔名 為 main.js /** * 或 * * entry: { * index: './src/index.js' * } */ output: { path: path.resolve(__dirname, 'dist'), // 打包後專案 輸出到專案根目錄下 dist 資料夾 filename: '[name].js' // 輸出的 入口JS檔名稱 }, // loader 相關配置 module: { rules: [] }, // 外掛 相關配置 plugins: [] }; 複製程式碼
三、配置/生成 頁面 html
-
外掛:html-webpack-plugin
根據模板 生成頁面html
自動引入 JS 等外部資原始檔
設定 title 、mate 等標籤內容
優化html(壓縮、快取、轉換等)
-
安裝
npm i html-webpack-plugin@3.2.0 -D 複製程式碼
-
配置
// webpack.config.js 檔案 const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { plugins: [ new HtmlWebpackPlugin({ filename: 'index.html', // 檔名; 預設是index.html template: './src/index.html', // 指定模板html檔案 title: '11111', // html檔案 title標籤的內容 inject: true, // 自動引入JS指令碼的位置,預設值為 true(通常預設值即可滿足條件) /* * 此選項有如下四種值: * * true/'body': JS指令碼在 body標籤底部 引入 * 'head': JS指令碼在 bead標籤底部 引入 * false: 不插入任何JS(幾乎不會用到) */ // 如下 通常在生產模式下 才配置 hash: true, // 預設值為false, 值為true時,html 引入的指令碼、scss都加hash值(清除快取) // 建議 生產環境下 設定為 true cache: true, // 預設值為true, 設定快取 // 建議 生產環境下 設定為 true minify: { // 建議 生產環境下 再配置此選項 minifycss: true, // 壓縮css minifyJS: true, // 壓縮JS minifyURLs: true, // 壓縮URL removeComments: true, // 去掉註釋 removeAttributeQuotes: true, // 去掉標籤上 屬性的雙引號 collapseWhitespace: true, // 去掉空行 removeRedundantAttributes: true, // 去掉多餘的屬性 removeEmptyAttributes: true // 去掉空屬性 } }) ] }; 複製程式碼
-
配置說明
四、配置 本地服務
-
伺服器:webpack-dev-server
一個小型的 Node.js Express伺服器,程式開發時 本地執行專案
-
安裝
npm i webpack-dev-server@3.1.14 -D 複製程式碼
-
配置
// webpack.config.js 檔案 const path = require('path'); module.exports = { devServer:{ index: 'index.html', // 伺服器啟動的頁面(同 html-webpack-plugin 中 filename 選項); 預設值為 index.html port: 3000, // 指定埠號; 預設 8080 host: 'localhost', // 指定host; 預設 localhost /* * 或 * host: '0.0.0.0', // 可 通過IP 訪問,也可以通過 localhost 訪問 * useLocalIp: true, // browser open with your local IP */ open: true, // 啟動本地服務後,自動開啟頁面 compress: true, // 是否啟用 gzip 壓縮 overlay: true, // 編譯器錯誤或警告時, 在瀏覽器中顯示全屏覆蓋; 預設false progress: true, // 是否將執行進度輸出到控制檯; 預設 false contentBase: path.resolve(__dirname, 'dist'), // 告訴伺服器從哪裡提供內容。只有在你想要提供靜態檔案時才需要 // 精簡 終端輸出(本地執行時) stats: { modules: false, children: false, chunks: false, chunkModules: false } } }; 複製程式碼
-
配置說明
-
支援熱更新:檢測到專案中修改的程式碼,立即在瀏覽器中自動更新
新手需知道:熱更新僅限於專案程式碼;webpack 相關的配置不會參與熱更新
-
精簡終端輸出
-
關於 精簡終端輸出 詳細講解見之後的文章
-
小夥伴們可以對比下,本地執行專案時,有無 stats 選項,終端輸出的變化
-
-
熱替換
-
場景:建議開發環境下使用
-
好處:區域性載入 頁面有改動的地方;加快開發編譯速度
-
關於 熱替換 詳細講解見之後的文章
-
五、配置 npm script
-
在
package.json
中配置相關指令,實現 本地執行、打包專案終端執行 npm run xxx,就會執行 package.json 裡script對應的 xxx 指令
-
本地啟動專案
-
指令配置
// packgae.json 檔案 { "scripts": { "dev": "webpack-dev-server" } } 複製程式碼
-
說明
--progress
、--open
{ "scripts": { "dev": "webpack-dev-server --progress --open" } } // --progress 代表: 本地啟動專案終端顯示進度 // --open 代表: 執行後瀏覽器自動開啟頁面 // 這兩個和 webpack-dev-server 伺服器的配置選項 progress、open 達到的效果一致,無需重複配置 複製程式碼
--config
{ "scripts": { "dev": "webpack-dev-server --config webpack/config.js" } } // "dev": "webpack-dev-server"` 預設去找 根目錄下名為 `webpack.config.js` 的webpack配置檔案,進行打包、執行 // 如果有場景要自定義 webpack 配置檔名稱/路徑,可以使用 --config 指定 webpack 配置檔案,如上 複製程式碼
-
專案根目錄下,終端執行
npm run dev
即可本地執行專案瀏覽地址
http://localhost:3000/
-
-
打包專案
- 指令配置
// packgae.json { "scripts": { "build": "webpack" } } 複製程式碼
-
說明
-
如上打包會按照 webpack4.X 預設打包機制 進行打包
-
後續文章會講解 如何自定義打包
-
-
專案根目錄下,終端執行
npm run build
即可打包專案,輸出到 根目錄的dist
資料夾
六、配置 資源路徑
1. 解決 專案 中的路徑問題
-
loader:url-loader、file-loader
解決專案中的路徑問題(不限於 css)
讓 webpack 識別 圖片、視訊、字型 等資原始檔
-
url-loader 是 file-loader 的一個超集
低版本的 url-loader 中封裝了 file-loader,url-loader 的執行 不會依賴file-loader
高版本的 url-loader 在使用時,需要額外安裝 file-loader
-
url-loader 的 file-loader 區別
-
url-loader
解決專案中的路徑問題
將 小體積的資源 轉成 base64
讓 webpack 識別 資原始檔
-
file-loader
解決專案中的路徑問題
讓 webpack 識別 資原始檔
-
-
file-loader 原理淺析
眾所周知,webpack 會將各個模組打包成一個檔案,最終我們樣式中的 url 路徑是相對入口html頁面的,而不是相對於原始css檔案所在的路徑,這就會導致圖片引入失敗
file-loader可以解析專案中的url(不限於css),會根據配置 將圖片拷貝到相應的路徑,打包時會根據規則修改引入路徑
-
安裝
npm i url-loader@1.1.2 file-loader@3.0.1 -D 複製程式碼
-
配置
// webpack.config.js 檔案 module.exports = { module: { rules: [{ test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, use: [{ loader: 'url-loader', options: { limit: 8192, // 檔案體積小於 8192kb 時,將被轉為 base64 資源 name: '[name].[ext]', outputPath: 'static/assets/' // 資源 輸出路徑 } }] }, { test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, use: [{ loader: 'url-loader', options: { name: '[name].[ext]', outputPath: 'static/assets/' // 資源 輸出路徑 } }] }, { test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, use: [{ loader: 'url-loader', options: { name: '[name].[ext]', outputPath: 'static/assets/' // 資源 輸出路徑 } }] }] } }; 複製程式碼
-
說明
-
以配置中
options.outputPath
為例,資源將被輸出到 根目錄下static/assets
資料夾中
2. 解決 html 中的路徑問題
-
loader:html-withimg-loader
解決 html 中的路徑問題,如
img
標籤的路徑問題webpack 建議所有圖片都使用背景圖的方式,所以預設情況下 在html中使用
img
標籤,會顯示路徑錯誤 -
安裝
npm i html-withimg-loader@0.1.16 -D 複製程式碼
-
配置
// webpack.config.js 檔案 module.exports = { module: { rules: [{ test: /\.(htm|html)$/, use:[{ loader: 'html-withimg-loader' }] }] } }; 複製程式碼
七、配置 css相關
1. 識別 css
-
loader: css-loader style-loader
webpack 預設只識別JS檔案,要解析打包css 必須安裝相應的loader
-
安裝
npm i style-loader@0.23.1 css-loader@2.1.0 -D 複製程式碼
-
配置
// webpack.config.js 檔案 module.exports = { module: { rules: [{ test:/\.css$/, use: ['style-loader','css-loader'] }] } }; 複製程式碼
2. 識別 scss
-
loader 相關: sass-loader、node-sass
作為css預編譯語言,需要 相應的loader進行解析
-
安裝
npm i node-sass@4.11.0 sass-loader@7.1.0 -D 複製程式碼
-
配置
// webpack.config.js 檔案 module.exports = { module: { relus: [{ test: /\.scss$/, use: ['style-loader','css-loader','sass-loader'] // 編譯順序從右往左 }] } }; 複製程式碼
3. 識別 less
-
loader 相關: less-loader、less
作為css預編譯語言,需要 相應的loader進行解析
-
安裝
npm i less@3.9.0 less-loader@4.1.0 -D 複製程式碼
-
配置
// webpack.config.js 檔案 module.exports = { module: { relus: [{ test: /\.less$/, use: ['style-loader','css-loader','less-loader'] // 編譯順序從右往左 }] } }; 複製程式碼
4. 自動新增 css3屬性字首
-
loader 相關: postcss-loader、autoprefixer
針對css3新增的屬性,並不是所有瀏覽器都支援
為相容不同核心的瀏覽器,增加屬性字首(與核心相對應)
-webkit, -ms, -o, -moz
-
安裝
npm i postcss-loader@3.0.0 autoprefixer@9.4.4 -D 複製程式碼
-
配置
// 專案根目錄新建 檔案postcss.config.js,其中配置如下 module.exports = { plugins: [ require('autoprefixer')({ "browsers": [ "defaults", "not ie < 11", "last 2 versions", "> 1%", "iOS 7", "last 3 iOS versions" ] }) ] }; 複製程式碼
// webpack.config.js 檔案 // 給 css檔案 中的css3屬性自動 加屬性字首 module.exports = { module: { rules: [{ test: /\.css$/, use: ['style-loader', 'css-loader', 'postcss-loader'] }] } }; 複製程式碼
// webpack.config.js 檔案 // 給 scss檔案 中的css3屬性自動 加屬性字首 module.exports = { module: { rules: [{ test: /\.scss$/, use: ['style-loader', 'css-loader', 'postcss-loader', 'sass-loader'] // 編譯順序從右往左 }] } }; 複製程式碼
// webpack.config.js 檔案 // 給 css檔案 中的less屬性自動 加屬性字首 module.exports = { module: { rules: [{ test: /\.less$/, use: ['style-loader', 'css-loader', 'postcss-loader', 'less-loader'] // 編譯順序從右往左 }] } }; 複製程式碼
5. 分離 css
-
外掛:mini-css-extract-plugin
webpack 認為css應該被打包到JS中,以減少HTTP請求次數
但有的開發團隊,要求 抽離css單獨打包
-
安裝
npm i mini-css-extract-plugin@0.5.0 -D 複製程式碼
-
配置
// webpack.config.js 檔案,抽離css const MinicssExtractPlugin = require("mini-css-extract-plugin"); module.exports = { module: { rules: [{ test: /\.css$/, use: [MinicssExtractPlugin.loader, 'css-loader'] }] }, plugins: [ new MinicssExtractPlugin({ filename: "static/css/[name].[hash:7].css" }) ] } 複製程式碼
// webpack.config.js 檔案,抽離scss const MinicssExtractPlugin = require("mini-css-extract-plugin"); module.exports = { module: { rules: [{ test: /\.scss$/, use: [MinicssExtractPlugin.loader, 'css-loader', 'sass-loader'] }] }, plugins: [ // 新增一處即可 new MinicssExtractPlugin({ filename: "static/css/[name].[hash:7].css" }) ] } 複製程式碼
// webpack.config.js 檔案,抽離less const MinicssExtractPlugin = require("mini-css-extract-plugin"); module.exports = { module: { rules: [{ test: /\.less$/, use: [MinicssExtractPlugin.loader, 'css-loader', 'less-loader'] }] }, plugins: [ // 新增一處即可 new MinicssExtractPlugin({ filename: "static/css/[name].[hash:7].css" }) ] } 複製程式碼
-
解決 css抽離後導致的路徑問題
很容易將 css抽離出來,但是抽離出來的css中屬性 引用路徑並不對(原因淺析:打包後分離出來的css 和 html 不在同一級目錄下)
解決方案:配置資原始檔的輸出路徑(相對路徑 改成 絕對路徑)
// webpack.config.js 配置檔案 let publicPath = ''; const isProduction = false; // 是否是生產環境 if (!isProduction) { publicPath = 'http://localhost:3000/static/assets'; } else { // 將 publicPath 設定為線上釋出地址 } module.exports = { // loader 相關配置 module: { rules: [{ test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, use: [{ loader: 'url-loader', options: { limit: 8192, // 檔案體積小於 8192kb 時,將被轉為 base64 資源 name: '[name].[ext]', outputPath: 'static/assets/', // 資源 輸出路徑 publicPath } }] }, { test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, use: [{ loader: 'url-loader', options: { name: '[name].[ext]', outputPath: 'static/assets/', // 資源 輸出路徑 publicPath } }] }, { test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, use: [{ loader: 'url-loader', options: { name: '[name].[ext]', outputPath: 'static/assets/', // 資源 輸出路徑 publicPath } }] }] } }; 複製程式碼
6. 壓縮 分離後的css
-
外掛:optimize-css-assets-webpack-plugin
即使是生產模式下,分離後的css不會被壓縮
使用此外掛對css進行壓縮處理
-
安裝
npm i optimize-css-assets-webpack-plugin@5.0.1 -D 複製程式碼
-
配置
// webpack.config.js 檔案 const Optimizecss = require('optimize-css-assets-webpack-plugin'); module.exports = { plugins: [ new Optimizecss() ] } 複製程式碼
7. 淨化 分離後的css
-
外掛:purifycss-webpack、purify-css
對於頁面中沒有使用到的css,打包時可以通過此外掛進行清除
限制:僅限於 清除分離後的css檔案中 無用的樣式
-
安裝
npm i purifycss-webpack@0.7.0 purify-css@1.2.5 -D 複製程式碼
-
配置
// webpack.config.js 檔案 const glob = require('glob'); const PurifycssPlugin = require("purifycss-webpack"); module.exports = { plugins: [ new PurifycssPlugin({ paths: glob.sync(path.join(__dirname, 'src/*.html')), }) ] }; 複製程式碼
八、配置 JS相關
1. babel 轉換
-
概述
-
瀏覽器對 JavaScript 新語法、API、擴充套件語言的識別能力不同
-
babel 就是 JavaScript 語法編譯器 之一
-
主要將 ECMAScript 2015+ 的JS程式碼轉換成 低版本瀏覽器可識別的 JS 程式碼
-
將 JSX、TypeScript 等JS擴充套件語言 轉換成 瀏覽器可識別的原生 JS
-
-
-
安裝
npm i babel-loader@8.0.5 @babel/core@7.2.2 @babel/preset-env@7.2.3 @babel/plugin-transform-runtime@7.2.0 @babel/runtime@7.2.0 babel-plugin-transform-remove-console@6.9.4 @babel/plugin-syntax-dynamic-import@7.2.0 -D 複製程式碼
-
配置
下面是 babel 7+ | babel-loader 8+ 的相關配置
-
方式一:將 babel 的配置項抽離到 .babelrc 檔案中(推薦)
// webpack.config.js 檔案 const path = require('path'); module.exports = { module: { rules: [{ test: /\.js$/, use: ['babel-loader'], exclude: /node_modules/, // 排除不要載入的資料夾 include: path.resolve(__dirname, 'src') // 指定需要載入的資料夾 }] } }; 複製程式碼
// .babelrc 檔案中 配置 { "presets": [ [ "@babel/preset-env", // 根據 preset-env 標準進行轉換 { "modules": false // 不轉換模組型別 } ] ], "plugins": [ "@babel/plugin-transform-runtime", // 來處理全域性函式和優化babel編譯 "transform-remove-console" // 打包時 移除 console 相關(開發環境下 不需要配置) ], "comments": false // 打包時 移除指令碼中的註釋 } 複製程式碼
-
方式二:直接在 webpack 配置項中 配置(不推薦)
// webpack.config.js 檔案 const path = require('path'); module.exports = { module: { rules: [{ test: /\.js$/, use: [{ loader: 'babel-loader', options: { { presets: [ [ "@babel/preset-env", // 根據 preset-env 標準進行轉換 { "modules": false // 不轉換模組型別 } ] ], plugins: [ "@babel/plugin-transform-runtime", // 來處理全域性函式和優化babel編譯 "transform-remove-console" // 打包時 移除 console 相關 ], comments: false // 打包時 移除指令碼中的註釋 } } }], exclude: /node_modules/, // 排除不要載入的資料夾 include: path.resolve(__dirname, 'src') // 指定需要載入的資料夾 }] } }; 複製程式碼
-
-
說明
2. 壓縮 JS
-
webpack4.X 在
production
模式下,自動壓縮JS,所以通常情況下 專案中單獨配置外掛壓縮JS的場景不多了 -
如下兩個外掛,可以壓縮JS
九、webpack 配置檔案
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MinicssExtractPlugin = require("mini-css-extract-plugin");
const Optimizecss = require('optimize-css-assets-webpack-plugin');
const glob = require('glob');
const PurifycssPlugin = require("purifycss-webpack");
let publicPath = '';
const isProduction = false; // 是否是生產環境
if (!isProduction) {
publicPath = 'http://localhost:3000/static/assets';
} else {
// 將 publicPath 設定為線上釋出地址
}
module.exports = {
mode: 'development',
entry: {
index: './src/index.js'
},
output: {
path: path.resolve(__dirname, 'dist'), // 打包後專案 輸出到專案根目錄下 dist 資料夾
filename: '[name].js' // 輸出的 入口JS檔名稱
},
// loader 相關配置
module: {
rules: [{
test: /\.(htm|html)$/,
use:[{
loader: 'html-withimg-loader'
}]
}, {
test: /\.css$/,
use: [MinicssExtractPlugin.loader, 'css-loader']
}, {
test: /\.scss$/,
use: [MinicssExtractPlugin.loader, 'css-loader', 'sass-loader']
}, {
test: /\.less$/,
use: [MinicssExtractPlugin.loader, 'css-loader', 'less-loader']
}, {
test: /\.js$/,
use: ['babel-loader'],
exclude: /node_modules/, // 排除不要載入的資料夾
include: path.resolve(__dirname, 'src') // 指定需要載入的資料夾
}, {
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
use: [{
loader: 'url-loader',
options: {
limit: 8192, // 檔案體積小於 8192kb 時,將被轉為 base64 資源
name: '[name].[ext]',
outputPath: 'static/assets/',
publicPath
}
}]
}, {
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
use: [{
loader: 'url-loader',
options: {
name: '[name].[ext]',
outputPath: 'static/assets/' // 資源 輸出路徑
}
}]
}, {
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
use: [{
loader: 'url-loader',
options: {
name: '[name].[ext]',
outputPath: 'static/assets/' // 資源 輸出路徑
}
}]
}]
},
// 外掛 相關配置
plugins: [
new HtmlWebpackPlugin({
filename: 'index.html', // 檔名; 預設是index.html
template: './src/index.html' // 指定模板html檔案
}),
// 分離 css
new MinicssExtractPlugin({
filename: "static/css/[name].[hash:7].css"
}),
// 壓縮分離後的 css
new Optimizecss(),
// 淨化 css
new PurifycssPlugin({
paths: glob.sync(path.join(__dirname, 'src/*.html')),
})
],
devServer:{
index: 'index.html', // 伺服器啟動的頁面(同 html-webpack-plugin 中 filename 選項); 預設值為 index.html
host: 'localhost', // 指定host; 預設 localhost
port: 3000, // 指定埠號; 預設 8080
open: true, // 啟動本地服務後,自動開啟頁面
compress: true, // 是否啟用 gzip 壓縮
overlay: true, // 編譯器錯誤或警告時, 在瀏覽器中顯示全屏覆蓋; 預設false
progress: true, // 是否將執行進度輸出到控制檯; 預設 false
contentBase: path.resolve(__dirname, 'dist'), // 告訴伺服器從哪裡提供內容。只有在你想要提供靜態檔案時才需要
// 精簡 終端輸出(本地執行時)
stats: {
modules: false,
children: false,
chunks: false,
chunkModules: false
}
}
};
複製程式碼
附言
-
小夥伴們,有什麼問題 可以留言,一起交流哈
-
接下來,我還會發布幾篇 webpack4.X 實戰文章,敬請關注
-
我是一名熱衷於程式設計的前端開發,WX:ZXvictory66