UNPKG

next

Version:

The React Framework

623 lines (515 loc) • 16.8 kB
/** * @license React * react-server-dom-webpack.development.js * * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ 'use strict'; if (process.env.NODE_ENV !== "production") { (function() { 'use strict'; var React = require('react'); function createStringDecoder() { return new TextDecoder(); } var decoderOptions = { stream: true }; function readPartialStringChunk(decoder, buffer) { return decoder.decode(buffer, decoderOptions); } function readFinalStringChunk(decoder, buffer) { return decoder.decode(buffer); } function parseModel(response, json) { return JSON.parse(json, response._fromJSON); } // eslint-disable-next-line no-unused-vars function resolveModuleReference(bundlerConfig, moduleData) { if (bundlerConfig) { return bundlerConfig[moduleData.id][moduleData.name]; } return moduleData; } // The chunk cache contains all the chunks we've preloaded so far. // If they're still pending they're a thenable. This map also exists // in Webpack but unfortunately it's not exposed so we have to // replicate it in user space. null means that it has already loaded. var chunkCache = new Map(); // Start preloading the modules since we might need them soon. // This function doesn't suspend. function preloadModule(moduleData) { var chunks = moduleData.chunks; for (var i = 0; i < chunks.length; i++) { var chunkId = chunks[i]; var entry = chunkCache.get(chunkId); if (entry === undefined) { var thenable = globalThis.__next_chunk_load__(chunkId); var resolve = chunkCache.set.bind(chunkCache, chunkId, null); var reject = chunkCache.set.bind(chunkCache, chunkId); thenable.then(resolve, reject); chunkCache.set(chunkId, thenable); } } } // Actually require the module or suspend if it's not yet ready. // Increase priority if necessary. function requireModule(moduleData) { var chunks = moduleData.chunks; for (var i = 0; i < chunks.length; i++) { var chunkId = chunks[i]; var entry = chunkCache.get(chunkId); if (entry !== null) { // We assume that preloadModule has been called before. // So we don't expect to see entry being undefined here, that's an error. // Let's throw either an error or the Promise. throw entry; } } var moduleExports = globalThis.__next_require__(moduleData.id); if (moduleData.name === '*') { // This is a placeholder value that represents that the caller imported this // as a CommonJS module as is. return moduleExports; } if (moduleData.name === '') { // This is a placeholder value that represents that the caller accessed the // default property of this if it was an ESM interop module. return moduleExports.__esModule ? moduleExports.default : moduleExports; } return moduleExports[moduleData.name]; } // ATTENTION // When adding new symbols to this file, // Please consider also adding to 'react-devtools-shared/src/backend/ReactSymbols' // The Symbol used to tag the ReactElement-like types. var REACT_ELEMENT_TYPE = Symbol.for('react.element'); var REACT_LAZY_TYPE = Symbol.for('react.lazy'); var REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED = Symbol.for('react.default_value'); var ReactSharedInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; var ContextRegistry = ReactSharedInternals.ContextRegistry; function getOrCreateServerContext(globalName) { if (!ContextRegistry[globalName]) { ContextRegistry[globalName] = React.createServerContext(globalName, REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED); } return ContextRegistry[globalName]; } var PENDING = 0; var RESOLVED_MODEL = 1; var RESOLVED_MODULE = 2; var INITIALIZED = 3; var ERRORED = 4; function Chunk(status, value, response) { this._status = status; this._value = value; this._response = response; } Chunk.prototype.then = function (resolve) { var chunk = this; if (chunk._status === PENDING) { if (chunk._value === null) { chunk._value = []; } chunk._value.push(resolve); } else { resolve(); } }; function readChunk(chunk) { switch (chunk._status) { case INITIALIZED: return chunk._value; case RESOLVED_MODEL: return initializeModelChunk(chunk); case RESOLVED_MODULE: return initializeModuleChunk(chunk); case PENDING: // eslint-disable-next-line no-throw-literal throw chunk; default: throw chunk._value; } } function readRoot() { var response = this; var chunk = getChunk(response, 0); return readChunk(chunk); } function createPendingChunk(response) { return new Chunk(PENDING, null, response); } function createErrorChunk(response, error) { return new Chunk(ERRORED, error, response); } function createInitializedChunk(response, value) { return new Chunk(INITIALIZED, value, response); } function wakeChunk(listeners) { if (listeners !== null) { for (var i = 0; i < listeners.length; i++) { var listener = listeners[i]; listener(); } } } function triggerErrorOnChunk(chunk, error) { if (chunk._status !== PENDING) { // We already resolved. We didn't expect to see this. return; } var listeners = chunk._value; var erroredChunk = chunk; erroredChunk._status = ERRORED; erroredChunk._value = error; wakeChunk(listeners); } function createResolvedModelChunk(response, value) { return new Chunk(RESOLVED_MODEL, value, response); } function createResolvedModuleChunk(response, value) { return new Chunk(RESOLVED_MODULE, value, response); } function resolveModelChunk(chunk, value) { if (chunk._status !== PENDING) { // We already resolved. We didn't expect to see this. return; } var listeners = chunk._value; var resolvedChunk = chunk; resolvedChunk._status = RESOLVED_MODEL; resolvedChunk._value = value; wakeChunk(listeners); } function resolveModuleChunk(chunk, value) { if (chunk._status !== PENDING) { // We already resolved. We didn't expect to see this. return; } var listeners = chunk._value; var resolvedChunk = chunk; resolvedChunk._status = RESOLVED_MODULE; resolvedChunk._value = value; wakeChunk(listeners); } function initializeModelChunk(chunk) { var value = parseModel(chunk._response, chunk._value); var initializedChunk = chunk; initializedChunk._status = INITIALIZED; initializedChunk._value = value; return value; } function initializeModuleChunk(chunk) { var value = requireModule(chunk._value); var initializedChunk = chunk; initializedChunk._status = INITIALIZED; initializedChunk._value = value; return value; } // Report that any missing chunks in the model is now going to throw this // error upon read. Also notify any pending promises. function reportGlobalError(response, error) { response._chunks.forEach(function (chunk) { // If this chunk was already resolved or errored, it won't // trigger an error but if it wasn't then we need to // because we won't be getting any new data to resolve it. triggerErrorOnChunk(chunk, error); }); } function createElement(type, key, props) { var element = { // This tag allows us to uniquely identify this as a React Element $$typeof: REACT_ELEMENT_TYPE, // Built-in properties that belong on the element type: type, key: key, ref: null, props: props, // Record the component responsible for creating this element. _owner: null }; { // We don't really need to add any of these but keeping them for good measure. // Unfortunately, _store is enumerable in jest matchers so for equality to // work, I need to keep it or make _store non-enumerable in the other file. element._store = {}; Object.defineProperty(element._store, 'validated', { configurable: false, enumerable: false, writable: true, value: true // This element has already been validated on the server. }); Object.defineProperty(element, '_self', { configurable: false, enumerable: false, writable: false, value: null }); Object.defineProperty(element, '_source', { configurable: false, enumerable: false, writable: false, value: null }); } return element; } function createLazyChunkWrapper(chunk) { var lazyType = { $$typeof: REACT_LAZY_TYPE, _payload: chunk, _init: readChunk }; return lazyType; } function getChunk(response, id) { var chunks = response._chunks; var chunk = chunks.get(id); if (!chunk) { chunk = createPendingChunk(response); chunks.set(id, chunk); } return chunk; } function parseModelString(response, parentObject, value) { switch (value[0]) { case '$': { if (value === '$') { return REACT_ELEMENT_TYPE; } else if (value[1] === '$' || value[1] === '@') { // This was an escaped string value. return value.substring(1); } else { var id = parseInt(value.substring(1), 16); var chunk = getChunk(response, id); return readChunk(chunk); } } case '@': { var _id = parseInt(value.substring(1), 16); var _chunk = getChunk(response, _id); // We create a React.lazy wrapper around any lazy values. // When passed into React, we'll know how to suspend on this. return createLazyChunkWrapper(_chunk); } } return value; } function parseModelTuple(response, value) { var tuple = value; if (tuple[0] === REACT_ELEMENT_TYPE) { // TODO: Consider having React just directly accept these arrays as elements. // Or even change the ReactElement type to be an array. return createElement(tuple[1], tuple[2], tuple[3]); } return value; } function createResponse(bundlerConfig) { var chunks = new Map(); var response = { _bundlerConfig: bundlerConfig, _chunks: chunks, readRoot: readRoot }; return response; } function resolveModel(response, id, model) { var chunks = response._chunks; var chunk = chunks.get(id); if (!chunk) { chunks.set(id, createResolvedModelChunk(response, model)); } else { resolveModelChunk(chunk, model); } } function resolveProvider(response, id, contextName) { var chunks = response._chunks; chunks.set(id, createInitializedChunk(response, getOrCreateServerContext(contextName).Provider)); } function resolveModule(response, id, model) { var chunks = response._chunks; var chunk = chunks.get(id); var moduleMetaData = parseModel(response, model); var moduleReference = resolveModuleReference(response._bundlerConfig, moduleMetaData); // TODO: Add an option to encode modules that are lazy loaded. // For now we preload all modules as early as possible since it's likely // that we'll need them. preloadModule(moduleReference); if (!chunk) { chunks.set(id, createResolvedModuleChunk(response, moduleReference)); } else { resolveModuleChunk(chunk, moduleReference); } } function resolveSymbol(response, id, name) { var chunks = response._chunks; // We assume that we'll always emit the symbol before anything references it // to save a few bytes. chunks.set(id, createInitializedChunk(response, Symbol.for(name))); } function resolveError(response, id, message, stack) { // eslint-disable-next-line react-internal/prod-error-codes var error = new Error(message); error.stack = stack; var chunks = response._chunks; var chunk = chunks.get(id); if (!chunk) { chunks.set(id, createErrorChunk(response, error)); } else { triggerErrorOnChunk(chunk, error); } } function close(response) { // In case there are any remaining unresolved chunks, they won't // be resolved now. So we need to issue an error to those. // Ideally we should be able to early bail out if we kept a // ref count of pending chunks. reportGlobalError(response, new Error('Connection closed.')); } function processFullRow(response, row) { if (row === '') { return; } var tag = row[0]; // When tags that are not text are added, check them here before // parsing the row as text. // switch (tag) { // } var colon = row.indexOf(':', 1); var id = parseInt(row.substring(1, colon), 16); var text = row.substring(colon + 1); switch (tag) { case 'J': { resolveModel(response, id, text); return; } case 'M': { resolveModule(response, id, text); return; } case 'P': { resolveProvider(response, id, text); return; } case 'S': { resolveSymbol(response, id, JSON.parse(text)); return; } case 'E': { var errorInfo = JSON.parse(text); resolveError(response, id, errorInfo.message, errorInfo.stack); return; } default: { throw new Error("Error parsing the data. It's probably an error code or network corruption."); } } } function processStringChunk(response, chunk, offset) { var linebreak = chunk.indexOf('\n', offset); while (linebreak > -1) { var fullrow = response._partialRow + chunk.substring(offset, linebreak); processFullRow(response, fullrow); response._partialRow = ''; offset = linebreak + 1; linebreak = chunk.indexOf('\n', offset); } response._partialRow += chunk.substring(offset); } function processBinaryChunk(response, chunk) { var stringDecoder = response._stringDecoder; var linebreak = chunk.indexOf(10); // newline while (linebreak > -1) { var fullrow = response._partialRow + readFinalStringChunk(stringDecoder, chunk.subarray(0, linebreak)); processFullRow(response, fullrow); response._partialRow = ''; chunk = chunk.subarray(linebreak + 1); linebreak = chunk.indexOf(10); // newline } response._partialRow += readPartialStringChunk(stringDecoder, chunk); } function createFromJSONCallback(response) { return function (key, value) { if (typeof value === 'string') { // We can't use .bind here because we need the "this" value. return parseModelString(response, this, value); } if (typeof value === 'object' && value !== null) { return parseModelTuple(response, value); } return value; }; } function createResponse$1(bundlerConfig) { // NOTE: CHECK THE COMPILER OUTPUT EACH TIME YOU CHANGE THIS. // It should be inlined to one object literal but minor changes can break it. var stringDecoder = createStringDecoder() ; var response = createResponse(bundlerConfig); response._partialRow = ''; { response._stringDecoder = stringDecoder; } // Don't inline this call because it causes closure to outline the call above. response._fromJSON = createFromJSONCallback(response); return response; } function startReadingFromStream(response, stream) { var reader = stream.getReader(); function progress(_ref) { var done = _ref.done, value = _ref.value; if (done) { close(response); return; } var buffer = value; processBinaryChunk(response, buffer); return reader.read().then(progress, error); } function error(e) { reportGlobalError(response, e); } reader.read().then(progress, error); } function createFromReadableStream(stream, options) { var response = createResponse$1(options && options.moduleMap ? options.moduleMap : null); startReadingFromStream(response, stream); return response; } function createFromFetch(promiseForResponse, options) { var response = createResponse$1(options && options.moduleMap ? options.moduleMap : null); promiseForResponse.then(function (r) { startReadingFromStream(response, r.body); }, function (e) { reportGlobalError(response, e); }); return response; } function createFromXHR(request, options) { var response = createResponse$1(options && options.moduleMap ? options.moduleMap : null); var processedLength = 0; function progress(e) { var chunk = request.responseText; processStringChunk(response, chunk, processedLength); processedLength = chunk.length; } function load(e) { progress(); close(response); } function error(e) { reportGlobalError(response, new TypeError('Network error')); } request.addEventListener('progress', progress); request.addEventListener('load', load); request.addEventListener('error', error); request.addEventListener('abort', error); request.addEventListener('timeout', error); return response; } exports.createFromFetch = createFromFetch; exports.createFromReadableStream = createFromReadableStream; exports.createFromXHR = createFromXHR; })(); }