在開始以前,咱們先來看下官方文檔說明;查看vue-cli文檔中有這麼一句話:html
只有以 VUE_APP_ 開頭的變量會被 webpack.DefinePlugin 靜態嵌入到客戶端側的包中。
複製代碼
由此咱們能夠知道,vue-cli
是有針對 VUE_APP_
這個變量進行配置。接下來讓咱們查看源碼,看下vue-cli
是怎麼實現的。vue
查看根路徑的 package.json
文件咱們能夠知道,當執行 npm run serve
時會執行 vue-cli-service
;因此咱們找到該文件的執行地址node_modules/@vue/cli-service
。node
分析其 package.json
咱們知道,當咱們執行 vue-cli-service
時候會調用文件 lib/Service.js
中 init
函數:webpack
init (mode = process.env.VUE_CLI_MODE) {
...
this.mode = mode
// load mode .env
if (mode) {
this.loadEnv(mode)
}
// load base .env
this.loadEnv()
...
}
複製代碼
緊接着咱們再來看loadEnv
方法git
loadEnv (mode) {
const logger = debug('vue:env')
const basePath = path.resolve(this.context, `.env${mode ? `.${mode}` : ``}`)
// 注意這裏,無論你有沒有定義它都會在後面加上一個.local的後綴,感受這裏不是很好
const localPath = `${basePath}.local`
const load = path => {
try {
const env = dotenv.config({ path, debug: process.env.DEBUG })
dotenvExpand(env)
logger(path, env)
} catch (err) {
// only ignore error if file is not found
if (err.toString().indexOf('ENOENT') < 0) {
error(err)
}
}
}
load(localPath)
load(basePath)
...
}
複製代碼
這裏會先調用 dotenv
(位於 node_modules/dotenv
)的 config
函數,最終會返回這樣的格式 { parsed: { YOUR_ENV_KEY: '你設定的環境變量值' } }
。 而且咱們能夠看到,這裏已經將值存放到process.env
中了。github
function config (options /*: ?DotenvConfigOptions */) /*: DotenvConfigOutput */ {
...
try {
// specifying an encoding returns a string instead of a buffer
const parsed = parse(fs.readFileSync(dotenvPath, { encoding }), { debug })
Object.keys(parsed).forEach(function (key) {
if (!process.env.hasOwnProperty(key)) {
process.env[key] = parsed[key]
} else if (debug) {
log(`"${key}" is already defined in \`process.env\` and will not be overwritten`)
}
})
return { parsed }
} catch (e) {
return { error: e }
}
}
複製代碼
這裏再說下 parse
方法,會讀取你設置的全部 .env
文件,而後將裏面的數據轉換成對象,簡單來講就是 以換行符號來循環,用正則匹配出內容
,最終造成以{key: value}
的格式輸出。web
const NEWLINE = '\n'
const RE_INI_KEY_VAL = /^\s*([\w.-]+)\s*=\s*(.*)?\s*$/
const RE_NEWLINES = /\\n/g
function parse (src /*: string | Buffer */, options /*: ?DotenvParseOptions */) /*: DotenvParseOutput */ {
const debug = Boolean(options && options.debug)
const obj = {}
// convert Buffers before splitting into lines and processing
src.toString().split(NEWLINE).forEach(function (line, idx) {
// matching "KEY' and 'VAL' in 'KEY=VAL'
const keyValueArr = line.match(RE_INI_KEY_VAL)
// matched?
if (keyValueArr != null) {
const key = keyValueArr[1]
// default undefined or missing values to empty string
let val = (keyValueArr[2] || '')
const end = val.length - 1
const isDoubleQuoted = val[0] === '"' && val[end] === '"'
const isSingleQuoted = val[0] === "'" && val[end] === "'"
// if single or double quoted, remove quotes
if (isSingleQuoted || isDoubleQuoted) {
val = val.substring(1, end)
// if double quoted, expand newlines
if (isDoubleQuoted) {
val = val.replace(RE_NEWLINES, NEWLINE)
}
} else {
// remove surrounding whitespace
val = val.trim()
}
obj[key] = val
} else if (debug) {
log(`did not match key and value when parsing line ${idx + 1}: ${line}`)
}
})
return obj
}
複製代碼
而後咱們再來看下 dotenvExpand
方法,找到它位於 node_modules/dotenv-expand
下,這裏就沒啥好說的,就是將幾個環境變量的值放到一塊兒vue-cli
接下來讓咱們回到開頭說的 只有以 VUE_APP_ 開頭的變量會被 webpack.DefinePlugin 靜態嵌入到客戶端側的包中
,這個是在那裏配置的呢?npm
咱們知道 vue-cli
會對 webpack
進行配置擴展,因此咱們發如今 cli-service/lib/config/app.js
中json
const resolveClientEnv = require('../util/resolveClientEnv')
webpackConfig
.plugin('define')
.use(require('webpack/lib/DefinePlugin'), [
resolveClientEnv(options)
])
複製代碼
咱們接着找到 resolveClientEnv
方法,能夠看到是在這裏定義的,而且會將非 VUE_APP_
開頭的過濾掉
const prefixRE = /^VUE_APP_/
module.exports = function resolveClientEnv (options, raw) {
const env = {}
Object.keys(process.env).forEach(key => {
if (prefixRE.test(key) || key === 'NODE_ENV') {
env[key] = process.env[key]
}
})
// 須要注意的是 `baseUrl` 從 `Vue CLI 3.3` 起已棄用,請使用 `publicPath` 。如下源碼涉及此改動
env.BASE_URL = options.publicPath
if (raw) {
return env
}
for (const key in env) {
env[key] = JSON.stringify(env[key])
}
return {
'process.env': env
}
}
複製代碼
.env
和 .env.local
定義的環境變量會被全局引用,並會與其它環境變量合併VUE_APP_
開頭,否則會被過濾掉VUE_APP_*
變量以外,在你的應用代碼中始終可用的還有兩個特殊的變量:NODE_ENV
和 BASE_URL
最後,謝謝你們的觀看,若是想觀看個人更多文章,請點擊前往。 若是對您有幫助,請爲我點個小星星。
也歡迎你們交流分享本身的開發心得~
本文做者: Echi
本文連接: juejin.im/user/585e36…
版權聲明: 本文章除特別聲明外,均採用 @BY-NC-SA 許可協議。轉載請註明出處!