webpack一直是前端工程師的痛點,由於他的複雜、分散、loader、plugin這些第三方,讓咱們的學習成本陡然上升,使咱們一直對他的配置模棱兩可,今天帶你們完全明白他如何配置,擺脫困擾咱們好久的痛點。本篇主要是webpack基礎配置詳解,關於webpack的模塊chunk、編譯階段流程、輸出階段流程、loader的編寫和手寫plugin會在後續文章推出,爲了不錯過能夠關注我或者收藏個人我的博客www.ngaiwe.comcss
WebPack能夠看作是模塊打包機:它作的事情是,分析你的項目結構,找到JavaScript模塊以及其它的一些瀏覽器不能直接運行的拓展語言(Scss,TypeScript等),並將其打包爲合適的格式以供瀏覽器使用。而且跟具你的在項目中的各類需求,實現自動化處理,解放咱們的生產力html
mkdir webpack-start
cd webpack-start
npm init
複製代碼
Webpack 啓動後會從
Entry
裏配置的Module
開始遞歸解析 Entry 依賴的全部 Module。 每找到一個 Module, 就會根據配置的Loader
去找出對應的轉換規則,對 Module 進行轉換後,再解析出當前 Module 依賴的 Module。 這些模塊會以 Entry 爲單位進行分組,一個 Entry 和其全部依賴的 Module 被分到一個組也就是一個Chunk
。最後 Webpack 會把全部 Chunk 轉換成文件輸出。 在整個流程中 Webpack 會在恰當的時機執行 Plugin 裏定義的邏輯。前端
context用來解決配置文件和入口文件再也不同一層結構,列如咱們配置文件在config,入口文件在根目錄,則以下配置node
module.exports = {
context: path.join(__dirname, '..'), // 找到根目錄
entry: './main.js' //根目錄下的入口文件
}
複製代碼
最簡單的單頁面(SPA)Entry入口,將main.js引入,並根據main.js中引用和依賴的模塊開始解析react
module.exports = {
entry: './main.js'
}
複製代碼
多頁面(MPA)Entry入口,將多個文件引入,固然通常是讀取指定文件夾內的入口文件,而後引入jquery
entry: {
home: "./home.js",
about: "./about.js",
contact: "./contact.js"
}
複製代碼
若是是單頁面(傳入的是字符串或字符串數組),則chunk會被命名爲main,若是是多頁面(傳入一個對象),則每一個鍵(key)會是chunk的名稱,描述了chunk的入口起點webpack
Object 指示webpack如何去輸出,以及在哪裏輸出你的bundle、asset 和其餘你所打包或使用 webpack 載入的任何內容web
path:輸出目錄對應一個絕對路徑正則表達式
path: path.resolve(__dirname, 'dist')
複製代碼
pathinfo:boolean 默認false做用是告訴webpack在bundle中引入所包含模塊信息的相關注釋,不該用於生產環境(production),對開發環境(development)極其有用npm
publicPath:主要做用是針對打包後的文件裏面的靜態文件路徑處理
filename:定義每一個輸出bundle的名稱,這些bundle將寫入output.path選項指定的目錄下,對於單入口Entry,filename是一個靜態名稱
filename: "bundle.js"
複製代碼
可是在webpack中咱們會用到代碼拆分、各類插件plugin或多入口Entry建立多個bundle,這樣咱們就應該給每一個bundle一個惟一的名稱
filename: "[name].bundle.js"
複製代碼
使用內部chunk id
filename: "[id].bundle.js"
複製代碼
惟一hash生成
filename: "[name].[hash].bundle.js"
複製代碼
使用基於每一個 chunk 內容的 hash
filename: "[chunkhash].bundle.js"
複製代碼
處理項目中應用的不一樣模塊,主要配置皆在Rules中,匹配到請求的規則數組,這些規則可以對模塊應用loader,或者修改解析器parser
Module.noParse: 防止webpack解析的時候,將規則匹配成功的文件進行解析和忽略大型的library來對性能的優化,在被忽略的文件中不該該含有import、require和define的調用
module.exports = {
module: {
rules: [],
noParse: function(content) {
return /jquery|lodash/.test(content) // 忽略jquery文件解析,直接編譯打包
}
}
}
複製代碼
Rules:建立模塊時,匹配請求的規則數組
Rule條件:resource(請求文件的絕對路徑)、issuer(被請求資源的模塊文件的絕對路徑,導入時的位置),好比一個文件A導入文件B,resource是/B,issuer是/A是導入文件時的位置,而不是真正的位置,在規則中,test/include/exclude/resource對resource匹配,而issuer只對issuer匹配
Test/include/exclude/resource/issuer的用法和區別
module.exports = {
modules: {
rules: [
{
test: /\.js?$/,
include: [
path.resolve(__dirname, "app")
],
exclude: [
path.resolve(__dirname, "app/demo")
],
resource:{
test: /\.js?$/,
include: path.resolve(__dirname, "app"),
exclude: path.resolve(__dirname, "app/demo")
},
issuer: {
test: /\.js?$/,
include: path.resolve(__dirname, "app"),
exclude: path.resolve(__dirname, "app/demo")
}
}
]
}
}
複製代碼
test:通常是提供一個正則表達式或正則表達式的數組,絕對路徑符合這個正則的則意味着知足這個條件
include:是一個字符串或者字符串數組,指定目錄中的文件須要走這個規則
exclude:一樣是一個字符串或者字符串數組,指定目錄中的文件不須要走這個規則
resource:就是對text/include/exclude的一個對象包裝,和他們單獨寫沒有區別
issuer:和resource有殊途同歸的做用,不過區別在於它是將這個rule應用於哪一個文件以及這個文件所導入的全部依賴文件
resourceQuery:和resource用法同樣,不過針對的是匹配結果'?'後面的路徑參數,能夠調用resource中的text等
oneOf:表示對該資源只應用第一個匹配的規則,通常結合resourceQuery
{
test: /\.(png|jpe?g|gif|svg)$/,
oneOf: [
{
resourceQuery: /inline/,
loader: 'url-loader'
},
{
loader: 'file-loader'
}
]
}
複製代碼
useEntry:object包含着每個loader而且對應loader的配置文件
{
loader: "css-loader",
options: {
modules: true
}
}
複製代碼
options會傳入loader,能夠理解爲loader的選項
use:是對useEntry的集合,而且對每個入口指定使用一個loader
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1
}
},
{
loader: 'less-loader',
options: {
noIeCompat: true
}
}
]
複製代碼
主要用來模塊如何被解析,給webpack提供默認值
alias:object主要用來讓import和require調用更方便,設置初始路徑
module.exports = {
alias: {
Utilities: path.resolve(__dirname, 'src/utilities/'),
Templates: path.resolve(__dirname, 'src/templates/')
}
}
// 最開始的import
import Utility from '../../utilities/utility';
// 配置完之後
import Utility from 'Utilities/utility';
複製代碼
enforceExtension:Boolean 默認false,表示引用不須要擴展名,爲true時,import、require中引用必須加擴展名
extensions:Array 自動解析不須要擴展名
extensions: [".js", ".json"] // .js、.json引入不須要擴展名
複製代碼
modules:Array webpack解析模塊的時候須要搜索的目錄,通常用於優先搜索和非node_modules文件中的自定義模塊
modules: [path.resolve(__dirname, "src"), "node_modules"] //優先搜索src目錄
複製代碼
經過使用不一樣的Loader,Webpack能夠要把不一樣的文件都轉成JS文件,好比CSS、ES6/七、JSX等,通常用於module的use中
module: {
rules:[
{
test:/\.css$/,
use:['style-loader','css-loader'],
include:path.join(__dirname,'./src'),
exclude:/node_modules/
}
]
}
複製代碼
具體相關loader須要查看你要引入的loader官方文檔API,手寫Loader會在下一篇文章具體介紹
Array 擴展webpack,在webpack構建流程中的特定時機注入擴展邏輯來改變構建結果和想要作的事情,具體使用查看你引入的plugin官方文檔,手寫plugin會在後續文章中推出
開發中的server,webpack-dev-server能夠快速搭建起本地服務,具體使用查看 webpack-dev-server
此選項控制是否生成,以及如何生成,官方推薦 SourceMapDevToolPlugin 和 source-map-loader 建議看官方文檔 Devtool 主要用來控制打包品質和在dev環境的調試便捷度和編譯的快慢
webpack 能夠監聽文件變化,當它們修改後會從新編譯和 HotModuleReplacementPlugin 有類似之處,監聽文件變更熱啓動
webpack安裝命令
npm install webpack webpack-cli -D
複製代碼
Webpack.config.js
具體用到的plugin插件
const path = require('path');
const webpack = require('webpack');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin')
// npm i extract-text-webpack-plugin@next // @next能夠安裝下一個非正式版本
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin');
let cssExtract = new ExtractTextWebpackPlugin({
filename: 'css/css.css',
allChunks: true
});
let lessExtract = new ExtractTextWebpackPlugin('css/less.css');
let sassExtract = new ExtractTextWebpackPlugin('css/sass.css');
/**
* 有些時候咱們但願把頁面中的CSS文件單獨拉出來保存加載
* extract-text-webpack-plugin
*/
//let pages = ['index', 'base'];
// pages = pages.map(page => new HtmlWebpackPlugin({
// template: './src/index.html',//指定產的HTML模板
// filename: `${page}.html`,//產出的HTML文件名
// title: `${page}`,
// chunks: ['common', `${page}`],//在產出的HTML文件裏引入哪些代碼塊
// hash: true,// 會在引入的js里加入查詢字符串避免緩存,
// minify: {
// removeAttributeQuotes: true
// }
// }));
module.exports = {
//先找到每一個入口(Entry),而後從各個入口分別出發,找到依賴的模塊(Module),
//而後生成一個Chunk(代碼塊),最後會把Chunk寫到文件系統中(Assets)
entry: './src/main.js',
output: {
path: path.join(__dirname, 'dist'),//輸出的文件夾,只能是絕對路徑
//name是entry名字main,hash根據打包後的文件內容計算出來的一個hash值
filename: '[name].[hash].js' //打包後的文件名
},
resolve: {
//引入模塊的時候,能夠不用擴展名
extensions: [".js", ".less", ".json"],
alias: {//別名
"bootstrap": "bootstrap/dist/css/bootstrap.css"
}
},
//表示監控源文件的變化,當源文件發生改變後,則從新打包
watch: false,
watchOptions: {
ignored: /node_modules/,
poll: 1000,//每秒鐘詢問的次數
aggregateTimeout: 500//
},
//devtool: 'source-map',//單獨文件,能夠定位到哪一列出錯了
// devtool: 'cheap-module-source-map',//單獨文件,體積更小,但只能定位到哪一行出錯
// devtool: 'eval-source-map',//不會生成單獨文件,
// devtool: 'cheap-module-eval-source-map',//不會生成單獨文件 只定位到行,體積更小
/*
loader有三種寫法
use
loader
use+loader
* */
module: {
rules: [
{
test: require.resolve('jquery'),
use: {
loader: 'expose-loader',
options: '$'
}
},
{
test: /\.js/,
use: {
loader: 'babel-loader',
query: {
presets: ["env", "stage-0", "react"]
}
}
},
{
//file-loader是解析圖片地址,把圖片從源位置拷貝到目標位置而且修改原引用地址
//能夠處理任意的二進制,bootstrap 裏字體
//url-loader能夠在文件比較小的時候,直接變成base64字符串內嵌到頁面中
test: /\.(png|jpg|gif|svg|bmp|eot|woff|woff2|ttf)/,
loader: {
loader: 'url-loader',
options: {
limit: 5 * 1024,
//指定拷貝文件的輸出目錄
outputPath: 'images/'
}
}
},
{
test: /\.css$/,//轉換文件的匹配正則
//css-loader用來解析處理CSS文件中的url路徑,要把CSS文件變成一個模塊
//style-loader 能夠把CSS文件變成style標籤插入head中
//多個loader是有順序要求的,從右往左寫,由於轉換的時候是從右往左轉換
//此插件先用css-loader處理一下css文件
//若是壓縮
loader: cssExtract.extract({
use: ["css-loader?minimize"]
})
//loader: ["style-loader", "css-loader", "postcss-loader"]
},
{
test: /\.less$/,
loader: lessExtract.extract({
use: ["css-loader?minimize", "less-loader"]
})
//use: ["style-loader", "css-loader", "less-loader"]
},
{
test: /\.scss$/,
loader: sassExtract.extract({
use: ["css-loader?minimize", "sass-loader"]
})
// use: ["style-loader", "css-loader", "sass-loader"]
},
{
test: /\.(html|htm)/,
loader: 'html-withimg-loader'
}
]
},
plugins: [
//用來自動向模塊內部注入變量
// new webpack.ProvidePlugin({
// $: 'jquery'
// }),
new UglifyjsWebpackPlugin(),
new CleanWebpackPlugin([path.join(__dirname, 'dist')]),
//此插件能夠自動產出html文件
new HtmlWebpackPlugin({
template: './src/index.html',//指定產的HTML模板
filename: `index.html`,//產出的HTML文件名
title: 'index',
hash: true,// 會在引入的js里加入查詢字符串避免緩存,
minify: {
removeAttributeQuotes: true
}
}),
new CopyWebpackPlugin([{
from: path.join(__dirname, 'public'),
to: path.join(__dirname, 'dist', 'public')
}]),
cssExtract,
lessExtract,
sassExtract
],
//配置此靜態文件服務器,能夠用來預覽打包後項目
devServer: {
contentBase: './dist',
host: 'localhost',
port: 8000,
compress: true,//服務器返回給瀏覽器的時候是否啓動gzip壓縮
}
}
複製代碼
本篇偏向基礎,可以搭建起簡單的webpack配置,高級進階會在後續文章推出,而且但願你們多去看官方API而後自我總結輸出,只有將知識輸出出來,才能更好的記憶和學習
有任何問題可留言或者發送本人郵箱ngaiwe@126.com