UNPKG

@quasar/app-webpack

Version:

Quasar Framework App CLI with Webpack

232 lines (190 loc) 5.48 kB
const { existsSync, readFileSync } = require('node:fs') const { join, isAbsolute } = require('node:path') const { parse: dotEnvParse } = require('dotenv') const { expand: dotEnvExpand } = require('dotenv-expand') const { encodeForDiff } = require('./encode-for-diff.js') const readFileEnvCacheKey = 'readFileEnv' /** * Get the raw env definitions from the host * project env files. */ module.exports.readFileEnv = 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 (Webpack or Esbuild). */ module.exports.getBuildSystemDefine = 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 }