首先貼出官方解釋:javascript
本質上,webpack 是一個現代 JavaScript 應用程序的靜態模塊打包器(module bundler)。當 webpack 處理應用程序時,它會遞歸地構建一個依賴關係圖(dependency graph),其中包含應用程序須要的每一個模塊,而後將全部這些模塊打包成一個或多個 bundle。css
通俗的講,webpack 是一個代碼加工機器,咱們把本身的代碼丟給他,它通過加工以後再還給咱們。
以上所說的加工,包括但不限於如下幾點:html
- 代碼打包壓縮
- 代碼編譯(ES6轉ES五、ts 轉 js 、less\sass 轉 css 等)
- 代碼優化,提取公共模塊
webpack 還能夠爲咱們提供前端靜態服務,極大地方便了咱們平常的開發調試。前端
綜上,咱們之因此使用 webpack ,主要是爲了提升開發效率,優化自身代碼。java
當咱們把自身代碼交給 webpack 加工時,必然會須要一個入口,而加工事後的代碼須要還給咱們,確定也會須要出口,而在加工的過程當中 webpack 須要進行一系列的工序。如同麪粉變成麪包,不僅是烘烤這麼簡單。
由上,咱們來理解 webpack 核心的四個概念:node
- entry : 文件入口
- output : 文件出口
- module : 工序一 (經過配置,對不一樣的文件類型作處理,完成模塊代碼的轉換)
- plugins : 工序二 (經過插件,來獲取更增強大的加工處理能力,完成更復雜的構建任務)
到這裏,咱們即可以寫出一份簡單的配置文件骨架:react
module.exports = {
entry: {
··· 文件入口
},
output: {
··· 文件出口
},
module: {
rules: [
··· 一些列的 loader
],
},
plugins: [
··· 一系列的插件
]
}
複製代碼
在 webpack 4.0以上版本中爲咱們提供了 --mode
這個命令配置項,mode 分爲 development 和 production 兩個選項,默認爲production。它爲咱們提供了一些簡單的基本配置,對於簡單的項目,咱們再也不須要配置文件,mode 默認入口文件爲 src 文件夾 下的 index.js,出口爲 dist 文件夾,打包時,咱們只須要選擇 mode 的參數便可。webpack
webpack --mode development/production
複製代碼
在 mode 的默認配置中,已經爲咱們處理了一些常見的用法。可是,這些默認配置,沒法處理非 js 文件內容。web
下面這段話來自知乎:正則表達式
development默認值會給你最好的開發體驗,它注重:
瀏覽器調試工具
快速開發週期中的快速增量編譯
在運行過程當中提供有效的錯誤信息
而production默認值會給你提供一系列有效的默認值以便部署你的應用,它注重:
小的輸出體積
運行快速的代碼
忽略僅在開發時須要的代碼
不暴露源碼和文件路徑
易於使用的輸出產物
複製代碼
實際上,就目前看來,在項目開發中,咱們仍需配置本身的配置文件。
在平常的開發中,咱們通常須要 webpack 爲咱們解決下面這些問題:
- 構建咱們發佈須要的 HTML、CSS、JS 文件
- 使用 CSS 預處理器來編寫樣式
- 處理和壓縮圖片
- 使用 Babel 來支持 ES 新特性
- 本地提供靜態服務以方便開發調試
根據以上需求,咱們能夠這樣配置本身 webpack.config.js :
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin'); // 注意版本號 webpack 4 以上版本請下載 @next 版本
const path = require('path');
module.exports = {
entry: {
index: './src/index.js',
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].min.js'
},
module:{
rules: [
{
test: /\.jsx?$/,// 匹配文件路徑的正則表達式,一般咱們都是匹配文件類型後綴
exclude: /(node_modules|bower_components)/, // 過濾掉不須要處理的文件
use: { loader: 'babel-loader' } // 指定使用的 loader
},
{
test: /\.less/,
use: ExtractTextPlugin.extract({ // 使用插件抽離 css ,生成單獨的 css 文件
fallback: 'style-loader',
use: ['css-loader', 'less-loader']
})
},
{
test: /\.html$/,
use: [
{
loader: 'html-loader',
options: { // 壓縮 html
minimize: true
}
}
]
},
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'file-loader',
options: {
// 自定義配置,圖片壓縮、處理等
}
}
]
}
]
},
// 提供靜態服務
devServer:{
port: 9999,
headers: { // 添加頭部信息
"X-Custom-Foo": "bar"
},
proxy: { // 請求代理
"/api": {
target: "http://localhost:3000"
}
}
},
plugins: [
// 每次打包前清除 dist 下的文件
new CleanWebpackPlugin('dist'),
// 提取樣式,生成單獨文件
new ExtractTextPlugin("styles.css"),
// 生成新的 html 文件
new HtmlWebpackPlugin({
filename: 'index.html', // 若是文件名不是 index , 開發時要在 url 處添加文件名
template: path.resolve(__dirname + '/src/index.html'), // 注意路徑,
})
]
}
複製代碼
package.json (請注意版本號,由於版本更新會形成不可預期的錯誤)
{
"name": "webpack-share",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "webpack-dev-server --open --inline --mode development --progress",
"build": "webpack --mode production --progress"
},
"author": "",
"license": "ISC",
"devDependencies": {
"babel": "^6.23.0",
"babel-core": "^6.26.0",
"babel-loader": "^7.1.4",
"babel-preset-env": "^1.6.1",
"clean-webpack-plugin": "^0.1.19",
"css-loader": "^0.28.11",
"extract-text-webpack-plugin": "^3.0.2",
"file-loader": "^1.1.11",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^3.2.0",
"less": "^3.0.1",
"less-loader": "^4.1.0",
"path": "^0.12.7",
"style-loader": "^0.20.3",
"webpack": "^4.5.0",
"webpack-cli": "^2.0.14",
"webpack-dev-server": "^3.1.2"
}
}
複製代碼
這樣,一個簡單的前端開發環境就已經配置好了,這份配置文件解決了以前咱們所提出的問題:
一、構建咱們發佈須要的 HTML、CSS、JS 文件
- 使用 html-loader 、 html-webpack-plugin 處理 html 文件,引入處理後的 css , js 文件,使用 extract-text-webpack-plugin 抽離單獨的 css 文件(注意版本號,在 webpack 4 中須要下載 @next 版本)
二、使用 CSS 預處理器來編寫樣式
- 使用 less-loader、 css-loader 、style-loader 處理樣式文件
三、處理和壓縮圖片
- 使用 file-loader 處理圖片資源
四、使用 Babel 來支持 ES 新特性
- 使用 babel-loader 對 js 編譯
五、本地提供靜態服務以方便開發調試
- 使用 devServer 提供靜態服務,配置請求代理,避免產生跨域安全問題
若是在項目中引入 react ,咱們要作一下簡單修改:
{
test: /\.jsx?$/,// 匹配文件路徑的正則表達式,一般咱們都是匹配文件類型後綴
exclude: /(node_modules|bower_components)/, // 過濾掉不須要處理的文件
use: { // 指定使用的 loader
loader: 'babel-loader',
options: {
// presets: ['es2015','react'] webpack 3
presets: ['@babel/preset-react','@babel/preset-es2015'] // webpack 4
}
}
},
複製代碼
package.json :
"@babel/preset-es2015": "^7.0.0-beta.44",
"@babel/preset-react": "^7.0.0-beta.44",
複製代碼
若是要引入 antd , 在 less-loader 中還須要作一下修改:
{
test: /\.less/,
use: ExtractTextPlugin.extract({ // 使用插件抽離 css ,生成單獨的 css 文件
fallback: 'style-loader',
use: [
{
loader: 'css-loader'
},
{
loader: 'less-loader',
options: { // 引入 js
javascriptEnabled: true
}
}
]
})
}
複製代碼
這裏只作簡單介紹,更多詳情,請看官網
在 webpack 中,和模塊路徑解析相關的配置都在 resolve 字段下,咱們能夠經過配置 resolve 來提升自身開發的體驗,例如經常使用的 alias 別名設置,簡化了咱們引入文件的路徑。 首先咱們來了解一下在 webpack 中的解析規則:
一、若是是文件,直接加載
二、若是是文件夾,則查找文件夾下 package.json 文件
- 找到 package.json: 則通常狀況會對照 main 屬性,獲取文件路徑來解析,若是找不到 main 字段,通常狀況話會尋找文件夾下的 index.js
- 找不到 package.json : 會尋找 index.js
直接查找文件
由下自上查找 node_modules 中的模塊
alias 能夠爲一段路徑建立一個別名,使一些較爲經常使用的冗長路徑獲得簡化:
題外話:
path.join([path1][, path2][, ...])用於鏈接路徑。該方法的主要用途在於,會正確使用當前系統的路徑分隔符,Unix系統是/,Windows系統是\。
path.resolve([from ...], to) 將 to 參數解析爲絕對路徑。
resolve: {
alias: {
Js: path.resolve(__dirname + '/src/js'),
Less: path.resolve(__dirname, './src/css'), // 模糊匹配: 引用時,只要匹配到 Less 都會被替換
Css$: path.resolve(__dirname, './src/css/index.css') // 精確匹配:引用時,只能 improt 'Css'
}
},
複製代碼
這樣,咱們在引入 css 和 js 時,只須要在別名下查找相應文件就好:
// 設置別名前
import '../css/a.less';
// 設置別名後
import 'Less/a.less';
improt 'Css'
複製代碼
resolve: {
// 默認配置
// extensions: [".js", ".json"]
extensions: ['.js','.jsx','.less','.css']
},
複製代碼
設置補全擴展名數組,引用文件時,能夠不加後綴,wepack 會從數組中自動補全。
resolve: {
// 當目錄下有 package.json 文件時,默認查找字段
// 配置 target === "web" 或者 target === "webworker" 時 mainFields 默認值是:
mainFields: ['browser', 'module', 'main'],
// target 的值爲其餘時,mainFields 默認值爲:
mainFields: ["module", "main"],
// 當目錄下沒有 package.json 文件時,默認查找文件
mainFiles: ["index"],
modules: [
path.resolve(__dirname, 'my_modules'), //告訴 webpack 解析模塊時應該搜索的目錄,能夠自定義一些本身的模塊路徑。
'node_modules',
]
}
複製代碼
devtool: 'source-map',
複製代碼
此選項控制是否生成,以及如何生成 source map。在開發環境時使用,便於準肯定位代碼位置。
devServer:{
contentBase: path.resolve(__dirname, "dist"), // 未經 webpack 處理的靜態文件訪問路徑
port: 9999,
publicPath: '/', // 肯定應該從哪裏提供 bundle,而且此選項優先。建議將 devServer.publicPath 和 output.publicPath 的值保持一致。
overlay:{ //當有編譯錯誤或者警告的時候顯示一個全屏 overlay
errors:true,
warnings:true,
},
headers: { // 添加頭部信息
"X-Custom-Foo": "bar"
},
proxy: { // 請求代理
"/api": {
target: "http://localhost:3000",
}
},
},
複製代碼
基於開發環境和生產環境的需求差別,咱們通常須要使用兩套不一樣的配置文件。
首先,咱們來看一下開發環境和生產環境環境需求點的異同:
相同點
一、共同的入口
二、共同的代碼處理
三、一樣的解析配置
三、共同的出口
複製代碼
不一樣點
開發環境
一、模塊熱更新 // 提升開發效率
二、接口代理 // 方便接口調用
三、devtool // 準肯定位代碼位置
生產環境
一、提取公共代碼
二、壓縮混淆
三、去除無用代碼
四、文件壓縮 // 減少代碼體積
複製代碼
咱們發現,在 wenpack 4 中,mode 的兩個參數已經能很好地解決咱們大部分的需求,可是仍有些個性配置須要咱們手動建立。咱們須要根據不一樣的業務需求對配置文件進行拆分,而後利用 webpack-merge 對不一樣的配置文件進行合併。
一般狀況下,咱們會拆分出三個配置文件:
webpack.base.conf.js // 公共配置
webpack.prod.conf.js // 生產環境配置
webpack.dev.conf.js // 開發環境配置
複製代碼
你能夠把兩份差別配置引入公共配置,而後判斷傳入參數來決定使用那份配置:
webpack-dev-server --config ./webpack.base.conf.js --mode development/production 或 --env development/production
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin'); // 注意版本號 webpack 4 以上版本請下載 @next 版本
const merge = require('webpack-merge')
const webpack = require('webpack');
const path = require('path');
const prodConf = require('./webpack.prod.conf');
const devConf = require('./webpack.dev.conf');
module.exports = (env, argv) => {
console.log(env,'==================', argv.mode)
const baseConf = {
entry: {
index: path.resolve(__dirname, '../src/index.js'),
},
output: {
path: path.resolve(__dirname, '../dist'),
filename: 'js/[name].min.js'
},
····
}
const config = env === 'dev' ? devConf : prodConf;
return merge(baseConf,devConf)
}
複製代碼
也能夠將共同配置分別引入差別配置中,在啓動命令上指定所使用的配置文件:
webpack-dev-server --config 配置文件
複製代碼
略