UNPKG

vike

Version:

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

183 lines (179 loc) 8.21 kB
export { getVirtualFileImportUserCode }; import { assert, assertPosixPath, scriptFileExtensions, debugGlob, isVersionOrAbove, assertWarning } from '../../utils.js'; import { isVirtualFileIdImportUserCode } from '../../../shared/virtual-files/virtualFileImportUserCode.js'; import { version as viteVersion } from 'vite'; import { fileTypes } from '../../../../shared/getPageFiles/fileTypes.js'; import path from 'path'; import { getVirtualFilePageConfigs } from './v1-design/virtual-files/getVirtualFilePageConfigs.js'; import { isV1Design as isV1Design_ } from './v1-design/getVikeConfig.js'; import { getOutDirs } from '../../shared/getOutDirs.js'; import { isViteServerBuild_options } from '../../shared/isViteServerBuild.js'; async function getVirtualFileImportUserCode(id, options, vikeConfig, config, isDev) { const idParsed = isVirtualFileIdImportUserCode(id); assert(idParsed); const { isForClientSide, isClientRouting } = idParsed; assert(isForClientSide === !isViteServerBuild_options(options)); const code = await getCode(config, vikeConfig, isForClientSide, isClientRouting, isDev, id); return code; } async function getCode(config, vikeConfig, 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, vikeConfig, config, 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, vikeConfig, config, isDev, id) { let fileContent = `// Generated by https://github.com/vikejs/vike/blob/main/vike/node/plugin/plugins/importUserCode/getVirtualFileImportUserCode.ts export const pageFilesLazy = {}; export const pageFilesEager = {}; export const pageFilesExportNamesLazy = {}; export const pageFilesExportNamesEager = {}; export const pageFilesList = []; export const neverLoaded = {}; ${await getVirtualFilePageConfigs(isForClientSide, isDev, id, isClientRouting, config)} `; // We still use import.meta.glob() when using th V1 design in order to not break the V1 design deprecation warning const isV1Design = isV1Design_(config); // Old design => no + files => only to enable pre-rendering is setting `vike({prerender})` in vite.config.js const isPrerendering = !!vikeConfig.global.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); } }); // TODO/now: add meta.default const includeAssetsImportedByServer = vikeConfig.global.config.includeAssetsImportedByServer ?? true; 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}.${scriptFileExtensions}`].filter(Boolean).join('/'); if (!globPath.startsWith('/')) { globPath = '/' + globPath; } return globPath; }