最近在做前端切版的時候,遇到了一個以前沒注意到的問題,就是在本機端開發時,存取圖片或其他檔案都預設從根目錄開始找 (e.g. /images/...
),可是當專案開發完,要發佈到其他位置時,圖片等檔案的位置就會有所變更,這時候圖片的路徑就會找不到檔案了,必須要再手動調整過,當然不可能每次都手動一個一個改路徑。
所以開始著手研究怎麼把路徑的變數,透過 webpack 編譯階段判斷目前是開發環境,還是 production 環境,來改變圖片等檔案的前綴路徑。底下就以 pug-sass-template 專案來說明幾個重要的步驟。
Step 1 - Webpack Get Environment Variables
參考: https://webpack.js.org/guides/environment-variables/
上面網址提供的範例在傳入參數時,一個與多個在接收時,其實有所不同,這邊也是踩了雷才注意到
Webpack 版本 : 4.43.0
npx webpack --env NODE_ENV=local --env production --progress
module.exports = (env) => { console.log('env:', env); console.log('Production: ', env.production);
return { entry: './src/index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist'), }, }; };
|
傳入兩組 env 值的時候,所收到的 env 其實是一組陣列,各別是 --env XXXXX
裡面的 XXXXX
,但是當傳入的只有一組 env 時,例如:--env production
這時候 env 就是 production
這個值,就不再是陣列了
npx webpack --env production --progress
module.exports = (env) => { console.log('env:', env);
return { entry: './src/index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist'), }, }; };
|
雖然目前 webpack 參考的頁面是 v5.31.0 版,可是沒特別寫出這個差異,讓我一直踩雷踩到懷疑人生了…
另外,可以也使用 mode 來傳入環境變數
npx webpack --mode production --progress
module.exports = (env, options) => { console.log('options.mode:', options.mode);
return { entry: './src/index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist'), }, }; };
|
Step 2 - Pass Variables Into PUG files
參考: https://www.npmjs.com/package/pug-html-loader
根據這個套件的說明,可以簡單地透過在 options
裡面加入 data
來將要傳入 pug 的變數傳進去即可。而 data 的格式,寫成 JSON 即可。結合一下上面的步驟一,就可以來調整圖片的前綴網址。
webpack --env production --mode production --config webpack.config.js
module.exports = (env, options) => { const _VARIABLES = { IMG_PREFIX_URL: (options.mode === 'production') ? 'https://soarlin.github.io/' : '/' };
let config = { context: path.resolve(__dirname, 'src'), entry: { index: './js/index.js' }, output: ...., module: { rules: [ { test: /\.pug$/, use: [ { loader: 'html-loader', options: { minimize: (options.mode === 'production') ? true : false } }, { loader: 'pug-html-loader', options: { data: _VARIABLES, pretty: (options.mode === 'production') ? false : true } } ] }, .... ] }, plugins: [ ... ] }
return config; };
|
而到時候 pug 檔內,就可以讀到傳入的變數了
// 接收變數 - var imgPrefixUrl = IMG_PREFIX_URL
// 套用在圖片上 img.rounded-circle(src=imgPrefixUrl+'images/soarlin-avatar.jpg', alt="avatar")
|
Step 3 - Pass Variables Into Sass/SCSS files
參考: https://www.npmjs.com/package/sass-loader#additionaldata
雖然在 stack overflow 上也有找到解答,可是上面的解答實際使用時有問題,後來是在 sass-loader npm 的頁面上找到正確的參數,可能是版本的關係產生的不同吧!
在 sass-loader 的 options
加入 additionalData
來傳入參數到 Sass/SCSS 檔內。而 additionalData 可使用字串或是函示,使用的方式在上述參考網址也有了,所以我就以我自己的範例來寫就好
webpack --env production --mode production --config webpack.config.js
module.exports = (env, options) => { const _VARIABLES = { IMG_PREFIX_URL: (options.mode === 'production') ? 'https://soarlin.github.io/' : '/' };
let config = { context: path.resolve(__dirname, 'src'), entry: { index: './js/index.js' }, output: ...., module: { rules: [ ..., { test: /\.s[ac]ss$/i, use: [ 'style-loader', 'css-loader', { loader: 'sass-loader', options: { sourceMap: true, additionalData: "$imgPrefix: '" + _VARIABLES.IMG_PREFIX_URL + "';" } } ] }, .... ] }, plugins: [ ... ] }
return config; };
|
這樣似乎會將 additionalData 放在所有 Sass/SCSS 的最前方,讓它以變數的方式直接帶入 Sass/SCSS 內,所以就可以直接使用變數
.item-bg { background-image: url($imgPrefix+'images/background-0.jpg'); background-repeat: no-repeat; background-position: center center; background-size: cover; }
|
以上大概就是這在切版遇到的問題,為了找這些方法花了不少時間,所以非得好好紀錄一下,以供後人參考,減少走冤枉路。也讓自己以後可以拿來抄。
而文中寫到的範例程式,都可以到 Github 上的 pug-sass-template 專案上找到,歡迎大家幫忙按顆星星。