UNPKG

vike

Version:

The Framework *You* Control - Next.js & Nuxt alternative for unprecedented flexibility and dependability.

95 lines (94 loc) 5.29 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.pluginEnvVars = pluginEnvVars; const magic_string_1 = __importDefault(require("magic-string")); const vite_1 = require("vite"); const utils_js_1 = require("../utils.js"); const getFilePath_js_1 = require("../shared/getFilePath.js"); const normalizeId_js_1 = require("../shared/normalizeId.js"); const isViteServerBuild_js_1 = require("../shared/isViteServerBuild.js"); const applyRegExWithMagicString_js_1 = require("../shared/applyRegExWithMagicString.js"); // TODO/enventually: // - Make import.meta.env work inside +config.js // - For it to work, we'll probably need the user to define the settings (e.g. `envDir`) for loadEnv() inside vike.config.js instead of vite.config.js // - Or stop using Vite's `mode` implementation and have Vike implement its own `mode` feature? (So that the only dependencies are `$ vike build --mode staging` and `$ MODE=staging vike build`.) const PUBLIC_ENV_PREFIX = 'PUBLIC_ENV__'; const PUBLIC_ENV_ALLOWLIST = [ // https://github.com/vikejs/vike/issues/1724 'STORYBOOK', ]; function pluginEnvVars() { let envsAll; let config; return { name: 'vike:pluginEnvVars', enforce: 'post', configResolved(config_) { config = config_; envsAll = (0, vite_1.loadEnv)(config.mode, config.envDir || config.root, ''); config.plugins.sort((0, utils_js_1.lowerFirst)((plugin) => (plugin.name === 'vite:define' ? 1 : 0))); }, transform(code, id, options) { id = (0, normalizeId_js_1.normalizeId)(id); (0, utils_js_1.assertPosixPath)(id); if (id.includes('/node_modules/')) return; (0, utils_js_1.assertPosixPath)(config.root); if (!id.startsWith(config.root)) return; if (!code.includes('import.meta.env.')) return; const isBuild = config.command === 'build'; const isClientSide = !(0, isViteServerBuild_js_1.isViteServerBuild_safe)(config, options); const magicString = new magic_string_1.default(code); // Find & check const replacements = Object.entries(envsAll) .filter(([key]) => { // Already handled by Vite const envPrefix = !config.envPrefix ? [] : (0, utils_js_1.isArray)(config.envPrefix) ? config.envPrefix : [config.envPrefix]; return !envPrefix.some((prefix) => key.startsWith(prefix)); }) .map(([envName, envVal]) => { const envStatement = `import.meta.env.${envName}`; const envStatementRegExpStr = (0, utils_js_1.escapeRegex)(envStatement) + '\\b'; // Security check { const isPrivate = !envName.startsWith(PUBLIC_ENV_PREFIX) && !PUBLIC_ENV_ALLOWLIST.includes(envName); if (isPrivate && isClientSide) { if (!new RegExp(envStatementRegExpStr).test(code)) return; const modulePath = (0, getFilePath_js_1.getModuleFilePathAbsolute)(id, config); const errMsgAddendum = isBuild ? '' : ' (Vike will prevent your app from building for production)'; const keyPublic = `${PUBLIC_ENV_PREFIX}${envName}`; const errMsg = `${envStatement} is used in client-side file ${modulePath} which means that the environment variable ${envName} will be included in client-side bundles and, therefore, ${envName} will be publicly exposed which can be a security leak${errMsgAddendum}. Use ${envStatement} only in server-side files, or rename ${envName} to ${keyPublic}, see https://vike.dev/env`; if (isBuild) { (0, utils_js_1.assertUsage)(false, errMsg); } else { // - Only a warning for faster development DX (e.g. when user toggles `ssr: boolean` or `onBeforeRenderIsomorph: boolean`). // - But only showing a warning can be confusing: https://github.com/vikejs/vike/issues/1641 (0, utils_js_1.assertWarning)(false, errMsg, { onlyOnce: true }); } } // Double check (0, utils_js_1.assert)(!(isPrivate && isClientSide) || !isBuild); } return { regExpStr: envStatementRegExpStr, replacement: envVal }; }) .filter(utils_js_1.isNotNullish); // Apply replacements.forEach(({ regExpStr, replacement }) => { (0, applyRegExWithMagicString_js_1.applyRegExpWithMagicString)(magicString, regExpStr, replacement); }); if (!magicString.hasChanged()) return null; return { code: magicString.toString(), map: magicString.generateMap({ hires: true, source: id }), }; }, }; }