@quilted/create 0.3.2 → 0.3.3

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 (21) hide show
  1. package/CHANGELOG.md +105 -0
  2. package/build/esm/_virtual/index7.mjs +2 -2
  3. package/build/esm/_virtual/index8.mjs +2 -2
  4. package/build/esm/node_modules/.pnpm/dir-glob@3.0.1/node_modules/dir-glob/index.mjs +1 -1
  5. package/build/esm/node_modules/.pnpm/fast-glob@3.3.3/node_modules/fast-glob/out/utils/index.mjs +1 -1
  6. package/build/esnext/node_modules/.pnpm/@nodelib_fs.stat@2.0.5/node_modules/@nodelib/fs.stat/out/index.esnext +1 -1
  7. package/build/esnext/node_modules/.pnpm/@nodelib_fs.stat@2.0.5/node_modules/@nodelib/fs.stat/out/providers/async.esnext +1 -1
  8. package/build/esnext/node_modules/.pnpm/@nodelib_fs.stat@2.0.5/node_modules/@nodelib/fs.stat/out/providers/sync.esnext +1 -1
  9. package/build/esnext/node_modules/.pnpm/@nodelib_fs.stat@2.0.5/node_modules/@nodelib/fs.stat/out/settings.esnext +1 -1
  10. package/build/esnext/node_modules/.pnpm/@nodelib_fs.walk@1.2.8/node_modules/@nodelib/fs.walk/out/index.esnext +1 -1
  11. package/build/esnext/node_modules/.pnpm/@nodelib_fs.walk@1.2.8/node_modules/@nodelib/fs.walk/out/providers/async.esnext +1 -1
  12. package/build/esnext/node_modules/.pnpm/@nodelib_fs.walk@1.2.8/node_modules/@nodelib/fs.walk/out/providers/sync.esnext +1 -1
  13. package/build/esnext/node_modules/.pnpm/@nodelib_fs.walk@1.2.8/node_modules/@nodelib/fs.walk/out/settings.esnext +1 -1
  14. package/build/esnext/node_modules/.pnpm/fast-glob@3.3.3/node_modules/fast-glob/out/readers/stream.esnext +1 -1
  15. package/build/esnext/node_modules/.pnpm/fast-glob@3.3.3/node_modules/fast-glob/out/utils/stream.esnext +1 -1
  16. package/build/esnext/node_modules/.pnpm/prompts@2.4.2/node_modules/prompts/dist/prompts.esnext +1 -1
  17. package/build/esnext/node_modules/.pnpm/prompts@2.4.2/node_modules/prompts/lib/prompts.esnext +1 -1
  18. package/package.json +1 -1
  19. package/templates/app-basic/browser.tsx +20 -39
  20. package/templates/app-graphql/browser.tsx +20 -39
  21. package/templates/app-trpc/browser.tsx +20 -39
package/CHANGELOG.md CHANGED
@@ -1,5 +1,110 @@
1
1
  # @quilted/create
2
2
 
3
+ ## 0.3.3
4
+
5
+ ### Patch Changes
6
+
7
+ - [#890](https://github.com/lemonmade/quilt/pull/890) [`b0f2334`](https://github.com/lemonmade/quilt/commit/b0f23340945280c951998bf77b3be8b8df13338c) Thanks [@lemonmade](https://github.com/lemonmade)! - Redesign asset loading APIs for better performance and clearer structure.
8
+
9
+ ## Breaking changes
10
+
11
+ ### `@quilted/assets`: `BrowserAssetsEntry` redesigned
12
+
13
+ The `BrowserAssetsEntry` type has been completely restructured. The previous flat `scripts` and `styles` arrays have been replaced with structured `script` and `style` objects that separate the entry asset from its dependencies:
14
+
15
+ ```ts
16
+ // Before
17
+ interface BrowserAssetsEntry {
18
+ scripts: Asset[];
19
+ styles: Asset[];
20
+ }
21
+
22
+ // After
23
+ interface BrowserAssetsEntry {
24
+ script?: {
25
+ asset: Asset;
26
+ syncDependencies: readonly Asset[];
27
+ asyncDependencies: readonly Asset[];
28
+ };
29
+ style?: {
30
+ asset: Asset;
31
+ syncDependencies: readonly Asset[];
32
+ asyncDependencies: readonly Asset[];
33
+ };
34
+ }
35
+ ```
36
+
37
+ This separation enables the renderer to treat the entry script, its preloadable sync dependencies, and its async dependencies differently in the HTML output.
38
+
39
+ ### `@quilted/assets`: `BrowserAssets.modules()` return type changed
40
+
41
+ `modules()` now returns `readonly BrowserAssetsEntry[]` (one entry per module ID) instead of a single merged `BrowserAssetsEntry`:
42
+
43
+ ```ts
44
+ // Before
45
+ modules(modules: Iterable<...>, options?): BrowserAssetsEntry;
46
+
47
+ // After
48
+ modules(modules: Iterable<string>, options?): readonly BrowserAssetsEntry[];
49
+ ```
50
+
51
+ ### `@quilted/assets`: `BrowserAssetModuleSelector` removed
52
+
53
+ The `BrowserAssetModuleSelector` interface and the `modules` field on `BrowserAssetSelector` have been removed. If you want to get the asset details for modules in addition to the entrypoints, use `BrowserAssets.modules()` instead.
54
+
55
+ ### `@quilted/assets`: `AssetBuildManifest` module entry format changed
56
+
57
+ `AssetBuildManifest.modules` values changed from `number[]` to the new `AssetBuildModuleEntry` tuple type. The tuple uses positional slots for each asset category and is serialized in JSON as an object with numeric string keys (omitting empty positions):
58
+
59
+ ```ts
60
+ type AssetBuildModuleEntry = [
61
+ script?: number, // [0] entry JS chunk
62
+ style?: number, // [1] entry CSS file
63
+ scriptSync?: number[], // [2] sync JS dependency indices
64
+ styleSync?: number[], // [3] CSS from sync JS dependencies
65
+ scriptAsync?: number[], // [4] dynamic JS dependency indices
66
+ styleAsync?: number[], // [5] CSS from dynamic JS dependencies
67
+ ];
68
+ ```
69
+
70
+ ### `@quilted/browser`: `BrowserResponseAssets.get()` return type changed
71
+
72
+ `get()` now returns `string[]` (module IDs) instead of `BrowserAssetModuleSelector[]`.
73
+
74
+ ## New features
75
+
76
+ ### `@quilted/preact-browser`: `BrowserApp` class
77
+
78
+ A new `BrowserApp` class simplifies constructing and running a browser app. It handles waiting for the `#app` DOM element via `MutationObserver`, which is necessary now that the entry script runs with the `async` attribute:
79
+
80
+ ```ts
81
+ import {BrowserApp} from '@quilted/quilt/browser';
82
+ import {BrowserAppContext} from '~/context/browser.ts';
83
+ import {App} from './App.tsx';
84
+
85
+ const context = new BrowserAppContext();
86
+ const app = new BrowserApp(<App context={context} />, {context});
87
+ await app.hydrate();
88
+ ```
89
+
90
+ ## Render behavior changes
91
+
92
+ ### Entry script rendered as `async` module
93
+
94
+ The browser entry script is now rendered as `<script type="module" async>` instead of a blocking `<script type="module">`. This means the script no longer blocks HTML parsing, and does not wait for DOMContentLoaded. This change is meant to allow streaming HTML responses to begin executing JavaScript earlier.
95
+
96
+ ### Sync dependencies rendered as `modulepreload` links
97
+
98
+ Sync JS dependencies (previously rendered as additional `<script type="module">` tags) are now rendered as `<link rel="modulepreload">` hints. This tells the browser to fetch them eagerly without executing them, since the entry script will import them when it runs.
99
+
100
+ ### Stylesheets rendered after all script references
101
+
102
+ Entry and async stylesheets are now emitted from the `<HTMLTemplate.Assets async />` placeholder, after all script and modulepreload tags. This ensures the stylesheet `<link>` elements appear after all JS references in the HTML.
103
+
104
+ ### Asset deduplication across streamed chunks
105
+
106
+ Asset deduplication (preventing the same `src`/`href` from appearing more than once) now works across all streamed HTML chunks within a single response, not just within a single placeholder.
107
+
3
108
  ## 0.3.2
4
109
 
5
110
  ### Patch Changes
@@ -1,3 +1,3 @@
1
- var dirGlob = {exports: {}};
1
+ var utils = {};
2
2
 
3
- export { dirGlob as __module };
3
+ export { utils as __exports };
@@ -1,3 +1,3 @@
1
- var utils = {};
1
+ var dirGlob = {exports: {}};
2
2
 
3
- export { utils as __exports };
3
+ export { dirGlob as __module };
@@ -1,4 +1,4 @@
1
- import { __module as dirGlob } from '../../../../../_virtual/index7.mjs';
1
+ import { __module as dirGlob } from '../../../../../_virtual/index8.mjs';
2
2
  import path__default from 'node:path';
3
3
  import { __require as requirePathType } from '../../../path-type@4.0.0/node_modules/path-type/index.mjs';
4
4
 
@@ -1,4 +1,4 @@
1
- import { __exports as utils } from '../../../../../../../_virtual/index8.mjs';
1
+ import { __exports as utils } from '../../../../../../../_virtual/index7.mjs';
2
2
  import { __require as requireArray } from './array.mjs';
3
3
  import { __require as requireErrno } from './errno.mjs';
4
4
  import { __require as requireFs } from './fs.mjs';
@@ -1,4 +1,4 @@
1
- import { __exports as out } from '../../../../../../../_virtual/index10.esnext';
1
+ import { __exports as out } from '../../../../../../../_virtual/index11.esnext';
2
2
  import { __require as requireAsync } from './providers/async.esnext';
3
3
  import { __require as requireSync } from './providers/sync.esnext';
4
4
  import { __require as requireSettings } from './settings.esnext';
@@ -1,4 +1,4 @@
1
- import { __exports as async } from '../../../../../../../../_virtual/async3.esnext';
1
+ import { __exports as async } from '../../../../../../../../_virtual/async4.esnext';
2
2
 
3
3
  var hasRequiredAsync;
4
4
  function requireAsync() {
@@ -1,4 +1,4 @@
1
- import { __exports as sync } from '../../../../../../../../_virtual/sync3.esnext';
1
+ import { __exports as sync } from '../../../../../../../../_virtual/sync4.esnext';
2
2
 
3
3
  var hasRequiredSync;
4
4
  function requireSync() {
@@ -1,4 +1,4 @@
1
- import { __exports as settings } from '../../../../../../../_virtual/settings2.esnext';
1
+ import { __exports as settings } from '../../../../../../../_virtual/settings3.esnext';
2
2
  import { __require as requireFs } from './adapters/fs.esnext';
3
3
 
4
4
  var hasRequiredSettings;
@@ -1,4 +1,4 @@
1
- import { __exports as out } from '../../../../../../../_virtual/index11.esnext';
1
+ import { __exports as out } from '../../../../../../../_virtual/index10.esnext';
2
2
  import { __require as requireAsync } from './providers/async.esnext';
3
3
  import { __require as requireStream } from './providers/stream.esnext';
4
4
  import { __require as requireSync } from './providers/sync.esnext';
@@ -1,4 +1,4 @@
1
- import { __exports as async } from '../../../../../../../../_virtual/async4.esnext';
1
+ import { __exports as async } from '../../../../../../../../_virtual/async3.esnext';
2
2
  import { __require as requireAsync$1 } from '../readers/async.esnext';
3
3
 
4
4
  var hasRequiredAsync;
@@ -1,4 +1,4 @@
1
- import { __exports as sync } from '../../../../../../../../_virtual/sync4.esnext';
1
+ import { __exports as sync } from '../../../../../../../../_virtual/sync3.esnext';
2
2
  import { __require as requireSync$1 } from '../readers/sync.esnext';
3
3
 
4
4
  var hasRequiredSync;
@@ -1,4 +1,4 @@
1
- import { __exports as settings } from '../../../../../../../_virtual/settings3.esnext';
1
+ import { __exports as settings } from '../../../../../../../_virtual/settings2.esnext';
2
2
  import path__default from 'node:path';
3
3
  import { __require as requireOut } from '../../../../../@nodelib_fs.scandir@2.1.5/node_modules/@nodelib/fs.scandir/out/index.esnext';
4
4
 
@@ -1,4 +1,4 @@
1
- import { __exports as stream } from '../../../../../../../_virtual/stream3.esnext';
1
+ import { __exports as stream } from '../../../../../../../_virtual/stream2.esnext';
2
2
  import require$$0 from 'node:stream';
3
3
  import { __require as requireOut } from '../../../../../@nodelib_fs.stat@2.0.5/node_modules/@nodelib/fs.stat/out/index.esnext';
4
4
  import { __require as requireOut$1 } from '../../../../../@nodelib_fs.walk@1.2.8/node_modules/@nodelib/fs.walk/out/index.esnext';
@@ -1,4 +1,4 @@
1
- import { __exports as stream } from '../../../../../../../_virtual/stream2.esnext';
1
+ import { __exports as stream } from '../../../../../../../_virtual/stream3.esnext';
2
2
  import { __require as requireMerge2 } from '../../../../../merge2@1.4.1/node_modules/merge2/index.esnext';
3
3
 
4
4
  var hasRequiredStream;
@@ -1,4 +1,4 @@
1
- import { __exports as prompts } from '../../../../../../_virtual/prompts.esnext';
1
+ import { __exports as prompts } from '../../../../../../_virtual/prompts2.esnext';
2
2
  import { __require as requireElements } from './elements/index.esnext';
3
3
 
4
4
  var hasRequiredPrompts;
@@ -1,4 +1,4 @@
1
- import { __exports as prompts } from '../../../../../../_virtual/prompts2.esnext';
1
+ import { __exports as prompts } from '../../../../../../_virtual/prompts.esnext';
2
2
  import { __require as requireElements } from './elements/index.esnext';
3
3
 
4
4
  var hasRequiredPrompts;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@quilted/create",
3
3
  "type": "module",
4
- "version": "0.3.2",
4
+ "version": "0.3.3",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -1,45 +1,26 @@
1
1
  import './browser.css';
2
2
 
3
- import type {ComponentChild} from 'preact';
4
- import {hydrate} from '@quilted/quilt/browser';
3
+ import {BrowserApp} from '@quilted/quilt/browser';
5
4
 
6
5
  import {BrowserAppContext} from '~/context/browser.ts';
7
6
  import {App} from './App.tsx';
8
7
 
9
- class BrowserApp {
10
- /**
11
- * The app’s globally-available context.
12
- */
13
- readonly context: BrowserAppContext;
14
-
15
- /**
16
- * The app’s root JSX element, seeded with the necessary app context.
17
- */
18
- readonly rendered: ComponentChild;
19
-
20
- constructor() {
21
- this.context = new BrowserAppContext();
22
- this.rendered = <App context={this.context} />;
23
-
24
- // Makes key parts of the app available in the browser console.
25
- //
26
- // @example
27
- // ```js
28
- // // Log the current URL
29
- // console.log(globalThis.app.context.router.currentRequest.url);
30
- // ```
31
- Object.defineProperty(globalThis, 'app', {
32
- value: this,
33
- enumerable: false,
34
- configurable: true,
35
- writable: true,
36
- });
37
- }
38
-
39
- hydrate() {
40
- hydrate(this.rendered);
41
- }
42
- }
43
-
44
- const app = new BrowserApp();
45
- app.hydrate();
8
+ const context = new BrowserAppContext();
9
+
10
+ const app = new BrowserApp(<App context={context} />, {context});
11
+
12
+ // Makes key parts of the app available in the browser console.
13
+ //
14
+ // @example
15
+ // ```js
16
+ // // Log the current URL
17
+ // console.log(globalThis.app.context.router.currentRequest.url);
18
+ // ```
19
+ Object.defineProperty(globalThis, 'app', {
20
+ value: app,
21
+ enumerable: false,
22
+ configurable: true,
23
+ writable: true,
24
+ });
25
+
26
+ await app.hydrate();
@@ -1,46 +1,27 @@
1
1
  import './browser.css';
2
2
 
3
- import type {ComponentChild} from 'preact';
4
- import {hydrate} from '@quilted/quilt/browser';
3
+ import {BrowserApp} from '@quilted/quilt/browser';
5
4
 
6
5
  import {BrowserAppContext} from '~/context/browser.ts';
7
6
 
8
7
  import {App} from './App.tsx';
9
8
 
10
- class BrowserApp {
11
- /**
12
- * The app's globally-available context.
13
- */
14
- readonly context: BrowserAppContext;
15
-
16
- /**
17
- * The app's root JSX element, seeded with the necessary app context.
18
- */
19
- readonly rendered: ComponentChild;
20
-
21
- constructor() {
22
- this.context = new BrowserAppContext();
23
- this.rendered = <App context={this.context} />;
24
-
25
- // Makes key parts of the app available in the browser console.
26
- //
27
- // @example
28
- // ```js
29
- // // Log the current URL
30
- // console.log(globalThis.app.context.navigation.router.currentRequest.url);
31
- // ```
32
- Object.defineProperty(globalThis, 'app', {
33
- value: this,
34
- enumerable: false,
35
- configurable: true,
36
- writable: true,
37
- });
38
- }
39
-
40
- hydrate() {
41
- hydrate(this.rendered);
42
- }
43
- }
44
-
45
- const app = new BrowserApp();
46
- app.hydrate();
9
+ const context = new BrowserAppContext();
10
+
11
+ const app = new BrowserApp(<App context={context} />, {context});
12
+
13
+ // Makes key parts of the app available in the browser console.
14
+ //
15
+ // @example
16
+ // ```js
17
+ // // Log the current URL
18
+ // console.log(globalThis.app.context.navigation.router.currentRequest.url);
19
+ // ```
20
+ Object.defineProperty(globalThis, 'app', {
21
+ value: app,
22
+ enumerable: false,
23
+ configurable: true,
24
+ writable: true,
25
+ });
26
+
27
+ await app.hydrate();
@@ -1,46 +1,27 @@
1
1
  import './browser.css';
2
2
 
3
- import type {ComponentChild} from 'preact';
4
- import {hydrate} from '@quilted/quilt/browser';
3
+ import {BrowserApp} from '@quilted/quilt/browser';
5
4
 
6
5
  import {BrowserAppContext} from '~/context/browser.ts';
7
6
 
8
7
  import {App} from './App.tsx';
9
8
 
10
- class BrowserApp {
11
- /**
12
- * The app's globally-available context.
13
- */
14
- readonly context: BrowserAppContext;
15
-
16
- /**
17
- * The app's root JSX element, seeded with the necessary app context.
18
- */
19
- readonly rendered: ComponentChild;
20
-
21
- constructor() {
22
- this.context = new BrowserAppContext();
23
- this.rendered = <App context={this.context} />;
24
-
25
- // Makes key parts of the app available in the browser console.
26
- //
27
- // @example
28
- // ```js
29
- // // Log the current URL
30
- // console.log(globalThis.app.context.navigation.router.currentRequest.url);
31
- // ```
32
- Object.defineProperty(globalThis, 'app', {
33
- value: this,
34
- enumerable: false,
35
- configurable: true,
36
- writable: true,
37
- });
38
- }
39
-
40
- hydrate() {
41
- hydrate(this.rendered);
42
- }
43
- }
44
-
45
- const app = new BrowserApp();
46
- app.hydrate();
9
+ const context = new BrowserAppContext();
10
+
11
+ const app = new BrowserApp(<App context={context} />, {context});
12
+
13
+ // Makes key parts of the app available in the browser console.
14
+ //
15
+ // @example
16
+ // ```js
17
+ // // Log the current URL
18
+ // console.log(globalThis.app.context.navigation.router.currentRequest.url);
19
+ // ```
20
+ Object.defineProperty(globalThis, 'app', {
21
+ value: app,
22
+ enumerable: false,
23
+ configurable: true,
24
+ writable: true,
25
+ });
26
+
27
+ await app.hydrate();