@lwc/engine-core 8.0.0-alpha.1 → 8.1.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/advanced-mutation-tracker.d.ts +7 -0
- package/dist/framework/advanced-instrumentation.d.ts +2 -0
- package/dist/framework/advanced-mutation-tracker.d.ts +7 -0
- package/dist/framework/mutation-logger.d.ts +34 -0
- package/dist/framework/profiler.d.ts +5 -2
- package/dist/framework/profiling/advanced-instrumentation.d.ts +2 -0
- package/dist/framework/profiling/advanced-mutation-tracker.d.ts +7 -0
- package/dist/index.cjs.js +371 -125
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.js +372 -126
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.cjs.js
CHANGED
|
@@ -180,7 +180,208 @@ function logWarnOnce(message, vm) {
|
|
|
180
180
|
}
|
|
181
181
|
|
|
182
182
|
/*
|
|
183
|
-
* Copyright (c)
|
|
183
|
+
* Copyright (c) 2018, salesforce.com, inc.
|
|
184
|
+
* All rights reserved.
|
|
185
|
+
* SPDX-License-Identifier: MIT
|
|
186
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
|
|
187
|
+
*/
|
|
188
|
+
let nextTickCallbackQueue = [];
|
|
189
|
+
const SPACE_CHAR = 32;
|
|
190
|
+
const EmptyObject = shared.seal(shared.create(null));
|
|
191
|
+
const EmptyArray = shared.seal([]);
|
|
192
|
+
function flushCallbackQueue() {
|
|
193
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
194
|
+
if (nextTickCallbackQueue.length === 0) {
|
|
195
|
+
throw new Error(`Internal Error: If callbackQueue is scheduled, it is because there must be at least one callback on this pending queue.`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
const callbacks = nextTickCallbackQueue;
|
|
199
|
+
nextTickCallbackQueue = []; // reset to a new queue
|
|
200
|
+
for (let i = 0, len = callbacks.length; i < len; i += 1) {
|
|
201
|
+
callbacks[i]();
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
function addCallbackToNextTick(callback) {
|
|
205
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
206
|
+
if (!shared.isFunction(callback)) {
|
|
207
|
+
throw new Error(`Internal Error: addCallbackToNextTick() can only accept a function callback`);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
if (nextTickCallbackQueue.length === 0) {
|
|
211
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
212
|
+
Promise.resolve().then(flushCallbackQueue);
|
|
213
|
+
}
|
|
214
|
+
shared.ArrayPush.call(nextTickCallbackQueue, callback);
|
|
215
|
+
}
|
|
216
|
+
function guid() {
|
|
217
|
+
function s4() {
|
|
218
|
+
return Math.floor((1 + Math.random()) * 0x10000)
|
|
219
|
+
.toString(16)
|
|
220
|
+
.substring(1);
|
|
221
|
+
}
|
|
222
|
+
return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
|
|
223
|
+
}
|
|
224
|
+
// Borrowed from Vue template compiler.
|
|
225
|
+
// https://github.com/vuejs/vue/blob/531371b818b0e31a989a06df43789728f23dc4e8/src/platforms/web/util/style.js#L5-L16
|
|
226
|
+
const DECLARATION_DELIMITER = /;(?![^(]*\))/g;
|
|
227
|
+
const PROPERTY_DELIMITER = /:(.+)/;
|
|
228
|
+
function parseStyleText(cssText) {
|
|
229
|
+
const styleMap = {};
|
|
230
|
+
const declarations = cssText.split(DECLARATION_DELIMITER);
|
|
231
|
+
for (const declaration of declarations) {
|
|
232
|
+
if (declaration) {
|
|
233
|
+
const [prop, value] = declaration.split(PROPERTY_DELIMITER);
|
|
234
|
+
if (prop !== undefined && value !== undefined) {
|
|
235
|
+
styleMap[prop.trim()] = value.trim();
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return styleMap;
|
|
240
|
+
}
|
|
241
|
+
// Make a shallow copy of an object but omit the given key
|
|
242
|
+
function cloneAndOmitKey(object, keyToOmit) {
|
|
243
|
+
const result = {};
|
|
244
|
+
for (const key of shared.keys(object)) {
|
|
245
|
+
if (key !== keyToOmit) {
|
|
246
|
+
result[key] = object[key];
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return result;
|
|
250
|
+
}
|
|
251
|
+
function flattenStylesheets(stylesheets) {
|
|
252
|
+
const list = [];
|
|
253
|
+
for (const stylesheet of stylesheets) {
|
|
254
|
+
if (!shared.isArray(stylesheet)) {
|
|
255
|
+
list.push(stylesheet);
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
list.push(...flattenStylesheets(stylesheet));
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return list;
|
|
262
|
+
}
|
|
263
|
+
// Throw an error if we're running in prod mode. Ensures code is truly removed from prod mode.
|
|
264
|
+
function assertNotProd() {
|
|
265
|
+
/* istanbul ignore if */
|
|
266
|
+
if (process.env.NODE_ENV === 'production') {
|
|
267
|
+
// this method should never leak to prod
|
|
268
|
+
throw new ReferenceError();
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
function shouldBeFormAssociated(Ctor) {
|
|
272
|
+
const ctorFormAssociated = Boolean(Ctor.formAssociated);
|
|
273
|
+
const apiVersion = getComponentAPIVersion(Ctor);
|
|
274
|
+
const apiFeatureEnabled = shared.isAPIFeatureEnabled(7 /* APIFeature.ENABLE_ELEMENT_INTERNALS_AND_FACE */, apiVersion);
|
|
275
|
+
if (process.env.NODE_ENV !== 'production' && ctorFormAssociated && !apiFeatureEnabled) {
|
|
276
|
+
const tagName = getComponentRegisteredName(Ctor);
|
|
277
|
+
logWarnOnce(`Component <${tagName}> set static formAssociated to true, but form ` +
|
|
278
|
+
`association is not enabled because the API version is ${apiVersion}. To enable form association, ` +
|
|
279
|
+
`update the LWC component API version to 61 or above. https://lwc.dev/guide/versioning`);
|
|
280
|
+
}
|
|
281
|
+
return ctorFormAssociated && apiFeatureEnabled;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/*
|
|
285
|
+
* Copyright (c) 2024, Salesforce, Inc.
|
|
286
|
+
* All rights reserved.
|
|
287
|
+
* SPDX-License-Identifier: MIT
|
|
288
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
|
|
289
|
+
*/
|
|
290
|
+
//
|
|
291
|
+
// Do additional mutation tracking for DevTools performance profiling, in dev mode only.
|
|
292
|
+
//
|
|
293
|
+
const reactiveObserversToVMs = new WeakMap();
|
|
294
|
+
const targetsToPropertyKeys = new WeakMap();
|
|
295
|
+
let mutationLogs = [];
|
|
296
|
+
/**
|
|
297
|
+
* Flush all the logs we've written so far and return the current logs.
|
|
298
|
+
*/
|
|
299
|
+
function getAndFlushMutationLogs() {
|
|
300
|
+
assertNotProd();
|
|
301
|
+
const result = mutationLogs;
|
|
302
|
+
mutationLogs = [];
|
|
303
|
+
return result;
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Log a new mutation for this reactive observer.
|
|
307
|
+
* @param reactiveObserver - relevant ReactiveObserver
|
|
308
|
+
* @param target - target object that is being observed
|
|
309
|
+
* @param key - key (property) that was mutated
|
|
310
|
+
*/
|
|
311
|
+
function logMutation(reactiveObserver, target, key) {
|
|
312
|
+
assertNotProd();
|
|
313
|
+
const parentKey = targetsToPropertyKeys.get(target);
|
|
314
|
+
const vm = reactiveObserversToVMs.get(reactiveObserver);
|
|
315
|
+
/* istanbul ignore if */
|
|
316
|
+
if (shared.isUndefined(vm)) {
|
|
317
|
+
// VM should only be undefined in Vitest tests, where a reactive observer is not always associated with a VM
|
|
318
|
+
// because the unit tests just create Reactive Observers on-the-fly.
|
|
319
|
+
// Note we could explicitly target Vitest with `process.env.NODE_ENV === 'test'`, but then that would also
|
|
320
|
+
// affect our downstream consumers' Jest/Vitest tests, and we don't want to throw an error just for a logger.
|
|
321
|
+
if (process.env.NODE_ENV === 'test-karma-lwc') {
|
|
322
|
+
throw new Error('The VM should always be defined except possibly in unit tests');
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
const stringKey = shared.toString(key);
|
|
327
|
+
let prop;
|
|
328
|
+
if (shared.isUndefined(parentKey)) {
|
|
329
|
+
prop = stringKey;
|
|
330
|
+
}
|
|
331
|
+
else if (/^\w+$/.test(stringKey)) {
|
|
332
|
+
// Human-readable prop like `items[0].name` on a deep object/array
|
|
333
|
+
prop = `${shared.toString(parentKey)}.${stringKey}`;
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
// e.g. `obj["prop with spaces"]`
|
|
337
|
+
prop = `${shared.toString(parentKey)}[${JSON.stringify(stringKey)}]`;
|
|
338
|
+
}
|
|
339
|
+
shared.ArrayPush.call(mutationLogs, { vm, prop });
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Flush logs associated with a given VM.
|
|
344
|
+
* @param vm - given VM
|
|
345
|
+
*/
|
|
346
|
+
function flushMutationLogsForVM(vm) {
|
|
347
|
+
assertNotProd();
|
|
348
|
+
mutationLogs = shared.ArrayFilter.call(mutationLogs, (log) => log.vm !== vm);
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Mark this ReactiveObserver as related to this VM. This is only needed for mutation tracking in dev mode.
|
|
352
|
+
* @param reactiveObserver
|
|
353
|
+
* @param vm
|
|
354
|
+
*/
|
|
355
|
+
function associateReactiveObserverWithVM(reactiveObserver, vm) {
|
|
356
|
+
assertNotProd();
|
|
357
|
+
reactiveObserversToVMs.set(reactiveObserver, vm);
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Deeply track all objects in a target and associate with a given key.
|
|
361
|
+
* @param key - key associated with the object in the component
|
|
362
|
+
* @param target - tracked target object
|
|
363
|
+
*/
|
|
364
|
+
function trackTargetForMutationLogging(key, target) {
|
|
365
|
+
assertNotProd();
|
|
366
|
+
if (shared.isObject(target) && !shared.isNull(target)) {
|
|
367
|
+
// only track non-primitives; others are invalid as WeakMap keys
|
|
368
|
+
targetsToPropertyKeys.set(target, key);
|
|
369
|
+
// Deeply traverse arrays and objects to track every object within
|
|
370
|
+
if (shared.isArray(target)) {
|
|
371
|
+
for (let i = 0; i < target.length; i++) {
|
|
372
|
+
trackTargetForMutationLogging(`${shared.toString(key)}[${i}]`, target[i]);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
else {
|
|
376
|
+
for (const prop of shared.keys(target)) {
|
|
377
|
+
trackTargetForMutationLogging(`${shared.toString(key)}.${prop}`, target[prop]);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/*
|
|
384
|
+
* Copyright (c) 2024, Salesforce, Inc.
|
|
184
385
|
* All rights reserved.
|
|
185
386
|
* SPDX-License-Identifier: MIT
|
|
186
387
|
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
|
|
@@ -203,6 +404,9 @@ function valueMutated(target, key) {
|
|
|
203
404
|
if (!shared.isUndefined(reactiveObservers)) {
|
|
204
405
|
for (let i = 0, len = reactiveObservers.length; i < len; i += 1) {
|
|
205
406
|
const ro = reactiveObservers[i];
|
|
407
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
408
|
+
logMutation(ro, target, key);
|
|
409
|
+
}
|
|
206
410
|
ro.notify();
|
|
207
411
|
}
|
|
208
412
|
}
|
|
@@ -362,7 +566,7 @@ class SignalTracker {
|
|
|
362
566
|
}
|
|
363
567
|
|
|
364
568
|
/*
|
|
365
|
-
* Copyright (c)
|
|
569
|
+
* Copyright (c) 2024, Salesforce, Inc.
|
|
366
570
|
* All rights reserved.
|
|
367
571
|
* SPDX-License-Identifier: MIT
|
|
368
572
|
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
|
|
@@ -407,108 +611,6 @@ function createReactiveObserver(callback) {
|
|
|
407
611
|
return process.env.IS_BROWSER ? new ReactiveObserver(callback) : DUMMY_REACTIVE_OBSERVER;
|
|
408
612
|
}
|
|
409
613
|
|
|
410
|
-
/*
|
|
411
|
-
* Copyright (c) 2018, salesforce.com, inc.
|
|
412
|
-
* All rights reserved.
|
|
413
|
-
* SPDX-License-Identifier: MIT
|
|
414
|
-
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
|
|
415
|
-
*/
|
|
416
|
-
let nextTickCallbackQueue = [];
|
|
417
|
-
const SPACE_CHAR = 32;
|
|
418
|
-
const EmptyObject = shared.seal(shared.create(null));
|
|
419
|
-
const EmptyArray = shared.seal([]);
|
|
420
|
-
function flushCallbackQueue() {
|
|
421
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
422
|
-
if (nextTickCallbackQueue.length === 0) {
|
|
423
|
-
throw new Error(`Internal Error: If callbackQueue is scheduled, it is because there must be at least one callback on this pending queue.`);
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
const callbacks = nextTickCallbackQueue;
|
|
427
|
-
nextTickCallbackQueue = []; // reset to a new queue
|
|
428
|
-
for (let i = 0, len = callbacks.length; i < len; i += 1) {
|
|
429
|
-
callbacks[i]();
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
function addCallbackToNextTick(callback) {
|
|
433
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
434
|
-
if (!shared.isFunction(callback)) {
|
|
435
|
-
throw new Error(`Internal Error: addCallbackToNextTick() can only accept a function callback`);
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
if (nextTickCallbackQueue.length === 0) {
|
|
439
|
-
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
440
|
-
Promise.resolve().then(flushCallbackQueue);
|
|
441
|
-
}
|
|
442
|
-
shared.ArrayPush.call(nextTickCallbackQueue, callback);
|
|
443
|
-
}
|
|
444
|
-
function guid() {
|
|
445
|
-
function s4() {
|
|
446
|
-
return Math.floor((1 + Math.random()) * 0x10000)
|
|
447
|
-
.toString(16)
|
|
448
|
-
.substring(1);
|
|
449
|
-
}
|
|
450
|
-
return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
|
|
451
|
-
}
|
|
452
|
-
// Borrowed from Vue template compiler.
|
|
453
|
-
// https://github.com/vuejs/vue/blob/531371b818b0e31a989a06df43789728f23dc4e8/src/platforms/web/util/style.js#L5-L16
|
|
454
|
-
const DECLARATION_DELIMITER = /;(?![^(]*\))/g;
|
|
455
|
-
const PROPERTY_DELIMITER = /:(.+)/;
|
|
456
|
-
function parseStyleText(cssText) {
|
|
457
|
-
const styleMap = {};
|
|
458
|
-
const declarations = cssText.split(DECLARATION_DELIMITER);
|
|
459
|
-
for (const declaration of declarations) {
|
|
460
|
-
if (declaration) {
|
|
461
|
-
const [prop, value] = declaration.split(PROPERTY_DELIMITER);
|
|
462
|
-
if (prop !== undefined && value !== undefined) {
|
|
463
|
-
styleMap[prop.trim()] = value.trim();
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
return styleMap;
|
|
468
|
-
}
|
|
469
|
-
// Make a shallow copy of an object but omit the given key
|
|
470
|
-
function cloneAndOmitKey(object, keyToOmit) {
|
|
471
|
-
const result = {};
|
|
472
|
-
for (const key of shared.keys(object)) {
|
|
473
|
-
if (key !== keyToOmit) {
|
|
474
|
-
result[key] = object[key];
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
return result;
|
|
478
|
-
}
|
|
479
|
-
function flattenStylesheets(stylesheets) {
|
|
480
|
-
const list = [];
|
|
481
|
-
for (const stylesheet of stylesheets) {
|
|
482
|
-
if (!shared.isArray(stylesheet)) {
|
|
483
|
-
list.push(stylesheet);
|
|
484
|
-
}
|
|
485
|
-
else {
|
|
486
|
-
list.push(...flattenStylesheets(stylesheet));
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
return list;
|
|
490
|
-
}
|
|
491
|
-
// Throw an error if we're running in prod mode. Ensures code is truly removed from prod mode.
|
|
492
|
-
function assertNotProd() {
|
|
493
|
-
/* istanbul ignore if */
|
|
494
|
-
if (process.env.NODE_ENV === 'production') {
|
|
495
|
-
// this method should never leak to prod
|
|
496
|
-
throw new ReferenceError();
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
function shouldBeFormAssociated(Ctor) {
|
|
500
|
-
const ctorFormAssociated = Boolean(Ctor.formAssociated);
|
|
501
|
-
const apiVersion = getComponentAPIVersion(Ctor);
|
|
502
|
-
const apiFeatureEnabled = shared.isAPIFeatureEnabled(7 /* APIFeature.ENABLE_ELEMENT_INTERNALS_AND_FACE */, apiVersion);
|
|
503
|
-
if (process.env.NODE_ENV !== 'production' && ctorFormAssociated && !apiFeatureEnabled) {
|
|
504
|
-
const tagName = getComponentRegisteredName(Ctor);
|
|
505
|
-
logWarnOnce(`Component <${tagName}> set static formAssociated to true, but form ` +
|
|
506
|
-
`association is not enabled because the API version is ${apiVersion}. To enable form association, ` +
|
|
507
|
-
`update the LWC component API version to 61 or above. https://lwc.dev/guide/versioning`);
|
|
508
|
-
}
|
|
509
|
-
return ctorFormAssociated && apiFeatureEnabled;
|
|
510
|
-
}
|
|
511
|
-
|
|
512
614
|
/*
|
|
513
615
|
* Copyright (c) 2020, salesforce.com, inc.
|
|
514
616
|
* All rights reserved.
|
|
@@ -2121,6 +2223,9 @@ function createConfigWatcher(component, configCallback, callbackWhenConfigIsRead
|
|
|
2121
2223
|
});
|
|
2122
2224
|
}
|
|
2123
2225
|
});
|
|
2226
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
2227
|
+
associateReactiveObserverWithVM(ro, getAssociatedVM(component));
|
|
2228
|
+
}
|
|
2124
2229
|
const computeConfigAndUpdate = () => {
|
|
2125
2230
|
let config;
|
|
2126
2231
|
ro.observe(() => (config = configCallback(component)));
|
|
@@ -2409,6 +2514,9 @@ function internalTrackDecorator(key) {
|
|
|
2409
2514
|
}
|
|
2410
2515
|
}
|
|
2411
2516
|
const reactiveOrAnyValue = getReactiveProxy(newValue);
|
|
2517
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
2518
|
+
trackTargetForMutationLogging(key, newValue);
|
|
2519
|
+
}
|
|
2412
2520
|
updateComponentValue(vm, key, reactiveOrAnyValue);
|
|
2413
2521
|
},
|
|
2414
2522
|
enumerable: true,
|
|
@@ -5694,7 +5802,7 @@ const api = shared.freeze({
|
|
|
5694
5802
|
});
|
|
5695
5803
|
|
|
5696
5804
|
/*
|
|
5697
|
-
* Copyright (c)
|
|
5805
|
+
* Copyright (c) 2024, Salesforce, Inc.
|
|
5698
5806
|
* All rights reserved.
|
|
5699
5807
|
* SPDX-License-Identifier: MIT
|
|
5700
5808
|
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
|
|
@@ -5710,6 +5818,26 @@ const operationIdNameMapping = [
|
|
|
5710
5818
|
'lwc-hydrate',
|
|
5711
5819
|
'lwc-rehydrate',
|
|
5712
5820
|
];
|
|
5821
|
+
const operationTooltipMapping = [
|
|
5822
|
+
// constructor
|
|
5823
|
+
'component constructor()',
|
|
5824
|
+
// render
|
|
5825
|
+
'component render() and virtual DOM rendered',
|
|
5826
|
+
// patch
|
|
5827
|
+
'component DOM rendered',
|
|
5828
|
+
// connectedCallback
|
|
5829
|
+
'component connectedCallback()',
|
|
5830
|
+
// renderedCallback
|
|
5831
|
+
'component renderedCallback()',
|
|
5832
|
+
// disconnectedCallback
|
|
5833
|
+
'component disconnectedCallback()',
|
|
5834
|
+
// errorCallback
|
|
5835
|
+
'component errorCallback()',
|
|
5836
|
+
// lwc-hydrate
|
|
5837
|
+
'component first rendered',
|
|
5838
|
+
// lwc-rehydrate
|
|
5839
|
+
'component re-rendered',
|
|
5840
|
+
];
|
|
5713
5841
|
// Even if all the browser the engine supports implements the UserTiming API, we need to guard the measure APIs.
|
|
5714
5842
|
// JSDom (used in Jest) for example doesn't implement the UserTiming APIs.
|
|
5715
5843
|
const isUserTimingSupported = typeof performance !== 'undefined' &&
|
|
@@ -5724,8 +5852,17 @@ const start = !isUserTimingSupported
|
|
|
5724
5852
|
};
|
|
5725
5853
|
const end = !isUserTimingSupported
|
|
5726
5854
|
? shared.noop
|
|
5727
|
-
: (measureName, markName) => {
|
|
5728
|
-
performance.measure(measureName,
|
|
5855
|
+
: (measureName, markName, devtools) => {
|
|
5856
|
+
performance.measure(measureName, {
|
|
5857
|
+
start: markName,
|
|
5858
|
+
detail: {
|
|
5859
|
+
devtools: {
|
|
5860
|
+
dataType: 'track-entry',
|
|
5861
|
+
track: '⚡️ Lightning Web Components',
|
|
5862
|
+
...devtools,
|
|
5863
|
+
},
|
|
5864
|
+
},
|
|
5865
|
+
});
|
|
5729
5866
|
// Clear the created marks and measure to avoid filling the performance entries buffer.
|
|
5730
5867
|
// Note: Even if the entries get deleted, existing PerformanceObservers preserve a copy of those entries.
|
|
5731
5868
|
performance.clearMarks(markName);
|
|
@@ -5742,6 +5879,66 @@ function getMarkName(opId, vm) {
|
|
|
5742
5879
|
// the right measures for components that are recursive.
|
|
5743
5880
|
return `${getMeasureName(opId, vm)} - ${vm.idx}`;
|
|
5744
5881
|
}
|
|
5882
|
+
function getProperties(vm) {
|
|
5883
|
+
return [
|
|
5884
|
+
['Tag Name', vm.tagName],
|
|
5885
|
+
['Component ID', String(vm.idx)],
|
|
5886
|
+
['Render Mode', vm.renderMode === 0 /* RenderMode.Light */ ? 'light DOM' : 'shadow DOM'],
|
|
5887
|
+
['Shadow Mode', vm.shadowMode === 0 /* ShadowMode.Native */ ? 'native' : 'synthetic'],
|
|
5888
|
+
];
|
|
5889
|
+
}
|
|
5890
|
+
// Create a list of tag names to the properties that were mutated, to help answer the question of
|
|
5891
|
+
// "why did this component re-render?"
|
|
5892
|
+
function getMutationProperties(mutationLogs) {
|
|
5893
|
+
// `mutationLogs` should never have length 0, but bail out if it does for whatever reason
|
|
5894
|
+
if (shared.isUndefined(mutationLogs)) {
|
|
5895
|
+
return EmptyArray;
|
|
5896
|
+
}
|
|
5897
|
+
if (!mutationLogs.length) {
|
|
5898
|
+
// Currently this only occurs for experimental signals, because those mutations are not triggered by accessors
|
|
5899
|
+
// TODO [#4546]: support signals in mutation logging
|
|
5900
|
+
return EmptyArray;
|
|
5901
|
+
}
|
|
5902
|
+
// Keep track of unique IDs per tag name so we can just report a raw count at the end, e.g.
|
|
5903
|
+
// `<x-foo> (x2)` to indicate that two instances of `<x-foo>` were rendered.
|
|
5904
|
+
const tagNamesToIdsAndProps = new Map();
|
|
5905
|
+
for (const { vm: { tagName, idx }, prop, } of mutationLogs) {
|
|
5906
|
+
let idsAndProps = tagNamesToIdsAndProps.get(tagName);
|
|
5907
|
+
if (shared.isUndefined(idsAndProps)) {
|
|
5908
|
+
idsAndProps = { ids: new Set(), keys: new Set() };
|
|
5909
|
+
tagNamesToIdsAndProps.set(tagName, idsAndProps);
|
|
5910
|
+
}
|
|
5911
|
+
idsAndProps.ids.add(idx);
|
|
5912
|
+
idsAndProps.keys.add(prop);
|
|
5913
|
+
}
|
|
5914
|
+
// Sort by tag name
|
|
5915
|
+
const entries = shared.ArraySort.call([...tagNamesToIdsAndProps], (a, b) => a[0].localeCompare(b[0]));
|
|
5916
|
+
const tagNames = shared.ArrayMap.call(entries, (item) => item[0]);
|
|
5917
|
+
// Show e.g. `<x-foo>` for one instance, or `<x-foo> (x2)` for two instances. (\u00D7 is multiplication symbol)
|
|
5918
|
+
const tagNamesToDisplayTagNames = new Map();
|
|
5919
|
+
for (const tagName of tagNames) {
|
|
5920
|
+
const { ids } = tagNamesToIdsAndProps.get(tagName);
|
|
5921
|
+
const displayTagName = `<${tagName}>${ids.size > 1 ? ` (\u00D7${ids.size})` : ''}`;
|
|
5922
|
+
tagNamesToDisplayTagNames.set(tagName, displayTagName);
|
|
5923
|
+
}
|
|
5924
|
+
// Summary row
|
|
5925
|
+
const usePlural = tagNames.length > 1 || tagNamesToIdsAndProps.get(tagNames[0]).ids.size > 1;
|
|
5926
|
+
const result = [
|
|
5927
|
+
[
|
|
5928
|
+
`Re-rendered Component${usePlural ? 's' : ''}`,
|
|
5929
|
+
shared.ArrayJoin.call(shared.ArrayMap.call(tagNames, (_) => tagNamesToDisplayTagNames.get(_)), ', '),
|
|
5930
|
+
],
|
|
5931
|
+
];
|
|
5932
|
+
// Detail rows
|
|
5933
|
+
for (const [prettyTagName, { keys }] of entries) {
|
|
5934
|
+
const displayTagName = tagNamesToDisplayTagNames.get(prettyTagName);
|
|
5935
|
+
shared.ArrayPush.call(result, [displayTagName, shared.ArrayJoin.call(shared.ArraySort.call([...keys]), ', ')]);
|
|
5936
|
+
}
|
|
5937
|
+
return result;
|
|
5938
|
+
}
|
|
5939
|
+
function getTooltipText(measureName, opId) {
|
|
5940
|
+
return `${measureName} - ${operationTooltipMapping[opId]}`;
|
|
5941
|
+
}
|
|
5745
5942
|
/** Indicates if operations should be logged via the User Timing API. */
|
|
5746
5943
|
const isMeasureEnabled = process.env.NODE_ENV !== 'production';
|
|
5747
5944
|
/** Indicates if operations should be logged by the profiler. */
|
|
@@ -5779,30 +5976,61 @@ function logOperationEnd(opId, vm) {
|
|
|
5779
5976
|
if (isMeasureEnabled) {
|
|
5780
5977
|
const markName = getMarkName(opId, vm);
|
|
5781
5978
|
const measureName = getMeasureName(opId, vm);
|
|
5782
|
-
end(measureName, markName
|
|
5979
|
+
end(measureName, markName, {
|
|
5980
|
+
color: opId === 1 /* OperationId.Render */ ? 'primary' : 'secondary',
|
|
5981
|
+
tooltipText: getTooltipText(measureName, opId),
|
|
5982
|
+
properties: getProperties(vm),
|
|
5983
|
+
});
|
|
5783
5984
|
}
|
|
5784
5985
|
if (isProfilerEnabled) {
|
|
5785
5986
|
currentDispatcher(opId, 1 /* Phase.Stop */, vm.tagName, vm.idx, vm.renderMode, vm.shadowMode);
|
|
5786
5987
|
}
|
|
5787
5988
|
}
|
|
5788
|
-
function logGlobalOperationStart(opId
|
|
5989
|
+
function logGlobalOperationStart(opId) {
|
|
5789
5990
|
if (isMeasureEnabled) {
|
|
5790
|
-
const
|
|
5791
|
-
|
|
5991
|
+
const markName = getOperationName(opId);
|
|
5992
|
+
start(markName);
|
|
5993
|
+
}
|
|
5994
|
+
if (isProfilerEnabled) {
|
|
5995
|
+
currentDispatcher(opId, 0 /* Phase.Start */);
|
|
5996
|
+
}
|
|
5997
|
+
}
|
|
5998
|
+
function logGlobalOperationStartWithVM(opId, vm) {
|
|
5999
|
+
if (isMeasureEnabled) {
|
|
6000
|
+
const markName = getMarkName(opId, vm);
|
|
5792
6001
|
start(markName);
|
|
5793
6002
|
}
|
|
5794
6003
|
if (isProfilerEnabled) {
|
|
5795
|
-
currentDispatcher(opId, 0 /* Phase.Start */, vm
|
|
6004
|
+
currentDispatcher(opId, 0 /* Phase.Start */, vm.tagName, vm.idx, vm.renderMode, vm.shadowMode);
|
|
6005
|
+
}
|
|
6006
|
+
}
|
|
6007
|
+
function logGlobalOperationEnd(opId, mutationLogs) {
|
|
6008
|
+
if (isMeasureEnabled) {
|
|
6009
|
+
const opName = getOperationName(opId);
|
|
6010
|
+
const markName = opName;
|
|
6011
|
+
end(opName, markName, {
|
|
6012
|
+
// not really an error, but we want to draw attention to re-renders since folks may want to debug it
|
|
6013
|
+
color: 'error',
|
|
6014
|
+
tooltipText: getTooltipText(opName, opId),
|
|
6015
|
+
properties: getMutationProperties(mutationLogs),
|
|
6016
|
+
});
|
|
6017
|
+
}
|
|
6018
|
+
if (isProfilerEnabled) {
|
|
6019
|
+
currentDispatcher(opId, 1 /* Phase.Stop */);
|
|
5796
6020
|
}
|
|
5797
6021
|
}
|
|
5798
|
-
function
|
|
6022
|
+
function logGlobalOperationEndWithVM(opId, vm) {
|
|
5799
6023
|
if (isMeasureEnabled) {
|
|
5800
6024
|
const opName = getOperationName(opId);
|
|
5801
|
-
const markName =
|
|
5802
|
-
end(opName, markName
|
|
6025
|
+
const markName = getMarkName(opId, vm);
|
|
6026
|
+
end(opName, markName, {
|
|
6027
|
+
color: 'tertiary',
|
|
6028
|
+
tooltipText: getTooltipText(opName, opId),
|
|
6029
|
+
properties: getProperties(vm),
|
|
6030
|
+
});
|
|
5803
6031
|
}
|
|
5804
6032
|
if (isProfilerEnabled) {
|
|
5805
|
-
currentDispatcher(opId, 1 /* Phase.Stop */, vm
|
|
6033
|
+
currentDispatcher(opId, 1 /* Phase.Stop */, vm.tagName, vm.idx, vm.renderMode, vm.shadowMode);
|
|
5806
6034
|
}
|
|
5807
6035
|
}
|
|
5808
6036
|
|
|
@@ -5858,6 +6086,12 @@ function getVMBeingRendered() {
|
|
|
5858
6086
|
function setVMBeingRendered(vm) {
|
|
5859
6087
|
vmBeingRendered = vm;
|
|
5860
6088
|
}
|
|
6089
|
+
const VALID_SCOPE_TOKEN_REGEX = /^[a-zA-Z0-9\-_.]+$/;
|
|
6090
|
+
// See W-16614556
|
|
6091
|
+
// TODO [#2826]: freeze the template object
|
|
6092
|
+
function isValidScopeToken(token) {
|
|
6093
|
+
return shared.isString(token) && VALID_SCOPE_TOKEN_REGEX.test(token);
|
|
6094
|
+
}
|
|
5861
6095
|
function validateSlots(vm) {
|
|
5862
6096
|
assertNotProd(); // this method should never leak to prod
|
|
5863
6097
|
const { cmpSlots } = vm;
|
|
@@ -6010,9 +6244,9 @@ function buildParseFragmentFn(createFragmentFn) {
|
|
|
6010
6244
|
}
|
|
6011
6245
|
}
|
|
6012
6246
|
// See W-16614556
|
|
6013
|
-
if ((hasStyleToken && !
|
|
6014
|
-
(hasLegacyToken && !
|
|
6015
|
-
throw new Error('stylesheet token must be a string');
|
|
6247
|
+
if ((hasStyleToken && !isValidScopeToken(stylesheetToken)) ||
|
|
6248
|
+
(hasLegacyToken && !isValidScopeToken(legacyStylesheetToken))) {
|
|
6249
|
+
throw new Error('stylesheet token must be a valid string');
|
|
6016
6250
|
}
|
|
6017
6251
|
// If legacy stylesheet tokens are required, then add them to the rendered string
|
|
6018
6252
|
const stylesheetTokenToRender = stylesheetToken + (hasLegacyToken ? ` ${legacyStylesheetToken}` : '');
|
|
@@ -6304,13 +6538,17 @@ function getComponentAPIVersion(Ctor) {
|
|
|
6304
6538
|
return apiVersion;
|
|
6305
6539
|
}
|
|
6306
6540
|
function getTemplateReactiveObserver(vm) {
|
|
6307
|
-
|
|
6541
|
+
const reactiveObserver = createReactiveObserver(() => {
|
|
6308
6542
|
const { isDirty } = vm;
|
|
6309
6543
|
if (shared.isFalse(isDirty)) {
|
|
6310
6544
|
markComponentAsDirty(vm);
|
|
6311
6545
|
scheduleRehydration(vm);
|
|
6312
6546
|
}
|
|
6313
6547
|
});
|
|
6548
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
6549
|
+
associateReactiveObserverWithVM(reactiveObserver, vm);
|
|
6550
|
+
}
|
|
6551
|
+
return reactiveObserver;
|
|
6314
6552
|
}
|
|
6315
6553
|
function resetTemplateObserverAndUnsubscribe(vm) {
|
|
6316
6554
|
const { tro, component } = vm;
|
|
@@ -6385,7 +6623,12 @@ function rerenderVM(vm) {
|
|
|
6385
6623
|
}
|
|
6386
6624
|
function connectRootElement(elm) {
|
|
6387
6625
|
const vm = getAssociatedVM(elm);
|
|
6388
|
-
|
|
6626
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
6627
|
+
// Flush any logs for this VM so that the initial properties from the constructor don't "count"
|
|
6628
|
+
// in subsequent re-renders (lwc-rehydrate). Right now we're at the first render (lwc-hydrate).
|
|
6629
|
+
flushMutationLogsForVM(vm);
|
|
6630
|
+
}
|
|
6631
|
+
logGlobalOperationStartWithVM(7 /* OperationId.GlobalHydrate */, vm);
|
|
6389
6632
|
// Usually means moving the element from one place to another, which is observable via
|
|
6390
6633
|
// life-cycle hooks.
|
|
6391
6634
|
if (vm.state === 1 /* VMState.connected */) {
|
|
@@ -6393,7 +6636,7 @@ function connectRootElement(elm) {
|
|
|
6393
6636
|
}
|
|
6394
6637
|
runConnectedCallback(vm);
|
|
6395
6638
|
rehydrate(vm);
|
|
6396
|
-
|
|
6639
|
+
logGlobalOperationEndWithVM(7 /* OperationId.GlobalHydrate */, vm);
|
|
6397
6640
|
}
|
|
6398
6641
|
function disconnectRootElement(elm) {
|
|
6399
6642
|
const vm = getAssociatedVM(elm);
|
|
@@ -6699,6 +6942,9 @@ function runRenderedCallback(vm) {
|
|
|
6699
6942
|
}
|
|
6700
6943
|
let rehydrateQueue = [];
|
|
6701
6944
|
function flushRehydrationQueue() {
|
|
6945
|
+
// Gather the logs before rehydration starts so they can be reported at the end of rehydration.
|
|
6946
|
+
// Note that we also clear all existing logs at this point so that subsequent re-renders start from a clean slate.
|
|
6947
|
+
const mutationLogs = process.env.NODE_ENV !== 'production' ? getAndFlushMutationLogs() : undefined;
|
|
6702
6948
|
logGlobalOperationStart(8 /* OperationId.GlobalRehydrate */);
|
|
6703
6949
|
if (process.env.NODE_ENV !== 'production') {
|
|
6704
6950
|
shared.assert.invariant(rehydrateQueue.length, `If rehydrateQueue was scheduled, it is because there must be at least one VM on this pending queue instead of ${rehydrateQueue}.`);
|
|
@@ -6719,13 +6965,13 @@ function flushRehydrationQueue() {
|
|
|
6719
6965
|
shared.ArrayUnshift.apply(rehydrateQueue, shared.ArraySlice.call(vms, i + 1));
|
|
6720
6966
|
}
|
|
6721
6967
|
// we need to end the measure before throwing.
|
|
6722
|
-
logGlobalOperationEnd(8 /* OperationId.GlobalRehydrate
|
|
6968
|
+
logGlobalOperationEnd(8 /* OperationId.GlobalRehydrate */, mutationLogs);
|
|
6723
6969
|
// re-throwing the original error will break the current tick, but since the next tick is
|
|
6724
6970
|
// already scheduled, it should continue patching the rest.
|
|
6725
6971
|
throw error;
|
|
6726
6972
|
}
|
|
6727
6973
|
}
|
|
6728
|
-
logGlobalOperationEnd(8 /* OperationId.GlobalRehydrate
|
|
6974
|
+
logGlobalOperationEnd(8 /* OperationId.GlobalRehydrate */, mutationLogs);
|
|
6729
6975
|
}
|
|
6730
6976
|
function runConnectedCallback(vm) {
|
|
6731
6977
|
const { state } = vm;
|
|
@@ -8136,5 +8382,5 @@ exports.swapTemplate = swapTemplate;
|
|
|
8136
8382
|
exports.track = track;
|
|
8137
8383
|
exports.unwrap = unwrap;
|
|
8138
8384
|
exports.wire = wire;
|
|
8139
|
-
/** version: 8.0.0
|
|
8385
|
+
/** version: 8.0.0 */
|
|
8140
8386
|
//# sourceMappingURL=index.cjs.js.map
|