feat(smart-app): implement complete mobile app MVP

- App.tsx: full navigation (Auth stack + Main tabs with 5 screens)
- Auth: LoginScreen, RegisterScreen, ForgotPasswordScreen
- HomeScreen: dashboard with IoT metrics, weather widget, alerts, quick actions, sensors
- MapScreen: interactive map with layer toggles (6 layers)
- MarketplaceScreen: categories (6), products (5), search
- ChatScreen: AI chat with quick prompts (4), bot responses
- ProfileScreen: user info, stats, menu (9 items), logout
- AlertsScreen: alert list with severity, acknowledge
- SensorsScreen: sensor list with type filters (6 types), search
- ZonesScreen: zone cards with stats
- SettingsScreen: language picker (FR/EN/ES/DE), privacy, about
- Stores: iotStore (sensors, zones, alerts), notificationStore, uiStore + i18n
- Hooks: useSensors, useAlerts, useNotifications, useLocation
- Components: Card, Button, LoadingSpinner, ErrorBoundary, Header
- Services: iotService, notificationService (with axios API client)
- Utils: formatters (temp, AQI, noise, dates), validators (email, password, IBAN)
- Theme: colors.ts with full design system (Blue Ocean palette)
- Ditto: fixed MongoDB connection, new JWT secrets, official gateway image
This commit is contained in:
Eric FELIXINE
2026-06-01 18:00:35 -04:00
parent 08ca495bde
commit e30ae8ed09
35578 changed files with 3703534 additions and 43 deletions

View File

@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015-present 650 Industries, Inc. (aka Expo)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,23 @@
# `@expo/metro-config`
This package contains the default Metro config that is required for bundling apps with Expo CLI. Refer to the [Expo `metro.config.js` docs](https://docs.expo.dev/versions/latest/config/metro/) to learn more.
`metro.config.js`
```js
// Learn more https://docs.expo.io/guides/customizing-metro
const { getDefaultConfig } = require('expo/metro-config');
/** @type {import('expo/metro-config').MetroConfig} */
const config = getDefaultConfig(__dirname);
module.exports = config;
```
## Exotic
> As of SDK 51, the exotic transformer has been fully removed in favor of the default `@expo/metro-config` transformer. The export `@expo/metro-config/transformer` no longer exists.
Most of the [Exotic mode](https://blog.expo.dev/drastically-faster-bundling-in-react-native-a54f268e0ed1) performance benefits have been integrated in the default Expo CLI bundling pipeline (e.g. [less AST cloning](https://github.com/facebook/metro/pull/854), [faster worker creation](https://github.com/facebook/metro/pull/856)), and as such, the feature no longer needs to be enabled/disabled. Setting `mode: "exotic"` will no longer have any additional effects over the default.
Ensure you extend the `@expo/metro-config/babel-transformer` when customizing babel. Learn more: [Extending the Babel transformer](https://docs.expo.dev/versions/latest/config/metro/#extending-the-babel-transformer).

View File

@@ -0,0 +1 @@
export * from '../build/babel-transformer';

View File

@@ -0,0 +1 @@
module.exports = require('../build/babel-transformer');

View File

@@ -0,0 +1,35 @@
import { MixedOutput, Module, ReadOnlyGraph, Reporter } from 'metro';
import { ConfigT as MetroConfig, InputConfigT } from 'metro-config';
import { INTERNAL_CALLSITES_REGEX } from './customizeFrame';
export interface LoadOptions {
config?: string;
maxWorkers?: number;
port?: number;
reporter?: Reporter;
resetCache?: boolean;
}
export interface DefaultConfigOptions {
/** @deprecated */
mode?: 'exotic';
/**
* **Experimental:** Enable CSS support for Metro web, and shim on native.
*
* This is an experimental feature and may change in the future. The underlying implementation
* is subject to change, and native support for CSS Modules may be added in the future during a non-major SDK release.
*/
isCSSEnabled?: boolean;
/**
* **Experimental:** Modify premodules before a code asset is serialized
*
* This is an experimental feature and may change in the future. The underlying implementation
* is subject to change.
*/
unstable_beforeAssetSerializationPlugins?: ((serializationInput: {
graph: ReadOnlyGraph<MixedOutput>;
premodules: Module[];
debugId?: string;
}) => Module[])[];
}
export declare function getDefaultConfig(projectRoot: string, { mode, isCSSEnabled, unstable_beforeAssetSerializationPlugins }?: DefaultConfigOptions): InputConfigT;
export { MetroConfig, INTERNAL_CALLSITES_REGEX };
export declare const EXPO_DEBUG: boolean;

View File

@@ -0,0 +1,270 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.EXPO_DEBUG = exports.INTERNAL_CALLSITES_REGEX = exports.getDefaultConfig = void 0;
// Copyright 2023-present 650 Industries (Expo). All rights reserved.
const config_1 = require("@expo/config");
const paths_1 = require("@expo/config/paths");
const runtimeEnv = __importStar(require("@expo/env"));
const json_file_1 = __importDefault(require("@expo/json-file"));
const chalk_1 = __importDefault(require("chalk"));
const metro_cache_1 = require("metro-cache");
const os_1 = __importDefault(require("os"));
const path_1 = __importDefault(require("path"));
const resolve_from_1 = __importDefault(require("resolve-from"));
const customizeFrame_1 = require("./customizeFrame");
Object.defineProperty(exports, "INTERNAL_CALLSITES_REGEX", { enumerable: true, get: function () { return customizeFrame_1.INTERNAL_CALLSITES_REGEX; } });
const env_1 = require("./env");
const file_store_1 = require("./file-store");
const getModulesPaths_1 = require("./getModulesPaths");
const getWatchFolders_1 = require("./getWatchFolders");
const rewriteRequestUrl_1 = require("./rewriteRequestUrl");
const withExpoSerializers_1 = require("./serializer/withExpoSerializers");
const postcss_1 = require("./transform-worker/postcss");
const metro_config_1 = require("./traveling/metro-config");
const debug = require('debug')('expo:metro:config');
function getAssetPlugins(projectRoot) {
const hashAssetFilesPath = resolve_from_1.default.silent(projectRoot, 'expo-asset/tools/hashAssetFiles');
if (!hashAssetFilesPath) {
throw new Error(`The required package \`expo-asset\` cannot be found`);
}
return [hashAssetFilesPath];
}
let hasWarnedAboutExotic = false;
// Patch Metro's graph to support always parsing certain modules. This enables
// things like Tailwind CSS which update based on their own heuristics.
function patchMetroGraphToSupportUncachedModules() {
const { Graph } = require('metro/src/DeltaBundler/Graph');
const original_traverseDependencies = Graph.prototype.traverseDependencies;
if (!original_traverseDependencies.__patched) {
original_traverseDependencies.__patched = true;
Graph.prototype.traverseDependencies = function (paths, options) {
this.dependencies.forEach((dependency) => {
// Find any dependencies that have been marked as `skipCache` and ensure they are invalidated.
// `skipCache` is set when a CSS module is found by PostCSS.
if (dependency.output.find((file) => file.data.css?.skipCache) &&
!paths.includes(dependency.path)) {
// Ensure we invalidate the `unstable_transformResultKey` (input hash) so the module isn't removed in
// the Graph._processModule method.
dependency.unstable_transformResultKey = dependency.unstable_transformResultKey + '.';
// Add the path to the list of modified paths so it gets run through the transformer again,
// this will ensure it is passed to PostCSS -> Tailwind.
paths.push(dependency.path);
}
});
// Invoke the original method with the new paths to ensure the standard behavior is preserved.
return original_traverseDependencies.call(this, paths, options);
};
// Ensure we don't patch the method twice.
Graph.prototype.traverseDependencies.__patched = true;
}
}
function getDefaultConfig(projectRoot, { mode, isCSSEnabled = true, unstable_beforeAssetSerializationPlugins } = {}) {
const { getDefaultConfig: getDefaultMetroConfig, mergeConfig } = (0, metro_config_1.importMetroConfig)(projectRoot);
if (isCSSEnabled) {
patchMetroGraphToSupportUncachedModules();
}
const isExotic = mode === 'exotic' || env_1.env.EXPO_USE_EXOTIC;
if (isExotic && !hasWarnedAboutExotic) {
hasWarnedAboutExotic = true;
console.log(chalk_1.default.gray(`\u203A Feature ${chalk_1.default.bold `EXPO_USE_EXOTIC`} has been removed in favor of the default transformer.`));
}
const reactNativePath = path_1.default.dirname((0, resolve_from_1.default)(projectRoot, 'react-native/package.json'));
const sourceExtsConfig = { isTS: true, isReact: true, isModern: true };
const sourceExts = (0, paths_1.getBareExtensions)([], sourceExtsConfig);
// Add support for cjs (without platform extensions).
sourceExts.push('cjs');
const reanimatedVersion = getPkgVersion(projectRoot, 'react-native-reanimated');
let sassVersion = null;
if (isCSSEnabled) {
sassVersion = getPkgVersion(projectRoot, 'sass');
// Enable SCSS by default so we can provide a better error message
// when sass isn't installed.
sourceExts.push('scss', 'sass', 'css');
}
const envFiles = runtimeEnv.getFiles(process.env.NODE_ENV, { silent: true });
const pkg = (0, config_1.getPackageJson)(projectRoot);
const watchFolders = (0, getWatchFolders_1.getWatchFolders)(projectRoot);
const nodeModulesPaths = (0, getModulesPaths_1.getModulesPaths)(projectRoot);
if (env_1.env.EXPO_DEBUG) {
console.log();
console.log(`Expo Metro config:`);
try {
console.log(`- Version: ${require('../package.json').version}`);
}
catch { }
console.log(`- Extensions: ${sourceExts.join(', ')}`);
console.log(`- React Native: ${reactNativePath}`);
console.log(`- Watch Folders: ${watchFolders.join(', ')}`);
console.log(`- Node Module Paths: ${nodeModulesPaths.join(', ')}`);
console.log(`- Env Files: ${envFiles}`);
console.log(`- Sass: ${sassVersion}`);
console.log(`- Reanimated: ${reanimatedVersion}`);
console.log();
}
const {
// Remove the default reporter which metro always resolves to be the react-native-community/cli reporter.
// This prints a giant React logo which is less accessible to users on smaller terminals.
reporter, ...metroDefaultValues } = getDefaultMetroConfig.getDefaultValues(projectRoot);
const cacheStore = new file_store_1.FileStore({
root: path_1.default.join(os_1.default.tmpdir(), 'metro-cache'),
});
const serverRoot = (0, getModulesPaths_1.getServerRoot)(projectRoot);
// Merge in the default config from Metro here, even though loadConfig uses it as defaults.
// This is a convenience for getDefaultConfig use in metro.config.js, e.g. to modify assetExts.
const metroConfig = mergeConfig(metroDefaultValues, {
watchFolders,
resolver: {
unstable_conditionsByPlatform: {
ios: ['react-native'],
android: ['react-native'],
// This is removed for server platforms.
web: ['browser'],
},
unstable_conditionNames: ['require', 'import'],
resolverMainFields: ['react-native', 'browser', 'main'],
platforms: ['ios', 'android'],
assetExts: metroDefaultValues.resolver.assetExts
.concat(
// Add default support for `expo-image` file types.
['heic', 'avif'],
// Add default support for `expo-sqlite` file types.
['db'])
.filter((assetExt) => !sourceExts.includes(assetExt)),
sourceExts,
nodeModulesPaths,
},
cacheStores: [cacheStore],
watcher: {
// strip starting dot from env files
additionalExts: envFiles.map((file) => file.replace(/^\./, '')),
},
serializer: {
getModulesRunBeforeMainModule: () => {
const preModules = [
// MUST be first
require.resolve(path_1.default.join(reactNativePath, 'Libraries/Core/InitializeCore')),
];
const stdRuntime = resolve_from_1.default.silent(projectRoot, 'expo/build/winter');
if (stdRuntime) {
preModules.push(stdRuntime);
}
// We need to shift this to be the first module so web Fast Refresh works as expected.
// This will only be applied if the module is installed and imported somewhere in the bundle already.
const metroRuntime = resolve_from_1.default.silent(projectRoot, '@expo/metro-runtime');
if (metroRuntime) {
preModules.push(metroRuntime);
}
return preModules;
},
getPolyfills: ({ platform }) => {
// Do nothing for nullish platforms.
if (!platform) {
return [];
}
if (platform === 'web') {
return [
// Ensure that the error-guard polyfill is included in the web polyfills to
// make metro-runtime work correctly.
require.resolve('@react-native/js-polyfills/error-guard'),
];
}
// Native behavior.
return require('@react-native/js-polyfills')();
},
},
server: {
rewriteRequestUrl: (0, rewriteRequestUrl_1.getRewriteRequestUrl)(projectRoot),
port: Number(env_1.env.RCT_METRO_PORT) || 8081,
// NOTE(EvanBacon): Moves the server root down to the monorepo root.
// This enables proper monorepo support for web.
unstable_serverRoot: serverRoot,
},
symbolicator: {
customizeFrame: (0, customizeFrame_1.getDefaultCustomizeFrame)(),
},
transformerPath: require.resolve('./transform-worker/transform-worker'),
transformer: {
// Custom: These are passed to `getCacheKey` and ensure invalidation when the version changes.
// @ts-expect-error: not on type.
unstable_renameRequire: false,
postcssHash: (0, postcss_1.getPostcssConfigHash)(projectRoot),
browserslistHash: pkg.browserslist
? (0, metro_cache_1.stableHash)(JSON.stringify(pkg.browserslist)).toString('hex')
: null,
sassVersion,
// Ensure invalidation when the version changes due to the Babel plugin.
reanimatedVersion,
// Ensure invalidation when using identical projects in monorepos
_expoRelativeProjectRoot: path_1.default.relative(serverRoot, projectRoot),
// `require.context` support
unstable_allowRequireContext: true,
allowOptionalDependencies: true,
babelTransformerPath: require.resolve('./babel-transformer'),
// See: https://github.com/facebook/react-native/blob/v0.73.0/packages/metro-config/index.js#L72-L74
asyncRequireModulePath: (0, resolve_from_1.default)(reactNativePath, metroDefaultValues.transformer.asyncRequireModulePath),
assetRegistryPath: '@react-native/assets-registry/registry',
assetPlugins: getAssetPlugins(projectRoot),
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: false,
},
}),
},
});
return (0, withExpoSerializers_1.withExpoSerializers)(metroConfig, { unstable_beforeAssetSerializationPlugins });
}
exports.getDefaultConfig = getDefaultConfig;
// re-export for legacy cases.
exports.EXPO_DEBUG = env_1.env.EXPO_DEBUG;
function getPkgVersion(projectRoot, pkgName) {
const targetPkg = resolve_from_1.default.silent(projectRoot, pkgName);
if (!targetPkg)
return null;
const targetPkgJson = findUpPackageJson(targetPkg);
if (!targetPkgJson)
return null;
const pkg = json_file_1.default.read(targetPkgJson);
debug(`${pkgName} package.json:`, targetPkgJson);
const pkgVersion = pkg.version;
if (typeof pkgVersion === 'string') {
return pkgVersion;
}
return null;
}
function findUpPackageJson(cwd) {
if (['.', path_1.default.sep].includes(cwd))
return null;
const found = resolve_from_1.default.silent(cwd, './package.json');
if (found) {
return found;
}
return findUpPackageJson(path_1.default.dirname(cwd));
}
//# sourceMappingURL=ExpoMetroConfig.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
export { type PluginItem, type TransformOptions, transformFromAstSync, transformSync, } from '@babel/core';

View File

@@ -0,0 +1,8 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformSync = exports.transformFromAstSync = void 0;
// re-exported because babel/core is hard to mock.
var core_1 = require("@babel/core");
Object.defineProperty(exports, "transformFromAstSync", { enumerable: true, get: function () { return core_1.transformFromAstSync; } });
Object.defineProperty(exports, "transformSync", { enumerable: true, get: function () { return core_1.transformSync; } });
//# sourceMappingURL=babel-core.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"babel-core.js","sourceRoot":"","sources":["../src/babel-core.ts"],"names":[],"mappings":";;;AAAA,kDAAkD;AAClD,oCAKqB;AAFnB,4GAAA,oBAAoB,OAAA;AACpB,qGAAA,aAAa,OAAA"}

View File

@@ -0,0 +1,17 @@
import type { TransformOptions } from './babel-core';
export type ExpoBabelCaller = TransformOptions['caller'] & {
supportsReactCompiler?: boolean;
isReactServer?: boolean;
isHMREnabled?: boolean;
isServer?: boolean;
isNodeModule?: boolean;
preserveEnvVars?: boolean;
isDev?: boolean;
asyncRoutes?: boolean;
baseUrl?: string;
engine?: string;
bundler?: 'metro' | (string & object);
platform?: string | null;
routerRoot?: string;
projectRoot: string;
};

View File

@@ -0,0 +1,135 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const node_assert_1 = __importDefault(require("node:assert"));
const loadBabelConfig_1 = require("./loadBabelConfig");
const transformSync_1 = require("./transformSync");
const debug = require('debug')('expo:metro-config:babel-transformer');
function isCustomTruthy(value) {
return value === true || value === 'true';
}
function memoize(fn) {
const cache = new Map();
return ((...args) => {
const key = JSON.stringify(args);
if (cache.has(key)) {
return cache.get(key);
}
const result = fn(...args);
cache.set(key, result);
return result;
});
}
const memoizeWarning = memoize((message) => {
debug(message);
});
function getBabelCaller({ filename, options, }) {
const isNodeModule = filename.includes('node_modules');
const isReactServer = options.customTransformOptions?.environment === 'react-server';
const isGenericServer = options.customTransformOptions?.environment === 'node';
const isServer = isReactServer || isGenericServer;
const routerRoot = typeof options.customTransformOptions?.routerRoot === 'string'
? decodeURI(options.customTransformOptions.routerRoot)
: undefined;
if (routerRoot == null) {
memoizeWarning('Warning: Missing transform.routerRoot option in Metro bundling request, falling back to `app` as routes directory. This can occur if you bundle without Expo CLI or expo/metro-config.');
}
return {
name: 'metro',
bundler: 'metro',
platform: options.platform,
// Empower the babel preset to know the env it's bundling for.
// Metro automatically updates the cache to account for the custom transform options.
isServer,
// Enable React Server Component rules for AST.
isReactServer,
// The base url to make requests from, used for hosting from non-standard locations.
baseUrl: typeof options.customTransformOptions?.baseUrl === 'string'
? decodeURI(options.customTransformOptions.baseUrl)
: '',
// Ensure we always use a mostly-valid router root.
routerRoot: routerRoot ?? 'app',
isDev: options.dev,
// This value indicates if the user has disabled the feature or not.
// Other criteria may still cause the feature to be disabled, but all inputs used are
// already considered in the cache key.
preserveEnvVars: isCustomTruthy(options.customTransformOptions?.preserveEnvVars)
? true
: undefined,
asyncRoutes: isCustomTruthy(options.customTransformOptions?.asyncRoutes) ? true : undefined,
// Pass the engine to babel so we can automatically transpile for the correct
// target environment.
engine: stringOrUndefined(options.customTransformOptions?.engine),
// Provide the project root for accurately reading the Expo config.
projectRoot: options.projectRoot,
isNodeModule,
isHMREnabled: options.hot,
// Set the standard Babel flag to disable ESM transformations.
supportsStaticESM: options.experimentalImportSupport,
// Enable React compiler support in Babel.
// TODO: Remove this in the future when compiler is on by default.
supportsReactCompiler: isCustomTruthy(options.customTransformOptions?.reactCompiler)
? true
: undefined,
};
}
function stringOrUndefined(value) {
return typeof value === 'string' ? value : undefined;
}
const transform = ({ filename, src, options,
// `plugins` is used for `functionMapBabelPlugin` from `metro-source-map`. Could make sense to move this to `babel-preset-expo` too.
plugins, }) => {
const OLD_BABEL_ENV = process.env.BABEL_ENV;
process.env.BABEL_ENV = options.dev ? 'development' : process.env.BABEL_ENV || 'production';
try {
const babelConfig = {
// ES modules require sourceType='module' but OSS may not always want that
sourceType: 'unambiguous',
// The output we want from Babel methods
ast: true,
code: false,
// NOTE(EvanBacon): We split the parse/transform steps up to accommodate
// Hermes parsing, but this defaults to cloning the AST which increases
// the transformation time by a fair amount.
// You get this behavior by default when using Babel's `transform` method directly.
cloneInputAst: false,
// Options for debugging
cwd: options.projectRoot,
filename,
highlightCode: true,
// Load the project babel config file.
...(0, loadBabelConfig_1.loadBabelConfig)(options),
babelrc: typeof options.enableBabelRCLookup === 'boolean' ? options.enableBabelRCLookup : true,
plugins,
// NOTE(EvanBacon): We heavily leverage the caller functionality to mutate the babel config.
// This compensates for the lack of a format plugin system in Metro. Users can modify the
// all (most) of the transforms in their local Babel config.
// This also helps us keep the transform layers small and focused on a single task. We can also use this to
// ensure the Babel config caching is more accurate.
// Additionally, by moving everything Babel-related to the Babel preset, it makes it easier for users to reason
// about the requirements of an Expo project, making it easier to migrate to other transpilers in the future.
caller: getBabelCaller({ filename, options }),
};
const result = (0, transformSync_1.transformSync)(src, babelConfig, options);
// The result from `transformFromAstSync` can be null (if the file is ignored)
if (!result) {
// BabelTransformer specifies that the `ast` can never be null but
// the function returns here. Discovered when typing `BabelNode`.
return { ast: null };
}
(0, node_assert_1.default)(result.ast);
return { ast: result.ast, metadata: result.metadata };
}
finally {
if (OLD_BABEL_ENV) {
process.env.BABEL_ENV = OLD_BABEL_ENV;
}
}
};
const babelTransformer = {
transform,
};
module.exports = babelTransformer;
//# sourceMappingURL=babel-transformer.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"babel-transformer.js","sourceRoot":"","sources":["../src/babel-transformer.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,10 @@
import { SymbolicatorConfigT } from 'metro-config';
type CustomizeFrameFunc = SymbolicatorConfigT['customizeFrame'];
export declare const INTERNAL_CALLSITES_REGEX: RegExp;
/**
* The default frame processor. This is used to modify the stack traces.
* This method attempts to collapse all frames that aren't relevant to
* the user by default.
*/
export declare function getDefaultCustomizeFrame(): CustomizeFrameFunc;
export {};

View File

@@ -0,0 +1,97 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getDefaultCustomizeFrame = exports.INTERNAL_CALLSITES_REGEX = void 0;
const url_1 = require("url");
// Import only the types here, the values will be imported from the project, at runtime.
exports.INTERNAL_CALLSITES_REGEX = new RegExp([
'/Libraries/Renderer/implementations/.+\\.js$',
'/Libraries/BatchedBridge/MessageQueue\\.js$',
'/Libraries/YellowBox/.+\\.js$',
'/Libraries/LogBox/.+\\.js$',
'/Libraries/Core/Timers/.+\\.js$',
'node_modules/react-devtools-core/.+\\.js$',
'node_modules/react-refresh/.+\\.js$',
'node_modules/scheduler/.+\\.js$',
// Metro replaces `require()` with a different method,
// we want to omit this method from the stack trace.
// This is akin to most React tooling.
'/metro/.*/polyfills/require.js$',
// Hide frames related to a fast refresh.
'/metro/.*/lib/bundle-modules/.+\\.js$',
'node_modules/react-native/Libraries/Utilities/HMRClient.js$',
'node_modules/eventemitter3/index.js',
'node_modules/event-target-shim/dist/.+\\.js$',
// Improve errors thrown by invariant (ex: `Invariant Violation: "main" has not been registered`).
'node_modules/invariant/.+\\.js$',
// Remove babel runtime additions
'node_modules/regenerator-runtime/.+\\.js$',
// Remove react native setImmediate ponyfill
'node_modules/promise/setimmediate/.+\\.js$',
// Babel helpers that implement language features
'node_modules/@babel/runtime/.+\\.js$',
// Hide Hermes internal bytecode
'/InternalBytecode/InternalBytecode\\.js$',
// Block native code invocations
`\\[native code\\]`,
// Hide react-dom (web)
'node_modules/react-dom/.+\\.js$',
// Hide node.js evaluation code
'node_modules/require-from-string/.+\\.js$',
// Block expo's metro-runtime
'@expo/metro-runtime/.+\\.ts',
// Block upstream metro-runtime
'/metro-runtime/.+\\.js$',
// Block all whatwg polyfills
'node_modules/whatwg-.+\\.js$',
// Hide expo-router warnings which are often wrapping all routes and imports.
'node_modules/expo-router/build/',
// No Expo CLI logs
'/@expo/cli/.+',
// No context modules as these are virtual
'.+?ctx=[a-zA-Z0-9]+$',
// Hide react-native-web warning wrappers. These are most likely related to style deprecations.
'/react-native-web/dist/.+\\.js$',
].join('|'));
function isUrl(value) {
try {
// eslint-disable-next-line no-new
new url_1.URL(value);
return true;
}
catch {
return false;
}
}
/**
* The default frame processor. This is used to modify the stack traces.
* This method attempts to collapse all frames that aren't relevant to
* the user by default.
*/
function getDefaultCustomizeFrame() {
return (frame) => {
if (frame.file && isUrl(frame.file)) {
return {
...frame,
// HACK: This prevents Metro from attempting to read the invalid file URL it sent us.
lineNumber: null,
column: null,
// This prevents the invalid frame from being shown by default.
collapse: true,
};
}
let collapse = Boolean(frame.file && exports.INTERNAL_CALLSITES_REGEX.test(frame.file));
if (!collapse) {
// This represents the first frame of the stacktrace.
// Often this looks like: `__r(0);`.
// The URL will also be unactionable in the app and therefore not very useful to the developer.
if (frame.column === 3 &&
frame.methodName === 'global code' &&
frame.file?.match(/^https?:\/\//g)) {
collapse = true;
}
}
return { ...(frame || {}), collapse };
};
}
exports.getDefaultCustomizeFrame = getDefaultCustomizeFrame;
//# sourceMappingURL=customizeFrame.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"customizeFrame.js","sourceRoot":"","sources":["../src/customizeFrame.ts"],"names":[],"mappings":";;;AAEA,6BAA0B;AAI1B,wFAAwF;AAC3E,QAAA,wBAAwB,GAAG,IAAI,MAAM,CAChD;IACE,8CAA8C;IAC9C,6CAA6C;IAC7C,+BAA+B;IAC/B,4BAA4B;IAC5B,iCAAiC;IACjC,2CAA2C;IAC3C,qCAAqC;IACrC,iCAAiC;IACjC,sDAAsD;IACtD,oDAAoD;IACpD,sCAAsC;IACtC,iCAAiC;IACjC,yCAAyC;IACzC,uCAAuC;IACvC,6DAA6D;IAC7D,qCAAqC;IACrC,8CAA8C;IAC9C,kGAAkG;IAClG,iCAAiC;IACjC,iCAAiC;IACjC,2CAA2C;IAC3C,4CAA4C;IAC5C,4CAA4C;IAC5C,iDAAiD;IACjD,sCAAsC;IACtC,gCAAgC;IAChC,0CAA0C;IAC1C,gCAAgC;IAChC,mBAAmB;IACnB,uBAAuB;IACvB,iCAAiC;IACjC,+BAA+B;IAC/B,2CAA2C;IAC3C,6BAA6B;IAC7B,6BAA6B;IAC7B,+BAA+B;IAC/B,yBAAyB;IAEzB,6BAA6B;IAC7B,8BAA8B;IAC9B,6EAA6E;IAC7E,iCAAiC;IACjC,mBAAmB;IACnB,eAAe;IACf,0CAA0C;IAC1C,sBAAsB;IACtB,+FAA+F;IAC/F,iCAAiC;CAClC,CAAC,IAAI,CAAC,GAAG,CAAC,CACZ,CAAC;AAEF,SAAS,KAAK,CAAC,KAAa;IAC1B,IAAI;QACF,kCAAkC;QAClC,IAAI,SAAG,CAAC,KAAK,CAAC,CAAC;QACf,OAAO,IAAI,CAAC;KACb;IAAC,MAAM;QACN,OAAO,KAAK,CAAC;KACd;AACH,CAAC;AAED;;;;GAIG;AACH,SAAgB,wBAAwB;IACtC,OAAO,CAAC,KAAwC,EAAE,EAAE;QAClD,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE;YACnC,OAAO;gBACL,GAAG,KAAK;gBACR,qFAAqF;gBACrF,UAAU,EAAE,IAAI;gBAChB,MAAM,EAAE,IAAI;gBACZ,+DAA+D;gBAC/D,QAAQ,EAAE,IAAI;aACf,CAAC;SACH;QACD,IAAI,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,IAAI,gCAAwB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;QAEhF,IAAI,CAAC,QAAQ,EAAE;YACb,qDAAqD;YACrD,oCAAoC;YACpC,+FAA+F;YAC/F,IACE,KAAK,CAAC,MAAM,KAAK,CAAC;gBAClB,KAAK,CAAC,UAAU,KAAK,aAAa;gBAClC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,eAAe,CAAC,EAClC;gBACA,QAAQ,GAAG,IAAI,CAAC;aACjB;SACF;QAED,OAAO,EAAE,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC;IACxC,CAAC,CAAC;AACJ,CAAC;AA7BD,4DA6BC"}

View File

@@ -0,0 +1,14 @@
declare class Env {
/** Enable debug logging */
get EXPO_DEBUG(): boolean;
/** Enable the experimental "exotic" mode. [Learn more](https://blog.expo.dev/drastically-faster-bundling-in-react-native-a54f268e0ed1). */
get EXPO_USE_EXOTIC(): boolean;
/** The React Metro port that's baked into react-native scripts and tools. */
get RCT_METRO_PORT(): number;
/** Enable auto server root detection for Metro. This will change the server root to the workspace root. */
get EXPO_USE_METRO_WORKSPACE_ROOT(): boolean;
/** Disable Environment Variable injection in client bundles. */
get EXPO_NO_CLIENT_ENV_VARS(): boolean;
}
export declare const env: Env;
export {};

View File

@@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.env = void 0;
const getenv_1 = require("getenv");
class Env {
/** Enable debug logging */
get EXPO_DEBUG() {
return (0, getenv_1.boolish)('EXPO_DEBUG', false);
}
/** Enable the experimental "exotic" mode. [Learn more](https://blog.expo.dev/drastically-faster-bundling-in-react-native-a54f268e0ed1). */
get EXPO_USE_EXOTIC() {
return (0, getenv_1.boolish)('EXPO_USE_EXOTIC', false);
}
/** The React Metro port that's baked into react-native scripts and tools. */
get RCT_METRO_PORT() {
return (0, getenv_1.int)('RCT_METRO_PORT', 8081);
}
/** Enable auto server root detection for Metro. This will change the server root to the workspace root. */
get EXPO_USE_METRO_WORKSPACE_ROOT() {
return (0, getenv_1.boolish)('EXPO_USE_METRO_WORKSPACE_ROOT', false);
}
/** Disable Environment Variable injection in client bundles. */
get EXPO_NO_CLIENT_ENV_VARS() {
return (0, getenv_1.boolish)('EXPO_NO_CLIENT_ENV_VARS', false);
}
}
exports.env = new Env();
//# sourceMappingURL=env.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":";;;AAAA,mCAAsC;AAEtC,MAAM,GAAG;IACP,2BAA2B;IAC3B,IAAI,UAAU;QACZ,OAAO,IAAA,gBAAO,EAAC,YAAY,EAAE,KAAK,CAAC,CAAC;IACtC,CAAC;IAED,2IAA2I;IAC3I,IAAI,eAAe;QACjB,OAAO,IAAA,gBAAO,EAAC,iBAAiB,EAAE,KAAK,CAAC,CAAC;IAC3C,CAAC;IAED,6EAA6E;IAC7E,IAAI,cAAc;QAChB,OAAO,IAAA,YAAG,EAAC,gBAAgB,EAAE,IAAI,CAAC,CAAC;IACrC,CAAC;IAED,2GAA2G;IAC3G,IAAI,6BAA6B;QAC/B,OAAO,IAAA,gBAAO,EAAC,+BAA+B,EAAE,KAAK,CAAC,CAAC;IACzD,CAAC;IAED,gEAAgE;IAChE,IAAI,uBAAuB;QACzB,OAAO,IAAA,gBAAO,EAAC,yBAAyB,EAAE,KAAK,CAAC,CAAC;IACnD,CAAC;CACF;AAEY,QAAA,GAAG,GAAG,IAAI,GAAG,EAAE,CAAC"}

View File

@@ -0,0 +1,5 @@
/// <reference types="node" />
import UpstreamFileStore from 'metro-cache/src/stores/FileStore';
export declare class FileStore<T> extends UpstreamFileStore<T> {
set(key: Buffer, value: any): Promise<void>;
}

View File

@@ -0,0 +1,20 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.FileStore = void 0;
const FileStore_1 = __importDefault(require("metro-cache/src/stores/FileStore"));
const debug = require('debug')('expo:metro:cache');
class FileStore extends FileStore_1.default {
async set(key, value) {
// Prevent caching of CSS files that have the skipCache flag set.
if (value?.output?.[0]?.data?.css?.skipCache) {
debug('Skipping caching for CSS file:', value.path);
return;
}
return await super.set(key, value);
}
}
exports.FileStore = FileStore;
//# sourceMappingURL=file-store.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"file-store.js","sourceRoot":"","sources":["../src/file-store.ts"],"names":[],"mappings":";;;;;;AAAA,iFAAiE;AAEjE,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,kBAAkB,CAAuB,CAAC;AAEzE,MAAa,SAAa,SAAQ,mBAAoB;IACpD,KAAK,CAAC,GAAG,CAAC,GAAW,EAAE,KAAU;QAC/B,iEAAiE;QACjE,IAAI,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE;YAC5C,KAAK,CAAC,gCAAgC,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YACpD,OAAO;SACR;QACD,OAAO,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACrC,CAAC;CACF;AATD,8BASC"}

View File

@@ -0,0 +1,4 @@
/** Wraps `findWorkspaceRoot` and guards against having an empty `package.json` file in an upper directory. */
export declare function getWorkspaceRoot(projectRoot: string): string | null;
export declare function getModulesPaths(projectRoot: string): string[];
export declare function getServerRoot(projectRoot: string): string;

View File

@@ -0,0 +1,41 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getServerRoot = exports.getModulesPaths = exports.getWorkspaceRoot = void 0;
const find_yarn_workspace_root_1 = __importDefault(require("find-yarn-workspace-root"));
const path_1 = __importDefault(require("path"));
const env_1 = require("./env");
/** Wraps `findWorkspaceRoot` and guards against having an empty `package.json` file in an upper directory. */
function getWorkspaceRoot(projectRoot) {
try {
return (0, find_yarn_workspace_root_1.default)(projectRoot);
}
catch (error) {
if (error.message.includes('Unexpected end of JSON input')) {
return null;
}
throw error;
}
}
exports.getWorkspaceRoot = getWorkspaceRoot;
function getModulesPaths(projectRoot) {
const paths = [];
// Only add the project root if it's not the current working directory
// this minimizes the chance of Metro resolver breaking on new Node.js versions.
const workspaceRoot = getWorkspaceRoot(path_1.default.resolve(projectRoot)); // Absolute path or null
if (workspaceRoot) {
paths.push(path_1.default.resolve(projectRoot, 'node_modules'));
paths.push(path_1.default.resolve(workspaceRoot, 'node_modules'));
}
return paths;
}
exports.getModulesPaths = getModulesPaths;
function getServerRoot(projectRoot) {
return env_1.env.EXPO_USE_METRO_WORKSPACE_ROOT
? getWorkspaceRoot(projectRoot) ?? projectRoot
: projectRoot;
}
exports.getServerRoot = getServerRoot;
//# sourceMappingURL=getModulesPaths.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"getModulesPaths.js","sourceRoot":"","sources":["../src/getModulesPaths.ts"],"names":[],"mappings":";;;;;;AAAA,wFAAyD;AACzD,gDAAwB;AAExB,+BAA4B;AAE5B,8GAA8G;AAC9G,SAAgB,gBAAgB,CAAC,WAAmB;IAClD,IAAI;QACF,OAAO,IAAA,kCAAiB,EAAC,WAAW,CAAC,CAAC;KACvC;IAAC,OAAO,KAAU,EAAE;QACnB,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,8BAA8B,CAAC,EAAE;YAC1D,OAAO,IAAI,CAAC;SACb;QACD,MAAM,KAAK,CAAC;KACb;AACH,CAAC;AATD,4CASC;AAED,SAAgB,eAAe,CAAC,WAAmB;IACjD,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,sEAAsE;IACtE,gFAAgF;IAChF,MAAM,aAAa,GAAG,gBAAgB,CAAC,cAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,wBAAwB;IAC3F,IAAI,aAAa,EAAE;QACjB,KAAK,CAAC,IAAI,CAAC,cAAI,CAAC,OAAO,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC,CAAC;QACtD,KAAK,CAAC,IAAI,CAAC,cAAI,CAAC,OAAO,CAAC,aAAa,EAAE,cAAc,CAAC,CAAC,CAAC;KACzD;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAZD,0CAYC;AAED,SAAgB,aAAa,CAAC,WAAmB;IAC/C,OAAO,SAAG,CAAC,6BAA6B;QACtC,CAAC,CAAC,gBAAgB,CAAC,WAAW,CAAC,IAAI,WAAW;QAC9C,CAAC,CAAC,WAAW,CAAC;AAClB,CAAC;AAJD,sCAIC"}

View File

@@ -0,0 +1,16 @@
/**
* @param workspaceProjectRoot Root file path for the yarn workspace
* @param linkedPackages List of folders that contain linked node modules, ex: `['packages/*', 'apps/*']`
* @returns List of valid package.json file paths, ex: `['/Users/me/app/apps/my-app/package.json', '/Users/me/app/packages/my-package/package.json']`
*/
export declare function globAllPackageJsonPaths(workspaceProjectRoot: string, linkedPackages: string[]): string[];
/**
* @param workspaceProjectRoot root file path for a yarn workspace.
* @returns list of package.json file paths that are linked to the yarn workspace.
*/
export declare function resolveAllWorkspacePackageJsonPaths(workspaceProjectRoot: string): string[];
/**
* @param projectRoot file path to app's project root
* @returns list of node module paths to watch in Metro bundler, ex: `['/Users/me/app/node_modules/', '/Users/me/app/apps/my-app/', '/Users/me/app/packages/my-package/']`
*/
export declare function getWatchFolders(projectRoot: string): string[];

View File

@@ -0,0 +1,98 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getWatchFolders = exports.resolveAllWorkspacePackageJsonPaths = exports.globAllPackageJsonPaths = void 0;
const assert_1 = __importDefault(require("assert"));
const fs_1 = __importDefault(require("fs"));
const glob_1 = require("glob");
const path_1 = __importDefault(require("path"));
const getModulesPaths_1 = require("./getModulesPaths");
function readJsonFile(filePath) {
// Read with fs
const file = fs_1.default.readFileSync(filePath, 'utf8');
// Parse with JSON.parse
return JSON.parse(file);
}
function isValidJsonFile(filePath) {
try {
// Throws if invalid or unable to read.
readJsonFile(filePath);
return true;
}
catch {
return false;
}
}
/**
* @param workspaceProjectRoot Root file path for the yarn workspace
* @param linkedPackages List of folders that contain linked node modules, ex: `['packages/*', 'apps/*']`
* @returns List of valid package.json file paths, ex: `['/Users/me/app/apps/my-app/package.json', '/Users/me/app/packages/my-package/package.json']`
*/
function globAllPackageJsonPaths(workspaceProjectRoot, linkedPackages) {
return linkedPackages
.map((glob) => {
return (0, glob_1.sync)(path_1.default.join(glob, 'package.json').replace(/\\/g, '/'), {
cwd: workspaceProjectRoot,
absolute: true,
ignore: ['**/@(Carthage|Pods|node_modules)/**'],
}).map((pkgPath) => {
return isValidJsonFile(pkgPath) ? pkgPath : null;
});
})
.flat()
.filter(Boolean)
.map((p) => path_1.default.join(p));
}
exports.globAllPackageJsonPaths = globAllPackageJsonPaths;
function getWorkspacePackagesArray({ workspaces }) {
if (Array.isArray(workspaces)) {
return workspaces;
}
(0, assert_1.default)(workspaces?.packages, 'Could not find a `workspaces` object in the root package.json');
return workspaces.packages;
}
/**
* @param workspaceProjectRoot root file path for a yarn workspace.
* @returns list of package.json file paths that are linked to the yarn workspace.
*/
function resolveAllWorkspacePackageJsonPaths(workspaceProjectRoot) {
try {
const rootPackageJsonFilePath = path_1.default.join(workspaceProjectRoot, 'package.json');
// Could throw if package.json is invalid.
const rootPackageJson = readJsonFile(rootPackageJsonFilePath);
// Extract the "packages" array or use "workspaces" as packages array (yarn workspaces spec).
const packages = getWorkspacePackagesArray(rootPackageJson);
// Glob all package.json files and return valid paths.
return globAllPackageJsonPaths(workspaceProjectRoot, packages);
}
catch {
return [];
}
}
exports.resolveAllWorkspacePackageJsonPaths = resolveAllWorkspacePackageJsonPaths;
/**
* @param projectRoot file path to app's project root
* @returns list of node module paths to watch in Metro bundler, ex: `['/Users/me/app/node_modules/', '/Users/me/app/apps/my-app/', '/Users/me/app/packages/my-package/']`
*/
function getWatchFolders(projectRoot) {
const workspaceRoot = (0, getModulesPaths_1.getWorkspaceRoot)(path_1.default.resolve(projectRoot));
// Rely on default behavior in standard projects.
if (!workspaceRoot) {
return [];
}
const packages = resolveAllWorkspacePackageJsonPaths(workspaceRoot);
if (!packages.length) {
return [];
}
return uniqueItems([
path_1.default.join(workspaceRoot, 'node_modules'),
...packages.map((pkg) => path_1.default.dirname(pkg)),
]);
}
exports.getWatchFolders = getWatchFolders;
function uniqueItems(items) {
return [...new Set(items)];
}
//# sourceMappingURL=getWatchFolders.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"getWatchFolders.js","sourceRoot":"","sources":["../src/getWatchFolders.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,9 @@
import type { TransformOptions } from './babel-core';
/**
* Returns a memoized function that checks for the existence of a
* project-level .babelrc file. If it doesn't exist, it reads the
* default React Native babelrc file and uses that.
*/
export declare const loadBabelConfig: ({ projectRoot }: {
projectRoot: string;
}) => Pick<TransformOptions, "extends" | "presets">;

View File

@@ -0,0 +1,45 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.loadBabelConfig = void 0;
/**
* Copyright (c) 650 Industries (Expo). All rights reserved.
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_1 = __importDefault(require("node:path"));
/**
* Returns a memoized function that checks for the existence of a
* project-level .babelrc file. If it doesn't exist, it reads the
* default React Native babelrc file and uses that.
*/
exports.loadBabelConfig = (function () {
let babelRC = null;
return function _getBabelRC({ projectRoot }) {
if (babelRC !== null) {
return babelRC;
}
babelRC = {};
if (projectRoot) {
// Check for various babel config files in the project root
// TODO(EvanBacon): We might want to disable babelrc lookup when the user specifies `enableBabelRCLookup: false`.
const possibleBabelRCPaths = ['.babelrc', '.babelrc.js', 'babel.config.js'];
const foundBabelRCPath = possibleBabelRCPaths.find((configFileName) => node_fs_1.default.existsSync(node_path_1.default.resolve(projectRoot, configFileName)));
// Extend the config if a babel config file is found
if (foundBabelRCPath) {
babelRC.extends = node_path_1.default.resolve(projectRoot, foundBabelRCPath);
}
}
// Use the default preset for react-native if no babel config file is found
if (!babelRC.extends) {
babelRC.presets = [require('babel-preset-expo')];
}
return babelRC;
};
})();
//# sourceMappingURL=loadBabelConfig.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"loadBabelConfig.js","sourceRoot":"","sources":["../src/loadBabelConfig.ts"],"names":[],"mappings":";;;;;;AAAA;;;;;;GAMG;AACH,sDAAyB;AACzB,0DAA6B;AAI7B;;;;GAIG;AACU,QAAA,eAAe,GAAG,CAAC;IAC9B,IAAI,OAAO,GAAyD,IAAI,CAAC;IAEzE,OAAO,SAAS,WAAW,CAAC,EAAE,WAAW,EAA2B;QAClE,IAAI,OAAO,KAAK,IAAI,EAAE;YACpB,OAAO,OAAO,CAAC;SAChB;QAED,OAAO,GAAG,EAAE,CAAC;QAEb,IAAI,WAAW,EAAE;YACf,2DAA2D;YAC3D,iHAAiH;YACjH,MAAM,oBAAoB,GAAG,CAAC,UAAU,EAAE,aAAa,EAAE,iBAAiB,CAAC,CAAC;YAE5E,MAAM,gBAAgB,GAAG,oBAAoB,CAAC,IAAI,CAAC,CAAC,cAAc,EAAE,EAAE,CACpE,iBAAE,CAAC,UAAU,CAAC,mBAAI,CAAC,OAAO,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC,CACzD,CAAC;YAEF,oDAAoD;YACpD,IAAI,gBAAgB,EAAE;gBACpB,OAAO,CAAC,OAAO,GAAG,mBAAI,CAAC,OAAO,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAC;aAC/D;SACF;QAED,2EAA2E;QAC3E,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE;YACpB,OAAO,CAAC,OAAO,GAAG,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAAC;SAClD;QAED,OAAO,OAAO,CAAC;IACjB,CAAC,CAAC;AACJ,CAAC,CAAC,EAAE,CAAC"}

View File

@@ -0,0 +1,2 @@
export declare function getRouterDirectory(projectRoot: string): string;
export declare function getRewriteRequestUrl(projectRoot: string): (url: string) => string;

View File

@@ -0,0 +1,102 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getRewriteRequestUrl = exports.getRouterDirectory = void 0;
// Copyright 2023-present 650 Industries (Expo). All rights reserved.
const config_1 = require("@expo/config");
const paths_1 = require("@expo/config/paths");
const chalk_1 = __importDefault(require("chalk"));
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const getModulesPaths_1 = require("./getModulesPaths");
const debug = require('debug')('expo:metro:config:rewriteRequestUrl');
function directoryExistsSync(file) {
try {
return fs_1.default.statSync(file)?.isDirectory() ?? false;
}
catch {
return false;
}
}
function isEnableHermesManaged(expoConfig, platform) {
switch (platform) {
case 'android': {
return (expoConfig.android?.jsEngine ?? expoConfig.jsEngine) !== 'jsc';
}
case 'ios': {
return (expoConfig.ios?.jsEngine ?? expoConfig.jsEngine) !== 'jsc';
}
default:
return false;
}
}
function getRouterDirectoryModuleIdWithManifest(projectRoot, exp) {
return exp.extra?.router?.root ?? getRouterDirectory(projectRoot);
}
function getRouterDirectory(projectRoot) {
// more specific directories first
if (directoryExistsSync(path_1.default.join(projectRoot, 'src/app'))) {
debug('Using src/app as the root directory for Expo Router.');
return 'src/app';
}
debug('Using app as the root directory for Expo Router.');
return 'app';
}
exports.getRouterDirectory = getRouterDirectory;
function getRewriteRequestUrl(projectRoot) {
function rewriteExpoRequestUrl(url) {
// Like: `/.expo/.virtual-metro-entry.bundle?platform=ios&dev=true&minify=false&modulesOnly=false&runModule=true&app=com.bacon.test-custom-entry`
// Sometimes a fully qualified URL is passed in, e.g. `http://localhost:19001/.expo/.virtual-metro-entry.bundle?platform=ios&dev=true&minify=false&modulesOnly=false&runModule=true&app=com.bacon.test-custom-entry`
if (url.includes('/.expo/.virtual-metro-entry.bundle?')) {
const { pkg, exp } = (0, config_1.getConfig)(projectRoot, { skipSDKVersionRequirement: true });
const ensured = url.startsWith('/') ? new URL(url, 'https://acme.dev') : new URL(url);
// TODO: Maybe this function could be memoized in some capacity?
const { searchParams } = ensured;
const platform = searchParams.get('platform') ?? 'web';
debug('Rewriting magic request url to entry point', { url, platform });
const entry = (0, paths_1.resolveEntryPoint)(projectRoot, {
platform,
pkg,
});
if (!entry) {
throw new Error((0, chalk_1.default) `The project entry file could not be resolved (platform: ${platform}, root: ${projectRoot}). Define it in the {bold package.json} "main" field.`);
}
// Infer the missing transform properties to attempt to match the manifest request.
// NOTE: Keep in sync with metroOptions.ts
if (!ensured.searchParams.has('transform.routerRoot')) {
ensured.searchParams.set('transform.routerRoot', getRouterDirectoryModuleIdWithManifest(projectRoot, exp));
}
if (!ensured.searchParams.has('transform.reactCompiler') && exp.experiments?.reactCompiler) {
ensured.searchParams.set('transform.reactCompiler', String(!!exp.experiments?.reactCompiler));
}
if (!ensured.searchParams.has('transform.engine')) {
const isHermesEnabled = isEnableHermesManaged(exp, platform);
if (isHermesEnabled) {
debug('Enabling Hermes for managed project');
ensured.searchParams.set('transform.engine', 'hermes');
ensured.searchParams.set('transform.bytecode', 'true');
}
}
const serverRoot = (0, getModulesPaths_1.getServerRoot)(projectRoot);
const relativeEntry = path_1.default.relative(serverRoot, entry).replace(/\.[tj]sx?$/, '');
debug('Resolved entry point', { entry, relativeEntry, serverRoot });
// Only return the pathname when url is relative
if (url.startsWith('/')) {
// Like: `/index.bundle?platform=ios&dev=true&minify=false&modulesOnly=false&runModule=true&app=com.bacon.test-custom-entry`
return '/' + relativeEntry + '.bundle?' + searchParams.toString();
}
// Modify the pathname within the URL and return the full URL
ensured.pathname = '/' + relativeEntry + '.bundle';
const outputUrl = ensured.toString();
debug('Redirected:', outputUrl);
// Like: `http://localhost:19001/index.bundle?platform=ios&dev=true&minify=false&modulesOnly=false&runModule=true&app=com.bacon.test-custom-entry`
return outputUrl;
}
return url;
}
return rewriteExpoRequestUrl;
}
exports.getRewriteRequestUrl = getRewriteRequestUrl;
//# sourceMappingURL=rewriteRequestUrl.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"rewriteRequestUrl.js","sourceRoot":"","sources":["../src/rewriteRequestUrl.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,12 @@
/**
* Copyright © 2023 650 Industries.
* Copyright (c) 2022, Sentry.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* Deterministically hashes a string and turns the hash into a uuid.
* https://github.com/getsentry/sentry-javascript-bundler-plugins/blob/58271f1af2ade6b3e64d393d70376ae53bc5bd2f/packages/bundler-plugin-core/src/utils.ts#L174
*/
export declare function stringToUUID(str: string): string;

View File

@@ -0,0 +1,38 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.stringToUUID = void 0;
const node_crypto_1 = __importDefault(require("node:crypto"));
/**
* Copyright © 2023 650 Industries.
* Copyright (c) 2022, Sentry.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* Deterministically hashes a string and turns the hash into a uuid.
* https://github.com/getsentry/sentry-javascript-bundler-plugins/blob/58271f1af2ade6b3e64d393d70376ae53bc5bd2f/packages/bundler-plugin-core/src/utils.ts#L174
*/
function stringToUUID(str) {
const md5sum = node_crypto_1.default.createHash('md5');
md5sum.update(str);
const md5Hash = md5sum.digest('hex');
// Position 16 is fixed to either 8, 9, a, or b in the uuid v4 spec (10xx in binary)
// RFC 4122 section 4.4
const v4variant = ['8', '9', 'a', 'b'][md5Hash.substring(16, 17).charCodeAt(0) % 4];
return (md5Hash.substring(0, 8) +
'-' +
md5Hash.substring(8, 12) +
'-4' +
md5Hash.substring(13, 16) +
'-' +
v4variant +
md5Hash.substring(17, 20) +
'-' +
md5Hash.substring(20)).toLowerCase();
}
exports.stringToUUID = stringToUUID;
//# sourceMappingURL=debugId.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"debugId.js","sourceRoot":"","sources":["../../src/serializer/debugId.ts"],"names":[],"mappings":";;;;;;AAAA,8DAAiC;AAEjC;;;;;;GAMG;AAEH;;;GAGG;AACH,SAAgB,YAAY,CAAC,GAAW;IACtC,MAAM,MAAM,GAAG,qBAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IACxC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACnB,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAErC,oFAAoF;IACpF,uBAAuB;IACvB,MAAM,SAAS,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAW,CAAC;IAE9F,OAAO,CACL,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC;QACvB,GAAG;QACH,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC;QACxB,IAAI;QACJ,OAAO,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,CAAC;QACzB,GAAG;QACH,SAAS;QACT,OAAO,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,CAAC;QACzB,GAAG;QACH,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,CACtB,CAAC,WAAW,EAAE,CAAC;AAClB,CAAC;AArBD,oCAqBC"}

View File

@@ -0,0 +1,14 @@
/// <reference types="node" />
/**
* Copyright © 2022 650 Industries.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import { ReadOnlyGraph, MixedOutput, Module, SerializerOptions } from 'metro';
import { SerializerParameters } from './withExpoSerializers';
export declare function getTransformEnvironment(url: string): string | null;
/** Strips the process.env polyfill in server environments to allow for accessing environment variables off the global. */
export declare function serverPreludeSerializerPlugin(entryPoint: string, preModules: readonly Module<MixedOutput>[], graph: ReadOnlyGraph, options: SerializerOptions): SerializerParameters;
export declare function environmentVariableSerializerPlugin(entryPoint: string, preModules: readonly Module<MixedOutput>[], graph: ReadOnlyGraph, options: SerializerOptions): SerializerParameters;
export declare function getEnvVarDevString(env?: NodeJS.ProcessEnv): string;

View File

@@ -0,0 +1,119 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getEnvVarDevString = exports.environmentVariableSerializerPlugin = exports.serverPreludeSerializerPlugin = exports.getTransformEnvironment = void 0;
const CountingSet_1 = __importDefault(require("metro/src/lib/CountingSet"));
const countLines_1 = __importDefault(require("metro/src/lib/countLines"));
const debug = require('debug')('expo:metro-config:serializer:env-var');
function getTransformEnvironment(url) {
const match = url.match(/[&?]transform\.environment=([^&]+)/);
return match ? match[1] : null;
}
exports.getTransformEnvironment = getTransformEnvironment;
function getAllExpoPublicEnvVars(inputEnv = process.env) {
// Create an object containing all environment variables that start with EXPO_PUBLIC_
const env = {};
for (const key in inputEnv) {
if (key.startsWith('EXPO_PUBLIC_')) {
// @ts-expect-error: TS doesn't know that the key starts with EXPO_PUBLIC_
env[key] = inputEnv[key];
}
}
return env;
}
function isServerEnvironment(graph, options) {
// Requests from a dev server will use sourceUrl.
if (!graph.transformOptions.customTransformOptions) {
if (options.sourceUrl) {
const env = getTransformEnvironment(options.sourceUrl);
return env === 'node' || env === 'react-server';
}
return false;
}
// Other requests will use customTransformOptions.environment.
const env = graph.transformOptions.customTransformOptions.environment;
return env === 'node' || env === 'react-server';
}
/** Strips the process.env polyfill in server environments to allow for accessing environment variables off the global. */
function serverPreludeSerializerPlugin(entryPoint, preModules, graph, options) {
if (isServerEnvironment(graph, options)) {
const prelude = preModules.find((module) => module.path === '__prelude__');
if (prelude) {
debug('Stripping environment variable polyfill in server environment.');
prelude.output[0].data.code = prelude.output[0].data.code
.replace(/process=this\.process\|\|{},/, '')
.replace(/process\.env=process\.env\|\|{};process\.env\.NODE_ENV=process\.env\.NODE_ENV\|\|"\w+";/, '');
}
}
return [entryPoint, preModules, graph, options];
}
exports.serverPreludeSerializerPlugin = serverPreludeSerializerPlugin;
function environmentVariableSerializerPlugin(entryPoint, preModules, graph, options) {
// Skip replacement in Node.js environments.
if (isServerEnvironment(graph, options)) {
debug('Skipping environment variable inlining in Node.js environment.');
return [entryPoint, preModules, graph, options];
}
// In development, we need to add the process.env object to ensure it
// persists between Fast Refresh updates.
if (!options.dev) {
debug('Skipping environment variable inlining in production environment in favor of babel-preset-expo inlining with source maps.');
return [entryPoint, preModules, graph, options];
}
const code = getEnvVarDevString();
const prelude = preModules.find((module) => module.path === '\0polyfill:environment-variables');
if (prelude) {
debug('Injecting environment variables in virtual module.');
// !!MUST!! be one line in order to ensure Metro's asymmetric serializer system can handle it.
prelude.output[0].data.code = code;
return [entryPoint, preModules, graph, options];
}
// Old system which doesn't work very well since Metro doesn't serialize graphs the same way in all cases.
// e.g. the `.map` endpoint is serialized differently to error symbolication.
// Inject the new module at index 1
// @ts-expect-error: The preModules are mutable and we need to mutate them in order to ensure the changes are applied outside of the serializer.
preModules.splice(
// Inject at index 1 to ensure it runs after the prelude (which injects env vars).
1, 0, getEnvPrelude(code));
return [entryPoint, preModules, graph, options];
}
exports.environmentVariableSerializerPlugin = environmentVariableSerializerPlugin;
function getEnvVarDevString(env = process.env) {
// Set the process.env object to the current environment variables object
// ensuring they aren't iterable, settable, or enumerable.
const str = `process.env=Object.defineProperties(process.env, {` +
Object.keys(getAllExpoPublicEnvVars(env))
.map((key) => `${JSON.stringify(key)}: { value: ${JSON.stringify(env[key])} }`)
.join(',') +
'});';
const code = '/* HMR env vars from Expo CLI (dev-only) */ ' + str;
const lineCount = (0, countLines_1.default)(code);
if (lineCount !== 1) {
throw new Error(`Virtual environment variable code must be one line, got "${lineCount}" lines.`);
}
return code;
}
exports.getEnvVarDevString = getEnvVarDevString;
function getEnvPrelude(code) {
const name = `\0polyfill:environment-variables`;
return {
dependencies: new Map(),
getSource: () => Buffer.from(code),
inverseDependencies: new CountingSet_1.default(),
path: name,
output: [
{
type: 'js/script/virtual',
data: {
code,
// @ts-expect-error: typed incorrectly upstream
lineCount: 1,
map: [],
},
},
],
};
}
//# sourceMappingURL=environmentVariableSerializerPlugin.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"environmentVariableSerializerPlugin.js","sourceRoot":"","sources":["../../src/serializer/environmentVariableSerializerPlugin.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,12 @@
interface HermesBundleOutput {
hbc: Uint8Array;
sourcemap: string | null;
}
type BuildHermesOptions = {
filename: string;
code: string;
map: string | null;
minify?: boolean;
};
export declare function buildHermesBundleAsync(options: BuildHermesOptions): Promise<HermesBundleOutput>;
export {};

View File

@@ -0,0 +1,113 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildHermesBundleAsync = void 0;
const spawn_async_1 = __importDefault(require("@expo/spawn-async"));
const chalk_1 = __importDefault(require("chalk"));
const fs_extra_1 = __importDefault(require("fs-extra"));
const metro_source_map_1 = require("metro-source-map");
const os_1 = __importDefault(require("os"));
const path_1 = __importDefault(require("path"));
const process_1 = __importDefault(require("process"));
const debug = require('debug')('expo:metro:hermes');
function importHermesCommandFromProject() {
const platformExecutable = getHermesCommandPlatform();
const hermescLocations = [
// Override hermesc dir by environment variables
process_1.default.env['REACT_NATIVE_OVERRIDE_HERMES_DIR']
? `${process_1.default.env['REACT_NATIVE_OVERRIDE_HERMES_DIR']}/build/bin/hermesc`
: '',
// Building hermes from source
'react-native/ReactAndroid/hermes-engine/build/hermes/bin/hermesc',
// Prebuilt hermesc in official react-native 0.69+
`react-native/sdks/hermesc/${platformExecutable}`,
// Legacy hermes-engine package
`hermes-engine/${platformExecutable}`,
];
for (const location of hermescLocations) {
try {
return require.resolve(location);
}
catch { }
}
throw new Error('Cannot find the hermesc executable.');
}
function getHermesCommandPlatform() {
switch (os_1.default.platform()) {
case 'darwin':
return 'osx-bin/hermesc';
case 'linux':
return 'linux64-bin/hermesc';
case 'win32':
return 'win64-bin/hermesc.exe';
default:
throw new Error(`Unsupported host platform for Hermes compiler: ${os_1.default.platform()}`);
}
}
// Only one hermes build at a time is supported.
let currentHermesBuild = null;
async function buildHermesBundleAsync(options) {
if (currentHermesBuild) {
debug(`Waiting for existing Hermes builds to finish`);
await currentHermesBuild;
}
currentHermesBuild = directlyBuildHermesBundleAsync(options);
return await currentHermesBuild;
}
exports.buildHermesBundleAsync = buildHermesBundleAsync;
async function directlyBuildHermesBundleAsync({ code, map, minify = false, filename, }) {
const tempDir = path_1.default.join(os_1.default.tmpdir(), `expo-bundler-${Math.random()}-${Date.now()}`);
await fs_extra_1.default.ensureDir(tempDir);
try {
const tempBundleFile = path_1.default.join(tempDir, 'index.js');
await fs_extra_1.default.writeFile(tempBundleFile, code);
if (map) {
const tempSourcemapFile = path_1.default.join(tempDir, 'index.js.map');
await fs_extra_1.default.writeFile(tempSourcemapFile, map);
}
const tempHbcFile = path_1.default.join(tempDir, 'index.hbc');
const hermesCommand = importHermesCommandFromProject();
const args = ['-emit-binary', '-out', tempHbcFile, tempBundleFile];
if (minify) {
args.push('-O');
}
if (map) {
args.push('-output-source-map');
}
debug(`Running hermesc: ${hermesCommand} ${args.join(' ')}`);
await (0, spawn_async_1.default)(hermesCommand, args);
let hbc;
let sourcemap = null;
if (!map) {
hbc = await fs_extra_1.default.readFile(tempHbcFile);
}
else {
[hbc, sourcemap] = await Promise.all([
fs_extra_1.default.readFile(tempHbcFile),
createHermesSourcemapAsync(map, `${tempHbcFile}.map`),
]);
}
return {
hbc,
sourcemap,
};
}
catch (error) {
console.error(chalk_1.default.red(`\nFailed to generate Hermes bytecode for: ${filename}`));
if ('status' in error) {
console.error(error.output.join('\n'));
}
throw error;
}
finally {
await fs_extra_1.default.remove(tempDir);
}
}
async function createHermesSourcemapAsync(sourcemap, hermesMapFile) {
const bundlerSourcemap = JSON.parse(sourcemap);
const hermesSourcemap = await fs_extra_1.default.readJSON(hermesMapFile);
return JSON.stringify((0, metro_source_map_1.composeSourceMaps)([bundlerSourcemap, hermesSourcemap]));
}
//# sourceMappingURL=exportHermes.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"exportHermes.js","sourceRoot":"","sources":["../../src/serializer/exportHermes.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,5 @@
export declare function getExportPathForDependencyWithOptions(dependencyPath: string, { platform, src, serverRoot }: {
platform: string;
serverRoot: string;
src: string;
}): string;

View File

@@ -0,0 +1,27 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getExportPathForDependencyWithOptions = void 0;
/**
* Copyright © 2023 650 Industries.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const path_1 = __importDefault(require("path"));
const getCssDeps_1 = require("./getCssDeps");
function getExportPathForDependencyWithOptions(dependencyPath, { platform, src, serverRoot }) {
const bundlePath = path_1.default.relative(serverRoot, dependencyPath);
const relativePathname = path_1.default.join(path_1.default.dirname(bundlePath),
// Strip the file extension
path_1.default.basename(bundlePath, path_1.default.extname(bundlePath)));
const name = (0, getCssDeps_1.fileNameFromContents)({
filepath: relativePathname,
src,
});
return `_expo/static/js/${platform}/${name}.js`;
}
exports.getExportPathForDependencyWithOptions = getExportPathForDependencyWithOptions;
//# sourceMappingURL=exportPath.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"exportPath.js","sourceRoot":"","sources":["../../src/serializer/exportPath.ts"],"names":[],"mappings":";;;;;;AAAA;;;;;GAKG;AACH,gDAAwB;AAExB,6CAAoD;AAEpD,SAAgB,qCAAqC,CACnD,cAAsB,EACtB,EAAE,QAAQ,EAAE,GAAG,EAAE,UAAU,EAAyD;IAEpF,MAAM,UAAU,GAAG,cAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;IAC7D,MAAM,gBAAgB,GAAG,cAAI,CAAC,IAAI,CAChC,cAAI,CAAC,OAAO,CAAC,UAAU,CAAC;IACxB,2BAA2B;IAC3B,cAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,cAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CACpD,CAAC;IACF,MAAM,IAAI,GAAG,IAAA,iCAAoB,EAAC;QAChC,QAAQ,EAAE,gBAAgB;QAC1B,GAAG;KACJ,CAAC,CAAC;IACH,OAAO,mBAAmB,QAAQ,IAAI,IAAI,KAAK,CAAC;AAClD,CAAC;AAfD,sFAeC"}

View File

@@ -0,0 +1,38 @@
/**
* Copyright © 2022 650 Industries.
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* Fork with bundle splitting and better source map support.
* https://github.com/facebook/metro/blob/bbdd7d7c5e6e0feb50a9967ffae1f723c1d7c4e8/packages/metro/src/DeltaBundler/Serializers/baseJSBundle.js#L1
*/
import type { MixedOutput, Module, ReadOnlyGraph, SerializerOptions } from 'metro';
export type ModuleMap = [number, string][];
export type Bundle = {
modules: ModuleMap;
post: string;
pre: string;
};
export type ExpoSerializerOptions = SerializerOptions & {
serializerOptions?: {
baseUrl?: string;
skipWrapping?: boolean;
splitChunks?: boolean;
output?: string;
includeSourceMaps?: boolean;
};
debugId?: string;
};
export declare function getPlatformOption(graph: Pick<ReadOnlyGraph, 'transformOptions'>, options: Pick<SerializerOptions, 'sourceUrl'>): string | null;
export declare function getBaseUrlOption(graph: Pick<ReadOnlyGraph, 'transformOptions'>, options: Pick<ExpoSerializerOptions, 'serializerOptions'>): string;
export declare function baseJSBundle(entryPoint: string, preModules: readonly Module[], graph: Pick<ReadOnlyGraph, 'dependencies' | 'transformOptions'>, options: ExpoSerializerOptions): Bundle;
export declare function baseJSBundleWithDependencies(entryPoint: string, preModules: readonly Module[], dependencies: Module<MixedOutput>[], options: ExpoSerializerOptions & {
platform: string;
baseUrl: string;
splitChunks: boolean;
skipWrapping: boolean;
computedAsyncModulePaths: Record<string, string> | null;
debugId?: string;
}): Bundle;

View File

@@ -0,0 +1,142 @@
"use strict";
/**
* Copyright © 2022 650 Industries.
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* Fork with bundle splitting and better source map support.
* https://github.com/facebook/metro/blob/bbdd7d7c5e6e0feb50a9967ffae1f723c1d7c4e8/packages/metro/src/DeltaBundler/Serializers/baseJSBundle.js#L1
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.baseJSBundleWithDependencies = exports.baseJSBundle = exports.getBaseUrlOption = exports.getPlatformOption = void 0;
const jsc_safe_url_1 = require("jsc-safe-url");
const CountingSet_1 = __importDefault(require("metro/src/lib/CountingSet"));
const countLines_1 = __importDefault(require("metro/src/lib/countLines"));
const getAppendScripts_1 = __importDefault(require("metro/src/lib/getAppendScripts"));
const processModules_1 = require("./processModules");
function getPlatformOption(graph, options) {
if (graph.transformOptions?.platform != null) {
return graph.transformOptions.platform;
}
if (!options.sourceUrl) {
return null;
}
const sourceUrl = (0, jsc_safe_url_1.isJscSafeUrl)(options.sourceUrl)
? (0, jsc_safe_url_1.toNormalUrl)(options.sourceUrl)
: options.sourceUrl;
const url = new URL(sourceUrl, 'https://expo.dev');
return url.searchParams.get('platform') ?? null;
}
exports.getPlatformOption = getPlatformOption;
function getBaseUrlOption(graph, options) {
const baseUrl = graph.transformOptions?.customTransformOptions?.baseUrl;
if (typeof baseUrl === 'string') {
// This tells us that the value came over a URL and may be encoded.
const mayBeEncoded = options.serializerOptions == null;
const option = mayBeEncoded ? decodeURIComponent(baseUrl) : baseUrl;
return option.replace(/\/+$/, '') + '/';
}
return '/';
}
exports.getBaseUrlOption = getBaseUrlOption;
function baseJSBundle(entryPoint, preModules, graph, options) {
const platform = getPlatformOption(graph, options);
if (platform == null) {
throw new Error('platform could not be determined for Metro bundle');
}
return baseJSBundleWithDependencies(entryPoint, preModules, [...graph.dependencies.values()], {
...options,
baseUrl: getBaseUrlOption(graph, options),
splitChunks: !!options.serializerOptions?.splitChunks,
platform,
skipWrapping: !!options.serializerOptions?.skipWrapping,
computedAsyncModulePaths: null,
});
}
exports.baseJSBundle = baseJSBundle;
function baseJSBundleWithDependencies(entryPoint, preModules, dependencies, options) {
for (const module of dependencies) {
options.createModuleId(module.path);
}
const processModulesOptions = {
filter: options.processModuleFilter,
createModuleId: options.createModuleId,
dev: options.dev,
includeAsyncPaths: options.includeAsyncPaths,
projectRoot: options.projectRoot,
serverRoot: options.serverRoot,
sourceUrl: options.sourceUrl,
platform: options.platform,
baseUrl: options.baseUrl,
splitChunks: options.splitChunks,
skipWrapping: options.skipWrapping,
computedAsyncModulePaths: options.computedAsyncModulePaths,
};
// Do not prepend polyfills or the require runtime when only modules are requested
if (options.modulesOnly) {
preModules = [];
}
const preCode = (0, processModules_1.processModules)(preModules, processModulesOptions)
.map(([, code]) => code.src)
.join('\n');
const modules = [...dependencies].sort((a, b) => options.createModuleId(a.path) - options.createModuleId(b.path));
const sourceMapUrl = options.serializerOptions?.includeSourceMaps === false ? undefined : options.sourceMapUrl;
const modulesWithAnnotations = (0, getAppendScripts_1.default)(entryPoint, [...preModules, ...modules], {
asyncRequireModulePath: options.asyncRequireModulePath,
createModuleId: options.createModuleId,
getRunModuleStatement: options.getRunModuleStatement,
inlineSourceMap: options.inlineSourceMap,
runBeforeMainModule: options.runBeforeMainModule,
runModule: options.runModule,
shouldAddToIgnoreList: options.shouldAddToIgnoreList,
sourceMapUrl,
// This directive doesn't make a lot of sense in the context of a large single bundle that represent
// multiple files. It's usually used for things like TypeScript where you want the file name to appear with a
// different extension. Since it's unclear to me (Bacon) how it is used on native, I'm only disabling in web and native in production.
sourceUrl: options.platform === 'web' ? undefined : !options.dev ? undefined : options.sourceUrl,
});
// If the `debugId` annotation is available and we aren't inlining the source map, add it to the bundle.
// NOTE: We may want to move this assertion up further.
const hasExternalMaps = !options.inlineSourceMap && !!sourceMapUrl;
if (hasExternalMaps && options.debugId != null) {
const code = `//# debugId=${options.debugId}`;
modulesWithAnnotations.push({
path: 'debug-id-annotation',
dependencies: new Map(),
getSource: () => Buffer.from(''),
inverseDependencies: new CountingSet_1.default(),
output: [
{
type: 'js/script/virtual',
data: {
code,
lineCount: (0, countLines_1.default)(code),
map: [],
},
},
],
});
}
const postCode = (0, processModules_1.processModules)(modulesWithAnnotations, processModulesOptions)
.map(([, code]) => code.src)
.join('\n');
const mods = (0, processModules_1.processModules)([...dependencies], processModulesOptions).map(([module, code]) => [
options.createModuleId(module.path),
code,
]);
return {
pre: preCode,
post: postCode,
modules: mods.map(([id, code]) => [
id,
typeof code === 'number' ? code : code.src,
]),
};
}
exports.baseJSBundleWithDependencies = baseJSBundleWithDependencies;
//# sourceMappingURL=baseJSBundle.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"baseJSBundle.js","sourceRoot":"","sources":["../../../src/serializer/fork/baseJSBundle.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;;;;;AAEH,+CAAyD;AAEzD,4EAAoD;AACpD,0EAAkD;AAClD,sFAA8D;AAE9D,qDAAkD;AAwBlD,SAAgB,iBAAiB,CAC/B,KAA8C,EAC9C,OAA6C;IAE7C,IAAI,KAAK,CAAC,gBAAgB,EAAE,QAAQ,IAAI,IAAI,EAAE;QAC5C,OAAO,KAAK,CAAC,gBAAgB,CAAC,QAAQ,CAAC;KACxC;IACD,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE;QACtB,OAAO,IAAI,CAAC;KACb;IAED,MAAM,SAAS,GAAG,IAAA,2BAAY,EAAC,OAAO,CAAC,SAAS,CAAC;QAC/C,CAAC,CAAC,IAAA,0BAAW,EAAC,OAAO,CAAC,SAAS,CAAC;QAChC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;IACtB,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,SAAS,EAAE,kBAAkB,CAAC,CAAC;IACnD,OAAO,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC;AAClD,CAAC;AAhBD,8CAgBC;AAED,SAAgB,gBAAgB,CAC9B,KAA8C,EAC9C,OAAyD;IAEzD,MAAM,OAAO,GAAG,KAAK,CAAC,gBAAgB,EAAE,sBAAsB,EAAE,OAAO,CAAC;IACxE,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE;QAC/B,mEAAmE;QACnE,MAAM,YAAY,GAAG,OAAO,CAAC,iBAAiB,IAAI,IAAI,CAAC;QACvD,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;QAEpE,OAAO,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC;KACzC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAbD,4CAaC;AAED,SAAgB,YAAY,CAC1B,UAAkB,EAClB,UAA6B,EAC7B,KAA+D,EAC/D,OAA8B;IAE9B,MAAM,QAAQ,GAAG,iBAAiB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACnD,IAAI,QAAQ,IAAI,IAAI,EAAE;QACpB,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;KACtE;IAED,OAAO,4BAA4B,CAAC,UAAU,EAAE,UAAU,EAAE,CAAC,GAAG,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE;QAC5F,GAAG,OAAO;QACV,OAAO,EAAE,gBAAgB,CAAC,KAAK,EAAE,OAAO,CAAC;QACzC,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,iBAAiB,EAAE,WAAW;QACrD,QAAQ;QACR,YAAY,EAAE,CAAC,CAAC,OAAO,CAAC,iBAAiB,EAAE,YAAY;QACvD,wBAAwB,EAAE,IAAI;KAC/B,CAAC,CAAC;AACL,CAAC;AAnBD,oCAmBC;AAED,SAAgB,4BAA4B,CAC1C,UAAkB,EAClB,UAA6B,EAC7B,YAAmC,EACnC,OAOC;IAED,KAAK,MAAM,MAAM,IAAI,YAAY,EAAE;QACjC,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;KACrC;IAED,MAAM,qBAAqB,GAAG;QAC5B,MAAM,EAAE,OAAO,CAAC,mBAAmB;QACnC,cAAc,EAAE,OAAO,CAAC,cAAc;QACtC,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,iBAAiB,EAAE,OAAO,CAAC,iBAAiB;QAC5C,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,wBAAwB,EAAE,OAAO,CAAC,wBAAwB;KAC3D,CAAC;IAEF,kFAAkF;IAClF,IAAI,OAAO,CAAC,WAAW,EAAE;QACvB,UAAU,GAAG,EAAE,CAAC;KACjB;IAED,MAAM,OAAO,GAAG,IAAA,+BAAc,EAAC,UAAU,EAAE,qBAAqB,CAAC;SAC9D,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC;SAC3B,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,MAAM,OAAO,GAAG,CAAC,GAAG,YAAY,CAAC,CAAC,IAAI,CACpC,CAAC,CAAsB,EAAE,CAAsB,EAAE,EAAE,CACjD,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,CAClE,CAAC;IAEF,MAAM,YAAY,GAChB,OAAO,CAAC,iBAAiB,EAAE,iBAAiB,KAAK,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC;IAE5F,MAAM,sBAAsB,GAAG,IAAA,0BAAgB,EAAC,UAAU,EAAE,CAAC,GAAG,UAAU,EAAE,GAAG,OAAO,CAAC,EAAE;QACvF,sBAAsB,EAAE,OAAO,CAAC,sBAAsB;QACtD,cAAc,EAAE,OAAO,CAAC,cAAc;QACtC,qBAAqB,EAAE,OAAO,CAAC,qBAAqB;QACpD,eAAe,EAAE,OAAO,CAAC,eAAe;QACxC,mBAAmB,EAAE,OAAO,CAAC,mBAAmB;QAChD,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,qBAAqB,EAAE,OAAO,CAAC,qBAAqB;QACpD,YAAY;QACZ,oGAAoG;QACpG,6GAA6G;QAC7G,sIAAsI;QACtI,SAAS,EACP,OAAO,CAAC,QAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS;KACxF,CAAC,CAAC;IAEH,wGAAwG;IACxG,uDAAuD;IACvD,MAAM,eAAe,GAAG,CAAC,OAAO,CAAC,eAAe,IAAI,CAAC,CAAC,YAAY,CAAC;IACnE,IAAI,eAAe,IAAI,OAAO,CAAC,OAAO,IAAI,IAAI,EAAE;QAC9C,MAAM,IAAI,GAAG,eAAe,OAAO,CAAC,OAAO,EAAE,CAAC;QAC9C,sBAAsB,CAAC,IAAI,CAAC;YAC1B,IAAI,EAAE,qBAAqB;YAC3B,YAAY,EAAE,IAAI,GAAG,EAAE;YACvB,SAAS,EAAE,GAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;YACxC,mBAAmB,EAAE,IAAI,qBAAW,EAAE;YACtC,MAAM,EAAE;gBACN;oBACE,IAAI,EAAE,mBAAmB;oBACzB,IAAI,EAAE;wBACJ,IAAI;wBACJ,SAAS,EAAE,IAAA,oBAAU,EAAC,IAAI,CAAC;wBAC3B,GAAG,EAAE,EAAE;qBACR;iBACF;aACF;SACF,CAAC,CAAC;KACJ;IAED,MAAM,QAAQ,GAAG,IAAA,+BAAc,EAAC,sBAAsB,EAAE,qBAAqB,CAAC;SAC3E,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC;SAC3B,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,MAAM,IAAI,GAAG,IAAA,+BAAc,EAAC,CAAC,GAAG,YAAY,CAAC,EAAE,qBAAqB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC;QAC5F,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC;QACnC,IAAI;KACL,CAAC,CAAC;IACH,OAAO;QACL,GAAG,EAAE,OAAO;QACZ,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC;YAChC,EAAE;YACF,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG;SAC3C,CAAc;KAChB,CAAC;AACJ,CAAC;AAxGD,oEAwGC"}

View File

@@ -0,0 +1,37 @@
/**
* Copyright © 2022 650 Industries.
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* Fork of the metro helper, but with bundle splitting support.
* https://github.com/facebook/metro/blob/bbdd7d7c5e6e0feb50a9967ffae1f723c1d7c4e8/packages/metro/src/DeltaBundler/Serializers/helpers/js.js#L1
*/
import type { MixedOutput, Module } from 'metro';
import type { JsOutput } from 'metro-transform-worker';
export type Options = {
createModuleId: (module: string) => number | string;
dev: boolean;
includeAsyncPaths: boolean;
projectRoot: string;
serverRoot: string;
sourceUrl: string | undefined;
splitChunks: boolean;
skipWrapping: boolean;
computedAsyncModulePaths: Record<string, string> | null;
};
export declare function wrapModule(module: Module, options: Options): {
src: string;
paths: Record<string, string>;
};
export declare function getModuleParams(module: Module, options: Pick<Options, 'createModuleId' | 'sourceUrl' | 'includeAsyncPaths' | 'serverRoot' | 'splitChunks' | 'dev' | 'projectRoot' | 'computedAsyncModulePaths'>): {
params: any[];
paths: Record<string, string>;
};
export declare function getJsOutput(module: {
output: readonly MixedOutput[];
path?: string;
}): JsOutput;
export declare function isJsModule(module: Module): boolean;
export declare function isJsOutput(output: MixedOutput): output is MixedOutput;

View File

@@ -0,0 +1,102 @@
"use strict";
/**
* Copyright © 2022 650 Industries.
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* Fork of the metro helper, but with bundle splitting support.
* https://github.com/facebook/metro/blob/bbdd7d7c5e6e0feb50a9967ffae1f723c1d7c4e8/packages/metro/src/DeltaBundler/Serializers/helpers/js.js#L1
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.isJsOutput = exports.isJsModule = exports.getJsOutput = exports.getModuleParams = exports.wrapModule = void 0;
const assert_1 = __importDefault(require("assert"));
const jsc_safe_url_1 = __importDefault(require("jsc-safe-url"));
const metro_transform_plugins_1 = require("metro-transform-plugins");
const path_1 = __importDefault(require("path"));
function wrapModule(module, options) {
const output = getJsOutput(module);
if (output.type.startsWith('js/script')) {
return { src: output.data.code, paths: {} };
}
const { params, paths } = getModuleParams(module, options);
const src = (0, metro_transform_plugins_1.addParamsToDefineCall)(output.data.code, ...params);
return { src, paths };
}
exports.wrapModule = wrapModule;
function getModuleParams(module, options) {
const moduleId = options.createModuleId(module.path);
const paths = {};
let hasPaths = false;
const dependencyMapArray = Array.from(module.dependencies.values()).map((dependency) => {
const id = options.createModuleId(dependency.absolutePath);
if (
// NOTE(EvanBacon): Disabled this to ensure that paths are provided even when the entire bundle
// is created. This is required for production bundle splitting.
// options.includeAsyncPaths &&
dependency.data.data.asyncType != null) {
if (options.includeAsyncPaths) {
if (options.sourceUrl) {
hasPaths = true;
// TODO: Only include path if the target is not in the bundle
// Construct a server-relative URL for the split bundle, propagating
// most parameters from the main bundle's URL.
const { searchParams } = new URL(jsc_safe_url_1.default.toNormalUrl(options.sourceUrl));
searchParams.set('modulesOnly', 'true');
searchParams.set('runModule', 'false');
const bundlePath = path_1.default.relative(options.serverRoot, dependency.absolutePath);
paths[id] =
'/' +
path_1.default.join(path_1.default.dirname(bundlePath),
// Strip the file extension
path_1.default.basename(bundlePath, path_1.default.extname(bundlePath))) +
'.bundle?' +
searchParams.toString();
}
}
else if (options.splitChunks && options.computedAsyncModulePaths != null) {
hasPaths = true;
// A template string that we'll match and replace later when we know the content hash for a given path.
paths[id] = options.computedAsyncModulePaths[dependency.absolutePath];
}
}
return id;
});
const params = [
moduleId,
hasPaths
? {
...dependencyMapArray,
paths,
}
: dependencyMapArray,
];
if (options.dev) {
// Add the relative path of the module to make debugging easier.
// This is mapped to `module.verboseName` in `require.js`.
params.push(path_1.default.relative(options.projectRoot, module.path));
}
return { params, paths };
}
exports.getModuleParams = getModuleParams;
function getJsOutput(module) {
const jsModules = module.output.filter(({ type }) => type.startsWith('js/'));
(0, assert_1.default)(jsModules.length === 1, `Modules must have exactly one JS output, but ${module.path ?? 'unknown module'} has ${jsModules.length} JS outputs.`);
const jsOutput = jsModules[0];
(0, assert_1.default)(Number.isFinite(jsOutput.data.lineCount), `JS output must populate lineCount, but ${module.path ?? 'unknown module'} has ${jsOutput.type} output with lineCount '${jsOutput.data.lineCount}'`);
return jsOutput;
}
exports.getJsOutput = getJsOutput;
function isJsModule(module) {
return module.output.filter(isJsOutput).length > 0;
}
exports.isJsModule = isJsModule;
function isJsOutput(output) {
return output.type.startsWith('js/');
}
exports.isJsOutput = isJsOutput;
//# sourceMappingURL=js.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"js.js","sourceRoot":"","sources":["../../../src/serializer/fork/js.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,23 @@
/**
* Copyright © 2022 650 Industries.
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import type { Module } from 'metro';
export declare function processModules(modules: readonly Module[], { filter, createModuleId, dev, includeAsyncPaths, projectRoot, serverRoot, sourceUrl, splitChunks, skipWrapping, computedAsyncModulePaths, }: {
splitChunks: boolean;
filter?: (module: Module) => boolean;
createModuleId: (module: string) => number;
dev: boolean;
includeAsyncPaths: boolean;
projectRoot: string;
serverRoot: string;
sourceUrl: string | undefined;
skipWrapping: boolean;
computedAsyncModulePaths: Record<string, string> | null;
}): readonly [Module, {
src: string;
paths: Record<string, string>;
}][];

View File

@@ -0,0 +1,32 @@
"use strict";
/**
* Copyright © 2022 650 Industries.
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.processModules = void 0;
const js_1 = require("./js");
function processModules(modules, { filter = () => true, createModuleId, dev, includeAsyncPaths, projectRoot, serverRoot, sourceUrl, splitChunks, skipWrapping, computedAsyncModulePaths, }) {
return [...modules]
.filter(js_1.isJsModule)
.filter(filter)
.map((module) => [
module,
(0, js_1.wrapModule)(module, {
splitChunks,
createModuleId,
dev,
includeAsyncPaths,
projectRoot,
serverRoot,
sourceUrl,
skipWrapping,
computedAsyncModulePaths,
}),
]);
}
exports.processModules = processModules;
//# sourceMappingURL=processModules.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"processModules.js","sourceRoot":"","sources":["../../../src/serializer/fork/processModules.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;AAIH,6BAA8C;AAE9C,SAAgB,cAAc,CAC5B,OAA0B,EAC1B,EACE,MAAM,GAAG,GAAG,EAAE,CAAC,IAAI,EACnB,cAAc,EACd,GAAG,EACH,iBAAiB,EACjB,WAAW,EACX,UAAU,EACV,SAAS,EACT,WAAW,EACX,YAAY,EACZ,wBAAwB,GAYzB;IAED,OAAO,CAAC,GAAG,OAAO,CAAC;SAChB,MAAM,CAAC,eAAU,CAAC;SAClB,MAAM,CAAC,MAAM,CAAC;SACd,GAAG,CAAC,CAAC,MAAc,EAAE,EAAE,CAAC;QACvB,MAAM;QACN,IAAA,eAAU,EAAC,MAAM,EAAE;YACjB,WAAW;YACX,cAAc;YACd,GAAG;YACH,iBAAiB;YACjB,WAAW;YACX,UAAU;YACV,SAAS;YACT,YAAY;YACZ,wBAAwB;SACzB,CAAC;KACH,CAAC,CAAC;AACP,CAAC;AA3CD,wCA2CC"}

View File

@@ -0,0 +1,34 @@
import type { Module } from 'metro';
import { SerialAsset } from './serializerAssets';
export type ReadOnlyDependencies<T = any> = ReadonlyMap<string, Module<T>>;
type Options = {
processModuleFilter: (modules: Module) => boolean;
assetPlugins: readonly string[];
platform?: string | null;
projectRoot: string;
publicPath: string;
};
export type JSModule = Module<{
data: {
code: string;
map: unknown;
lineCount: number;
css?: {
code: string;
map: unknown;
lineCount: number;
skipCache?: boolean;
};
};
type: 'js/module';
}> & {
unstable_transformResultKey?: string;
};
export declare function filterJsModules(dependencies: ReadOnlyDependencies, type: 'js/script' | 'js/module' | 'js/module/asset', { processModuleFilter, projectRoot }: Pick<Options, 'projectRoot' | 'processModuleFilter'>): JSModule[];
export declare function getCssSerialAssets<T extends any>(dependencies: ReadOnlyDependencies<T>, { processModuleFilter, projectRoot }: Pick<Options, 'projectRoot' | 'processModuleFilter'>): SerialAsset[];
export declare function fileNameFromContents({ filepath, src }: {
filepath: string;
src: string;
}): string;
export declare function getFileName(module: string): string;
export {};

View File

@@ -0,0 +1,79 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getFileName = exports.fileNameFromContents = exports.getCssSerialAssets = exports.filterJsModules = void 0;
const js_1 = require("metro/src/DeltaBundler/Serializers/helpers/js");
const path_1 = __importDefault(require("path"));
const css_1 = require("../transform-worker/css");
const hash_1 = require("../utils/hash");
// s = static
const STATIC_EXPORT_DIRECTORY = '_expo/static/css';
function filterJsModules(dependencies, type, { processModuleFilter, projectRoot }) {
const assets = [];
for (const module of dependencies.values()) {
if ((0, js_1.isJsModule)(module) &&
processModuleFilter(module) &&
(0, js_1.getJsOutput)(module).type === type &&
path_1.default.relative(projectRoot, module.path) !== 'package.json') {
assets.push(module);
}
}
return assets;
}
exports.filterJsModules = filterJsModules;
function getCssSerialAssets(dependencies, { processModuleFilter, projectRoot }) {
const assets = [];
for (const module of filterJsModules(dependencies, 'js/module', {
processModuleFilter,
projectRoot,
})) {
const cssMetadata = getCssMetadata(module);
if (cssMetadata) {
const contents = cssMetadata.code;
const originFilename = path_1.default.relative(projectRoot, module.path);
const filename = path_1.default.join(
// Consistent location
STATIC_EXPORT_DIRECTORY,
// Hashed file contents + name for caching
fileNameFromContents({
// Stable filename for hashing in CI.
filepath: originFilename,
src: contents,
}) + '.css');
assets.push({
type: 'css',
originFilename,
filename,
source: contents,
metadata: {
hmrId: (0, css_1.pathToHtmlSafeName)(originFilename),
},
});
}
}
return assets;
}
exports.getCssSerialAssets = getCssSerialAssets;
function getCssMetadata(module) {
const data = module.output[0]?.data;
if (data && typeof data === 'object' && 'css' in data) {
if (typeof data.css !== 'object' || !('code' in data.css)) {
throw new Error(`Unexpected CSS metadata in Metro module (${module.path}): ${JSON.stringify(data.css)}`);
}
return data.css;
}
return null;
}
function fileNameFromContents({ filepath, src }) {
// Decode if the path is encoded from the Metro dev server, then normalize paths for Windows support.
const decoded = decodeURIComponent(filepath).replace(/\\/g, '/');
return getFileName(decoded) + '-' + (0, hash_1.hashString)(src);
}
exports.fileNameFromContents = fileNameFromContents;
function getFileName(module) {
return path_1.default.basename(module).replace(/\.[^.]+$/, '');
}
exports.getFileName = getFileName;
//# sourceMappingURL=getCssDeps.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"getCssDeps.js","sourceRoot":"","sources":["../../src/serializer/getCssDeps.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,41 @@
/**
* Copyright © 2023-present 650 Industries (Expo). All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import { FBSourceFunctionMap, MetroSourceMapSegmentTuple } from 'metro-source-map';
export type JSFileType = 'js/script' | 'js/module' | 'js/module/asset';
export type JsOutput = {
data: {
code: string;
lineCount: number;
map: MetroSourceMapSegmentTuple[];
functionMap: FBSourceFunctionMap | null;
css?: {
code: string;
lineCount: number;
map: MetroSourceMapSegmentTuple[];
functionMap: FBSourceFunctionMap | null;
};
};
type: JSFileType;
};
export type ExpoJsOutput = Omit<JsOutput, 'data'> & {
data: JsOutput['data'] & {
profiling?: {
start: number;
end: number;
duration: number;
};
css?: {
code: string;
lineCount: number;
map: unknown[];
functionMap: null;
skipCache?: boolean;
};
};
};
export declare function isExpoJsOutput(output: any): output is ExpoJsOutput;
export declare function isTransformOptionTruthy(option: any): boolean;

View File

@@ -0,0 +1,14 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isTransformOptionTruthy = exports.isExpoJsOutput = void 0;
function isExpoJsOutput(output) {
return 'data' in output && typeof output.data === 'object';
}
exports.isExpoJsOutput = isExpoJsOutput;
// Because transform options can be passed directly during export, or through a query parameter
// during a request, we need to normalize the options.
function isTransformOptionTruthy(option) {
return option === true || option === 'true' || option === '1';
}
exports.isTransformOptionTruthy = isTransformOptionTruthy;
//# sourceMappingURL=jsOutput.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"jsOutput.js","sourceRoot":"","sources":["../../src/serializer/jsOutput.ts"],"names":[],"mappings":";;;AA4CA,SAAgB,cAAc,CAAC,MAAW;IACxC,OAAO,MAAM,IAAI,MAAM,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,CAAC;AAC7D,CAAC;AAFD,wCAEC;AAED,+FAA+F;AAC/F,sDAAsD;AACtD,SAAgB,uBAAuB,CAAC,MAAW;IACjD,OAAO,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,GAAG,CAAC;AAChE,CAAC;AAFD,0DAEC"}

View File

@@ -0,0 +1,44 @@
import { AssetData, MetroConfig, MixedOutput, Module, ReadOnlyGraph } from 'metro';
import { ConfigT, SerializerConfigT } from 'metro-config';
import { ExpoSerializerOptions } from './fork/baseJSBundle';
import { SerialAsset } from './serializerAssets';
import { SerializerConfigOptions } from './withExpoSerializers';
type Serializer = NonNullable<ConfigT['serializer']['customSerializer']>;
type SerializerParameters = Parameters<Serializer>;
export type SerializeChunkOptions = {
includeSourceMaps: boolean;
splitChunks: boolean;
} & SerializerConfigOptions;
export declare function graphToSerialAssetsAsync(config: MetroConfig, serializeChunkOptions: SerializeChunkOptions, ...props: SerializerParameters): Promise<{
artifacts: SerialAsset[] | null;
assets: AssetData[];
}>;
export declare class Chunk {
name: string;
entries: Module<MixedOutput>[];
graph: ReadOnlyGraph<MixedOutput>;
options: ExpoSerializerOptions;
isAsync: boolean;
isVendor: boolean;
deps: Set<Module>;
preModules: Set<Module>;
requiredChunks: Set<Chunk>;
constructor(name: string, entries: Module<MixedOutput>[], graph: ReadOnlyGraph<MixedOutput>, options: ExpoSerializerOptions, isAsync?: boolean, isVendor?: boolean);
private getPlatform;
private getFilename;
private getStableChunkSource;
private getFilenameForConfig;
private serializeToCodeWithTemplates;
hasAbsolutePath(absolutePath: string): boolean;
private getComputedPathsForAsyncDependencies;
private getAdjustedSourceMapUrl;
private serializeToCode;
private boolishTransformOption;
serializeToAssetsAsync(serializerConfig: Partial<SerializerConfigT>, chunks: Chunk[], { includeSourceMaps, unstable_beforeAssetSerializationPlugins }: SerializeChunkOptions): Promise<SerialAsset[]>;
private supportsBytecode;
isHermesEnabled(): boolean;
}
export declare function getSortedModules(modules: Module<MixedOutput>[], { createModuleId, }: {
createModuleId: (path: string) => number;
}): readonly Module<any>[];
export {};

View File

@@ -0,0 +1,467 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getSortedModules = exports.Chunk = exports.graphToSerialAssetsAsync = void 0;
/**
* Copyright © 2023 650 Industries.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const assert_1 = __importDefault(require("assert"));
const sourceMapString_1 = __importDefault(require("metro/src/DeltaBundler/Serializers/sourceMapString"));
const bundleToString_1 = __importDefault(require("metro/src/lib/bundleToString"));
const path_1 = __importDefault(require("path"));
const debugId_1 = require("./debugId");
const exportHermes_1 = require("./exportHermes");
const exportPath_1 = require("./exportPath");
const baseJSBundle_1 = require("./fork/baseJSBundle");
const getCssDeps_1 = require("./getCssDeps");
const getAssets_1 = __importDefault(require("../transform-worker/getAssets"));
// Convert file paths to regex matchers.
function pathToRegex(path) {
// Escape regex special characters, except for '*'
let regexSafePath = path.replace(/[-[\]{}()+?.,\\^$|#\s]/g, '\\$&');
// Replace '*' with '.*' to act as a wildcard in regex
regexSafePath = regexSafePath.replace(/\*/g, '.*');
// Create a RegExp object with the modified string
return new RegExp('^' + regexSafePath + '$');
}
const sourceMapString = typeof sourceMapString_1.default !== 'function'
? sourceMapString_1.default.sourceMapString
: sourceMapString_1.default;
async function graphToSerialAssetsAsync(config, serializeChunkOptions, ...props) {
const [entryFile, preModules, graph, options] = props;
const cssDeps = (0, getCssDeps_1.getCssSerialAssets)(graph.dependencies, {
projectRoot: options.projectRoot,
processModuleFilter: options.processModuleFilter,
});
// Create chunks for splitting.
const chunks = new Set();
[
{
test: pathToRegex(entryFile),
},
].map((chunkSettings) => gatherChunks(chunks, chunkSettings, preModules, graph, options, false));
// Get the common modules and extract them into a separate chunk.
const entryChunk = [...chunks.values()].find((chunk) => !chunk.isAsync && chunk.hasAbsolutePath(entryFile));
if (entryChunk) {
for (const chunk of chunks.values()) {
if (chunk !== entryChunk && chunk.isAsync) {
for (const dep of chunk.deps.values()) {
if (entryChunk.deps.has(dep)) {
// Remove the dependency from the async chunk since it will be loaded in the main chunk.
chunk.deps.delete(dep);
}
}
}
}
const toCompare = [...chunks.values()];
const commonDependencies = [];
while (toCompare.length) {
const chunk = toCompare.shift();
for (const chunk2 of toCompare) {
if (chunk !== chunk2 && chunk.isAsync && chunk2.isAsync) {
const commonDeps = [...chunk.deps].filter((dep) => chunk2.deps.has(dep));
for (const dep of commonDeps) {
chunk.deps.delete(dep);
chunk2.deps.delete(dep);
}
commonDependencies.push(...commonDeps);
}
}
}
// If common dependencies were found, extract them to the entry chunk.
// TODO: Extract the metro-runtime to a common chunk apart from the entry chunk then load the common dependencies before the entry chunk.
if (commonDependencies.length) {
for (const dep of commonDependencies) {
entryChunk.deps.add(dep);
}
// const commonDependenciesUnique = [...new Set(commonDependencies)];
// const commonChunk = new Chunk(
// chunkIdForModules(commonDependenciesUnique),
// commonDependenciesUnique,
// graph,
// options,
// false,
// true
// );
// entryChunk.requiredChunks.add(commonChunk);
// chunks.add(commonChunk);
}
// TODO: Optimize this pass more.
// Remove all dependencies from async chunks that are already in the common chunk.
for (const chunk of [...chunks.values()]) {
if (chunk !== entryChunk) {
for (const dep of chunk.deps) {
if (entryChunk.deps.has(dep)) {
chunk.deps.delete(dep);
}
}
}
}
}
const jsAssets = await serializeChunksAsync(chunks, config.serializer ?? {}, serializeChunkOptions);
// TODO: Can this be anything besides true?
const isExporting = true;
const baseUrl = (0, baseJSBundle_1.getBaseUrlOption)(graph, { serializerOptions: serializeChunkOptions });
const assetPublicUrl = (baseUrl.replace(/\/+$/, '') ?? '') + '/assets';
const publicPath = isExporting
? graph.transformOptions.platform === 'web'
? `/assets?export_path=${assetPublicUrl}`
: assetPublicUrl
: '/assets/?unstable_path=.';
// TODO: Convert to serial assets
// TODO: Disable this call dynamically in development since assets are fetched differently.
const metroAssets = (await (0, getAssets_1.default)(graph.dependencies, {
processModuleFilter: options.processModuleFilter,
assetPlugins: config.transformer?.assetPlugins ?? [],
platform: (0, baseJSBundle_1.getPlatformOption)(graph, options) ?? 'web',
projectRoot: options.projectRoot,
publicPath,
}));
return { artifacts: [...jsAssets, ...cssDeps], assets: metroAssets };
}
exports.graphToSerialAssetsAsync = graphToSerialAssetsAsync;
class Chunk {
name;
entries;
graph;
options;
isAsync;
isVendor;
deps = new Set();
preModules = new Set();
// Chunks that are required to be loaded synchronously before this chunk.
// These are included in the HTML as <script> tags.
requiredChunks = new Set();
constructor(name, entries, graph, options, isAsync = false, isVendor = false) {
this.name = name;
this.entries = entries;
this.graph = graph;
this.options = options;
this.isAsync = isAsync;
this.isVendor = isVendor;
this.deps = new Set(entries);
}
getPlatform() {
(0, assert_1.default)(this.graph.transformOptions.platform, "platform is required to be in graph's transformOptions");
return this.graph.transformOptions.platform;
}
getFilename(src) {
return this.options.dev
? this.name
: (0, exportPath_1.getExportPathForDependencyWithOptions)(this.name, {
platform: this.getPlatform(),
src,
serverRoot: this.options.serverRoot,
});
}
getStableChunkSource(serializerConfig) {
return this.options.dev
? ''
: this.serializeToCodeWithTemplates(serializerConfig, {
// Disable source maps when creating a sha to reduce the number of possible changes that could
// influence the cache hit.
serializerOptions: {
includeSourceMaps: false,
},
sourceMapUrl: undefined,
debugId: undefined,
});
}
getFilenameForConfig(serializerConfig) {
return this.getFilename(this.getStableChunkSource(serializerConfig));
}
serializeToCodeWithTemplates(serializerConfig, options = {}) {
const entryFile = this.name;
// TODO: Disable all debugId steps when a dev server is enabled. This is an export-only feature.
const preModules = [...this.preModules.values()];
const dependencies = [...this.deps];
const jsSplitBundle = (0, baseJSBundle_1.baseJSBundleWithDependencies)(entryFile, preModules, dependencies, {
...this.options,
runBeforeMainModule: serializerConfig?.getModulesRunBeforeMainModule?.(path_1.default.relative(this.options.projectRoot, entryFile)) ?? [],
runModule: !this.isVendor && !this.isAsync,
modulesOnly: this.preModules.size === 0,
platform: this.getPlatform(),
baseUrl: (0, baseJSBundle_1.getBaseUrlOption)(this.graph, this.options),
splitChunks: !!this.options.serializerOptions?.splitChunks,
skipWrapping: true,
computedAsyncModulePaths: null,
...options,
});
return (0, bundleToString_1.default)(jsSplitBundle).code;
}
hasAbsolutePath(absolutePath) {
return [...this.deps].some((module) => module.path === absolutePath);
}
getComputedPathsForAsyncDependencies(serializerConfig, chunks) {
const baseUrl = (0, baseJSBundle_1.getBaseUrlOption)(this.graph, this.options);
// Only calculate production paths when all chunks are being exported.
if (this.options.includeAsyncPaths) {
return null;
}
const computedAsyncModulePaths = {};
this.deps.forEach((module) => {
module.dependencies.forEach((dependency) => {
if (dependency.data.data.asyncType) {
const chunkContainingModule = chunks.find((chunk) => chunk.hasAbsolutePath(dependency.absolutePath));
(0, assert_1.default)(chunkContainingModule, 'Chunk containing module not found: ' + dependency.absolutePath);
// NOTE(kitten): We shouldn't have any async imports on non-async chunks
// However, due to how chunks merge, some async imports may now be pointing
// at entrypoint (or vendor) chunks. We omit the path so that the async import
// helper doesn't reload and reevaluate the entrypoint.
if (chunkContainingModule.isAsync) {
const moduleIdName = chunkContainingModule.getFilenameForConfig(serializerConfig);
computedAsyncModulePaths[dependency.absolutePath] = (baseUrl ?? '/') + moduleIdName;
}
}
});
});
return computedAsyncModulePaths;
}
getAdjustedSourceMapUrl(serializerConfig) {
// Metro really only accounts for development, so we'll use the defaults here.
if (this.options.dev) {
return this.options.sourceMapUrl ?? null;
}
if (this.options.serializerOptions?.includeSourceMaps !== true) {
return null;
}
if (this.options.inlineSourceMap || !this.options.sourceMapUrl) {
return this.options.sourceMapUrl ?? null;
}
const platform = this.getPlatform();
const isAbsolute = platform !== 'web';
const baseUrl = (0, baseJSBundle_1.getBaseUrlOption)(this.graph, this.options);
const filename = this.getFilenameForConfig(serializerConfig);
const isAbsoluteBaseUrl = !!baseUrl?.match(/https?:\/\//);
const pathname = (isAbsoluteBaseUrl ? '' : baseUrl.replace(/\/+$/, '')) +
'/' +
filename.replace(/^\/+$/, '') +
'.map';
let adjustedSourceMapUrl = this.options.sourceMapUrl;
// Metro has lots of issues...
if (this.options.sourceMapUrl.startsWith('//localhost')) {
adjustedSourceMapUrl = 'http:' + this.options.sourceMapUrl;
}
try {
const parsed = new URL(pathname, isAbsoluteBaseUrl ? baseUrl : adjustedSourceMapUrl);
if (isAbsoluteBaseUrl || isAbsolute) {
return parsed.href;
}
return parsed.pathname;
}
catch (error) {
// NOTE: export:embed that don't use baseUrl will use file paths instead of URLs.
if (!this.options.dev && isAbsolute) {
return adjustedSourceMapUrl;
}
console.error(`Failed to link source maps because the source map URL "${this.options.sourceMapUrl}" is corrupt:`, error);
return null;
}
}
serializeToCode(serializerConfig, { debugId, chunks }) {
return this.serializeToCodeWithTemplates(serializerConfig, {
skipWrapping: false,
sourceMapUrl: this.getAdjustedSourceMapUrl(serializerConfig) ?? undefined,
computedAsyncModulePaths: this.getComputedPathsForAsyncDependencies(serializerConfig, chunks),
debugId,
});
}
boolishTransformOption(name) {
const value = this.graph.transformOptions?.customTransformOptions?.[name];
return value === true || value === 'true';
}
async serializeToAssetsAsync(serializerConfig, chunks, { includeSourceMaps, unstable_beforeAssetSerializationPlugins }) {
// Create hash without wrapping to prevent it changing when the wrapping changes.
const outputFile = this.getFilenameForConfig(serializerConfig);
// We already use a stable hash for the output filename, so we'll reuse that for the debugId.
const debugId = (0, debugId_1.stringToUUID)(path_1.default.basename(outputFile, path_1.default.extname(outputFile)));
let premodules = [...this.preModules];
if (unstable_beforeAssetSerializationPlugins) {
for (const plugin of unstable_beforeAssetSerializationPlugins) {
premodules = plugin({ graph: this.graph, premodules, debugId });
}
this.preModules = new Set(premodules);
}
const jsCode = this.serializeToCode(serializerConfig, { chunks, debugId });
const relativeEntry = path_1.default.relative(this.options.projectRoot, this.name);
const jsAsset = {
filename: outputFile,
originFilename: relativeEntry,
type: 'js',
metadata: {
isAsync: this.isAsync,
requires: [...this.requiredChunks.values()].map((chunk) => chunk.getFilenameForConfig(serializerConfig)),
// Provide a list of module paths that can be used for matching chunks to routes.
// TODO: Move HTML serializing closer to this code so we can reduce passing this much data around.
modulePaths: [...this.deps].map((module) => module.path),
},
source: jsCode,
};
const assets = [jsAsset];
const mutateSourceMapWithDebugId = (sourceMap) => {
// TODO: Upstream this so we don't have to parse the source map back and forth.
if (!debugId) {
return sourceMap;
}
// NOTE: debugId isn't required for inline source maps because the source map is included in the same file, therefore
// we don't need to disambiguate between multiple source maps.
const sourceMapObject = JSON.parse(sourceMap);
sourceMapObject.debugId = debugId;
// NOTE: Sentry does this, but bun does not.
// sourceMapObject.debug_id = debugId;
return JSON.stringify(sourceMapObject);
};
if (
// Only include the source map if the `options.sourceMapUrl` option is provided and we are exporting a static build.
includeSourceMaps &&
!this.options.inlineSourceMap &&
this.options.sourceMapUrl) {
const modules = [
...this.preModules,
...getSortedModules([...this.deps], {
createModuleId: this.options.createModuleId,
}),
].map((module) => {
// TODO: Make this user-configurable.
// Make all paths relative to the server root to prevent the entire user filesystem from being exposed.
if (module.path.startsWith('/')) {
return {
...module,
path: '/' + path_1.default.relative(this.options.serverRoot ?? this.options.projectRoot, module.path),
};
}
return module;
});
// TODO: We may not need to mutate the original source map with a `debugId` when hermes is enabled since we'll have different source maps.
const sourceMap = mutateSourceMapWithDebugId(sourceMapString(modules, {
excludeSource: false,
...this.options,
}));
assets.push({
filename: this.options.dev ? jsAsset.filename + '.map' : outputFile + '.map',
originFilename: jsAsset.originFilename,
type: 'map',
metadata: {},
source: sourceMap,
});
}
if (this.boolishTransformOption('bytecode') && this.isHermesEnabled()) {
const adjustedSource = jsAsset.source.replace(/^\/\/# (sourceMappingURL)=(.*)$/gm, (...props) => {
if (props[1] === 'sourceMappingURL') {
const mapName = props[2].replace(/\.js\.map$/, '.hbc.map');
return `//# ${props[1]}=` + mapName;
}
return '';
});
// TODO: Generate hbc for each chunk
const hermesBundleOutput = await (0, exportHermes_1.buildHermesBundleAsync)({
filename: this.name,
code: adjustedSource,
map: assets[1] ? assets[1].source : null,
// TODO: Maybe allow prod + no minify.
minify: true, //!this.options.dev,
});
if (hermesBundleOutput.hbc) {
// TODO: Unclear if we should add multiple assets, link the assets, or mutate the first asset.
// jsAsset.metadata.hbc = hermesBundleOutput.hbc;
// @ts-expect-error: TODO
jsAsset.source = hermesBundleOutput.hbc;
jsAsset.filename = jsAsset.filename.replace(/\.js$/, '.hbc');
}
if (assets[1] && hermesBundleOutput.sourcemap) {
assets[1].source = mutateSourceMapWithDebugId(hermesBundleOutput.sourcemap);
assets[1].filename = assets[1].filename.replace(/\.js\.map$/, '.hbc.map');
}
}
return assets;
}
supportsBytecode() {
return this.getPlatform() !== 'web';
}
isHermesEnabled() {
// TODO: Revisit.
// TODO: There could be an issue with having the serializer for export:embed output hermes since the native scripts will
// also create hermes bytecode. We may need to disable in one of the two places.
return (!this.options.dev &&
this.supportsBytecode() &&
this.graph.transformOptions.customTransformOptions?.engine === 'hermes');
}
}
exports.Chunk = Chunk;
function getEntryModulesForChunkSettings(graph, settings) {
return [...graph.dependencies.entries()]
.filter(([path]) => settings.test.test(path))
.map(([, module]) => module);
}
function chunkIdForModules(modules) {
return modules
.map((module) => module.path)
.sort()
.join('=>');
}
function gatherChunks(chunks, settings, preModules, graph, options, isAsync = false) {
let entryModules = getEntryModulesForChunkSettings(graph, settings);
const existingChunks = [...chunks.values()];
entryModules = entryModules.filter((module) => {
return !existingChunks.find((chunk) => chunk.entries.includes(module));
});
// Prevent processing the same entry file twice.
if (!entryModules.length) {
return chunks;
}
const entryChunk = new Chunk(chunkIdForModules(entryModules), entryModules, graph, options, isAsync);
// Add all the pre-modules to the first chunk.
if (preModules.length) {
// On native, use the preModules in insert code in the entry chunk.
for (const module of preModules.values()) {
entryChunk.preModules.add(module);
}
}
chunks.add(entryChunk);
function includeModule(entryModule) {
for (const dependency of entryModule.dependencies.values()) {
if (dependency.data.data.asyncType &&
// Support disabling multiple chunks.
entryChunk.options.serializerOptions?.splitChunks !== false) {
gatherChunks(chunks, { test: pathToRegex(dependency.absolutePath) }, [], graph, options, true);
}
else {
const module = graph.dependencies.get(dependency.absolutePath);
if (module) {
// Prevent circular dependencies from creating infinite loops.
if (!entryChunk.deps.has(module)) {
entryChunk.deps.add(module);
includeModule(module);
}
}
}
}
}
for (const entryModule of entryModules) {
includeModule(entryModule);
}
return chunks;
}
async function serializeChunksAsync(chunks, serializerConfig, options) {
const jsAssets = [];
const chunksArray = [...chunks.values()];
await Promise.all(chunksArray.map(async (chunk) => {
jsAssets.push(...(await chunk.serializeToAssetsAsync(serializerConfig, chunksArray, options)));
}));
return jsAssets;
}
function getSortedModules(modules, { createModuleId, }) {
// Assign IDs to modules in a consistent order
for (const module of modules) {
createModuleId(module.path);
}
// Sort by IDs
return modules.sort((a, b) => createModuleId(a.path) - createModuleId(b.path));
}
exports.getSortedModules = getSortedModules;
//# sourceMappingURL=serializeChunks.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,10 @@
export type SerialAsset = {
originFilename: string;
filename: string;
source: string;
type: 'css' | 'js' | 'map';
metadata: {
isAsync?: boolean;
modulePaths?: string[];
} & Record<string, boolean | string | string[]>;
};

View File

@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=serializerAssets.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"serializerAssets.js","sourceRoot":"","sources":["../../src/serializer/serializerAssets.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1,24 @@
import { MetroConfig, MixedOutput, Module, ReadOnlyGraph } from 'metro';
import { ConfigT, InputConfigT } from 'metro-config';
import { ExpoSerializerOptions } from './fork/baseJSBundle';
import { SerialAsset } from './serializerAssets';
export type Serializer = NonNullable<ConfigT['serializer']['customSerializer']>;
export type SerializerParameters = [
string,
readonly Module[],
ReadOnlyGraph,
ExpoSerializerOptions
];
export type SerializerConfigOptions = {
unstable_beforeAssetSerializationPlugins?: ((serializationInput: {
graph: ReadOnlyGraph<MixedOutput>;
premodules: Module[];
debugId?: string;
}) => Module[])[];
};
export type SerializerPlugin = (...props: SerializerParameters) => SerializerParameters;
export declare function withExpoSerializers(config: InputConfigT, options?: SerializerConfigOptions): InputConfigT;
export declare function withSerializerPlugins(config: InputConfigT, processors: SerializerPlugin[], options?: SerializerConfigOptions): InputConfigT;
export declare function createDefaultExportCustomSerializer(config: Partial<MetroConfig>, configOptions?: SerializerConfigOptions): Serializer;
export declare function createSerializerFromSerialProcessors(config: MetroConfig, processors: (SerializerPlugin | undefined)[], originalSerializer: Serializer | null, options?: SerializerConfigOptions): Serializer;
export { SerialAsset };

View File

@@ -0,0 +1,207 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createSerializerFromSerialProcessors = exports.createDefaultExportCustomSerializer = exports.withSerializerPlugins = exports.withExpoSerializers = void 0;
/**
* Copyright © 2022 650 Industries.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const jsc_safe_url_1 = require("jsc-safe-url");
const sourceMapString_1 = __importDefault(require("metro/src/DeltaBundler/Serializers/sourceMapString"));
const bundleToString_1 = __importDefault(require("metro/src/lib/bundleToString"));
const debugId_1 = require("./debugId");
const environmentVariableSerializerPlugin_1 = require("./environmentVariableSerializerPlugin");
const baseJSBundle_1 = require("./fork/baseJSBundle");
const serializeChunks_1 = require("./serializeChunks");
const env_1 = require("../env");
const sourceMapString = typeof sourceMapString_1.default !== 'function'
? sourceMapString_1.default.sourceMapString
: sourceMapString_1.default;
function withExpoSerializers(config, options = {}) {
const processors = [];
processors.push(environmentVariableSerializerPlugin_1.serverPreludeSerializerPlugin);
if (!env_1.env.EXPO_NO_CLIENT_ENV_VARS) {
processors.push(environmentVariableSerializerPlugin_1.environmentVariableSerializerPlugin);
}
return withSerializerPlugins(config, processors, options);
}
exports.withExpoSerializers = withExpoSerializers;
// There can only be one custom serializer as the input doesn't match the output.
// Here we simply run
function withSerializerPlugins(config, processors, options = {}) {
const originalSerializer = config.serializer?.customSerializer;
return {
...config,
serializer: {
...config.serializer,
customSerializer: createSerializerFromSerialProcessors(config, processors, originalSerializer ?? null, options),
},
};
}
exports.withSerializerPlugins = withSerializerPlugins;
function createDefaultExportCustomSerializer(config, configOptions = {}) {
return async (entryPoint, preModules, graph, options) => {
const isPossiblyDev = graph.transformOptions.hot;
// TODO: This is a temporary solution until we've converged on using the new serializer everywhere.
const enableDebugId = options.inlineSourceMap !== true && !isPossiblyDev;
let debugId;
const loadDebugId = () => {
if (!enableDebugId || debugId) {
return debugId;
}
// TODO: Perform this cheaper.
const bundle = (0, baseJSBundle_1.baseJSBundle)(entryPoint, preModules, graph, {
...options,
debugId: undefined,
});
const outputCode = (0, bundleToString_1.default)(bundle).code;
debugId = (0, debugId_1.stringToUUID)(outputCode);
return debugId;
};
let premodulesToBundle = [...preModules];
let bundleCode = null;
let bundleMap = null;
if (config.serializer?.customSerializer) {
const bundle = await config.serializer?.customSerializer(entryPoint, premodulesToBundle, graph, options);
if (typeof bundle === 'string') {
bundleCode = bundle;
}
else {
bundleCode = bundle.code;
bundleMap = bundle.map;
}
}
else {
const debugId = loadDebugId();
if (configOptions.unstable_beforeAssetSerializationPlugins) {
for (const plugin of configOptions.unstable_beforeAssetSerializationPlugins) {
premodulesToBundle = plugin({ graph, premodules: [...premodulesToBundle], debugId });
}
}
bundleCode = (0, bundleToString_1.default)((0, baseJSBundle_1.baseJSBundle)(entryPoint, premodulesToBundle, graph, {
...options,
debugId,
})).code;
}
const getEnsuredMaps = () => {
bundleMap ??= sourceMapString([...premodulesToBundle, ...(0, serializeChunks_1.getSortedModules)([...graph.dependencies.values()], options)], {
// TODO: Surface this somehow.
excludeSource: false,
// excludeSource: options.serializerOptions?.excludeSource,
processModuleFilter: options.processModuleFilter,
shouldAddToIgnoreList: options.shouldAddToIgnoreList,
});
return bundleMap;
};
if (!bundleMap && options.sourceUrl) {
const url = (0, jsc_safe_url_1.isJscSafeUrl)(options.sourceUrl)
? (0, jsc_safe_url_1.toNormalUrl)(options.sourceUrl)
: options.sourceUrl;
const parsed = new URL(url, 'http://expo.dev');
// Is dev server request for source maps...
if (parsed.pathname.endsWith('.map')) {
return {
code: bundleCode,
map: getEnsuredMaps(),
};
}
}
if (isPossiblyDev) {
if (bundleMap == null) {
return bundleCode;
}
return {
code: bundleCode,
map: bundleMap,
};
}
// Exports....
bundleMap ??= getEnsuredMaps();
if (enableDebugId) {
const mutateSourceMapWithDebugId = (sourceMap) => {
// NOTE: debugId isn't required for inline source maps because the source map is included in the same file, therefore
// we don't need to disambiguate between multiple source maps.
const sourceMapObject = JSON.parse(sourceMap);
sourceMapObject.debugId = loadDebugId();
// NOTE: Sentry does this, but bun does not.
// sourceMapObject.debug_id = debugId;
return JSON.stringify(sourceMapObject);
};
return {
code: bundleCode,
map: mutateSourceMapWithDebugId(bundleMap),
};
}
return {
code: bundleCode,
map: bundleMap,
};
};
}
exports.createDefaultExportCustomSerializer = createDefaultExportCustomSerializer;
function getDefaultSerializer(config, fallbackSerializer, configOptions = {}) {
const defaultSerializer = fallbackSerializer ?? createDefaultExportCustomSerializer(config, configOptions);
return async (...props) => {
const [, , , options] = props;
const customSerializerOptions = options.serializerOptions;
// Custom options can only be passed outside of the dev server, meaning
// we don't need to stringify the results at the end, i.e. this is `npx expo export` or `npx expo export:embed`.
const supportsNonSerialReturn = !!customSerializerOptions?.output;
const serializerOptions = (() => {
if (customSerializerOptions) {
return {
outputMode: customSerializerOptions.output,
splitChunks: customSerializerOptions.splitChunks,
includeSourceMaps: customSerializerOptions.includeSourceMaps,
};
}
if (options.sourceUrl) {
const sourceUrl = (0, jsc_safe_url_1.isJscSafeUrl)(options.sourceUrl)
? (0, jsc_safe_url_1.toNormalUrl)(options.sourceUrl)
: options.sourceUrl;
const url = new URL(sourceUrl, 'https://expo.dev');
return {
outputMode: url.searchParams.get('serializer.output'),
splitChunks: url.searchParams.get('serializer.splitChunks') === 'true',
includeSourceMaps: url.searchParams.get('serializer.map') === 'true',
};
}
return null;
})();
if (serializerOptions?.outputMode !== 'static') {
return defaultSerializer(...props);
}
// Mutate the serializer options with the parsed options.
options.serializerOptions = {
...options.serializerOptions,
...serializerOptions,
};
const assets = await (0, serializeChunks_1.graphToSerialAssetsAsync)(config, {
includeSourceMaps: !!serializerOptions.includeSourceMaps,
splitChunks: !!serializerOptions.splitChunks,
...configOptions,
}, ...props);
if (supportsNonSerialReturn) {
// @ts-expect-error: this is future proofing for adding assets to the output as well.
return assets;
}
return JSON.stringify(assets);
};
}
function createSerializerFromSerialProcessors(config, processors, originalSerializer, options = {}) {
const finalSerializer = getDefaultSerializer(config, originalSerializer, options);
return (...props) => {
for (const processor of processors) {
if (processor) {
props = processor(...props);
}
}
return finalSerializer(...props);
};
}
exports.createSerializerFromSerialProcessors = createSerializerFromSerialProcessors;
//# sourceMappingURL=withExpoSerializers.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,4 @@
import { BabelTransformerArgs } from 'metro-babel-transformer';
export declare function transform({ filename, options }: BabelTransformerArgs, assetRegistryPath: string, assetDataPlugins: readonly string[]): Promise<{
ast: import("@babel/parser").ParseResult<import("@babel/types").File>;
}>;

View File

@@ -0,0 +1,34 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.transform = void 0;
/**
* Copyright 2023-present 650 Industries (Expo). All rights reserved.
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* Fork of the upstream transformer, but with modifications made for web production hashing.
* https://github.com/facebook/metro/blob/412771475c540b6f85d75d9dcd5a39a6e0753582/packages/metro-transform-worker/src/utils/assetTransformer.js#L1
*/
const util_1 = require("metro/src/Bundler/util");
const node_path_1 = __importDefault(require("node:path"));
const getAssets_1 = require("./getAssets");
async function transform({ filename, options }, assetRegistryPath, assetDataPlugins) {
options ??= options || {
platform: '',
projectRoot: '',
inlineRequires: false,
minify: false,
};
const absolutePath = node_path_1.default.resolve(options.projectRoot, filename);
const data = await (0, getAssets_1.getUniversalAssetData)(absolutePath, filename, assetDataPlugins, options.platform, options.publicPath);
return {
ast: (0, util_1.generateAssetCodeFileAst)(assetRegistryPath, data),
};
}
exports.transform = transform;
//# sourceMappingURL=asset-transformer.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"asset-transformer.js","sourceRoot":"","sources":["../../src/transform-worker/asset-transformer.ts"],"names":[],"mappings":";;;;;;AAAA;;;;;;;;;GASG;AACH,iDAAkE;AAElE,0DAA6B;AAE7B,2CAAoD;AAE7C,KAAK,UAAU,SAAS,CAC7B,EAAE,QAAQ,EAAE,OAAO,EAAwB,EAC3C,iBAAyB,EACzB,gBAAmC;IAEnC,OAAO,KAAK,OAAO,IAAI;QACrB,QAAQ,EAAE,EAAE;QACZ,WAAW,EAAE,EAAE;QACf,cAAc,EAAE,KAAK;QACrB,MAAM,EAAE,KAAK;KACd,CAAC;IAEF,MAAM,YAAY,GAAG,mBAAI,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IAEjE,MAAM,IAAI,GAAG,MAAM,IAAA,iCAAqB,EACtC,YAAY,EACZ,QAAQ,EACR,gBAAgB,EAChB,OAAO,CAAC,QAAQ,EAChB,OAAO,CAAC,UAAU,CACnB,CAAC;IAEF,OAAO;QACL,GAAG,EAAE,IAAA,+BAAwB,EAAC,iBAAiB,EAAE,IAAI,CAAC;KACvD,CAAC;AACJ,CAAC;AAzBD,8BAyBC"}

View File

@@ -0,0 +1,21 @@
/// <reference types="node" />
export declare function transformCssModuleWeb(props: {
filename: string;
src: string;
options: {
projectRoot: string;
minify: boolean;
dev: boolean;
sourceMap: boolean;
};
}): Promise<{
output: string;
css: Buffer;
map: void | Buffer;
}>;
export declare function convertLightningCssToReactNativeWebStyleSheet(input: import('lightningcss').CSSModuleExports): {
styles: Record<string, string>;
reactNativeWeb: Record<string, any>;
variables: Record<string, string>;
};
export declare function matchCssModule(filePath: string): boolean;

View File

@@ -0,0 +1,68 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.matchCssModule = exports.convertLightningCssToReactNativeWebStyleSheet = exports.transformCssModuleWeb = void 0;
const css_1 = require("./css");
const RNW_CSS_CLASS_ID = '_';
async function transformCssModuleWeb(props) {
const { transform } = require('lightningcss');
// TODO: Add bundling to resolve imports
// https://lightningcss.dev/bundling.html#bundling-order
const cssResults = transform({
filename: props.filename,
code: Buffer.from(props.src),
sourceMap: props.options.sourceMap,
cssModules: {
// Prevent renaming CSS variables to ensure
// variables created in global files are available.
dashedIdents: false,
},
// cssModules: true,
projectRoot: props.options.projectRoot,
minify: props.options.minify,
});
const codeAsString = cssResults.code.toString();
const { styles, reactNativeWeb, variables } = convertLightningCssToReactNativeWebStyleSheet(cssResults.exports);
let outputModule = `module.exports=Object.assign(${JSON.stringify(styles)},{unstable_styles:${JSON.stringify(reactNativeWeb)}},${JSON.stringify(variables)});`;
if (props.options.dev) {
const runtimeCss = (0, css_1.wrapDevelopmentCSS)({
...props,
src: codeAsString,
});
outputModule += '\n' + runtimeCss;
}
return {
output: outputModule,
css: cssResults.code,
map: cssResults.map,
};
}
exports.transformCssModuleWeb = transformCssModuleWeb;
function convertLightningCssToReactNativeWebStyleSheet(input) {
const styles = {};
const reactNativeWeb = {};
const variables = {};
// e.g. { container: { name: 'ahs8IW_container', composes: [], isReferenced: false }, }
Object.entries(input).map(([key, value]) => {
// order matters here
let className = value.name;
if (value.composes.length) {
className += ' ' + value.composes.map((value) => value.name).join(' ');
}
// CSS Variables will be `{string: string}`
if (key.startsWith('--')) {
variables[key] = className;
}
styles[key] = className;
reactNativeWeb[key] = { $$css: true, [RNW_CSS_CLASS_ID]: className };
return {
[key]: { $$css: true, [RNW_CSS_CLASS_ID]: className },
};
});
return { styles, reactNativeWeb, variables };
}
exports.convertLightningCssToReactNativeWebStyleSheet = convertLightningCssToReactNativeWebStyleSheet;
function matchCssModule(filePath) {
return !!/\.module(\.(native|ios|android|web))?\.(css|s[ac]ss)$/.test(filePath);
}
exports.matchCssModule = matchCssModule;
//# sourceMappingURL=css-modules.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"css-modules.js","sourceRoot":"","sources":["../../src/transform-worker/css-modules.ts"],"names":[],"mappings":";;;AAAA,+BAA2C;AAE3C,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAEtB,KAAK,UAAU,qBAAqB,CAAC,KAI3C;IACC,MAAM,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,cAAc,CAAkC,CAAC;IAE/E,wCAAwC;IACxC,wDAAwD;IAExD,MAAM,UAAU,GAAG,SAAS,CAAC;QAC3B,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;QAC5B,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC,SAAS;QAClC,UAAU,EAAE;YACV,2CAA2C;YAC3C,mDAAmD;YACnD,YAAY,EAAE,KAAK;SACpB;QACD,oBAAoB;QACpB,WAAW,EAAE,KAAK,CAAC,OAAO,CAAC,WAAW;QACtC,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM;KAC7B,CAAC,CAAC;IACH,MAAM,YAAY,GAAG,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;IAEhD,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,SAAS,EAAE,GAAG,6CAA6C,CACzF,UAAU,CAAC,OAAQ,CACpB,CAAC;IAEF,IAAI,YAAY,GAAG,gCAAgC,IAAI,CAAC,SAAS,CAC/D,MAAM,CACP,qBAAqB,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC;IAEvF,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE;QACrB,MAAM,UAAU,GAAG,IAAA,wBAAkB,EAAC;YACpC,GAAG,KAAK;YACR,GAAG,EAAE,YAAY;SAClB,CAAC,CAAC;QAEH,YAAY,IAAI,IAAI,GAAG,UAAU,CAAC;KACnC;IAED,OAAO;QACL,MAAM,EAAE,YAAY;QACpB,GAAG,EAAE,UAAU,CAAC,IAAI;QACpB,GAAG,EAAE,UAAU,CAAC,GAAG;KACpB,CAAC;AACJ,CAAC;AA/CD,sDA+CC;AAED,SAAgB,6CAA6C,CAC3D,KAA8C;IAE9C,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,MAAM,cAAc,GAAwB,EAAE,CAAC;IAC/C,MAAM,SAAS,GAA2B,EAAE,CAAC;IAC7C,uFAAuF;IACvF,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE;QACzC,qBAAqB;QACrB,IAAI,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC;QAE3B,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE;YACzB,SAAS,IAAI,GAAG,GAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;SACxE;QAED,2CAA2C;QAC3C,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE;YACxB,SAAS,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;SAC5B;QAED,MAAM,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;QACxB,cAAc,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,gBAAgB,CAAC,EAAE,SAAS,EAAE,CAAC;QACrE,OAAO;YACL,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,gBAAgB,CAAC,EAAE,SAAS,EAAE;SACtD,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,SAAS,EAAE,CAAC;AAC/C,CAAC;AA5BD,sGA4BC;AAED,SAAgB,cAAc,CAAC,QAAgB;IAC7C,OAAO,CAAC,CAAC,uDAAuD,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAClF,CAAC;AAFD,wCAEC"}

View File

@@ -0,0 +1,7 @@
export declare function pathToHtmlSafeName(path: string): string;
export declare function getHotReplaceTemplate(id: string): string;
export declare function wrapDevelopmentCSS(props: {
src: string;
filename: string;
}): string;
export declare function escapeBackticksAndOctals(str: string): string;

View File

@@ -0,0 +1,50 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.escapeBackticksAndOctals = exports.wrapDevelopmentCSS = exports.getHotReplaceTemplate = exports.pathToHtmlSafeName = void 0;
function pathToHtmlSafeName(path) {
return path.replace(/[^a-zA-Z0-9_]/g, '_');
}
exports.pathToHtmlSafeName = pathToHtmlSafeName;
function getHotReplaceTemplate(id) {
// In dev mode, we need to replace the style tag instead of appending it
// use the path as the expo-css-hmr attribute to find the style tag
// to replace.
const attr = JSON.stringify(pathToHtmlSafeName(id));
return `style.setAttribute('data-expo-css-hmr', ${attr});
const previousStyle = document.querySelector('[data-expo-css-hmr=${attr}]');
if (previousStyle) {
previousStyle.parentNode.removeChild(previousStyle);
}`;
}
exports.getHotReplaceTemplate = getHotReplaceTemplate;
function wrapDevelopmentCSS(props) {
const withBackTicksEscaped = escapeBackticksAndOctals(props.src);
return `(() => {
if (typeof window === 'undefined') {
return
}
const head = document.head || document.getElementsByTagName('head')[0];
const style = document.createElement('style');
${getHotReplaceTemplate(props.filename)}
style.setAttribute('data-expo-loader', 'css');
head.appendChild(style);
const css = \`${withBackTicksEscaped}\`;
if (style.styleSheet){
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
})();`;
}
exports.wrapDevelopmentCSS = wrapDevelopmentCSS;
function escapeBackticksAndOctals(str) {
if (typeof str !== 'string') {
return '';
}
return str
.replace(/\\/g, '\\\\')
.replace(/`/g, '\\`')
.replace(/[\0-\7]/g, (match) => `\\0${match.charCodeAt(0).toString(8)}`);
}
exports.escapeBackticksAndOctals = escapeBackticksAndOctals;
//# sourceMappingURL=css.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"css.js","sourceRoot":"","sources":["../../src/transform-worker/css.ts"],"names":[],"mappings":";;;AAAA,SAAgB,kBAAkB,CAAC,IAAY;IAC7C,OAAO,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,GAAG,CAAC,CAAC;AAC7C,CAAC;AAFD,gDAEC;AAED,SAAgB,qBAAqB,CAAC,EAAU;IAC9C,wEAAwE;IACxE,mEAAmE;IACnE,cAAc;IACd,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC,CAAC;IACpD,OAAO,2CAA2C,IAAI;qEACa,IAAI;;;IAGrE,CAAC;AACL,CAAC;AAVD,sDAUC;AAED,SAAgB,kBAAkB,CAAC,KAAwC;IACzE,MAAM,oBAAoB,GAAG,wBAAwB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACjE,OAAO;;;;;;IAML,qBAAqB,CAAC,KAAK,CAAC,QAAQ,CAAC;;;kBAGvB,oBAAoB;;;;;;MAMhC,CAAC;AACP,CAAC;AAlBD,gDAkBC;AAED,SAAgB,wBAAwB,CAAC,GAAW;IAClD,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE;QAC3B,OAAO,EAAE,CAAC;KACX;IAED,OAAO,GAAG;SACP,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC;SACpB,OAAO,CAAC,UAAU,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAC7E,CAAC;AATD,4DASC"}

View File

@@ -0,0 +1,23 @@
/**
* Copyright 2023-present 650 Industries (Expo). All rights reserved.
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import { AssetData, Module } from 'metro';
import { ReadOnlyDependencies } from '../serializer/getCssDeps';
type Options = {
processModuleFilter: (modules: Module) => boolean;
assetPlugins: readonly string[];
platform?: string | null;
projectRoot: string;
publicPath: string;
};
export declare function getUniversalAssetData(assetPath: string, localPath: string, assetDataPlugins: readonly string[], platform: string | null | undefined, publicPath: string): Promise<HashedAssetData>;
export type HashedAssetData = AssetData & {
fileHashes: string[];
_name?: string;
};
export default function getAssets(dependencies: ReadOnlyDependencies, options: Options): Promise<HashedAssetData[]>;
export {};

View File

@@ -0,0 +1,49 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getUniversalAssetData = void 0;
const Assets_1 = require("metro/src/Assets");
const js_1 = require("metro/src/DeltaBundler/Serializers/helpers/js");
const node_assert_1 = __importDefault(require("node:assert"));
const node_crypto_1 = __importDefault(require("node:crypto"));
const node_path_1 = __importDefault(require("node:path"));
function md5Hash(data) {
if (data.length === 1)
return data[0];
const hash = node_crypto_1.default.createHash('md5');
hash.update(data.join(''));
return hash.digest('hex');
}
function assertHashedAssetData(data) {
(0, node_assert_1.default)('fileHashes' in data, 'Assets must have hashed files. Ensure the expo-asset plugin is installed.');
}
async function getUniversalAssetData(assetPath, localPath, assetDataPlugins, platform, publicPath) {
const data = await (0, Assets_1.getAssetData)(assetPath, localPath, assetDataPlugins, platform, publicPath);
assertHashedAssetData(data);
// NOTE(EvanBacon): This is where we modify the asset to include a hash in the name for web cache invalidation.
if (platform === 'web' && publicPath.includes('?export_path=')) {
// `local-image.[contenthash]`. Using `.` but this won't work if we ever apply to Android because Android res files cannot contain `.`.
// TODO: Prevent one multi-res image from updating the hash in all images.
// @ts-expect-error: name is typed as readonly.
data.name = `${data.name}.${md5Hash(data.fileHashes)}`;
}
return data;
}
exports.getUniversalAssetData = getUniversalAssetData;
async function getAssets(dependencies, options) {
const promises = [];
const { processModuleFilter } = options;
for (const module of dependencies.values()) {
if ((0, js_1.isJsModule)(module) &&
processModuleFilter(module) &&
(0, js_1.getJsOutput)(module).type === 'js/module/asset' &&
node_path_1.default.relative(options.projectRoot, module.path) !== 'package.json') {
promises.push(getUniversalAssetData(module.path, node_path_1.default.relative(options.projectRoot, module.path), options.assetPlugins, options.platform, options.publicPath));
}
}
return await Promise.all(promises);
}
exports.default = getAssets;
//# sourceMappingURL=getAssets.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"getAssets.js","sourceRoot":"","sources":["../../src/transform-worker/getAssets.ts"],"names":[],"mappings":";;;;;;AAQA,6CAAgD;AAChD,sEAAwF;AACxF,8DAAiC;AACjC,8DAAiC;AACjC,0DAA6B;AAY7B,SAAS,OAAO,CAAC,IAAc;IAC7B,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC;IACtC,MAAM,IAAI,GAAG,qBAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IACtC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IAC3B,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC5B,CAAC;AAED,SAAS,qBAAqB,CAAC,IAAe;IAC5C,IAAA,qBAAM,EACJ,YAAY,IAAI,IAAI,EACpB,2EAA2E,CAC5E,CAAC;AACJ,CAAC;AAEM,KAAK,UAAU,qBAAqB,CACzC,SAAiB,EACjB,SAAiB,EACjB,gBAAmC,EACnC,QAAmC,EACnC,UAAkB;IAElB,MAAM,IAAI,GAAG,MAAM,IAAA,qBAAY,EAAC,SAAS,EAAE,SAAS,EAAE,gBAAgB,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;IAC9F,qBAAqB,CAAC,IAAI,CAAC,CAAC;IAE5B,+GAA+G;IAC/G,IAAI,QAAQ,KAAK,KAAK,IAAI,UAAU,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE;QAC9D,uIAAuI;QACvI,0EAA0E;QAC1E,+CAA+C;QAC/C,IAAI,CAAC,IAAI,GAAG,GAAG,IAAI,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;KACxD;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAnBD,sDAmBC;AAIc,KAAK,UAAU,SAAS,CACrC,YAAkC,EAClC,OAAgB;IAEhB,MAAM,QAAQ,GAA+B,EAAE,CAAC;IAChD,MAAM,EAAE,mBAAmB,EAAE,GAAG,OAAO,CAAC;IAExC,KAAK,MAAM,MAAM,IAAI,YAAY,CAAC,MAAM,EAAE,EAAE;QAC1C,IACE,IAAA,eAAU,EAAC,MAAM,CAAC;YAClB,mBAAmB,CAAC,MAAM,CAAC;YAC3B,IAAA,gBAAW,EAAC,MAAM,CAAC,CAAC,IAAI,KAAK,iBAAiB;YAC9C,mBAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,cAAc,EAClE;YACA,QAAQ,CAAC,IAAI,CACX,qBAAqB,CACnB,MAAM,CAAC,IAAI,EACX,mBAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC,EAC/C,OAAO,CAAC,YAAY,EACpB,OAAO,CAAC,QAAQ,EAChB,OAAO,CAAC,UAAU,CACnB,CACF,CAAC;SACH;KACF;IAED,OAAO,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AACrC,CAAC;AA3BD,4BA2BC"}

View File

@@ -0,0 +1,11 @@
/// <reference types="node" />
/// <reference types="metro" />
import type { TransformResultDependency } from 'metro/src/DeltaBundler';
import { JsOutput, JsTransformerConfig, JsTransformOptions } from 'metro-transform-worker';
export { JsTransformOptions };
interface TransformResponse {
readonly dependencies: readonly TransformResultDependency[];
readonly output: readonly JsOutput[];
}
export declare function transform(config: JsTransformerConfig, projectRoot: string, filename: string, data: Buffer, options: JsTransformOptions): Promise<TransformResponse>;
export declare function getCacheKey(config: JsTransformerConfig): string;

View File

@@ -0,0 +1,466 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getCacheKey = exports.transform = void 0;
/**
* Copyright 2023-present 650 Industries (Expo). All rights reserved.
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* Fork of the Metro transformer worker, but with additional transforms moved to `babel-preset-expo` and modifications made for web support.
* https://github.com/facebook/metro/blob/412771475c540b6f85d75d9dcd5a39a6e0753582/packages/metro-transform-worker/src/index.js#L1
*/
const core_1 = require("@babel/core");
const generator_1 = __importDefault(require("@babel/generator"));
const babylon = __importStar(require("@babel/parser"));
const types = __importStar(require("@babel/types"));
const JsFileWrapping_1 = __importDefault(require("metro/src/ModuleGraph/worker/JsFileWrapping"));
const collectDependencies_1 = __importStar(require("metro/src/ModuleGraph/worker/collectDependencies"));
const generateImportNames_1 = __importDefault(require("metro/src/ModuleGraph/worker/generateImportNames"));
const countLines_1 = __importDefault(require("metro/src/lib/countLines"));
const metro_cache_1 = require("metro-cache");
const metro_cache_key_1 = __importDefault(require("metro-cache-key"));
const metro_source_map_1 = require("metro-source-map");
const metro_transform_plugins_1 = __importDefault(require("metro-transform-plugins"));
const getMinifier_1 = __importDefault(require("metro-transform-worker/src/utils/getMinifier"));
const node_assert_1 = __importDefault(require("node:assert"));
const assetTransformer = __importStar(require("./asset-transformer"));
const resolveOptions_1 = require("./resolveOptions");
// asserts non-null
function nullthrows(x, message) {
(0, node_assert_1.default)(x != null, message);
return x;
}
function getDynamicDepsBehavior(inPackages, filename) {
switch (inPackages) {
case 'reject':
return 'reject';
case 'throwAtRuntime':
return /(?:^|[/\\])node_modules[/\\]/.test(filename) ? inPackages : 'reject';
default:
throw new Error(`invalid value for dynamic deps behavior: \`${inPackages}\``);
}
}
const minifyCode = async (config, projectRoot, filename, code, source, map, reserved = []) => {
const sourceMap = (0, metro_source_map_1.fromRawMappings)([
{
code,
source,
map,
// functionMap is overridden by the serializer
functionMap: null,
path: filename,
// isIgnored is overriden by the serializer
isIgnored: false,
},
]).toMap(undefined, {});
const minify = (0, getMinifier_1.default)(config.minifierPath);
try {
const minified = await minify({
code,
map: sourceMap,
filename,
reserved,
config: config.minifierConfig,
});
return {
code: minified.code,
map: minified.map ? (0, metro_source_map_1.toBabelSegments)(minified.map).map(metro_source_map_1.toSegmentTuple) : [],
};
}
catch (error) {
if (error.constructor.name === 'JS_Parse_Error') {
throw new Error(`${error.message} in file ${filename} at ${error.line}:${error.col}`);
}
throw error;
}
};
const disabledDependencyTransformer = {
transformSyncRequire: () => { },
transformImportCall: () => { },
transformPrefetch: () => { },
transformIllegalDynamicRequire: () => { },
};
class InvalidRequireCallError extends Error {
innerError;
filename;
constructor(innerError, filename) {
super(`${filename}:${innerError.message}`);
this.innerError = innerError;
this.filename = filename;
}
}
async function transformJS(file, { config, options, projectRoot }) {
// Transformers can output null ASTs (if they ignore the file). In that case
// we need to parse the module source code to get their AST.
let ast = file.ast ?? babylon.parse(file.code, { sourceType: 'unambiguous' });
// NOTE(EvanBacon): This can be really expensive on larger files. We should replace it with a cheaper alternative that just iterates and matches.
const { importDefault, importAll } = (0, generateImportNames_1.default)(ast);
// Add "use strict" if the file was parsed as a module, and the directive did
// not exist yet.
const { directives } = ast.program;
if (ast.program.sourceType === 'module' &&
directives != null &&
directives.findIndex((d) => d.value.value === 'use strict') === -1) {
directives.push(types.directive(types.directiveLiteral('use strict')));
}
// Perform the import-export transform (in case it's still needed), then
// fold requires and perform constant folding (if in dev).
const plugins = [];
const babelPluginOpts = {
...options,
inlineableCalls: [importDefault, importAll],
importDefault,
importAll,
};
// NOTE(EvanBacon): This is effectively a replacement for the `@babel/plugin-transform-modules-commonjs`
// plugin that's running in `@@react-native/babel-preset`, but with shared names for inlining requires.
if (options.experimentalImportSupport === true) {
plugins.push([metro_transform_plugins_1.default.importExportPlugin, babelPluginOpts]);
}
// NOTE(EvanBacon): This can basically never be safely enabled because it doesn't respect side-effects and
// has no ability to respect side-effects because the transformer hasn't collected all dependencies yet.
if (options.inlineRequires) {
plugins.push([
metro_transform_plugins_1.default.inlineRequiresPlugin,
{
...babelPluginOpts,
ignoredRequires: options.nonInlinedRequires,
},
]);
}
// NOTE(EvanBacon): We apply this conditionally in `babel-preset-expo` with other AST transforms.
// plugins.push([metroTransformPlugins.inlinePlugin, babelPluginOpts]);
// TODO: This MUST be run even though no plugins are added, otherwise the babel runtime generators are broken.
if (plugins.length) {
ast = nullthrows(
// @ts-expect-error
(0, core_1.transformFromAstSync)(ast, '', {
ast: true,
babelrc: false,
code: false,
configFile: false,
comments: true,
filename: file.filename,
plugins,
sourceMaps: false,
// NOTE(kitten): This was done to wipe the paths/scope caches, which the `constantFoldingPlugin` needs to work,
// but has been replaced with `programPath.scope.crawl()`.
// Old Note from Metro:
// > Not-Cloning the input AST here should be safe because other code paths above this call
// > are mutating the AST as well and no code is depending on the original AST.
// > However, switching the flag to false caused issues with ES Modules if `experimentalImportSupport` isn't used https://github.com/facebook/metro/issues/641
// > either because one of the plugins is doing something funky or Babel messes up some caches.
// > Make sure to test the above mentioned case before flipping the flag back to false.
cloneInputAst: false,
}).ast);
}
if (!options.dev) {
// NOTE(kitten): Any Babel helpers that have been added (`path.hub.addHelper(...)`) will usually not have any
// references, and hence the `constantFoldingPlugin` below will remove them.
// To fix the references we add an explicit `programPath.scope.crawl()`. Alternatively, we could also wipe the
// Babel traversal cache (`traverse.cache.clear()`)
const clearProgramScopePlugin = {
visitor: {
Program: {
enter(path) {
path.scope.crawl();
},
},
},
};
// Run the constant folding plugin in its own pass, avoiding race conditions
// with other plugins that have exit() visitors on Program (e.g. the ESM
// transform).
ast = nullthrows(
// @ts-expect-error
(0, core_1.transformFromAstSync)(ast, '', {
ast: true,
babelrc: false,
code: false,
configFile: false,
comments: true,
filename: file.filename,
plugins: [
clearProgramScopePlugin,
[metro_transform_plugins_1.default.constantFoldingPlugin, babelPluginOpts],
],
sourceMaps: false,
// NOTE(kitten): In Metro, this is also false, but only works because the prior run of `transformFromAstSync` was always
// running with `cloneInputAst: true`.
// This isn't needed anymore since `clearProgramScopePlugin` re-crawls the ASTs scope instead.
cloneInputAst: false,
}).ast);
}
let dependencyMapName = '';
let dependencies;
let wrappedAst;
// If the module to transform is a script (meaning that is not part of the
// dependency graph and it code will just be prepended to the bundle modules),
// we need to wrap it differently than a commonJS module (also, scripts do
// not have dependencies).
if (file.type === 'js/script') {
dependencies = [];
wrappedAst = JsFileWrapping_1.default.wrapPolyfill(ast);
}
else {
try {
const opts = {
asyncRequireModulePath: config.asyncRequireModulePath,
dependencyTransformer: config.unstable_disableModuleWrapping === true
? disabledDependencyTransformer
: undefined,
dynamicRequires: getDynamicDepsBehavior(config.dynamicDepsInPackages, file.filename),
inlineableCalls: [importDefault, importAll],
keepRequireNames: options.dev,
allowOptionalDependencies: config.allowOptionalDependencies,
dependencyMapName: config.unstable_dependencyMapReservedName,
unstable_allowRequireContext: config.unstable_allowRequireContext,
};
({ ast, dependencies, dependencyMapName } = (0, collectDependencies_1.default)(ast, opts));
}
catch (error) {
if (error instanceof collectDependencies_1.InvalidRequireCallError) {
throw new InvalidRequireCallError(error, file.filename);
}
throw error;
}
if (config.unstable_disableModuleWrapping === true) {
wrappedAst = ast;
}
else {
// TODO: Replace this with a cheaper transform that doesn't require AST.
({ ast: wrappedAst } = JsFileWrapping_1.default.wrapModule(ast, importDefault, importAll, dependencyMapName, config.globalPrefix,
// TODO: This config is optional to allow its introduction in a minor
// release. It should be made non-optional in ConfigT or removed in
// future.
// @ts-expect-error: Not on types yet (Metro 0.80.9).
config.unstable_renameRequire === false));
}
}
const reserved = [];
if (config.unstable_dependencyMapReservedName != null) {
reserved.push(config.unstable_dependencyMapReservedName);
}
const minify = (0, resolveOptions_1.shouldMinify)(options);
if (minify &&
file.inputFileSize <= config.optimizationSizeLimit &&
!config.unstable_disableNormalizePseudoGlobals) {
// NOTE(EvanBacon): Simply pushing this function will mutate the AST, so it must run before the `generate` step!!
reserved.push(...metro_transform_plugins_1.default.normalizePseudoGlobals(wrappedAst, {
reservedNames: reserved,
}));
}
const result = (0, generator_1.default)(wrappedAst, {
comments: true,
compact: config.unstable_compactOutput,
filename: file.filename,
retainLines: false,
sourceFileName: file.filename,
sourceMaps: true,
}, file.code);
// @ts-expect-error: incorrectly typed upstream
let map = result.rawMappings ? result.rawMappings.map(metro_source_map_1.toSegmentTuple) : [];
let code = result.code;
if (minify) {
({ map, code } = await minifyCode(config, projectRoot, file.filename, result.code, file.code, map, reserved));
}
const output = [
{
data: {
code,
lineCount: (0, countLines_1.default)(code),
map,
functionMap: file.functionMap,
},
type: file.type,
},
];
return {
dependencies,
output,
};
}
/** Transforms an asset file. */
async function transformAsset(file, context) {
const { assetRegistryPath, assetPlugins } = context.config;
// TODO: Add web asset hashing in production.
const result = await assetTransformer.transform(getBabelTransformArgs(file, context), assetRegistryPath, assetPlugins);
const jsFile = {
...file,
type: 'js/module/asset',
ast: result.ast,
functionMap: null,
};
return transformJS(jsFile, context);
}
/**
* Transforms a JavaScript file with Babel before processing the file with
* the generic JavaScript transformation.
*/
async function transformJSWithBabel(file, context) {
const { babelTransformerPath } = context.config;
const transformer = require(babelTransformerPath);
// HACK: React Compiler injects import statements and exits the Babel process which leaves the code in
// a malformed state. For now, we'll enable the experimental import support which compiles import statements
// outside of the standard Babel process.
if (!context.options.experimentalImportSupport) {
const reactCompilerFlag = context.options.customTransformOptions?.reactCompiler;
if (reactCompilerFlag === true || reactCompilerFlag === 'true') {
// @ts-expect-error: readonly.
context.options.experimentalImportSupport = true;
}
}
const transformResult = await transformer.transform(
// functionMapBabelPlugin populates metadata.metro.functionMap
getBabelTransformArgs(file, context, [metro_source_map_1.functionMapBabelPlugin]));
const jsFile = {
...file,
ast: transformResult.ast,
functionMap: transformResult.metadata?.metro?.functionMap ??
// Fallback to deprecated explicitly-generated `functionMap`
transformResult.functionMap ??
null,
};
return await transformJS(jsFile, context);
}
async function transformJSON(file, { options, config, projectRoot }) {
let code = config.unstable_disableModuleWrapping === true
? JsFileWrapping_1.default.jsonToCommonJS(file.code)
: JsFileWrapping_1.default.wrapJson(file.code, config.globalPrefix);
let map = [];
const minify = (0, resolveOptions_1.shouldMinify)(options);
if (minify) {
({ map, code } = await minifyCode(config, projectRoot, file.filename, code, file.code, map));
}
let jsType;
if (file.type === 'asset') {
jsType = 'js/module/asset';
}
else if (file.type === 'script') {
jsType = 'js/script';
}
else {
jsType = 'js/module';
}
const output = [
{
data: { code, lineCount: (0, countLines_1.default)(code), map, functionMap: null },
type: jsType,
},
];
return {
dependencies: [],
output,
};
}
function getBabelTransformArgs(file, { options, config, projectRoot }, plugins = []) {
const { inlineRequires: _, ...babelTransformerOptions } = options;
return {
filename: file.filename,
options: {
...babelTransformerOptions,
enableBabelRCLookup: config.enableBabelRCLookup,
enableBabelRuntime: config.enableBabelRuntime,
hermesParser: config.hermesParser,
projectRoot,
publicPath: config.publicPath,
globalPrefix: config.globalPrefix,
platform: babelTransformerOptions.platform ?? null,
},
plugins,
src: file.code,
};
}
async function transform(config, projectRoot, filename, data, options) {
const context = {
config,
projectRoot,
options,
};
const sourceCode = data.toString('utf8');
const { unstable_dependencyMapReservedName } = config;
if (unstable_dependencyMapReservedName != null) {
const position = sourceCode.indexOf(unstable_dependencyMapReservedName);
if (position > -1) {
throw new SyntaxError('Source code contains the reserved string `' +
unstable_dependencyMapReservedName +
'` at character offset ' +
position);
}
}
if (filename.endsWith('.json')) {
const jsonFile = {
filename,
inputFileSize: data.length,
code: sourceCode,
type: options.type,
};
return transformJSON(jsonFile, context);
}
if (options.type === 'asset') {
const file = {
filename,
inputFileSize: data.length,
code: sourceCode,
type: options.type,
};
return transformAsset(file, context);
}
const file = {
filename,
inputFileSize: data.length,
code: sourceCode,
type: options.type === 'script' ? 'js/script' : 'js/module',
functionMap: null,
};
return transformJSWithBabel(file, context);
}
exports.transform = transform;
function getCacheKey(config) {
const { babelTransformerPath, minifierPath, ...remainingConfig } = config;
const filesKey = (0, metro_cache_key_1.default)([
require.resolve(babelTransformerPath),
require.resolve(minifierPath),
require.resolve('metro-transform-worker/src/utils/getMinifier'),
require.resolve('./asset-transformer'),
require.resolve('metro/src/ModuleGraph/worker/generateImportNames'),
require.resolve('metro/src/ModuleGraph/worker/JsFileWrapping'),
...metro_transform_plugins_1.default.getTransformPluginCacheKeyFiles(),
]);
const babelTransformer = require(babelTransformerPath);
return [
filesKey,
(0, metro_cache_1.stableHash)(remainingConfig).toString('hex'),
babelTransformer.getCacheKey ? babelTransformer.getCacheKey() : '',
].join('$');
}
exports.getCacheKey = getCacheKey;
//# sourceMappingURL=metro-transform-worker.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,20 @@
type PostCSSInputConfig = {
plugins?: any[];
from?: string;
to?: string;
syntax?: string;
map?: boolean;
parser?: string;
stringifier?: string;
};
export declare function transformPostCssModule(projectRoot: string, { src, filename }: {
src: string;
filename: string;
}): Promise<{
src: string;
hasPostcss: boolean;
}>;
export declare function pluginFactory(): (plugins?: any) => Map<string, any>;
export declare function resolvePostcssConfig(projectRoot: string): PostCSSInputConfig | null;
export declare function getPostcssConfigHash(projectRoot: string): string | null;
export {};

View File

@@ -0,0 +1,207 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getPostcssConfigHash = exports.resolvePostcssConfig = exports.pluginFactory = exports.transformPostCssModule = void 0;
/**
* Copyright © 2023 650 Industries.
* Copyright JS Foundation and other contributors
*
* https://github.com/webpack-contrib/postcss-loader/
*/
const json_file_1 = __importDefault(require("@expo/json-file"));
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const resolve_from_1 = __importDefault(require("resolve-from"));
const require_1 = require("./utils/require");
const CONFIG_FILE_NAME = 'postcss.config';
const debug = require('debug')('expo:metro:transformer:postcss');
async function transformPostCssModule(projectRoot, { src, filename }) {
const inputConfig = resolvePostcssConfig(projectRoot);
if (!inputConfig) {
return { src, hasPostcss: false };
}
return {
src: await processWithPostcssInputConfigAsync(projectRoot, {
inputConfig,
src,
filename,
}),
hasPostcss: true,
};
}
exports.transformPostCssModule = transformPostCssModule;
async function processWithPostcssInputConfigAsync(projectRoot, { src, filename, inputConfig }) {
const { plugins, processOptions } = await parsePostcssConfigAsync(projectRoot, {
config: inputConfig,
resourcePath: filename,
});
debug('options:', processOptions);
debug('plugins:', plugins);
// TODO: Surely this can be cached...
const postcss = require('postcss');
const processor = postcss.default(plugins);
const { content } = await processor.process(src, processOptions);
return content;
}
async function parsePostcssConfigAsync(projectRoot, { resourcePath: file, config: { plugins: inputPlugins, map, parser, stringifier, syntax, ...config } = {}, }) {
const factory = pluginFactory();
factory(inputPlugins);
// delete config.plugins;
const plugins = [...factory()].map((item) => {
const [plugin, options] = item;
if (typeof plugin === 'string') {
return loadPlugin(projectRoot, plugin, options, file);
}
return plugin;
});
if (config.from) {
config.from = path_1.default.resolve(projectRoot, config.from);
}
if (config.to) {
config.to = path_1.default.resolve(projectRoot, config.to);
}
const processOptions = {
from: file,
to: file,
map: false,
};
if (typeof parser === 'string') {
try {
processOptions.parser = await (0, require_1.tryRequireThenImport)(resolve_from_1.default.silent(projectRoot, parser) ?? parser);
}
catch (error) {
if (error instanceof Error) {
throw new Error(`Loading PostCSS "${parser}" parser failed: ${error.message}\n\n(@${file})`);
}
throw error;
}
}
if (typeof stringifier === 'string') {
try {
processOptions.stringifier = await (0, require_1.tryRequireThenImport)(resolve_from_1.default.silent(projectRoot, stringifier) ?? stringifier);
}
catch (error) {
if (error instanceof Error) {
throw new Error(`Loading PostCSS "${stringifier}" stringifier failed: ${error.message}\n\n(@${file})`);
}
throw error;
}
}
if (typeof syntax === 'string') {
try {
processOptions.syntax = await (0, require_1.tryRequireThenImport)(resolve_from_1.default.silent(projectRoot, syntax) ?? syntax);
}
catch (error) {
throw new Error(`Loading PostCSS "${syntax}" syntax failed: ${error.message}\n\n(@${file})`);
}
}
if (map === true) {
// https://github.com/postcss/postcss/blob/master/docs/source-maps.md
processOptions.map = { inline: true };
}
return { plugins, processOptions };
}
function loadPlugin(projectRoot, plugin, options, file) {
try {
debug('load plugin:', plugin);
// e.g. `tailwindcss`
let loadedPlugin = require((0, resolve_from_1.default)(projectRoot, plugin));
if (loadedPlugin.default) {
loadedPlugin = loadedPlugin.default;
}
if (!options || !Object.keys(options).length) {
return loadedPlugin;
}
return loadedPlugin(options);
}
catch (error) {
if (error instanceof Error) {
throw new Error(`Loading PostCSS "${plugin}" plugin failed: ${error.message}\n\n(@${file})`);
}
throw error;
}
}
function pluginFactory() {
const listOfPlugins = new Map();
return (plugins) => {
if (typeof plugins === 'undefined') {
return listOfPlugins;
}
if (Array.isArray(plugins)) {
for (const plugin of plugins) {
if (Array.isArray(plugin)) {
const [name, options] = plugin;
if (typeof name !== 'string') {
throw new Error(`PostCSS plugin must be a string, but "${name}" was found. Please check your configuration.`);
}
listOfPlugins.set(name, options);
}
else if (plugin && typeof plugin === 'function') {
listOfPlugins.set(plugin, undefined);
}
else if (plugin &&
Object.keys(plugin).length === 1 &&
(typeof plugin[Object.keys(plugin)[0]] === 'object' ||
typeof plugin[Object.keys(plugin)[0]] === 'boolean') &&
plugin[Object.keys(plugin)[0]] !== null) {
const [name] = Object.keys(plugin);
const options = plugin[name];
if (options === false) {
listOfPlugins.delete(name);
}
else {
listOfPlugins.set(name, options);
}
}
else if (plugin) {
listOfPlugins.set(plugin, undefined);
}
}
}
else {
const objectPlugins = Object.entries(plugins);
for (const [name, options] of objectPlugins) {
if (options === false) {
listOfPlugins.delete(name);
}
else {
listOfPlugins.set(name, options);
}
}
}
return listOfPlugins;
};
}
exports.pluginFactory = pluginFactory;
function resolvePostcssConfig(projectRoot) {
// TODO: Maybe support platform-specific postcss config files in the future.
const jsConfigPath = path_1.default.join(projectRoot, CONFIG_FILE_NAME + '.js');
if (fs_1.default.existsSync(jsConfigPath)) {
debug('load file:', jsConfigPath);
return (0, require_1.requireUncachedFile)(jsConfigPath);
}
const jsonConfigPath = path_1.default.join(projectRoot, CONFIG_FILE_NAME + '.json');
if (fs_1.default.existsSync(jsonConfigPath)) {
debug('load file:', jsonConfigPath);
return json_file_1.default.read(jsonConfigPath, { json5: true });
}
return null;
}
exports.resolvePostcssConfig = resolvePostcssConfig;
function getPostcssConfigHash(projectRoot) {
// TODO: Maybe recurse plugins and add versions to the hash in the future.
const { stableHash } = require('metro-cache');
const jsConfigPath = path_1.default.join(projectRoot, CONFIG_FILE_NAME + '.js');
if (fs_1.default.existsSync(jsConfigPath)) {
return stableHash(fs_1.default.readFileSync(jsConfigPath, 'utf8')).toString('hex');
}
const jsonConfigPath = path_1.default.join(projectRoot, CONFIG_FILE_NAME + '.json');
if (fs_1.default.existsSync(jsonConfigPath)) {
return stableHash(fs_1.default.readFileSync(jsonConfigPath, 'utf8')).toString('hex');
}
return null;
}
exports.getPostcssConfigHash = getPostcssConfigHash;
//# sourceMappingURL=postcss.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
import { JsTransformOptions } from 'metro-transform-worker';
export declare function shouldMinify(options: Pick<JsTransformOptions, 'unstable_transformProfile' | 'customTransformOptions' | 'minify'>): boolean;

View File

@@ -0,0 +1,21 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.shouldMinify = void 0;
function isHermesEngine(options) {
// NOTE: This has multiple inputs since we also use the `customTransformOptions.engine` option to indicate the Hermes engine.
return (options.unstable_transformProfile === 'hermes-canary' ||
options.unstable_transformProfile === 'hermes-stable');
}
function isBytecodeEnabled(options) {
return (options.customTransformOptions?.bytecode === true ||
options.customTransformOptions?.bytecode === 'true');
}
function shouldMinify(options) {
// If using Hermes + bytecode, then skip minification because the Hermes compiler will minify the code.
if (isHermesEngine(options) && isBytecodeEnabled(options)) {
return false;
}
return options.minify;
}
exports.shouldMinify = shouldMinify;
//# sourceMappingURL=resolveOptions.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"resolveOptions.js","sourceRoot":"","sources":["../../src/transform-worker/resolveOptions.ts"],"names":[],"mappings":";;;AAEA,SAAS,cAAc,CAAC,OAA8D;IACpF,6HAA6H;IAC7H,OAAO,CACL,OAAO,CAAC,yBAAyB,KAAK,eAAe;QACrD,OAAO,CAAC,yBAAyB,KAAK,eAAe,CACtD,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,OAA2D;IACpF,OAAO,CACL,OAAO,CAAC,sBAAsB,EAAE,QAAQ,KAAK,IAAI;QACjD,OAAO,CAAC,sBAAsB,EAAE,QAAQ,KAAK,MAAM,CACpD,CAAC;AACJ,CAAC;AAED,SAAgB,YAAY,CAC1B,OAGC;IAED,uGAAuG;IACvG,IAAI,cAAc,CAAC,OAAO,CAAC,IAAI,iBAAiB,CAAC,OAAO,CAAC,EAAE;QACzD,OAAO,KAAK,CAAC;KACd;IAED,OAAO,OAAO,CAAC,MAAM,CAAC;AACxB,CAAC;AAZD,oCAYC"}

View File

@@ -0,0 +1,9 @@
/// <reference types="source-map-js" />
export declare function matchSass(filename: string): import('sass').Syntax | null;
export declare function compileSass(projectRoot: string, { filename, src }: {
filename: string;
src: string;
}, options?: Partial<import('sass').StringOptions<'sync'>>): {
src: string;
map: import("source-map-js").RawSourceMap | undefined;
};

View File

@@ -0,0 +1,41 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.compileSass = exports.matchSass = void 0;
const resolve_from_1 = __importDefault(require("resolve-from"));
let sassInstance = null;
function getSassInstance(projectRoot) {
if (!sassInstance) {
const sassPath = resolve_from_1.default.silent(projectRoot, 'sass');
if (!sassPath) {
throw new Error(`Cannot parse Sass files without the module 'sass' installed. Run 'yarn add sass' and try again.`);
}
sassInstance = require(sassPath);
}
return sassInstance;
}
function matchSass(filename) {
if (filename.endsWith('.sass')) {
return 'indented';
}
else if (filename.endsWith('.scss')) {
return 'scss';
}
return null;
}
exports.matchSass = matchSass;
function compileSass(projectRoot, { filename, src },
// TODO: Expose to users somehow...
options) {
const sass = getSassInstance(projectRoot);
const result = sass.compileString(src, options);
return {
src: result.css,
// TODO: Should we use this? Leaning towards no since the CSS will be parsed again by the CSS loader.
map: result.sourceMap,
};
}
exports.compileSass = compileSass;
//# sourceMappingURL=sass.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"sass.js","sourceRoot":"","sources":["../../src/transform-worker/sass.ts"],"names":[],"mappings":";;;;;;AAAA,gEAAuC;AAEvC,IAAI,YAAY,GAAiC,IAAI,CAAC;AAEtD,SAAS,eAAe,CAAC,WAAmB;IAC1C,IAAI,CAAC,YAAY,EAAE;QACjB,MAAM,QAAQ,GAAG,sBAAW,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QAEzD,IAAI,CAAC,QAAQ,EAAE;YACb,MAAM,IAAI,KAAK,CACb,iGAAiG,CAClG,CAAC;SACH;QAED,YAAY,GAAG,OAAO,CAAC,QAAQ,CAA0B,CAAC;KAC3D;IAED,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,SAAgB,SAAS,CAAC,QAAgB;IACxC,IAAI,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE;QAC9B,OAAO,UAAU,CAAC;KACnB;SAAM,IAAI,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE;QACrC,OAAO,MAAM,CAAC;KACf;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAPD,8BAOC;AAED,SAAgB,WAAW,CACzB,WAAmB,EACnB,EAAE,QAAQ,EAAE,GAAG,EAAqC;AACpD,mCAAmC;AACnC,OAAuD;IAEvD,MAAM,IAAI,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAChD,OAAO;QACL,GAAG,EAAE,MAAM,CAAC,GAAG;QACf,qGAAqG;QACrG,GAAG,EAAE,MAAM,CAAC,SAAS;KACtB,CAAC;AACJ,CAAC;AAbD,kCAaC"}

View File

@@ -0,0 +1,3 @@
/// <reference types="node" />
import type { JsTransformerConfig, JsTransformOptions, TransformResponse } from 'metro-transform-worker';
export declare function transform(config: JsTransformerConfig, projectRoot: string, filename: string, data: Buffer, options: JsTransformOptions): Promise<TransformResponse>;

View File

@@ -0,0 +1,184 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.transform = void 0;
/**
* Copyright 2023-present 650 Industries (Expo). All rights reserved.
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const countLines_1 = __importDefault(require("metro/src/lib/countLines"));
const css_1 = require("./css");
const css_modules_1 = require("./css-modules");
const worker = __importStar(require("./metro-transform-worker"));
const postcss_1 = require("./postcss");
const sass_1 = require("./sass");
async function transform(config, projectRoot, filename, data, options) {
const isCss = options.type !== 'asset' && /\.(s?css|sass)$/.test(filename);
// If the file is not CSS, then use the default behavior.
if (!isCss) {
const environment = options.customTransformOptions?.environment;
const isClientEnvironment = environment !== 'node' && environment !== 'react-server';
if (isClientEnvironment &&
// TODO: Ensure this works with windows.
(filename.match(new RegExp(`^app/\\+html(\\.${options.platform})?\\.([tj]sx?|[cm]js)?$`)) ||
// Strip +api files.
filename.match(/\+api(\.(native|ios|android|web))?\.[tj]sx?$/))) {
// Remove the server-only +html file and API Routes from the bundle when bundling for a client environment.
return worker.transform(config, projectRoot, filename, !options.minify
? Buffer.from(
// Use a string so this notice is visible in the bundle if the user is
// looking for it.
'"> The server-only file was removed from the client JS bundle by Expo CLI."')
: Buffer.from(''), options);
}
if (isClientEnvironment &&
!filename.match(/\/node_modules\//) &&
filename.match(/\+api(\.(native|ios|android|web))?\.[tj]sx?$/)) {
// Clear the contents of +api files when bundling for the client.
// This ensures that the client doesn't accidentally use the server-only +api files.
return worker.transform(config, projectRoot, filename, Buffer.from(''), options);
}
return worker.transform(config, projectRoot, filename, data, options);
}
// If the platform is not web, then return an empty module.
if (options.platform !== 'web') {
const code = (0, css_modules_1.matchCssModule)(filename) ? 'module.exports={ unstable_styles: {} };' : '';
return worker.transform(config, projectRoot, filename,
// TODO: Native CSS Modules
Buffer.from(code), options);
}
let code = data.toString('utf8');
// Apply postcss transforms
const postcssResults = await (0, postcss_1.transformPostCssModule)(projectRoot, {
src: code,
filename,
});
if (postcssResults.hasPostcss) {
code = postcssResults.src;
}
// TODO: When native has CSS support, this will need to move higher up.
const syntax = (0, sass_1.matchSass)(filename);
if (syntax) {
code = (0, sass_1.compileSass)(projectRoot, { filename, src: code }, { syntax }).src;
}
// If the file is a CSS Module, then transform it to a JS module
// in development and a static CSS file in production.
if ((0, css_modules_1.matchCssModule)(filename)) {
const results = await (0, css_modules_1.transformCssModuleWeb)({
filename,
src: code,
options: {
projectRoot,
dev: options.dev,
minify: options.minify,
sourceMap: false,
},
});
const jsModuleResults = await worker.transform(config, projectRoot, filename, Buffer.from(results.output), options);
const cssCode = results.css.toString();
const output = [
{
type: 'js/module',
data: {
...jsModuleResults.output[0]?.data,
// Append additional css metadata for static extraction.
css: {
code: cssCode,
lineCount: (0, countLines_1.default)(cssCode),
map: [],
functionMap: null,
},
},
},
];
return {
dependencies: jsModuleResults.dependencies,
output,
};
}
// Global CSS:
const { transform } = require('lightningcss');
// TODO: Add bundling to resolve imports
// https://lightningcss.dev/bundling.html#bundling-order
const cssResults = transform({
filename,
code: Buffer.from(code),
sourceMap: false,
cssModules: false,
projectRoot,
minify: options.minify,
});
// TODO: Warnings:
// cssResults.warnings.forEach((warning) => {
// });
// Create a mock JS module that exports an empty object,
// this ensures Metro dependency graph is correct.
const jsModuleResults = await worker.transform(config, projectRoot, filename, options.dev ? Buffer.from((0, css_1.wrapDevelopmentCSS)({ src: code, filename })) : Buffer.from(''), options);
const cssCode = cssResults.code.toString();
// In production, we export the CSS as a string and use a special type to prevent
// it from being included in the JS bundle. We'll extract the CSS like an asset later
// and append it to the HTML bundle.
const output = [
{
type: 'js/module',
data: {
...jsModuleResults.output[0].data,
// Append additional css metadata for static extraction.
css: {
code: cssCode,
lineCount: (0, countLines_1.default)(cssCode),
map: [],
functionMap: null,
// Disable caching for CSS files when postcss is enabled and has been run on the file.
// This ensures that things like tailwind can update on every change.
skipCache: postcssResults.hasPostcss,
},
},
},
];
return {
dependencies: jsModuleResults.dependencies,
output,
};
}
exports.transform = transform;
/**
* A custom Metro transformer that adds support for processing Expo-specific bundler features.
* - Global CSS files on web.
* - CSS Modules on web.
* - TODO: Tailwind CSS on web.
*/
module.exports = {
// Use defaults for everything that's not custom.
...worker,
transform,
};
//# sourceMappingURL=transform-worker.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"transform-worker.js","sourceRoot":"","sources":["../../src/transform-worker/transform-worker.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,2 @@
export declare function tryRequireThenImport<TModule>(moduleId: string): Promise<TModule>;
export declare function requireUncachedFile(moduleId: string): any;

View File

@@ -0,0 +1,40 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.requireUncachedFile = exports.tryRequireThenImport = void 0;
async function tryRequireThenImport(moduleId) {
try {
return require(moduleId);
}
catch (requireError) {
let importESM;
try {
// eslint-disable-next-line no-new-func
importESM = new Function('id', 'return import(id);');
}
catch {
importESM = null;
}
if (requireError?.code === 'ERR_REQUIRE_ESM' && importESM) {
return (await importESM(moduleId)).default;
}
throw requireError;
}
}
exports.tryRequireThenImport = tryRequireThenImport;
function requireUncachedFile(moduleId) {
try {
// delete require.cache[require.resolve(moduleId)];
}
catch { }
try {
return require(moduleId);
}
catch (error) {
if (error instanceof Error) {
error.message = `Cannot load file ${moduleId}: ${error.message}`;
}
throw error;
}
}
exports.requireUncachedFile = requireUncachedFile;
//# sourceMappingURL=require.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"require.js","sourceRoot":"","sources":["../../../src/transform-worker/utils/require.ts"],"names":[],"mappings":";;;AAAO,KAAK,UAAU,oBAAoB,CAAU,QAAgB;IAClE,IAAI;QACF,OAAO,OAAO,CAAC,QAAQ,CAAC,CAAC;KAC1B;IAAC,OAAO,YAAiB,EAAE;QAC1B,IAAI,SAAS,CAAC;QACd,IAAI;YACF,uCAAuC;YACvC,SAAS,GAAG,IAAI,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC,CAAC;SACtD;QAAC,MAAM;YACN,SAAS,GAAG,IAAI,CAAC;SAClB;QAED,IAAI,YAAY,EAAE,IAAI,KAAK,iBAAiB,IAAI,SAAS,EAAE;YACzD,OAAO,CAAC,MAAM,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC;SAC5C;QAED,MAAM,YAAY,CAAC;KACpB;AACH,CAAC;AAlBD,oDAkBC;AAED,SAAgB,mBAAmB,CAAC,QAAgB;IAClD,IAAI;QACF,mDAAmD;KACpD;IAAC,MAAM,GAAE;IACV,IAAI;QACF,OAAO,OAAO,CAAC,QAAQ,CAAC,CAAC;KAC1B;IAAC,OAAO,KAAc,EAAE;QACvB,IAAI,KAAK,YAAY,KAAK,EAAE;YAC1B,KAAK,CAAC,OAAO,GAAG,oBAAoB,QAAQ,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;SAClE;QACD,MAAM,KAAK,CAAC;KACb;AACH,CAAC;AAZD,kDAYC"}

Some files were not shown because too many files have changed in this diff Show More