Files
Fluxup_PAP/node_modules/babel-preset-expo/build/server-data-loaders-plugin.js
2026-03-10 16:18:05 +00:00

148 lines
6.9 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.serverDataLoadersPlugin = serverDataLoadersPlugin;
const common_1 = require("./common");
const debug = require('debug')('expo:babel:server-data-loaders');
const LOADER_EXPORT_NAME = 'loader';
function serverDataLoadersPlugin(api) {
const { types: t } = api;
const routerAbsoluteRoot = api.caller(common_1.getExpoRouterAbsoluteAppRoot);
const isLoaderBundle = api.caller(common_1.getIsLoaderBundle);
return {
name: 'expo-server-data-loaders',
visitor: {
ExportDefaultDeclaration(path, state) {
// Early exit if file is not within the `app/` directory
if (!isInAppDirectory(state.file.opts.filename ?? '', routerAbsoluteRoot)) {
return;
}
// Only remove default exports in loader-only bundles
if (!isLoaderBundle) {
return;
}
debug('Loader bundle: removing default export from', state.file.opts.filename);
markForConstantFolding(state);
path.remove();
},
ExportNamedDeclaration(path, state) {
// Early exit if file is not within the `app/` directory
if (!isInAppDirectory(state.file.opts.filename ?? '', routerAbsoluteRoot)) {
debug('Skipping file outside app directory:', state.file.opts.filename);
return;
}
debug(`Processing ${isLoaderBundle ? 'loader' : 'client'} bundle:`, state.file.opts.filename);
const { declaration, specifiers } = path.node;
// Is this a type export like `export type Foo`?
const isTypeExport = path.node.exportKind === 'type';
// NOTE(@hassankhan): We should add proper handling for specifiers too
const hasSpecifiers = specifiers.length > 0;
if (isTypeExport || hasSpecifiers) {
return;
}
// Handles `export function loader() { ... }`
if (t.isFunctionDeclaration(declaration)) {
const name = declaration.id?.name;
if (name && isLoaderIdentifier(name)) {
// Mark the file as having a loader (for all bundle types)
markWithLoaderReference(state);
if (!isLoaderBundle) {
// Client bundles: remove loader
debug('Found and removed loader function declaration');
markForConstantFolding(state);
path.remove();
}
// Loader bundle: keep the loader
}
else if (name && isLoaderBundle) {
// Loader bundle: remove non-loader function declarations
debug('Loader bundle: removing non-loader function declaration:', name);
markForConstantFolding(state);
path.remove();
}
}
// Handles `export const loader = ...`
if (t.isVariableDeclaration(declaration)) {
let hasModified = false;
// Check if any declaration is a loader
const hasLoaderDeclaration = declaration.declarations.some((declarator) => {
const name = t.isIdentifier(declarator.id) ? declarator.id.name : null;
return name && isLoaderIdentifier(name);
});
// Mark the file as having a loader (for all bundle types)
if (hasLoaderDeclaration) {
markWithLoaderReference(state);
}
if (isLoaderBundle) {
// Loader bundle: keep only loader declarations, remove others
declaration.declarations = declaration.declarations.filter((declarator) => {
const name = t.isIdentifier(declarator.id) ? declarator.id.name : null;
if (name && !isLoaderIdentifier(name)) {
debug('Loader bundle: removing non-loader variable declaration:', name);
hasModified = true;
return false;
}
return true;
});
}
else {
// Client bundles: remove loader declarations
declaration.declarations = declaration.declarations.filter((declarator) => {
const name = t.isIdentifier(declarator.id) ? declarator.id.name : null;
if (name && isLoaderIdentifier(name)) {
debug('Found and removed loader variable declaration');
hasModified = true;
return false;
}
return true;
});
}
if (hasModified) {
markForConstantFolding(state);
// If all declarations were removed, remove the export
if (declaration.declarations.length === 0) {
path.remove();
}
}
}
},
},
};
}
/**
* Checks if identifier name is `loader`
*/
function isLoaderIdentifier(name) {
return name === LOADER_EXPORT_NAME;
}
function assertExpoMetadata(metadata) {
if (metadata && typeof metadata === 'object') {
return;
}
throw new Error('Expected Babel state.file.metadata to be an object');
}
/**
* Check if file is within the `app/` directory
*/
function isInAppDirectory(filePath, routerRoot) {
const normalizedFilePath = (0, common_1.toPosixPath)(filePath);
const normalizedAppRoot = (0, common_1.toPosixPath)(routerRoot);
return normalizedFilePath.startsWith(normalizedAppRoot + '/');
}
/**
* Marks a file for Metro's constant folding. This will work for both development and production bundles.
*
* @see packages/@expo/metro-config/src/transform-worker/metro-transform-worker.ts#transformJS
*/
function markForConstantFolding(state) {
assertExpoMetadata(state.file.metadata);
state.file.metadata.performConstantFolding = true;
}
/**
* Sets the `loaderReference` metadata to the file path. This is used to collect all modules with
* loaders in the Metro serializer.
*/
function markWithLoaderReference(state) {
assertExpoMetadata(state.file.metadata);
state.file.metadata.loaderReference = state.file.opts.filename ?? undefined;
}