本文所用示例的倉庫地址: gayhubjavascript
上文使用 HtmlWebpackPlugin
生成了一個 index.html
文件,而且插件自動把打包後的資源添加到 index.html
文件中,使咱們能夠打開 index.html
在瀏覽器看到 js 的執行效果。本節咱們將用 Webpack Loaders 來處理工做中會用到的其餘三種類型文件:圖片、樣式、字體。css
從這一節開始,因爲項目資源類型變得複雜,每一節的測試項目會放到 demo/
下,再也不是文檔根目錄。html
官網對 Loaders 的介紹很簡單,只有簡單三點:vue
loaderName!
, 好比 import 'style-loader!css-loader?modules!./css/test.css'
rules
中配置,見下文yarn add file-loader
複製代碼
一般狀況下,咱們只須要把圖片複製到(打包)目標目錄,此時咱們使用 file-laoderjava
{
test: /\.(png|jpe?g|gif|webp)$/,
use: [
{
loader: 'file-loader',
options: {
// 文件命名
name: '[name].[ext]',
// 輸出路徑
outputPath: 'imgs/'
}
}
]
}
複製代碼
執行 webpack
命令後,咱們能夠看到圖片已經被打包到了 dist/imgs/
目錄下,而且命名未修改。webpack
yarn add url-loader
複製代碼
當咱們的圖片文件存在一些小標籤時,若是每一個小標籤都獨立請求,顯然是會形成帶寬浪費的,這不合規矩。這個時候咱們須要有相似雪碧圖同樣的方案,把多個小圖片整合爲一個請求。url-loader 就能夠作這樣的整合,但和雪碧圖不一樣的是,它是把大小小於限定值的圖片轉成 base64 編碼放到打包後的代碼中。ios
{
test: /\.(png|jpe?g|gif|webp)$/,
use: [
{
loader: 'url-loader',
options: {
// 文件命名
name: '[name].[ext]',
// 輸出路徑
outputPath: 'imgs/',
// 小於 10k 的圖片轉成 base64 編碼
limit: 10240
}
}
]
}
複製代碼
執行 webpack
命令後,咱們能夠看到只有 多啦A夢.jpg
圖片被打包到了 dist/imgs/
目錄下,其餘 5 個小圖被打包成了一串 base64 碼(在 dist/dist.js
中)。git
大於 10k 的圖github
/***/ "./src/imgs/多啦A夢.jpg":
/*!***************************!*\ !*** ./src/imgs/多啦A夢.jpg ***! \***************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
eval("module.exports = __webpack_require__.p + \"imgs/多啦A夢.jpg\";\n\n//# sourceURL=webpack:///./src/imgs/%E5%A4%9A%E5%95%A6A%E6%A2%A6.jpg?");
/***/ }),
複製代碼
小於 10k 的圖web
/***/ "./src/imgs/分享.png":
/*!*************************!*\ !*** ./src/imgs/分享.png ***! \*************************/
/*! no static exports found */
/***/ (function(module, exports) {
eval("module.exports = \"data:image/png;base64,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\"\n\n//# sourceURL=webpack:///./src/imgs/%E5%88%86%E4%BA%AB.png?");
/***/ })
複製代碼
若是咱們不使用 loader 來處理樣式,執行 webpack
能夠看到這樣的提示 You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file.
yarn add css-loader style-loader
複製代碼
css-loader
解析 CSS 文件style-loader
把樣式插入到 DOM 中loader 從右往左、從下往上執行
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
}
複製代碼
此時執行 webpack
就能正確打包了,但並不會再 dist/
下生成 .css
文件,而是把樣式以 style
標籤的形式插入到 index.html
的 head
標籤中(在瀏覽器控制檯查看,插入前樣式文件在 JS 中)。
因爲我是看黃軼講師的「高仿餓了麼」課程後,纔開始在項目中使用預處理器,因此會更喜歡 stylus ,本文的例子也使用 stylus 。
stylus-loader
默認項目中存在 stylus
依賴,因此安裝 stylus-loader
時不要忘記安裝 stylus
yarn add stylus stylus-loader css-loader style-loader
複製代碼
{
test: /\.styl(us)?$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1 // 在 css-loader 前執行的 loader 數量
}
},
{
loader: 'stylus-loader',
options: {
preferPathResolver: 'webpack' // 優先使用 webpack 用於路徑解析,找不到再使用 stylus-loader 的路徑解析
}
}
]
}
複製代碼
幾年之前寫 CSS 有個蛋疼的地方,某些屬性咱們須要爲不一樣瀏覽器加上不一樣的前綴,好比 Firefox 的 -moz-transform
和 IE 的 -ms-transform
,但有了 PostCSS 後你只須要寫無前綴的屬性,PostCSS 會根據 Can i use 的數據爲你的 CSS 屬性補充上前綴。
yarn add postcss-loader -D
複製代碼
{
test: /\.styl(us)?$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 2 // 在 css-loader 前執行的 loader 數量
}
},
'postcss-loader',
{
loader: 'stylus-loader',
options: {
preferPathResolver: 'webpack' // 優先使用 webpack 用於路徑解析,找不到再使用 stylus-loader 的路徑解析
}
}
]
}
複製代碼
PostCSS 配置文件 postcss.config.js
,配置自動補全(須要 autoprefixer
插件)
yarn add autoprefixer -D
複製代碼
postcss.config.js
module.exports = {
plugins: [
require('autoprefixer')
]
}
複製代碼
此時執行 webpack
命令,能夠在瀏覽器中看到 transform rotate(180deg)
被翻譯成 -webkit-transform: rotate(180deg); transform: rotate(180deg);
。
兩個注意點:
postcss-loader
的順序,在 css-loader
前一步執行postcss-loader
的地方使用 options 來配置 PostCSS ,但更推薦在項目根目錄添加 postcss.config.js
配置文件,別人能更容易知道你使用了 PostCSS。上文有提到 style-loader
把樣式插入到 html 文件,這樣作減小了請求數。但正常項目樣式文件會佔據不小的體積,要知道在插入 index.html
前咱們的樣式文件是儲存在 JS 文件中的,因此 JS 文件會很是大,而且咱們可能須要更清晰的生成物結構,因此也應當清楚如何把樣式從 js 中分離出來 —— 使用 MiniCssExtractPlugin。
yarn add mini-css-extract-plugin -D
複製代碼
把 style-loader
替換爲 MiniCssExtractPlugin Loader
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
module: {
rules: [
{
test: /\.styl(us)?$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../',
hmr: process.env.NODE_ENV === 'development',
reloadAll: true
},
},
{
loader: 'css-loader',
options: {
importLoaders: 2 // 在 css-loader 前執行的 loader 數量
}
},
'postcss-loader',
{
loader: 'stylus-loader',
options: {
preferPathResolver: 'webpack' // 優先使用 webpack 用於路徑解析,找不到再使用 stylus-loader 的路徑解析
}
}
]
}
],
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/[name].css',
chunkFilename: 'css/[name].css',
}),
]
};
複製代碼
執行 webpack
命令後能夠看到,在 dist/css
目錄下生成了 main.css
文件,而且該文件在 index.html
中引入了。
字體文件和圖片相似,只須要拷貝並放到 dist/fonts/
目錄下,仍然使用 file-loader / url-loader
。
{
test: /\.(woff2?|eot|ttf|otf|svg)(\?.*)?$/i,
use: {
loader: 'url-loader',
options: {
limit: 4096,
name: '[name]_[hash:5].[ext]',
outputPath: 'fonts/'
}
}
}
複製代碼
另外提一句,如今更流行使用 svg 來繪製圖標,繪製路徑存在 iconfong.js
中(阿里圖標庫下載舉例),此時切記不要把 iconfong.js
放在 src/
目錄,由於打包 iconfont.js
毫無心義,只是增長打包時長罷了。應當放到不用打包的靜態目錄,好比 vue-cli 2 的 static/
和 vue-cli 3 的 public/
,並在 html 中引用他們,打包時使用 CopyWebpackPlugin
把 static / public
整個文件夾複製到 dist/
。