UNPKG

@quasar/app-vite

Version:

Quasar Framework App CLI with Vite

231 lines (189 loc) 5.34 kB
import { existsSync, readFileSync } from 'node:fs' import { join, isAbsolute } from 'node:path' import { parse as dotEnvParse } from 'dotenv' import { expand as dotEnvExpand } from 'dotenv-expand' import { encodeForDiff } from './encode-for-diff.js' const readFileEnvCacheKey = 'readFileEnv' /** * Get the raw env definitions from the host * project env files. */ export function readFileEnv({ ctx, quasarConf }) { const { cacheProxy } = ctx const opts = { envFolder: quasarConf.build.envFolder, envFiles: quasarConf.build.envFiles, envFilter: quasarConf.build.envFilter } const configHash = encodeForDiff(opts) const cache = cacheProxy.getRuntime(readFileEnvCacheKey, () => ({})) if (cache.configHash !== configHash) { const result = getFileEnvResult({ ...opts, appPaths: ctx.appPaths, quasarMode: ctx.modeName, buildType: ctx.dev ? 'dev' : 'prod' }) if (opts.envFilter !== void 0) { result.fileEnv = opts.envFilter(result.fileEnv) || {} } cacheProxy.setRuntime(readFileEnvCacheKey, { configHash, result: { ...result, envFromCache: true } }) return result } return cache.result } function getFileEnvResult({ appPaths, quasarMode, buildType, envFolder = appPaths.appDir, envFiles = [] }) { const fileList = [ // .env // loaded in all cases '.env', // .env.local // loaded in all cases, ignored by git '.env.local', // .env.[dev|prod] // loaded for dev or prod only `.env.${buildType}`, // .env.local.[dev|prod] // loaded for dev or prod only, ignored by git `.env.local.${buildType}`, // .env.[quasarMode] // loaded for specific Quasar CLI mode only `.env.${quasarMode}`, // .env.local.[quasarMode] // loaded for specific Quasar CLI mode only, ignored by git `.env.local.${quasarMode}`, // .env.[dev|prod].[quasarMode] // loaded for specific Quasar CLI mode and dev|prod only `.env.${buildType}.${quasarMode}`, // .env.local.[dev|prod].[quasarMode] // loaded for specific Quasar CLI mode and dev|prod only, ignored by git `.env.local.${buildType}.${quasarMode}`, // additional user-defined env files ...envFiles ] const usedEnvFiles = [] const folder = isAbsolute(envFolder) === true ? envFolder : join(appPaths.appDir, envFolder) const env = Object.fromEntries( fileList.flatMap(file => { const filePath = isAbsolute(file) === true ? file : join(folder, file) if (existsSync(filePath) === false) { return [] } usedEnvFiles.push(file) return Object.entries(dotEnvParse(readFileSync(filePath, 'utf-8'))) }) ) if (Object.keys(env).length === 0) { return {} } const { parsed: rawFileEnv } = dotEnvExpand({ parsed: env }) return { fileEnv: getFileEnv(rawFileEnv), usedEnvFiles, envFromCache: false } } const validKeyRE = /^[a-zA-Z_$][a-zA-Z0-9_$]+/ /** * Filter out keys that cannot be used in JS * as process.env.[key] * Examples: ProgramFiles(x86), BASH_FUNC_which%% */ function getFileEnv(env) { const validKeys = Object.keys(env).filter(key => validKeyRE.test(key)) return validKeys.reduce((acc, key) => { acc[key] = env[key] return acc }, {}) } /** * Get the final env definitions to supply to * the build system (Vite or Esbuild). */ export function getBuildSystemDefine({ fileEnv = {}, buildEnv = {}, buildRawDefine = {} }) { const acc = {} for (const key in fileEnv) { const val = fileEnv[key] acc[`process.env.${key}`] = val === 'true' || val === 'false' ? val // let's keep it as boolean and not transform it to string : JSON.stringify(fileEnv[key]) } const flatBuildEnv = flattenObject(buildEnv) for (const key in flatBuildEnv) { acc[`process.env.${key}`] = JSON.stringify(flatBuildEnv[key]) } for (const key in buildRawDefine) { const val = buildRawDefine[key] acc[key] = typeof val === 'string' ? buildRawDefine[key] : JSON.stringify(buildRawDefine[key]) } return acc } /** * Flattens the object to a single level. * Keys of the result will be the keypaths of the properties of the parameter. * It will also preserve the original nested objects with their root keypath. * * @param {Object} obj * * @example * flattenObject({ * foo: 1, * bar: { * baz: 2, * qux: { * quux: { * quuz: 3 * } * } * } * }) * // Result: * // foo: 1 * // bar: {baz: 2, qux: {…}, qux.quux: {…}, qux.quux.quuz: 3} * // bar.baz: 2 * // bar.qux: {quux: {…}, quux.quuz: 3} * // bar.qux.quux: {quuz: 3} * // bar.qux.quux.quuz: 3 */ const flattenObject = obj => { const result = {} for (const key in obj) { if (!Object.prototype.hasOwnProperty.call(obj, key)) continue if (typeof obj[key] !== 'object') { result[key] = obj[key] continue } const flatObj = flattenObject(obj[key]) // Save the object itself to it's root key result[key] = flatObj // Save the child keys for (const flatKey in flatObj) { if (!Object.prototype.hasOwnProperty.call(flatObj, flatKey)) continue result[`${key}.${flatKey}`] = flatObj[flatKey] } } return result }