Skip to content
This repository was archived by the owner on Jul 30, 2025. It is now read-only.

Commit 00b87c0

Browse files
committed
fix: reduce expense of preloader on webapp init
by refactoring the load path for mode and badge registration logic Fixes #3286
1 parent 7a0a48c commit 00b87c0

File tree

19 files changed

+176
-92
lines changed

19 files changed

+176
-92
lines changed

packages/core/src/api/commands.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ export {
7777
KResponse,
7878
ParsedOptions,
7979
EvaluatorArgs as Arguments,
80+
Event,
8081
CommandRegistrar as Registrar
8182
} from '../models/command'
8283

packages/core/src/api/selection.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/*
2+
* Copyright 2019 IBM Corporation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
export { clearSelection, currentSelection } from '../webapp/views/sidecar-visibility'

packages/core/src/api/tab.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@
1515
*/
1616

1717
export { Tab } from '../webapp/tab'
18+
export { default as TabState } from '../models/tab-state'
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright 2019 IBM Corporation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { Tab } from '../../webapp/tab'
18+
import { MetadataBearing } from '../entity'
19+
import { MultiModalResponse, Button } from './types'
20+
import { SidecarMode } from '../../webapp/bottom-stripe'
21+
22+
export function formatButton<T extends MetadataBearing>(
23+
tab: Tab,
24+
resource: T,
25+
{ mode, label, command, confirm, kind }: Button
26+
): SidecarMode {
27+
const cmd = typeof command === 'string' ? command : command(tab, resource)
28+
29+
return {
30+
mode,
31+
label,
32+
flush: 'right',
33+
actAsButton: true,
34+
direct: confirm ? `confirm "${cmd}"` : cmd,
35+
execOptions: {
36+
exec: kind === 'view' ? 'qexec' : 'pexec'
37+
}
38+
}
39+
}
40+
41+
export function formatButtons(tab: Tab, mmr: MultiModalResponse, buttons: Button[]): SidecarMode[] {
42+
return buttons.map(button => formatButton(tab, mmr, button))
43+
}

packages/core/src/models/mmr/show.ts

Lines changed: 13 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@
1616

1717
import { Tab } from '../../webapp/tab'
1818
import { MetadataBearing } from '../entity'
19-
import { CustomSpec, isCustomSpec, showCustom } from '../../webapp/views/sidecar'
19+
import { CustomSpec } from '../../webapp/views/sidecar-core'
20+
import { isCustomSpec } from '../../webapp/views/custom-content'
2021
import { SidecarMode, addModeButtons } from '../../webapp/bottom-stripe'
2122
import { isTable, isMultiTable, Table, MultiTable } from '../../webapp/models/table'
22-
import { formatTable } from '../../webapp/views/table'
2323

24-
import { MultiModalResponse, Button, isButton } from './types'
24+
import { MultiModalResponse, isButton } from './types'
2525
import {
2626
Content,
2727
hasContent,
@@ -33,6 +33,8 @@ import {
3333
isFunctionContent
3434
} from './content-types'
3535

36+
import { formatButtons } from './button'
37+
3638
type Viewable = CustomSpec | HTMLElement | Table | MultiTable
3739

3840
/**
@@ -67,37 +69,17 @@ export async function format<T extends MetadataBearing>(
6769
}
6870
}
6971

70-
function wrapTable(tab: Tab, table: Table | MultiTable): HTMLElement {
72+
async function wrapTable(tab: Tab, table: Table | MultiTable): Promise<HTMLElement> {
7173
const dom1 = document.createElement('div')
7274
const dom2 = document.createElement('div')
7375
dom1.classList.add('scrollable', 'scrollable-auto')
7476
dom2.classList.add('result-as-table', 'repl-result')
7577
dom1.appendChild(dom2)
76-
formatTable(tab, table, dom2)
77-
return dom1
78-
}
7978

80-
export function formatButton<T extends MetadataBearing>(
81-
tab: Tab,
82-
resource: T,
83-
{ mode, label, command, confirm, kind }: Button
84-
): SidecarMode {
85-
const cmd = typeof command === 'string' ? command : command(tab, resource)
86-
87-
return {
88-
mode,
89-
label,
90-
flush: 'right',
91-
actAsButton: true,
92-
direct: confirm ? `confirm "${cmd}"` : cmd,
93-
execOptions: {
94-
exec: kind === 'view' ? 'qexec' : 'pexec'
95-
}
96-
}
97-
}
79+
const { formatTable } = await import('../../webapp/views/table')
80+
formatTable(tab, table, dom2)
9881

99-
function formatButtons(tab: Tab, mmr: MultiModalResponse, buttons: Button[]): SidecarMode[] {
100-
return buttons.map(button => formatButton(tab, mmr, button))
82+
return dom1
10183
}
10284

10385
async function renderContent<T extends MetadataBearing>(
@@ -112,7 +94,7 @@ async function renderContent<T extends MetadataBearing>(
11294
if (!isScalarContent(actualContent)) {
11395
if (isTable(actualContent) || isMultiTable(actualContent)) {
11496
return {
115-
content: wrapTable(tab, actualContent)
97+
content: await wrapTable(tab, actualContent)
11698
}
11799
} else {
118100
return {
@@ -126,7 +108,7 @@ async function renderContent<T extends MetadataBearing>(
126108
return content
127109
} else if (isTable(content) || isMultiTable(content)) {
128110
return {
129-
content: wrapTable(tab, content)
111+
content: await wrapTable(tab, content)
130112
}
131113
}
132114
}
@@ -179,6 +161,7 @@ export async function show(tab: Tab, mmr: MultiModalResponse) {
179161

180162
if (content) {
181163
if (isCustomSpec(content)) {
164+
const { showCustom } = await import('../../webapp/views/sidecar')
182165
return showCustom(tab, Object.assign({ modes: modesWithButtons, toolbarText: mmr.toolbarText }, content), {
183166
leaveBottomStripeAlone: true
184167
})
@@ -195,6 +178,7 @@ export async function show(tab: Tab, mmr: MultiModalResponse) {
195178
await renderContent(tab, mmr, content)
196179
)
197180

181+
const { showCustom } = await import('../../webapp/views/sidecar')
198182
return showCustom(tab, custom, { leaveBottomStripeAlone: true })
199183
}
200184
} else {

packages/core/src/plugins/preloader.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ import { PrescanModel } from './prescan'
2222

2323
import { MetadataBearing } from '../models/entity'
2424
import { ImplForPlugins } from '../core/command-tree'
25-
import { registerBadge, registerMode, BadgeRegistration, ModeRegistration } from '../api/registrars'
25+
import { registerSidecarBadge as registerBadge, BadgeRegistration } from '../webapp/views/registrar/badges'
26+
import { registerSidecarMode as registerMode, ModeRegistration } from '../webapp/views/registrar/modes'
2627
import { PreloadRegistration, PreloadRegistrar, CapabilityRegistration } from '../models/plugin'
2728

2829
class PreloaderRegistrarImpl extends ImplForPlugins implements PreloadRegistrar {

packages/core/src/repl/exec.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import { split, patterns } from './split'
2929
import { ExecType, Evaluator, EvaluatorArgs, KResponse, ParsedOptions, YargsParserFlags } from '../models/command'
3030

3131
import REPL from '../models/repl'
32-
import { ElementMimic } from '../util/mimic-dom'
32+
import isFakeDom from '../util/is-fake-dom'
3333
import {
3434
RawContent,
3535
RawResponse,
@@ -40,7 +40,6 @@ import {
4040
} from '../models/entity'
4141
import { ExecOptions, DefaultExecOptions, DefaultExecOptionsForTab } from '../models/execOptions'
4242
import eventBus from '../core/events'
43-
import historyModel from '../models/history'
4443
import { CodedError } from '../models/errors'
4544
import { UsageError, UsageModel, UsageRow } from '../core/usage-error'
4645

@@ -246,6 +245,7 @@ class InProcessExecutor implements Executor {
246245
// add a history entry
247246
if (!execOptions || !execOptions.noHistory) {
248247
if (!execOptions || !execOptions.quiet) {
248+
const historyModel = (await import('../models/history')).default
249249
execOptions.history = historyModel.add({
250250
raw: command
251251
})
@@ -486,7 +486,7 @@ class InProcessExecutor implements Executor {
486486
if (!(nActualArgs >= nRequiredArgs && nActualArgs <= nRequiredArgs + nPositionalOptionals)) {
487487
// yup, scan for implicitOK
488488
const implicitIdx = required.findIndex(({ implicitOK }) => implicitOK !== undefined)
489-
const { currentSelection } = await import('../webapp/views/sidecar') // FIXME
489+
const { currentSelection } = await import('../webapp/views/sidecar-visibility') // FIXME
490490
const selection = currentSelection(tab)
491491

492492
let nActualArgsWithImplicit = nActualArgs
@@ -658,10 +658,7 @@ class InProcessExecutor implements Executor {
658658
// response=true means we are in charge of 'ok'
659659
if (
660660
!render &&
661-
((execOptions && execOptions.replSilence) ||
662-
nested ||
663-
isLowLevelLoop(response) ||
664-
ElementMimic.isFakeDom(block))
661+
((execOptions && execOptions.replSilence) || nested || isLowLevelLoop(response) || isFakeDom(block))
665662
) {
666663
// the parent exec will deal with the repl
667664
debug('passing control back to prompt processor or headless')

packages/core/src/util/is-fake-dom.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright 2019 IBM Corporation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
/**
18+
* This is a cheap form of isFakeDom for use by repl/exec.ts
19+
*
20+
*/
21+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
22+
export default function isFakeDom(dom: any): boolean {
23+
return dom && Object.prototype.hasOwnProperty.call(dom, '_isFakeDom')
24+
}

packages/core/src/webapp/bottom-stripe.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ import { Tab } from './cli'
2020
import { removeAllDomChildren } from './util/dom'
2121
import { isTable, isMultiTable, Table, MultiTable } from './models/table'
2222
import { Capturable } from './models/capturable'
23-
import { formatTable } from './views/table'
24-
import { getSidecar, showCustom, isCustomSpec, CustomSpec, insertCustomContent } from './views/sidecar'
23+
import { CustomSpec, getSidecar } from './views/sidecar-core'
24+
import { isCustomSpec } from './views/custom-content'
2525
import sidecarSelector from './views/sidecar-selector'
2626
import { ExecOptions } from '../models/execOptions'
2727
import { apply as addRelevantModes } from './views/registrar/modes'
@@ -448,13 +448,15 @@ const _addModeButton = (
448448
}
449449
}
450450

451-
const present = (view: Entity) => {
451+
const present = async (view: Entity) => {
452452
if (typeof view === 'string') {
453453
const dom = document.createElement('div')
454454
dom.classList.add('padding-content', 'scrollable', 'scrollable-auto')
455455
dom.innerText = view
456+
const { insertCustomContent } = await import('./views/sidecar')
456457
insertCustomContent(tab, dom)
457458
} else if (isStringWithOptionalContentType(view) && isMetadataBearing(entity)) {
459+
const { showCustom } = await import('./views/sidecar')
458460
showCustom(
459461
tab,
460462
{
@@ -469,16 +471,20 @@ const _addModeButton = (
469471
const dom = document.createElement('div')
470472
dom.classList.add('padding-content', 'scrollable', 'scrollable-auto')
471473
dom.appendChild(view)
474+
const { insertCustomContent } = await import('./views/sidecar')
472475
insertCustomContent(tab, dom)
473476
} else if (isCustomSpec(view)) {
477+
const { showCustom } = await import('./views/sidecar')
474478
showCustom(tab, view, { leaveBottomStripeAlone: leaveBottomStripeAlone })
475479
} else if (isTable(view) || isMultiTable(view)) {
476480
const dom1 = document.createElement('div')
477481
const dom2 = document.createElement('div')
478482
dom1.classList.add('scrollable', 'scrollable-auto')
479483
dom2.classList.add('result-as-table', 'repl-result')
480484
dom1.appendChild(dom2)
485+
const { formatTable } = await import('./views/table')
481486
formatTable(tab, view, dom2, { usePip: true })
487+
const { insertCustomContent } = await import('./views/sidecar')
482488
insertCustomContent(tab, dom1)
483489
}
484490
}
@@ -510,8 +516,9 @@ const _addModeButton = (
510516
changeActiveButton()
511517
}
512518

513-
present(view)
519+
await present(view)
514520
} else if (!isToggle(view) && isCustomSpec(view)) {
521+
const { showCustom } = await import('./views/sidecar')
515522
showCustom(tab, view, { leaveBottomStripeAlone: leaveBottomStripeAlone })
516523
} else if (!leaveBottomStripeAlone) {
517524
changeActiveButton()
@@ -534,7 +541,7 @@ const _addModeButton = (
534541
const { format } = await import('../models/mmr/show')
535542
const view = await format(tab, entity as MetadataBearing, opts)
536543
changeActiveButton()
537-
present(view)
544+
await present(view)
538545
}
539546
}
540547
}

packages/core/src/webapp/popup.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ debug('loading')
2121
import { getCurrentTab } from './tab'
2222
import { SidecarMode } from './bottom-stripe'
2323

24-
import { prettyPrintTime } from './util/time'
2524
import { removeAllDomChildren } from './util/dom'
2625
import { Badge } from './views/badge'
2726
import Presentation from './views/presentation'
@@ -62,6 +61,8 @@ export const renderPopupContent = async (
6261
!_prettyType || _prettyType === 'custom' ? process.env.KUI_DEFAULT_PRETTY_TYPE || command : _prettyType
6362
debug('renderPopupContent', command, entity, prettyType)
6463

64+
const { prettyPrintTime } = await import('./util/time')
65+
6566
// Last updated... text
6667
const subtext = document.createElement('div')
6768
subtext.appendChild(document.createTextNode('Last updated '))

0 commit comments

Comments
 (0)