UNPKG

vite-plugin-env-parse

Version:

Parse env string values to correct values, not all values are strings. And automatically generate ImportMetaEnv

240 lines (232 loc) 9.38 kB
var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { envParse: () => envParse, parseLoadedEnv: () => parseEnv }); module.exports = __toCommonJS(src_exports); var import_node_fs2 = __toESM(require("fs")); var import_node_path = __toESM(require("path")); // src/parseEnvComment.ts function parseEnvComment(content) { let res = {}; let lines = content.toString().replace(/\r\n?/gm, "\n").split("\n"); const commentReg = /^\s*#\s*(.*)\s*/; const keyReg = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)/; const startMultiSharpReg = /^\#+/; let commentString = []; lines.forEach((line) => { if (commentReg.test(line)) { const comment = line.replace(commentReg, "$1").replace(startMultiSharpReg, "").trim(); commentString.push(comment); } else if (keyReg.test(line)) { const matched = line.match(keyReg); const key = matched ? matched[1] : ""; key && commentString.length && (res[key] = commentString.join("\n * ")); commentString.length = 0; } else if (commentString.length) { commentString.length = 0; } }); return res; } // src/utils.ts var htmlLangRE = /\.(?:html|htm)$/; var CSS_LANGS_RE = /\.(css|less|sass|scss|styl|stylus|pcss|postcss|sss)(?:$|\?)/; var nonJsRe = /\.json(?:$|\?)/; var isHTMLRequest = (requestId) => htmlLangRE.test(requestId); var isCSSRequest = (requestId) => CSS_LANGS_RE.test(requestId); var isNonJsRequest = (requestId) => nonJsRe.test(requestId); function errorLog(content) { console.log("\n"); console.log("\x1B[31m%s%s\x1B[0m", "\u2718 [env-parse] - ", content); console.log(); } // src/parseEnv.ts function parseEnv(env, options = {}) { const { parseJson = true, exclude = [], customParser } = options; const parsedRes = {}; const booleanValueMap = { true: true, false: false }; for (const envKey of Object.keys(env)) { let value = env[envKey]; if (typeof value === "string" || !exclude.includes(envKey)) { if (value === "true" || value === "false") { value = booleanValueMap[value]; } else if (typeof value !== "boolean" && value !== "" && !isNaN(value)) { value = parseFloat(value) || value; } else if (parseJson) { try { value = JSON.parse(value); } catch (e) { try { const temp = (0, eval)(`(${value})`); if (!(temp instanceof RegExp)) { value = temp; } } catch (e2) { } } } if (customParser) { value = customParser && customParser(envKey, value) || value; } } parsedRes[envKey] = value; } return parsedRes; } // src/writeEnvInterface.ts var import_node_fs = __toESM(require("fs")); function writeEnvInterface(path2, envInterface) { const importMetaEnvRegexp = /interface ImportMetaEnv\s*\{[\s\S]*?\}/g; if (import_node_fs.default.existsSync(path2)) { const fileContent = import_node_fs.default.readFileSync(path2, { encoding: "utf-8" }); if (importMetaEnvRegexp.test(fileContent)) { envInterface = fileContent.replace(importMetaEnvRegexp, envInterface); } else { envInterface = `${fileContent} ${envInterface}`; } } else { envInterface = `/// <reference types="vite/client" /> ${envInterface}`; } import_node_fs.default.writeFileSync(path2, envInterface); } // src/generateEnvInterface.ts function generateEnvInterface(env, commentRecord) { let interfaceItem = []; const excludeKey = ["MODE", "BASE_URL", "PROD", "DEV", "SSR"]; const typeMap = { boolean: "boolean", string: "string", number: "number", array: "any[]", object: "Record<string, any>" }; for (const envKey of Object.keys(env)) { if (excludeKey.includes(envKey)) continue; const value = env[envKey]; const comment = commentRecord[envKey]; let valueType = typeof value; valueType = valueType === "object" ? Array.isArray(value) ? "array" : valueType : valueType; const jsDocComment = comment ? `/** * ${comment} */ ` : ""; const keyValue = `readonly ${envKey}: ${typeMap[valueType] || "any"}`; interfaceItem.push(jsDocComment + keyValue); } if (!interfaceItem.length) return; return `interface ImportMetaEnv { // Auto generate by env-parse ${interfaceItem.join("\n ")} }`; } // src/index.ts function envParse(options = {}) { const { parseJson = true, exclude = [], dtsPath = "env.d.ts", customParser, dev = true, build = false } = options; let parsedEnv; let isBuild = false; let userConfig; const importMetaEnvReg = /(?<![\'\"])import\.meta\.env\.([\w-]+)/gi; const importObjReg = /(import\.meta\.env)(?:[^.])/gi; return { name: "vite-plugin-env-parse", enforce: "pre", transform(code, id) { if (!isBuild || // exclude html, css and static assets for performance isHTMLRequest(id) || isCSSRequest(id) || isNonJsRequest(id) || userConfig.assetsInclude(id)) { return; } if (code.includes("import.meta.env")) { code = code.replace(importMetaEnvReg, (matched, envKey) => { let val = parsedEnv[envKey]; if (typeof val !== "undefined") { return typeof val === "string" ? `'${val}'` : JSON.stringify(val); } return matched; }).replace(importObjReg, (matched, envKey) => matched.replace(envKey, JSON.stringify(parsedEnv))); return { code, map: null }; } }, configResolved(config) { const { command } = config; try { isBuild = command === "build"; userConfig = config; parsedEnv = parseEnv(config.env, { parseJson, customParser, exclude }); if (!isBuild && dev || isBuild && build) { const { mode, envDir, root } = config; const baseEnvFilePath = import_node_path.default.resolve(envDir || root, `.env`); const modeFilePath = import_node_path.default.resolve(envDir || root, `.env.${mode}`); const localEnvFilePath = import_node_path.default.resolve(envDir || root, `.env.local`); const modeLocalFilePath = import_node_path.default.resolve(envDir || root, `.env.${mode}.local`); const modeEnvFileContent = import_node_fs2.default.existsSync(modeFilePath) && import_node_fs2.default.readFileSync(modeFilePath, "utf-8"); const modeLocalEnvFileContent = import_node_fs2.default.existsSync(modeLocalFilePath) && import_node_fs2.default.readFileSync(modeLocalFilePath, "utf-8"); const localEnvFileContent = import_node_fs2.default.existsSync(localEnvFilePath) && import_node_fs2.default.readFileSync(localEnvFilePath, "utf-8"); const baseEnvFileContent = import_node_fs2.default.existsSync(baseEnvFilePath) && import_node_fs2.default.readFileSync(baseEnvFilePath, "utf-8"); const modeEnvCommentRecord = modeEnvFileContent ? parseEnvComment(modeEnvFileContent) : {}; const modeLocalCommentRecord = modeLocalEnvFileContent ? parseEnvComment(modeLocalEnvFileContent) : {}; const localEnvCommentRecord = localEnvFileContent ? parseEnvComment(localEnvFileContent) : {}; const baseEnvCommentRecord = baseEnvFileContent ? parseEnvComment(baseEnvFileContent) : {}; const envCommentRecord = { ...baseEnvCommentRecord, ...localEnvCommentRecord, ...modeEnvCommentRecord, ...modeLocalCommentRecord }; const envInterface = generateEnvInterface(parsedEnv, envCommentRecord); envInterface && writeEnvInterface(import_node_path.default.resolve(root, dtsPath), envInterface); } if (!isBuild && dev) { Object.defineProperty(config, "env", { get() { return parsedEnv; } }); } } catch (error) { errorLog(error.message); } } }; } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { envParse, parseLoadedEnv });