UNPKG

@expo/xdl

Version:
668 lines (521 loc) 18.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.buildPublishBundlesAsync = buildPublishBundlesAsync; exports.publishAsync = publishAsync; function _config() { const data = require("@expo/config"); _config = function () { return data; }; return data; } function _devServer() { const data = require("@expo/dev-server"); _devServer = function () { return data; }; return data; } function _axios() { const data = _interopRequireDefault(require("axios")); _axios = function () { return data; }; return data; } function _chalk() { const data = _interopRequireDefault(require("chalk")); _chalk = function () { return data; }; return data; } function _formData() { const data = _interopRequireDefault(require("form-data")); _formData = function () { return data; }; return data; } function _fsExtra() { const data = _interopRequireDefault(require("fs-extra")); _fsExtra = function () { return data; }; return data; } function _path() { const data = _interopRequireDefault(require("path")); _path = function () { return data; }; return data; } function _Analytics() { const data = _interopRequireDefault(require("../Analytics")); _Analytics = function () { return data; }; return data; } function _ApiV() { const data = _interopRequireDefault(require("../ApiV2")); _ApiV = function () { return data; }; return data; } function _Config() { const data = _interopRequireDefault(require("../Config")); _Config = function () { return data; }; return data; } function EmbeddedAssets() { const data = _interopRequireWildcard(require("../EmbeddedAssets")); EmbeddedAssets = function () { return data; }; return data; } function _Env() { const data = require("../Env"); _Env = function () { return data; }; return data; } function _Logger() { const data = _interopRequireDefault(require("../Logger")); _Logger = function () { return data; }; return data; } function _ProjectAssets() { const data = require("../ProjectAssets"); _ProjectAssets = function () { return data; }; return data; } function Sentry() { const data = _interopRequireWildcard(require("../Sentry")); Sentry = function () { return data; }; return data; } function UrlUtils() { const data = _interopRequireWildcard(require("../UrlUtils")); UrlUtils = function () { return data; }; return data; } function _User() { const data = _interopRequireDefault(require("../User")); _User = function () { return data; }; return data; } function _XDLError() { const data = _interopRequireDefault(require("../XDLError")); _XDLError = function () { return data; }; return data; } function ExponentTools() { const data = _interopRequireWildcard(require("../detach/ExponentTools")); ExponentTools = function () { return data; }; return data; } function TableText() { const data = _interopRequireWildcard(require("../logs/TableText")); TableText = function () { return data; }; return data; } function _TerminalLink() { const data = require("../logs/TerminalLink"); _TerminalLink = function () { return data; }; return data; } function _startLegacyReactNativeServerAsync() { const data = require("../start/startLegacyReactNativeServerAsync"); _startLegacyReactNativeServerAsync = function () { return data; }; return data; } function _resolveEntryPoint() { const data = require("../tools/resolveEntryPoint"); _resolveEntryPoint = function () { return data; }; return data; } function Doctor() { const data = _interopRequireWildcard(require("./Doctor")); Doctor = function () { return data; }; return data; } function ProjectUtils() { const data = _interopRequireWildcard(require("./ProjectUtils")); ProjectUtils = function () { return data; }; return data; } function _getPublishExpConfigAsync() { const data = require("./getPublishExpConfigAsync"); _getPublishExpConfigAsync = function () { return data; }; return data; } function _runHook() { const data = require("./runHook"); _runHook = function () { return data; }; return data; } function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; } function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (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; } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const MINIMUM_BUNDLE_SIZE = 500; async function buildPublishBundlesAsync(projectRoot, publishOptions = {}, bundleOptions) { if (!bundleOptions.useDevServer) { try { await (0, _startLegacyReactNativeServerAsync().startReactNativeServerAsync)({ projectRoot, options: { nonPersistent: true, maxWorkers: publishOptions.maxWorkers, target: publishOptions.target, reset: publishOptions.resetCache }, verbose: !publishOptions.quiet }); return await fetchPublishBundlesAsync(projectRoot); } finally { await (0, _startLegacyReactNativeServerAsync().stopReactNativeServerAsync)(projectRoot); } } const isLegacy = (0, _config().isLegacyImportsEnabled)((0, _config().getConfig)(projectRoot, { skipSDKVersionRequirement: true }).exp); // If not legacy, delete the target option to prevent warnings from being thrown. if (!isLegacy) { delete publishOptions.target; } const platforms = ['android', 'ios']; const [android, ios] = await (0, _devServer().bundleAsync)(projectRoot, { target: publishOptions.target, resetCache: publishOptions.resetCache, logger: ProjectUtils().getLogger(projectRoot), quiet: publishOptions.quiet }, platforms.map(platform => ({ platform, entryPoint: (0, _resolveEntryPoint().resolveEntryPoint)(projectRoot, platform), dev: bundleOptions.dev }))); return { android, ios }; } // Fetch iOS and Android bundles for publishing async function fetchPublishBundlesAsync(projectRoot, opts) { const entryPoint = (0, _resolveEntryPoint().resolveEntryPoint)(projectRoot); const publishUrl = await UrlUtils().constructPublishUrlAsync(projectRoot, entryPoint, undefined, opts); const sourceMapUrl = await UrlUtils().constructSourceMapUrlAsync(projectRoot, entryPoint); const assetsUrl = await UrlUtils().constructAssetsUrlAsync(projectRoot, entryPoint); _Logger().default.global.info('Building iOS bundle'); const iosBundle = await _getForPlatformAsync(projectRoot, publishUrl, 'ios', { errorCode: 'INVALID_BUNDLE', minLength: MINIMUM_BUNDLE_SIZE }); _Logger().default.global.info('Building Android bundle'); const androidBundle = await _getForPlatformAsync(projectRoot, publishUrl, 'android', { errorCode: 'INVALID_BUNDLE', minLength: MINIMUM_BUNDLE_SIZE }); _Logger().default.global.info('Building source maps'); const iosSourceMap = await _getForPlatformAsync(projectRoot, sourceMapUrl, 'ios', { errorCode: 'INVALID_BUNDLE', minLength: MINIMUM_BUNDLE_SIZE }); const androidSourceMap = await _getForPlatformAsync(projectRoot, sourceMapUrl, 'android', { errorCode: 'INVALID_BUNDLE', minLength: MINIMUM_BUNDLE_SIZE }); _Logger().default.global.info('Building asset maps'); const iosAssetsJson = await _getForPlatformAsync(projectRoot, assetsUrl, 'ios', { errorCode: 'INVALID_ASSETS' }); const androidAssetsJson = await _getForPlatformAsync(projectRoot, assetsUrl, 'android', { errorCode: 'INVALID_ASSETS' }); return { android: { code: androidBundle, map: androidSourceMap, assets: JSON.parse(androidAssetsJson) }, ios: { code: iosBundle, map: iosSourceMap, assets: JSON.parse(iosAssetsJson) } }; } async function _getForPlatformAsync(projectRoot, url, platform, { errorCode, minLength }) { const fullUrl = `${url}&platform=${platform}`; let response; try { response = await _axios().default.request({ url: fullUrl, responseType: 'text', // Workaround for https://github.com/axios/axios/issues/907. // Without transformResponse, axios will parse the body as JSON regardless of the responseType/ transformResponse: [data => data], proxy: false, validateStatus: status => status === 200, headers: { 'Exponent-Platform': platform } }); } catch (error) { if (error.response) { if (error.response.data) { let body; try { body = JSON.parse(error.response.data); } catch (e) { ProjectUtils().logError(projectRoot, 'expo', error.response.data); } if (body) { if (body.message) { ProjectUtils().logError(projectRoot, 'expo', body.message); } else { ProjectUtils().logError(projectRoot, 'expo', error.response.data); } } } throw new (_XDLError().default)(errorCode, `Packager URL ${fullUrl} returned unexpected code ${error.response.status}. ` + 'Please open your project in the Expo app and see if there are any errors. ' + 'Also scroll up and make sure there were no errors or warnings when opening your project.'); } else { throw error; } } if (!response.data || minLength && response.data.length < minLength) { throw new (_XDLError().default)(errorCode, `Body is: ${response.data}`); } return response.data; } async function publishAsync(projectRoot, options = {}) { var _options$target, _exp$android, _exp$ios, _exp$ios2, _exp$android2, _options$releaseChann; options.target = (_options$target = options.target) !== null && _options$target !== void 0 ? _options$target : (0, _config().getDefaultTarget)(projectRoot); const target = options.target; const user = await _User().default.ensureLoggedInAsync(); if ((0, _Env().isDebug)()) { console.log(); console.log('Publish Assets:'); console.log(`- Asset target: ${target}`); console.log(); } _Analytics().default.logEvent('Publish', { projectRoot, developerTool: _Config().default.developerTool }); const validationStatus = await Doctor().validateWithNetworkAsync(projectRoot); if (validationStatus === Doctor().ERROR || validationStatus === Doctor().FATAL) { throw new (_XDLError().default)('PUBLISH_VALIDATION_ERROR', "Couldn't publish because errors were found. (See logs above.) Please fix the errors and try again."); } // Get project config const { exp, pkg, hooks } = await (0, _getPublishExpConfigAsync().getPublishExpConfigAsync)(projectRoot, options); // Exit early if kernel builds are created with robot users if (exp.isKernel && user.kind === 'robot') { throw new (_XDLError().default)('ROBOT_ACCOUNT_ERROR', 'Kernel builds are not available for robot users'); } // TODO: refactor this out to a function, throw error if length doesn't match const validPostPublishHooks = (0, _runHook().prepareHooks)(hooks, 'postPublish', projectRoot); const bundles = await buildPublishBundlesAsync(projectRoot, options, { useDevServer: (0, _Env().shouldUseDevServer)(exp) }); const androidBundle = bundles.android.code; const iosBundle = bundles.ios.code; const files = [['index.ios.js', bundles.ios.code], ['index.android.js', bundles.android.code]]; // Account for inline source maps if (bundles.ios.map) { files.push([_chalk().default.dim('index.ios.js.map'), bundles.ios.map]); } if (bundles.android.map) { files.push([_chalk().default.dim('index.android.js.map'), bundles.android.map]); } _Logger().default.global.info(''); _Logger().default.global.info(TableText().createFilesTable(files)); _Logger().default.global.info(''); _Logger().default.global.info(`💡 JavaScript bundle sizes affect startup time. ${_chalk().default.dim((0, _TerminalLink().learnMore)(`https://expo.fyi/javascript-bundle-sizes`))}`); _Logger().default.global.info(''); await (0, _ProjectAssets().publishAssetsAsync)({ projectRoot, exp, bundles }); const hasHooks = validPostPublishHooks.length > 0; const shouldPublishAndroidMaps = !!((_exp$android = exp.android) === null || _exp$android === void 0 ? void 0 : _exp$android.publishSourceMapPath); const shouldPublishIosMaps = !!((_exp$ios = exp.ios) === null || _exp$ios === void 0 ? void 0 : _exp$ios.publishSourceMapPath); const androidSourceMap = hasHooks || shouldPublishAndroidMaps ? bundles.android.map : null; const iosSourceMap = hasHooks || shouldPublishIosMaps ? bundles.ios.map : null; let response; try { response = await _uploadArtifactsAsync({ pkg, exp, iosBundle, androidBundle, options }); } catch (e) { if (e.serverError === 'SCHEMA_VALIDATION_ERROR') { throw new Error(`There was an error validating your project schema. Check for any warnings about the contents of your app.json or app.config.js.`); } Sentry().captureException(e); throw e; } let androidManifest = {}; let iosManifest = {}; if (validPostPublishHooks.length || ((_exp$ios2 = exp.ios) === null || _exp$ios2 === void 0 ? void 0 : _exp$ios2.publishManifestPath) || ((_exp$android2 = exp.android) === null || _exp$android2 === void 0 ? void 0 : _exp$android2.publishManifestPath) || EmbeddedAssets().shouldEmbedAssetsForExpoUpdates(projectRoot, exp, pkg, target)) { [androidManifest, iosManifest] = await Promise.all([ExponentTools().getManifestAsync(response.url, { 'Exponent-SDK-Version': exp.sdkVersion, 'Exponent-Platform': 'android', 'Expo-Release-Channel': options.releaseChannel, Accept: 'application/expo+json,application/json' }), ExponentTools().getManifestAsync(response.url, { 'Exponent-SDK-Version': exp.sdkVersion, 'Exponent-Platform': 'ios', 'Expo-Release-Channel': options.releaseChannel, Accept: 'application/expo+json,application/json' })]); const hookOptions = { url: response.url, exp, iosBundle, iosSourceMap, iosManifest, androidBundle, androidSourceMap, androidManifest, projectRoot, log: msg => { _Logger().default.global.info({ quiet: true }, msg); } }; for (const hook of validPostPublishHooks) { _Logger().default.global.info(`Running postPublish hook: ${hook.file}`); try { (0, _runHook().runHook)(hook, hookOptions); } catch (e) { _Logger().default.global.warn(`Warning: postPublish hook '${hook.file}' failed: ${e.stack}`); } } } const fullManifestUrl = response.url.replace('exp://', 'https://'); await EmbeddedAssets().configureAsync({ projectRoot, pkg, exp, releaseChannel: (_options$releaseChann = options.releaseChannel) !== null && _options$releaseChann !== void 0 ? _options$releaseChann : 'default', iosManifestUrl: fullManifestUrl, iosManifest, iosBundle, iosSourceMap, androidManifestUrl: fullManifestUrl, androidManifest, androidBundle, androidSourceMap, target }); // TODO: move to postPublish hook // This method throws early when a robot account is used for a kernel build if (exp.isKernel && user.kind !== 'robot') { await _handleKernelPublishedAsync({ user, exp, projectRoot, url: response.url }); } return { ...response, url: options.releaseChannel && options.releaseChannel !== 'default' ? `${response.url}?release-channel=${options.releaseChannel}` : response.url }; } async function _uploadArtifactsAsync({ exp, iosBundle, androidBundle, options, pkg }) { _Logger().default.global.info(''); _Logger().default.global.info('Uploading JavaScript bundles'); const formData = new (_formData().default)(); formData.append('expJson', JSON.stringify(exp)); formData.append('packageJson', JSON.stringify(pkg)); formData.append('iosBundle', iosBundle, 'iosBundle'); formData.append('androidBundle', androidBundle, 'androidBundle'); formData.append('options', JSON.stringify(options)); const user = await _User().default.ensureLoggedInAsync(); const api = _ApiV().default.clientForUser(user); return await api.uploadFormDataAsync('publish/new', formData); } async function _handleKernelPublishedAsync({ projectRoot, user, exp, url }) { var _exp$kernel, _exp$kernel2; let kernelBundleUrl = `${_Config().default.api.scheme}://${_Config().default.api.host}`; if (_Config().default.api.port) { kernelBundleUrl = `${kernelBundleUrl}:${_Config().default.api.port}`; } kernelBundleUrl = `${kernelBundleUrl}/@${user.username}/${exp.slug}/bundle`; if ((_exp$kernel = exp.kernel) === null || _exp$kernel === void 0 ? void 0 : _exp$kernel.androidManifestPath) { const manifest = await ExponentTools().getManifestAsync(url, { 'Exponent-SDK-Version': exp.sdkVersion, 'Exponent-Platform': 'android', Accept: 'application/expo+json,application/json' }); manifest.bundleUrl = kernelBundleUrl; manifest.sdkVersion = 'UNVERSIONED'; await _fsExtra().default.writeFile(_path().default.resolve(projectRoot, exp.kernel.androidManifestPath), JSON.stringify(manifest)); } if ((_exp$kernel2 = exp.kernel) === null || _exp$kernel2 === void 0 ? void 0 : _exp$kernel2.iosManifestPath) { const manifest = await ExponentTools().getManifestAsync(url, { 'Exponent-SDK-Version': exp.sdkVersion, 'Exponent-Platform': 'ios', Accept: 'application/expo+json,application/json' }); manifest.bundleUrl = kernelBundleUrl; manifest.sdkVersion = 'UNVERSIONED'; await _fsExtra().default.writeFile(_path().default.resolve(projectRoot, exp.kernel.iosManifestPath), JSON.stringify(manifest)); } } //# sourceMappingURL=../__sourcemaps__/project/publishAsync.js.map