webpack多頁應用架構系列(六):聽說webpack連圖片和字體也能打包?

本文首發(fā)于Array_Huang的技術博客——實用至上,非經作者同意,請勿轉載。
原文地址:https://segmentfault.com/a/1190000006907701
如果您對本系列文章感興趣,歡迎關注訂閱這里:https://segmentfault.com/blog/array_huang

前言

上一篇《聽說webpack連less/css也能打包?》說到使用loader來加載CSS,這一篇來講講如何籠統(tǒng)地加載其它類型的資源。為什么強調是“籠統(tǒng)”呢?這是因為本文介紹的方法并不針對任何類型的資源,這意味著,什么類型的資源都能用,但效果也都只是有限的。

用的什么loader呢?

本文介紹倆loader:file-loader和url-loader。

file-loader

file-loader的主要功能是:把源文件遷移到指定的目錄(可以簡單理解為從源文件目錄遷移到build目錄),并返回新文件的路徑(簡單拼接而成)。

file-loader需要傳入name參數(shù),該參數(shù)接受以下變量(以下討論的前提是:源文件src/public-resource/imgs/login-bg.jpg;在根目錄內執(zhí)行webpack命令,也就是當前的上下文環(huán)境與src目錄同級):

  • [ext]:文件的后綴名,示例為'jpg'。
  • [name]:文件名本身,示例為'login-bg'。
  • [path]:相對于當前執(zhí)行webpack命令的目錄的相對路徑(不含文件名本身),示例為'src/public-resource/imgs/'。這個參數(shù)我感覺用處不大,除非你想把遷移后的文件放回源文件的目錄或其子目錄里。
  • [hash]:源文件內容的hash,用于緩存解決方案。

我的做法是,require('!file-loader?name=static/images/[name].[ext]!../imgs/login-bg.jpg'),這樣login-bg.jpg的路徑就變成static/images/login-bg.jpg了,注意這還不是完整的路徑,最終還是要拼上webpack配置中的output.publicPath參數(shù)的;比如說我的output.publicPath參數(shù)是../../../../build/,那么最終從require()里獲得的完整路徑就會是../../../../build/static/images/login-bg.jpg了。

url-loader

url-loader的主要功能是:將源文件轉換成DataUrl(聲明文件mimetype的base64編碼)。據(jù)我所知,在前端范疇里,圖片和字體文件的DataUrl都是可以被瀏覽器所識別的,因此可以把圖片和字體都轉化成DataUrl收納在HTML/CSS/JS文件里,以減少HTTP連接數(shù)。

url-loader主要接受以下參數(shù):

  • limit參數(shù),數(shù)據(jù)類型為整型,表示目標文件的體積大于多少字節(jié)就換用file-loader來處理了,不填則永遠不會交給file-loader處理。例如require("url?limit=10000!./file.png");,表示如果目標文件大于10000字節(jié),就交給file-loader處理了。
  • mimetype參數(shù),前面說了,DataUrl是需要聲明文件的mimetype的,因此我們可以通過這個參數(shù)來強行設置mimetype,不填寫的話則默認從目標文件的后綴名進行判斷。例如require("url?mimetype=image/png!./file.jpg");,強行把jpg當png使哈。
  • 一切file-loader的參數(shù),這些參數(shù)會在啟用file-loader時傳參給file-loader,比如最重要的name參數(shù)。

實操演示

接下來還是用我的腳手架項目webpack-seed來介紹如何利用url-loader和file-loader來加載各類資源。

圖片

這一塊我是直接在webpack配置文件里設置的:

        {
          // 圖片加載器,雷同file-loader,更適合圖片,可以將較小的圖片轉成base64,減少http請求
          // 如下配置,將小于8192byte的圖片轉成base64碼
          test: /\.(png|jpg|gif)$/,
          loader: 'url-loader?limit=8192&name=./static/img/[hash].[ext]',
        },

由于使用了[hash],因此即便是不同頁面引用了相同名字但實際內容不同的圖片,也不會造成“覆蓋”的情況出現(xiàn);進一步講,如果不同頁面引用了在不同位置但實際內容相同的圖片,這還可以歸并成一張圖片,方便瀏覽器緩存呢。

字體文件

這一塊我也還是直接在webpack配置里配置的:

        {
          // 專供iconfont方案使用的,后面會帶一串時間戳,需要特別匹配到
          test: /\.(woff|woff2|svg|eot|ttf)\??.*$/,
          loader: 'file?name=./static/fonts/[name].[ext]',
        },

需要聲明的是,由于我使用的是阿里媽媽的iconfont方案,此方案加載字體文件的方式有一點點特殊,所以正則匹配的時候要注意一點,iconfont的CSS是這樣的,你們看看就明白了:

@font-face {font-family: "iconfont";
  src: url('iconfont.eot?t=1473142795'); /* IE9*/
  src: url('iconfont.eot?t=1473142795#iefix') format('embedded-opentype'), /* IE6-IE8 */
  url('iconfont.woff?t=1473142795') format('woff'), /* chrome, firefox */
  url('iconfont.ttf?t=1473142795') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
  url('iconfont.svg?t=1473142795#iconfont') format('svg'); /* iOS 4.1- */
}

其它資源

也許你會問,我們?yōu)槭裁催€需要轉移其它資源呢?直接引用不就可以了嗎?

我之前也是這么做的,直接引用源文件目錄src里的資源,比如說webuploader用到的swf文件,比如說用來兼容IE而又不需要打包的js文件。但是后來我發(fā)現(xiàn),這樣做的話,就導致部署上線的時候要把build目錄和src目錄同時放上去了;而且由于build目錄和src目錄同級,我就只能用build目錄和src目錄的上一級目錄作為網站的根目錄了(因為如果把build目錄設為網站,用戶就讀取不到src目錄了),反正就是各種的不方便。

那么,我是怎么做的呢?

我建了一個config文件,名為build-file.config.js,內容如下:

module.exports = {
  js: {
    xdomain: require('!file-loader?name=static/js/[name].[ext]!../../../vendor/ie-fix/xdomain.all.js'),
    html5shiv: require('!file-loader?name=static/js/[name].[ext]!../../../vendor/ie-fix/html5shiv.min.js'),
    respond: require('!file-loader?name=static/js/[name].[ext]!../../../vendor/ie-fix/respond.min.js'),
  },
  images: {
    'login-bg': require('!file-loader?name=static/images/[name].[ext]!../imgs/login-bg.jpg'),
  },
};

這個config文件起到兩個作用:

  1. 每次加載到這個config文件的時候,會執(zhí)行那些require()語句,對目標文件進行轉移(從src目錄到build目錄)。
  2. 調用目標文件的代碼段,可以從這個config文件取出目標文件轉移后的完整路徑,例如我在src/public-resource/components/header/html.ejs里是這么用的:
<!DOCTYPE html>
<html lang="zh-cmn-Hans">
<head>
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <title><% if (pageTitle) { %> <%= pageTitle %> - <% } %> XXXX后臺</title>
  <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1" /> 
  <meta name="renderer" content="webkit" />

  <!--[if lt IE 10]>
    <script src="<%= BUILD_FILE.js.xdomain %>" slave="<%= SERVER_API_URL %>cors-proxy.html"></script>
    <script src="<%= BUILD_FILE.js.html5shiv %>"></script>
  <![endif]-->
</head>
<body>
  <!--[if lt IE 9]>
    <script src="<%= BUILD_FILE.js.respond %>"></script>
  <![endif]-->

恩,你可能會好奇這HTML里怎么能直接引用js的值,哈哈哈,超綱了超綱了,這是我后面要講到的內容了。

示例代碼

諸位看本系列文章,搭配我在Github上的腳手架項目食用更佳哦(笑):Array-Huang/webpack-seed(https://github.com/Array-Huang/webpack-seed)。

附系列文章目錄(同步更新)

本文首發(fā)于Array_Huang的技術博客——實用至上,非經作者同意,請勿轉載。
原文地址:https://segmentfault.com/a/1190000006907701
如果您對本系列文章感興趣,歡迎關注訂閱這里:https://segmentfault.com/blog/array_huang

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容