create-what 0.11.7 → 0.11.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +123 -11
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -160,24 +160,37 @@ function generatePackageJson(packageName, { reactCompat, cssApproach, template }
|
|
|
160
160
|
// Full-stack apps are buildless: server.js does SSR + ISR and serves the
|
|
161
161
|
// client entry as native ES modules, so there is no Vite/compiler toolchain.
|
|
162
162
|
// `npm run dev` runs the real app with auto-restart on change.
|
|
163
|
+
// `what-devtools` is the browser bridge: without it the MCP server has nothing
|
|
164
|
+
// to talk to and every live tool reports no browser. In the SPA template the
|
|
165
|
+
// what-devtools-mcp Vite plugin injects it. The full-stack template is
|
|
166
|
+
// buildless and has no plugin to do the injecting, but it still needs the
|
|
167
|
+
// package present: server.js serves it over the import map in dev, the same
|
|
168
|
+
// way it already serves what-framework and what-core. Shipping the template
|
|
169
|
+
// with .mcp.json, .cursor/mcp.json and an MCP-promising CLAUDE.md while
|
|
170
|
+
// omitting the one package that makes any of it work is the worst combination,
|
|
171
|
+
// because the agent is primed to call tools that cannot answer.
|
|
163
172
|
const devDeps = template === 'fullstack'
|
|
164
173
|
? {
|
|
174
|
+
'what-devtools': whatVersionRange,
|
|
165
175
|
'what-devtools-mcp': whatVersionRange,
|
|
166
176
|
eslint: '^9.0.0',
|
|
167
177
|
'eslint-plugin-what': whatVersionRange,
|
|
178
|
+
typescript: '^5.6.0',
|
|
168
179
|
}
|
|
169
180
|
: {
|
|
170
181
|
vite: '^6.0.0',
|
|
171
182
|
'what-compiler': whatVersionRange,
|
|
183
|
+
'what-devtools': whatVersionRange,
|
|
172
184
|
'what-devtools-mcp': whatVersionRange,
|
|
173
185
|
'@babel/core': '^7.23.0',
|
|
174
186
|
eslint: '^9.0.0',
|
|
175
187
|
'eslint-plugin-what': whatVersionRange,
|
|
188
|
+
typescript: '^5.6.0',
|
|
176
189
|
};
|
|
177
190
|
|
|
178
191
|
const scripts = template === 'fullstack'
|
|
179
|
-
? { dev: 'node --watch server.js', start: 'node server.js', lint: 'eslint .' }
|
|
180
|
-
: { dev: 'vite', build: 'vite build', preview: 'vite preview', lint: 'eslint .' };
|
|
192
|
+
? { dev: 'node --watch server.js', start: 'node server.js', lint: 'eslint .', typecheck: 'tsc --noEmit' }
|
|
193
|
+
: { dev: 'vite', build: 'vite build', preview: 'vite preview', lint: 'eslint .', typecheck: 'tsc --noEmit' };
|
|
181
194
|
if (template === 'fullstack') {
|
|
182
195
|
deps['what-isr'] = whatVersionRange;
|
|
183
196
|
}
|
|
@@ -1179,6 +1192,31 @@ function matchPage(pathname) {
|
|
|
1179
1192
|
const vnode = matchPage(location.pathname);
|
|
1180
1193
|
if (vnode) hydrate(vnode, document.body);
|
|
1181
1194
|
|
|
1195
|
+
// Dev-only devtools bridge. This is what makes the \\\`what_*\\\` MCP tools in
|
|
1196
|
+
// CLAUDE.md able to see this running app: without it every live tool reports
|
|
1197
|
+
// "no browser connected". The SPA template gets this from the what-devtools-mcp
|
|
1198
|
+
// Vite plugin; this template is buildless, so it does the same three steps by
|
|
1199
|
+
// hand. server.js sets __WHAT_DEV__ and __WHAT_MCP__ in dev only, and the
|
|
1200
|
+
// imports are dynamic, so a production page never fetches either module.
|
|
1201
|
+
if (globalThis.__WHAT_DEV__) {
|
|
1202
|
+
Promise.all([
|
|
1203
|
+
import('what-core'),
|
|
1204
|
+
import('what-devtools'),
|
|
1205
|
+
]).then(async ([core, devtools]) => {
|
|
1206
|
+
// installDevTools alone makes the app inspectable in the browser. Connecting
|
|
1207
|
+
// to the MCP bridge is a second, optional step: it only happens once
|
|
1208
|
+
// \\\`npx what-devtools-mcp\\\` has run and written a token, so an app started
|
|
1209
|
+
// without the MCP server makes no connection attempts and logs nothing.
|
|
1210
|
+
devtools.installDevTools(core);
|
|
1211
|
+
if (globalThis.__WHAT_MCP__) {
|
|
1212
|
+
const mcp = await import('what-devtools-mcp/client');
|
|
1213
|
+
mcp.connectDevToolsMCP(globalThis.__WHAT_MCP__);
|
|
1214
|
+
}
|
|
1215
|
+
}).catch((err) => {
|
|
1216
|
+
console.warn('[what] devtools unavailable:', err.message);
|
|
1217
|
+
});
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1182
1220
|
// Progressive enhancement for server-action forms: submit as JSON to
|
|
1183
1221
|
// /__what_action with the X-What-Action header (the served-action protocol),
|
|
1184
1222
|
// then navigate to the result. The CSRF token comes from the double-submit
|
|
@@ -1300,7 +1338,7 @@ textarea {
|
|
|
1300
1338
|
|
|
1301
1339
|
import http from 'node:http';
|
|
1302
1340
|
import { randomBytes } from 'node:crypto';
|
|
1303
|
-
import { existsSync, statSync, createReadStream } from 'node:fs';
|
|
1341
|
+
import { existsSync, statSync, createReadStream, readFileSync } from 'node:fs';
|
|
1304
1342
|
import { extname, join, resolve } from 'node:path';
|
|
1305
1343
|
import { fileURLToPath } from 'node:url';
|
|
1306
1344
|
import { createRequestHandler, renderDocument, toNodeListener } from 'what-framework/server';
|
|
@@ -1370,15 +1408,52 @@ const importMap = {
|
|
|
1370
1408
|
imports: {
|
|
1371
1409
|
'what-framework': '/node_modules/what-framework/src/index.js',
|
|
1372
1410
|
'what-core': '/node_modules/what-core/src/index.js',
|
|
1411
|
+
// Dev only. This template is buildless, so there is no Vite plugin to inject
|
|
1412
|
+
// the devtools bridge the way the SPA template gets it. Mapping the two
|
|
1413
|
+
// specifiers here (and serving them below) is all it takes for the MCP
|
|
1414
|
+
// \`what_*\` tools to see this app: entry-client.js dynamically imports them
|
|
1415
|
+
// behind the __WHAT_DEV__ flag, so production never fetches either module.
|
|
1416
|
+
...(isProd ? {} : {
|
|
1417
|
+
'what-devtools': '/node_modules/what-devtools/src/index.js',
|
|
1418
|
+
'what-devtools-mcp/client': '/node_modules/what-devtools-mcp/src/client.js',
|
|
1419
|
+
}),
|
|
1373
1420
|
},
|
|
1374
1421
|
};
|
|
1375
1422
|
|
|
1423
|
+
// The MCP bridge writes its token here when \`npx what-devtools-mcp\` starts.
|
|
1424
|
+
// Read per render, not once at boot, so starting the bridge after the server is
|
|
1425
|
+
// already up only costs a page reload.
|
|
1426
|
+
//
|
|
1427
|
+
// The token is passed INLINE rather than via the Vite plugin's same-origin
|
|
1428
|
+
// discovery endpoint, which this server does not implement. That is deliberate:
|
|
1429
|
+
// the client only probes for a bridge when it has a token or a discovery URL, so
|
|
1430
|
+
// an app running without the MCP server makes no requests and logs nothing at
|
|
1431
|
+
// all. Handing it a discovery URL that 404s would put a red line in every
|
|
1432
|
+
// developer's console on every page load.
|
|
1433
|
+
function mcpToken() {
|
|
1434
|
+
try {
|
|
1435
|
+
return JSON.parse(readFileSync(join(ROOT, 'node_modules', '.cache', 'what-devtools-mcp', 'token'), 'utf8')).token || '';
|
|
1436
|
+
} catch {
|
|
1437
|
+
return '';
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
function devToolsHead() {
|
|
1442
|
+
if (isProd) return '';
|
|
1443
|
+
const token = mcpToken();
|
|
1444
|
+
if (!token) return '<script>globalThis.__WHAT_DEV__=true</script>';
|
|
1445
|
+
return \`<script>globalThis.__WHAT_DEV__=true;globalThis.__WHAT_MCP__=\${JSON.stringify({ port: 9229, token })}</script>\`;
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1376
1448
|
const documentOptions = {
|
|
1377
1449
|
clientEntry: '/src/entry-client.js',
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1450
|
+
// A getter, so devToolsHead() re-reads the token on every render.
|
|
1451
|
+
get head() {
|
|
1452
|
+
return \`<script type="importmap">\${JSON.stringify(importMap)}</script>\` +
|
|
1453
|
+
devToolsHead() +
|
|
1454
|
+
'<link rel="stylesheet" href="/src/styles.css">' +
|
|
1455
|
+
'<link rel="icon" type="image/svg+xml" href="/favicon.svg">';
|
|
1456
|
+
},
|
|
1382
1457
|
};
|
|
1383
1458
|
|
|
1384
1459
|
// Render a matched route. Mirrors the framework default renderer, plus:
|
|
@@ -1437,6 +1512,9 @@ const SERVED_PREFIXES = [
|
|
|
1437
1512
|
'/src/components/', // client-shared UI (create as needed)
|
|
1438
1513
|
'/node_modules/what-framework/',
|
|
1439
1514
|
'/node_modules/what-core/',
|
|
1515
|
+
// Dev only: the devtools bridge entry-client imports when __WHAT_DEV__ is set.
|
|
1516
|
+
// Gated on isProd so a production deploy never serves dev tooling.
|
|
1517
|
+
...(isProd ? [] : ['/node_modules/what-devtools/', '/node_modules/what-devtools-mcp/']),
|
|
1440
1518
|
];
|
|
1441
1519
|
|
|
1442
1520
|
function resolveStaticFile(pathname) {
|
|
@@ -1518,6 +1596,40 @@ async function main() {
|
|
|
1518
1596
|
},
|
|
1519
1597
|
}, null, 2) + '\n');
|
|
1520
1598
|
|
|
1599
|
+
const isFullstack = options.template === 'fullstack';
|
|
1600
|
+
|
|
1601
|
+
// The two templates have different authoring models: the SPA compiles JSX
|
|
1602
|
+
// through Vite + what-compiler, the full-stack template is buildless and has
|
|
1603
|
+
// neither. An agent told to write JSX in the full-stack app writes code that
|
|
1604
|
+
// cannot run.
|
|
1605
|
+
const authoringNotes = isFullstack
|
|
1606
|
+
? `Components run ONCE. This is the buildless full-stack template: \`server.js\` renders
|
|
1607
|
+
file routes and serves \`src/\` as native ES modules. There is **no compiler and no JSX**:
|
|
1608
|
+
write views with \`h()\` and pass \`() => ...\` for anything reactive.
|
|
1609
|
+
|
|
1610
|
+
\`\`\`js
|
|
1611
|
+
h('p', {}, () => \`Count: \${count()}\`)
|
|
1612
|
+
\`\`\`
|
|
1613
|
+
|
|
1614
|
+
Pages live in \`src/pages/\` and export \`page\` (route config), \`loader\` (server data), and a
|
|
1615
|
+
default component. \`src/db.js\`, \`src/routes.js\` and \`src/actions/\` are server-only: they are
|
|
1616
|
+
importable by Node but never served to the browser.`
|
|
1617
|
+
: `Components run ONCE. This is the SPA template: Vite + \`what-compiler\` compile JSX into
|
|
1618
|
+
fine-grained DOM operations, so write JSX and use \`() => ...\` for reactive text.
|
|
1619
|
+
|
|
1620
|
+
\`\`\`jsx
|
|
1621
|
+
<p>{() => \`Count: \${count()}\`}</p>
|
|
1622
|
+
\`\`\`
|
|
1623
|
+
`;
|
|
1624
|
+
|
|
1625
|
+
const mcpIntro = isFullstack
|
|
1626
|
+
? `This project includes MCP devtools that connect to the running app in the browser.
|
|
1627
|
+
The SPA template gets the bridge from a Vite plugin; this template is buildless, so
|
|
1628
|
+
\`src/entry-client.js\` imports it directly when \`server.js\` sets \`__WHAT_DEV__\` (dev only).
|
|
1629
|
+
Run \`npm run dev\`, open the app, then use the live \`what_*\` tools below. \`what_lint\`,
|
|
1630
|
+
\`what_scaffold\` and \`what_fix\` also work offline with no browser at all.`
|
|
1631
|
+
: `This project includes MCP devtools that connect to the running app in the browser.`;
|
|
1632
|
+
|
|
1521
1633
|
// CLAUDE.md — agent instructions for Claude Code (also useful for other AI tools)
|
|
1522
1634
|
writeFileSync(resolve(root, 'CLAUDE.md'), `# ${packageName}
|
|
1523
1635
|
|
|
@@ -1537,13 +1649,13 @@ const doubled = computed(() => count() * 2); // derived
|
|
|
1537
1649
|
effect(() => console.log(count())); // side effect
|
|
1538
1650
|
\`\`\`
|
|
1539
1651
|
|
|
1540
|
-
|
|
1652
|
+
${authoringNotes}
|
|
1541
1653
|
|
|
1542
1654
|
**Signal scope:** \`signal()\` works anywhere — module scope (shared state), component scope (local state). Components run once, so signal declarations execute exactly once.
|
|
1543
1655
|
|
|
1544
1656
|
## MCP DevTools
|
|
1545
1657
|
|
|
1546
|
-
|
|
1658
|
+
${mcpIntro}
|
|
1547
1659
|
|
|
1548
1660
|
### Quick Start (First 5 Minutes)
|
|
1549
1661
|
|
|
@@ -1577,7 +1689,7 @@ This project includes MCP devtools that connect to the running app in the browse
|
|
|
1577
1689
|
| Change a signal live | \`what_set_signal {signalId, value}\` |
|
|
1578
1690
|
| Validate code before saving | \`what_lint {code}\` |
|
|
1579
1691
|
| Generate boilerplate | \`what_scaffold {type, name}\` |
|
|
1580
|
-
| Diagnose an error code | \`what_fix {
|
|
1692
|
+
| Diagnose an error code | \`what_fix {error}\` |
|
|
1581
1693
|
|
|
1582
1694
|
### Workflows
|
|
1583
1695
|
|
|
@@ -1792,7 +1904,7 @@ export default [
|
|
|
1792
1904
|
esModuleInterop: true,
|
|
1793
1905
|
resolveJsonModule: true,
|
|
1794
1906
|
isolatedModules: true,
|
|
1795
|
-
types: ['vite/client'],
|
|
1907
|
+
...(isFullstack ? {} : { types: ['vite/client'] }),
|
|
1796
1908
|
},
|
|
1797
1909
|
include: ['src'],
|
|
1798
1910
|
}, null, 2) + '\n');
|