---
# System prepended metadata

title: 來點 Webpack 動態 CDN (publicPath)

---

# 來點 Webpack 動態 CDN (publicPath)

用webpack打包的專案，如果你使用 環境參數來指定 cdn 網址

```environment=
// env.beta
ASSET_PATH = 'http://beta.cdn.com'
```

然後再把自己設定好的環境參數丟給 webpack

```typescript=
import webpack from 'webpack';

const ASSET_PATH = process.env.ASSET_PATH || '/';

export default {
    output: {
        publicPath: ASSET_PATH
    },
    plugins: {
        new webpack.DefinePlugin({
            'process.env.ASSET_PATH': JSON.stringify(ASSET_PATH)
        })
    }
};
```
等於是有 6 個環境就要分別下 6 次不同指令做 6 次打包
這就是 666 罷…

能不能只打包一次進 docker image ，之後所有 container 都是從這個 image 建立出來 從 開發(dev) 到 測試(test) , 封測 (beta) , 上線(prod) 都使用同一個image 並且修改掉 cdn ?
答案是 ***YES ! 你可以***

> 其實這樣的需求很符合邏輯，在不同環境的打包或者 node, npm, yarn 版本有所不同打包出來的東西都會不一樣，即使 yarn.lock似乎會幫你瑣住那些版本，但只要 dependencies沒有設定好 yarn install下去依舊有機會安裝到非預期的套件版本，重新打包永遠都帶有風險。

先說結論
`__webpack_public_path__` 就是他!

[官方文件](https://webpack.js.org/guides/public-path/)

## 什麼是 PublicPath

很多人會寫 V A R 三大框架，但絕大多數的人並沒有自己去設定過 webpack，
打包時我們可以設定 publicPath 來改變所有打包過的檔案的 baseurl 如下

```typescript=
// 打包前
const img = require('img/taiwan_can_help.jpg');

// 打包後
const img = 'img/taiwan_can_help.ef1241s.jpg';

// 設定 { publicPath: 'http://dev.cdn.com' }
const img = 'http://dev.cdn.com/img/taiwan_can_help.ef1241s.jpg';
```

`publicPath` 影響著 .js .css. .html img… 幾乎所有檔案都囊括了，但當你寫在 webpack.config.js 內時，就注定有幾個環境就得打包幾次…

### 如何讓他動態被定義呢?

首先我們必須使用到另一個技術 webpackChunk ，chunk可以將你肥肥的程式碼切分了許多塊，在適當的時機讓使用者載入，大大的降低伺服器負載並友善了使用者體驗。chunk 會在打包時整理出一份 vendor.js 裡面存放著所有將會使用到的檔案的路徑，並在使用者瀏覽 App 時利用 vendor 去找到那些檔案路徑，而我們就是要搶在檔案尚未被真正加載之前改掉他的 base url

這時候就要用到 `__webpack_public_path__` 這個動態變數

如果他在 你的入口檔案 (也就是 [Entry Point](https://webpack.js.org/concepts/entry-points/)) 的最一開始被定義，那麼接下來 vendor 讀出的檔案都會改訪問新的 `publicPath`


### 為什麼不直接定義在 `<head><script>` 內
webpack 所有處理都會被包進去 一個 function 內，所以 `__webpack_public_path__` 在 bowser 情境下是一個 scope variable，是無法使用 `window.__webpack_public_path__` 從外部改變的喔
接下來只要簡單的在 `docker run container` 前去修改 domain.js 的 `window.cdnDomain` 間接去影響 `__webpack_public_path__` 就不用為了變換 cdn 再次打包了!

記得 檢查自己的 webpack 是否有使用 **PreloadPlugin** 這個套件
他會把路徑 直接打包在 `<head>` 內，`__webpack_public_path__` 無法動態影響他，記得刪掉並使用內建的 `webpackPrefech` 來達到最好的效果喔!