iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 15
1
Modern Web

Quasar CLI Framework 邪教:整合分散的前端技術和工具、常見的開發需求系列 第 15

第十五天:專案的初始化 - 拆分環境變數 (feat. process.env、CommonJS)

※ 今天的內容

一、為何需要環境變數?
二、Quasar CLI 的環境變數
三、實作將API位置拆散到不同的環境變數設定檔(.env)
四、何謂CommonJS
五、總結
六、延伸閱讀

一、為何需要環境變數?

在專案開發,有些參數設定會因測試環境或正式環境有所區別
看到昨天src/boot/axios.js的初始化程式碼:
其中的API Base URL 就是常見的例子之一

import axios from 'axios'

export default ({ app, router, store, Vue }) => {
  axios.defaults.baseURL = 'http://api.test.com.tw/'
    
  axios.interceptors.request.use((config) => {
    return config
  }) 
  Vue.prototype.$axios = axios
}

當我們使用quasar devquasar build
會在我們電腦上的Node.js執行Webpack,對網頁進行編譯與打包的方式

  1. 執行前者quasar dev,Quasar CLI會讓Webpack依照「測試環境」的參數配置,
    將編譯與打包後的檔案放到Webpack Dev Servr
  2. 執行後者quasar build,Quasar CLI會讓Webpack依照「正式環境」的參數配置,
    將編譯與打包後的檔案產生至dist/src底下

而這些環境的參數配置可以存放在哪? Node.js 的 process.env

二、Quasar CLI 的環境變數

(一) 文件導讀

在Quasar的官方文件提到,我們可以在專案裡面使用以下的預設環境變數
https://quasar.dev/quasar-cli/handling-process-env#Import-based-on-process.env

環境變數 說明
process.env.DEV Boolean Code runs in development mode
process.env.PROD Boolean Code runs in production mode
process.env.CLIENT Boolean Code runs on client (not on server)
process.env.SERVER Boolean Code runs on server (not on client)
process.env.MODE String Quasar CLI mode (spa, pwa, …)
process.env.NODE_ENV String Has two possible values: production or development
  1. process.env.DEV、process.env.PROD:可以用來實現哪些程式碼,只有在測試環境或正式環境下會執行
  2. process.env.CLIENT、process.env.SERVER:可以用來確認程式當下是在Sever端渲染還是Client端渲染
  3. process.env.MODE:判斷目前是執行在哪種Quasar的專案模式,例如SPA、PWA
  4. process.env.NODE_ENV:判斷目前是執行在測試環境還是正式環境

讓我們來做四個小Lab,示範環境變數的變化

(二) Lab實驗-1 SPA + Dev

  1. 在某個Quasar專案,以終端機執行quasar dev,以SPA的模式啟動測試伺服器
  2. src/pages/Index.vuemounted()裡面,透過console輸出上方四個環境變數
<script>
export default {
  name: 'DemoPage',

  data () {
    return {
    }
  },
  mounted () {
    // 是否在測試環境
    console.info('process.env.DEV :', process.env.DEV)
    // 是否在正式環境
    console.info('process.env.PROD :', process.env.PROD)
    
    // 當前是否在client端渲染時執行
    console.info('process.env.CLIENT :', process.env.CLIENT)
    // 當前是否在server端渲染時執行
    console.info('process.env.SERVER :', process.env.SERVER)
    
    // 目前是執行在哪種Quasar的專案模式
    console.info('process.env.MODE :', process.env.MODE)
    // 目前是執行在哪種環境?
    console.info('process.env.NODE_ENV :', process.env.NODE_ENV)
  }
}
</script>

這時你會得到下面的輸出結果:
https://ithelp.ithome.com.tw/upload/images/20200930/20120331i4bjSB6jXw.png

(三) Lab實驗-2 SSR + Dev

  1. 在某個Quasar專案,以終端機執行quasar dev -m ssr,以SSR的模式啟動測試伺服器
  2. src/pages/Index.vuemounted()裡面,透過console輸出上方四個環境變數 (同上)

這時你會得到下面的輸出結果:https://ithelp.ithome.com.tw/upload/images/20200930/20120331u93wrX5PH4.png

前兩個Lab唯一的差別是:process.env.MODE 從原本的 spa 變成 ssr

你可能會有一個疑惑:
為什麼process.env.CLIENT 會是 true?
因為輸出console.info('process.env.CLIENT :', process.env.CLIENT)是在mounted()
mounted()是在Client端渲染的時候執行的

(三) Lab實驗-3 SPA + Production

  1. 在某個Quasar專案,以終端機執行quasar build,以SPA的模式打包並建置
  2. 在src/pages/Index.vue 輸出上方四個環境變數 (同上)
  3. 將quasar build 編譯後的網頁檔案放到任一個Http伺服器上,透過網址進入

這時你會得到下面的輸出結果:
https://ithelp.ithome.com.tw/upload/images/20200930/201203316izw6ImI97.png

可以看到和Lab-1最大的差異是
process.env.NODE_ENV 從 development 變成 production

(四) Lab實驗4:SSR + Dev + PreFetch()

  1. 在某個Quasar專案,以終端機執行quasar dev -m ssr,以SSR的模式啟動測試伺服器
  2. src/pages/Index.vuepreFetch()裡面,透過console輸出上方四個環境變數
    (記得在quasar.config.js,設定preFetch: true)
preFetch () {
    console.info('process.env.DEV :', process.env.DEV)
    console.info('process.env.PROD :', process.env.PROD)
    console.info('process.env.CLIENT :', process.env.CLIENT)
    console.info('process.env.SERVER :', process.env.SERVER)
    console.info('process.env.MODE :', process.env.MODE)
    console.info('process.env.NODE_ENV :', process.env.NODE_ENV)
    // console.log(this.$store.getters['example/getToken'])
    // this.$store.commit('example/readToken', 'Test002')
 }

重新整理網頁後,你會在終端機看到多出了這幾行訊息
https://ithelp.ithome.com.tw/upload/images/20200930/20120331rbNI4TxHIh.png

和Lab-2最大的差異是,process.env.Server 變成 true
也就是說,quasar 的 preFetch() 是在Server端渲染時執行的

三、實作將API位置拆散到不同的環境變數設定檔(.env)

(一) 需求說明

現在我們要將測試環境的API網址和正式環境的API網址
分別存到.env.development 與 .env.production

  1. 當我執行quasar dev,打開測試伺服器的網頁時,axios的base url 會是測試環境的API網址
  2. 當我執行quasar build,打開正式伺服器的網頁時,axios的base url 會是正式環境的API網址

(二) 實作細節 (作法一)

我們可以安裝Quasar的extension @quasar/dotenv

這個套件裝完後,每當進入網站後
會在昨天談到的Quasar 初始化流程的第二個順序,幫我們存取測試環境和正式環境的.env參數
存放到process.env裡面

作法一的好處是,裝完後不需要做額外設定即可使用
缺點是,只能使用在Quasar CLI建立的專案

https://github.com/quasarframework/app-extension-dotenv/tree/dev/app-extension

  1. 在專案的資料夾底下,透過終端機執行指令,加入「@quasar/dotenv」extension
quasar ext add @quasar/dotenv

2.依序回答下列問題,完成安裝

"What is the name of your .env that you will be using for development builds?"
.env.development

"What is the name of your .env that you will be using for production builds?"
.env.production

"What name would you like to use for your Common Root Object ('none' means to not use one)?"
none

"Create your .env files for you?"
yes

"For security, would you like your .env files automatically added to .gitignore?"
yes
  1. 在專案的根目錄底下,會出現.env.development與.env.production
    https://ithelp.ithome.com.tw/upload/images/20200930/20120331g1tXxhbqJv.png

分別在這個檔案加入API_URL=http://api.dev.com.twAPI_URL=http://api.production.com.tw
https://ithelp.ithome.com.tw/upload/images/20200930/20120331ZmkbcZNof2.png

  1. 修改昨天的src/boot/axios.js
import axios from 'axios'

export default ({ app, router, store, Vue }) => {
  axios.defaults.baseURL = process.env.API_URL // 從env取得API的網址
    
  axios.interceptors.request.use((config) => {
    return config
  }) 
  Vue.prototype.$axios = axios
}

  1. 在src/pages/Index.vue,隨便撰寫一個API
<script>
export default {
  name: 'DemoPage',

  data () {
    return {
    }
  },
  mounted () {
    this.$axios.post('login', {
      username: 'username',
      password: 'password'
    })
  }
}
</script>

分別在測試伺服器與正式伺服器打開網頁
會看到呼叫api的url網域是不一樣的 (左:測試區 右:正式區)
https://ithelp.ithome.com.tw/upload/images/20200930/20120331goir4Q8Goc.png

(三) 實作細節 (作法二)

這個方法是自己用dot-env讀.env檔的方式
塞到quasar.config.js裡面 (Webpack的編譯設定)
相當於作法一用的套件,底層的作法
不需要依賴 Quasar CLI

  1. 安裝dot-env
    透過dot-env的第三方套件,取得.env裡面的Key 與 Value
npm install — save-dev dotenv
  1. src/config,新增一個EnvParse.js,透過下面的程式碼,將.env的參數設定轉換成JSON的格式
    其中利用process.env.NODE_ENV,在quasar dev 與 quasar build時,取得不同的環境變數檔
const DotEnv = require('dotenv')
const parsedEnv = DotEnv.config({ path: `.env.${process.env.NODE_ENV}` }).parsed

module.exports = function () {
  return parsedEnv
}
  1. 在quasar.config.js的build{},加入env: require('./src/config/EnvParse.js.js')()
    將自訂的環境變數資料,存到process.env,給所有的專案程式可以使用

比較要注意的是,quasar.config.js預設是不能使用ESModule,需要用CommonJS
而且quasar.config.js不在Webpack打包的範圍內,不用考慮Tree Shaking的問題

build: {
    ...
    env: require('./src/config/EnvParse.js')(),
}
  1. 在專案的跟目錄底下,新增.env.development.env.production

https://ithelp.ithome.com.tw/upload/images/20200930/20120331g1tXxhbqJv.png

分別在這個檔案加入API_URL=http://api.dev.com.twAPI_URL=http://api.production.com.tw
https://ithelp.ithome.com.tw/upload/images/20200930/20120331ZmkbcZNof2.png

  1. 修改昨天的src/boot/axios.js
import axios from 'axios'

export default ({ app, router, store, Vue }) => {
  axios.defaults.baseURL = process.env.API_URL // 從env取得API的網址
    
  axios.interceptors.request.use((config) => {
    return config
  }) 
  Vue.prototype.$axios = axios
}

  1. 在src/pages/Index.vue,隨便撰寫一個API
<script>
export default {
  name: 'DemoPage',

  data () {
    return {
    }
  },
  mounted () {
    this.$axios.post('login', {
      username: 'username',
      password: 'password'
    })
  }
}
</script>

分別在測試伺服器與正式伺服器打開網頁
會看到呼叫api的url網域是不一樣的 (左:測試區 右:正式區)
https://ithelp.ithome.com.tw/upload/images/20200930/20120331goir4Q8Goc.png

四、何謂CommonJS

早期Javascript官方沒有明定的模組規範
CommonJS 是第一次在Node.js出現的時候,用來拆分程式模組的規範
ESModule 是 ECMAScript 官方拆分模組的規範

CommonJS和ESModule除了語法上的差異之外
很多概念其實是相同的
如果想更深入的了解,可以參考下方延伸閱讀

五、總結

環境變數在專案開發上真的蠻好用
還可以透過package.json的scripts
將Node_Env更改成development,以測試環境的API來打包,放在實體的測試伺服器進行測試

"scripts": {
    "build:dev": "NODE_ENV=development&&quasar build",
}

專案初始化的部分大致撰寫的差不多了
之後會用一個整合的實作案例,來統整第三部分的內容

可惜連假鐵人賽沒放假

五、延伸閱讀

webpack 新手教學之淺談模組化與 snowpack
CommonJs 和 ESModule 的 区别整理
[Node] 環境變數設置 NODE_ENV (environment variable)


上一篇
第十四天:專案的初始化 - JS 程式 (feat. ESModule)
下一篇
第十六天:專案的初始化 - 「前後台頁面存取權限」情境需求練習 (第三部分總結)
系列文
Quasar CLI Framework 邪教:整合分散的前端技術和工具、常見的開發需求31

尚未有邦友留言

立即登入留言