- Consolidated duplicate UndoManagers to single instance - Fixed connection promise to only resolve on 'connected' status - Fixed WebSocketProvider import (WebsocketProvider) - Added proper doc.destroy() cleanup - Renamed isPresenceInitialized property to avoid conflict Co-Authored-By: Paperclip <noreply@paperclip.ing>
1460 lines
46 KiB
JavaScript
1460 lines
46 KiB
JavaScript
"use strict";
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true,
|
|
});
|
|
exports.default = void 0;
|
|
var _Assets = require("./Assets");
|
|
var _baseJSBundle = _interopRequireDefault(
|
|
require("./DeltaBundler/Serializers/baseJSBundle"),
|
|
);
|
|
var _getAllFiles = _interopRequireDefault(
|
|
require("./DeltaBundler/Serializers/getAllFiles"),
|
|
);
|
|
var _getAssets = _interopRequireDefault(
|
|
require("./DeltaBundler/Serializers/getAssets"),
|
|
);
|
|
var _getExplodedSourceMap = require("./DeltaBundler/Serializers/getExplodedSourceMap");
|
|
var _getRamBundleInfo = _interopRequireDefault(
|
|
require("./DeltaBundler/Serializers/getRamBundleInfo"),
|
|
);
|
|
var _sourceMapString = require("./DeltaBundler/Serializers/sourceMapString");
|
|
var _IncrementalBundler = _interopRequireDefault(
|
|
require("./IncrementalBundler"),
|
|
);
|
|
var _ResourceNotFoundError = _interopRequireDefault(
|
|
require("./IncrementalBundler/ResourceNotFoundError"),
|
|
);
|
|
var _bundleProgressUtils = require("./lib/bundleProgressUtils");
|
|
var _bundleToString = _interopRequireDefault(require("./lib/bundleToString"));
|
|
var _formatBundlingError = _interopRequireDefault(
|
|
require("./lib/formatBundlingError"),
|
|
);
|
|
var _getGraphId = _interopRequireDefault(require("./lib/getGraphId"));
|
|
var _parseBundleOptionsFromBundleRequestUrl = _interopRequireDefault(
|
|
require("./lib/parseBundleOptionsFromBundleRequestUrl"),
|
|
);
|
|
var _parseJsonBody = _interopRequireDefault(require("./lib/parseJsonBody"));
|
|
var _splitBundleOptions = _interopRequireDefault(
|
|
require("./lib/splitBundleOptions"),
|
|
);
|
|
var transformHelpers = _interopRequireWildcard(
|
|
require("./lib/transformHelpers"),
|
|
);
|
|
var _ModuleResolution = require("./node-haste/DependencyGraph/ModuleResolution");
|
|
var _parsePlatformFilePath = _interopRequireDefault(
|
|
require("./node-haste/lib/parsePlatformFilePath"),
|
|
);
|
|
var _MultipartResponse = _interopRequireDefault(
|
|
require("./Server/MultipartResponse"),
|
|
);
|
|
var _symbolicate = _interopRequireDefault(require("./Server/symbolicate"));
|
|
var _types = require("./shared/types");
|
|
var _codeFrame = require("@babel/code-frame");
|
|
var fs = _interopRequireWildcard(require("graceful-fs"));
|
|
var jscSafeUrl = _interopRequireWildcard(require("jsc-safe-url"));
|
|
var _metroCore = require("metro-core");
|
|
var _mimeTypes = _interopRequireDefault(require("mime-types"));
|
|
var _nullthrows = _interopRequireDefault(require("nullthrows"));
|
|
var _path = _interopRequireDefault(require("path"));
|
|
var _perf_hooks = require("perf_hooks");
|
|
var _querystring = _interopRequireDefault(require("querystring"));
|
|
function _interopRequireWildcard(e, t) {
|
|
if ("function" == typeof WeakMap)
|
|
var r = new WeakMap(),
|
|
n = new WeakMap();
|
|
return (_interopRequireWildcard = function (e, t) {
|
|
if (!t && e && e.__esModule) return e;
|
|
var o,
|
|
i,
|
|
f = { __proto__: null, default: e };
|
|
if (null === e || ("object" != typeof e && "function" != typeof e))
|
|
return f;
|
|
if ((o = t ? n : r)) {
|
|
if (o.has(e)) return o.get(e);
|
|
o.set(e, f);
|
|
}
|
|
for (const t in e)
|
|
"default" !== t &&
|
|
{}.hasOwnProperty.call(e, t) &&
|
|
((i =
|
|
(o = Object.defineProperty) &&
|
|
Object.getOwnPropertyDescriptor(e, t)) &&
|
|
(i.get || i.set)
|
|
? o(f, t, i)
|
|
: (f[t] = e[t]));
|
|
return f;
|
|
})(e, t);
|
|
}
|
|
function _interopRequireDefault(e) {
|
|
return e && e.__esModule ? e : { default: e };
|
|
}
|
|
const debug = require("debug")("Metro:Server");
|
|
const { createActionStartEntry, createActionEndEntry, log } = _metroCore.Logger;
|
|
const noopLogger = {
|
|
start: () => {},
|
|
point: () => {},
|
|
annotate: () => {},
|
|
subSpan: () => noopLogger,
|
|
end: () => {},
|
|
};
|
|
const DELTA_ID_HEADER = "X-Metro-Delta-ID";
|
|
const FILES_CHANGED_COUNT_HEADER = "X-Metro-Files-Changed-Count";
|
|
class Server {
|
|
constructor(config, options) {
|
|
this._config = config;
|
|
this._serverOptions = options;
|
|
if (this._config.resetCache) {
|
|
this._config.cacheStores.forEach((store) => store.clear());
|
|
this._config.reporter.update({
|
|
type: "transform_cache_reset",
|
|
});
|
|
}
|
|
this._reporter = config.reporter;
|
|
this._logger = _metroCore.Logger;
|
|
this._platforms = new Set(this._config.resolver.platforms);
|
|
this._allowedSuffixesForSourceRequests = [
|
|
...new Set(
|
|
[
|
|
...this._config.resolver.sourceExts,
|
|
...this._config.watcher.additionalExts,
|
|
...this._config.resolver.assetExts,
|
|
].map((ext) => "." + ext),
|
|
),
|
|
];
|
|
this._sourceRequestRoutingMap = [
|
|
["/[metro-project]/", _path.default.resolve(this._config.projectRoot)],
|
|
...this._config.watchFolders.map((watchFolder, index) => [
|
|
`/[metro-watchFolders]/${index}/`,
|
|
_path.default.resolve(watchFolder),
|
|
]),
|
|
];
|
|
this._isEnded = false;
|
|
this._fetchTimings = [];
|
|
this._activeFetchCount = 0;
|
|
this._createModuleId = config.serializer.createModuleIdFactory();
|
|
this._bundler = new _IncrementalBundler.default(config, {
|
|
hasReducedPerformance: options && options.hasReducedPerformance,
|
|
watch: options ? options.watch : undefined,
|
|
});
|
|
this._nextBundleBuildNumber = 1;
|
|
}
|
|
async end() {
|
|
if (!this._isEnded) {
|
|
await this._bundler.end();
|
|
this._isEnded = true;
|
|
}
|
|
}
|
|
getBundler() {
|
|
return this._bundler;
|
|
}
|
|
getCreateModuleId() {
|
|
return this._createModuleId;
|
|
}
|
|
async _serializeGraph({ splitOptions, prepend, graph }) {
|
|
const {
|
|
entryFile,
|
|
graphOptions,
|
|
resolverOptions,
|
|
serializerOptions,
|
|
transformOptions,
|
|
} = splitOptions;
|
|
const entryPoint = this._getEntryPointAbsolutePath(entryFile);
|
|
const bundleOptions = {
|
|
asyncRequireModulePath: await this._resolveRelativePath(
|
|
this._config.transformer.asyncRequireModulePath,
|
|
{
|
|
relativeTo: "project",
|
|
resolverOptions,
|
|
transformOptions,
|
|
},
|
|
),
|
|
processModuleFilter: this._config.serializer.processModuleFilter,
|
|
createModuleId: this._createModuleId,
|
|
getRunModuleStatement: this._config.serializer.getRunModuleStatement,
|
|
globalPrefix: this._config.transformer.globalPrefix,
|
|
dev: transformOptions.dev,
|
|
includeAsyncPaths: graphOptions.lazy,
|
|
projectRoot: this._config.projectRoot,
|
|
modulesOnly: serializerOptions.modulesOnly,
|
|
runBeforeMainModule:
|
|
this._config.serializer.getModulesRunBeforeMainModule(
|
|
_path.default.relative(this._config.projectRoot, entryPoint),
|
|
),
|
|
runModule: serializerOptions.runModule,
|
|
sourceMapUrl: serializerOptions.sourceMapUrl,
|
|
sourceUrl: serializerOptions.sourceUrl,
|
|
inlineSourceMap: serializerOptions.inlineSourceMap,
|
|
serverRoot:
|
|
this._config.server.unstable_serverRoot ?? this._config.projectRoot,
|
|
shouldAddToIgnoreList: (module) =>
|
|
this._shouldAddModuleToIgnoreList(module),
|
|
getSourceUrl: (module) =>
|
|
this._getModuleSourceUrl(module, serializerOptions.sourcePaths),
|
|
};
|
|
let bundleCode = null;
|
|
let bundleMap = null;
|
|
if (this._config.serializer.customSerializer) {
|
|
const bundle = await this._config.serializer.customSerializer(
|
|
entryPoint,
|
|
prepend,
|
|
graph,
|
|
bundleOptions,
|
|
);
|
|
if (typeof bundle === "string") {
|
|
bundleCode = bundle;
|
|
} else {
|
|
bundleCode = bundle.code;
|
|
bundleMap = bundle.map;
|
|
}
|
|
} else {
|
|
bundleCode = (0, _bundleToString.default)(
|
|
(0, _baseJSBundle.default)(entryPoint, prepend, graph, bundleOptions),
|
|
).code;
|
|
}
|
|
if (!bundleMap) {
|
|
bundleMap = await (0, _sourceMapString.sourceMapStringNonBlocking)(
|
|
[...prepend, ...this._getSortedModules(graph)],
|
|
{
|
|
excludeSource: serializerOptions.excludeSource,
|
|
processModuleFilter: this._config.serializer.processModuleFilter,
|
|
shouldAddToIgnoreList: bundleOptions.shouldAddToIgnoreList,
|
|
getSourceUrl: (module) =>
|
|
this._getModuleSourceUrl(module, serializerOptions.sourcePaths),
|
|
},
|
|
);
|
|
}
|
|
return {
|
|
code: bundleCode,
|
|
map: bundleMap,
|
|
};
|
|
}
|
|
async build(bundleOptions, { withAssets } = {}) {
|
|
const splitOptions = (0, _splitBundleOptions.default)(bundleOptions);
|
|
const {
|
|
entryFile,
|
|
graphOptions,
|
|
onProgress,
|
|
resolverOptions,
|
|
transformOptions,
|
|
} = splitOptions;
|
|
const { prepend, graph } = await this._bundler.buildGraph(
|
|
entryFile,
|
|
transformOptions,
|
|
resolverOptions,
|
|
{
|
|
onProgress,
|
|
shallow: graphOptions.shallow,
|
|
lazy: graphOptions.lazy,
|
|
},
|
|
);
|
|
const [{ code, map }, assets] = await Promise.all([
|
|
this._serializeGraph({
|
|
splitOptions,
|
|
prepend,
|
|
graph,
|
|
}),
|
|
withAssets
|
|
? this._getAssetsFromDependencies(
|
|
graph.dependencies,
|
|
bundleOptions.platform,
|
|
)
|
|
: null,
|
|
]);
|
|
return {
|
|
code,
|
|
map,
|
|
...(withAssets
|
|
? {
|
|
assets: (0, _nullthrows.default)(assets),
|
|
}
|
|
: null),
|
|
};
|
|
}
|
|
async getRamBundleInfo(options) {
|
|
const {
|
|
entryFile,
|
|
graphOptions,
|
|
onProgress,
|
|
resolverOptions,
|
|
serializerOptions,
|
|
transformOptions,
|
|
} = (0, _splitBundleOptions.default)(options);
|
|
const { prepend, graph } = await this._bundler.buildGraph(
|
|
entryFile,
|
|
transformOptions,
|
|
resolverOptions,
|
|
{
|
|
onProgress,
|
|
shallow: graphOptions.shallow,
|
|
lazy: graphOptions.lazy,
|
|
},
|
|
);
|
|
const entryPoint = this._getEntryPointAbsolutePath(entryFile);
|
|
return await (0, _getRamBundleInfo.default)(entryPoint, prepend, graph, {
|
|
asyncRequireModulePath: await this._resolveRelativePath(
|
|
this._config.transformer.asyncRequireModulePath,
|
|
{
|
|
relativeTo: "project",
|
|
resolverOptions,
|
|
transformOptions,
|
|
},
|
|
),
|
|
processModuleFilter: this._config.serializer.processModuleFilter,
|
|
createModuleId: this._createModuleId,
|
|
dev: transformOptions.dev,
|
|
excludeSource: serializerOptions.excludeSource,
|
|
getRunModuleStatement: this._config.serializer.getRunModuleStatement,
|
|
getTransformOptions: this._config.transformer.getTransformOptions,
|
|
globalPrefix: this._config.transformer.globalPrefix,
|
|
includeAsyncPaths: graphOptions.lazy,
|
|
platform: transformOptions.platform,
|
|
projectRoot: this._config.projectRoot,
|
|
modulesOnly: serializerOptions.modulesOnly,
|
|
runBeforeMainModule:
|
|
this._config.serializer.getModulesRunBeforeMainModule(
|
|
_path.default.relative(this._config.projectRoot, entryPoint),
|
|
),
|
|
runModule: serializerOptions.runModule,
|
|
sourceMapUrl: serializerOptions.sourceMapUrl,
|
|
sourceUrl: serializerOptions.sourceUrl,
|
|
inlineSourceMap: serializerOptions.inlineSourceMap,
|
|
serverRoot:
|
|
this._config.server.unstable_serverRoot ?? this._config.projectRoot,
|
|
shouldAddToIgnoreList: (module) =>
|
|
this._shouldAddModuleToIgnoreList(module),
|
|
getSourceUrl: (module) =>
|
|
this._getModuleSourceUrl(module, serializerOptions.sourcePaths),
|
|
});
|
|
}
|
|
async getAssets(options) {
|
|
const { entryFile, onProgress, resolverOptions, transformOptions } = (0,
|
|
_splitBundleOptions.default)(options);
|
|
const dependencies = await this._bundler.getDependencies(
|
|
[entryFile],
|
|
transformOptions,
|
|
resolverOptions,
|
|
{
|
|
onProgress,
|
|
shallow: false,
|
|
lazy: false,
|
|
},
|
|
);
|
|
return this._getAssetsFromDependencies(
|
|
dependencies,
|
|
transformOptions.platform,
|
|
);
|
|
}
|
|
async _getAssetsFromDependencies(dependencies, platform) {
|
|
return await (0, _getAssets.default)(dependencies, {
|
|
processModuleFilter: this._config.serializer.processModuleFilter,
|
|
assetPlugins: this._config.transformer.assetPlugins,
|
|
platform,
|
|
projectRoot: this._getServerRootDir(),
|
|
publicPath: this._config.transformer.publicPath,
|
|
});
|
|
}
|
|
async getOrderedDependencyPaths(options) {
|
|
const { entryFile, onProgress, resolverOptions, transformOptions } = (0,
|
|
_splitBundleOptions.default)({
|
|
...Server.DEFAULT_BUNDLE_OPTIONS,
|
|
...options,
|
|
});
|
|
const { prepend, graph } = await this._bundler.buildGraph(
|
|
entryFile,
|
|
transformOptions,
|
|
resolverOptions,
|
|
{
|
|
onProgress,
|
|
shallow: false,
|
|
lazy: false,
|
|
},
|
|
);
|
|
const platform =
|
|
transformOptions.platform ||
|
|
(0, _parsePlatformFilePath.default)(entryFile, this._platforms).platform;
|
|
return await (0, _getAllFiles.default)(prepend, graph, {
|
|
platform,
|
|
processModuleFilter: this._config.serializer.processModuleFilter,
|
|
});
|
|
}
|
|
_rangeRequestMiddleware(req, res, data, assetPath) {
|
|
if (req.headers && req.headers.range) {
|
|
const [rangeStart, rangeEnd] = req.headers.range
|
|
.replace(/bytes=/, "")
|
|
.split("-");
|
|
const dataStart = parseInt(rangeStart, 10);
|
|
const dataEnd = rangeEnd ? parseInt(rangeEnd, 10) : data.length - 1;
|
|
const chunksize = dataEnd - dataStart + 1;
|
|
res.writeHead(206, {
|
|
"Accept-Ranges": "bytes",
|
|
"Content-Length": chunksize.toString(),
|
|
"Content-Range": `bytes ${dataStart}-${dataEnd}/${data.length}`,
|
|
});
|
|
return data.slice(dataStart, dataEnd + 1);
|
|
}
|
|
res.setHeader("Content-Length", String(Buffer.byteLength(data)));
|
|
return data;
|
|
}
|
|
async _processSingleAssetRequest(req, res) {
|
|
debug("Processing single asset request: %s", req.url);
|
|
if (!URL.canParse(req.url, "resolve://")) {
|
|
throw new Error("Could not parse URL", {
|
|
cause: req.url,
|
|
});
|
|
}
|
|
const urlObj = new URL(req.url, "resolve://");
|
|
const formattedUrl = urlObj.toString();
|
|
if (req.url !== formattedUrl) {
|
|
debug("Formatted as: %s", formattedUrl);
|
|
}
|
|
let [, assetPath] =
|
|
urlObj.pathname
|
|
.split("/")
|
|
.map((segment) => decodeURIComponent(segment))
|
|
.join("/")
|
|
.match(/^\/assets\/(.+)$/) || [];
|
|
if (!assetPath && urlObj.searchParams.get("unstable_path")) {
|
|
const [, actualPath, secondaryQuery] = (0, _nullthrows.default)(
|
|
(urlObj.searchParams.get("unstable_path") || "").match(
|
|
/^([^?]*)\??(.*)$/,
|
|
),
|
|
);
|
|
if (secondaryQuery) {
|
|
Object.entries(_querystring.default.parse(secondaryQuery)).forEach(
|
|
([key, value]) => {
|
|
urlObj.searchParams.set(key, value);
|
|
},
|
|
);
|
|
}
|
|
assetPath = actualPath;
|
|
}
|
|
if (!assetPath) {
|
|
throw new Error("Could not extract asset path from URL");
|
|
}
|
|
const processingAssetRequestLogEntry = log(
|
|
createActionStartEntry({
|
|
action_name: "Processing asset request",
|
|
asset: assetPath[1],
|
|
}),
|
|
);
|
|
try {
|
|
const depGraph = await this._bundler.getBundler().getDependencyGraph();
|
|
const data = await (0, _Assets.getAsset)(
|
|
assetPath,
|
|
this._config.projectRoot,
|
|
this._config.watchFolders,
|
|
urlObj.searchParams.get("platform"),
|
|
this._config.resolver.assetExts,
|
|
(filePath) => depGraph.doesFileExist(filePath),
|
|
);
|
|
if (process.env.REACT_NATIVE_ENABLE_ASSET_CACHING === true) {
|
|
res.setHeader("Cache-Control", "max-age=31536000");
|
|
}
|
|
res.setHeader(
|
|
"Content-Type",
|
|
_mimeTypes.default.lookup(_path.default.basename(assetPath)),
|
|
);
|
|
res.end(this._rangeRequestMiddleware(req, res, data, assetPath));
|
|
process.nextTick(() => {
|
|
log(createActionEndEntry(processingAssetRequestLogEntry));
|
|
});
|
|
} catch (error) {
|
|
console.error(error.stack);
|
|
res.writeHead(404);
|
|
res.end("Asset not found");
|
|
}
|
|
}
|
|
processRequest = (req, res, next) => {
|
|
this._processRequest(req, res, next).catch(next);
|
|
};
|
|
_parseOptions(url) {
|
|
const { bundleType: _bundleType, ...bundleOptions } = (0,
|
|
_parseBundleOptionsFromBundleRequestUrl.default)(
|
|
url,
|
|
new Set(this._config.resolver.platforms),
|
|
);
|
|
return bundleOptions;
|
|
}
|
|
_rewriteAndNormalizeUrl(requestUrl) {
|
|
return jscSafeUrl.toNormalUrl(
|
|
this._config.server.rewriteRequestUrl(jscSafeUrl.toNormalUrl(requestUrl)),
|
|
);
|
|
}
|
|
async _processRequest(req, res, next) {
|
|
const originalUrl = req.url;
|
|
debug("Handling request: %s", originalUrl);
|
|
req.url = this._rewriteAndNormalizeUrl(req.url);
|
|
if (req.url !== originalUrl) {
|
|
debug("Rewritten to: %s", req.url);
|
|
}
|
|
const reqHost = req.headers["x-forwarded-host"] || req.headers["host"];
|
|
debug("Request host is: %s", req.headers["host"]);
|
|
if (req.headers["x-forwarded-host"]) {
|
|
debug(
|
|
"Request x-forwarded-host is: %s",
|
|
req.headers["x-forwarded-host"],
|
|
);
|
|
}
|
|
if (!reqHost) {
|
|
throw new Error("No host header was found.");
|
|
}
|
|
const reqProtocol =
|
|
req.headers["x-forwarded-proto"] ||
|
|
(req.socket?.encrypted === true ? "https" : "http");
|
|
const urlObj = new URL(req.url, reqProtocol + "://" + reqHost);
|
|
const formattedUrl = urlObj.toString();
|
|
if (req.url !== formattedUrl) {
|
|
debug("Formatted as: %s", formattedUrl);
|
|
}
|
|
const pathname = urlObj.pathname || "";
|
|
const filePathname = pathname
|
|
.split("/")
|
|
.map((segment) => decodeURIComponent(segment))
|
|
.join("/");
|
|
const buildNumber = this.getNewBuildNumber();
|
|
if (pathname.endsWith(".bundle")) {
|
|
const options = this._parseOptions(formattedUrl);
|
|
await this._processBundleRequest(req, res, options, {
|
|
buildNumber,
|
|
bundlePerfLogger:
|
|
this._config.unstable_perfLoggerFactory?.("BUNDLING_REQUEST", {
|
|
key: buildNumber,
|
|
}) ?? noopLogger,
|
|
});
|
|
if (this._serverOptions && this._serverOptions.onBundleBuilt) {
|
|
this._serverOptions.onBundleBuilt(filePathname);
|
|
}
|
|
} else if (pathname.endsWith(".map")) {
|
|
res.setHeader("Access-Control-Allow-Origin", "devtools://devtools");
|
|
await this._processSourceMapRequest(
|
|
req,
|
|
res,
|
|
this._parseOptions(formattedUrl),
|
|
{
|
|
buildNumber,
|
|
bundlePerfLogger: noopLogger,
|
|
},
|
|
);
|
|
} else if (pathname.endsWith(".assets")) {
|
|
await this._processAssetsRequest(
|
|
req,
|
|
res,
|
|
this._parseOptions(formattedUrl),
|
|
{
|
|
buildNumber,
|
|
bundlePerfLogger: noopLogger,
|
|
},
|
|
);
|
|
} else if (pathname.startsWith("/assets/") || pathname === "/assets") {
|
|
await this._processSingleAssetRequest(req, res);
|
|
} else if (pathname === "/symbolicate") {
|
|
await this._symbolicate(req, res);
|
|
} else {
|
|
let handled = false;
|
|
for (const [pathnamePrefix, normalizedRootDir] of this
|
|
._sourceRequestRoutingMap) {
|
|
if (filePathname.startsWith(pathnamePrefix)) {
|
|
const relativeFilePathname = filePathname.substr(
|
|
pathnamePrefix.length,
|
|
);
|
|
await this._processSourceRequest(
|
|
relativeFilePathname,
|
|
normalizedRootDir,
|
|
res,
|
|
);
|
|
handled = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!handled) {
|
|
next();
|
|
}
|
|
}
|
|
}
|
|
async _processSourceRequest(relativeFilePathname, rootDir, res) {
|
|
if (
|
|
!this._allowedSuffixesForSourceRequests.some((suffix) =>
|
|
relativeFilePathname.endsWith(suffix),
|
|
)
|
|
) {
|
|
res.writeHead(404);
|
|
res.end();
|
|
return;
|
|
}
|
|
const depGraph = await this._bundler.getBundler().getDependencyGraph();
|
|
const filePath = _path.default.join(rootDir, relativeFilePathname);
|
|
try {
|
|
await depGraph.getOrComputeSha1(filePath);
|
|
} catch {
|
|
res.writeHead(404);
|
|
res.end();
|
|
return;
|
|
}
|
|
const mimeType = _mimeTypes.default.lookup(
|
|
_path.default.basename(relativeFilePathname),
|
|
);
|
|
res.setHeader("Content-Type", mimeType);
|
|
const stream = fs.createReadStream(filePath);
|
|
stream.pipe(res);
|
|
stream.on("error", (error) => {
|
|
if (error.code === "ENOENT") {
|
|
res.writeHead(404);
|
|
res.end();
|
|
} else {
|
|
res.writeHead(500);
|
|
res.end();
|
|
}
|
|
});
|
|
}
|
|
_createRequestProcessor({
|
|
bundleType,
|
|
createStartEntry,
|
|
createEndEntry,
|
|
build,
|
|
delete: deleteFn,
|
|
finish,
|
|
}) {
|
|
return async function requestProcessor(
|
|
req,
|
|
res,
|
|
bundleOptions,
|
|
buildContext,
|
|
) {
|
|
const requestStartTimestamp =
|
|
_perf_hooks.performance.timeOrigin + _perf_hooks.performance.now();
|
|
const { buildNumber } = buildContext;
|
|
const {
|
|
entryFile,
|
|
graphOptions,
|
|
resolverOptions,
|
|
serializerOptions,
|
|
transformOptions,
|
|
} = (0, _splitBundleOptions.default)(bundleOptions);
|
|
let resolvedEntryFilePath;
|
|
try {
|
|
resolvedEntryFilePath = await this._resolveRelativePath(entryFile, {
|
|
relativeTo: "server",
|
|
resolverOptions,
|
|
transformOptions,
|
|
});
|
|
} catch (error) {
|
|
const formattedError = (0, _formatBundlingError.default)(error);
|
|
const status =
|
|
error instanceof _ModuleResolution.UnableToResolveError ? 404 : 500;
|
|
res.writeHead(status, {
|
|
"Content-Type": "application/json; charset=UTF-8",
|
|
});
|
|
res.end(JSON.stringify(formattedError));
|
|
return;
|
|
}
|
|
const graphId = (0, _getGraphId.default)(
|
|
resolvedEntryFilePath,
|
|
transformOptions,
|
|
{
|
|
unstable_allowRequireContext:
|
|
this._config.transformer.unstable_allowRequireContext,
|
|
resolverOptions,
|
|
shallow: graphOptions.shallow,
|
|
lazy: graphOptions.lazy,
|
|
},
|
|
);
|
|
if (deleteFn && req.method === "DELETE") {
|
|
const deleteContext = {
|
|
graphId,
|
|
req,
|
|
res,
|
|
};
|
|
try {
|
|
await deleteFn(deleteContext);
|
|
} catch (error) {
|
|
const formattedError = (0, _formatBundlingError.default)(error);
|
|
const status =
|
|
error instanceof _ResourceNotFoundError.default ? 404 : 500;
|
|
res.writeHead(status, {
|
|
"Content-Type": "application/json; charset=UTF-8",
|
|
});
|
|
res.end(JSON.stringify(formattedError));
|
|
}
|
|
return;
|
|
}
|
|
const mres = _MultipartResponse.default.wrapIfSupported(req, res);
|
|
let onProgress = null;
|
|
let lastRatio = -1;
|
|
if (this._config.reporter) {
|
|
onProgress = (transformedFileCount, totalFileCount) => {
|
|
const newRatio = (0,
|
|
_bundleProgressUtils.calculateBundleProgressRatio)(
|
|
transformedFileCount,
|
|
totalFileCount,
|
|
lastRatio,
|
|
);
|
|
if (newRatio > lastRatio) {
|
|
if (mres instanceof _MultipartResponse.default) {
|
|
mres.writeChunk(
|
|
{
|
|
"Content-Type": "application/json",
|
|
},
|
|
JSON.stringify({
|
|
done: transformedFileCount,
|
|
total: totalFileCount,
|
|
percent: Math.floor(newRatio * 100),
|
|
}),
|
|
);
|
|
}
|
|
if (res.socket != null && res.socket.uncork != null) {
|
|
res.socket.uncork();
|
|
}
|
|
lastRatio = newRatio;
|
|
}
|
|
this._reporter.update({
|
|
buildID: getBuildID(buildNumber),
|
|
type: "bundle_transform_progressed",
|
|
transformedFileCount,
|
|
totalFileCount,
|
|
});
|
|
};
|
|
}
|
|
this._reporter.update({
|
|
buildID: getBuildID(buildNumber),
|
|
bundleDetails: {
|
|
bundleType,
|
|
customResolverOptions: bundleOptions.customResolverOptions,
|
|
customTransformOptions: bundleOptions.customTransformOptions,
|
|
dev: transformOptions.dev,
|
|
entryFile: resolvedEntryFilePath,
|
|
minify: transformOptions.minify,
|
|
platform: transformOptions.platform,
|
|
},
|
|
isPrefetch: req.method === "HEAD",
|
|
type: "bundle_build_started",
|
|
});
|
|
const startContext = {
|
|
buildNumber,
|
|
bundleOptions,
|
|
entryFile: resolvedEntryFilePath,
|
|
graphId,
|
|
graphOptions,
|
|
mres,
|
|
onProgress,
|
|
req,
|
|
resolverOptions,
|
|
serializerOptions,
|
|
transformOptions,
|
|
bundlePerfLogger: buildContext.bundlePerfLogger,
|
|
requestStartTimestamp,
|
|
};
|
|
const logEntry = log(
|
|
createActionStartEntry(createStartEntry(startContext)),
|
|
);
|
|
const fetchTiming = {
|
|
graphId,
|
|
startTime: requestStartTimestamp,
|
|
endTime: null,
|
|
isPrefetch: req.method === "HEAD",
|
|
};
|
|
let result;
|
|
try {
|
|
this._fetchTimings.push(fetchTiming);
|
|
this._activeFetchCount++;
|
|
result = await build(startContext);
|
|
} catch (error) {
|
|
const formattedError = (0, _formatBundlingError.default)(error);
|
|
const status =
|
|
error instanceof _ResourceNotFoundError.default ? 404 : 500;
|
|
mres.writeHead(status, {
|
|
"Content-Type": "application/json; charset=UTF-8",
|
|
});
|
|
mres.end(JSON.stringify(formattedError));
|
|
this._reporter.update({
|
|
buildID: getBuildID(buildNumber),
|
|
type: "bundle_build_failed",
|
|
bundleOptions,
|
|
});
|
|
this._reporter.update({
|
|
error,
|
|
type: "bundling_error",
|
|
});
|
|
log({
|
|
action_name: "bundling_error",
|
|
error_type: formattedError.type,
|
|
log_entry_label: "bundling_error",
|
|
bundle_id: graphId,
|
|
build_id: getBuildID(buildNumber),
|
|
stack: formattedError.message,
|
|
});
|
|
debug("Bundling error", error);
|
|
buildContext.bundlePerfLogger.end("FAIL");
|
|
return;
|
|
} finally {
|
|
fetchTiming.endTime =
|
|
_perf_hooks.performance.timeOrigin + _perf_hooks.performance.now();
|
|
if (!fetchTiming.isPrefetch) {
|
|
buildContext.bundlePerfLogger.annotate({
|
|
bool: {
|
|
had_competing_prefetch: this._fetchTimings
|
|
.filter((t) => t.isPrefetch && t.graphId !== graphId)
|
|
.some((prefetch) => {
|
|
const prefetchEndTime =
|
|
prefetch.endTime ?? Number.MAX_SAFE_INTEGER;
|
|
const fetchEndTime =
|
|
fetchTiming.endTime ?? Number.MAX_SAFE_INTEGER;
|
|
return (
|
|
prefetch.startTime < fetchEndTime &&
|
|
prefetchEndTime > fetchTiming.startTime
|
|
);
|
|
}),
|
|
},
|
|
});
|
|
}
|
|
this._activeFetchCount--;
|
|
if (this._activeFetchCount === 0) {
|
|
this._fetchTimings = [];
|
|
}
|
|
}
|
|
const endContext = {
|
|
...startContext,
|
|
result,
|
|
};
|
|
finish(endContext);
|
|
this._reporter.update({
|
|
buildID: getBuildID(buildNumber),
|
|
type: "bundle_build_done",
|
|
});
|
|
log(
|
|
createActionEndEntry({
|
|
...logEntry,
|
|
...createEndEntry(endContext),
|
|
}),
|
|
);
|
|
};
|
|
}
|
|
_processBundleRequest = this._createRequestProcessor({
|
|
bundleType: "bundle",
|
|
createStartEntry(context) {
|
|
return {
|
|
action_name: "Requesting bundle",
|
|
bundle_url: context.req.url,
|
|
bundle_original_url: context.req.originalUrl ?? "unknown",
|
|
entry_point: context.entryFile,
|
|
bundler: "delta",
|
|
build_id: getBuildID(context.buildNumber),
|
|
bundle_options: context.bundleOptions,
|
|
bundle_hash: context.graphId,
|
|
user_agent: context.req.headers["user-agent"] ?? "unknown",
|
|
};
|
|
},
|
|
createEndEntry(context) {
|
|
return {
|
|
outdated_modules: context.result.numModifiedFiles,
|
|
};
|
|
},
|
|
build: async ({
|
|
entryFile,
|
|
graphId,
|
|
graphOptions,
|
|
onProgress,
|
|
resolverOptions,
|
|
serializerOptions,
|
|
transformOptions,
|
|
bundlePerfLogger,
|
|
requestStartTimestamp,
|
|
}) => {
|
|
bundlePerfLogger.start({
|
|
timestamp: requestStartTimestamp,
|
|
});
|
|
bundlePerfLogger.annotate({
|
|
string: {
|
|
bundle_url: entryFile,
|
|
},
|
|
});
|
|
const revPromise = this._bundler.getRevisionByGraphId(graphId);
|
|
bundlePerfLogger.point("resolvingAndTransformingDependencies_start");
|
|
bundlePerfLogger.annotate({
|
|
bool: {
|
|
initial_build: revPromise == null,
|
|
},
|
|
});
|
|
const { delta, revision } = await (revPromise != null
|
|
? this._bundler.updateGraph(await revPromise, false)
|
|
: this._bundler.initializeGraph(
|
|
entryFile,
|
|
transformOptions,
|
|
resolverOptions,
|
|
{
|
|
onProgress,
|
|
shallow: graphOptions.shallow,
|
|
lazy: graphOptions.lazy,
|
|
},
|
|
));
|
|
bundlePerfLogger.annotate({
|
|
int: {
|
|
graph_node_count: revision.graph.dependencies.size,
|
|
},
|
|
});
|
|
bundlePerfLogger.point("resolvingAndTransformingDependencies_end");
|
|
bundlePerfLogger.point("serializingBundle_start");
|
|
const serializer =
|
|
this._config.serializer.customSerializer ||
|
|
((entryPoint, preModules, graph, options) =>
|
|
(0, _bundleToString.default)(
|
|
(0, _baseJSBundle.default)(entryPoint, preModules, graph, options),
|
|
).code);
|
|
const bundle = await serializer(
|
|
entryFile,
|
|
revision.prepend,
|
|
revision.graph,
|
|
{
|
|
asyncRequireModulePath: await this._resolveRelativePath(
|
|
this._config.transformer.asyncRequireModulePath,
|
|
{
|
|
relativeTo: "project",
|
|
resolverOptions,
|
|
transformOptions,
|
|
},
|
|
),
|
|
processModuleFilter: this._config.serializer.processModuleFilter,
|
|
createModuleId: this._createModuleId,
|
|
getRunModuleStatement: this._config.serializer.getRunModuleStatement,
|
|
globalPrefix: this._config.transformer.globalPrefix,
|
|
includeAsyncPaths: graphOptions.lazy,
|
|
dev: transformOptions.dev,
|
|
projectRoot: this._config.projectRoot,
|
|
modulesOnly: serializerOptions.modulesOnly,
|
|
runBeforeMainModule:
|
|
this._config.serializer.getModulesRunBeforeMainModule(
|
|
_path.default.relative(this._config.projectRoot, entryFile),
|
|
),
|
|
runModule: serializerOptions.runModule,
|
|
sourceMapUrl: serializerOptions.sourceMapUrl,
|
|
sourceUrl: serializerOptions.sourceUrl,
|
|
inlineSourceMap: serializerOptions.inlineSourceMap,
|
|
serverRoot:
|
|
this._config.server.unstable_serverRoot ?? this._config.projectRoot,
|
|
shouldAddToIgnoreList: (module) =>
|
|
this._shouldAddModuleToIgnoreList(module),
|
|
getSourceUrl: (module) =>
|
|
this._getModuleSourceUrl(module, serializerOptions.sourcePaths),
|
|
},
|
|
);
|
|
bundlePerfLogger.point("serializingBundle_end");
|
|
const bundleCode = typeof bundle === "string" ? bundle : bundle.code;
|
|
return {
|
|
numModifiedFiles: delta.reset
|
|
? delta.added.size + revision.prepend.length
|
|
: delta.added.size + delta.modified.size + delta.deleted.size,
|
|
lastModifiedDate: revision.date,
|
|
nextRevId: revision.id,
|
|
bundle: bundleCode,
|
|
};
|
|
},
|
|
finish({ req, mres, serializerOptions, result, bundlePerfLogger }) {
|
|
bundlePerfLogger.annotate({
|
|
int: {
|
|
bundle_length: result.bundle.length,
|
|
bundle_byte_length: Buffer.byteLength(result.bundle),
|
|
},
|
|
});
|
|
mres.once("error", () => {
|
|
bundlePerfLogger.end("FAIL");
|
|
});
|
|
mres.once("finish", () => {
|
|
bundlePerfLogger.end("SUCCESS");
|
|
});
|
|
if (
|
|
req.headers["if-modified-since"] ===
|
|
result.lastModifiedDate.toUTCString()
|
|
) {
|
|
bundlePerfLogger.annotate({
|
|
string: {
|
|
http_status: "304",
|
|
},
|
|
});
|
|
debug("Responding with 304");
|
|
mres.writeHead(304);
|
|
mres.end();
|
|
} else {
|
|
bundlePerfLogger.annotate({
|
|
string: {
|
|
http_status: "200",
|
|
},
|
|
});
|
|
mres.setHeader(
|
|
FILES_CHANGED_COUNT_HEADER,
|
|
String(result.numModifiedFiles),
|
|
);
|
|
mres.setHeader(DELTA_ID_HEADER, String(result.nextRevId));
|
|
if (serializerOptions?.sourceUrl != null) {
|
|
mres.setHeader("Content-Location", serializerOptions.sourceUrl);
|
|
}
|
|
mres.setHeader("Content-Type", "application/javascript; charset=UTF-8");
|
|
mres.setHeader("Last-Modified", result.lastModifiedDate.toUTCString());
|
|
mres.setHeader(
|
|
"Content-Length",
|
|
String(Buffer.byteLength(result.bundle)),
|
|
);
|
|
mres.end(result.bundle);
|
|
}
|
|
},
|
|
delete: async ({ graphId, res }) => {
|
|
await this._bundler.endGraph(graphId);
|
|
res.statusCode = 204;
|
|
res.end();
|
|
},
|
|
});
|
|
_getSortedModules(graph) {
|
|
const modules = [...graph.dependencies.values()];
|
|
for (const module of modules) {
|
|
this._createModuleId(module.path);
|
|
}
|
|
return modules.sort(
|
|
(a, b) => this._createModuleId(a.path) - this._createModuleId(b.path),
|
|
);
|
|
}
|
|
_processSourceMapRequest = this._createRequestProcessor({
|
|
bundleType: "map",
|
|
createStartEntry(context) {
|
|
return {
|
|
action_name: "Requesting sourcemap",
|
|
bundle_url: context.req.url,
|
|
entry_point: context.entryFile,
|
|
bundler: "delta",
|
|
};
|
|
},
|
|
createEndEntry(context) {
|
|
return {
|
|
bundler: "delta",
|
|
};
|
|
},
|
|
build: async ({
|
|
entryFile,
|
|
graphId,
|
|
graphOptions,
|
|
onProgress,
|
|
resolverOptions,
|
|
serializerOptions,
|
|
transformOptions,
|
|
}) => {
|
|
let revision;
|
|
const revPromise = this._bundler.getRevisionByGraphId(graphId);
|
|
if (revPromise == null) {
|
|
({ revision } = await this._bundler.initializeGraph(
|
|
entryFile,
|
|
transformOptions,
|
|
resolverOptions,
|
|
{
|
|
onProgress,
|
|
shallow: graphOptions.shallow,
|
|
lazy: graphOptions.lazy,
|
|
},
|
|
));
|
|
} else {
|
|
({ revision } = await this._bundler.updateGraph(
|
|
await revPromise,
|
|
false,
|
|
));
|
|
}
|
|
let { prepend, graph } = revision;
|
|
if (serializerOptions.modulesOnly) {
|
|
prepend = [];
|
|
}
|
|
return await (0, _sourceMapString.sourceMapStringNonBlocking)(
|
|
[...prepend, ...this._getSortedModules(graph)],
|
|
{
|
|
excludeSource: serializerOptions.excludeSource,
|
|
processModuleFilter: this._config.serializer.processModuleFilter,
|
|
shouldAddToIgnoreList: (module) =>
|
|
this._shouldAddModuleToIgnoreList(module),
|
|
getSourceUrl: (module) =>
|
|
this._getModuleSourceUrl(module, serializerOptions.sourcePaths),
|
|
},
|
|
);
|
|
},
|
|
finish({ mres, result }) {
|
|
mres.setHeader("Content-Type", "application/json");
|
|
mres.end(result.toString());
|
|
},
|
|
});
|
|
_processAssetsRequest = this._createRequestProcessor({
|
|
bundleType: "assets",
|
|
createStartEntry(context) {
|
|
return {
|
|
action_name: "Requesting assets",
|
|
bundle_url: context.req.url,
|
|
entry_point: context.entryFile,
|
|
bundler: "delta",
|
|
};
|
|
},
|
|
createEndEntry(context) {
|
|
return {
|
|
bundler: "delta",
|
|
};
|
|
},
|
|
build: async ({
|
|
entryFile,
|
|
onProgress,
|
|
resolverOptions,
|
|
transformOptions,
|
|
}) => {
|
|
const dependencies = await this._bundler.getDependencies(
|
|
[entryFile],
|
|
transformOptions,
|
|
resolverOptions,
|
|
{
|
|
onProgress,
|
|
shallow: false,
|
|
lazy: false,
|
|
},
|
|
);
|
|
return await (0, _getAssets.default)(dependencies, {
|
|
processModuleFilter: this._config.serializer.processModuleFilter,
|
|
assetPlugins: this._config.transformer.assetPlugins,
|
|
platform: transformOptions.platform,
|
|
publicPath: this._config.transformer.publicPath,
|
|
projectRoot: this._config.projectRoot,
|
|
});
|
|
},
|
|
finish({ mres, result }) {
|
|
mres.setHeader("Content-Type", "application/json");
|
|
mres.end(JSON.stringify(result));
|
|
},
|
|
});
|
|
async _symbolicate(req, res) {
|
|
const depGraph = await this._bundler.getBundler().getDependencyGraph();
|
|
const getCodeFrame = (urls, symbolicatedStack) => {
|
|
const allFramesCollapsed = symbolicatedStack.every(
|
|
({ collapse }) => collapse,
|
|
);
|
|
for (let i = 0; i < symbolicatedStack.length; i++) {
|
|
const { collapse, column, file, lineNumber } = symbolicatedStack[i];
|
|
if (
|
|
(!allFramesCollapsed && collapse) ||
|
|
lineNumber == null ||
|
|
(file != null && urls.has(file))
|
|
) {
|
|
continue;
|
|
}
|
|
const fileAbsolute = _path.default.resolve(
|
|
this._config.projectRoot,
|
|
file ?? "",
|
|
);
|
|
if (!depGraph.doesFileExist(fileAbsolute)) {
|
|
debug(
|
|
"Skipping code frame for file not in dependency graph.",
|
|
fileAbsolute,
|
|
);
|
|
continue;
|
|
}
|
|
try {
|
|
return {
|
|
content: (0, _codeFrame.codeFrameColumns)(
|
|
fs.readFileSync(fileAbsolute, "utf8"),
|
|
{
|
|
start: {
|
|
column: column + 1,
|
|
line: lineNumber,
|
|
},
|
|
},
|
|
{
|
|
forceColor: true,
|
|
},
|
|
),
|
|
location: {
|
|
row: lineNumber,
|
|
column,
|
|
},
|
|
fileName: file,
|
|
};
|
|
} catch (error) {
|
|
debug(
|
|
"Generating code frame failed on file read.",
|
|
fileAbsolute,
|
|
error,
|
|
);
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
let inputValidated = false;
|
|
try {
|
|
const symbolicatingLogEntry = log(
|
|
createActionStartEntry("Symbolicating"),
|
|
);
|
|
debug("Start symbolication");
|
|
let parsedBody;
|
|
if ("rawBody" in req) {
|
|
const body = await req.rawBody;
|
|
parsedBody = JSON.parse(body);
|
|
} else {
|
|
parsedBody = await (0, _parseJsonBody.default)(req, {
|
|
strict: false,
|
|
});
|
|
}
|
|
let validatedBody;
|
|
if (
|
|
parsedBody != null &&
|
|
typeof parsedBody === "object" &&
|
|
!Array.isArray(parsedBody) &&
|
|
Array.isArray(parsedBody["stack"])
|
|
) {
|
|
const maybeStack = parsedBody["stack"];
|
|
const extraData = parsedBody["extraData"];
|
|
validatedBody = {
|
|
stack: maybeStack,
|
|
extraData,
|
|
};
|
|
} else {
|
|
throw new Error(
|
|
`Bad symbolication input, expected object with stack array, got: ${JSON.stringify(parsedBody)}`,
|
|
);
|
|
}
|
|
const validateAndNormalizeStackFrame = (frame) => {
|
|
if (
|
|
frame == null ||
|
|
typeof frame !== "object" ||
|
|
Array.isArray(frame)
|
|
) {
|
|
throw new Error("Expected frame to be a JSON object");
|
|
}
|
|
if (frame.file != null && typeof frame.file !== "string") {
|
|
throw new Error("Expected file to be string or nullish");
|
|
}
|
|
let frameFile = frame.file;
|
|
if (frameFile != null && frameFile.includes("://")) {
|
|
frameFile = this._rewriteAndNormalizeUrl(frameFile);
|
|
}
|
|
if (frame.methodName != null && typeof frame.methodName !== "string") {
|
|
throw new Error("Expected methodName to be string or nullish");
|
|
}
|
|
if (frame.lineNumber != null && typeof frame.lineNumber !== "number") {
|
|
throw new Error("Expected lineNumber to be number or nullish");
|
|
}
|
|
if (frame.column != null && typeof frame.column !== "number") {
|
|
throw new Error("Expected column to be number or nullish");
|
|
}
|
|
return {
|
|
...frame,
|
|
file: frameFile,
|
|
lineNumber: frame.lineNumber,
|
|
column: frame.column,
|
|
methodName: frame.methodName,
|
|
};
|
|
};
|
|
const stack = validatedBody.stack.map((frame, lineNumber) => {
|
|
try {
|
|
return validateAndNormalizeStackFrame(frame);
|
|
} catch (e) {
|
|
throw new Error(`Bad frame at line ${lineNumber}: ${e.message}`);
|
|
}
|
|
});
|
|
inputValidated = true;
|
|
const urls = new Set();
|
|
stack.forEach((frame) => {
|
|
const sourceUrl = frame.file;
|
|
if (
|
|
sourceUrl != null &&
|
|
!urls.has(sourceUrl) &&
|
|
!sourceUrl.endsWith("/debuggerWorker.js") &&
|
|
sourceUrl.startsWith("http")
|
|
) {
|
|
urls.add(sourceUrl);
|
|
}
|
|
});
|
|
debug("Getting source maps for symbolication");
|
|
const sourceMaps = await Promise.all(
|
|
Array.from(urls.values()).map((normalizedUrl) =>
|
|
this._explodedSourceMapForBundleOptions(
|
|
this._parseOptions(normalizedUrl),
|
|
),
|
|
),
|
|
);
|
|
debug("Performing fast symbolication");
|
|
const symbolicatedStack = await (0, _symbolicate.default)(
|
|
stack,
|
|
zip(urls.values(), sourceMaps),
|
|
this._config,
|
|
validatedBody.extraData ?? {},
|
|
);
|
|
debug("Symbolication done");
|
|
res.end(
|
|
JSON.stringify({
|
|
codeFrame: getCodeFrame(urls, symbolicatedStack),
|
|
stack: symbolicatedStack,
|
|
}),
|
|
);
|
|
process.nextTick(() => {
|
|
log(createActionEndEntry(symbolicatingLogEntry));
|
|
});
|
|
} catch (error) {
|
|
debug("Symbolication failed", error.stack || error);
|
|
res.statusCode = inputValidated ? 500 : 400;
|
|
res.end(
|
|
JSON.stringify({
|
|
error: error.message,
|
|
}),
|
|
);
|
|
}
|
|
}
|
|
async _explodedSourceMapForBundleOptions(bundleOptions) {
|
|
const {
|
|
entryFile,
|
|
graphOptions,
|
|
onProgress,
|
|
resolverOptions,
|
|
serializerOptions,
|
|
transformOptions,
|
|
} = (0, _splitBundleOptions.default)(bundleOptions);
|
|
const resolvedEntryFilePath = await this._resolveRelativePath(entryFile, {
|
|
relativeTo: "server",
|
|
resolverOptions,
|
|
transformOptions,
|
|
});
|
|
const graphId = (0, _getGraphId.default)(
|
|
resolvedEntryFilePath,
|
|
transformOptions,
|
|
{
|
|
unstable_allowRequireContext:
|
|
this._config.transformer.unstable_allowRequireContext,
|
|
resolverOptions,
|
|
shallow: graphOptions.shallow,
|
|
lazy: graphOptions.lazy,
|
|
},
|
|
);
|
|
let revision;
|
|
const revPromise = this._bundler.getRevisionByGraphId(graphId);
|
|
if (revPromise == null) {
|
|
({ revision } = await this._bundler.initializeGraph(
|
|
resolvedEntryFilePath,
|
|
transformOptions,
|
|
resolverOptions,
|
|
{
|
|
onProgress,
|
|
shallow: graphOptions.shallow,
|
|
lazy: graphOptions.lazy,
|
|
},
|
|
));
|
|
} else {
|
|
({ revision } = await this._bundler.updateGraph(await revPromise, false));
|
|
}
|
|
let { prepend, graph } = revision;
|
|
if (serializerOptions.modulesOnly) {
|
|
prepend = [];
|
|
}
|
|
return (0, _getExplodedSourceMap.getExplodedSourceMap)(
|
|
[...prepend, ...this._getSortedModules(graph)],
|
|
{
|
|
processModuleFilter: this._config.serializer.processModuleFilter,
|
|
},
|
|
);
|
|
}
|
|
async _resolveRelativePath(
|
|
filePath,
|
|
{ relativeTo, resolverOptions, transformOptions },
|
|
) {
|
|
const resolutionFn = await transformHelpers.getResolveDependencyFn(
|
|
this._bundler.getBundler(),
|
|
transformOptions.platform,
|
|
resolverOptions,
|
|
);
|
|
const rootDir =
|
|
relativeTo === "server"
|
|
? this._getServerRootDir()
|
|
: this._config.projectRoot;
|
|
return resolutionFn(`${rootDir}/.`, {
|
|
name: filePath,
|
|
data: {
|
|
key: filePath,
|
|
locs: [],
|
|
asyncType: null,
|
|
isESMImport: false,
|
|
},
|
|
}).filePath;
|
|
}
|
|
getNewBuildNumber() {
|
|
return this._nextBundleBuildNumber++;
|
|
}
|
|
getPlatforms() {
|
|
return this._config.resolver.platforms;
|
|
}
|
|
getWatchFolders() {
|
|
return this._config.watchFolders;
|
|
}
|
|
static DEFAULT_GRAPH_OPTIONS = {
|
|
customResolverOptions: Object.create(null),
|
|
customTransformOptions: Object.create(null),
|
|
dev: true,
|
|
minify: false,
|
|
unstable_transformProfile: "default",
|
|
};
|
|
static DEFAULT_BUNDLE_OPTIONS = {
|
|
...Server.DEFAULT_GRAPH_OPTIONS,
|
|
excludeSource: false,
|
|
inlineSourceMap: false,
|
|
lazy: false,
|
|
modulesOnly: false,
|
|
onProgress: null,
|
|
runModule: true,
|
|
shallow: false,
|
|
sourceMapUrl: null,
|
|
sourceUrl: null,
|
|
sourcePaths: _types.SourcePathsMode.Absolute,
|
|
};
|
|
_getServerRootDir() {
|
|
return this._config.server.unstable_serverRoot ?? this._config.projectRoot;
|
|
}
|
|
_getEntryPointAbsolutePath(entryFile) {
|
|
return _path.default.resolve(this._getServerRootDir(), entryFile);
|
|
}
|
|
async ready() {
|
|
await this._bundler.ready();
|
|
}
|
|
_shouldAddModuleToIgnoreList(module) {
|
|
return (
|
|
module.path === "__prelude__" ||
|
|
module.path.includes("?ctx=") ||
|
|
this._config.serializer.isThirdPartyModule(module)
|
|
);
|
|
}
|
|
_getModuleSourceUrl(module, mode) {
|
|
switch (mode) {
|
|
case _types.SourcePathsMode.ServerUrl:
|
|
for (const [pathnamePrefix, normalizedRootDir] of this
|
|
._sourceRequestRoutingMap) {
|
|
if (module.path.startsWith(normalizedRootDir + _path.default.sep)) {
|
|
const relativePath = module.path.slice(
|
|
normalizedRootDir.length + 1,
|
|
);
|
|
const relativePathPosix = relativePath
|
|
.split(_path.default.sep)
|
|
.map((segment) => encodeURIComponent(segment))
|
|
.join("/");
|
|
return pathnamePrefix + relativePathPosix;
|
|
}
|
|
}
|
|
const modulePathPosix = module.path
|
|
.split(_path.default.sep)
|
|
.map((segment) => encodeURIComponent(segment))
|
|
.join("/");
|
|
return modulePathPosix.startsWith("/")
|
|
? modulePathPosix
|
|
: "/" + modulePathPosix;
|
|
case _types.SourcePathsMode.Absolute:
|
|
return module.path;
|
|
}
|
|
}
|
|
}
|
|
exports.default = Server;
|
|
function* zip(xs, ys) {
|
|
const ysIter = ys[Symbol.iterator]();
|
|
for (const x of xs) {
|
|
const y = ysIter.next();
|
|
if (y.done) {
|
|
return;
|
|
}
|
|
yield [x, y.value];
|
|
}
|
|
}
|
|
function getBuildID(buildNumber) {
|
|
return buildNumber.toString(36);
|
|
}
|