一、版本
當前 webpack 版本 : v4.18.0
webpack -v
// 4.18.0
同之前的版本不一樣的地方是需要 全局安裝 webpack-cli
webpack-cli -v
// 3.1.0
思考這個 webpack-cli 是真的有用么? 其實對於我來講感覺很雞肋,雖然它是出現是為了讓我webpack 零配置化,但就目前 webpack-cli 的體驗來講,還是比較雞肋,在實際的開發過程中,我還是比較喜歡 diy ,這樣自由的折騰方式, 零配置,就意味着你要為 高度定制化作出犧牲。
這讓我想起了之前面試很多前端開發的時候,其實就是一個很簡單的問題,如何搭建一個最簡單的 webpack 的開發架構,JS 壓縮一下, LESS 預編譯一下, CSS 壓縮一下。這類,很多習慣了用 vue-cli 的同學就懵逼了,因為他們認為 架構就是用別人的東西,但實際的開發中,出於業務需求的需要,我們的架構需要更加多的靈活性和高度可定制化性。 所以這才是寫這篇文章的 出發點。
二、webpack 的主體概念
開局一張圖:
本質上,webpack
是一個現代 JavaScript 應用程序的靜態模塊打包器
(static module bundler)。在 webpack 處理應用程序時,它會在內部創建一個依賴圖(dependency graph),用於映射到項目需要的每個模塊,然后將所有這些依賴生成到一個或多個bundle。
在開始前我們需要先理解它的
核心概念
:
- 入口(entry)
- 輸出(output)
- loader
- 插件(plugins)
2-1、入口
入口起點(entry point)
這里是一切開始的起點。面對實際的業務來講的話,可以分為單頁面( SPA ) 和多頁面。那么今天就針對這2種情況來分別 介紹下 利用 webpack 進行項目架構的需要注意的地方。
2-1-1、單頁面入口
2-1-1-1、實現的寫法:
webpack.config.js
module.exports = {
entry: './app.js'
}
2-1-1-2、同樣也可以通過對象語法來解決不同場景的問題:
webpack.config.js
module.exports = {
entry: {
app: './app.js',
vendors: './src/JQ.js'
}
}
2-1-2、多頁面應用的入口
webpack.config.js
module.exports = {
entry: {
pageOne: './src/pageOne/index.js',
pageTwo: './src/pageTwo/index.js',
pageThree: './src/pageThree/index.js'
}
};
但是這里只是人工的去配置了多頁面,其實很明顯這種做法很不聰明。
所以你需要一個聰明的做法,這里就大致講一下思路。 通過
( ' ./src/**/*.js' ) 匹配到 多頁面到文件入口路徑,然后 通過 glob.sync(globPath)
獲取到全部路徑,拿到每個頁面的 入口文件路徑。 最后傳值給 webpack 的 entry 對象。
2-2、輸出
2-2-1、單頁面 輸出
webpack.config.js
module.exports = {
output: {
filename: 'bundle.js',
path: '/home/proj/public/assets'
}
};
2-2-2、多頁面 輸出
webpack.config.js
module.exports = {
output: {
filename: '[name].js',
path: __dirname + '/dist'
}
};
2-3、loader
這里的 loader 就像一個又一個的加工廠一樣,把你輸送給 加工產的原材料加工生成你想要的成品或者半成品。最后出廠~
有用過 gulp 類似的構建工具等同學 就很 容易理解,這里的一個個的 loader 就想當一一個個的 task, 這個任務完成就會交給下一個人,直到整個流水線工作跑完~
在更高層面,在 webpack 的配置中 loader 有兩個特征(demo):
webpack.config.js
const path = require('path');
module.exports = {
output: {
filename: 'my-first-webpack.bundle.js'
},
module: {
rules: [
{ test: /\.txt$/, use: 'raw-loader' }
]
}
}
其中有三個需要注意的地方:
1、loader 的特征之一: test
屬性,用於標識出應該被對應的 loader 進行轉換的某個或某些文件。
2、loader 的特征之二: use
屬性,表示進行轉換時,應該使用哪個 loader。
3、在 webpack 配置中定義 loader 時,要定義在 module.rules
中,而不是 rules
2-3-1、如何編寫一個 loader
前期這里也只是大概的了解一下,在后面的文章中,我們會手把手的教你 手寫一個 loader
這篇文章還只是教你如何使用 webpack。 敬請期待后面的文章吧 😁
2-4、plugins
插件是 webpack 的支柱
功能。webpack 自身也是構建於,你在 webpack 配置中用到的相同的插件系統之上!
插件目的在於解決 loader 無法實現
的其他事。
webpack.config.js
module.exports = {
entry: './path/to/my/entry/file.js',
output: {
filename: 'my-first-webpack.bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: 'babel-loader'
}
]
},
plugins: [
new HtmlWebpackPlugin({template: './src/index.html'})
]
}
2-4-1、如何編寫一個plugins
一樣的,前期這里也只是大概的了解一下,在后面的文章中,我們會手把手的教你 手寫一個 plugins
這篇文章還只是教你如何使用 webpack。 敬請期待后面的文章吧 😁
三、如何使用
在上面的文章中,我們已經大致介紹了 webpack 的概念,下面就是需要我們來配置一個 可以實際使用的項目。
3-1 關於 resolve 解析的相關的疑問
3-1-1 resolve.alias
創建 import 或 require 的別名,來確保模塊引入變得更簡單。例如,一些位於 src/ 文件夾下的常用模塊:
module.exports = {
//...
resolve: {
alias: {
'vue$': 'vue/dist/vue.common.js',
'src': path.resolve(__dirname, './src/src/'),
'assets': path.resolve(__dirname, './src/assets/'),
'components': path.resolve(__dirname, '../src/components')
}
}
};
有了上面的配置后,在項目文件中如果需要引用 components 文件夾下面的某個組件的時候 就可以 直接 如下的引用方式:
import Alert from 'component/alert'
這樣就可以 忽略因為項目文件過深而引起的 引用組件路徑出錯的問題,從而加快效率。
3-1-2 resolve.extensions
自動解析確定的擴展。默認值為:
module.exports = {
//...
resolve: {
extensions: ['.wasm', '.mjs', '.js', '.json']
}
};
這樣的話,就會幫你把未加上 后綴名的文件自動加上配置后綴,從而加快開發效率。
當然也是按照你所給出的文件路徑去匹配的后綴,而不是隨意加上后綴名。
關於 resolve 解析 的內容還有很多,大家可以參考 webpack 官方文檔去尋找自己需要的內容,讓自己開發項目的速度變得更加快捷方便。
4-1 優化(optimization)
在 4.0 以后的 webpack 版本,他們專門把 optimization 提取出來作為一個大的模塊來進行了優化,因為這個功能實在是太能有效的提升項目的加載速度了。為什么會這么說呢?下面我們就來了解了解~
我們先來看一個簡單的配置:
module.exports = {
//...
optimization: {
minimize: false
}
};
4-1-1 optimization.minimize
這個屬性是一個 布爾類型,是告訴 webpack 我們是否在當前環境下去壓縮混淆我們的 JS 代碼。
當然 需要配合這個屬性來使用的還有一個 插件
主要注意: UglifyjsWebpackPlugin
4-1-2 optimization.splitChunks
這個屬性是在 webpack 4.0 + 才提供的。用來 分離切割 體積較大的 JS 文件。
然后 webpack 會自動將 通用的 chunk 進行分割,從而最大限度的做到 復用
,從而減少 main chunk 的體積。
5-1 插件(plugins)
plugins
選項用於以各種方式自定義 webpack 構建過程。webpack 附帶了各種內置插件,可以通過webpack.[plugin-name]
訪問這些插件。
webpack 插件列表。例如,當多個 bundle 共享一些相同的依賴,CommonsChunkPlugin 有助於提取這些依賴到共享的 bundle 中,來避免重復打包。這里還是舉例說明:
module.exports = {
//...
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
filename: 'vendor-[hash].min.js',
})
]
};
這里 CommonsChunkPlugin 就會告訴 webpack 讓它把 多個 bundle 共享一些相同的依賴,抽離出來,形成一個單獨的 bundle 從而避免重復打包而帶來的性能損耗。
6-1 開發中 server (devServer)
這里的重要部分就是 webpack-dev-server 這個插件了。
webpack-dev-server 創建當前本地開發的node環境,從而才能有上面種種 webpack 對於文件的操作權限,才能為所欲為,這個是基本。我們還是來一個最簡單的 demo。
module.exports = {
//...
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true,
port: 9000
}
};
這里面也有非常多的 屬性配置,基本滿足了我們開發中遇到的大多數的問題。
四、總結
基本上完成了上面文章中介紹到的內容,我們就已經可以完成基本的 webpack 配置的功能了, 注意: 這里說到的是 基本的 webpack 的配置工作,那么在我們的實際的項目開發中,我們會遇到的問題和需要我們通過webpack 來解決的問題非常之多。
因為我們需要結合一系列的框架來完成我們的前端開發的工作,React、Vue、Angular、JQ,Backbone 等等等。 這系列的框架 風格各異,但是又萬變不離其宗,核心需要注意的地方就那么多,下一篇文章就會 講到一個 現代 前端開發 需要注意的一個重要 插件。
Babel
。
關於 webpack 入門的文章就介紹到這里了,歡迎一起來論道~
GitHub 地址:(歡迎 star 、歡迎推薦 : )