@expo/cli
Version:
384 lines (383 loc) • 17.7 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "exportAppAsync", {
enumerable: true,
get: function() {
return exportAppAsync;
}
});
function _config() {
const data = require("@expo/config");
_config = function() {
return data;
};
return data;
}
function _assert() {
const data = /*#__PURE__*/ _interop_require_default(require("assert"));
_assert = function() {
return data;
};
return data;
}
function _chalk() {
const data = /*#__PURE__*/ _interop_require_default(require("chalk"));
_chalk = function() {
return data;
};
return data;
}
function _fs() {
const data = /*#__PURE__*/ _interop_require_default(require("fs"));
_fs = function() {
return data;
};
return data;
}
function _path() {
const data = /*#__PURE__*/ _interop_require_default(require("path"));
_path = function() {
return data;
};
return data;
}
const _createMetadataJson = require("./createMetadataJson");
const _exportAssets = require("./exportAssets");
const _exportDomComponents = require("./exportDomComponents");
const _exportHermes = require("./exportHermes");
const _exportStaticAsync = require("./exportStaticAsync");
const _favicon = require("./favicon");
const _getPublicExpoManifest = require("./getPublicExpoManifest");
const _publicFolder = require("./publicFolder");
const _saveAssets = require("./saveAssets");
const _writeContents = require("./writeContents");
const _log = /*#__PURE__*/ _interop_require_wildcard(require("../log"));
const _WebSupportProjectPrerequisite = require("../start/doctor/web/WebSupportProjectPrerequisite");
const _DevServerManager = require("../start/server/DevServerManager");
const _MetroBundlerDevServer = require("../start/server/metro/MetroBundlerDevServer");
const _router = require("../start/server/metro/router");
const _serializeHtml = require("../start/server/metro/serializeHtml");
const _ManifestMiddleware = require("../start/server/middleware/ManifestMiddleware");
const _metroOptions = require("../start/server/middleware/metroOptions");
const _webTemplate = require("../start/server/webTemplate");
const _env = require("../utils/env");
const _errors = require("../utils/errors");
const _nodeEnv = require("../utils/nodeEnv");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function _getRequireWildcardCache(nodeInterop) {
if (typeof WeakMap !== "function") return null;
var cacheBabelInterop = new WeakMap();
var cacheNodeInterop = new WeakMap();
return (_getRequireWildcardCache = function(nodeInterop) {
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
})(nodeInterop);
}
function _interop_require_wildcard(obj, nodeInterop) {
if (!nodeInterop && obj && obj.__esModule) {
return obj;
}
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
return {
default: obj
};
}
var cache = _getRequireWildcardCache(nodeInterop);
if (cache && cache.has(obj)) {
return cache.get(obj);
}
var newObj = {
__proto__: null
};
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
for(var key in obj){
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
if (desc && (desc.get || desc.set)) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
}
}
newObj.default = obj;
if (cache) {
cache.set(obj, newObj);
}
return newObj;
}
async function exportAppAsync(projectRoot, { platforms, outputDir, clear, dev, dumpAssetmap, sourceMaps, minify, bytecode, maxWorkers, skipSSG }) {
var _exp_web, _exp_web1;
// Force the environment during export and do not allow overriding it.
const environment = dev ? 'development' : 'production';
process.env.NODE_ENV = environment;
(0, _nodeEnv.setNodeEnv)(environment);
require('@expo/env').load(projectRoot);
const projectConfig = (0, _config().getConfig)(projectRoot);
const exp = await (0, _getPublicExpoManifest.getPublicExpoManifestAsync)(projectRoot, {
// Web doesn't require validation.
skipValidation: platforms.length === 1 && platforms[0] === 'web'
});
if (platforms.includes('web')) {
await new _WebSupportProjectPrerequisite.WebSupportProjectPrerequisite(projectRoot).assertAsync();
}
const useServerRendering = [
'static',
'server'
].includes(((_exp_web = exp.web) == null ? void 0 : _exp_web.output) ?? '');
if (skipSSG && ((_exp_web1 = exp.web) == null ? void 0 : _exp_web1.output) !== 'server') {
throw new _errors.CommandError('--no-ssg can only be used with `web.output: server`');
}
const baseUrl = (0, _metroOptions.getBaseUrlFromExpoConfig)(exp);
if (!bytecode && (platforms.includes('ios') || platforms.includes('android'))) {
_log.warn(`Bytecode makes the app startup faster, disabling bytecode is highly discouraged and should only be used for debugging purposes.`);
}
// Print out logs
if (baseUrl) {
_log.log();
_log.log(_chalk().default.gray`Using (experimental) base path: ${baseUrl}`);
// Warn if not using an absolute path.
if (!baseUrl.startsWith('/')) {
_log.log(_chalk().default.yellow` Base path does not start with a slash. Requests will not be absolute.`);
}
}
const mode = dev ? 'development' : 'production';
const publicPath = _path().default.resolve(projectRoot, _env.env.EXPO_PUBLIC_FOLDER);
const outputPath = _path().default.resolve(projectRoot, outputDir);
// Write the JS bundles to disk, and get the bundle file names (this could change with async chunk loading support).
const files = new Map();
const devServerManager = await _DevServerManager.DevServerManager.startMetroAsync(projectRoot, {
minify,
mode,
port: 8081,
isExporting: true,
location: {},
resetDevServer: clear,
maxWorkers
});
const devServer = devServerManager.getDefaultDevServer();
(0, _assert().default)(devServer instanceof _MetroBundlerDevServer.MetroBundlerDevServer);
const bundles = {};
const domComponentAssetsMetadata = {};
const spaPlatforms = // TODO: Support server and static rendering for server component exports.
useServerRendering && !devServer.isReactServerComponentsEnabled ? platforms.filter((platform)=>platform !== 'web') : platforms;
try {
if (devServer.isReactServerComponentsEnabled) {
// In RSC mode, we only need these to be in the client dir.
// TODO: Merge back with other copy after we add SSR.
try {
await (0, _publicFolder.copyPublicFolderAsync)(publicPath, _path().default.join(outputPath, 'client'));
} catch (error) {
_log.error('Failed to copy public directory to dist directory');
throw error;
}
} else {
// NOTE(kitten): The public folder is currently always copied, regardless of targetDomain
// split. Hence, there's another separate `copyPublicFolderAsync` call below for `web`
await (0, _publicFolder.copyPublicFolderAsync)(publicPath, outputPath);
}
let templateHtml;
// Can be empty during web-only SSG.
if (spaPlatforms.length) {
await Promise.all(spaPlatforms.map(async (platform)=>{
// Assert early so the user doesn't have to wait until bundling is complete to find out that
// Hermes won't be available.
const isHermes = (0, _exportHermes.isEnableHermesManaged)(exp, platform);
if (isHermes) {
await (0, _exportHermes.assertEngineMismatchAsync)(projectRoot, exp, platform);
}
let bundle;
try {
var _exp_experiments;
// Run metro bundler and create the JS bundles/source maps.
bundle = await devServer.nativeExportBundleAsync(exp, {
platform,
splitChunks: !_env.env.EXPO_NO_BUNDLE_SPLITTING && (devServer.isReactServerComponentsEnabled && !bytecode || platform === 'web'),
mainModuleName: (0, _ManifestMiddleware.getEntryWithServerRoot)(projectRoot, {
platform,
pkg: projectConfig.pkg
}),
mode: dev ? 'development' : 'production',
engine: isHermes ? 'hermes' : undefined,
serializerIncludeMaps: sourceMaps,
bytecode: bytecode && isHermes,
reactCompiler: !!((_exp_experiments = exp.experiments) == null ? void 0 : _exp_experiments.reactCompiler)
}, files);
} catch (error) {
_log.log('');
if (error instanceof Error) {
_log.exception(error);
} else {
_log.error('Failed to bundle the app');
_log.log(error);
}
process.exit(1);
}
bundles[platform] = bundle;
(0, _saveAssets.getFilesFromSerialAssets)(bundle.artifacts, {
includeSourceMaps: sourceMaps,
files,
isServerHosted: devServer.isReactServerComponentsEnabled
});
// TODO: Remove duplicates...
const expoDomComponentReferences = bundle.artifacts.map((artifact)=>Array.isArray(artifact.metadata.expoDomComponentReferences) ? artifact.metadata.expoDomComponentReferences : []).flat();
await Promise.all(// TODO: Make a version of this which uses `this.metro.getBundler().buildGraphForEntries([])` to bundle all the DOM components at once.
expoDomComponentReferences.map(async (filePath)=>{
const { bundle: platformDomComponentsBundle, htmlOutputName } = await (0, _exportDomComponents.exportDomComponentAsync)({
filePath,
projectRoot,
dev,
devServer,
isHermes,
includeSourceMaps: sourceMaps,
exp,
files,
useMd5Filename: true
});
// Merge the assets from the DOM component into the output assets.
// @ts-expect-error: mutate assets
bundle.assets.push(...platformDomComponentsBundle.assets);
(0, _exportDomComponents.transformNativeBundleForMd5Filename)({
domComponentReference: filePath,
nativeBundle: bundle,
files,
htmlOutputName
});
domComponentAssetsMetadata[platform] = [
...await (0, _exportDomComponents.addDomBundleToMetadataAsync)(platformDomComponentsBundle),
...(0, _exportDomComponents.transformDomEntryForMd5Filename)({
files,
htmlOutputName
})
];
}));
if (platform === 'web') {
// TODO: Unify with exportStaticAsync
// TODO: Maybe move to the serializer.
let html = await (0, _serializeHtml.serializeHtmlWithAssets)({
isExporting: true,
resources: bundle.artifacts,
template: await (0, _webTemplate.createTemplateHtmlFromExpoConfigAsync)(projectRoot, {
scripts: [],
cssLinks: [],
exp: projectConfig.exp
}),
baseUrl
});
// Add the favicon assets to the HTML.
const modifyHtml = await (0, _favicon.getVirtualFaviconAssetsAsync)(projectRoot, {
outputDir,
baseUrl,
files,
exp: projectConfig.exp
});
if (modifyHtml) {
html = modifyHtml(html);
}
// HACK: This is used for adding SSR shims in React Server Components.
templateHtml = html;
// Generate SPA-styled HTML file.
// If web exists, then write the template HTML file.
files.set('index.html', {
contents: html,
targetDomain: devServer.isReactServerComponentsEnabled ? 'server' : 'client'
});
}
}));
if (devServer.isReactServerComponentsEnabled) {
const isWeb = platforms.includes('web');
await (0, _exportStaticAsync.exportApiRoutesStandaloneAsync)(devServer, {
files,
platform: 'web',
apiRoutesOnly: !isWeb,
templateHtml
});
}
// TODO: Use same asset system across platforms again.
const { assets, embeddedHashSet } = await (0, _exportAssets.exportAssetsAsync)(projectRoot, {
files,
exp,
outputDir: outputPath,
bundles,
baseUrl
});
if (dumpAssetmap) {
_log.log('Creating asset map');
files.set('assetmap.json', {
contents: JSON.stringify((0, _writeContents.createAssetMap)({
assets
}))
});
}
const targetDomain = devServer.isReactServerComponentsEnabled ? 'client/' : '';
const fileNames = Object.fromEntries(Object.entries(bundles).map(([platform, bundle])=>[
platform,
bundle.artifacts.filter((asset)=>asset.type === 'js').map((asset)=>targetDomain + asset.filename)
]));
// Generate a `metadata.json` for EAS Update.
const contents = (0, _createMetadataJson.createMetadataJson)({
bundles,
fileNames,
embeddedHashSet,
domComponentAssetsMetadata
});
files.set('metadata.json', {
contents: JSON.stringify(contents)
});
}
// Additional web-only steps...
if (platforms.includes('web') && useServerRendering) {
var _exp_web2;
const exportServer = ((_exp_web2 = exp.web) == null ? void 0 : _exp_web2.output) === 'server';
if (exportServer) {
// TODO: Remove when this is abstracted into the files map
await (0, _publicFolder.copyPublicFolderAsync)(publicPath, _path().default.resolve(outputPath, 'client'));
}
if (skipSSG) {
_log.log('Skipping static site generation');
await (0, _exportStaticAsync.exportApiRoutesStandaloneAsync)(devServer, {
files,
platform: 'web',
apiRoutesOnly: true
});
// Output a placeholder index.html if one doesn't exist in the public directory.
// This ensures native + API routes have some content at the root URL.
const placeholderIndex = _path().default.resolve(outputPath, 'client/index.html');
if (!_fs().default.existsSync(placeholderIndex)) {
files.set('index.html', {
contents: `<html><body></body></html>`,
targetDomain: 'client'
});
}
} else if (// TODO: Support static export with RSC.
!devServer.isReactServerComponentsEnabled) {
var _exp_experiments;
await (0, _exportStaticAsync.exportFromServerAsync)(projectRoot, devServer, {
mode,
files,
clear: !!clear,
outputDir: outputPath,
minify,
baseUrl,
includeSourceMaps: sourceMaps,
routerRoot: (0, _router.getRouterDirectoryModuleIdWithManifest)(projectRoot, exp),
reactCompiler: !!((_exp_experiments = exp.experiments) == null ? void 0 : _exp_experiments.reactCompiler),
exportServer,
maxWorkers,
isExporting: true,
exp: projectConfig.exp
});
}
}
} finally{
await devServerManager.stopAsync();
}
// Write all files at the end for unified logging.
await (0, _saveAssets.persistMetroFilesAsync)(files, outputPath);
}
//# sourceMappingURL=exportApp.js.map
;