Webpack--理解“publicPath”的奧秘(翻譯)

原文:Webpack — Understanding the ‘publicPath’ mystery

你曾多少次被webapck's publicPath的配置絆倒?老實說妄均,在每次開始一個新項目的時候,我總是遇到這個問題境肾,并且花費很長時間去探索它到底是怎么工作的徽千。我閱讀了官方文檔,但并沒有什么用珍手。
所以办铡,這里我決定根據(jù)我的經(jīng)驗和理解去揭開publicPath的神秘面紗。如果對你有幫助琳要,歡迎反饋意見寡具。

當你的publicPath配置錯誤時,通常會遇到這2個問題:

  1. webpack-dev-server: live-reload(瀏覽器自動刷新)機制沒有正常執(zhí)行稚补,比如說童叠,瀏覽器不會自動重新加載,或者加載的代碼不是最新的课幕。
  2. 生成的css文件厦坛,圖片、字體路徑發(fā)生報錯乍惊,打斷編譯打包的過程杜秸。

讓我們來從一個基礎的配置去分析這件事。我們有一個文件結構润绎,如下顯示:

appMain [Project Folder]
|-- src
     |-- index.js
|-- index.html
|-- webpack.config.js
|-- package.json
|-- dist
// 極簡配置的webpack
module.exports = {
  entry: './src/index.js',
  output: {
    filename: './dist/bundle.js'
  }
};
// index.html中引入生成的bundle.js
<script src="./dist/bundle.js"></script>

如果我們只運行 webpack命令撬碟,會默認執(zhí)行webpack.config.js, 生產(chǎn)打包文件到 dist 文件夾下。

此外莉撇,如果你使用了 webpack-dev-server啟動呢蛤,live-reload就開始生效了,即是棍郎,任何在js源文件 [index.js] 中的修改都會立即在瀏覽器中生效其障,不需要手動刷新。
我們可以通過console.log()打印一些消息來測試這個功能涂佃。

注意:webpack-dev-server 啟動的服務励翼,使用的并不是真實生成的包文件蜈敢,它只是監(jiān)聽你的源代碼,當它們發(fā)生變化時去重新編譯抚笔。這個修改的包是直接從內存中讀取的扶认。??

現(xiàn)在讓我們加入配置path到webpack output 對象中,來代替在output.filename中使用完整路徑的配置殊橙。

const resolve = require('path').resolve;

module.exports = {
  entry: './src/index.js',
  output: {
    // seperated path and filename of generated output
    path: resolve('dist'),
    filename: 'bundle.js'
  }
};

請注意output.path需要使用絕對路徑而不是相對路徑辐宾,否則webpack會報錯。所以膨蛮,我們使用了path模塊的resolve方法叠纹。

報錯信息: Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema. \- configuration.output.path: The provided value "./dist" is not an absolute path!

在這種情況下,webpack會生成錯誤的輸出敞葛,比如有bundle.js文件誉察,但webpack-dev-serverlive-reload會突然停止執(zhí)行。并且惹谐,關于源文件[index.js]的任何修改持偏,無論怎么刷新瀏覽器都無法顯示,盡管終端顯示源文件已經(jīng)編譯成功氨肌。

現(xiàn)在鸿秆,如果你停止你的webpack-dev-server 服務,再次執(zhí)行webpack命令怎囚,然后再重新啟動 webpack-dev-server卿叽,修改的自動更新又正常了,但是我們不能每次都這樣做吧恳守,真的神煩考婴。??

所以,是哪個環(huán)節(jié)出錯了催烘?

主要是因為當path的未配置時沥阱,webpack-dev-config 會把它的值默認為項目的根目錄,即 ./

const resolve = require('path').resolve;

module.exports = {
  entry: './src/index.js',
  output: {
    // 如果path未配置颗圣,默認值是 './'
    path: resolve('./'),
    filename: './dist/bundle.js'
  }
};

所以喳钟,可以正常工作。
但當我們配置為真實的路徑在岂,比如reslove('dist'), webpack仍然在./位置編譯生成輸出文件。
你可以直接在瀏覽器中訪問服務的URL地址驗證這一點

http://localhost:8080/dist/bundle.js
// 總是指向我們運行webpack命令時生成的舊代碼
http://localhost:8080/bundle.js
// 總是指向最新編譯后的代碼蛮寂,在src變化后會立即重新加載
注意:這兩個打包的文件并不是完全相同的蔽午,后者因為使用dev-server會注入一些額外的代碼

所以,這里live-reload舊代碼導致的問題是酬蹋,我們使用了前者打包的 bundle.js及老,卻在index.html使用的是 webpack 命令生成的路徑抽莱。
任何代碼的改變,webpack-dev-server 會生成一個包骄恶,但地址是不同的食铐。

解決這個問題,只需要改變一下index.html中的script:src屬性僧鲁,一切又能正常運行了虐呻。
神速!我們理解并修復了這個問題寞秃。

進一步來說斟叼,我們使用 webpack 的publicPath去配置 webpack-dev-server 生成的打包文件的位置,是個虛擬位置, 而不是真實的文件系統(tǒng)春寿。
這個虛擬位置可以用來在 index.html 中定位引入生成的文件朗涩。

const resolve = require('path').resolve;

module.exports = {
  entry: './src/index.js',
  output: {
    path: resolve('dist'),
    filename: 'bundle.js',
    // Add vitual path for generating the bundle files
    publicPath: 'some-virtual-location'
  }
};
// 更新script:src到新的虛擬位置(Virtual-Path)
<script src="./some-virtual-location/bundle.js"></script>

這樣,我們就可以在本地開發(fā)中模擬真實服務器部署環(huán)境或者CDN绑改。
一些開發(fā)者更喜歡命名為 assets, public, dist, / 等等谢床,這完全看你喜歡如何維護生成的文件結構和命名方式。
底線就是厘线,index.html 中引入的script:src的值必須與 publicPath 的配置保持一致识腿。

publicPath對CSS的其他影響 -- 圖片、字體的路徑等等

在生成最終的styles時皆的,webpack默認會把 publicPath的配置添加到 圖片的URL覆履,字體的路徑上。
示例费薄,我添加2個文件到當前的項目中:

appMain
|-- src
     |-- index.js
     |-- main.css [Source CSS/SCSS file]
     |-- background-image.jpg
|-- index.html
|-- webpack.config.js
|-- package.json
|-- dist

main.css (使用相對路徑引入背景圖片)

.main {
    background-image: url("background.jpg");
}

我們使用了 css/scss 文件和圖片硝全,所以也要更新webpack.config配置,添加相應的 loaders 或 plugin楞抡。
webpack.config.js

const resolve = require('path').resolve;
const ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    path: resolve('dist'),
    filename: 'bundle.js',
    publicPath: 'some-virtual-location/'
  },
  // 添加 CSS 和 Style Loader
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: 'css-loader'
        })
      },
      {
        test: /\.(png|jpg|gif)$/,
        use: [
          {
            loader: 'file-loader',
            options: {
              name: '[name].[ext]'
            }
          }
        ]
      }
    ]
  },
  // 生成單獨的樣式文件
  plugins: [
    new ExtractTextPlugin('styles.css')
  ]
};

當你運行webpack命令時伟众,會觸發(fā)下面行為:

  1. background-image.jpg 文件會被 file-loader拷貝到dist文件夾中。
  2. styles.css會被插件 ExtractTextPlugin 根據(jù)main.css生成到dist文件夾中召廷。
  3. 生成的css文件中background-image: url會被自動添加publicPath的配置凳厢。
.main {
    background-image: url(some-virtual-location/background.jpg);
}

這個規(guī)則同樣適用于其他的靜態(tài)資源,比如fonts.
所以正確的配置publicPath非常重要竞慢,Webpack 的 Loaders 和 Plugins 會使用這個配置先紫。

希望這篇文章能讓你深入的理解神秘的publicPath是怎么工作的,怎樣正確的使用它筹煮。

歡迎在評論區(qū)寫下你的想法和意見遮精,我們可以進一步的討論。??????

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市本冲,隨后出現(xiàn)的幾起案子准脂,更是在濱河造成了極大的恐慌,老刑警劉巖檬洞,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件狸膏,死亡現(xiàn)場離奇詭異,居然都是意外死亡添怔,警方通過查閱死者的電腦和手機湾戳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來澎灸,“玉大人院塞,你說我怎么就攤上這事⌒哉眩” “怎么了拦止?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵,是天一觀的道長糜颠。 經(jīng)常有香客問我汹族,道長,這世上最難降的妖魔是什么其兴? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任顶瞒,我火速辦了婚禮,結果婚禮上元旬,老公的妹妹穿的比我還像新娘榴徐。我一直安慰自己,他們只是感情好匀归,可當我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布坑资。 她就那樣靜靜地躺著,像睡著了一般穆端。 火紅的嫁衣襯著肌膚如雪袱贮。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天体啰,我揣著相機與錄音攒巍,去河邊找鬼。 笑死荒勇,一個胖子當著我的面吹牛柒莉,可吹牛的內容都是我干的。 我是一名探鬼主播沽翔,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼常柄,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了搀擂?” 一聲冷哼從身側響起西潘,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎哨颂,沒想到半個月后喷市,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡威恼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年品姓,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片箫措。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡腹备,死狀恐怖,靈堂內的尸體忽然破棺而出斤蔓,到底是詐尸還是另有隱情植酥,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布弦牡,位于F島的核電站友驮,受9級特大地震影響,放射性物質發(fā)生泄漏驾锰。R本人自食惡果不足惜卸留,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望椭豫。 院中可真熱鬧耻瑟,春花似錦、人聲如沸赏酥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽今缚。三九已至算柳,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間姓言,已是汗流浹背瞬项。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留何荚,地道東北人囱淋。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像餐塘,于是被迫代替她去往敵國和親妥衣。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內容