UNPKG

@expo/xdl

Version:
482 lines (364 loc) 14.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.exportAppAsync = exportAppAsync; function _config() { const data = require("@expo/config"); _config = function () { return data; }; return data; } function _assert() { const data = _interopRequireDefault(require("assert")); _assert = function () { return data; }; return data; } function _crypto() { const data = _interopRequireDefault(require("crypto")); _crypto = function () { return data; }; return data; } function _fsExtra() { const data = _interopRequireDefault(require("fs-extra")); _fsExtra = function () { return data; }; return data; } function _hashids() { const data = _interopRequireDefault(require("hashids")); _hashids = function () { return data; }; return data; } function _path() { const data = _interopRequireDefault(require("path")); _path = function () { return data; }; return data; } function _readLastLines() { const data = _interopRequireDefault(require("read-last-lines")); _readLastLines = function () { return data; }; return data; } function _semver() { const data = _interopRequireDefault(require("semver")); _semver = function () { return data; }; return data; } function _urlJoin() { const data = _interopRequireDefault(require("url-join")); _urlJoin = function () { return data; }; return data; } function _uuid() { const data = _interopRequireDefault(require("uuid")); _uuid = 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 _User() { const data = _interopRequireWildcard(require("../User")); _User = function () { return data; }; return data; } function _XDLError() { const data = _interopRequireDefault(require("../XDLError")); _XDLError = function () { return data; }; return data; } function _ArtifactUtils() { const data = require("../tools/ArtifactUtils"); _ArtifactUtils = function () { return data; }; return data; } function _getPublishExpConfigAsync() { const data = require("./getPublishExpConfigAsync"); _getPublishExpConfigAsync = function () { return data; }; return data; } function _publishAsync() { const data = require("./publishAsync"); _publishAsync = 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 bundlePlatforms = ['android', 'ios']; /** * If the `eas` flag is true, the stucture of the outputDir will be: ├── assets │ └── * ├── bundles │ ├── android-01ee6e3ab3e8c16a4d926c91808d5320.js │ └── ios-ee8206cc754d3f7aa9123b7f909d94ea.js └── metadata.json * If the `eas` flag is not true, then this function is for self hosting * and the outputDir will have the files created in the project directory the following way: . ├── android-index.json ├── ios-index.json ├── assets │ └── 1eccbc4c41d49fd81840aef3eaabe862 └── bundles ├── android-01ee6e3ab3e8c16a4d926c91808d5320.js └── ios-ee8206cc754d3f7aa9123b7f909d94ea.js */ async function exportAppAsync(projectRoot, publicUrl, assetUrl, outputDir, options = {}, experimentalBundle) { var _options$publishOptio, _options$publishOptio2; const absoluteOutputDir = _path().default.resolve(process.cwd(), outputDir); const defaultTarget = (0, _config().getDefaultTarget)(projectRoot); const target = (_options$publishOptio = (_options$publishOptio2 = options.publishOptions) === null || _options$publishOptio2 === void 0 ? void 0 : _options$publishOptio2.target) !== null && _options$publishOptio !== void 0 ? _options$publishOptio : defaultTarget; if ((0, _Env().isDebug)()) { console.log(); console.log('Export Assets:'); console.log(`- Asset target: ${target}`); console.log(); } // build the bundles // make output dirs if not exists const assetPathToWrite = _path().default.resolve(projectRoot, _path().default.join(outputDir, 'assets')); await _fsExtra().default.ensureDir(assetPathToWrite); const bundlesPathToWrite = _path().default.resolve(projectRoot, _path().default.join(outputDir, 'bundles')); await _fsExtra().default.ensureDir(bundlesPathToWrite); const { exp, pkg, hooks } = await (0, _getPublishExpConfigAsync().getPublishExpConfigAsync)(projectRoot, options.publishOptions || {}); const bundles = await (0, _publishAsync().buildPublishBundlesAsync)(projectRoot, options.publishOptions, { dev: options.isDev, useDevServer: (0, _Env().shouldUseDevServer)(exp) }); const iosBundle = bundles.ios.code; const androidBundle = bundles.android.code; const iosBundleHash = _crypto().default.createHash('md5').update(iosBundle).digest('hex'); const iosBundleUrl = `ios-${iosBundleHash}.js`; const iosJsPath = _path().default.join(absoluteOutputDir, 'bundles', iosBundleUrl); const androidBundleHash = _crypto().default.createHash('md5').update(androidBundle).digest('hex'); const androidBundleUrl = `android-${androidBundleHash}.js`; const androidJsPath = _path().default.join(absoluteOutputDir, 'bundles', androidBundleUrl); const relativeBundlePaths = { android: _path().default.join('bundles', androidBundleUrl), ios: _path().default.join('bundles', iosBundleUrl) }; await (0, _ArtifactUtils().writeArtifactSafelyAsync)(projectRoot, null, iosJsPath, iosBundle); await (0, _ArtifactUtils().writeArtifactSafelyAsync)(projectRoot, null, androidJsPath, androidBundle); _Logger().default.global.info('Finished saving JS Bundles.'); const { assets } = await (0, _ProjectAssets().exportAssetsAsync)({ projectRoot, exp, hostedUrl: publicUrl, assetPath: 'assets', outputDir: absoluteOutputDir, bundles, experimentalBundle }); if (experimentalBundle) { // Build metadata.json const fileMetadata = { android: {}, ios: {} }; bundlePlatforms.forEach(platform => { fileMetadata[platform].assets = []; bundles[platform].assets.forEach(asset => { fileMetadata[platform].assets = [...fileMetadata[platform].assets, ...asset.fileHashes.map(hash => { return { path: _path().default.join('assets', hash), ext: asset.type }; })]; }); fileMetadata[platform].bundle = relativeBundlePaths[platform]; }); const metadata = { version: 0, bundler: 'metro', fileMetadata: fileMetadata }; _fsExtra().default.writeFileSync(_path().default.resolve(outputDir, 'metadata.json'), JSON.stringify(metadata)); } if (options.dumpAssetmap) { _Logger().default.global.info('Dumping asset map.'); const assetmap = {}; assets.forEach(asset => { assetmap[asset.hash] = asset; }); await (0, _ArtifactUtils().writeArtifactSafelyAsync)(projectRoot, null, _path().default.join(absoluteOutputDir, 'assetmap.json'), JSON.stringify(assetmap)); } const iosSourceMap = bundles.ios.map; const androidSourceMap = bundles.android.map; // build source maps if (options.dumpSourcemap) { // write the sourcemap files const iosMapName = `ios-${iosBundleHash}.map`; const iosMapPath = _path().default.join(absoluteOutputDir, 'bundles', iosMapName); await (0, _ArtifactUtils().writeArtifactSafelyAsync)(projectRoot, null, iosMapPath, iosSourceMap); const androidMapName = `android-${androidBundleHash}.map`; const androidMapPath = _path().default.join(absoluteOutputDir, 'bundles', androidMapName); await (0, _ArtifactUtils().writeArtifactSafelyAsync)(projectRoot, null, androidMapPath, androidSourceMap); if (target === 'managed' && _semver().default.lt(exp.sdkVersion, '40.0.0')) { // Remove original mapping to incorrect sourcemap paths // In SDK 40+ and bare projects, we no longer need to do this. _Logger().default.global.info('Configuring source maps'); await truncateLastNLines(iosJsPath, 1); await truncateLastNLines(androidJsPath, 1); } // Add correct mapping to sourcemap paths await _fsExtra().default.appendFile(iosJsPath, `\n//# sourceMappingURL=${iosMapName}`); await _fsExtra().default.appendFile(androidJsPath, `\n//# sourceMappingURL=${androidMapName}`); // Make a debug html so user can debug their bundles _Logger().default.global.info('Preparing additional debugging files'); const debugHtml = ` <script src="${(0, _urlJoin().default)('bundles', iosBundleUrl)}"></script> <script src="${(0, _urlJoin().default)('bundles', androidBundleUrl)}"></script> Open up this file in Chrome. In the Javascript developer console, navigate to the Source tab. You can see a red coloured folder containing the original source code from your bundle. `; await (0, _ArtifactUtils().writeArtifactSafelyAsync)(projectRoot, null, _path().default.join(absoluteOutputDir, 'debug.html'), debugHtml); } // Skip the hooks and manifest creation if building for EAS. if (!experimentalBundle) { const validPostExportHooks = (0, _runHook().prepareHooks)(hooks, 'postExport', projectRoot); // Add assetUrl to manifest exp.assetUrlOverride = assetUrl; exp.publishedTime = new Date().toISOString(); exp.commitTime = new Date().toISOString(); exp.releaseId = _uuid().default.v4(); // generate revisionId and id the same way www does const hashIds = new (_hashids().default)(_uuid().default.v1(), 10); exp.revisionId = hashIds.encode(Date.now()); if (options.isDev) { exp.developer = { tool: 'exp' }; } if (!exp.slug) { throw new (_XDLError().default)('INVALID_MANIFEST', 'Must provide a slug field in the app.json manifest.'); } let username = await _User().default.getCurrentUsernameAsync(); if (!username) { username = _User().ANONYMOUS_USERNAME; } exp.id = `@${username}/${exp.slug}`; // save the android manifest const androidManifest = { ...exp, bundleUrl: (0, _urlJoin().default)(publicUrl, 'bundles', androidBundleUrl), platform: 'android', dependencies: Object.keys(pkg.dependencies) }; await (0, _ArtifactUtils().writeArtifactSafelyAsync)(projectRoot, null, _path().default.join(absoluteOutputDir, 'android-index.json'), JSON.stringify(androidManifest)); // save the ios manifest const iosManifest = { ...exp, bundleUrl: (0, _urlJoin().default)(publicUrl, 'bundles', iosBundleUrl), platform: 'ios', dependencies: Object.keys(pkg.dependencies) }; await (0, _ArtifactUtils().writeArtifactSafelyAsync)(projectRoot, null, _path().default.join(absoluteOutputDir, 'ios-index.json'), JSON.stringify(iosManifest)); (0, _assert().default)(androidManifest, 'should have been assigned'); (0, _assert().default)(iosManifest, 'should have been assigned'); const hookOptions = { url: null, exp, iosBundle, iosSourceMap, iosManifest, androidBundle, androidSourceMap, androidManifest, projectRoot, log: msg => { _Logger().default.global.info({ quiet: true }, msg); } }; for (const hook of validPostExportHooks) { _Logger().default.global.info(`Running postExport hook: ${hook.file}`); try { (0, _runHook().runHook)(hook, hookOptions); } catch (e) { _Logger().default.global.warn(`Warning: postExport hook '${hook.file}' failed: ${e.stack}`); } } // configure embedded assets for expo-updates or ExpoKit await EmbeddedAssets().configureAsync({ projectRoot, pkg, exp, iosManifestUrl: (0, _urlJoin().default)(publicUrl, 'ios-index.json'), iosManifest, iosBundle, iosSourceMap, androidManifestUrl: (0, _urlJoin().default)(publicUrl, 'android-index.json'), androidManifest, androidBundle, androidSourceMap, target }); } } // truncate the last n lines in a file async function truncateLastNLines(filePath, n) { const lines = await _readLastLines().default.read(filePath, n); const to_vanquish = lines.length; const { size } = await _fsExtra().default.stat(filePath); await _fsExtra().default.truncate(filePath, size - to_vanquish); } //# sourceMappingURL=../__sourcemaps__/project/exportAppAsync.js.map