UNPKG

vike

Version:

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

186 lines (182 loc) 8.15 kB
export { getVirtualFileEntry }; import { assert, assertPosixPath, scriptFileExtensionPattern, debugGlob, isVersionOrAbove, assertWarning, } from '../../utils.js'; import { isVirtualFileIdEntry } from '../../../shared/virtualFiles/virtualFileEntry.js'; import { version as viteVersion } from 'vite'; import { fileTypes } from '../../../../shared/getPageFiles/fileTypes.js'; import path from 'node:path'; import { getVirtualFilePageConfigsEager } from './getVirtualFilePageConfigsEager.js'; import { getVikeConfigInternal, isV1Design as isV1Design_ } from '../../shared/resolveVikeConfigInternal.js'; import { getOutDirs } from '../../shared/getOutDirs.js'; import { isViteServerBuild_options } from '../../shared/isViteServerBuild.js'; import { resolveIncludeAssetsImportedByServer } from '../../../runtime/renderPage/getPageAssets.js'; async function getVirtualFileEntry(id, options, config, isDev) { const idParsed = isVirtualFileIdEntry(id); assert(idParsed); const { isForClientSide, isClientRouting } = idParsed; assert(isForClientSide === !isViteServerBuild_options(options)); const code = await getCode(config, isForClientSide, isClientRouting, isDev, id); return code; } async function getCode(config, isForClientSide, isClientRouting, isDev, id) { const { command } = config; assert(command === 'serve' || command === 'build'); const isBuild = command === 'build'; assert(isDev === !isBuild); let content = ''; { const globRoots = getGlobRoots(config); debugGlob('Glob roots: ', globRoots); content += await generateGlobImports(globRoots, isBuild, isForClientSide, isClientRouting, isDev, id); } debugGlob(`Glob imports for ${isForClientSide ? 'client' : 'server'}:\n`, content); return content; } function determineInjection({ fileType, isForClientSide, isClientRouting, isPrerendering, isBuild, }) { if (!isForClientSide) { return { includeImport: fileType === '.page.server' || fileType === '.page' || fileType === '.page.route', includeExportNames: isPrerendering && isBuild ? fileType === '.page.client' || fileType === '.page.server' || fileType === '.page' // We extensively use `PageFile['exportNames']` while pre-rendering, in order to avoid loading page files unnecessarily, and therefore reducing memory usage. : fileType === '.page.client', }; } else { const includeImport = fileType === '.page.client' || fileType === '.css' || fileType === '.page'; if (!isClientRouting) { return { includeImport, includeExportNames: false, }; } else { return { includeImport: includeImport || fileType === '.page.route', includeExportNames: fileType === '.page.client' || fileType === '.page.server' || fileType === '.page', }; } } } async function generateGlobImports(globRoots, isBuild, isForClientSide, isClientRouting, isDev, id) { let fileContent = `// Generated by Vike export const pageFilesLazy = {}; export const pageFilesEager = {}; export const pageFilesExportNamesLazy = {}; export const pageFilesExportNamesEager = {}; export const pageFilesList = []; export const neverLoaded = {}; ${await getVirtualFilePageConfigsEager(isForClientSide, isDev, id, isClientRouting)} `; // We still use import.meta.glob() when using th V1 design in order to not break the V1 design deprecation warning const isV1Design = isV1Design_(); const vikeConfig = await getVikeConfigInternal(); // Old design => no + files => only to enable pre-rendering is setting `vike({prerender})` in vite.config.js const isPrerendering = !!vikeConfig.config.prerender; fileTypes .filter((fileType) => fileType !== '.css') .forEach((fileType) => { const { includeImport, includeExportNames } = determineInjection({ fileType, isForClientSide, isClientRouting, isPrerendering, isBuild, }); if (includeImport) { fileContent += getGlobs(globRoots, isBuild, fileType, null, isV1Design); } if (includeExportNames) { fileContent += getGlobs(globRoots, isBuild, fileType, 'extractExportNames', isV1Design); } }); const includeAssetsImportedByServer = resolveIncludeAssetsImportedByServer(vikeConfig.config); if (includeAssetsImportedByServer && isForClientSide) { fileContent += getGlobs(globRoots, isBuild, '.page.server', 'extractAssets', isV1Design); } return fileContent; } function getGlobs(globRoots, isBuild, fileType, query, isV1Design) { const isEager = isBuild && (query === 'extractExportNames' || fileType === '.page.route'); let pageFilesVar; if (query === 'extractExportNames') { if (!isEager) { pageFilesVar = 'pageFilesExportNamesLazy'; } else { pageFilesVar = 'pageFilesExportNamesEager'; } } else if (query === 'extractAssets') { assert(!isEager); pageFilesVar = 'neverLoaded'; } else if (!query) { if (!isEager) { pageFilesVar = 'pageFilesLazy'; } else { // Used for `.page.route.js` files pageFilesVar = 'pageFilesEager'; } } else { assert(false); } const varNameSuffix = (fileType === '.page' && 'Isomorph') || (fileType === '.page.client' && 'Client') || (fileType === '.page.server' && 'Server') || (fileType === '.page.route' && 'Route'); assert(varNameSuffix); const varName = `${pageFilesVar}${varNameSuffix}`; const varNameLocals = []; return [ ...globRoots.map((globRoot, i) => { const varNameLocal = `${varName}${i + 1}`; varNameLocals.push(varNameLocal); const globIncludePath = `'${getGlobPath(globRoot.includeDir, fileType)}'`; const globExcludePath = globRoot.excludeDir ? `'!${getGlobPath(globRoot.excludeDir, fileType)}'` : null; const globOptions = { eager: isEager }; if (query) { const isNewViteInterface = isVersionOrAbove(viteVersion, '5.1.0'); if (isNewViteInterface && // When used for the old design, the new syntax breaks Vike's CI (surprinsigly so). I couldn't reproduce locally (I didn't dig much). isV1Design) { globOptions.query = `?${query}`; } else { globOptions.as = query; const msg = [ "Update to the new V1 design to get rid of Vite's warning:", 'The glob option "as" has been deprecated in favour of "query".', 'See https://vike.dev/migration/v1-design for how to migrate.', ].join(' '); assertWarning(!isNewViteInterface, msg, { onlyOnce: true }); } } const globPaths = globExcludePath ? `[${globIncludePath}, ${globExcludePath}]` : `[${globIncludePath}]`; const globLine = `const ${varNameLocal} = import.meta.glob(${globPaths}, ${JSON.stringify(globOptions)});`; return globLine; }), `const ${varName} = {${varNameLocals.map((varNameLocal) => `...${varNameLocal}`).join(',')}};`, `${pageFilesVar}['${fileType}'] = ${varName};`, '', ].join('\n'); } function getGlobRoots(config) { const globRoots = [ { includeDir: '/', excludeDir: path.posix.relative(config.root, getOutDirs(config).outDirRoot), }, ]; return globRoots; } function getGlobPath(globRootDir, fileType) { assertPosixPath(globRootDir); let globPath = [...globRootDir.split('/'), '**', `*${fileType}.${scriptFileExtensionPattern}`] .filter(Boolean) .join('/'); if (!globPath.startsWith('/')) { globPath = '/' + globPath; } return globPath; }