UNPKG

vike

Version:

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

291 lines (290 loc) 13.4 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.serializeConfigValues = serializeConfigValues; exports.getConfigValuesBase = getConfigValuesBase; exports.isJsonValue = isJsonValue; const assertSetup_js_1 = require("../../../utils/assertSetup.js"); const utils_js_1 = require("../../../node/plugin/utils.js"); const pointerImports_js_1 = require("../../../node/plugin/plugins/importUserCode/v1-design/getVikeConfig/pointerImports.js"); const helpers_js_1 = require("../helpers.js"); const stringify_1 = require("@brillout/json-serializer/stringify"); const picocolors_1 = __importDefault(require("@brillout/picocolors")); const getVikeConfig_js_1 = require("../../../node/plugin/plugins/importUserCode/v1-design/getVikeConfig.js"); const stringifyOptions = { forbidReactElements: true }; const REPLACE_ME_BEFORE = '__VIKE__REPLACE_ME_BEFORE__'; const REPLACE_ME_AFTER = '__VIKE__REPLACE_ME_AFTER__'; // This file is never loaded on the client-side but we save it under the vike/shared/ directory in order to collocate it with parsePageConfigs() // - vike/shared/page-configs/serialize/parsePageConfigs.ts // - parsePageConfigs() is loaded on both the client- and server-side. (0, assertSetup_js_1.assertIsNotProductionRuntime)(); function serializeConfigValues(pageConfig, importStatements, filesEnv, isEnvMatch, tabspace, isEager) { const lines = []; tabspace += ' '; getConfigValuesBase(pageConfig, isEnvMatch, isEager).forEach((entry) => { if (entry.configValueBase.type === 'computed') { (0, utils_js_1.assert)('value' in entry); // Help TS const { configValueBase, value, configName, configEnv } = entry; const valueData = getValueSerializedWithJson(value, configName, configValueBase.definedAtData, importStatements, filesEnv, configEnv); serializeConfigValue(configValueBase, valueData, configName, lines, tabspace); } if (entry.configValueBase.type === 'standard') { (0, utils_js_1.assert)('sourceRelevant' in entry); // Help TS const { configValueBase, sourceRelevant, configName } = entry; const valueData = getValueSerializedFromSource(sourceRelevant, configName, importStatements, filesEnv); serializeConfigValue(configValueBase, valueData, configName, lines, tabspace); } if (entry.configValueBase.type === 'cumulative') { (0, utils_js_1.assert)('sourcesRelevant' in entry); // Help TS const { configValueBase, sourcesRelevant, configName } = entry; const valueDataList = []; sourcesRelevant.forEach((source) => { const valueData = getValueSerializedFromSource(source, configName, importStatements, filesEnv); valueDataList.push(valueData); }); serializeConfigValue(configValueBase, valueDataList, configName, lines, tabspace); } }); return lines; } function getValueSerializedFromSource(configValueSource, configName, importStatements, filesEnv) { let valueData; if (configValueSource.valueIsLoaded && !configValueSource.valueIsLoadedWithImport) { valueData = getValueSerializedWithJson(configValueSource.value, configName, configValueSource.definedAt, importStatements, filesEnv, configValueSource.configEnv); } else { valueData = getValueSerializedWithImport(configValueSource, importStatements, filesEnv, configName); } return valueData; } function serializeConfigValue(configValueBase, valueData, configName, lines, tabspace) { lineAdd(`[${JSON.stringify(configName)}]: {`); { tab(); lineAdd(`type: "${configValueBase.type}",`); lineAdd(`definedAtData: ${JSON.stringify(configValueBase.definedAtData)},`); lineAdd(`valueSerialized:`); if (!Array.isArray(valueData)) { serializeValueData(valueData); } else { lineAppend(' ['); valueData.forEach(serializeValueData); lineAppend(` ],`); } untab(); } lineAdd('},'); return; function serializeValueData(valueData) { lineAppend(` {`); tab(); lineAdd(`type: "${valueData.type}",`); const valueProp = valueData.type !== 'plus-file' ? 'value' : 'exportValues'; lineAdd(`${valueProp}: ${valueData.valueAsJsCode},`); untab(); lineAdd(`},`); } function lineAppend(str) { const i = lines.length - 1; lines[i] = lines[i] += str; } function lineAdd(str) { lines.push(`${tabspace}${str}`); } function tab() { tabspace += ' '; } function untab() { tabspace = tabspace.slice(2); } } function getValueSerializedWithImport(configValueSource, importStatements, filesEnv, configName) { (0, utils_js_1.assert)(!configValueSource.valueIsFilePath); const { valueIsDefinedByPlusValueFile, definedAt, configEnv } = configValueSource; (0, utils_js_1.assert)(!definedAt.definedBy); const { filePathAbsoluteVite, fileExportName } = definedAt; if (valueIsDefinedByPlusValueFile) (0, utils_js_1.assert)(fileExportName === undefined); const { importName } = addImportStatement(importStatements, filePathAbsoluteVite, fileExportName || '*', filesEnv, configEnv, configName); return { type: valueIsDefinedByPlusValueFile ? 'plus-file' : 'pointer-import', valueAsJsCode: importName }; } function getValueSerializedWithJson(value, configName, definedAtData, importStatements, filesEnv, configEnv) { const valueAsJsCode = valueToJson(value, configName, definedAtData, importStatements, filesEnv, configEnv); return { type: 'js-serialized', valueAsJsCode }; } function valueToJson(value, configName, definedAtData, importStatements, filesEnv, configEnv) { const valueName = `config${(0, utils_js_1.getPropAccessNotation)(configName)}`; let configValueSerialized; try { configValueSerialized = (0, stringify_1.stringify)(value, { valueName, ...stringifyOptions, // Replace import strings with import variables. // - We don't need this anymore and could remove it. // - We temporarily needed it for nested document configs (`config.document.{title,description,favicon}`), but we finally decided to go for flat document configs instead (`config.{title,description,favicon}`). // - https://github.com/vikejs/vike-react/pull/113 replacer(_, value) { if (typeof value === 'string') { const importData = (0, pointerImports_js_1.parsePointerImportData)(value); if (importData) { const { importName } = addImportStatement(importStatements, importData.importPath, importData.exportName, filesEnv, configEnv, configName); const replacement = [REPLACE_ME_BEFORE, importName, REPLACE_ME_AFTER].join(''); return { replacement }; } } } }); } catch (err) { logJsonSerializeError(err, configName, definedAtData); (0, utils_js_1.assert)(false); } configValueSerialized = configValueSerialized.replaceAll(`"${REPLACE_ME_BEFORE}`, ''); configValueSerialized = configValueSerialized.replaceAll(`${REPLACE_ME_AFTER}"`, ''); (0, utils_js_1.assert)(!configValueSerialized.includes(REPLACE_ME_BEFORE)); (0, utils_js_1.assert)(!configValueSerialized.includes(REPLACE_ME_AFTER)); return configValueSerialized; } function isJsonValue(value) { try { (0, stringify_1.stringify)(value, stringifyOptions); } catch (err) { return false; } return true; } function logJsonSerializeError(err, configName, definedAtData) { /* // import { isJsonSerializerError } from '@brillout/json-serializer/stringify' let serializationErrMsg = '' if (isJsonSerializerError(err)) { serializationErrMsg = err.messageCore } else { // When a property getter throws an error console.error('Serialization error:') console.error(err) serializationErrMsg = 'see serialization error printed above' } //*/ const configValueFilePathToShowToUser = (0, helpers_js_1.getConfigValueFilePathToShowToUser)(definedAtData); (0, utils_js_1.assert)(configValueFilePathToShowToUser); (0, utils_js_1.assertUsage)(false, `${picocolors_1.default.cyan(configName)} defined by ${configValueFilePathToShowToUser} must be defined over a so-called "pointer import", see https://vike.dev/config#pointer-imports`); } function getConfigValuesBase(pageConfig, isEnvMatch, isEager) { const fromComputed = Object.entries(pageConfig.configValuesComputed ?? {}).map(([configName, valueInfo]) => { const { configEnv, value } = valueInfo; if (!isEnvMatch(configEnv)) return 'SKIP'; // Is there a use case for overriding computed values? If yes, then configValeSources has higher precedence if (pageConfig.configValueSources[configName]) return 'SKIP'; const configValueBase = { type: 'computed', definedAtData: null }; return { configValueBase, value, configName, configEnv }; }); const fromSources = Object.entries(pageConfig.configValueSources).map(([configName, sources]) => { const configDef = pageConfig.configDefinitions[configName]; (0, utils_js_1.assert)(configDef); if (isEager !== null && isEager !== !!configDef.eager) return 'SKIP'; if (!configDef.cumulative) { const source = sources[0]; (0, utils_js_1.assert)(source); if (!isEnvMatch(source.configEnv)) return 'SKIP'; const definedAtFile = getDefinedAtFileSource(source); const configValueBase = { type: 'standard', definedAtData: definedAtFile }; return { configValueBase, sourceRelevant: source, configName }; } else { const sourcesRelevant = sources .filter((source) => !(0, getVikeConfig_js_1.isOverriden)(source, configName, pageConfig)) .filter((source) => isEnvMatch(source.configEnv)); if (sourcesRelevant.length === 0) return 'SKIP'; const definedAtData = []; sourcesRelevant.forEach((source) => { const definedAtFile = getDefinedAtFileSource(source); definedAtData.push(definedAtFile); }); const configValueBase = { type: 'cumulative', definedAtData }; return { configValueBase, sourcesRelevant, configName }; } }); return [...fromComputed, ...fromSources].filter((r) => r !== 'SKIP'); } function getDefinedAtFileSource(source) { const { definedAt } = source; if (definedAt.definedBy) return definedAt; const definedAtFile = { filePathToShowToUser: definedAt.filePathToShowToUser, fileExportPathToShowToUser: definedAt.fileExportPathToShowToUser }; return definedAtFile; } /* * Naming: * `import { someExport as someImport } from './some-file'` * <=> * `{` * `importPath: './some-file',` * `exportName: 'someExport',` * `importName: 'someImport',` * `}` */ function addImportStatement(importStatements, importPath, exportName, filesEnv, configEnv, configName) { const importCounter = importStatements.length + 1; const importName = `import${importCounter}`; const importLiteral = (() => { if (exportName === '*') { return `* as ${importName}`; } if (exportName === 'default') { return importName; } return `{ ${exportName} as ${importName} }`; })(); const importStatement = `import ${importLiteral} from '${importPath}';`; importStatements.push(importStatement); assertFileEnv(importPath, configEnv, configName, filesEnv); return { importName }; } function assertFileEnv(importPath, configEnv, configName, filesEnv) { (0, utils_js_1.assert)(!(0, utils_js_1.isImportPathRelative)(importPath)); const key = importPath; (0, utils_js_1.assert)(key); (0, utils_js_1.assertPosixPath)(key); if (!filesEnv.has(key)) { filesEnv.set(key, []); } const fileEnvs = filesEnv.get(key); const fileEnvNew = { configEnv, configName }; fileEnvs.push(fileEnvNew); const fileEnvDiff = fileEnvs.filter((c) => !(0, utils_js_1.deepEqual)(c.configEnv, configEnv))[0]; if (fileEnvDiff) { (0, utils_js_1.assertUsage)(false, [ `${importPath} defines the value of configs living in different environments:`, ...[fileEnvDiff, fileEnvNew].map((c) => ` - config ${picocolors_1.default.code(c.configName)} which value lives in environment ${picocolors_1.default.code(JSON.stringify(c.configEnv))}`), 'Defining config values in the same file is allowed only if they live in the same environment, see https://vike.dev/config#pointer-imports' ].join('\n')); } }