mirror of
https://github.com/facebook/react.git
synced 2026-02-26 18:58:05 +00:00
This commit adds code to all React bundles to explicitly register the beginning and ending of the module. This is done by creating Error objects (which capture the file name, line number, and column number) and passing them explicitly to a DevTools hook (when present). Next, as the Scheduling Profiler logs metadata to the User Timing API, it prints these module ranges along with other metadata (like Lane values and profiler version number). Lastly, the Scheduling Profiler UI compares stack frames to these ranges when drawing the flame graph and dims or de-emphasizes frames that fall within an internal module. The net effect of this is that user code (and 3rd party code) stands out clearly in the flame graph while React internal modules are dimmed. Internal module ranges are completely optional. Older profiling samples, or ones recorded without the React DevTools extension installed, will simply not dim the internal frames.
395 lines
7.7 KiB
JavaScript
395 lines
7.7 KiB
JavaScript
'use strict';
|
|
|
|
const {resolve} = require('path');
|
|
const {readFileSync} = require('fs');
|
|
const {bundleTypes, moduleTypes} = require('./bundles');
|
|
const reactVersion = require('../../package.json').version;
|
|
|
|
const {
|
|
NODE_ES2015,
|
|
NODE_ESM,
|
|
UMD_DEV,
|
|
UMD_PROD,
|
|
UMD_PROFILING,
|
|
NODE_DEV,
|
|
NODE_PROD,
|
|
NODE_PROFILING,
|
|
FB_WWW_DEV,
|
|
FB_WWW_PROD,
|
|
FB_WWW_PROFILING,
|
|
RN_OSS_DEV,
|
|
RN_OSS_PROD,
|
|
RN_OSS_PROFILING,
|
|
RN_FB_DEV,
|
|
RN_FB_PROD,
|
|
RN_FB_PROFILING,
|
|
} = bundleTypes;
|
|
|
|
const {RECONCILER} = moduleTypes;
|
|
|
|
function registerInternalModuleStart(globalName) {
|
|
const path = resolve(
|
|
__dirname,
|
|
'..',
|
|
'..',
|
|
'packages/shared/registerInternalModuleStart.js'
|
|
);
|
|
return String(readFileSync(path)).trim();
|
|
}
|
|
|
|
function registerInternalModuleStop(globalName) {
|
|
const path = resolve(
|
|
__dirname,
|
|
'..',
|
|
'..',
|
|
'packages/shared/registerInternalModuleStop.js'
|
|
);
|
|
return String(readFileSync(path)).trim();
|
|
}
|
|
|
|
const license = ` * 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.`;
|
|
|
|
const wrappers = {
|
|
/***************** NODE_ES2015 *****************/
|
|
[NODE_ES2015](source, globalName, filename, moduleType) {
|
|
return `/** @license React v${reactVersion}
|
|
* ${filename}
|
|
*
|
|
${license}
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
${source}`;
|
|
},
|
|
|
|
/***************** NODE_ESM *****************/
|
|
[NODE_ESM](source, globalName, filename, moduleType) {
|
|
return `/** @license React v${reactVersion}
|
|
* ${filename}
|
|
*
|
|
${license}
|
|
*/
|
|
|
|
${source}`;
|
|
},
|
|
|
|
/***************** UMD_DEV *****************/
|
|
[UMD_DEV](source, globalName, filename, moduleType) {
|
|
return `/** @license React v${reactVersion}
|
|
* ${filename}
|
|
*
|
|
${license}
|
|
*/
|
|
${source}`;
|
|
},
|
|
|
|
/***************** UMD_PROD *****************/
|
|
[UMD_PROD](source, globalName, filename, moduleType) {
|
|
return `/** @license React v${reactVersion}
|
|
* ${filename}
|
|
*
|
|
${license}
|
|
*/
|
|
(function(){${source}})();`;
|
|
},
|
|
|
|
/***************** UMD_PROFILING *****************/
|
|
[UMD_PROFILING](source, globalName, filename, moduleType) {
|
|
return `/** @license React v${reactVersion}
|
|
* ${filename}
|
|
*
|
|
${license}
|
|
*/
|
|
(function(){${source}})();`;
|
|
},
|
|
|
|
/***************** NODE_DEV *****************/
|
|
[NODE_DEV](source, globalName, filename, moduleType) {
|
|
return `/** @license React v${reactVersion}
|
|
* ${filename}
|
|
*
|
|
${license}
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
if (process.env.NODE_ENV !== "production") {
|
|
(function() {
|
|
${source}
|
|
})();
|
|
}`;
|
|
},
|
|
|
|
/***************** NODE_PROD *****************/
|
|
[NODE_PROD](source, globalName, filename, moduleType) {
|
|
return `/** @license React v${reactVersion}
|
|
* ${filename}
|
|
*
|
|
${license}
|
|
*/
|
|
${source}`;
|
|
},
|
|
|
|
/***************** NODE_PROFILING *****************/
|
|
[NODE_PROFILING](source, globalName, filename, moduleType) {
|
|
return `/** @license React v${reactVersion}
|
|
* ${filename}
|
|
*
|
|
${license}
|
|
*/
|
|
${source}`;
|
|
},
|
|
|
|
/****************** FB_WWW_DEV ******************/
|
|
[FB_WWW_DEV](source, globalName, filename, moduleType) {
|
|
return `/**
|
|
${license}
|
|
*
|
|
* @noflow
|
|
* @nolint
|
|
* @preventMunge
|
|
* @preserve-invariant-messages
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
if (__DEV__) {
|
|
(function() {
|
|
${source}
|
|
})();
|
|
}`;
|
|
},
|
|
|
|
/****************** FB_WWW_PROD ******************/
|
|
[FB_WWW_PROD](source, globalName, filename, moduleType) {
|
|
return `/**
|
|
${license}
|
|
*
|
|
* @noflow
|
|
* @nolint
|
|
* @preventMunge
|
|
* @preserve-invariant-messages
|
|
*/
|
|
|
|
${source}`;
|
|
},
|
|
|
|
/****************** FB_WWW_PROFILING ******************/
|
|
[FB_WWW_PROFILING](source, globalName, filename, moduleType) {
|
|
return `/**
|
|
${license}
|
|
*
|
|
* @noflow
|
|
* @nolint
|
|
* @preventMunge
|
|
* @preserve-invariant-messages
|
|
*/
|
|
|
|
${source}`;
|
|
},
|
|
|
|
/****************** RN_OSS_DEV ******************/
|
|
[RN_OSS_DEV](source, globalName, filename, moduleType) {
|
|
return `/**
|
|
${license}
|
|
*
|
|
* @noflow
|
|
* @nolint
|
|
* @providesModule ${globalName}-dev
|
|
* @preventMunge
|
|
* ${'@gen' + 'erated'}
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
if (__DEV__) {
|
|
(function() {
|
|
${source}
|
|
})();
|
|
}`;
|
|
},
|
|
|
|
/****************** RN_OSS_PROD ******************/
|
|
[RN_OSS_PROD](source, globalName, filename, moduleType) {
|
|
return `/**
|
|
${license}
|
|
*
|
|
* @noflow
|
|
* @nolint
|
|
* @providesModule ${globalName}-prod
|
|
* @preventMunge
|
|
* ${'@gen' + 'erated'}
|
|
*/
|
|
|
|
${source}`;
|
|
},
|
|
|
|
/****************** RN_OSS_PROFILING ******************/
|
|
[RN_OSS_PROFILING](source, globalName, filename, moduleType) {
|
|
return `/**
|
|
${license}
|
|
*
|
|
* @noflow
|
|
* @nolint
|
|
* @providesModule ${globalName}-profiling
|
|
* @preventMunge
|
|
* ${'@gen' + 'erated'}
|
|
*/
|
|
|
|
${source}`;
|
|
},
|
|
|
|
/****************** RN_FB_DEV ******************/
|
|
[RN_FB_DEV](source, globalName, filename, moduleType) {
|
|
return `/**
|
|
${license}
|
|
*
|
|
* @noflow
|
|
* @nolint
|
|
* @preventMunge
|
|
* ${'@gen' + 'erated'}
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
if (__DEV__) {
|
|
(function() {
|
|
${source}
|
|
})();
|
|
}`;
|
|
},
|
|
|
|
/****************** RN_FB_PROD ******************/
|
|
[RN_FB_PROD](source, globalName, filename, moduleType) {
|
|
return `/**
|
|
${license}
|
|
*
|
|
* @noflow
|
|
* @nolint
|
|
* @preventMunge
|
|
* ${'@gen' + 'erated'}
|
|
*/
|
|
|
|
${source}`;
|
|
},
|
|
|
|
/****************** RN_FB_PROFILING ******************/
|
|
[RN_FB_PROFILING](source, globalName, filename, moduleType) {
|
|
return `/**
|
|
${license}
|
|
*
|
|
* @noflow
|
|
* @nolint
|
|
* @preventMunge
|
|
* ${'@gen' + 'erated'}
|
|
*/
|
|
|
|
${source}`;
|
|
},
|
|
};
|
|
|
|
const reconcilerWrappers = {
|
|
/***************** NODE_DEV (reconciler only) *****************/
|
|
[NODE_DEV](source, globalName, filename, moduleType) {
|
|
return `/** @license React v${reactVersion}
|
|
* ${filename}
|
|
*
|
|
${license}
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
if (process.env.NODE_ENV !== "production") {
|
|
module.exports = function $$$reconciler($$$hostConfig) {
|
|
var exports = {};
|
|
${source}
|
|
return exports;
|
|
};
|
|
}`;
|
|
},
|
|
|
|
/***************** NODE_PROD (reconciler only) *****************/
|
|
[NODE_PROD](source, globalName, filename, moduleType) {
|
|
return `/** @license React v${reactVersion}
|
|
* ${filename}
|
|
*
|
|
${license}
|
|
*/
|
|
module.exports = function $$$reconciler($$$hostConfig) {
|
|
var exports = {};
|
|
${source}
|
|
return exports;
|
|
};`;
|
|
},
|
|
|
|
/***************** NODE_PROFILING (reconciler only) *****************/
|
|
[NODE_PROFILING](source, globalName, filename, moduleType) {
|
|
return `/** @license React v${reactVersion}
|
|
* ${filename}
|
|
*
|
|
${license}
|
|
*/
|
|
module.exports = function $$$reconciler($$$hostConfig) {
|
|
var exports = {};
|
|
${source}
|
|
return exports;
|
|
};`;
|
|
},
|
|
};
|
|
|
|
function wrapBundle(
|
|
source,
|
|
bundleType,
|
|
globalName,
|
|
filename,
|
|
moduleType,
|
|
wrapWithModuleBoundaries
|
|
) {
|
|
if (wrapWithModuleBoundaries) {
|
|
switch (bundleType) {
|
|
case NODE_DEV:
|
|
case NODE_PROFILING:
|
|
case FB_WWW_DEV:
|
|
case FB_WWW_PROFILING:
|
|
case RN_OSS_DEV:
|
|
case RN_OSS_PROFILING:
|
|
case RN_FB_DEV:
|
|
case RN_FB_PROFILING:
|
|
// Certain DEV and Profiling bundles should self-register their own module boundaries with DevTools.
|
|
// This allows the Scheduling Profiler to de-emphasize (dim) internal stack frames.
|
|
source = `
|
|
${registerInternalModuleStart(globalName)}
|
|
${source}
|
|
${registerInternalModuleStop(globalName)}
|
|
`;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (moduleType === RECONCILER) {
|
|
// Standalone reconciler is only used by third-party renderers.
|
|
// It is handled separately.
|
|
const wrapper = reconcilerWrappers[bundleType];
|
|
if (typeof wrapper !== 'function') {
|
|
throw new Error(
|
|
`Unsupported build type for the reconciler package: ${bundleType}.`
|
|
);
|
|
}
|
|
return wrapper(source, globalName, filename, moduleType);
|
|
}
|
|
// All the other packages.
|
|
const wrapper = wrappers[bundleType];
|
|
if (typeof wrapper !== 'function') {
|
|
throw new Error(`Unsupported build type: ${bundleType}.`);
|
|
}
|
|
return wrapper(source, globalName, filename, moduleType);
|
|
}
|
|
|
|
module.exports = {
|
|
wrapBundle,
|
|
};
|