home / skills / trantuananh-17 / product-reviews / scripttag

scripttag skill

/.claude/skills/scripttag

This skill provides Preact-based storefront widget patterns to optimize performance, reduce bundle size, and enable lazy loading for rapid storefront

npx playbooks add skill trantuananh-17/product-reviews --skill scripttag

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
5.4 KB
---
name: storefront-widget
description: Use this skill when the user asks about "storefront widget", "scripttag", "customer-facing", "Preact", "bundle size", "lazy loading", "performance optimization", or any storefront frontend work. Provides Preact patterns for lightweight storefront widgets.
---

# Scripttag Development (Storefront Widget)

## Overview

The scripttag package contains **customer-facing storefront widgets** injected into merchant stores. Performance is **CRITICAL** - every KB and millisecond impacts merchant store speed and conversion rates.

---

## Architecture

### Tech Stack

| Technology | Purpose | Why |
|------------|---------|-----|
| **Preact** | UI library | 3KB vs React's 40KB+ |
| **preact-lazy** | Lazy loading | Lightweight lazy loader |
| **SCSS** | Styling | Scoped styles, minimal footprint |
| **Rspack** | Bundler | 10x faster than webpack |

> **Styling:** Always use custom SCSS/CSS. Avoid UI libraries - they add unnecessary bundle size.

---

## Directory Structure

```
packages/scripttag/
├── src/                      # Main widget entry
│   ├── index.js              # Main entry point
│   ├── loader.js             # Minimal loader script
│   ├── components/           # Shared components
│   ├── managers/             # API, Display managers
│   ├── helpers/              # Utility functions
│   └── styles/               # Global styles
├── [feature-name]/           # Feature-specific modules
│   ├── index.js              # Feature entry point
│   ├── components/           # Feature components
│   └── helpers/              # Feature helpers
└── rspack.config.js          # Build configuration
```

---

## Performance Rules (CRITICAL)

### 1. Minimal Loader Pattern

```javascript
// loader.js - Keep as small as possible (~2KB)
function loadScript() {
  const script = document.createElement('script');
  script.async = true;
  script.src = `${CDN_URL}/main.min.js`;
  document.head.appendChild(script);
}

// Load after page ready (non-blocking)
if (document.readyState === 'complete') {
  setTimeout(loadScript, 1);
} else {
  window.addEventListener('load', loadScript, false);
}
```

### 2. Lazy Loading Components

```javascript
import lazy from 'preact-lazy';

const HeavyComponent = lazy(() => import('./HeavyComponent'));
```

### 3. Tree Shaking

```javascript
// BAD: Import entire library
import * as utils from '@avada/utils';

// GOOD: Import only what you need
import {isEmpty} from '@avada/utils/lib/isEmpty';

// BAD: Barrel imports
import {formatDate, formatCurrency} from '../helpers';

// GOOD: Direct path imports
import formatDate from '../helpers/formatDate';
import formatCurrency from '../helpers/formatCurrency';
```

### 4. Bundle Size Limits

| Component | Target Size |
|-----------|-------------|
| Loader script | < 3KB gzipped |
| Main bundle | < 50KB gzipped |
| Feature chunk | < 30KB gzipped |
| Initial load total | < 60KB gzipped |

---

## Preact Patterns

### Use Preact Instead of React

```javascript
// Use preact directly
import {render} from 'preact';
import {useState, useEffect} from 'preact/hooks';

// Rspack aliases handle React compat:
// 'react' -> 'preact/compat'
// 'react-dom' -> 'preact/compat'
```

### Functional Components with Hooks

```javascript
import {useState, useEffect, useMemo, useCallback} from 'preact/hooks';

function Widget() {
  const [data, setData] = useState(null);

  useEffect(() => {
    fetchData().then(setData);
  }, []);

  return data ? <Display data={data} /> : null;
}
```

---

## Styling (Recommended Approach)

### Custom SCSS (Preferred)

```scss
// Lightweight custom styles with BEM
.widget {
  &__button {
    padding: 8px 16px;
    border: none;
    border-radius: 4px;
    background: var(--primary-color);
    color: white;
    cursor: pointer;

    &:hover {
      opacity: 0.9;
    }

    &--secondary {
      background: transparent;
      border: 1px solid var(--primary-color);
      color: var(--primary-color);
    }
  }
}
```

### CSS Variables for Theming

```scss
:root {
  --primary-color: #{$primaryColor};
  --text-color: #{$textColor};
  --bg-color: #{$backgroundColor};
}

.card {
  background: var(--bg-color);
  color: var(--text-color);
}
```

---

## Window Data Pattern

Storefront widgets receive data via global window object:

```javascript
const {
  shop,           // Shop configuration
  customer,       // Current customer data
  settings,       // Widget settings
  translation,    // i18n translations
} = window.APP_DATA || {};

// Always destructure with defaults
const {items = [], config = {}} = settings || {};
```

---

## Development Commands

```bash
# Development with watch
npm run watch

# Production build
npm run build

# Analyze bundle size
npm run build:analyze

# Development build (unminified)
npm run build:dev
```

---

## Checklist

### Before Commit

```
- No barrel imports (use direct paths)
- Heavy components lazy loaded
- Dynamic imports for conditional features
- Tree-shaking friendly imports
- No console.log in production
- Custom SCSS with BEM naming
- No UI library dependencies
```

### Bundle Size Check

```
- Run build:analyze
- Loader < 3KB gzipped
- No unexpected large chunks
- No duplicate dependencies
- All imports use direct paths
```

### Performance

```
- Loads after document ready
- Non-blocking script loading
- Retry logic with backoff
- Performance tracking in place
- No synchronous heavy operations
```

Overview

This skill provides concise guidance and patterns for building lightweight, customer-facing storefront widgets injected as scripttags. It focuses on Preact-based components, minimal loader scripts, lazy loading, and strict bundle-size targets to protect merchant storefront performance. Use these patterns to deliver fast, low-impact UI features that load non-blockingly and respect resource budgets.

How this skill works

The skill describes a minimal loader pattern that appends an async script after page load, Preact component patterns using hooks, and lightweight lazy-loading for heavy features. It enforces tree-shaking friendly imports, direct-path modules, and SCSS-based styling with CSS variables. Targets for gzipped sizes and chunking guide build and bundler choices to minimize runtime impact.

When to use it

  • Adding a customer-facing widget via a scripttag to a merchant storefront
  • Optimizing bundle size and load order for storefront UI elements
  • Implementing Preact components and hooks for lightweight widgets
  • Lazy-loading optional or heavy UI features to avoid blocking rendering
  • Auditing imports to ensure tree-shaking and no unnecessary UI libraries

Best practices

  • Keep the loader script under ~3KB gzipped and load after window 'load' to be non-blocking
  • Use Preact (or preact/compat) and functional hooks instead of React to reduce bundle size
  • Lazy-load heavy components with a lightweight loader (e.g., preact-lazy) and dynamic import
  • Avoid barrel imports; import direct paths so tree shaking can remove unused code
  • Style with custom SCSS/BEM and CSS variables; avoid third-party UI libraries
  • Enforce bundle targets: main < 50KB, feature chunks < 30KB, initial total < 60KB gzipped

Example use cases

  • Inject a lightweight product recommendation card that loads only when visible
  • Add a small signup modal that is lazy-loaded after user interaction
  • Implement a localized pricing badge using window-provided shop and translation data
  • Create a performance-safe upsell widget that honors strict bundle budgets
  • Build feature flags that dynamically import optional modules to keep initial bundle tiny

FAQ

How should the loader script be delivered?

Serve a minimal async loader (<3KB gzipped) that appends the main bundle after document ready to avoid blocking page render.

What bundler and UI library are recommended?

Use a fast bundler like rspack and Preact for UI. Aliases can map 'react' to 'preact/compat' if needed.

How do I keep bundle size under control?

Use direct-path imports, lazy-load heavy components, avoid UI libraries, analyze builds, and enforce the documented gzipped targets.