UNPKG

vike

Version:

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

125 lines (124 loc) 6.64 kB
// Files loaded at config time: export { loadPointerImport }; export { loadValueFile }; export { loadConfigFile }; import { assert, assertUsage, assertIsNotProductionRuntime, isArrayOfStrings, isObject } from '../../utils.js'; import { transpileAndExecuteFile } from './transpileAndExecuteFile.js'; import { getConfigDefinitionOptional } from '../resolveVikeConfigInternal.js'; import { assertPlusFileExport } from '../../../../shared/page-configs/assertPlusFileExport.js'; import pc from '@brillout/picocolors'; import { parsePointerImportData } from './pointerImports.js'; import { getConfigFileExport } from './getConfigFileExport.js'; import { resolvePointerImportData } from './resolvePointerImport.js'; import { getConfigDefinedAt } from '../../../../shared/page-configs/getConfigDefinedAt.js'; assertIsNotProductionRuntime(); // Load pointer import async function loadPointerImport(pointerImport, userRootDir, configName, configDefinitions, esbuildCache) { // The value of `extends` was already loaded and already used: we don't need the value of `extends` anymore if (configName === 'extends') return; const configDef = getConfigDefinitionOptional(configDefinitions, configName); // Only load pointer import if `env.config===true` if (!configDef || !shouldBeLoadableAtBuildTime(configDef)) return; const configDefinedAt = getConfigDefinedAt('Config', configName, pointerImport.fileExportPath); assertUsage(pointerImport.fileExportPath.filePathAbsoluteFilesystem, `${configDefinedAt} cannot be defined over an aliased import`); const { fileExports } = await transpileAndExecuteFile(pointerImport.fileExportPath, userRootDir, false, esbuildCache); const fileExportValue = fileExports[pointerImport.fileExportPath.fileExportName]; pointerImport.fileExportValueLoaded = true; assert(pointerImport.fileExportValueLoaded); pointerImport.fileExportValue = fileExportValue; } // Load +{configName}.js async function loadValueFile(interfaceValueFile, configDefinitions, userRootDir, esbuildCache) { const { configName } = interfaceValueFile; const configDef = getConfigDefinitionOptional(configDefinitions, configName); // Only load value files with `env.config===true` if (!configDef || !shouldBeLoadableAtBuildTime(configDef)) return; interfaceValueFile.isNotLoaded = false; assert(!interfaceValueFile.isNotLoaded); interfaceValueFile.fileExportsByConfigName = {}; const { fileExports } = await transpileAndExecuteFile(interfaceValueFile.filePath, userRootDir, false, esbuildCache); const { filePathToShowToUser } = interfaceValueFile.filePath; assertPlusFileExport(fileExports, filePathToShowToUser, configName); Object.entries(fileExports).forEach(([exportName, configValue]) => { const configName_ = exportName === 'default' ? configName : exportName; interfaceValueFile.fileExportsByConfigName[configName_] = configValue; }); } // Load +config.js, including all its extends pointer imports async function loadConfigFile(configFilePath, userRootDir, visited, isExtensionConfig, esbuildCache) { const { filePathAbsoluteFilesystem } = configFilePath; assertNoInfiniteLoop(visited, filePathAbsoluteFilesystem); const { fileExports } = await transpileAndExecuteFile(configFilePath, userRootDir, isExtensionConfig, esbuildCache); const { extendsConfigs, extendsFilePaths } = await loadExtendsConfigs(fileExports, configFilePath, userRootDir, [...visited, filePathAbsoluteFilesystem], esbuildCache); const configFile = { fileExports, filePath: configFilePath, extendsFilePaths, }; return { configFile, extendsConfigs }; } function assertNoInfiniteLoop(visited, filePathAbsoluteFilesystem) { const idx = visited.indexOf(filePathAbsoluteFilesystem); if (idx === -1) return; const loop = visited.slice(idx); assert(loop[0] === filePathAbsoluteFilesystem); assertUsage(idx === -1, `Infinite extends loop ${[...loop, filePathAbsoluteFilesystem].join('>')}`); } async function loadExtendsConfigs(configFileExports, configFilePath, userRootDir, visited, esbuildCache) { const { extendsPointerImportData, extendsConfigs } = getExtendsPointerImportData(configFileExports, configFilePath); const extendsConfigFiles = []; extendsPointerImportData.map((pointerImportData) => { const filePath = resolvePointerImportData(pointerImportData, configFilePath, userRootDir); assert(filePath.filePathAbsoluteFilesystem); extendsConfigFiles.push(filePath); }); const results = await Promise.all(extendsConfigFiles.map(async (configFilePath) => await loadConfigFile(configFilePath, userRootDir, visited, true, esbuildCache))); results.forEach((result) => { extendsConfigs.push(result.configFile); extendsConfigs.push(...result.extendsConfigs); }); const extendsFilePaths = extendsConfigFiles.map((f) => f.filePathAbsoluteFilesystem); return { extendsConfigs, extendsFilePaths }; } function getExtendsPointerImportData(configFileExports, configFilePath) { const { filePathToShowToUser } = configFilePath; const configFileExport = getConfigFileExport(configFileExports, filePathToShowToUser); const extendsConfigs = []; const extendsPointerImportData = []; if ('extends' in configFileExport) { const extendsValue = configFileExport.extends; const extendList = []; const wrongUsage = `${filePathToShowToUser} sets the config ${pc.cyan('extends')} to an invalid value, see https://vike.dev/extends`; if (typeof extendsValue === 'string') { extendList.push(extendsValue); } else if (isArrayOfStrings(extendsValue)) { extendList.push(...extendsValue); } else if (isObject(extendsValue)) { /* If we want to implement this then we need to make filePath optional extendsConfigs.push({ fileExports: extendsValue, filePath: null, }) */ assertUsage(false, wrongUsage); } else { assertUsage(false, wrongUsage); } extendsPointerImportData.push(...extendList.map((importString) => { const pointerImportData = parsePointerImportData(importString); assertUsage(pointerImportData, wrongUsage); return pointerImportData; })); } return { extendsPointerImportData, extendsConfigs }; } function shouldBeLoadableAtBuildTime(configDef) { return !!configDef.env.config && !configDef._valueIsFilePath; }