wirejs-scripts 3.0.189 → 3.0.191

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.
Files changed (4) hide show
  1. package/README.md +323 -2
  2. package/bin.js +123 -33
  3. package/package.json +3 -3
  4. package/ssg.js +1 -7
package/README.md CHANGED
@@ -1,3 +1,324 @@
1
- Experimental.
1
+ # wirejs-scripts
2
2
 
3
- If this package interests you, contact the author.
3
+ > **Experimental:** WireJS is an experimental hobby project and is not production software. For a professionally supported project in a similar spirit, see [AWS Blocks](https://github.com/aws-devtools-labs/aws-blocks), which benefits from lessons and ideas explored here.
4
+
5
+ Experimental build and development commands for WireJS apps.
6
+
7
+ This package owns the CLI behavior behind the generated app scripts, including TypeScript bundling, local development serving, SSR/SSG processing, hydration bundles, static asset handling, and workspace helper commands.
8
+
9
+ ## Commands
10
+
11
+ Generated apps typically expose these through `package.json` scripts:
12
+
13
+ ```sh
14
+ npm run start # local development server + watch builds
15
+ npm run start:public # local development with public/NAT-PMP behavior when available
16
+ npm run build # production build
17
+ ```
18
+
19
+ The underlying CLI is `wirejs-scripts`.
20
+
21
+ ## Expected app layout
22
+
23
+ ```text
24
+ api/ API/resource workspace
25
+ src/ssr/ server-rendered request-time routes
26
+ src/ssg/ statically generated pages/artifacts
27
+ src/ shared source/components/layouts
28
+ static/ public static assets, served as /static/*
29
+ dist/ generated output
30
+ pre-dist/ intermediate build output
31
+ ```
32
+
33
+ ## SSR handling
34
+
35
+ Files under `src/ssr/` are compiled to `dist/ssr/`. At request time, WireJS hosting matches the request path to the best compiled SSR module and invokes its exported `generate(context)` function.
36
+
37
+ A minimal request-time route can return a plain body:
38
+
39
+ ```ts
40
+ // src/ssr/debug.txt.ts -> /debug.txt
41
+ import type { Context } from 'wirejs-resources';
42
+
43
+ export async function generate(context: Context) {
44
+ context.responseHeaders['cache-control'] = 'no-store';
45
+ return `Path: ${context.location.pathname}\n`;
46
+ }
47
+ ```
48
+
49
+ For non-HTML SSR responses, the hosting layer infers a `content-type` from the requested extension when possible. You can also set one explicitly through `context.responseHeaders`, which is recommended when you care about charset or a more specific MIME type:
50
+
51
+ ```ts
52
+ // src/ssr/feed.xml.ts -> /feed.xml
53
+ import type { Context } from 'wirejs-resources';
54
+
55
+ export async function generate(context: Context) {
56
+ context.responseHeaders['content-type'] = 'application/rss+xml; charset=utf-8';
57
+ context.responseHeaders['cache-control'] = 'max-age=300';
58
+
59
+ return `<?xml version="1.0" encoding="UTF-8"?>
60
+ <rss version="2.0"><channel><title>Example feed</title></channel></rss>`;
61
+ }
62
+ ```
63
+
64
+ ```ts
65
+ // src/ssr/manifest.json.ts -> /manifest.json
66
+ import type { Context } from 'wirejs-resources';
67
+
68
+ export async function generate(context: Context) {
69
+ context.responseHeaders['content-type'] = 'application/manifest+json; charset=utf-8';
70
+ return JSON.stringify({
71
+ name: 'Example app',
72
+ start_url: '/',
73
+ display: 'standalone',
74
+ }, null, 2);
75
+ }
76
+ ```
77
+
78
+ The examples in generated apps use `wirejs-dom/v2` for HTML. That is not required by `wirejs-scripts`, but it demonstrates the intended SSR + client-bundle flow:
79
+
80
+ ```ts
81
+ // src/ssr/counter.ts -> /counter
82
+ import { html, id, text, hydrate as wireHydrate } from 'wirejs-dom/v2';
83
+ import type { Context } from 'wirejs-resources';
84
+
85
+ function Counter(init: { count?: number } = {}) {
86
+ let count = init.count ?? 0;
87
+ const self = html`<button id="counter" ${id('button')}>
88
+ Clicked ${text('count', String(count))} times
89
+ </button>`;
90
+
91
+ self.data.button.onclick = () => {
92
+ count += 1;
93
+ self.data.count = String(count);
94
+ };
95
+
96
+ return self;
97
+ }
98
+
99
+ export async function generate(context: Context) {
100
+ return html`<html>
101
+ <head><title>Counter</title></head>
102
+ <body>${Counter({ count: Number(context.location.searchParams.get('count') ?? 0) })}</body>
103
+ </html>`;
104
+ }
105
+
106
+ export function onload() {
107
+ wireHydrate('counter', () => Counter());
108
+ }
109
+ ```
110
+
111
+ `generate()` is used for the server-side render. The exported `onload()` function is used as the browser entrypoint. This lets a module share selected components/functions between server generation and the client bundle while keeping server-only code inside `generate()` or behind server-only imports.
112
+
113
+ If `generate()` returns a DOM/document-like value, hosting serializes it as HTML. If it returns a string or other non-DOM body, hosting sends that body with a content type inferred from the requested extension when possible, unless `context.responseHeaders['content-type']` overrides it.
114
+
115
+ Routing notes:
116
+
117
+ - Request paths are matched against compiled `.js` files under `dist/ssr/`.
118
+ - `%` in an SSR filename acts as a wildcard pattern.
119
+ - Wildcard SSR routes use a canonical encoded client script path such as `/wild/%25.client.js`, so all instances of the route share one cacheable browser bundle.
120
+ - Direct `/ssr` and `/ssr/*` static-file access is blocked; SSR modules are executable server code, not public assets.
121
+ - If SSR code changes `context.location`, hosting can emit a redirect-style response when no explicit `responseCode` is set.
122
+ - Pre-extension filenames work for SSR non-HTML responses: `src/ssr/feed.xml.ts` compiles to a handler for `/feed.xml`; `src/ssr/data.json.ts` handles `/data.json`.
123
+
124
+ ## Client hydration bundles
125
+
126
+ SSR/SSG pages may register browser-side hydration through the DOM package used by the app. `wirejs-scripts` builds associated browser bundles for those pages so event handlers and client-only behavior can attach after generated HTML loads.
127
+
128
+ For SSR, the compiled server module lives under `dist/ssr/*.js` and the browser bundle is served through the corresponding `*.client.js` path when hydration is needed.
129
+
130
+ For SSG HTML outputs, `wirejs-scripts` emits a browser IIFE bundle for the page module. The generated HTML references that bundle only when the server/build module exports `onload()`. Non-HTML SSG outputs do not receive sibling browser JS bundles.
131
+
132
+ A useful pattern is to split code by what can safely run in both places:
133
+
134
+ ```ts
135
+ // shared: safe for server generation and browser hydration
136
+ function TodoList() { /* returns DOM and attaches browser-safe handlers */ }
137
+
138
+ // server-only: reads request context, private resources, secrets, etc.
139
+ export async function generate(context) {
140
+ const todos = await loadTodosFor(context);
141
+ return Page({ todos });
142
+ }
143
+
144
+ // browser-only entrypoint: attaches behavior to generated markup
145
+ export function onload() {
146
+ wireHydrate('todos', () => TodoList());
147
+ }
148
+ ```
149
+
150
+ Because the browser bundle starts from the exported `onload()` entrypoint, you can avoid pulling server-only dependencies into the client by keeping them out of the functions imported/called by `onload()`.
151
+
152
+ ## SSG handling
153
+
154
+ Files under `src/ssg/` are built and executed at build time. Each module's `generate()` output is written to `dist/` as a static artifact.
155
+
156
+ ```ts
157
+ // src/ssg/about.ts -> dist/about.html
158
+ import { html } from 'wirejs-dom/v2';
159
+
160
+ export async function generate() {
161
+ return html`<html><body><h1>About</h1></body></html>`;
162
+ }
163
+ ```
164
+
165
+ SSG uses the same shared-component pattern as SSR. For static HTML with browser behavior, export an `onload()` function from the page module and call your DOM library's hydration registration there. The server/build side calls `generate()` once, and the emitted client bundle imports the page module and calls exported `onload()` in the browser.
166
+
167
+ ### Non-HTML SSG outputs
168
+
169
+ SSG supports "pre-extension" filenames for generated assets that are not HTML:
170
+
171
+ ```ts
172
+ // src/ssg/feed.xml.ts -> dist/feed.xml
173
+ export async function generate() {
174
+ return `<?xml version="1.0" encoding="UTF-8"?>
175
+ <rss version="2.0"><channel><title>Example</title></channel></rss>`;
176
+ }
177
+ ```
178
+
179
+ ```ts
180
+ // src/ssg/manifest.json.ts -> dist/manifest.json
181
+ export async function generate() {
182
+ return {
183
+ name: 'Example app',
184
+ start_url: '/',
185
+ display: 'standalone',
186
+ };
187
+ }
188
+ ```
189
+
190
+ Convention:
191
+
192
+ - `src/ssg/page.ts` emits `dist/page.html`.
193
+ - `src/ssg/name.ext.ts` emits `dist/name.ext`.
194
+ - `.json` outputs are JSON-stringified when `generate()` returns an object.
195
+ - Other non-HTML outputs are stringified with `String(value)` unless `generate()` returns a string or buffer.
196
+ - Non-HTML outputs do not get hydration/client JS bundles.
197
+
198
+ Use SSG for pages or files that can be produced ahead of time. Use SSR for request-dependent content, per-user data, redirects, request-specific headers/cookies, or data that must be fresh on every request.
199
+
200
+ In local watch/start mode, `wirejs-scripts` watches source files and debounces SSG rebuilds. Rebuilds are queued so overlapping changes do not run multiple SSG builds concurrently.
201
+
202
+ ## Static files
203
+
204
+ Put public static assets in the app's top-level `static/` directory and reference them with root-relative `/static/...` URLs, for example:
205
+
206
+ ```html
207
+ <link rel="stylesheet" href="/static/default.css">
208
+ <img src="/static/images/logo.svg">
209
+ ```
210
+
211
+ Current behavior:
212
+
213
+ - Local development serves `/static/*` directly from the source `static/` directory.
214
+ - Production/build output expects static assets to be public under the `/static/` URL space.
215
+ - Static path resolution is normalized so requests cannot escape the intended static/dist root.
216
+ - Do not put private files in `static/`; it is public web content.
217
+
218
+ ## API and request handling
219
+
220
+ WireJS APIs are imported like ordinary TypeScript modules. Client code, SSR, and SSG should import from the app's API package and call functions directly; `wirejs-scripts` handles the client/server wiring, request protocol, serialization, and server execution.
221
+
222
+ In short: treat the API as a module that just happens to run on the server.
223
+
224
+ ```ts
225
+ // api/index.ts
226
+ export const todos = {
227
+ async list(userId: string) {
228
+ return [{ id: 't1', title: `Todo for ${userId}` }];
229
+ },
230
+ };
231
+ ```
232
+
233
+ ```ts
234
+ // src/ssg or src/ssr or browser/client code
235
+ import { todos } from 'internal-api';
236
+
237
+ const items = await todos.list('user-1');
238
+ ```
239
+
240
+ The generated client module preserves end-to-end TypeScript types without requiring app code to know the wire protocol. Do not manually call WireJS's internal API transport endpoints from app code. If you need a real URL/path for callers that are not using the WireJS module protocol, define a custom `Endpoint` resource in the API package.
241
+
242
+ Custom `Endpoint` is appropriate for:
243
+
244
+ - webhooks and third-party callbacks;
245
+ - OIDC/provider callback paths;
246
+ - custom admin/settings portals;
247
+ - compatibility routes for callers that cannot import the WireJS API package;
248
+ - serving non-API content from an API module, such as generated images, files, feeds, or health-check text.
249
+
250
+ The local server creates a `wirejs-resources` `Context` for each request, then routes through static handling, SSR, API, endpoint, and not-found behavior. API modules and endpoint handlers receive the same context model used by SSR.
251
+
252
+ ## Deployment config
253
+
254
+ Generated apps may include a top-level `deployment-config.ts` exporting `DeploymentConfig` from `wirejs-resources`. `wirejs-scripts` reads this file for build-time behavior, and deployment providers read the same file for hosting/infrastructure behavior.
255
+
256
+ `deployment-config.ts` is the provider-neutral place for build/deployment intent that should be supported consistently by hosting providers over time, including:
257
+
258
+ - runtime memory/timeout/Node version preferences;
259
+ - server bundle options such as bundled node modules, output format, and minification;
260
+ - extra SSG externals for modules that should remain external during static generation;
261
+ - branch/domain mapping;
262
+ - host redirects;
263
+ - DNS records.
264
+
265
+ Minimal build/runtime example:
266
+
267
+ ```ts
268
+ import { DeploymentConfig } from 'wirejs-resources';
269
+
270
+ export default {
271
+ runtimeDesiredMemoryMB: 1024,
272
+ runtimeNodeVersion: 22,
273
+ bundleNodeModules: ['jsdom'],
274
+ ssgExternalModules: ['sharp'],
275
+ } satisfies DeploymentConfig;
276
+ ```
277
+
278
+ Domain-oriented example:
279
+
280
+ ```ts
281
+ import { DeploymentConfig } from 'wirejs-resources';
282
+
283
+ export default {
284
+ domainsByBranch: {
285
+ main: 'staging.example.com',
286
+ prod: 'www.example.com',
287
+ '*': '{branch}.example.com',
288
+ },
289
+ redirects: [
290
+ { from: 'example.com', to: 'www.example.com', mode: 'permanent' },
291
+ { from: '{branch}.old.example.com', to: '{branch}.new.example.com' },
292
+ ],
293
+ dnsRecordsByBranch: {
294
+ main: [
295
+ { name: '@', zoneDomain: 'example.com', type: 'MX', values: ['1 aspmx.l.google.com.'] },
296
+ ],
297
+ '*': [
298
+ { name: '_verify.{branch}', zoneDomain: 'example.com', type: 'TXT', values: ['"ok-{branch}"'] },
299
+ ],
300
+ },
301
+ } satisfies DeploymentConfig;
302
+ ```
303
+
304
+ Provider-specific packages decide which fields they currently support and how those fields map to infrastructure. The intent is that new deployment providers should use the same `DeploymentConfig` surface whenever the concept applies.
305
+
306
+ ## Implemented deployments
307
+
308
+ Currently documented deployment provider:
309
+
310
+ - [`wirejs-deploy-cdk`](../wirejs-deploy-cdk/README.md) — AWS CDK deployment with Lambda, CloudFront, S3, DynamoDB, Cognito, custom domains, redirects, and Route53 DNS records.
311
+
312
+ When working in an installed app, prefer version-locked docs from `node_modules`:
313
+
314
+ ```sh
315
+ node -e "console.log(require.resolve('wirejs-deploy-cdk/package.json').replace(/package\.json$/, 'README.md'))"
316
+ ```
317
+
318
+ If browsing online, use npm as a secondary reference: <https://www.npmjs.com/package/wirejs-deploy-cdk>
319
+
320
+ ## Workspace helpers
321
+
322
+ Generated apps use `wirejs-scripts ws-run-parallel ...` to run matching scripts across workspaces during development.
323
+
324
+ WireJS is experimental. Expect breaking changes and prefer the README installed with your exact package version.
package/bin.js CHANGED
@@ -299,14 +299,7 @@ async function compile(watch = false) {
299
299
  const staticDir = path.join(CWD, 'static');
300
300
  const distDir = path.join(CWD, 'dist');
301
301
  const ssrOutDir = path.join(distDir, 'ssr');
302
-
303
- /**
304
- * Copy all files from src to dest recursively.
305
- */
306
- async function copyStatic() {
307
- if (!fs.existsSync(staticDir)) return;
308
- await fs.promises.cp(staticDir, distDir, { recursive: true });
309
- }
302
+ const preSsrClientWrapperDir = path.join(CWD, 'pre-dist', '.wirejs', 'ssr-client-wrappers');
310
303
 
311
304
  /**
312
305
  * Find all .ts files recursively in a directory.
@@ -334,6 +327,25 @@ async function compile(watch = false) {
334
327
  return explicitExt || 'html';
335
328
  }
336
329
 
330
+ async function createPageClientWrapper(sourceFile, sourceRoot, wrapperRoot) {
331
+ const relativeToSource = path.relative(sourceRoot, sourceFile);
332
+ const wrapperPath = path.join(wrapperRoot, relativeToSource);
333
+ await fs.promises.mkdir(path.dirname(wrapperPath), { recursive: true });
334
+
335
+ const rawImportPath = path.relative(path.dirname(wrapperPath), sourceFile).replace(/\\/g, '/');
336
+ const importPath = rawImportPath.startsWith('.') ? rawImportPath : `./${rawImportPath}`;
337
+ const wrapperSource = [
338
+ `import * as page from ${JSON.stringify(importPath)};`,
339
+ '',
340
+ 'if (typeof page["onload"] === "function") {',
341
+ '\tpage["onload"]();',
342
+ '}',
343
+ ].join('\n');
344
+
345
+ await fs.promises.writeFile(wrapperPath, wrapperSource, 'utf8');
346
+ return wrapperPath;
347
+ }
348
+
337
349
  /**
338
350
  * Build SSG files and write the generated HTML to dist/.
339
351
  * Also produces browser-compatible IIFE bundles at dist/*.js so that
@@ -344,15 +356,37 @@ async function compile(watch = false) {
344
356
  if (ssgFiles.length === 0) return;
345
357
 
346
358
  const preSsgDir = path.join(CWD, 'pre-dist', 'ssg');
359
+ const preSsgHydrateWrapperDir = path.join(CWD, 'pre-dist', '.wirejs', 'ssg-hydrate-wrappers');
347
360
  const preDist = path.join(CWD, 'pre-dist');
348
361
  const configuredSsgExternals = await resolveSsgExternals();
349
362
 
363
+
364
+ async function buildSsgHydrationIife(entryPoint, browserExternal) {
365
+ await esbuild.build({
366
+ entryPoints: [entryPoint],
367
+ outdir: distDir,
368
+ outbase: preSsgHydrateWrapperDir,
369
+ bundle: true,
370
+ treeShaking: true,
371
+ platform: 'browser',
372
+ format: 'iife',
373
+ conditions: ['wirejs:client'],
374
+ external: browserExternal,
375
+ sourcemap: true,
376
+ logOverride: {
377
+ 'import-is-undefined': 'silent',
378
+ },
379
+ });
380
+ }
381
+
350
382
  for (const ssgFile of ssgFiles) {
351
383
  const external = configuredSsgExternals;
352
384
  const browserExternal = Array.from(new Set([
353
385
  ...NODE_BUILTIN_EXTERNALS,
354
386
  ...configuredSsgExternals,
355
387
  ]));
388
+ const outputExtension = getSsgOutputExtension(ssgFile);
389
+ const compiledSsgFile = path.join(preSsgDir, path.relative(ssgDir, ssgFile)).replace(/\.[^.]+$/, '.js');
356
390
 
357
391
  // 1. Build server-side bundles (ESM, for ssg.js import()) into pre-dist/ssg/
358
392
  await esbuild.build({
@@ -362,23 +396,17 @@ async function compile(watch = false) {
362
396
  bundle: true,
363
397
  platform: 'node',
364
398
  format: 'esm',
399
+ treeShaking: true,
365
400
  conditions: ['wirejs:client'],
366
401
  external,
367
402
  });
368
403
 
369
- // 2. Build browser-side bundles (IIFE, for client hydration) into dist/
370
- // These are referenced by <script src="..."> tags injected by ssg.js.
371
- await esbuild.build({
372
- entryPoints: [ssgFile],
373
- outdir: distDir,
374
- outbase: ssgDir,
375
- bundle: true,
376
- platform: 'browser',
377
- format: 'iife',
378
- conditions: ['wirejs:client'],
379
- external: browserExternal,
380
- sourcemap: true,
381
- });
404
+ // 2. Build browser-side bundles only for HTML SSG outputs.
405
+ // Non-HTML artifacts should not emit a sibling .js bundle.
406
+ if (outputExtension === 'html') {
407
+ const clientWrapperFile = await createPageClientWrapper(ssgFile, ssgDir, preSsgHydrateWrapperDir);
408
+ await buildSsgHydrationIife(clientWrapperFile, browserExternal);
409
+ }
382
410
  }
383
411
 
384
412
  await Promise.all(ssgFiles.map(async ssgFile => {
@@ -472,19 +500,78 @@ async function compile(watch = false) {
472
500
  outbase: ssrDir,
473
501
  entryNames: '[dir]/[name]',
474
502
  bundle: true,
475
- platform: 'browser',
503
+ platform: 'node',
476
504
  format: 'esm',
477
505
  conditions: ['wirejs:client'],
478
506
  sourcemap: true,
479
507
  });
480
508
  await ssrCtx.rebuild();
481
509
  ssrCtx.watch();
510
+
511
+ const ssrClientWrapperFiles = await Promise.all(ssrFiles.map(ssrFile =>
512
+ createPageClientWrapper(ssrFile, ssrDir, preSsrClientWrapperDir)
513
+ ));
514
+ const ssrClientCtx = await esbuild.context({
515
+ entryPoints: ssrClientWrapperFiles,
516
+ outdir: ssrOutDir,
517
+ outbase: preSsrClientWrapperDir,
518
+ entryNames: '[dir]/[name].client',
519
+ bundle: true,
520
+ platform: 'browser',
521
+ format: 'esm',
522
+ conditions: ['wirejs:client'],
523
+ sourcemap: true,
524
+ logOverride: {
525
+ 'import-is-undefined': 'silent',
526
+ },
527
+ });
528
+ await ssrClientCtx.rebuild();
529
+ ssrClientCtx.watch();
482
530
  }
483
531
 
484
- // Static files
485
- await copyStatic();
486
- // SSG (run once; changes require a restart)
487
- await buildSsg();
532
+ // SSG watch (debounced + queued to avoid overlapping rebuilds)
533
+ let ssgBuildInProgress = false;
534
+ let ssgBuildQueued = false;
535
+ let ssgRebuildDebounce;
536
+
537
+ const runSsgBuild = async () => {
538
+ if (ssgBuildInProgress) {
539
+ ssgBuildQueued = true;
540
+ return;
541
+ }
542
+
543
+ ssgBuildInProgress = true;
544
+ try {
545
+ do {
546
+ ssgBuildQueued = false;
547
+ await buildSsg();
548
+ } while (ssgBuildQueued);
549
+ } finally {
550
+ ssgBuildInProgress = false;
551
+ }
552
+ };
553
+
554
+ await runSsgBuild();
555
+
556
+ if (fs.existsSync(srcDir)) {
557
+ fs.watch(srcDir, { recursive: true }, (_eventType, filename) => {
558
+ if (!filename) return;
559
+ const normalized = filename.replace(/\\/g, '/');
560
+
561
+ // Rebuild SSG when any source dependency changes, not just direct
562
+ // src/ssg/*.ts edits.
563
+ if (normalized.startsWith('ssr/')) return;
564
+ if (!/\.(ts|tsx|js|jsx|mjs|cjs|json|css)$/.test(normalized)) return;
565
+
566
+ if (ssgRebuildDebounce) clearTimeout(ssgRebuildDebounce);
567
+ ssgRebuildDebounce = setTimeout(() => {
568
+ ssgRebuildDebounce = undefined;
569
+ runSsgBuild().catch(error => {
570
+ logger.error('SSG rebuild failed', error);
571
+ });
572
+ }, 200);
573
+ });
574
+ }
488
575
 
489
576
  // NAT-PMP / --public flag
490
577
  if (actionArgs.includes('--public') || actionArgs.includes('-p')) {
@@ -514,6 +601,7 @@ async function compile(watch = false) {
514
601
  const server = wirejsCreateServer({
515
602
  apiDir: path.join(CWD, 'api'),
516
603
  distDir,
604
+ staticDir,
517
605
  port: httpPort,
518
606
  attributes: () => [
519
607
  new SystemAttribute('wirejs', 'deployment-type', {
@@ -575,24 +663,26 @@ async function compile(watch = false) {
575
663
  // preserveSymlinks: true,
576
664
  });
577
665
  // client bundle
666
+ const ssrClientWrapperFiles = await Promise.all(ssrFiles.map(ssrFile =>
667
+ createPageClientWrapper(ssrFile, ssrDir, preSsrClientWrapperDir)
668
+ ));
578
669
  await esbuild.build({
579
- entryPoints: ssrFiles,
670
+ entryPoints: ssrClientWrapperFiles,
580
671
  outdir: ssrOutDir,
581
- outbase: ssrDir,
672
+ outbase: preSsrClientWrapperDir,
582
673
  entryNames: '[dir]/[name].client',
583
674
  bundle: true,
584
675
  platform: 'browser',
585
- format: 'iife',
676
+ format: 'esm',
586
677
  conditions: ['wirejs:client'],
587
678
  sourcemap: true,
679
+ logOverride: {
680
+ 'import-is-undefined': 'silent',
681
+ },
588
682
  // preserveSymlinks: true,
589
683
  });
590
684
  }
591
685
 
592
- // Static files
593
- console.log('copying static files');
594
- await copyStatic();
595
-
596
686
  // SSG
597
687
  console.log('copying ssg files');
598
688
  await buildSsg();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wirejs-scripts",
3
- "version": "3.0.189",
3
+ "version": "3.0.191",
4
4
  "description": "Basic build and start commands for wirejs apps",
5
5
  "type": "module",
6
6
  "bin": {
@@ -28,7 +28,7 @@
28
28
  "node-cron": "^4.2.1",
29
29
  "rimraf": "^6.0.1",
30
30
  "wirejs-dom": "^1.0.44",
31
- "wirejs-hosting": "^0.1.191",
32
- "wirejs-resources": "^0.1.191"
31
+ "wirejs-hosting": "^0.1.193",
32
+ "wirejs-resources": "^0.1.193"
33
33
  }
34
34
  }
package/ssg.js CHANGED
@@ -36,13 +36,7 @@ async function build(filename, outputExtension = 'html') {
36
36
  const doc = generated;
37
37
  const doctype = doc?.parentNode?.doctype?.name || '';
38
38
 
39
- let hydrationsFound = 0;
40
- while (globalThis.pendingDehydrations?.length > 0) {
41
- globalThis.pendingDehydrations.shift()(doc);
42
- hydrationsFound++;
43
- }
44
-
45
- if (hydrationsFound) {
39
+ if (typeof module.onload === 'function') {
46
40
  const script = doc.parentNode.createElement('script');
47
41
  script.src = filename.substring((`${SRC_DIR}/ssg`).length);
48
42
  doc.parentNode.body.appendChild(script);