@occluze/tether 0.6.6 → 0.6.8
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/README.md +3 -3
- package/dist/esm/astro.js +2 -2
- package/dist/esm/chunks/account-C3NP6HFB.js +1 -0
- package/dist/esm/chunks/account-pages-WLK374FO.js +1 -0
- package/dist/esm/chunks/analytics-G3SAWMNL.js +1 -0
- package/dist/esm/chunks/chunk-27PJJZGC.js +1 -0
- package/dist/esm/chunks/chunk-2FSXS55U.js +1 -0
- package/dist/esm/chunks/chunk-FCSWQDVV.js +1 -0
- package/dist/esm/chunks/chunk-FOMSMIAM.js +1 -0
- package/dist/esm/chunks/chunk-GZJTCLLW.js +1 -0
- package/dist/esm/chunks/chunk-HEQILZVR.js +1 -0
- package/dist/esm/chunks/chunk-JOOEXYF3.js +4 -0
- package/dist/esm/chunks/chunk-MPTQYLSM.js +1 -0
- package/dist/esm/chunks/chunk-NEHZ37TU.js +3 -0
- package/dist/esm/chunks/chunk-V74KGEJF.js +1 -0
- package/dist/esm/chunks/chunk-VT4CDUJJ.js +1 -0
- package/dist/esm/chunks/chunk-YJLWX2HK.js +1 -0
- package/dist/esm/chunks/diagnose-6VVGZNTY.js +14 -0
- package/dist/esm/chunks/extras-GJVRDFM3.js +1 -0
- package/dist/esm/chunks/markets-ui-UNB4PTA7.js +1 -0
- package/dist/esm/chunks/search-OU75RNQL.js +1 -0
- package/dist/esm/index.js +1 -1
- package/dist/esm/server.js +2 -1
- package/dist/presets/barba.esm.js +56 -36
- package/dist/tether.account-pages.js +776 -432
- package/dist/tether.account-pages.min.js +1 -1
- package/dist/tether.account.js +655 -321
- package/dist/tether.account.min.js +1 -1
- package/dist/tether.analytics.js +318 -191
- package/dist/tether.analytics.min.js +1 -1
- package/dist/tether.diagnose.js +334 -243
- package/dist/tether.diagnose.min.js +2 -2
- package/dist/tether.extras.js +78 -33
- package/dist/tether.extras.min.js +1 -1
- package/dist/tether.js +3171 -1998
- package/dist/tether.markets.js +231 -126
- package/dist/tether.markets.min.js +1 -1
- package/dist/tether.min.js +0 -0
- package/dist/tether.min.js.map +4 -4
- package/dist/tether.search.js +221 -126
- package/dist/tether.search.min.js +1 -1
- package/package.json +23 -4
- package/src/account/addresses-view.js +92 -0
- package/src/account/browser-session.js +359 -0
- package/src/account/markup.js +48 -0
- package/src/account/operations.js +180 -0
- package/src/account/order-lines.js +96 -0
- package/src/account/order-list.js +91 -0
- package/src/account/order-page.js +192 -0
- package/src/account/page-events.js +288 -0
- package/src/account/server-client.js +172 -0
- package/src/account/shared.js +111 -0
- package/src/account/shopify-auth.js +150 -0
- package/src/account/subscriptions-view.js +158 -0
- package/src/account-api.js +118 -0
- package/src/account-links.js +35 -0
- package/src/account-pages.js +68 -284
- package/src/account.js +281 -317
- package/src/amounts.js +36 -0
- package/src/analytics-shopify.js +241 -0
- package/src/analytics.js +304 -184
- package/src/api-version.js +75 -25
- package/src/astro.js +233 -68
- package/src/cart/checkout.js +97 -0
- package/src/cart/drawer.js +138 -0
- package/src/cart/mutations.js +234 -0
- package/src/cart/render.js +294 -0
- package/src/cart/store.js +326 -0
- package/src/cart.js +322 -481
- package/src/client.js +214 -78
- package/src/collection.js +126 -57
- package/src/config.js +323 -59
- package/src/controls/cart-controls.js +155 -0
- package/src/controls/discount.js +96 -0
- package/src/controls/extras.js +63 -0
- package/src/controls/navigation.js +83 -0
- package/src/diagnose-markup.js +333 -0
- package/src/diagnose.js +251 -202
- package/src/dom.js +219 -220
- package/src/extras.js +119 -37
- package/src/fragments.js +115 -22
- package/src/images.js +104 -0
- package/src/index.js +245 -285
- package/src/initial.js +78 -66
- package/src/lazy-iife.js +92 -22
- package/src/lazy.js +25 -4
- package/src/loader.js +263 -124
- package/src/market-codes.js +35 -0
- package/src/markets-ui.js +169 -55
- package/src/markets.js +286 -85
- package/src/markup.js +64 -0
- package/src/mounting.js +214 -91
- package/src/page-market.js +116 -0
- package/src/parts/account-pages.js +4 -1
- package/src/parts/account.js +4 -1
- package/src/parts/analytics.js +4 -1
- package/src/parts/diagnose.js +4 -1
- package/src/parts/extras.js +4 -1
- package/src/parts/markets.js +4 -1
- package/src/parts/search.js +4 -1
- package/src/presets/barba.js +120 -30
- package/src/product-events.js +130 -0
- package/src/product-render.js +257 -0
- package/src/product-state.js +318 -0
- package/src/product.js +233 -459
- package/src/repeaters.js +173 -0
- package/src/search.js +277 -107
- package/src/selling-plans.js +107 -47
- package/src/server.js +168 -205
- package/src/shopify-values.js +89 -0
- package/src/status.js +99 -39
- package/src/store-html.js +0 -0
- package/src/storefront/catalog.js +199 -0
- package/src/storefront/json-ld.js +167 -0
- package/src/variant-render.js +165 -0
- package/types/astro.d.ts +13 -2
- package/types/index.d.ts +178 -27
- package/types/server.d.ts +89 -17
- package/dist/esm/chunks/account-QUBHQG3C.js +0 -1
- package/dist/esm/chunks/account-pages-VWDHF6WA.js +0 -1
- package/dist/esm/chunks/analytics-SLATWPLC.js +0 -1
- package/dist/esm/chunks/chunk-64TUD3QR.js +0 -1
- package/dist/esm/chunks/chunk-AJLPU2JC.js +0 -4
- package/dist/esm/chunks/chunk-FIOZPPC5.js +0 -1
- package/dist/esm/chunks/chunk-K2YEQAIH.js +0 -1
- package/dist/esm/chunks/chunk-L2TRRKYV.js +0 -1
- package/dist/esm/chunks/chunk-RREHGH4A.js +0 -1
- package/dist/esm/chunks/chunk-VC46IEJQ.js +0 -1
- package/dist/esm/chunks/chunk-VCPI7MJ2.js +0 -1
- package/dist/esm/chunks/chunk-VPVJPNB4.js +0 -1
- package/dist/esm/chunks/chunk-ZIUIWEON.js +0 -1
- package/dist/esm/chunks/diagnose-VXQBSD3A.js +0 -14
- package/dist/esm/chunks/extras-R4X34VQL.js +0 -1
- package/dist/esm/chunks/markets-ui-F3R5T5EL.js +0 -1
- package/dist/esm/chunks/search-NILMGYXG.js +0 -1
package/src/initial.js
CHANGED
|
@@ -1,75 +1,87 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* What the browser script
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* when the product requires a plan or defaultPurchase is 'subscription', low stock at 5 or fewer.
|
|
2
|
+
* What the browser script shows first for a product, as plain data, so a server renders the same and nothing flashes
|
|
3
|
+
* when Tether takes over. Public as `initialState()` of `@occluze/tether/server`; the rules are `product-state.js`'s,
|
|
4
|
+
* the ones the browser scope uses.
|
|
6
5
|
*/
|
|
7
|
-
import {
|
|
6
|
+
import { DEFAULTS } from './config.js';
|
|
7
|
+
import { initialChoice, isValueAvailable, productView } from './product-state.js';
|
|
8
|
+
import { allPlans, allocationFor, planPrice, planSavings } from './selling-plans.js';
|
|
9
|
+
/** @import { Money } from './shopify-values.js' */
|
|
10
|
+
/** @import { Product, ProductVariant } from './fragments.js' */
|
|
11
|
+
/** @import { PlanInGroup } from './selling-plans.js' */
|
|
12
|
+
/** @import { Selection, ShowCondition } from './product-state.js' */
|
|
8
13
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
14
|
+
/**
|
|
15
|
+
* @typedef {object} InitialOptions
|
|
16
|
+
* @property {string | null | undefined} [variant] The page's `?variant=`; the first variant for sale without.
|
|
17
|
+
* @property {string | null | undefined} [sellingPlan] The page's `?selling_plan=`: subscribes on that plan.
|
|
18
|
+
* @property {string | null | undefined} [defaultPurchase] `subscription` subscribes on the first plan.
|
|
19
|
+
* @property {number | undefined} [lowStock] `low-stock` at this many or fewer.
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* @typedef {object} InitialPlan A plan in the plan list (`tether-plan-list`).
|
|
23
|
+
* @property {string} id
|
|
24
|
+
* @property {string} name
|
|
25
|
+
* @property {Money | null} price On this plan, for the variant.
|
|
26
|
+
* @property {number} savings In %, 0 without savings.
|
|
27
|
+
* @property {boolean} selected `is-selected`: the line is bought on this plan.
|
|
28
|
+
* @property {boolean} available The variant is on this plan; `is-unavailable` when not.
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* @typedef {object} InitialState
|
|
32
|
+
* @property {ProductVariant} variant
|
|
33
|
+
* @property {Selection} selected Option name → value of the variant: `is-selected` on those buttons.
|
|
34
|
+
* @property {'one-time' | 'subscription'} purchase
|
|
35
|
+
* @property {PlanInGroup | null} plan The plan the line is bought on, `null` when bought once.
|
|
36
|
+
* @property {InitialPlan[]} plans
|
|
37
|
+
* @property {number} savings The offered plan's savings in % (`tether-bind="subscription-savings"`), 0 without.
|
|
38
|
+
* @property {Money} price
|
|
39
|
+
* @property {Money | null} compareAtPrice Only when on sale.
|
|
40
|
+
* @property {boolean} available
|
|
41
|
+
* @property {Record<ShowCondition, boolean>} show The `tether-show` conditions: `hidden={!state.show['out-of-stock']}`.
|
|
42
|
+
* @property {Record<string, string[]>} unavailable Per option, the values without a variant for sale (given the other
|
|
43
|
+
* selected values), as plain data for frameworks that serialise props.
|
|
44
|
+
* @property {(name: string, value: string) => boolean} isUnavailable The same as a function: `is-unavailable`.
|
|
45
|
+
*/
|
|
31
46
|
|
|
47
|
+
/**
|
|
48
|
+
* @param {Product | null | undefined} product
|
|
49
|
+
* @param {InitialOptions} [options]
|
|
50
|
+
* @returns {InitialState | null} `null` without a product or variants.
|
|
51
|
+
*/
|
|
52
|
+
export function initialState(product, options = {}) {
|
|
53
|
+
if (!product) return null;
|
|
54
|
+
const { variant, sellingPlan, defaultPurchase = DEFAULTS.defaultPurchase, lowStock = DEFAULTS.lowStock } = options;
|
|
55
|
+
const choice = initialChoice(product, { variant, sellingPlan, defaultPurchase });
|
|
56
|
+
const view = productView(product, { ...choice, quantity: 1 }, lowStock);
|
|
57
|
+
if (!view) return null;
|
|
58
|
+
const { selected, isSubscription } = view;
|
|
59
|
+
const isUnavailable = (/** @type {string} */ name, /** @type {string} */ value) =>
|
|
60
|
+
!isValueAvailable(product, selected, name, value);
|
|
32
61
|
return {
|
|
33
|
-
variant:
|
|
62
|
+
variant: view.variant,
|
|
34
63
|
selected,
|
|
35
|
-
purchase,
|
|
36
|
-
plan:
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
64
|
+
purchase: view.purchase.kind,
|
|
65
|
+
plan: isSubscription ? view.plan : null,
|
|
66
|
+
plans: allPlans(product).map((plan) => ({
|
|
67
|
+
id: plan.id,
|
|
68
|
+
name: plan.name,
|
|
69
|
+
price: planPrice(view.variant, plan.id),
|
|
70
|
+
savings: planSavings(view.variant, plan.id).percentage,
|
|
71
|
+
selected: isSubscription && plan.id === view.purchase.planId,
|
|
72
|
+
available: Boolean(allocationFor(view.variant, plan.id)),
|
|
41
73
|
})),
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
'has-variants': vs.length > 1,
|
|
55
|
-
'single-variant': vs.length === 1,
|
|
56
|
-
'low-stock': low,
|
|
57
|
-
'plenty-in-stock': v.availableForSale && !low,
|
|
58
|
-
'subscription-available': subscriptionAvailable,
|
|
59
|
-
'subscription-unavailable': !subscriptionAvailable,
|
|
60
|
-
'subscription-only': Boolean(product.requiresSellingPlan),
|
|
61
|
-
'one-time-available': !product.requiresSellingPlan,
|
|
62
|
-
'subscription-selected': sub,
|
|
63
|
-
'one-time-selected': !sub,
|
|
64
|
-
'has-savings': sub ? savingsNow > 0 : onSale,
|
|
65
|
-
},
|
|
66
|
-
/** Option values without an available variant, as plain data (for frameworks that serialise props). */
|
|
67
|
-
unavailable: Object.fromEntries((product.options || []).map((o) => [o.name, o.optionValues.map((x) => x.name).filter((n) => isUnavail(o.name, n))])),
|
|
68
|
-
/** Option values with no available variant (given the other selected options): class is-unavailable. */
|
|
69
|
-
isUnavailable: (name, value) => isUnavail(name, value),
|
|
74
|
+
savings: view.savings.percentage,
|
|
75
|
+
price: view.price,
|
|
76
|
+
compareAtPrice: view.compareAtPrice,
|
|
77
|
+
available: view.variant.availableForSale,
|
|
78
|
+
show: view.show,
|
|
79
|
+
unavailable: Object.fromEntries(
|
|
80
|
+
product.options.map((option) => [
|
|
81
|
+
option.name,
|
|
82
|
+
option.optionValues.map((value) => value.name).filter((value) => isUnavailable(option.name, value)),
|
|
83
|
+
]),
|
|
84
|
+
),
|
|
85
|
+
isUnavailable,
|
|
70
86
|
};
|
|
71
|
-
function isUnavail(name, value) {
|
|
72
|
-
return !vs.some((x) => x.availableForSale && x.selectedOptions.every((o) =>
|
|
73
|
-
(o.name === name ? o.value === value : selected[o.name] === o.value)));
|
|
74
|
-
}
|
|
75
87
|
}
|
package/src/lazy-iife.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* `<script>` build: the optional parts are separate files next to tether(.min).js (tether.markets.min.js), loaded on
|
|
3
|
+
* first use. `partsUrl` sets another folder. A part registers itself in `window.Tether.__parts` and uses the core
|
|
4
|
+
* modules in `window.Tether.__core` instead of bundling copies of them.
|
|
4
5
|
*/
|
|
5
6
|
import * as config from './config.js';
|
|
6
7
|
import * as client from './client.js';
|
|
@@ -13,34 +14,103 @@ import * as cart from './cart.js';
|
|
|
13
14
|
import * as product from './product.js';
|
|
14
15
|
import * as collection from './collection.js';
|
|
15
16
|
import * as mounting from './mounting.js';
|
|
17
|
+
import * as marketCodes from './market-codes.js';
|
|
18
|
+
import * as shopifyValues from './shopify-values.js';
|
|
19
|
+
import * as storeHtml from './store-html.js';
|
|
20
|
+
/** @import { Parts, PartName } from './lazy.js' */
|
|
16
21
|
|
|
17
22
|
const { cfg } = config;
|
|
18
23
|
|
|
19
|
-
/**
|
|
24
|
+
/**
|
|
25
|
+
* The modules a part may use, shared instead of bundled twice (scripts/build.mjs maps a part's imports to these).
|
|
26
|
+
*
|
|
27
|
+
* @type {Record<string, object>}
|
|
28
|
+
*/
|
|
20
29
|
export const coreModules = {
|
|
21
|
-
'config.js': config,
|
|
22
|
-
'
|
|
23
|
-
'
|
|
30
|
+
'config.js': config,
|
|
31
|
+
'client.js': client,
|
|
32
|
+
'dom.js': dom,
|
|
33
|
+
'fragments.js': fragments,
|
|
34
|
+
'loader.js': loader,
|
|
35
|
+
'selling-plans.js': sellingPlans,
|
|
36
|
+
'status.js': status,
|
|
37
|
+
'cart.js': cart,
|
|
38
|
+
'product.js': product,
|
|
39
|
+
'collection.js': collection,
|
|
40
|
+
'mounting.js': mounting,
|
|
41
|
+
'market-codes.js': marketCodes,
|
|
42
|
+
'shopify-values.js': shopifyValues,
|
|
43
|
+
'store-html.js': storeHtml,
|
|
24
44
|
};
|
|
25
45
|
|
|
26
|
-
const
|
|
27
|
-
const
|
|
46
|
+
const MINIFIED_SCRIPT = /\.min\.js(\?|$)/;
|
|
47
|
+
const coreScript = typeof document === 'undefined' ? '' : (document.currentScript?.getAttribute('src') ?? '');
|
|
48
|
+
const coreScriptUrl = coreScript ? new URL(coreScript, document.baseURI).href : '';
|
|
28
49
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
50
|
+
/** @type {Map<PartName, Promise<unknown>>} Parts loaded or loading. */
|
|
51
|
+
const parts = new Map();
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* The folder parts load from: `partsUrl`, else the core script's own folder. A `partsUrl` must be https or on this
|
|
55
|
+
* site, because the parts run with the same access as the core (the account part holds customer sessions).
|
|
56
|
+
*
|
|
57
|
+
* @throws {Error} For a `partsUrl` that is neither.
|
|
58
|
+
*/
|
|
59
|
+
function partsFolder() {
|
|
60
|
+
if (!cfg.partsUrl) return coreScriptUrl.replace(/[^/]*$/, '');
|
|
61
|
+
const folder = new URL(cfg.partsUrl, document.baseURI);
|
|
62
|
+
if (folder.protocol !== 'https:' && folder.origin !== window.location.origin) {
|
|
63
|
+
throw new Error(`partsUrl must be https or on this site: ${folder.href}`);
|
|
64
|
+
}
|
|
65
|
+
return folder.href;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* @param {PartName} name
|
|
70
|
+
* @param {string} url
|
|
71
|
+
* @returns {Promise<unknown>}
|
|
72
|
+
*/
|
|
73
|
+
function loadScript(name, url) {
|
|
74
|
+
return new Promise((resolve, reject) => {
|
|
75
|
+
const script = document.createElement('script');
|
|
76
|
+
script.src = url;
|
|
77
|
+
script.async = true;
|
|
78
|
+
script.onload = () => {
|
|
79
|
+
const { Tether } = /** @type {Window & { Tether?: { __parts?: Record<string, unknown> } }} */ (window);
|
|
80
|
+
const part = Tether?.__parts?.[name];
|
|
81
|
+
if (part) resolve(part);
|
|
82
|
+
else reject(new Error(`${url} did not register`));
|
|
83
|
+
};
|
|
84
|
+
script.onerror = () => {
|
|
85
|
+
parts.delete(name);
|
|
86
|
+
reject(new Error(`Could not load ${url}. Host it next to the Tether script, or set partsUrl.`));
|
|
87
|
+
};
|
|
88
|
+
document.head.appendChild(script);
|
|
41
89
|
});
|
|
42
|
-
return parts[name];
|
|
43
90
|
}
|
|
44
91
|
|
|
45
|
-
|
|
92
|
+
/**
|
|
93
|
+
* @template {PartName} Name
|
|
94
|
+
* @param {Name} name
|
|
95
|
+
* @returns {Promise<Parts[Name]>}
|
|
96
|
+
* @throws {Error} (rejected) When the part's file can't be loaded or doesn't register.
|
|
97
|
+
*/
|
|
98
|
+
export function loadPart(name) {
|
|
99
|
+
let loading = parts.get(name);
|
|
100
|
+
if (!loading) {
|
|
101
|
+
let folder;
|
|
102
|
+
try {
|
|
103
|
+
folder = partsFolder();
|
|
104
|
+
} catch (error) {
|
|
105
|
+
return Promise.reject(error instanceof Error ? error : new Error(String(error)));
|
|
106
|
+
}
|
|
107
|
+
const suffix = MINIFIED_SCRIPT.test(coreScriptUrl) || !coreScriptUrl ? '.min' : '';
|
|
108
|
+
loading = loadScript(name, `${folder.replace(/\/?$/, '/')}tether.${name}${suffix}.js`);
|
|
109
|
+
parts.set(name, loading);
|
|
110
|
+
}
|
|
111
|
+
// A part's file is built from the module `Parts[Name]` names (scripts/build.mjs), and registers that module.
|
|
112
|
+
return /** @type {Promise<Parts[Name]>} */ (loading);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Parts that load other parts (account → account-pages) use this same loader.
|
|
46
116
|
coreModules['lazy.js'] = { loadPart, coreModules };
|
package/src/lazy.js
CHANGED
|
@@ -1,8 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Optional parts that most pages never need, loaded on first use.
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* Optional parts that most pages never need, loaded on first use. In the ESM and Node builds they are dynamic
|
|
3
|
+
* imports, which bundlers split into their own chunks; the `<script>` build swaps this file for `lazy-iife.js`
|
|
4
|
+
* (scripts/build.mjs).
|
|
5
5
|
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @typedef {{
|
|
9
|
+
* diagnose: typeof import('./diagnose.js'),
|
|
10
|
+
* markets: typeof import('./markets-ui.js'),
|
|
11
|
+
* search: typeof import('./search.js'),
|
|
12
|
+
* extras: typeof import('./extras.js'),
|
|
13
|
+
* account: typeof import('./account.js'),
|
|
14
|
+
* 'account-pages': typeof import('./account-pages.js'),
|
|
15
|
+
* analytics: typeof import('./analytics.js'),
|
|
16
|
+
* }} Parts
|
|
17
|
+
*/
|
|
18
|
+
/** @typedef {keyof Parts} PartName */
|
|
19
|
+
|
|
20
|
+
/** @type {{ [Name in PartName]: () => Promise<Parts[Name]> }} */
|
|
6
21
|
const PARTS = {
|
|
7
22
|
diagnose: () => import('./diagnose.js'),
|
|
8
23
|
markets: () => import('./markets-ui.js'),
|
|
@@ -12,7 +27,13 @@ const PARTS = {
|
|
|
12
27
|
'account-pages': () => import('./account-pages.js'),
|
|
13
28
|
analytics: () => import('./analytics.js'),
|
|
14
29
|
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @template {PartName} Name
|
|
33
|
+
* @param {Name} name
|
|
34
|
+
* @returns {Promise<Parts[Name]>}
|
|
35
|
+
*/
|
|
15
36
|
export const loadPart = (name) => PARTS[name]();
|
|
16
37
|
|
|
17
|
-
|
|
38
|
+
/** Only the `<script>` build shares its modules with separately loaded parts. */
|
|
18
39
|
export const coreModules = undefined;
|