鍍金池/ 問答/網(wǎng)絡(luò)安全  HTML/ webpack打包如何統(tǒng)一js和css中圖片資源路徑

webpack打包如何統(tǒng)一js和css中圖片資源路徑

在webpack打包項目時經(jīng)常要處理資源的路徑問題,而通常處理方案有以下幾種

  1. 不設(shè)置publicPath,生成基于頁面的相對路徑
  2. 設(shè)置publicPath,可設(shè)置相對路徑和絕對路徑
  3. 設(shè)置__webpack_public_path__,js中資源路徑使用該變量, css中資源未使用

項目路徑:
圖片描述

開發(fā)環(huán)境因為都是基于/根目錄所以怎么設(shè)置都OK,到了測試環(huán)境和生產(chǎn)環(huán)境路徑就無法做到適配了。

開發(fā)環(huán)境頁面地址:http://localhost:8080/index.html
開發(fā)環(huán)境資源路徑:http://localhost:8080/[js|css|img]

測試環(huán)境頁面地址:http://www.test.com/webapp/aaa/index.html
測試環(huán)境資源路徑:http://cdn.test.com/static/aaa/[js|css|img]

生產(chǎn)環(huán)境頁面地址:http://www.prod.com/webapp/aaa/index.html
生產(chǎn)環(huán)境資源路徑:http://cdn.prod.com/static/aaa/[js|css|img]

問題: 對于測試環(huán)境和生產(chǎn)環(huán)境只會打包一次,如何做到j(luò)s和css里面的img路徑能適配不同的環(huán)境呢?

解決該問題首先有幾個要點

1、頁面和資源的域名和路徑都不同,不能簡單的使用相對路徑
2、js中的相對路徑是針對當(dāng)前頁面,css中的相對路徑是針對當(dāng)前css文件
3、js可以定義資源路徑前綴變量,css無法使用
4、可以針對資源類型可以單獨設(shè)置publicPath

問題解決思路

1、js中的資源路徑用引入外部變量,
比如: var imgPath = window.staticPath; //window.staticPath由后臺向index.html注入
<img alt="" src="../assets/xx.png" />
改為<img alt="" :src="'${imgPath}/img/xx.png'" />

改成動態(tài)的src缺點就是webpack不能識別這個動態(tài)拼接的地址就無法把assets下的圖片打包的dist/img路徑下,當(dāng)然有個小技巧是兩個src都設(shè)置。

2、js中設(shè)置__webpack_public_path__變量
比如:__webpack_public_path__ = window.resourcePath; //window.resourcePath由后臺向index.html注入
js中img寫法不變<img alt="" src="../assets/xx.png" />

該方式的缺點css中的img url不能使用

3、webpack中配置images rule的publicpath,

{ 
  name: 'img/[name].[ext]',
  publicPath:'../',
  limit: 1024
}

因為publicPath優(yōu)先級會大與__webpack_public_path__
所以缺點是js中的img src同樣會用此publicpath,而js中的相對路徑是基于當(dāng)前頁面

4、后面翻file-loader源碼發(fā)現(xiàn)publicpath,其實可以定義為一個function,
所以有了一個很傻的辦法,動態(tài)設(shè)置publicpath

{ 
  name: 'img/[name].[ext]',
  publicPath: function(url){
    if(assetsUtil.useWebpackPath(url)){
      return `__webpack_public_path__ + ${JSON.stringify(url)}`
    }

    return '../'
  },
  limit: 1024
}

缺點就是需要維護(hù)哪些資源使用絕對路徑,哪些使用相對路徑

綜上,目前還沒有一個很有效便捷的方法解決該問題。希望有遇到該問題的朋友提點方案和建議。

回答
編輯回答
蟲児飛

目前項目應(yīng)用的是vue-cli,自行修改了部分配置.三個環(huán)境的情況跟你差不多,測試/生產(chǎn)環(huán)境的層級比你還深。
先說下修改了哪些配置
1-build/utils.js下的cssLoaders內(nèi)的generateLoaders方法內(nèi)部的

// Extract CSS when that option is specified
    // (which is the case during production build)
    if (options.extract) {
      return ExtractTextPlugin.extract({
        use: loaders,
        fallback: 'vue-style-loader',
        publicPath: '../../' //此處修改是矯正iview的font等文件夾打包路徑錯誤
      })
    } else {
      return ['vue-style-loader'].concat(loaders)
    }

2-webpack.base.conf.js下的module對象內(nèi)的rules針對圖片類型的配置

      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 1024,
          name: utils.assetsPath('img/[folder]/[name].[ext]')
          // [folder]/ 是為了保留項目組件文件夾內(nèi)部資源文件夾
          // 在打包后在img文件夾里面對應(yīng)生成相同的文件夾,方便維護(hù)
          // 另外取消了圖片的hash
        }
      },

3-config/index.js
dev的配置就不說了,改了端口,偶爾會修改下默認(rèn)啟動的lolocalhost用于移動調(diào)試
主要是build下的

assetsPublicPath: './',//改為./

目前這套配置運行良好.圖片那里的修改你可以照樣引用原本的cli配置.我這是根據(jù)項目需求變動的.
assetsPath如下

exports.assetsPath = function (_path) {
  const assetsSubDirectory = process.env.NODE_ENV === 'production'
    ? config.build.assetsSubDirectory
    : config.dev.assetsSubDirectory

  return path.posix.join(assetsSubDirectory, _path)
}
2017年7月28日 11:09