| name | cf-b2b-website |
| description | Cloudflare Workers + D1 e-commerce site for Shengtuo Tractor. Deploy, DB ops, SEO, product sync. |
| triggers | ["cf-b2b-website","shengtuo tractor website","wrangler deploy","D1 database","sitemap.xml"] |
cf-b2b-website
Environment
| Item | Value |
|---|
| Worker | cf-b2b-website |
| D1 DB | b2b_database (remote) |
| KV | b2b_kv (contact form) |
| Deploy token | cfut_ZENfTsTx1akFdl... |
| URL | https://cf-b2b-website.sdtractor.workers.dev |
| Src | /home/ubuntu/cf_b2b/ |
Deploy
Normal deploy
cd /home/ubuntu/cf_b2b && CLOUDFLARE_API_TOKEN="cfut_..." npx wrangler deploy
Force redeploy (when cached/stale)
npx wrangler deploy --force
⚠️ Pitfall: wrangler deploy can exit 0 with NO visible output even on syntax errors. Always check output contains Uploaded and Deployed lines. If output is empty, check for JS syntax errors (e.g., duplicate const declarations) before retrying.
D1 Database
Batch SQL via file
npx wrangler d1 execute b2b_database --file=/tmp/sql.sql --remote
⚠️ Pitfall: D1 does NOT support BEGIN;...COMMIT; in file mode. Execute statements individually — each UPDATE/SET on its own line. No transactions.
Single query
npx wrangler d1 execute b2b_database --command="SELECT id, name FROM products LIMIT 5;" --remote
Product Catalog Sync (from shengtuo-tractor.com)
Site is Error 1016 (partially down) but browser still loads content — product images remain valid at shengtuo-tractor.com/uploadfile/ URLs.
Extract product list via browser console
[...document.querySelectorAll('ul.products_list li')].map(li => {
const a = li.querySelector('a[href$=".html"]');
const img = li.querySelector('img');
return a ? { name: a.title, href: a.href, img: img ? img.src : null } : null;
}).filter(Boolean)
Match strategy
Extract ST\d+[A-Z]* pattern from name to map site products → DB products by ID.
SQL generation pattern
UPDATE products SET image_url = 'https://www.shengtuo-tractor.com/uploadfile/FILE.jpg' WHERE id = N;
JS File Editing — CRITICAL
⚠️ NEVER use sed on .js files — corrupts template literal backtick nesting (\`` → raw `` ``).
⚠️ NEVER use echo heredoc to write .js files — same backtick corruption risk.
Always use patch() or write_file() only.
Common error this causes: inline <script> tags inside template literals get mangled, producing "has already been declared" or "unexpected token" build errors.
SEO Keyword Structure (100+ keywords in layout.js defaultKeywords)
Organized in src/pages/layout.js:
- Brand: China Shengtuo Tractor, Shengtuo Farm Tractor, Chinese Tractor Manufacturer, etc.
- Product HP (25–260HP): Compact Tractor, Mini Farm Tractor, Garden Tractor, Utility Tractor, Heavy Duty Farm Tractor
- Buyer intent: Farm Tractor for Sale, China Tractor Exporter, Wholesale Farm Tractor, Buy Farm Tractor
- Farm equipment: Rotary Tiller, Disc Harrow, Disc Plough, Front Loader, Backhoe Loader, Hay Baler
- Long-tail: 4WD Farm Tractor for Sale, Diesel Farm Tractor China, CE Farm Tractor Manufacturer, OEM Agricultural Tractor
- Model series: ST504, ST704, ST804, ST1154, ST1354, ST1604, ST1804, ST2204, ST2404 Tractor
- Country markets: Australia Tractor Supplier, South Africa Farm Tractor, Brazil Tractor Manufacturer, Romania Agricultural Tractor
Homepage Title Override Pattern (IMPORTANT)
createLayout uses isHome = (title === 'Home') to set special SEO title. When passing site_name (e.g. 'China Shengtuo Farm Tractor Manufacturer') instead of 'Home', pageTitlePrefix won't trigger and canonical breaks.
Always do this for homepage:
const homeTitle = 'China Shengtuo Farm Tractor Manufacturer | 25HP-260HP Agricultural Tractors & Farm Equipment';
const html = createLayout('Home', content, scripts, desc, false);
const finalHtml = html.replace('<title>Shengtuo Tractor</title>', `<title>${homeTitle}</title>`);
return new Response(finalHtml, { ... });
Canonical URL Logic
const isHome = title === 'Home';
const canonicalPath = isHome ? '/' : '/' + title.toLowerCase().replace(/\s+/g,'-').replace(/[^a-z0-9-/]/g,'');
Sitemap + Robots.txt
Both generated by src/pages/sitemap.js:
/sitemap.xml — 42 product URLs + 4 static pages
/robots.txt — allows all except /api/ and /admin/
Product Sort Order — FIX BOTH FILES
Products should show Tractors first, then Equipment. Both of these need the same SQL ORDER BY CASE pattern:
src/pages/products.js — server-rendered page
src/api/handlers/products.js — API endpoint
SQL pattern:
ORDER BY CASE WHEN category = 'SHENGTUO TRACTOR' THEN 1
WHEN category = 'SHENGTUO FARM EQUIPMENT' THEN 2
ELSE 3 END, name
⚠️ Pitfall: Even if products.js is fixed, if the API returns wrong order, pages that rely on API data will show wrong order. Fix BOTH files.
Product Detail Page Keywords
Build from DB fields dynamically:
const hp = product.hp_range || '';
const spec = product.key_spec || '';
metaKeywords = `${product.name}, Shengtuo ${category}, farm equipment, ${hp} tractor, agricultural machinery China, ${spec}`;
Tech Stack
- Cloudflare Workers (Pages-style routing via
router.js)
- D1 (SQLite) for product DB
- KV for contact form storage
- No build step — pure ES module
.js files