feat: hydrate mobile My Work before optional tools
CI / lint (pull_request) Successful in 3m33s
CI / build-release (pull_request) Successful in 7s
CI / browser-journey (pull_request) Successful in 6m40s
CI / release-candidate (pull_request) Has been skipped

Closes #1401
This commit is contained in:
timmy committed 2026-08-25 16:41:27 +00:00
1 parent e44f49708a
commit 297ae7550a
11 files changed
+259 -60

No files matched your search

@@ -169,7 +169,7 @@ def test_release_artifact_bootstraps_mobile_home_and_returns_from_insights(
workspace_requests.append(request.url),
launch_transfer_events.append("workspace-requested"),
)
if "feature-today-timer-" in request.url else None,
if "feature-work-core-" in request.url else None,
)
page.on(
"requestfinished",
+18 -4
View File
@@ -50,7 +50,7 @@ def test_product_workflows_are_stable_lazy_feature_chunks(tmp_path):
assert set(first.feature_bundles) == {
"comment-actions", "issue-capture", "pull-workflow", "push-notifications", "sign-out", "device-setup",
"today-timer", "security-center", "planning",
"work-core", "today-timer", "security-center", "planning",
}
assert first.dashboard_html.count("<script src=") == 1
assert f'<script src="{first.runtime_name}"></script>' in first.dashboard_html
@@ -95,7 +95,6 @@ def test_product_workflows_are_stable_lazy_feature_chunks(tmp_path):
assert f"BASE + '{pull_workflow.runtime_name}'" in first.service_worker_source
assert f'name="stackchain-feature-security-center" content="{security_center.runtime_name}"' in first.dashboard_html
assert f"BASE + '{security_center.runtime_name}'" in first.service_worker_source
shell_block, optional_block = first.service_worker_source.split(
"const OPTIONAL_FEATURES = [", 1
)
@@ -127,14 +126,29 @@ def test_product_workflows_are_stable_lazy_feature_chunks(tmp_path):
assert security_changed.feature_bundles["security-center"].runtime_name != security_center.runtime_name
def test_my_work_has_a_small_blocking_bundle_before_optional_workspace_hydration():
build = build_frontend(FRONTEND)
work_core = build.feature_bundles["work-core"]
today = build.feature_bundles["today-timer"]
assert b"function buildMyWork" in work_core.runtime_bytes
assert b"function createProgressiveMyWork" in work_core.runtime_bytes
assert b"function buildMyWork" not in today.runtime_bytes
assert b"loadWorkspace({document,window})" in build.runtime_bytes
assert b"const workspaceLifecycle" not in build.runtime_bytes
assert b"const workspaceLifecycle" in today.runtime_bytes
assert SCRIPT_PRELOAD.findall(build.dashboard_html) == [work_core.runtime_name]
assert len(build.runtime_gzip_bytes) + len(work_core.runtime_gzip_bytes) <= 150 * 1024
def test_mandatory_workspace_fetch_is_preloaded_without_blocking_launch():
build = build_frontend(FRONTEND)
workspace = build.feature_bundles["today-timer"]
workspace = build.feature_bundles["work-core"]
assert SCRIPT_PRELOAD.findall(build.dashboard_html) == [workspace.runtime_name]
assert build.dashboard_html.count(f'<script src="{workspace.runtime_name}"></script>') == 0
assert len(build.runtime_gzip_bytes) <= 100 * 1024
assert len(workspace.runtime_gzip_bytes) <= 111 * 1024
assert len(build.runtime_gzip_bytes) + len(workspace.runtime_gzip_bytes) <= 150 * 1024
shell_block = build.service_worker_source.split("const OPTIONAL_FEATURES = [", 1)[0]
assert f"BASE + '{workspace.runtime_name}'" not in shell_block
+38
View File
@@ -0,0 +1,38 @@
import json
import subprocess
from pathlib import Path
MODULE = Path(__file__).parents[1] / "frontend" / "progressive-my-work.js"
MY_WORK = Path(__file__).parents[1] / "frontend" / "my-work.js"
def test_progressive_my_work_renders_and_filters_assigned_work_before_full_workspace():
harness = f"""
const fs=require('fs'); const vm=require('vm');
const buttons=[
{{dataset:{{workFilter:'all'}},attrs:{{}},addEventListener(n,cb){{this.cb=cb;}},setAttribute(n,v){{this.attrs[n]=v;}}}},
{{dataset:{{workFilter:'issue'}},attrs:{{}},addEventListener(n,cb){{this.cb=cb;}},setAttribute(n,v){{this.attrs[n]=v;}}}},
];
const list={{innerHTML:''}}; const status={{textContent:''}};
const document={{querySelector:s=>s==='#my-work-list'?list:s==='#my-work-status'?status:null,querySelectorAll:()=>buttons}};
const context={{module:{{exports:{{}}}},exports:{{}},console,URL,document}}; vm.createContext(context);
vm.runInContext(fs.readFileSync({json.dumps(str(MY_WORK))},'utf8'),context);
context.buildMyWork=context.module.exports; context.module={{exports:{{}}}};
vm.runInContext(fs.readFileSync({json.dumps(str(MODULE))},'utf8'),context);
const createProgressiveMyWork=context.module.exports;
const flow=createProgressiveMyWork({{document,fetchSnapshot:async()=>({{
user:{{login:'timmy'}},issues:[{{number:7,title:'Fix mobile queue',repository:'stackchain/dashboard',assignees:['timmy'],url:'https://forge.example/issues/7'}}],pull_requests:[]
}})}});
(async()=>{{
await flow.start(); const rendered=list.innerHTML;
buttons[1].cb();
console.log(JSON.stringify({{status:status.textContent,rendered,pressed:buttons.map(b=>b.attrs['aria-pressed'])}}));
}})().catch(e=>{{console.error(e);process.exit(1);}});
"""
result = subprocess.run(["node", "-e", harness], check=True, capture_output=True, text=True)
state = json.loads(result.stdout)
assert state["status"] == "1 assigned work item ready."
assert "Fix mobile queue" in state["rendered"]
assert 'href="https://forge.example/issues/7"' in state["rendered"]
assert state["pressed"] == ["false", "true"]
+1
View File
@@ -1408,6 +1408,7 @@ def test_install_precaches_complete_subpath_scoped_app_shell():
"/dashboard/static/offline-work.js",
"/dashboard/static/offline-today.js",
"/dashboard/static/my-work.js",
"/dashboard/static/progressive-my-work.js",
"/dashboard/static/agenda-replan.js",
"/dashboard/static/agenda-calendar.js",
"/dashboard/static/protect-today.js",
+30 -4
View File
@@ -24,6 +24,7 @@ def test_workspace_bootstrap_loads_content_addressed_feature_before_startup():
const status={textContent:''};
const document={
querySelector(selector) {
if (selector === 'meta[name="stackchain-feature-work-core"]') return {content:'feature-work-core-123.js'};
if (selector === 'meta[name="stackchain-feature-today-timer"]') return {content:'feature-workspace-abc.js'};
if (selector === 'meta[name="stackchain-feature-planning"]') return {content:'feature-planning-def.js'};
if (selector === '#my-work-action-status') return status;
@@ -37,6 +38,7 @@ console.log(JSON.stringify({requested,status:status.textContent}));
""")
assert result == {
"requested": [
"work-core:feature-work-core-123.js",
"today-timer:feature-workspace-abc.js",
"planning:feature-planning-def.js",
],
@@ -44,6 +46,30 @@ console.log(JSON.stringify({requested,status:status.textContent}));
}
def test_workspace_bootstrap_returns_after_work_core_while_optional_features_hydrate():
result = run_bootstrap("""
const document={querySelector(selector) {
const match=selector.match(/stackchain-feature-([^\"]+)/);
return match ? {content:'feature-' + match[1] + '.js'} : null;
}};
const requested=[]; const releases={};
const createLoader=()=>({load:name=>{
requested.push(name);
if (name === 'work-core') return Promise.resolve();
return new Promise(resolve=>{releases[name]=resolve;});
}});
const lifecycle=await loadWorkspace({document,createLoader});
const returned=requested.slice();
releases['today-timer'](); releases.planning();
await lifecycle.optionalReady;
console.log(JSON.stringify({returned,settled:requested}));
""")
assert result == {
"returned": ["work-core", "today-timer", "planning"],
"settled": ["work-core", "today-timer", "planning"],
}
def test_workspace_bootstrap_recovers_one_transient_failure_in_place():
result = run_bootstrap("""
const status={textContent:''}; const retry={hidden:true,disabled:false}; let attempts=0;
@@ -72,7 +98,7 @@ const document={querySelector(selector) {
return null;
}};
const window={location:{reload(){reloads++;}},addEventListener(){},removeEventListener(){}};
const createLoader=()=>({load:async()=>{attempts++; if (attempts < 5) throw new Error('offline');}});
const createLoader=()=>({load:async()=>{attempts++; if (attempts < 3) throw new Error('offline');}});
const loading=loadWorkspace({document,window,createLoader,schedule:callback=>callback()});
await new Promise(resolve=>setImmediate(resolve));
const offered={hidden:retry.hidden,disabled:retry.disabled,status:status.textContent};
@@ -81,7 +107,7 @@ await Promise.all([first,second,loading]);
console.log(JSON.stringify({attempts,reloads,offered,status:status.textContent,retryHidden:retry.hidden}));
""")
assert result == {
"attempts": 6,
"attempts": 5,
"reloads": 0,
"offered": {
"hidden": False,
@@ -116,7 +142,7 @@ const window={
addEventListener(name,callback) { listeners[name]=callback; },
removeEventListener(name,callback) { if (listeners[name] === callback) delete listeners[name]; },
};
const createLoader=()=>({load:async()=>{attempts++; if (attempts < 5) throw new Error('offline');}});
const createLoader=()=>({load:async()=>{attempts++; if (attempts < 3) throw new Error('offline');}});
const loading=loadWorkspace({document,window,createLoader,schedule:callback=>callback()});
await new Promise(resolve=>setImmediate(resolve));
const waiting=Boolean(listeners.online);
@@ -125,7 +151,7 @@ await loading;
console.log(JSON.stringify({attempts,waiting,reloads,status:status.textContent}));
""")
assert result == {
"attempts": 6,
"attempts": 5,
"waiting": True,
"reloads": 0,
"status": "",