Skip to content

Commit f43b1e0

Browse files
author
Herve Tribouilloy
committed
first commit
0 parents  commit f43b1e0

67 files changed

Lines changed: 5845 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/release.yml

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
name: Build & publish widget
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*'
7+
workflow_dispatch:
8+
9+
jobs:
10+
release:
11+
runs-on: ubuntu-latest
12+
environment: reactedge
13+
14+
steps:
15+
- name: Checkout
16+
uses: actions/checkout@v4
17+
18+
- name: Setup Node
19+
uses: actions/setup-node@v4
20+
with:
21+
node-version: 20
22+
23+
- name: Install dependencies
24+
working-directory: vite_project
25+
run: npm install
26+
27+
- name: Build widget
28+
working-directory: vite_project
29+
run: npm run build
30+
31+
- name: Verify artifact exists
32+
run: |
33+
VERSION=$(node -p "require('./vite_project/package.json').version")
34+
test -f "www/widget-bannermulti@${VERSION}.iife.js"
35+
36+
- name: Setup SSH
37+
run: |
38+
mkdir -p ~/.ssh
39+
echo "${{ secrets.WIDGET_SSH_KEY }}" > ~/.ssh/id_ed25519
40+
chmod 600 ~/.ssh/id_ed25519
41+
42+
if [ -z "${{ secrets.WIDGET_SSH_HOST }}" ]; then
43+
echo "ERROR: WIDGET_SSH_HOST not set (environment secrets not visible)"
44+
exit 1
45+
fi
46+
47+
ssh-keyscan -H "${{ secrets.WIDGET_SSH_HOST }}" >> ~/.ssh/known_hosts
48+
49+
- name: Publish artifact
50+
run: |
51+
VERSION=$(node -p "require('./vite_project/package.json').version")
52+
ssh ${{ secrets.WIDGET_SSH_USER }}@${{ secrets.WIDGET_SSH_HOST }} \
53+
"mkdir -p /var/www/widgets/bannermulti"
54+
rsync -av \
55+
--chown=www-data:www-data \
56+
www/widget-bannermulti@${VERSION}.iife.js* \
57+
${{ secrets.WIDGET_SSH_USER }}@${{ secrets.WIDGET_SSH_HOST }}:/var/www/widgets/bannermulti/
58+
rsync -avz \
59+
www/cdn/ \
60+
${{ secrets.WIDGET_SSH_USER }}@${{ secrets.WIDGET_SSH_HOST }}:/var/www/widgets/bannermulti/cdn/

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.idea
2+
node_modules
3+
*.swp
4+
www
5+
.env
6+
widget.local.crt
7+
widget.local.key
8+
test-results

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 ReactEdge
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
# ReactEdge – Banner Widget
2+
3+
A small, embeddable **Banner (Unique Selling Points) widget** designed to be safely integrated into existing websites without owning the page or application lifecycle.
4+
5+
This widget is part of the **ReactEdge** initiative: a collection of frontend widgets built with a strong emphasis on isolation, reversibility, and clarity.
6+
7+
---
8+
9+
## What this is
10+
11+
- A lightweight frontend widget for displaying Banners
12+
- Designed to be embedded into existing platforms (e.g. legacy CMS, e-commerce sites)
13+
- Isolated by default (no global CSS or JS leakage)
14+
- Easy to install **and easy to remove**
15+
- Actively used and evolving
16+
17+
---
18+
19+
## What this is NOT
20+
21+
- ❌ A framework
22+
- ❌ A full design system
23+
- ❌ A conversion or growth “hack”
24+
- ❌ A replacement for CMS or backend logic
25+
- ❌ Opinionated about content or marketing strategy
26+
27+
This widget focuses on **delivery and safety**, not business promises.
28+
29+
---
30+
31+
## Design principles
32+
33+
- **Isolation first** – the widget does not assume ownership of the page or application
34+
- **Reversible by design** – removal should leave no trace on the host system
35+
- **Non-hostile to the host** – designed to coexist with existing themes and layouts rather than override them
36+
- **Minimal surface area** – only what is required to do the job
37+
- **Testable in isolation** – behaviour can be verified without the host platform
38+
- **Deferred by default** – does not require early page execution to function
39+
- **Layered structure** – organised to encourage consistency across ReactEdge widgets without enforcing a framework
40+
- **Boring on purpose** – clarity over cleverness
41+
- **Observable by the host** – key lifecycle and interaction events are emitted to allow integration with analytics or monitoring tools without coupling to a specific provider
42+
43+
---
44+
45+
## Project structure (high level)
46+
47+
This repository contains the widget itself, along with supporting tooling used for development, testing, and community maintenance.
48+
49+
- `vite_project/`
50+
Source code for the Banner widget and its build configuration.
51+
52+
- `tests/`
53+
End-to-end tests (Playwright) used to validate widget behaviour in a real browser environment.
54+
55+
- `docker/` and `docker-compose.yml`
56+
Optional local development tooling. These are provided for convenience and are not required to use the widget.
57+
58+
- `.github/`
59+
GitHub metadata (issue templates, CI workflows, etc.) to support collaboration and maintainability.
60+
61+
- `www/`
62+
Generated build output. This folder is intentionally not committed to the repository.
63+
64+
## Installation (high level)
65+
66+
The widget is delivered as a standalone JavaScript file and exposed via a custom element.
67+
68+
Typical usage looks like:
69+
70+
```html
71+
<script src="path-to-widget.js"></script>
72+
73+
<reactedge-banner-widget></reactedge-banner-widget>
74+
```
75+
76+
## Local development
77+
78+
This project uses Node.js and npm.
79+
80+
From the repository root:
81+
82+
```bash
83+
npm install
84+
```
85+
86+
To run the widget locally:
87+
88+
```bash
89+
cd vite_project
90+
npm install
91+
npm run dev
92+
```
93+
94+
To run the test suite:
95+
```bash
96+
npx playwright test --config=tests/playwright.dev.config.ts
97+
```
98+
99+
## Deploying the widget
100+
101+
ReactEdge widgets are deployed as **static JavaScript artefacts**.
102+
They do not require a server-side runtime once built.
103+
104+
### Build the artefact
105+
106+
From the `vite_project` directory:
107+
108+
```bash
109+
npm run build
110+
```
111+
112+
This produces a versioned JavaScript file in the www/ directory
113+
(e.g. widget-banner@x.y.z.iife.js).
114+
115+
The www/ Generated build output produced by the build process. This folder is intentionally not committed to the repository.
116+
117+
## CSS Isolation
118+
119+
ReactEdge widgets use PostCSS prefixing to guarantee style isolation
120+
when embedded into hostile environments such as WordPress or Magento.
121+
122+
All selectors are automatically scoped to a widget-specific root class.
123+
124+
### Example:
125+
Source CSS:
126+
```bash
127+
.slide { ... }
128+
```
129+
Production output:
130+
```bash
131+
.reactedge-banner .slide { ... }
132+
```
133+
134+
This prevents collisions with host themes or other plugins.

ROADMAP.md

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
2+
# Banner Widget – Image Compression Roadmap
3+
4+
The ReactEdge Banner Widget aims to provide a lightweight and flexible way to manage homepage banners without introducing friction between marketing and development teams.
5+
6+
A common issue with homepage banners is **image performance**. Large or poorly optimised images can negatively impact page speed and Lighthouse scores.
7+
8+
To address this problem, the banner widget introduces a progressive roadmap for **asynchronous image optimisation**.
9+
10+
The key principle is:
11+
12+
> Banner rendering must **never be blocked** by image optimisation.
13+
14+
Optimisation should always improve the system without introducing runtime fragility.
15+
16+
---
17+
18+
# Roadmap
19+
20+
| Phase | Title | Description | Notes |
21+
|------|------|-------------|------|
22+
| **Phase 1** | Compression Contract (Foundation) | Introduce a `compression` parameter in the banner `settings`. Supported values: `none`, `webp`, `avif`, `auto`. At this stage the widget accepts the parameter but performs no optimisation. The goal is to establish a stable contract and prepare the system for future optimisation workflows. | Safe foundation. No processing yet. |
23+
| **Phase 2** | MVP Compression (Manual Workflow) | Provide basic WebP compression using a manual workflow. Images can be compressed via CLI tools or a scheduled cron job. Once compressed images are produced, the banner contract can be manually updated to reference the optimised assets. The widget continues rendering normally even if compression has not yet occurred. | Low complexity. Demonstrates the concept and validates workflow. |
24+
| **Phase 3** | MVP v2 – Queue-based Compression | Introduce a queue-driven optimisation process. When compression is enabled, the system validates banner images and pushes optimisation jobs into a queue. Background workers generate WebP versions asynchronously. The original images remain active until the optimisation process completes. | First automated optimisation layer. |
25+
| **Phase 4** | Automated Asset Optimisation | Implement a full optimisation pipeline: automatic validation, compression generation (WebP/AVIF), contract state updates (`pending`, `optimised`, `valid`), and automatic activation of optimised assets. This optimisation capability becomes reusable across widgets (banner, gallery, CMS media). | Production-grade optimisation capability. |
26+
27+
---
28+
29+
# Banner Widget Contract (Extended)
30+
31+
Example contract including compression configuration:
32+
33+
```json
34+
{
35+
"data": {
36+
"slides": [
37+
{
38+
"image": {
39+
"src": "../banner-roofing-solutions.jpg",
40+
"srcset": "../banner-solutions.jpg 479w, ../banner-solutions-small.jpg 359w",
41+
"alt": "..."
42+
}
43+
},
44+
{
45+
"image": {
46+
"src": "../banner-example.jpg",
47+
"srcset": "../banner-example.jpg 479w, ../banner-example-small.jpg 359w",
48+
"alt": "..."
49+
}
50+
}
51+
]
52+
},
53+
"settings": {
54+
"mode": {
55+
"desktop": "static",
56+
"tablet": "slider",
57+
"mobile": "slider"
58+
},
59+
"height": "300px",
60+
"compression": "none"
61+
}
62+
}
63+
```
64+
65+
Supported compression modes:
66+
67+
```
68+
compression = "none" | "webp" | "avif" | "auto"
69+
```
70+
71+
---
72+
73+
# Architectural Principles
74+
75+
## Non-blocking optimisation
76+
77+
Banner rendering must **always work regardless of optimisation state**.
78+
79+
Images should render immediately, even if optimisation has not yet been performed.
80+
81+
---
82+
83+
## Contract-driven behaviour
84+
85+
Compression behaviour is controlled through the **banner contract**, ensuring transparency and predictability.
86+
87+
---
88+
89+
## Asynchronous improvement
90+
91+
Optimisation tasks are performed **outside the rendering path**, allowing improvements without affecting deployments or runtime stability.
92+
93+
---
94+
95+
# Future Extension (Optional)
96+
97+
Later versions may introduce optimisation status tracking.
98+
99+
Example:
100+
101+
```json
102+
"compression": {
103+
"mode": "webp",
104+
"status": "pending"
105+
}
106+
```
107+
108+
Possible states:
109+
110+
```
111+
pending
112+
optimised
113+
valid
114+
```
115+
116+
This would allow the system to automatically activate optimised assets once processing completes.
117+
118+
---
119+
120+
# Vision
121+
122+
The goal is simple:
123+
124+
**A homepage banner should never be the reason a website receives a poor Lighthouse score.**
125+
126+
By progressively introducing asynchronous optimisation, the ReactEdge Banner Widget enables teams to maintain performance while giving marketing teams full freedom to update campaigns independently.

docker-compose.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
services:
2+
nginx:
3+
image: nginx:1.27-alpine
4+
container_name: nginx_banner_multi_widget
5+
ports:
6+
- "8095:80"
7+
- "8456:443"
8+
volumes:
9+
- ./docker/nginx_vite/default.conf:/etc/nginx/conf.d/default.conf:ro
10+
- ./docker/nginx_vite/ssl:/etc/nginx/ssl:ro
11+
- ./www:/usr/share/nginx/html:ro
12+
restart: unless-stopped

0 commit comments

Comments
 (0)