Slim CLAUDE.md from 65K to 21K by splitting app-specific docs
Move OpenClaw, Palmr, MinIO, JSX publishing, MCP configs, and migration candidates into dedicated docs/ files. Keep only DevOps-essential content inline (deployment rules, DNS, router, credentials, troubleshooting). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
99
docs/publishing-artifacts.md
Normal file
99
docs/publishing-artifacts.md
Normal file
@@ -0,0 +1,99 @@
|
||||
# Publishing JSX/React Artifacts Online
|
||||
|
||||
Single-file React components (JSX) can be published as standalone web pages via the NUC's artifacts infrastructure.
|
||||
|
||||
## How It Works
|
||||
|
||||
```
|
||||
Public Internet → Tailscale Funnel (:443) → Traefik → artifacts-web (nginx) → /opt/artifacts/
|
||||
```
|
||||
|
||||
- **Funnel URL:** `https://alezmad-nuc.tail58f5ad.ts.net/artifacts/<name>/`
|
||||
- **LAN URL:** `https://artifacts.nuc.lan/<name>/`
|
||||
- **Nginx container:** `artifacts-web` (image: `nginx:alpine`, read-only mount of `/opt/artifacts`)
|
||||
- **Traefik public route:** `Host(alezmad-nuc.tail58f5ad.ts.net) && PathPrefix(/artifacts)` → strips `/artifacts` → `artifacts-web:80`
|
||||
- **Config file:** `/traefik/dynamic/nuc-services-public.yaml` (inside `coolify-proxy` container)
|
||||
|
||||
## Quick Publish Steps
|
||||
|
||||
```bash
|
||||
# 1. Build self-contained HTML from JSX
|
||||
# - Replace `import { useState, ... } from "react"` with `const { useState, ... } = React;`
|
||||
# - Remove `export default ComponentName;`
|
||||
# - Wrap in HTML with React 18 CDN + Babel standalone
|
||||
# - Add `ReactDOM.createRoot(root).render(<Component />)` at the end
|
||||
|
||||
# 2. Copy to NUC artifacts directory
|
||||
ssh nuc "echo '7vXHpSTD.' | sudo -S mkdir -p /opt/artifacts/<name>"
|
||||
scp /tmp/build/index.html nuc:~/tmp-artifact.html
|
||||
ssh nuc "echo '7vXHpSTD.' | sudo -S mv ~/tmp-artifact.html /opt/artifacts/<name>/index.html"
|
||||
ssh nuc "echo '7vXHpSTD.' | sudo -S chmod 644 /opt/artifacts/<name>/index.html"
|
||||
|
||||
# 3. Done! No server restart needed — nginx serves it immediately.
|
||||
```
|
||||
|
||||
## HTML Template for JSX Files
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>TITLE</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
||||
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
|
||||
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
|
||||
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { background: #08090d; overflow-x: hidden; }
|
||||
/* Add any @keyframes or global styles here */
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="text/babel">
|
||||
const { useState, useEffect, useRef, useCallback } = React;
|
||||
|
||||
// ... paste JSX component code here (without import/export lines) ...
|
||||
|
||||
const root = ReactDOM.createRoot(document.getElementById('root'));
|
||||
root.render(React.createElement(ComponentName));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
## Build Script (for large JSX files)
|
||||
|
||||
```bash
|
||||
# Automated: strips import/export, wraps in HTML
|
||||
cat > /tmp/build.html << 'HEADER'
|
||||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
|
||||
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
|
||||
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
|
||||
</head><body><div id="root"></div>
|
||||
<script type="text/babel">
|
||||
const { useState, useEffect, useRef, useCallback, useMemo, useReducer } = React;
|
||||
HEADER
|
||||
|
||||
# Strip first line (import) and last line (export), append body
|
||||
sed -n '2,$p' source.jsx | sed '$d' >> /tmp/build.html
|
||||
|
||||
# Add render footer (replace COMPONENT_NAME)
|
||||
cat >> /tmp/build.html << 'FOOTER'
|
||||
const root = ReactDOM.createRoot(document.getElementById('root'));
|
||||
root.render(React.createElement(COMPONENT_NAME));
|
||||
</script></body></html>
|
||||
FOOTER
|
||||
```
|
||||
|
||||
## Currently Published
|
||||
|
||||
| Path | Source | Public URL |
|
||||
|------|--------|------------|
|
||||
| `/opt/artifacts/checkin/` | `arrio/.scratch/checkin_demo_v1.jsx` | `https://alezmad-nuc.tail58f5ad.ts.net/artifacts/checkin/` |
|
||||
Reference in New Issue
Block a user