Haeminway haeminway
한국어
Back to Tech Notes
1 min read

HtmlService Apps: Shell First, Then Async Load and Mobile Back

Loading data in the template delays first paint. Draw the shell first and load via google.script.run, but attach a failure handler to every call.

Don’t load all your data inside an HtmlService template. A slow load in a scriptlet (<?= ?>) leaves the user staring at a blank screen. Draw the shell first, then fetch data asynchronously via google.script.run.

Why it matters

If first paint lags 2–3 seconds on mobile, the user feels “it won’t open.” And google.script.run can fail: without a handler, the failure is silently swallowed and the screen looks frozen.

A failure handler on every call: via a Promise wrapper

function gasRun(fn, ...args) {
  return new Promise((resolve, reject) => {
    google.script.run
      .withSuccessHandler(resolve)
      .withFailureHandler(reject)   // mandatory: don't swallow failures
      [fn](...args);
  });
}

// usage
try {
  const data = await gasRun("getItems", filter);
  render(data);
} catch (err) {
  showError(err); // no dead overlay; offer a retry path
}

Block raw google.script.run calls in review and allow only this wrapper.

Mobile back button

A multi-screen app must support the phone’s back button. Push/replace state with google.script.history so screen changes enter browser history and back works naturally.

Don’t forget

  • <base target="_top">: so links change the parent from inside the iframe.
  • <meta viewport> and doGet().addMetaTag('viewport', ...): one alone breaks mobile width.
  • Load JavaScript at the bottom of the document so it doesn’t block first paint.

One line to keep: shell first → async load (failure handler required) → back button via history.

Frequently asked questions

Why is loading data directly inside an HtmlService template a problem?
A slow scriptlet load leaves the user staring at a blank screen. On mobile, a 2-3 second delay makes the app feel broken. Draw the shell first and fetch data asynchronously instead.
What happens if a google.script.run call has no failure handler?
The failure is silently swallowed and the screen looks frozen. Every call must have withFailureHandler attached, and the error UI should offer a retry path rather than a dead overlay.
How do you support the mobile back button in a multi-screen HtmlService app?
Use google.script.history to push or replace state on each screen transition. This records the change in browser history so the back button navigates naturally.