Webpack 4 構建大型項目實踐 / 處理圖片、樣式和字體

本文所用示例的倉庫地址: gayhubjavascript

上文使用 HtmlWebpackPlugin 生成了一個 index.html 文件,而且插件自動把打包後的資源添加到 index.html 文件中,使咱們能夠打開 index.html 在瀏覽器看到 js 的執行效果。本節咱們將用 Webpack Loaders 來處理工做中會用到的其餘三種類型文件:圖片、樣式、字體。css

從這一節開始,因爲項目資源類型變得複雜,每一節的測試項目會放到 demo/ 下,再也不是文檔根目錄。html

Loaders

官網對 Loaders 的介紹很簡單,只有簡單三點:vue

  • 能夠用 Loaders 打包任何 Javascript 以外的任何靜態資源
  • 用 Node.js 編寫一個 Loader 很簡單
  • 激活 Loader 有兩種方式:
    • 在引入語句中添加 loaderName! , 好比 import 'style-loader!css-loader?modules!./css/test.css'
    • rules 中配置,見下文

處理圖片

file-loader

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

url-loader

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.

CSS

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.htmlhead 標籤中(在瀏覽器控制檯查看,插入前樣式文件在 JS 中)。

CSS 預處理器

因爲我是看黃軼講師的「高仿餓了麼」課程後,纔開始在項目中使用預處理器,因此會更喜歡 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 的路徑解析
            }
        }
    ]
}
複製代碼

PostCSS

幾年之前寫 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 前一步執行
  • 能夠在 Webpack 配置 JS 中配置 postcss-loader 的地方使用 options 來配置 PostCSS ,但更推薦在項目根目錄添加 postcss.config.js 配置文件,別人能更容易知道你使用了 PostCSS。

從 JS 分離出樣式文件

上文有提到 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 中引用他們,打包時使用 CopyWebpackPluginstatic / public 整個文件夾複製到 dist/

參考文檔

相關文章
相關標籤/搜索