UNPKG

@edgeone/astro

Version:

Astro adapter for EdgeOne Pages

181 lines 7.46 kB
/** * Dependency analysis and copy utilities */ import { cpSync, existsSync, mkdirSync, readdirSync } from 'node:fs'; import { dirname, join } from 'node:path'; import { nodeFileTrace } from '@vercel/nft'; import { globSync } from 'tinyglobby'; /** * Analyze dependencies via @vercel/nft and return package names and file list * @param cache - Optional NFT cache object to speed up repeated analysis */ export async function analyzeDependencies(rootDir, serverDir, serverEntryFile, logger, cache) { const entryFile = join(serverDir, serverEntryFile); const renderersFile = join(serverDir, 'renderers.mjs'); if (!existsSync(entryFile)) { logger.warn(`${serverEntryFile} not found, skipping dependency analysis`); return { packageNames: new Set(), fileList: new Set() }; } try { // Analyze dependencies with NFT const filesToAnalyze = [entryFile]; if (existsSync(renderersFile)) { filesToAnalyze.push(renderersFile); } // Include all .mjs entry files under the pages/ directory const pagesDir = join(serverDir, 'pages'); if (existsSync(pagesDir)) { const addPageFiles = (dir) => { const entries = readdirSync(dir, { withFileTypes: true }); for (const entry of entries) { const fullPath = join(dir, entry.name); if (entry.isDirectory()) { addPageFiles(fullPath); } else if (entry.isFile() && entry.name.endsWith('.mjs')) { filesToAnalyze.push(fullPath); } } }; addPageFiles(pagesDir); } const { fileList, warnings } = await nodeFileTrace(filesToAnalyze, { base: rootDir, processCwd: rootDir, ts: true, mixedModules: true, ...(cache && { cache }), // Use provided cache if available }); // Handle warnings // Use a single regex to aggregate package names (sharp and its optional family) const aggregateRegex = /^(?:@img\/sharp.*|sharp(?:-|$).*)$/; const aggregatedModules = new Set(); for (const warning of warnings) { if (warning.message.startsWith("Failed to resolve dependency")) { const match = /Cannot find module '(.+?)' loaded from (.+)/.exec(warning.message); if (match) { const [, module, file] = match; // Ignore Astro internal module resolution errors if (module === "@astrojs/") { continue; } // Aggregate matched modules, skip per-item printing if (aggregateRegex.test(module)) { aggregatedModules.add(module); continue; } // Log other unresolved modules as warnings logger.warn(`Module "${module}" couldn't be resolved from "${file}"`); } } else if (warning.message.startsWith("Failed to parse")) { // Skip parse errors continue; } else { // Log other warnings from NFT logger.warn(`NFT warning: ${warning.message}`); } } // Emit a single aggregated message if any matched modules exist if (aggregatedModules.size > 0) { const modulesList = Array.from(aggregatedModules).sort().join(', '); logger.warn(`Astro Image (sharp) is not supported on EdgeOne Pages runtime. The following optional image modules were skipped: ${modulesList}.`); } const packageNames = new Set(); // Extract package names (do not copy files here) for (const file of fileList) { if (file.startsWith('node_modules/')) { const parts = file.split('/'); if (parts[1].startsWith('@')) { // Scoped package: @scope/name if (parts.length >= 3) { packageNames.add(`${parts[1]}/${parts[2]}`); } } else { // Regular package: name packageNames.add(parts[1]); } } } return { packageNames, fileList: new Set(fileList) }; } catch (error) { logger.error(`Failed to analyze dependencies: ${error}`); return { packageNames: new Set(['astro']), fileList: new Set() }; } } /** * Copy dependencies */ export async function copyDependencies(rootDir, serverDir, fileList, logger, includeFiles = [], excludeFiles = []) { const copiedFiles = new Set(); let fileCount = 0; for (const file of fileList) { const sourcePath = join(rootDir, file); const targetPath = join(serverDir, file); // Skip files already under the server-handler directory if (sourcePath.startsWith(serverDir)) { continue; } // Only process node_modules and package.json files if (!file.startsWith('node_modules/') && !file.endsWith('package.json')) { continue; } // Apply excludeFiles patterns if (excludeFiles.length > 0) { const shouldExclude = excludeFiles.some(pattern => { const regex = new RegExp(pattern.replace(/\*\*/g, '.*').replace(/\*/g, '[^/]*')); return regex.test(file); }); if (shouldExclude) { continue; } } if (existsSync(sourcePath) && !copiedFiles.has(file)) { try { mkdirSync(dirname(targetPath), { recursive: true }); cpSync(sourcePath, targetPath, { force: true }); copiedFiles.add(file); fileCount++; } catch (e) { // Ignore individual file copy errors } } } // Handle includeFiles - force include patterns (from project root) if (includeFiles.length > 0) { const additionalFiles = new Set(); // Use glob to find matched files for (const pattern of includeFiles) { try { const matched = globSync(pattern, { cwd: rootDir, absolute: false }); matched.forEach(file => additionalFiles.add(file)); } catch (e) { logger.warn(`Failed to match pattern "${pattern}": ${e}`); } } // Copy additional files for (const file of additionalFiles) { if (!copiedFiles.has(file)) { const sourcePath = join(rootDir, file); const targetPath = join(serverDir, file); if (existsSync(sourcePath)) { try { mkdirSync(dirname(targetPath), { recursive: true }); cpSync(sourcePath, targetPath, { force: true }); copiedFiles.add(file); fileCount++; } catch (e) { logger.warn(`Failed to copy ${file}: ${e}`); } } } } } } //# sourceMappingURL=dependencies.js.map