fuzor 0.4.0 → 0.5.1
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/README.md +36 -88
- package/dist/boundaries.d.ts +5 -0
- package/dist/boundaries.d.ts.map +1 -0
- package/dist/boundaries.js +5 -0
- package/dist/boundaries.js.map +1 -0
- package/dist/browser.d.ts +4 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +4 -0
- package/dist/browser.js.map +1 -0
- package/dist/build-output.d.ts +18 -0
- package/dist/build-output.d.ts.map +1 -0
- package/dist/build-output.js +91 -0
- package/dist/build-output.js.map +1 -0
- package/dist/cli.js +388 -34
- package/dist/cli.js.map +1 -1
- package/dist/compiler/api-routes.d.ts +14 -0
- package/dist/compiler/api-routes.d.ts.map +1 -0
- package/dist/compiler/api-routes.js +66 -0
- package/dist/compiler/api-routes.js.map +1 -0
- package/dist/compiler/base-links.d.ts +7 -0
- package/dist/compiler/base-links.d.ts.map +1 -0
- package/dist/compiler/base-links.js +40 -0
- package/dist/compiler/base-links.js.map +1 -0
- package/dist/compiler/data-document.d.ts +9 -0
- package/dist/compiler/data-document.d.ts.map +1 -0
- package/dist/compiler/data-document.js +21 -0
- package/dist/compiler/data-document.js.map +1 -0
- package/dist/compiler/docs.d.ts +6 -0
- package/dist/compiler/docs.d.ts.map +1 -0
- package/dist/compiler/docs.js +1131 -0
- package/dist/compiler/docs.js.map +1 -0
- package/dist/compiler/highlight.d.ts +13 -0
- package/dist/compiler/highlight.d.ts.map +1 -0
- package/dist/compiler/highlight.js +44 -0
- package/dist/compiler/highlight.js.map +1 -0
- package/dist/compiler/index.d.ts +132 -4
- package/dist/compiler/index.d.ts.map +1 -1
- package/dist/compiler/index.js +845 -48
- package/dist/compiler/index.js.map +1 -1
- package/dist/compiler/inline-assets.d.ts +6 -0
- package/dist/compiler/inline-assets.d.ts.map +1 -0
- package/dist/compiler/inline-assets.js +61 -0
- package/dist/compiler/inline-assets.js.map +1 -0
- package/dist/compiler/inline-modules.d.ts +7 -0
- package/dist/compiler/inline-modules.d.ts.map +1 -0
- package/dist/compiler/inline-modules.js +77 -0
- package/dist/compiler/inline-modules.js.map +1 -0
- package/dist/compiler/island-modules.d.ts +8 -0
- package/dist/compiler/island-modules.d.ts.map +1 -0
- package/dist/compiler/island-modules.js +42 -0
- package/dist/compiler/island-modules.js.map +1 -0
- package/dist/compiler/islands.d.ts +24 -3
- package/dist/compiler/islands.d.ts.map +1 -1
- package/dist/compiler/islands.js +50 -12
- package/dist/compiler/islands.js.map +1 -1
- package/dist/compiler/links.d.ts +37 -0
- package/dist/compiler/links.d.ts.map +1 -0
- package/dist/compiler/links.js +112 -0
- package/dist/compiler/links.js.map +1 -0
- package/dist/compiler/markdown.d.ts +17 -0
- package/dist/compiler/markdown.d.ts.map +1 -0
- package/dist/compiler/markdown.js +92 -0
- package/dist/compiler/markdown.js.map +1 -0
- package/dist/compiler/metadata.d.ts +37 -0
- package/dist/compiler/metadata.d.ts.map +1 -0
- package/dist/compiler/metadata.js +81 -0
- package/dist/compiler/metadata.js.map +1 -0
- package/dist/compiler/native-scripts.d.ts +13 -0
- package/dist/compiler/native-scripts.d.ts.map +1 -0
- package/dist/compiler/native-scripts.js +137 -0
- package/dist/compiler/native-scripts.js.map +1 -0
- package/dist/compiler/page-scripts.d.ts +36 -0
- package/dist/compiler/page-scripts.d.ts.map +1 -0
- package/dist/compiler/page-scripts.js +158 -0
- package/dist/compiler/page-scripts.js.map +1 -0
- package/dist/compiler/route-policy.d.ts +17 -0
- package/dist/compiler/route-policy.d.ts.map +1 -0
- package/dist/compiler/route-policy.js +68 -0
- package/dist/compiler/route-policy.js.map +1 -0
- package/dist/compiler/search.d.ts +13 -0
- package/dist/compiler/search.d.ts.map +1 -0
- package/dist/compiler/search.js +24 -0
- package/dist/compiler/search.js.map +1 -0
- package/dist/compiler/server-modules.d.ts +3 -0
- package/dist/compiler/server-modules.d.ts.map +1 -0
- package/dist/compiler/server-modules.js +31 -0
- package/dist/compiler/server-modules.js.map +1 -0
- package/dist/compiler/static-analysis.d.ts +20 -0
- package/dist/compiler/static-analysis.d.ts.map +1 -0
- package/dist/compiler/static-analysis.js +130 -0
- package/dist/compiler/static-analysis.js.map +1 -0
- package/dist/create-delegate.d.ts +17 -0
- package/dist/create-delegate.d.ts.map +1 -0
- package/dist/create-delegate.js +48 -0
- package/dist/create-delegate.js.map +1 -0
- package/dist/electron.d.ts +5 -0
- package/dist/electron.d.ts.map +1 -0
- package/dist/electron.js +32 -0
- package/dist/electron.js.map +1 -0
- package/dist/html-escape.d.ts +16 -0
- package/dist/html-escape.d.ts.map +1 -0
- package/dist/html-escape.js +26 -0
- package/dist/html-escape.js.map +1 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/islands/hydration.d.ts +7 -0
- package/dist/islands/hydration.d.ts.map +1 -0
- package/dist/islands/hydration.js +12 -0
- package/dist/islands/hydration.js.map +1 -0
- package/dist/islands/react.d.ts +9 -2
- package/dist/islands/react.d.ts.map +1 -1
- package/dist/islands/react.js +73 -14
- package/dist/islands/react.js.map +1 -1
- package/dist/islands/solid.d.ts.map +1 -1
- package/dist/islands/solid.js +10 -1
- package/dist/islands/solid.js.map +1 -1
- package/dist/islands/vue.d.ts.map +1 -1
- package/dist/islands/vue.js +15 -3
- package/dist/islands/vue.js.map +1 -1
- package/dist/module-specifiers.d.ts +5 -0
- package/dist/module-specifiers.d.ts.map +1 -0
- package/dist/module-specifiers.js +80 -0
- package/dist/module-specifiers.js.map +1 -0
- package/dist/route-path.d.ts +33 -0
- package/dist/route-path.d.ts.map +1 -0
- package/dist/route-path.js +81 -0
- package/dist/route-path.js.map +1 -0
- package/dist/route-patterns.d.ts +8 -0
- package/dist/route-patterns.d.ts.map +1 -0
- package/dist/route-patterns.js +84 -0
- package/dist/route-patterns.js.map +1 -0
- package/dist/runtime/activation.d.ts +29 -0
- package/dist/runtime/activation.d.ts.map +1 -0
- package/dist/runtime/activation.js +236 -0
- package/dist/runtime/activation.js.map +1 -0
- package/dist/runtime/browser-navigation.d.ts +20 -0
- package/dist/runtime/browser-navigation.d.ts.map +1 -0
- package/dist/runtime/browser-navigation.js +138 -0
- package/dist/runtime/browser-navigation.js.map +1 -0
- package/dist/runtime/browser-support.d.ts +20 -0
- package/dist/runtime/browser-support.d.ts.map +1 -0
- package/dist/runtime/browser-support.js +39 -0
- package/dist/runtime/browser-support.js.map +1 -0
- package/dist/runtime/capacitor.d.ts +43 -0
- package/dist/runtime/capacitor.d.ts.map +1 -0
- package/dist/runtime/capacitor.js +84 -0
- package/dist/runtime/capacitor.js.map +1 -0
- package/dist/runtime/client-routes.d.ts +4 -0
- package/dist/runtime/client-routes.d.ts.map +1 -0
- package/dist/runtime/client-routes.js +3 -0
- package/dist/runtime/client-routes.js.map +1 -0
- package/dist/runtime/coordinated-navigation.d.ts +7 -0
- package/dist/runtime/coordinated-navigation.d.ts.map +1 -0
- package/dist/runtime/coordinated-navigation.js +50 -0
- package/dist/runtime/coordinated-navigation.js.map +1 -0
- package/dist/runtime/coordinator.d.ts +32 -0
- package/dist/runtime/coordinator.d.ts.map +1 -0
- package/dist/runtime/coordinator.js +115 -0
- package/dist/runtime/coordinator.js.map +1 -0
- package/dist/runtime/data.d.ts +25 -0
- package/dist/runtime/data.d.ts.map +1 -0
- package/dist/runtime/data.js +115 -0
- package/dist/runtime/data.js.map +1 -0
- package/dist/runtime/docs-search.d.ts +13 -0
- package/dist/runtime/docs-search.d.ts.map +1 -0
- package/dist/runtime/docs-search.js +205 -0
- package/dist/runtime/docs-search.js.map +1 -0
- package/dist/runtime/docs-ui.d.ts +7 -0
- package/dist/runtime/docs-ui.d.ts.map +1 -0
- package/dist/runtime/docs-ui.js +85 -0
- package/dist/runtime/docs-ui.js.map +1 -0
- package/dist/runtime/document-navigation.d.ts +9 -0
- package/dist/runtime/document-navigation.d.ts.map +1 -0
- package/dist/runtime/document-navigation.js +27 -0
- package/dist/runtime/document-navigation.js.map +1 -0
- package/dist/runtime/dom-renderer.d.ts +36 -0
- package/dist/runtime/dom-renderer.d.ts.map +1 -0
- package/dist/runtime/dom-renderer.js +173 -0
- package/dist/runtime/dom-renderer.js.map +1 -0
- package/dist/runtime/hash-navigation.d.ts +12 -0
- package/dist/runtime/hash-navigation.d.ts.map +1 -0
- package/dist/runtime/hash-navigation.js +26 -0
- package/dist/runtime/hash-navigation.js.map +1 -0
- package/dist/runtime/history-navigation.d.ts +17 -0
- package/dist/runtime/history-navigation.d.ts.map +1 -0
- package/dist/runtime/history-navigation.js +172 -0
- package/dist/runtime/history-navigation.js.map +1 -0
- package/dist/runtime/href.d.ts +16 -0
- package/dist/runtime/href.d.ts.map +1 -0
- package/dist/runtime/href.js +38 -0
- package/dist/runtime/href.js.map +1 -0
- package/dist/runtime/index.d.ts +73 -26
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +33 -118
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/initial-route.d.ts +8 -0
- package/dist/runtime/initial-route.d.ts.map +1 -0
- package/dist/runtime/initial-route.js +72 -0
- package/dist/runtime/initial-route.js.map +1 -0
- package/dist/runtime/islands.d.ts +19 -5
- package/dist/runtime/islands.d.ts.map +1 -1
- package/dist/runtime/islands.js +15 -41
- package/dist/runtime/islands.js.map +1 -1
- package/dist/runtime/loading.d.ts +12 -0
- package/dist/runtime/loading.d.ts.map +1 -0
- package/dist/runtime/loading.js +43 -0
- package/dist/runtime/loading.js.map +1 -0
- package/dist/runtime/memory-navigation.d.ts +16 -0
- package/dist/runtime/memory-navigation.d.ts.map +1 -0
- package/dist/runtime/memory-navigation.js +98 -0
- package/dist/runtime/memory-navigation.js.map +1 -0
- package/dist/runtime/native.d.ts +108 -0
- package/dist/runtime/native.d.ts.map +1 -0
- package/dist/runtime/native.js +378 -0
- package/dist/runtime/native.js.map +1 -0
- package/dist/runtime/navigation-atom.d.ts +21 -0
- package/dist/runtime/navigation-atom.d.ts.map +1 -0
- package/dist/runtime/navigation-atom.js +76 -0
- package/dist/runtime/navigation-atom.js.map +1 -0
- package/dist/runtime/navigation.d.ts +61 -0
- package/dist/runtime/navigation.d.ts.map +1 -0
- package/dist/runtime/navigation.js +11 -0
- package/dist/runtime/navigation.js.map +1 -0
- package/dist/runtime/page-scripts.d.ts +54 -0
- package/dist/runtime/page-scripts.d.ts.map +1 -0
- package/dist/runtime/page-scripts.js +207 -0
- package/dist/runtime/page-scripts.js.map +1 -0
- package/dist/runtime/route-matches.d.ts +17 -0
- package/dist/runtime/route-matches.d.ts.map +1 -0
- package/dist/runtime/route-matches.js +50 -0
- package/dist/runtime/route-matches.js.map +1 -0
- package/dist/runtime/router-embedded.d.ts +28 -0
- package/dist/runtime/router-embedded.d.ts.map +1 -0
- package/dist/runtime/router-embedded.js +12 -0
- package/dist/runtime/router-embedded.js.map +1 -0
- package/dist/runtime/router-navigation-api.d.ts +28 -0
- package/dist/runtime/router-navigation-api.d.ts.map +1 -0
- package/dist/runtime/router-navigation-api.js +13 -0
- package/dist/runtime/router-navigation-api.js.map +1 -0
- package/dist/runtime/router.d.ts +137 -0
- package/dist/runtime/router.d.ts.map +1 -0
- package/dist/runtime/router.js +678 -0
- package/dist/runtime/router.js.map +1 -0
- package/dist/runtime/stale-deployment.d.ts +7 -0
- package/dist/runtime/stale-deployment.d.ts.map +1 -0
- package/dist/runtime/stale-deployment.js +30 -0
- package/dist/runtime/stale-deployment.js.map +1 -0
- package/dist/runtime/user-input.d.ts +25 -0
- package/dist/runtime/user-input.d.ts.map +1 -0
- package/dist/runtime/user-input.js +81 -0
- package/dist/runtime/user-input.js.map +1 -0
- package/dist/runtimes.d.ts +43 -0
- package/dist/runtimes.d.ts.map +1 -0
- package/dist/runtimes.js +152 -0
- package/dist/runtimes.js.map +1 -0
- package/dist/server/node.d.ts +47 -2
- package/dist/server/node.d.ts.map +1 -1
- package/dist/server/node.js +185 -23
- package/dist/server/node.js.map +1 -1
- package/dist/server/static.d.ts +11 -0
- package/dist/server/static.d.ts.map +1 -0
- package/dist/server/static.js +61 -0
- package/dist/server/static.js.map +1 -0
- package/dist/server-api.d.ts +73 -0
- package/dist/server-api.d.ts.map +1 -0
- package/dist/server-api.js +171 -0
- package/dist/server-api.js.map +1 -0
- package/dist/server-components/browser.d.ts +75 -0
- package/dist/server-components/browser.d.ts.map +1 -0
- package/dist/server-components/browser.js +558 -0
- package/dist/server-components/browser.js.map +1 -0
- package/dist/server-components/closures.d.ts +21 -0
- package/dist/server-components/closures.d.ts.map +1 -0
- package/dist/server-components/closures.js +192 -0
- package/dist/server-components/closures.js.map +1 -0
- package/dist/server-components/compiler.d.ts +6 -0
- package/dist/server-components/compiler.d.ts.map +1 -0
- package/dist/server-components/compiler.js +118 -0
- package/dist/server-components/compiler.js.map +1 -0
- package/dist/server-components/environment.d.ts +3 -0
- package/dist/server-components/environment.d.ts.map +1 -0
- package/dist/server-components/environment.js +11 -0
- package/dist/server-components/environment.js.map +1 -0
- package/dist/server-components/navigation.d.ts +10 -0
- package/dist/server-components/navigation.d.ts.map +1 -0
- package/dist/server-components/navigation.js +105 -0
- package/dist/server-components/navigation.js.map +1 -0
- package/dist/server-components/protocol.d.ts +77 -0
- package/dist/server-components/protocol.d.ts.map +1 -0
- package/dist/server-components/protocol.js +110 -0
- package/dist/server-components/protocol.js.map +1 -0
- package/dist/server-components/references.d.ts +22 -0
- package/dist/server-components/references.d.ts.map +1 -0
- package/dist/server-components/references.js +94 -0
- package/dist/server-components/references.js.map +1 -0
- package/dist/server-components/server.d.ts +78 -0
- package/dist/server-components/server.d.ts.map +1 -0
- package/dist/server-components/server.js +278 -0
- package/dist/server-components/server.js.map +1 -0
- package/dist/server-components/stream.d.ts +15 -0
- package/dist/server-components/stream.d.ts.map +1 -0
- package/dist/server-components/stream.js +72 -0
- package/dist/server-components/stream.js.map +1 -0
- package/dist/server-cookies.d.ts +41 -0
- package/dist/server-cookies.d.ts.map +1 -0
- package/dist/server-cookies.js +120 -0
- package/dist/server-cookies.js.map +1 -0
- package/dist/server-data.d.ts +51 -0
- package/dist/server-data.d.ts.map +1 -0
- package/dist/server-data.js +37 -0
- package/dist/server-data.js.map +1 -0
- package/dist/server.d.ts +57 -4
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +244 -13
- package/dist/server.js.map +1 -1
- package/dist/ui/behaviors/accordion.d.ts +14 -0
- package/dist/ui/behaviors/accordion.d.ts.map +1 -0
- package/dist/ui/behaviors/accordion.js +149 -0
- package/dist/ui/behaviors/accordion.js.map +1 -0
- package/dist/ui/behaviors/catalogue.d.ts +63 -0
- package/dist/ui/behaviors/catalogue.d.ts.map +1 -0
- package/dist/ui/behaviors/catalogue.js +284 -0
- package/dist/ui/behaviors/catalogue.js.map +1 -0
- package/dist/ui/behaviors/collapsible.d.ts +26 -0
- package/dist/ui/behaviors/collapsible.d.ts.map +1 -0
- package/dist/ui/behaviors/collapsible.js +145 -0
- package/dist/ui/behaviors/collapsible.js.map +1 -0
- package/dist/ui/behaviors/dialog.d.ts +16 -0
- package/dist/ui/behaviors/dialog.d.ts.map +1 -0
- package/dist/ui/behaviors/dialog.js +225 -0
- package/dist/ui/behaviors/dialog.js.map +1 -0
- package/dist/ui/behaviors/lifecycle.d.ts +15 -0
- package/dist/ui/behaviors/lifecycle.d.ts.map +1 -0
- package/dist/ui/behaviors/lifecycle.js +51 -0
- package/dist/ui/behaviors/lifecycle.js.map +1 -0
- package/dist/ui/behaviors/menu.d.ts +15 -0
- package/dist/ui/behaviors/menu.d.ts.map +1 -0
- package/dist/ui/behaviors/menu.js +162 -0
- package/dist/ui/behaviors/menu.js.map +1 -0
- package/dist/ui/behaviors/ownership.d.ts +7 -0
- package/dist/ui/behaviors/ownership.d.ts.map +1 -0
- package/dist/ui/behaviors/ownership.js +16 -0
- package/dist/ui/behaviors/ownership.js.map +1 -0
- package/dist/ui/behaviors/popover.d.ts +16 -0
- package/dist/ui/behaviors/popover.d.ts.map +1 -0
- package/dist/ui/behaviors/popover.js +90 -0
- package/dist/ui/behaviors/popover.js.map +1 -0
- package/dist/ui/behaviors/select.d.ts +37 -0
- package/dist/ui/behaviors/select.d.ts.map +1 -0
- package/dist/ui/behaviors/select.js +261 -0
- package/dist/ui/behaviors/select.js.map +1 -0
- package/dist/ui/behaviors/switch.d.ts +43 -0
- package/dist/ui/behaviors/switch.d.ts.map +1 -0
- package/dist/ui/behaviors/switch.js +269 -0
- package/dist/ui/behaviors/switch.js.map +1 -0
- package/dist/ui/behaviors/tabs.d.ts +4 -0
- package/dist/ui/behaviors/tabs.d.ts.map +1 -0
- package/dist/ui/behaviors/tabs.js +121 -0
- package/dist/ui/behaviors/tabs.js.map +1 -0
- package/dist/ui/behaviors/toolbar.d.ts +4 -0
- package/dist/ui/behaviors/toolbar.d.ts.map +1 -0
- package/dist/ui/behaviors/toolbar.js +81 -0
- package/dist/ui/behaviors/toolbar.js.map +1 -0
- package/dist/ui/behaviors/tooltip.d.ts +16 -0
- package/dist/ui/behaviors/tooltip.d.ts.map +1 -0
- package/dist/ui/behaviors/tooltip.js +91 -0
- package/dist/ui/behaviors/tooltip.js.map +1 -0
- package/dist/ui/behaviors/types.d.ts +51 -0
- package/dist/ui/behaviors/types.d.ts.map +1 -0
- package/dist/ui/behaviors/types.js +2 -0
- package/dist/ui/behaviors/types.js.map +1 -0
- package/dist/ui/catalogue-loaders.d.ts +4 -0
- package/dist/ui/catalogue-loaders.d.ts.map +1 -0
- package/dist/ui/catalogue-loaders.js +45 -0
- package/dist/ui/catalogue-loaders.js.map +1 -0
- package/dist/ui/catalogue.d.ts +465 -0
- package/dist/ui/catalogue.d.ts.map +1 -0
- package/dist/ui/catalogue.js +1570 -0
- package/dist/ui/catalogue.js.map +1 -0
- package/dist/ui/checkpoints.d.ts +20 -0
- package/dist/ui/checkpoints.d.ts.map +1 -0
- package/dist/ui/checkpoints.js +118 -0
- package/dist/ui/checkpoints.js.map +1 -0
- package/dist/ui/components/accordion/accordion.d.ts +22 -0
- package/dist/ui/components/accordion/accordion.d.ts.map +1 -0
- package/dist/ui/components/accordion/accordion.js +47 -0
- package/dist/ui/components/accordion/accordion.js.map +1 -0
- package/dist/ui/components/accordion/index.d.ts +2 -0
- package/dist/ui/components/accordion/index.d.ts.map +1 -0
- package/dist/ui/components/accordion/index.js +2 -0
- package/dist/ui/components/accordion/index.js.map +1 -0
- package/dist/ui/components/angle-slider/index.d.ts +5 -0
- package/dist/ui/components/angle-slider/index.d.ts.map +1 -0
- package/dist/ui/components/angle-slider/index.js +7 -0
- package/dist/ui/components/angle-slider/index.js.map +1 -0
- package/dist/ui/components/async-list/index.d.ts +5 -0
- package/dist/ui/components/async-list/index.d.ts.map +1 -0
- package/dist/ui/components/async-list/index.js +7 -0
- package/dist/ui/components/async-list/index.js.map +1 -0
- package/dist/ui/components/avatar/index.d.ts +5 -0
- package/dist/ui/components/avatar/index.d.ts.map +1 -0
- package/dist/ui/components/avatar/index.js +7 -0
- package/dist/ui/components/avatar/index.js.map +1 -0
- package/dist/ui/components/badge/badge.d.ts +6 -0
- package/dist/ui/components/badge/badge.d.ts.map +1 -0
- package/dist/ui/components/badge/badge.js +11 -0
- package/dist/ui/components/badge/badge.js.map +1 -0
- package/dist/ui/components/badge/index.d.ts +2 -0
- package/dist/ui/components/badge/index.d.ts.map +1 -0
- package/dist/ui/components/badge/index.js +2 -0
- package/dist/ui/components/badge/index.js.map +1 -0
- package/dist/ui/components/button/button.d.ts +26 -0
- package/dist/ui/components/button/button.d.ts.map +1 -0
- package/dist/ui/components/button/button.js +116 -0
- package/dist/ui/components/button/button.js.map +1 -0
- package/dist/ui/components/button/index.d.ts +2 -0
- package/dist/ui/components/button/index.d.ts.map +1 -0
- package/dist/ui/components/button/index.js +2 -0
- package/dist/ui/components/button/index.js.map +1 -0
- package/dist/ui/components/card/card.d.ts +21 -0
- package/dist/ui/components/card/card.d.ts.map +1 -0
- package/dist/ui/components/card/card.js +41 -0
- package/dist/ui/components/card/card.js.map +1 -0
- package/dist/ui/components/card/index.d.ts +2 -0
- package/dist/ui/components/card/index.d.ts.map +1 -0
- package/dist/ui/components/card/index.js +2 -0
- package/dist/ui/components/card/index.js.map +1 -0
- package/dist/ui/components/carousel/index.d.ts +5 -0
- package/dist/ui/components/carousel/index.d.ts.map +1 -0
- package/dist/ui/components/carousel/index.js +7 -0
- package/dist/ui/components/carousel/index.js.map +1 -0
- package/dist/ui/components/cascade-select/index.d.ts +7 -0
- package/dist/ui/components/cascade-select/index.d.ts.map +1 -0
- package/dist/ui/components/cascade-select/index.js +8 -0
- package/dist/ui/components/cascade-select/index.js.map +1 -0
- package/dist/ui/components/checkbox/index.d.ts +5 -0
- package/dist/ui/components/checkbox/index.d.ts.map +1 -0
- package/dist/ui/components/checkbox/index.js +7 -0
- package/dist/ui/components/checkbox/index.js.map +1 -0
- package/dist/ui/components/clipboard/index.d.ts +5 -0
- package/dist/ui/components/clipboard/index.d.ts.map +1 -0
- package/dist/ui/components/clipboard/index.js +7 -0
- package/dist/ui/components/clipboard/index.js.map +1 -0
- package/dist/ui/components/collapsible/collapsible.d.ts +21 -0
- package/dist/ui/components/collapsible/collapsible.d.ts.map +1 -0
- package/dist/ui/components/collapsible/collapsible.js +39 -0
- package/dist/ui/components/collapsible/collapsible.js.map +1 -0
- package/dist/ui/components/collapsible/index.d.ts +2 -0
- package/dist/ui/components/collapsible/index.d.ts.map +1 -0
- package/dist/ui/components/collapsible/index.js +2 -0
- package/dist/ui/components/collapsible/index.js.map +1 -0
- package/dist/ui/components/color-picker/index.d.ts +7 -0
- package/dist/ui/components/color-picker/index.d.ts.map +1 -0
- package/dist/ui/components/color-picker/index.js +8 -0
- package/dist/ui/components/color-picker/index.js.map +1 -0
- package/dist/ui/components/combobox/index.d.ts +7 -0
- package/dist/ui/components/combobox/index.d.ts.map +1 -0
- package/dist/ui/components/combobox/index.js +8 -0
- package/dist/ui/components/combobox/index.js.map +1 -0
- package/dist/ui/components/date-input/index.d.ts +7 -0
- package/dist/ui/components/date-input/index.d.ts.map +1 -0
- package/dist/ui/components/date-input/index.js +8 -0
- package/dist/ui/components/date-input/index.js.map +1 -0
- package/dist/ui/components/date-picker/index.d.ts +7 -0
- package/dist/ui/components/date-picker/index.d.ts.map +1 -0
- package/dist/ui/components/date-picker/index.js +8 -0
- package/dist/ui/components/date-picker/index.js.map +1 -0
- package/dist/ui/components/dialog/dialog.d.ts +44 -0
- package/dist/ui/components/dialog/dialog.d.ts.map +1 -0
- package/dist/ui/components/dialog/dialog.js +105 -0
- package/dist/ui/components/dialog/dialog.js.map +1 -0
- package/dist/ui/components/dialog/index.d.ts +2 -0
- package/dist/ui/components/dialog/index.d.ts.map +1 -0
- package/dist/ui/components/dialog/index.js +2 -0
- package/dist/ui/components/dialog/index.js.map +1 -0
- package/dist/ui/components/drawer/index.d.ts +5 -0
- package/dist/ui/components/drawer/index.d.ts.map +1 -0
- package/dist/ui/components/drawer/index.js +7 -0
- package/dist/ui/components/drawer/index.js.map +1 -0
- package/dist/ui/components/editable/index.d.ts +5 -0
- package/dist/ui/components/editable/index.d.ts.map +1 -0
- package/dist/ui/components/editable/index.js +7 -0
- package/dist/ui/components/editable/index.js.map +1 -0
- package/dist/ui/components/file-upload/index.d.ts +5 -0
- package/dist/ui/components/file-upload/index.d.ts.map +1 -0
- package/dist/ui/components/file-upload/index.js +7 -0
- package/dist/ui/components/file-upload/index.js.map +1 -0
- package/dist/ui/components/floating-panel/index.d.ts +5 -0
- package/dist/ui/components/floating-panel/index.d.ts.map +1 -0
- package/dist/ui/components/floating-panel/index.js +7 -0
- package/dist/ui/components/floating-panel/index.js.map +1 -0
- package/dist/ui/components/hover-card/index.d.ts +5 -0
- package/dist/ui/components/hover-card/index.d.ts.map +1 -0
- package/dist/ui/components/hover-card/index.js +7 -0
- package/dist/ui/components/hover-card/index.js.map +1 -0
- package/dist/ui/components/image-cropper/index.d.ts +5 -0
- package/dist/ui/components/image-cropper/index.d.ts.map +1 -0
- package/dist/ui/components/image-cropper/index.js +7 -0
- package/dist/ui/components/image-cropper/index.js.map +1 -0
- package/dist/ui/components/index.d.ts +61 -0
- package/dist/ui/components/index.d.ts.map +1 -0
- package/dist/ui/components/index.js +186 -0
- package/dist/ui/components/index.js.map +1 -0
- package/dist/ui/components/layout/box.d.ts +11 -0
- package/dist/ui/components/layout/box.d.ts.map +1 -0
- package/dist/ui/components/layout/box.js +44 -0
- package/dist/ui/components/layout/box.js.map +1 -0
- package/dist/ui/components/layout/container.d.ts +9 -0
- package/dist/ui/components/layout/container.d.ts.map +1 -0
- package/dist/ui/components/layout/container.js +38 -0
- package/dist/ui/components/layout/container.js.map +1 -0
- package/dist/ui/components/layout/flex.d.ts +10 -0
- package/dist/ui/components/layout/flex.d.ts.map +1 -0
- package/dist/ui/components/layout/flex.js +53 -0
- package/dist/ui/components/layout/flex.js.map +1 -0
- package/dist/ui/components/layout/grid.d.ts +10 -0
- package/dist/ui/components/layout/grid.d.ts.map +1 -0
- package/dist/ui/components/layout/grid.js +47 -0
- package/dist/ui/components/layout/grid.js.map +1 -0
- package/dist/ui/components/layout/index.d.ts +6 -0
- package/dist/ui/components/layout/index.d.ts.map +1 -0
- package/dist/ui/components/layout/index.js +6 -0
- package/dist/ui/components/layout/index.js.map +1 -0
- package/dist/ui/components/layout/stack.d.ts +9 -0
- package/dist/ui/components/layout/stack.d.ts.map +1 -0
- package/dist/ui/components/layout/stack.js +37 -0
- package/dist/ui/components/layout/stack.js.map +1 -0
- package/dist/ui/components/listbox/index.d.ts +8 -0
- package/dist/ui/components/listbox/index.d.ts.map +1 -0
- package/dist/ui/components/listbox/index.js +9 -0
- package/dist/ui/components/listbox/index.js.map +1 -0
- package/dist/ui/components/marquee/index.d.ts +5 -0
- package/dist/ui/components/marquee/index.d.ts.map +1 -0
- package/dist/ui/components/marquee/index.js +7 -0
- package/dist/ui/components/marquee/index.js.map +1 -0
- package/dist/ui/components/menu/index.d.ts +2 -0
- package/dist/ui/components/menu/index.d.ts.map +1 -0
- package/dist/ui/components/menu/index.js +2 -0
- package/dist/ui/components/menu/index.js.map +1 -0
- package/dist/ui/components/menu/menu.d.ts +23 -0
- package/dist/ui/components/menu/menu.d.ts.map +1 -0
- package/dist/ui/components/menu/menu.js +45 -0
- package/dist/ui/components/menu/menu.js.map +1 -0
- package/dist/ui/components/navigation/breadcrumbs.d.ts +19 -0
- package/dist/ui/components/navigation/breadcrumbs.d.ts.map +1 -0
- package/dist/ui/components/navigation/breadcrumbs.js +90 -0
- package/dist/ui/components/navigation/breadcrumbs.js.map +1 -0
- package/dist/ui/components/navigation/index.d.ts +6 -0
- package/dist/ui/components/navigation/index.d.ts.map +1 -0
- package/dist/ui/components/navigation/index.js +6 -0
- package/dist/ui/components/navigation/index.js.map +1 -0
- package/dist/ui/components/navigation/prose.d.ts +6 -0
- package/dist/ui/components/navigation/prose.d.ts.map +1 -0
- package/dist/ui/components/navigation/prose.js +11 -0
- package/dist/ui/components/navigation/prose.js.map +1 -0
- package/dist/ui/components/navigation/sidebar.d.ts +10 -0
- package/dist/ui/components/navigation/sidebar.d.ts.map +1 -0
- package/dist/ui/components/navigation/sidebar.js +35 -0
- package/dist/ui/components/navigation/sidebar.js.map +1 -0
- package/dist/ui/components/navigation/toc.d.ts +11 -0
- package/dist/ui/components/navigation/toc.d.ts.map +1 -0
- package/dist/ui/components/navigation/toc.js +82 -0
- package/dist/ui/components/navigation/toc.js.map +1 -0
- package/dist/ui/components/navigation-menu/index.d.ts +5 -0
- package/dist/ui/components/navigation-menu/index.d.ts.map +1 -0
- package/dist/ui/components/navigation-menu/index.js +7 -0
- package/dist/ui/components/navigation-menu/index.js.map +1 -0
- package/dist/ui/components/number-input/index.d.ts +5 -0
- package/dist/ui/components/number-input/index.d.ts.map +1 -0
- package/dist/ui/components/number-input/index.js +7 -0
- package/dist/ui/components/number-input/index.js.map +1 -0
- package/dist/ui/components/pagination/index.d.ts +5 -0
- package/dist/ui/components/pagination/index.d.ts.map +1 -0
- package/dist/ui/components/pagination/index.js +7 -0
- package/dist/ui/components/pagination/index.js.map +1 -0
- package/dist/ui/components/password-input/index.d.ts +5 -0
- package/dist/ui/components/password-input/index.d.ts.map +1 -0
- package/dist/ui/components/password-input/index.js +7 -0
- package/dist/ui/components/password-input/index.js.map +1 -0
- package/dist/ui/components/pin-input/index.d.ts +5 -0
- package/dist/ui/components/pin-input/index.d.ts.map +1 -0
- package/dist/ui/components/pin-input/index.js +7 -0
- package/dist/ui/components/pin-input/index.js.map +1 -0
- package/dist/ui/components/popover/index.d.ts +2 -0
- package/dist/ui/components/popover/index.d.ts.map +1 -0
- package/dist/ui/components/popover/index.js +2 -0
- package/dist/ui/components/popover/index.js.map +1 -0
- package/dist/ui/components/popover/popover.d.ts +14 -0
- package/dist/ui/components/popover/popover.d.ts.map +1 -0
- package/dist/ui/components/popover/popover.js +22 -0
- package/dist/ui/components/popover/popover.js.map +1 -0
- package/dist/ui/components/presence/index.d.ts +5 -0
- package/dist/ui/components/presence/index.d.ts.map +1 -0
- package/dist/ui/components/presence/index.js +7 -0
- package/dist/ui/components/presence/index.js.map +1 -0
- package/dist/ui/components/progress/index.d.ts +5 -0
- package/dist/ui/components/progress/index.d.ts.map +1 -0
- package/dist/ui/components/progress/index.js +7 -0
- package/dist/ui/components/progress/index.js.map +1 -0
- package/dist/ui/components/qr-code/index.d.ts +5 -0
- package/dist/ui/components/qr-code/index.d.ts.map +1 -0
- package/dist/ui/components/qr-code/index.js +7 -0
- package/dist/ui/components/qr-code/index.js.map +1 -0
- package/dist/ui/components/radio-group/index.d.ts +5 -0
- package/dist/ui/components/radio-group/index.d.ts.map +1 -0
- package/dist/ui/components/radio-group/index.js +7 -0
- package/dist/ui/components/radio-group/index.js.map +1 -0
- package/dist/ui/components/rating-group/index.d.ts +5 -0
- package/dist/ui/components/rating-group/index.d.ts.map +1 -0
- package/dist/ui/components/rating-group/index.js +7 -0
- package/dist/ui/components/rating-group/index.js.map +1 -0
- package/dist/ui/components/resize-handle/index.d.ts +2 -0
- package/dist/ui/components/resize-handle/index.d.ts.map +1 -0
- package/dist/ui/components/resize-handle/index.js +2 -0
- package/dist/ui/components/resize-handle/index.js.map +1 -0
- package/dist/ui/components/resize-handle/resize-handle.d.ts +39 -0
- package/dist/ui/components/resize-handle/resize-handle.d.ts.map +1 -0
- package/dist/ui/components/resize-handle/resize-handle.js +170 -0
- package/dist/ui/components/resize-handle/resize-handle.js.map +1 -0
- package/dist/ui/components/scroll-area/index.d.ts +5 -0
- package/dist/ui/components/scroll-area/index.d.ts.map +1 -0
- package/dist/ui/components/scroll-area/index.js +7 -0
- package/dist/ui/components/scroll-area/index.js.map +1 -0
- package/dist/ui/components/select/index.d.ts +2 -0
- package/dist/ui/components/select/index.d.ts.map +1 -0
- package/dist/ui/components/select/index.js +2 -0
- package/dist/ui/components/select/index.js.map +1 -0
- package/dist/ui/components/select/select.d.ts +40 -0
- package/dist/ui/components/select/select.d.ts.map +1 -0
- package/dist/ui/components/select/select.js +57 -0
- package/dist/ui/components/select/select.js.map +1 -0
- package/dist/ui/components/separator/index.d.ts +2 -0
- package/dist/ui/components/separator/index.d.ts.map +1 -0
- package/dist/ui/components/separator/index.js +2 -0
- package/dist/ui/components/separator/index.js.map +1 -0
- package/dist/ui/components/separator/separator.d.ts +9 -0
- package/dist/ui/components/separator/separator.d.ts.map +1 -0
- package/dist/ui/components/separator/separator.js +27 -0
- package/dist/ui/components/separator/separator.js.map +1 -0
- package/dist/ui/components/signature-pad/index.d.ts +5 -0
- package/dist/ui/components/signature-pad/index.d.ts.map +1 -0
- package/dist/ui/components/signature-pad/index.js +7 -0
- package/dist/ui/components/signature-pad/index.js.map +1 -0
- package/dist/ui/components/slider/index.d.ts +5 -0
- package/dist/ui/components/slider/index.d.ts.map +1 -0
- package/dist/ui/components/slider/index.js +7 -0
- package/dist/ui/components/slider/index.js.map +1 -0
- package/dist/ui/components/splitter/index.d.ts +5 -0
- package/dist/ui/components/splitter/index.d.ts.map +1 -0
- package/dist/ui/components/splitter/index.js +7 -0
- package/dist/ui/components/splitter/index.js.map +1 -0
- package/dist/ui/components/steps/index.d.ts +5 -0
- package/dist/ui/components/steps/index.d.ts.map +1 -0
- package/dist/ui/components/steps/index.js +7 -0
- package/dist/ui/components/steps/index.js.map +1 -0
- package/dist/ui/components/switch/index.d.ts +2 -0
- package/dist/ui/components/switch/index.d.ts.map +1 -0
- package/dist/ui/components/switch/index.js +2 -0
- package/dist/ui/components/switch/index.js.map +1 -0
- package/dist/ui/components/switch/switch.d.ts +48 -0
- package/dist/ui/components/switch/switch.d.ts.map +1 -0
- package/dist/ui/components/switch/switch.js +64 -0
- package/dist/ui/components/switch/switch.js.map +1 -0
- package/dist/ui/components/tabs/index.d.ts +2 -0
- package/dist/ui/components/tabs/index.d.ts.map +1 -0
- package/dist/ui/components/tabs/index.js +2 -0
- package/dist/ui/components/tabs/index.js.map +1 -0
- package/dist/ui/components/tabs/tabs.d.ts +22 -0
- package/dist/ui/components/tabs/tabs.d.ts.map +1 -0
- package/dist/ui/components/tabs/tabs.js +89 -0
- package/dist/ui/components/tabs/tabs.js.map +1 -0
- package/dist/ui/components/tags-input/index.d.ts +5 -0
- package/dist/ui/components/tags-input/index.d.ts.map +1 -0
- package/dist/ui/components/tags-input/index.js +7 -0
- package/dist/ui/components/tags-input/index.js.map +1 -0
- package/dist/ui/components/timer/index.d.ts +7 -0
- package/dist/ui/components/timer/index.d.ts.map +1 -0
- package/dist/ui/components/timer/index.js +8 -0
- package/dist/ui/components/timer/index.js.map +1 -0
- package/dist/ui/components/toast/index.d.ts +7 -0
- package/dist/ui/components/toast/index.d.ts.map +1 -0
- package/dist/ui/components/toast/index.js +8 -0
- package/dist/ui/components/toast/index.js.map +1 -0
- package/dist/ui/components/toc/index.d.ts +5 -0
- package/dist/ui/components/toc/index.d.ts.map +1 -0
- package/dist/ui/components/toc/index.js +7 -0
- package/dist/ui/components/toc/index.js.map +1 -0
- package/dist/ui/components/toggle/index.d.ts +5 -0
- package/dist/ui/components/toggle/index.d.ts.map +1 -0
- package/dist/ui/components/toggle/index.js +7 -0
- package/dist/ui/components/toggle/index.js.map +1 -0
- package/dist/ui/components/toggle-group/index.d.ts +5 -0
- package/dist/ui/components/toggle-group/index.d.ts.map +1 -0
- package/dist/ui/components/toggle-group/index.js +7 -0
- package/dist/ui/components/toggle-group/index.js.map +1 -0
- package/dist/ui/components/toolbar/index.d.ts +11 -0
- package/dist/ui/components/toolbar/index.d.ts.map +1 -0
- package/dist/ui/components/toolbar/index.js +18 -0
- package/dist/ui/components/toolbar/index.js.map +1 -0
- package/dist/ui/components/tooltip/index.d.ts +2 -0
- package/dist/ui/components/tooltip/index.d.ts.map +1 -0
- package/dist/ui/components/tooltip/index.js +2 -0
- package/dist/ui/components/tooltip/index.js.map +1 -0
- package/dist/ui/components/tooltip/tooltip.d.ts +14 -0
- package/dist/ui/components/tooltip/tooltip.d.ts.map +1 -0
- package/dist/ui/components/tooltip/tooltip.js +22 -0
- package/dist/ui/components/tooltip/tooltip.js.map +1 -0
- package/dist/ui/components/tour/index.d.ts +5 -0
- package/dist/ui/components/tour/index.d.ts.map +1 -0
- package/dist/ui/components/tour/index.js +7 -0
- package/dist/ui/components/tour/index.js.map +1 -0
- package/dist/ui/components/tree-view/index.d.ts +7 -0
- package/dist/ui/components/tree-view/index.d.ts.map +1 -0
- package/dist/ui/components/tree-view/index.js +8 -0
- package/dist/ui/components/tree-view/index.js.map +1 -0
- package/dist/ui/core/button-behavior.d.ts +3 -0
- package/dist/ui/core/button-behavior.d.ts.map +1 -0
- package/dist/ui/core/button-behavior.js +50 -0
- package/dist/ui/core/button-behavior.js.map +1 -0
- package/dist/ui/core/catalogue-element.d.ts +6 -0
- package/dist/ui/core/catalogue-element.d.ts.map +1 -0
- package/dist/ui/core/catalogue-element.js +28 -0
- package/dist/ui/core/catalogue-element.js.map +1 -0
- package/dist/ui/core/component-styles.d.ts +2 -0
- package/dist/ui/core/component-styles.d.ts.map +1 -0
- package/dist/ui/core/component-styles.js +77 -0
- package/dist/ui/core/component-styles.js.map +1 -0
- package/dist/ui/core/element.d.ts +12 -0
- package/dist/ui/core/element.d.ts.map +1 -0
- package/dist/ui/core/element.js +57 -0
- package/dist/ui/core/element.js.map +1 -0
- package/dist/ui/core/events.d.ts +6 -0
- package/dist/ui/core/events.d.ts.map +1 -0
- package/dist/ui/core/events.js +13 -0
- package/dist/ui/core/events.js.map +1 -0
- package/dist/ui/core/form-control.d.ts +4 -0
- package/dist/ui/core/form-control.d.ts.map +1 -0
- package/dist/ui/core/form-control.js +25 -0
- package/dist/ui/core/form-control.js.map +1 -0
- package/dist/ui/core/index.d.ts +5 -0
- package/dist/ui/core/index.d.ts.map +1 -0
- package/dist/ui/core/index.js +5 -0
- package/dist/ui/core/index.js.map +1 -0
- package/dist/ui/core/layout-styles.d.ts +2 -0
- package/dist/ui/core/layout-styles.d.ts.map +1 -0
- package/dist/ui/core/layout-styles.js +58 -0
- package/dist/ui/core/layout-styles.js.map +1 -0
- package/dist/ui/core/machine-checkpoints.d.ts +6 -0
- package/dist/ui/core/machine-checkpoints.d.ts.map +1 -0
- package/dist/ui/core/machine-checkpoints.js +47 -0
- package/dist/ui/core/machine-checkpoints.js.map +1 -0
- package/dist/ui/core/machine-clock.d.ts +16 -0
- package/dist/ui/core/machine-clock.d.ts.map +1 -0
- package/dist/ui/core/machine-clock.js +89 -0
- package/dist/ui/core/machine-clock.js.map +1 -0
- package/dist/ui/core/machine-codec.d.ts +29 -0
- package/dist/ui/core/machine-codec.d.ts.map +1 -0
- package/dist/ui/core/machine-codec.js +217 -0
- package/dist/ui/core/machine-codec.js.map +1 -0
- package/dist/ui/core/machine-profiles.d.ts +437 -0
- package/dist/ui/core/machine-profiles.d.ts.map +1 -0
- package/dist/ui/core/machine-profiles.js +1175 -0
- package/dist/ui/core/machine-profiles.js.map +1 -0
- package/dist/ui/core/machine-resources.d.ts +6 -0
- package/dist/ui/core/machine-resources.d.ts.map +1 -0
- package/dist/ui/core/machine-resources.js +46 -0
- package/dist/ui/core/machine-resources.js.map +1 -0
- package/dist/ui/core/machine.d.ts +29 -0
- package/dist/ui/core/machine.d.ts.map +1 -0
- package/dist/ui/core/machine.js +111 -0
- package/dist/ui/core/machine.js.map +1 -0
- package/dist/ui/core/parts.d.ts +4 -0
- package/dist/ui/core/parts.d.ts.map +1 -0
- package/dist/ui/core/parts.js +33 -0
- package/dist/ui/core/parts.js.map +1 -0
- package/dist/ui/core/portal.d.ts +11 -0
- package/dist/ui/core/portal.d.ts.map +1 -0
- package/dist/ui/core/portal.js +71 -0
- package/dist/ui/core/portal.js.map +1 -0
- package/dist/ui/core/public-machine.d.ts +4 -0
- package/dist/ui/core/public-machine.d.ts.map +1 -0
- package/dist/ui/core/public-machine.js +26 -0
- package/dist/ui/core/public-machine.js.map +1 -0
- package/dist/ui/core/resumable-machine.d.ts +13 -0
- package/dist/ui/core/resumable-machine.d.ts.map +1 -0
- package/dist/ui/core/resumable-machine.js +336 -0
- package/dist/ui/core/resumable-machine.js.map +1 -0
- package/dist/ui/drivers/bulma.d.ts +3 -0
- package/dist/ui/drivers/bulma.d.ts.map +1 -0
- package/dist/ui/drivers/bulma.js +249 -0
- package/dist/ui/drivers/bulma.js.map +1 -0
- package/dist/ui/drivers/daisyui.d.ts +9 -0
- package/dist/ui/drivers/daisyui.d.ts.map +1 -0
- package/dist/ui/drivers/daisyui.js +107 -0
- package/dist/ui/drivers/daisyui.js.map +1 -0
- package/dist/ui/drivers/index.d.ts +7 -0
- package/dist/ui/drivers/index.d.ts.map +1 -0
- package/dist/ui/drivers/index.js +7 -0
- package/dist/ui/drivers/index.js.map +1 -0
- package/dist/ui/drivers/registry.d.ts +11 -0
- package/dist/ui/drivers/registry.d.ts.map +1 -0
- package/dist/ui/drivers/registry.js +109 -0
- package/dist/ui/drivers/registry.js.map +1 -0
- package/dist/ui/drivers/shadcn.d.ts +3 -0
- package/dist/ui/drivers/shadcn.d.ts.map +1 -0
- package/dist/ui/drivers/shadcn.js +288 -0
- package/dist/ui/drivers/shadcn.js.map +1 -0
- package/dist/ui/drivers/types.d.ts +43 -0
- package/dist/ui/drivers/types.d.ts.map +1 -0
- package/dist/ui/drivers/types.js +2 -0
- package/dist/ui/drivers/types.js.map +1 -0
- package/dist/ui/drivers/unstyled.d.ts +3 -0
- package/dist/ui/drivers/unstyled.d.ts.map +1 -0
- package/dist/ui/drivers/unstyled.js +226 -0
- package/dist/ui/drivers/unstyled.js.map +1 -0
- package/dist/ui/engine.d.ts +24 -0
- package/dist/ui/engine.d.ts.map +1 -0
- package/dist/ui/engine.js +22 -0
- package/dist/ui/engine.js.map +1 -0
- package/dist/ui/index.d.ts +7 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +6 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/machine-state.d.ts +349 -0
- package/dist/ui/machine-state.d.ts.map +1 -0
- package/dist/ui/machine-state.js +105 -0
- package/dist/ui/machine-state.js.map +1 -0
- package/dist/ui/presentation.d.ts +7 -0
- package/dist/ui/presentation.d.ts.map +1 -0
- package/dist/ui/presentation.js +21 -0
- package/dist/ui/presentation.js.map +1 -0
- package/dist/ui/render.d.ts +18 -0
- package/dist/ui/render.d.ts.map +1 -0
- package/dist/ui/render.js +31 -0
- package/dist/ui/render.js.map +1 -0
- package/dist/ui/resume.d.ts +28 -0
- package/dist/ui/resume.d.ts.map +1 -0
- package/dist/ui/resume.js +417 -0
- package/dist/ui/resume.js.map +1 -0
- package/dist/ui/server.d.ts +9 -0
- package/dist/ui/server.d.ts.map +1 -0
- package/dist/ui/server.js +6 -0
- package/dist/ui/server.js.map +1 -0
- package/dist/ui/state.d.ts +24 -0
- package/dist/ui/state.d.ts.map +1 -0
- package/dist/ui/state.js +64 -0
- package/dist/ui/state.js.map +1 -0
- package/dist/ui-server.d.ts +2 -0
- package/dist/ui-server.d.ts.map +1 -0
- package/dist/ui-server.js +2 -0
- package/dist/ui-server.js.map +1 -0
- package/dist/ui.d.ts +2 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/ui.js +2 -0
- package/dist/ui.js.map +1 -0
- package/dist/vite-environments.d.ts +27 -0
- package/dist/vite-environments.d.ts.map +1 -0
- package/dist/vite-environments.js +63 -0
- package/dist/vite-environments.js.map +1 -0
- package/dist/vite.d.ts +120 -2
- package/dist/vite.d.ts.map +1 -1
- package/dist/vite.js +1292 -196
- package/dist/vite.js.map +1 -1
- package/dist/workflow/browser.d.ts +7 -0
- package/dist/workflow/browser.d.ts.map +1 -0
- package/dist/workflow/browser.js +60 -0
- package/dist/workflow/browser.js.map +1 -0
- package/dist/workflow/compiler.d.ts +8 -0
- package/dist/workflow/compiler.d.ts.map +1 -0
- package/dist/workflow/compiler.js +122 -0
- package/dist/workflow/compiler.js.map +1 -0
- package/dist/workflow/http.d.ts +20 -0
- package/dist/workflow/http.d.ts.map +1 -0
- package/dist/workflow/http.js +68 -0
- package/dist/workflow/http.js.map +1 -0
- package/dist/workflow/index.d.ts +46 -0
- package/dist/workflow/index.d.ts.map +1 -0
- package/dist/workflow/index.js +91 -0
- package/dist/workflow/index.js.map +1 -0
- package/dist/workflow/journal.d.ts +9 -0
- package/dist/workflow/journal.d.ts.map +1 -0
- package/dist/workflow/journal.js +18 -0
- package/dist/workflow/journal.js.map +1 -0
- package/dist/workflow/node.d.ts +6 -0
- package/dist/workflow/node.d.ts.map +1 -0
- package/dist/workflow/node.js +24 -0
- package/dist/workflow/node.js.map +1 -0
- package/dist/workflow/operation.d.ts +23 -0
- package/dist/workflow/operation.d.ts.map +1 -0
- package/dist/workflow/operation.js +65 -0
- package/dist/workflow/operation.js.map +1 -0
- package/dist/workflow/protocol.d.ts +36 -0
- package/dist/workflow/protocol.d.ts.map +1 -0
- package/dist/workflow/protocol.js +45 -0
- package/dist/workflow/protocol.js.map +1 -0
- package/package.json +158 -23
- package/dist/create.d.ts +0 -21
- package/dist/create.d.ts.map +0 -1
- package/dist/create.js +0 -111
- package/dist/create.js.map +0 -1
- package/dist/runtime/atom.d.ts +0 -10
- package/dist/runtime/atom.d.ts.map +0 -1
- package/dist/runtime/atom.js +0 -38
- package/dist/runtime/atom.js.map +0 -1
- package/templates/basic/README.md +0 -18
- package/templates/basic/_gitignore +0 -3
- package/templates/basic/components/app-badge.html +0 -1
- package/templates/basic/index.html +0 -12
- package/templates/basic/islands/counter.ts +0 -13
- package/templates/basic/package.json +0 -23
- package/templates/basic/pages/about/index.html +0 -5
- package/templates/basic/pages/docs/index.md +0 -9
- package/templates/basic/pages/index.html +0 -9
- package/templates/basic/pages/layout.html +0 -8
- package/templates/basic/pnpm-workspace.yaml +0 -5
- package/templates/basic/server.mjs +0 -11
- package/templates/basic/style.css +0 -1
- package/templates/basic/tsconfig.json +0 -13
- package/templates/basic/vite.config.ts +0 -4
package/dist/vite.js
CHANGED
|
@@ -1,29 +1,284 @@
|
|
|
1
|
+
import { inlineDocumentAssets } from "./compiler/inline-assets.js";
|
|
2
|
+
import { compileDataDocument } from './compiler/data-document.js';
|
|
3
|
+
import { parseRoutePolicy } from './compiler/route-policy.js';
|
|
4
|
+
import { extractPageScripts, compilePageScript } from "./compiler/page-scripts.js";
|
|
5
|
+
import { compileNativeScript } from "./compiler/native-scripts.js";
|
|
6
|
+
import { compileWorkflows, workflowPlugin } from "./workflow/compiler.js";
|
|
7
|
+
import { assertBrowserViewImport } from "./server-components/environment.js";
|
|
8
|
+
import { replaceClosures } from "./server-components/closures.js";
|
|
9
|
+
import { discoverViewReferences, browserReferencesCode } from "./server-components/references.js";
|
|
10
|
+
import { randomUUID } from "node:crypto";
|
|
11
|
+
import { compileFragment, compiledFragmentsPlugin } from "./server-components/compiler.js";
|
|
12
|
+
import { makeRouteMatches } from "./runtime/route-matches.js";
|
|
13
|
+
import { makeClientRouteMatcher } from "./runtime/client-routes.js";
|
|
14
|
+
import { errorHtml, notFoundHtml } from "./boundaries.js";
|
|
15
|
+
import { applyBaseToLinks, rewriteNavigationLinks } from "./compiler/base-links.js";
|
|
16
|
+
import { normalizeBase, routeKey, serverDataPrefix, serverDataUrl, stripBase, withBase } from "./route-path.js";
|
|
17
|
+
import { escapeAttribute, escapeText, inlineScript, jsonScript } from "./html-escape.js";
|
|
18
|
+
import { applyDocumentMetadata, applyGeneratorMetadata, pageHead, readDocumentHead } from "./compiler/metadata.js";
|
|
19
|
+
import * as Effect from "effect/Effect";
|
|
20
|
+
import { scanIslandModulesEffect } from "./compiler/island-modules.js";
|
|
1
21
|
import { mkdir, readFile, readdir, rmdir, unlink, writeFile } from "node:fs/promises";
|
|
22
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
23
|
+
import { fileURLToPath } from "node:url";
|
|
24
|
+
import { readFileSync } from "node:fs";
|
|
2
25
|
import path from "node:path";
|
|
3
|
-
import { createServer } from "vite";
|
|
4
|
-
import {
|
|
26
|
+
import { build as viteBuild, createServer } from "vite";
|
|
27
|
+
import { describeFindings, findInteractiveConstructs, projectImports } from "./compiler/static-analysis.js";
|
|
28
|
+
import { createRuntimes } from "./runtimes.js";
|
|
29
|
+
import { CompileCache, compilePlatformBlocks, compileProject } from "./compiler/index.js";
|
|
5
30
|
import { compileIslands } from "./compiler/islands.js";
|
|
6
|
-
import { createServerHandler } from "./server.js";
|
|
31
|
+
import { createServerHandler, isServerData } from "./server.js";
|
|
32
|
+
import { findServerModules } from "./compiler/server-modules.js";
|
|
33
|
+
import { findApiRoutes } from "./compiler/api-routes.js";
|
|
34
|
+
import { toWebRequest, writeWebResponse } from "./server/node.js";
|
|
35
|
+
import { routeTypes } from "./runtime/href.js";
|
|
36
|
+
import { writeElectronScaffold } from "./electron.js";
|
|
37
|
+
import { createEnvironmentModuleRuntime, detectViteEnvironmentApi, invalidateEnvironmentModule, normalizeEnvironmentConfiguration } from "./vite-environments.js";
|
|
7
38
|
const virtualId = "virtual:fuzor/client";
|
|
39
|
+
const rendererModules = {
|
|
40
|
+
"virtual:fuzor/compiler/react": 'export { createElement } from "react"; export { renderToString, renderToStaticMarkup } from "react-dom/server";',
|
|
41
|
+
"virtual:fuzor/compiler/vue": 'export { createSSRApp } from "vue"; export { renderToString } from "vue/server-renderer";',
|
|
42
|
+
"virtual:fuzor/compiler/solid": 'export { createComponent } from "solid-js"; export { renderToString, generateHydrationScript } from "solid-js/web";'
|
|
43
|
+
};
|
|
8
44
|
const resolvedVirtualId = `\0${virtualId}`;
|
|
9
45
|
const outletStart = "<!--fuzor:outlet-start-->";
|
|
10
46
|
const outletEnd = "<!--fuzor:outlet-end-->";
|
|
11
|
-
function
|
|
12
|
-
|
|
47
|
+
function findRoute(project, pathname) {
|
|
48
|
+
const key = routeKey(pathname);
|
|
49
|
+
return key === undefined ? undefined : project.routes.find((entry) => entry.path === key);
|
|
13
50
|
}
|
|
14
|
-
function
|
|
15
|
-
|
|
16
|
-
const route = project.routes.find((entry) => entry.path === normalized);
|
|
17
|
-
if (!route)
|
|
18
|
-
throw new Error(`No Fuzor route for ${normalized}`);
|
|
19
|
-
return route.html;
|
|
51
|
+
function boundaryFor(project, kind, scope) {
|
|
52
|
+
return project.boundaries?.find(boundary => boundary.kind === kind && boundary.scope === scope);
|
|
20
53
|
}
|
|
21
|
-
|
|
54
|
+
/** Boundary pages by scope, always including a root page (the author's or Fuzor's default). */
|
|
55
|
+
function boundaryPages(project, kind, fallback) {
|
|
56
|
+
const pages = new Map();
|
|
57
|
+
const title = kind === "not-found" ? "Page not found" : "Something went wrong";
|
|
58
|
+
pages.set("/", { html: fallback, metadata: { title } });
|
|
59
|
+
for (const boundary of project.boundaries ?? []) {
|
|
60
|
+
if (boundary.kind === kind)
|
|
61
|
+
pages.set(boundary.scope, { html: boundary.html, metadata: { title, ...boundary.metadata } });
|
|
62
|
+
}
|
|
63
|
+
return pages;
|
|
64
|
+
}
|
|
65
|
+
function paramsAttribute(params) {
|
|
66
|
+
return params ? ` data-fuzor-params="${escapeAttribute(JSON.stringify(params))}"` : "";
|
|
67
|
+
}
|
|
68
|
+
function routeAttributes(route, base) {
|
|
69
|
+
return `${paramsAttribute(route.params)}${route.pattern || route.requestPattern ? ` data-fuzor-pattern="${escapeAttribute(route.pattern ?? route.path)}"` : ""}${route.requestPattern ? ` data-fuzor-request-pattern="${escapeAttribute(route.requestPattern)}"` : ""}${route.serverData ? ` data-fuzor-data="${escapeAttribute(serverDataUrl(route.path, base))}"` : ""}`;
|
|
70
|
+
}
|
|
71
|
+
function outletFor(project, target, pathname, fallbacks, mixed = false) {
|
|
72
|
+
const current = findRoute(project, pathname);
|
|
73
|
+
if (mixed) {
|
|
74
|
+
target = current?.policy?.navigation === "spa" ? "spa" : "mpa";
|
|
75
|
+
if (target === "spa")
|
|
76
|
+
project = { ...project, routes: project.routes.filter(route => route.policy?.navigation === "spa" && route.policy.spaScope === current?.policy?.spaScope) };
|
|
77
|
+
}
|
|
22
78
|
if (target !== "spa") {
|
|
23
|
-
|
|
79
|
+
const route = findRoute(project, pathname);
|
|
80
|
+
if (!route)
|
|
81
|
+
throw new Error(`No Fuzor route for ${pathname}`);
|
|
82
|
+
return `<fuzor-router data-fuzor-navigation="document"${routeAttributes(route, fallbacks.base)}>${route.html}</fuzor-router>`;
|
|
83
|
+
}
|
|
84
|
+
const initial = findRoute(project, pathname);
|
|
85
|
+
const outlet = initial
|
|
86
|
+
? `<fuzor-router data-fuzor-navigation="spa" data-fuzor-initial-route="${escapeAttribute(initial.path)}"${routeAttributes(initial, fallbacks.base)}>${initial.html}</fuzor-router>`
|
|
87
|
+
: `<fuzor-router></fuzor-router>`;
|
|
88
|
+
const templates = project.routes.map((route) => `<template data-fuzor-route="${escapeAttribute(route.path)}"${routeAttributes(route, fallbacks.base)}>${route.html}</template>`).join("\n");
|
|
89
|
+
// "" holds the shell defaults, because the shared document's head already shows the first page's metadata.
|
|
90
|
+
const metadata = { "": fallbacks.head, ...Object.fromEntries(project.routes.map(route => [route.path, route.metadata ?? {}])) };
|
|
91
|
+
const boundaries = [];
|
|
92
|
+
for (const [kind, fallback] of [["not-found", fallbacks.notFound], ["error", fallbacks.error]]) {
|
|
93
|
+
for (const [scope, page] of boundaryPages(project, kind, fallback)) {
|
|
94
|
+
boundaries.push(`<template data-fuzor-${kind}="${escapeAttribute(scope)}">${page.html}</template>`);
|
|
95
|
+
metadata[`${kind}:${scope}`] = page.metadata;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const redirects = project.redirects ? `\n<script type="application/json" data-fuzor-redirects>${jsonScript(project.redirects)}</script>` : "";
|
|
99
|
+
return `${outlet}\n${templates}\n${boundaries.join("\n")}\n<script type="application/json" data-fuzor-metadata>${jsonScript(metadata)}</script>${redirects}`;
|
|
100
|
+
}
|
|
101
|
+
/** Bundle the parser-time selector without the asynchronous application runtime. */
|
|
102
|
+
async function inlineInitialRouteScript(options) {
|
|
103
|
+
const source = fileURLToPath(new URL(`./runtime/initial-route.${import.meta.url.endsWith(".ts") ? "ts" : "js"}`, import.meta.url));
|
|
104
|
+
const result = await viteBuild({
|
|
105
|
+
configFile: false, publicDir: false, logLevel: "silent",
|
|
106
|
+
build: { write: false, minify: true, lib: { entry: source, name: "fuzorInitial", formats: ["iife"] } }
|
|
107
|
+
});
|
|
108
|
+
const output = (Array.isArray(result) ? result[0] : result);
|
|
109
|
+
const code = output.output.find(item => item.type === "chunk")?.code;
|
|
110
|
+
if (!code)
|
|
111
|
+
throw new Error("Fuzor initial route selector could not be bundled");
|
|
112
|
+
return `<script>${inlineScript(`(()=>{${code}\nfuzorInitial.selectInitialRoute(window,${jsonScript(options)});})();`)}</script>`;
|
|
113
|
+
}
|
|
114
|
+
/** Finished documents for a server: nothing is assembled per request. */
|
|
115
|
+
/** Island names in a document: hosts and `client:none` markers. */
|
|
116
|
+
export function documentIslands(html) {
|
|
117
|
+
const names = new Set();
|
|
118
|
+
for (const match of html.matchAll(/<fuzor-island\b[^>]*?\ssrc="([^"]+)"/g))
|
|
119
|
+
names.add(match[1]);
|
|
120
|
+
for (const match of html.matchAll(/<!--fuzor:static ([^\s]+?)-->/g))
|
|
121
|
+
names.add(match[1]);
|
|
122
|
+
return names;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Links the stylesheets of every island in a document, so prerendered previews and client:none components are
|
|
126
|
+
* styled at first paint instead of when their JavaScript loads. Links from a template are replaced, not added to.
|
|
127
|
+
*/
|
|
128
|
+
export function withIslandStyles(html, styles, base) {
|
|
129
|
+
const stripped = html.replace(/<link rel="stylesheet" href="[^"]*" data-fuzor-island-css>/g, "");
|
|
130
|
+
const files = [...new Set([...documentIslands(stripped)].flatMap(name => styles[name] ?? styles["island:" + name] ?? []))]
|
|
131
|
+
.map(file => `${base.endsWith("/") ? base : `${base}/`}${file}`)
|
|
132
|
+
.filter(href => !stripped.includes(`href="${href}"`));
|
|
133
|
+
if (!files.length)
|
|
134
|
+
return stripped;
|
|
135
|
+
return stripped.replace("</head>", () => `${files.map(href => `<link rel="stylesheet" href="${escapeAttribute(href)}" data-fuzor-island-css>`).join("")}</head>`);
|
|
136
|
+
}
|
|
137
|
+
function serverManifest(project, target, template, base, fallbacks, finish = html => html, clientRoutes, assetDirectory, mixed = false) {
|
|
138
|
+
const boundaryDocuments = (kind, fallback) => Object.fromEntries([...boundaryPages(project, kind, fallback)].map(([scope, page]) => [scope, finish(applyDocumentMetadata(replaceOutlet(template, `<fuzor-router data-fuzor-${kind}="${escapeAttribute(scope)}">${page.html}</fuzor-router>`), pageHead(fallbacks.head, page.metadata)))]));
|
|
139
|
+
const notFoundDocuments = boundaryDocuments("not-found", fallbacks.notFound);
|
|
140
|
+
const revalidate = Object.fromEntries(project.routes.flatMap(route => route.metadata?.revalidate === undefined ? [] : [[route.path, route.metadata.revalidate]]));
|
|
141
|
+
const shared = {
|
|
142
|
+
...(Object.keys(revalidate).length ? { revalidate } : {}),
|
|
143
|
+
...(project.redirects ? { redirects: project.redirects } : {}),
|
|
144
|
+
requestPatterns: Object.fromEntries(project.routes.filter(route => route.requestPattern).map(route => [route.requestPattern, route.path])),
|
|
145
|
+
routePolicies: Object.fromEntries(project.routes.map(route => [route.path, route.policy ?? { rendering: "static", navigation: target === "spa" ? "spa" : "document" }])),
|
|
146
|
+
notFoundDocument: notFoundDocuments["/"],
|
|
147
|
+
...(Object.keys(notFoundDocuments).length > 1 ? { notFoundDocuments } : {}),
|
|
148
|
+
errorDocument: boundaryDocuments("error", fallbacks.error)["/"],
|
|
149
|
+
...(base === "/" ? {} : { base })
|
|
150
|
+
};
|
|
151
|
+
const manifest = target === "spa"
|
|
152
|
+
? { document: finish(template), routeDocuments: Object.fromEntries(project.routes.map(route => [route.path, finish(applyDocumentMetadata(replaceOutlet(template, outletFor(project, "spa", route.path, fallbacks)), pageHead(fallbacks.head, route.metadata ?? {})))])), routes: Object.fromEntries(project.routes.map((route) => [route.path, true])), ...(clientRoutes ? { clientRoutes, ...(assetDirectory ? { assetDirectory } : {}) } : {}), ...shared }
|
|
153
|
+
: { documents: Object.fromEntries(project.routes.map((route) => [route.path, finish(applyDocumentMetadata(replaceOutlet(template, outletFor(project, "mpa", route.path, fallbacks, mixed)), pageHead(fallbacks.head, route.metadata ?? {})))])), ...shared };
|
|
154
|
+
const documents = "documents" in manifest ? manifest.documents : manifest.routeDocuments ?? {};
|
|
155
|
+
return { ...manifest, dataBindings: Object.fromEntries(project.routes.filter(route => route.policy?.rendering === "request").map(route => [route.path, compileDataDocument(documents[route.path])])) };
|
|
156
|
+
}
|
|
157
|
+
/** Loads each page's `server.ts` default export and checks it was declared with `defineServerData`. */
|
|
158
|
+
async function loadRouteDataModules(project, load, root) {
|
|
159
|
+
const data = {};
|
|
160
|
+
for (const route of project.routes) {
|
|
161
|
+
if (!route.serverData)
|
|
162
|
+
continue;
|
|
163
|
+
const module = await load(route.serverData);
|
|
164
|
+
if (!isServerData(module.default)) {
|
|
165
|
+
throw new Error(`${path.relative(root, route.serverData)} must export default defineServerData(...) from "fuzor/server".`);
|
|
166
|
+
}
|
|
167
|
+
data[route.path] = { data: module.default, ...(route.params ? { params: route.params } : {}) };
|
|
168
|
+
}
|
|
169
|
+
return data;
|
|
170
|
+
}
|
|
171
|
+
/** Static hosts cannot send 308s from HTML: a refresh document works everywhere, `_redirects` on hosts that read it. */
|
|
172
|
+
function redirectDocument(destination) {
|
|
173
|
+
const target = escapeAttribute(destination);
|
|
174
|
+
return `<!doctype html>\n<html lang="en"><head><meta charset="utf-8"><title>Redirecting…</title><meta name="robots" content="noindex"><meta http-equiv="refresh" content="0; url=${target}"><link rel="canonical" href="${target}"></head><body><p>This page has moved to <a href="${target}">${escapeText(destination)}</a>.</p></body></html>\n`;
|
|
175
|
+
}
|
|
176
|
+
async function loadApiModules(files, load) {
|
|
177
|
+
return Promise.all(files.map(async (route) => ({ pattern: route.pattern, segments: route.segments, source: route.relative, module: await load(route.file) })));
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Cloudflare Workers output: static assets serve every prerendered page, `_redirects` and 404 pages, while
|
|
181
|
+
* only API endpoints and server data run the Worker. Deploy with `wrangler deploy --config <dir>/wrangler.jsonc`.
|
|
182
|
+
*/
|
|
183
|
+
async function writeCloudflareOutput(directory, root, target, base, clientDirectory, requestRoutes, assetReference) {
|
|
184
|
+
const packageName = await readFile(path.join(root, "package.json"), "utf8").then(text => JSON.parse(text).name, () => undefined);
|
|
185
|
+
const name = (packageName ?? path.basename(root)).replace(/^@[^/]+\//, "").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 63) || "fuzor-app";
|
|
186
|
+
await mkdir(path.join(directory, "cloudflare"), { recursive: true });
|
|
187
|
+
await writeFile(path.join(directory, "cloudflare/worker.mjs"), [
|
|
188
|
+
"// Generated by Fuzor. Static assets answer page requests; this Worker answers API and server data requests.",
|
|
189
|
+
'import { handler } from "../entry.mjs";',
|
|
190
|
+
"",
|
|
191
|
+
"export default {",
|
|
192
|
+
" fetch(request) {",
|
|
193
|
+
" return handler(request);",
|
|
194
|
+
" }",
|
|
195
|
+
"};",
|
|
196
|
+
""
|
|
197
|
+
].join("\n"), "utf8");
|
|
198
|
+
const prefix = base === "/" ? "" : base.slice(0, -1);
|
|
199
|
+
const config = {
|
|
200
|
+
$schema: "../node_modules/wrangler/config-schema.json",
|
|
201
|
+
name,
|
|
202
|
+
main: "cloudflare/worker.mjs",
|
|
203
|
+
compatibility_date: "2026-09-01",
|
|
204
|
+
assets: {
|
|
205
|
+
directory: assetReference,
|
|
206
|
+
binding: "ASSETS",
|
|
207
|
+
not_found_handling: target === "spa" ? "single-page-application" : "404-page",
|
|
208
|
+
run_worker_first: [...new Set([`${prefix}/api`, `${prefix}/api/*`, `${prefix}/_fuzor/data/*`, `${prefix}/_fuzor/render`, ...requestRoutes.map(route => withBase(route, base)), ...requestRoutes.map(route => withBase(route.replace(/\/$/, ""), base))])]
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
await writeFile(path.join(directory, "wrangler.jsonc"), `// Generated by Fuzor on each build; copy it next to your project to customize.\n${JSON.stringify(config, null, 2)}\n`, "utf8");
|
|
212
|
+
await writeFile(path.join(clientDirectory, ".assetsignore"), ".fuzor-assets.json\n", "utf8");
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Build-time previews and browser hydration must use the same framework version. React ships its server
|
|
216
|
+
* renderer in react-dom, a separate package, so a version mismatch between react and react-dom is an error.
|
|
217
|
+
*/
|
|
218
|
+
export function checkRendererVersions(root, islands, runtimes = {}) {
|
|
219
|
+
for (const [key, packages] of Object.entries(runtimes)) {
|
|
220
|
+
if (!packages.react || !islands.some(island => island.file.includes(`.${key}.`)))
|
|
221
|
+
continue;
|
|
222
|
+
if (!packages["react-dom"])
|
|
223
|
+
throw new Error(`Runtime ${key} maps react but not react-dom; React islands render and hydrate with both.`);
|
|
224
|
+
checkPair(root, packages.react, packages["react-dom"], key);
|
|
24
225
|
}
|
|
25
|
-
|
|
26
|
-
|
|
226
|
+
if (!islands.some(island => /\.react\.[jt]sx$/.test(island.file)))
|
|
227
|
+
return;
|
|
228
|
+
checkPair(root, "react", "react-dom");
|
|
229
|
+
}
|
|
230
|
+
function checkPair(root, reactName, domName, runtime) {
|
|
231
|
+
// Walk node_modules directories like Vite's resolver; NODE_PATH (set by pnpm scripts) must not count.
|
|
232
|
+
const version = (name) => {
|
|
233
|
+
for (let directory = path.resolve(root);; directory = path.dirname(directory)) {
|
|
234
|
+
try {
|
|
235
|
+
return JSON.parse(readFileSync(path.join(directory, "node_modules", name, "package.json"), "utf8")).version;
|
|
236
|
+
}
|
|
237
|
+
catch { }
|
|
238
|
+
if (path.dirname(directory) === directory)
|
|
239
|
+
return undefined;
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
const react = version(reactName);
|
|
243
|
+
const dom = version(domName);
|
|
244
|
+
const label = runtime ? `Runtime ${runtime} islands` : "React islands";
|
|
245
|
+
if (!react || !dom)
|
|
246
|
+
throw new Error(`${label} need both ${reactName} and ${domName} installed (found ${reactName} ${react ?? "missing"}, ${domName} ${dom ?? "missing"}).`);
|
|
247
|
+
if (react !== dom)
|
|
248
|
+
throw new Error(`${label} render at build time with ${domName} ${dom} and hydrate with ${reactName} ${react}. Install the same version of both packages.`);
|
|
249
|
+
}
|
|
250
|
+
/** Adds Vite's `id`, `loc` and `frame` to compiler errors so the overlay and build output point at the file. */
|
|
251
|
+
async function withViteLocation(error) {
|
|
252
|
+
const location = error?.location;
|
|
253
|
+
if (!location || !(error instanceof Error))
|
|
254
|
+
return error;
|
|
255
|
+
const extra = { id: location.file };
|
|
256
|
+
const line = location.line;
|
|
257
|
+
if (line !== undefined) {
|
|
258
|
+
extra.loc = { file: location.file, line, column: location.column ?? 1 };
|
|
259
|
+
const lines = await readFile(location.file, "utf8").then(text => text.split("\n"), () => []);
|
|
260
|
+
if (lines.length) {
|
|
261
|
+
const first = Math.max(1, line - 2);
|
|
262
|
+
extra.frame = lines.slice(first - 1, line + 2).map((text, index) => {
|
|
263
|
+
const number = first + index;
|
|
264
|
+
const gutter = `${number === line ? ">" : " "} ${String(number).padStart(String(line + 2).length)} | `;
|
|
265
|
+
return number === line ? `${gutter}${text}\n${" ".repeat(gutter.length + (location.column ?? 1) - 1)}^` : `${gutter}${text}`;
|
|
266
|
+
}).join("\n");
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return Object.assign(error, extra);
|
|
270
|
+
}
|
|
271
|
+
function searchIndex(project, option) {
|
|
272
|
+
if (!option)
|
|
273
|
+
return undefined;
|
|
274
|
+
const scope = typeof option === "object" && option.scope ? routeKey(option.scope) ?? "/" : "/";
|
|
275
|
+
const documents = project.routes.filter(route => route.path.startsWith(scope) && route.search).map(route => ({
|
|
276
|
+
path: route.path,
|
|
277
|
+
title: route.metadata?.navTitle ?? route.search.headings[0] ?? route.metadata?.title ?? route.path,
|
|
278
|
+
headings: route.search.headings.slice(1),
|
|
279
|
+
text: route.search.text
|
|
280
|
+
}));
|
|
281
|
+
return JSON.stringify({ version: 1, documents });
|
|
27
282
|
}
|
|
28
283
|
function replaceOutlet(document, content) {
|
|
29
284
|
const start = document.indexOf(outletStart);
|
|
@@ -32,288 +287,1129 @@ function replaceOutlet(document, content) {
|
|
|
32
287
|
throw new Error(`index.html must contain ${outletStart} and ${outletEnd}.`);
|
|
33
288
|
return document.slice(0, start + outletStart.length) + content + document.slice(end);
|
|
34
289
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
290
|
+
function serverViewDocument(html) {
|
|
291
|
+
let found = false;
|
|
292
|
+
const document = html.replace(/(<fuzor-router\b[^>]*>)[\s\S]*?<\/fuzor-router>/, (_match, open) => { found = true; return open + "<!--fuzor-view--></fuzor-router>"; });
|
|
293
|
+
if (!found || !document.includes("</body>"))
|
|
294
|
+
throw new Error("Server views require a compiled outlet and a document body.");
|
|
295
|
+
return document.replace("</body>", "<!--fuzor-snapshot--></body>");
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* The plugin creates private Vite servers to load island and `paths` modules. Their config file loads
|
|
299
|
+
* this plugin again; those nested instances only provide virtual modules and never compile the project.
|
|
300
|
+
*/
|
|
301
|
+
const nestedServer = new AsyncLocalStorage();
|
|
302
|
+
/**
|
|
303
|
+
* Vite servers Fuzor starts inside a dev server or build to load pages' modules and analyze islands. They must not
|
|
304
|
+
* open an HMR WebSocket (two would compete for its port, and a failed one never closes) and must not share the
|
|
305
|
+
* dev server's dependency cache (each would re-optimize and invalidate the other's pre-bundled files).
|
|
306
|
+
*/
|
|
307
|
+
export function nestedServerConfig(config) {
|
|
308
|
+
return {
|
|
309
|
+
root: config.root,
|
|
310
|
+
configFile: config.configFile ?? false,
|
|
311
|
+
plugins: [workflowPlugin(), {
|
|
312
|
+
name: "fuzor:nested-renderers",
|
|
313
|
+
resolveId(id) { if (Object.hasOwn(rendererModules, id))
|
|
314
|
+
return `\0${id}`; },
|
|
315
|
+
load(id) { if (id.startsWith("\0") && Object.hasOwn(rendererModules, id.slice(1)))
|
|
316
|
+
return rendererModules[id.slice(1)]; }
|
|
317
|
+
}],
|
|
318
|
+
server: { middlewareMode: true, hmr: false, ws: false },
|
|
319
|
+
cacheDir: path.join(config.cacheDir, "fuzor-nested"),
|
|
320
|
+
optimizeDeps: { noDiscovery: true, include: [] },
|
|
321
|
+
appType: "custom"
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Resolves the build profile. Sources, highest first: explicit `fuzorPlugin()` options, the `FUZOR_TARGET`,
|
|
326
|
+
* `FUZOR_SERVER` and `FUZOR_INLINE` environment variables (which the CLI flags set), then defaults
|
|
327
|
+
* (`spa`, static, not inline). A plugin option and a different environment value is a configuration
|
|
328
|
+
* error rather than a silent override, because the CLI flag would otherwise be ignored.
|
|
329
|
+
*/
|
|
330
|
+
export function resolveFuzorProfile(options = {}, env = process.env, serverModules = []) {
|
|
331
|
+
const flag = (name) => {
|
|
332
|
+
const value = env[name]?.trim().toLowerCase();
|
|
333
|
+
if (value === undefined || value === "")
|
|
334
|
+
return undefined;
|
|
335
|
+
if (value === "1" || value === "true")
|
|
336
|
+
return true;
|
|
337
|
+
if (value === "0" || value === "false")
|
|
338
|
+
return false;
|
|
339
|
+
throw new Error(`${name} must be 1, 0, true or false; received ${JSON.stringify(env[name])}.`);
|
|
340
|
+
};
|
|
341
|
+
if (options.navigation !== undefined && !["auto", "navigation-api", "embedded"].includes(options.navigation)) {
|
|
342
|
+
throw new Error(`fuzorPlugin({ navigation }) must be "auto", "navigation-api" or "embedded"; received ${JSON.stringify(options.navigation)}.`);
|
|
343
|
+
}
|
|
344
|
+
const envTarget = env.FUZOR_TARGET?.trim() || undefined;
|
|
345
|
+
if (envTarget !== undefined && envTarget !== "spa" && envTarget !== "mpa" && envTarget !== "electron") {
|
|
346
|
+
throw new Error(`Unknown Fuzor navigation target in FUZOR_TARGET: ${envTarget}. Choose spa, mpa or electron.`);
|
|
347
|
+
}
|
|
348
|
+
const envServer = flag("FUZOR_SERVER");
|
|
349
|
+
const envInline = flag("FUZOR_INLINE");
|
|
350
|
+
const envElectron = flag("FUZOR_ELECTRON");
|
|
351
|
+
const envPlatform = env.FUZOR_PLATFORM?.trim() || undefined;
|
|
352
|
+
const platform = options.platform ?? envPlatform ?? (envTarget === "electron" ? "desktop" : "web");
|
|
353
|
+
if (!/^[a-z][a-z0-9-]*$/.test(platform))
|
|
354
|
+
throw new Error(`Invalid Fuzor platform ${JSON.stringify(platform)}. Use lowercase letters, digits and hyphens.`);
|
|
355
|
+
if (options.platform !== undefined && envPlatform !== undefined && options.platform !== envPlatform) {
|
|
356
|
+
throw new Error(`fuzorPlugin({ platform: ${JSON.stringify(options.platform)} }) conflicts with FUZOR_PLATFORM=${JSON.stringify(envPlatform)}.`);
|
|
357
|
+
}
|
|
358
|
+
const envAdapter = env.FUZOR_ADAPTER?.trim() || undefined;
|
|
359
|
+
for (const [label, value] of [["fuzorPlugin({ adapter })", options.adapter], ["FUZOR_ADAPTER", envAdapter]]) {
|
|
360
|
+
if (value !== undefined && value !== "node" && value !== "cloudflare")
|
|
361
|
+
throw new Error(`Unknown Fuzor adapter in ${label}: ${value}. Choose node or cloudflare.`);
|
|
362
|
+
}
|
|
363
|
+
if (options.adapter !== undefined && envAdapter !== undefined && options.adapter !== envAdapter) {
|
|
364
|
+
throw new Error(`fuzorPlugin({ adapter: ${JSON.stringify(options.adapter)} }) conflicts with FUZOR_ADAPTER=${JSON.stringify(envAdapter)} (set by a CLI flag or the environment). Remove one of them.`);
|
|
39
365
|
}
|
|
40
|
-
const
|
|
41
|
-
const
|
|
42
|
-
|
|
366
|
+
const adapter = (options.adapter ?? envAdapter ?? "node");
|
|
367
|
+
const conflict = (option, optionValue, variable, envValue) => {
|
|
368
|
+
if (optionValue !== undefined && envValue !== undefined && optionValue !== envValue) {
|
|
369
|
+
throw new Error(`fuzorPlugin({ ${option}: ${JSON.stringify(optionValue)} }) conflicts with ${variable}=${JSON.stringify(envValue)} (set by a CLI flag or the environment). Remove one of them.`);
|
|
370
|
+
}
|
|
371
|
+
};
|
|
372
|
+
// The CLI always states server/inline explicitly; only an enabled flag can contradict a plugin option.
|
|
373
|
+
if (envServer)
|
|
374
|
+
conflict("server", options.server, "FUZOR_SERVER", envServer);
|
|
375
|
+
if (envInline)
|
|
376
|
+
conflict("inline", options.inline, "FUZOR_INLINE", envInline);
|
|
377
|
+
const packaged = ["desktop", "ios", "android"].includes(platform);
|
|
378
|
+
const requestedTarget = envTarget ?? (envInline || options.inline || packaged ? "spa" : "mpa");
|
|
379
|
+
const mixed = envTarget === undefined && !envInline && !options.inline && !packaged;
|
|
380
|
+
const electron = options.electron ?? envElectron ?? requestedTarget === "electron";
|
|
381
|
+
const target = (requestedTarget === "electron" ? "spa" : requestedTarget);
|
|
382
|
+
const serverReasons = serverModules.map(file => file.startsWith("api/") ? `${file} defines an API endpoint` : file.endsWith(".html") ? `${file} declares request rendering` : `${file} defines server data`);
|
|
383
|
+
if (options.serverComponents) {
|
|
384
|
+
makeClientRouteMatcher(Object.fromEntries(options.serverComponents.routes.map(route => [route, "/"])));
|
|
385
|
+
for (const entry of [options.serverComponents.server, options.serverComponents.client, options.serverComponents.references].filter((value) => value !== undefined)) {
|
|
386
|
+
if (!entry || path.isAbsolute(entry) || entry.split(/[\\/]/).includes(".."))
|
|
387
|
+
throw new Error("Server component entries must be paths inside the project.");
|
|
388
|
+
}
|
|
389
|
+
if (!options.serverComponents.client && !options.serverComponents.references)
|
|
390
|
+
throw new Error("Server components require a client entry or generated reference directory.");
|
|
391
|
+
if (!options.serverComponents.routes.length)
|
|
392
|
+
throw new Error("Server components need at least one route.");
|
|
393
|
+
if (options.navigation === "embedded")
|
|
394
|
+
throw new Error("Server components require HTTP navigation.");
|
|
395
|
+
serverReasons.push(`${options.serverComponents.server} defines server components`);
|
|
396
|
+
}
|
|
397
|
+
const inline = electron || packaged ? true : options.inline ?? envInline ?? false;
|
|
398
|
+
if (inline && target !== "spa")
|
|
399
|
+
throw new Error("Inline output is only supported for the SPA target.");
|
|
400
|
+
if (electron && target !== "spa")
|
|
401
|
+
throw new Error("Electron output is only supported for the SPA target.");
|
|
402
|
+
if (serverReasons.length) {
|
|
403
|
+
const needs = `This app needs server output because ${serverReasons.join("; ")}.`;
|
|
404
|
+
if (inline)
|
|
405
|
+
throw new Error(`${needs} Inline SPA output is a static single file and cannot answer data requests; remove --inline.`);
|
|
406
|
+
if (options.server === false)
|
|
407
|
+
throw new Error(`${needs} Remove server: false from fuzorPlugin().`);
|
|
408
|
+
if (envServer === false)
|
|
409
|
+
throw new Error(`${needs} Unset FUZOR_SERVER=0.`);
|
|
410
|
+
}
|
|
411
|
+
if (adapter === "cloudflare" && inline)
|
|
412
|
+
throw new Error("The cloudflare adapter builds a Worker and cannot be combined with inline output.");
|
|
413
|
+
if (adapter === "cloudflare" && options.server === false)
|
|
414
|
+
throw new Error("The cloudflare adapter implies server output; remove server: false.");
|
|
415
|
+
const server = serverReasons.length > 0 || adapter === "cloudflare" || (options.server ?? envServer ?? false);
|
|
416
|
+
if (inline && server)
|
|
43
417
|
throw new Error("SPA inline output cannot be combined with server output.");
|
|
44
|
-
|
|
418
|
+
return { target, mixed, backendOutDir: ".fuzor/dist-backend", platform, server, inline, outDir: electron ? ".fuzor/dist-desktop" : platform !== "web" ? `.fuzor/dist-${platform}` : mixed ? ".fuzor/web/dist" : `.fuzor/web/dist-${target}`, serverReasons, adapter, ...(electron ? { electron: true } : {}) };
|
|
419
|
+
}
|
|
420
|
+
export function fuzorPlugin(options = {}) {
|
|
421
|
+
const nested = nestedServer.getStore() === true;
|
|
422
|
+
let viewBuildId = randomUUID();
|
|
423
|
+
let referencesPromise;
|
|
424
|
+
const references = () => referencesPromise ??= discoverViewReferences(vite.root, options.serverComponents.references);
|
|
425
|
+
const referenceStub = (file, refs) => {
|
|
426
|
+
const relative = path.relative(vite.root, file).split(path.sep).join("/");
|
|
427
|
+
const client = refs.clients.find(ref => ref.file === relative);
|
|
428
|
+
if (client)
|
|
429
|
+
return `export default ${JSON.stringify({ id: client.id })};`;
|
|
430
|
+
const closures = refs.closures.filter(ref => ref.file === relative);
|
|
431
|
+
if (closures.length)
|
|
432
|
+
return readFile(file, "utf8").then(code => replaceClosures(code, closures));
|
|
433
|
+
const handlers = refs.handlers.filter(ref => ref.file === relative);
|
|
434
|
+
return handlers.length ? handlers.map(ref => `export const ${ref.name}=${JSON.stringify({ id: ref.id })};`).join("\n") : undefined;
|
|
435
|
+
};
|
|
436
|
+
const generatedViews = async (views) => {
|
|
437
|
+
if (!options.serverComponents?.references)
|
|
438
|
+
return views;
|
|
439
|
+
const refs = await references();
|
|
440
|
+
return { ...views, manifest: { buildId: viewBuildId, templates: refs.templates }, components: refs.clients.map(ref => ref.id), handlers: [...refs.handlers.map(ref => ref.id), ...refs.closures.map(ref => ref.id)] };
|
|
441
|
+
};
|
|
442
|
+
const configuredEnvironments = normalizeEnvironmentConfiguration(options.experimental?.environments);
|
|
443
|
+
const environmentNames = {
|
|
444
|
+
client: configuredEnvironments.client ?? "client",
|
|
445
|
+
server: configuredEnvironments.server ?? "server",
|
|
446
|
+
edge: configuredEnvironments.edge ?? "edge"
|
|
447
|
+
};
|
|
448
|
+
const environmentApiEnabled = Object.keys(configuredEnvironments).length > 0;
|
|
449
|
+
const moduleEnvironment = options.experimental?.runtime === "edge" ? environmentNames.edge : environmentNames.server;
|
|
450
|
+
// Validated immediately for early errors; server data detection refines it once the root is known.
|
|
451
|
+
let profile = resolveFuzorProfile(options);
|
|
452
|
+
let { target, inline } = profile;
|
|
453
|
+
let withServer = profile.server;
|
|
454
|
+
let serverModuleFiles = [];
|
|
455
|
+
let apiFiles = [];
|
|
456
|
+
/**
|
|
457
|
+
* Development CSS arrives through module imports; client:none components have none, so documents import them
|
|
458
|
+
* for their styles. Production builds link the extracted stylesheets instead.
|
|
459
|
+
*/
|
|
460
|
+
const withStaticModuleImports = (html) => {
|
|
461
|
+
const withoutPrevious = html.replace(/<script type="module" data-fuzor-static-css>.*?<\/script>/g, "");
|
|
462
|
+
const files = [...withoutPrevious.matchAll(/<!--fuzor:static ([^\s]+?)-->/g)].flatMap(match => islands.filter(island => island.name === match[1]).map(island => island.file));
|
|
463
|
+
return files.length ? withoutPrevious.replace("</head>", () => `<script type="module" data-fuzor-static-css>${[...new Set(files)].map(file => `import ${JSON.stringify(file)};`).join("")}</script></head>`) : withoutPrevious;
|
|
464
|
+
};
|
|
465
|
+
let buildFailed = false;
|
|
466
|
+
/** Stylesheets each island loads, from the client bundle. */
|
|
467
|
+
let islandStyles = {};
|
|
468
|
+
let bundleWritten = false;
|
|
45
469
|
let vite;
|
|
470
|
+
let environmentCapability = { supported: false, reason: "legacy" };
|
|
471
|
+
const environmentState = new Map();
|
|
472
|
+
let releaseRuntimeHooks = () => { };
|
|
473
|
+
let runtimes;
|
|
474
|
+
/** Runtime copies of framework adapters and renderers, by resolved module ID. */
|
|
475
|
+
const runtimeModules = new Map();
|
|
476
|
+
/** Path deployment base from Vite's `base`; relative and absolute-URL bases leave routes at `/`. */
|
|
477
|
+
let pathBase = "/";
|
|
478
|
+
/** The shell's own head, read before any page metadata is applied to it. */
|
|
479
|
+
let shellHead = {};
|
|
480
|
+
const fallbacks = () => ({ notFound: applyBaseToLinks(notFoundHtml, pathBase), error: applyBaseToLinks(errorHtml, pathBase), base: pathBase, head: shellHead });
|
|
46
481
|
let project;
|
|
482
|
+
let pageScripts = [];
|
|
483
|
+
const nativeHandlers = new Map();
|
|
484
|
+
let inlineModuleFiles = [];
|
|
485
|
+
let scriptRoutes = [];
|
|
486
|
+
const routeScriptId = (route) => `virtual:fuzor/route-client/${encodeURIComponent(route.path)}/${route.path === "/" ? "index" : route.path.split("/").filter(Boolean).join("-").replace(/[^a-zA-Z0-9_-]/g, "_")}-client.js`;
|
|
487
|
+
const pageScriptId = (script) => `virtual:fuzor/page-script/${script.id}.js`;
|
|
488
|
+
let revision = 0;
|
|
489
|
+
let compilation;
|
|
47
490
|
let projectPromise;
|
|
48
|
-
let rawProject;
|
|
49
491
|
let devServer;
|
|
50
|
-
let
|
|
492
|
+
let hydrationScript = "";
|
|
51
493
|
let islands = [];
|
|
52
494
|
const loadProject = async () => {
|
|
53
495
|
if (project)
|
|
54
496
|
return project;
|
|
55
497
|
if (projectPromise)
|
|
56
498
|
return projectPromise;
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
499
|
+
const version = revision;
|
|
500
|
+
const lifetime = new AbortController();
|
|
501
|
+
compilation = lifetime;
|
|
502
|
+
const registry = islands;
|
|
503
|
+
let solidHydrationScript = "";
|
|
504
|
+
const pending = (async () => {
|
|
505
|
+
let owned;
|
|
506
|
+
const createModuleServer = () => nestedServer.run(true, () => createServer(nestedServerConfig(vite)));
|
|
507
|
+
const moduleServer = () => devServer ? Promise.resolve(devServer) : owned ??= createModuleServer();
|
|
508
|
+
// client:none analysis reads client transforms without HMR code, which the dev server would add. It has its
|
|
509
|
+
// own server: client transforms wait for pending requests to settle, and preview renders on the module
|
|
510
|
+
// server are waiting for this analysis.
|
|
511
|
+
let ownedAnalysis;
|
|
512
|
+
const analysisServer = () => ownedAnalysis ??= createModuleServer();
|
|
513
|
+
const analyzed = new Map();
|
|
514
|
+
const analyze = (entry) => {
|
|
515
|
+
let pending = analyzed.get(entry);
|
|
516
|
+
if (!pending) {
|
|
517
|
+
pending = (async () => {
|
|
518
|
+
const server = await analysisServer();
|
|
519
|
+
const { parseAstAsync } = await import("vite");
|
|
520
|
+
const findings = [];
|
|
521
|
+
const seen = new Set();
|
|
522
|
+
const queue = [entry];
|
|
523
|
+
while (queue.length) {
|
|
524
|
+
const url = queue.shift();
|
|
525
|
+
if (seen.has(url))
|
|
526
|
+
continue;
|
|
527
|
+
seen.add(url);
|
|
528
|
+
const result = await server.transformRequest(url);
|
|
529
|
+
if (!result)
|
|
530
|
+
continue;
|
|
531
|
+
const program = await parseAstAsync(result.code);
|
|
532
|
+
findings.push(...findInteractiveConstructs(program, path.join(vite.root, url.split("?")[0])));
|
|
533
|
+
queue.push(...projectImports(program));
|
|
534
|
+
}
|
|
535
|
+
return findings;
|
|
536
|
+
})();
|
|
537
|
+
analyzed.set(entry, pending);
|
|
538
|
+
}
|
|
539
|
+
return pending;
|
|
540
|
+
};
|
|
70
541
|
try {
|
|
71
|
-
|
|
72
|
-
|
|
542
|
+
const raw = await compileRaw(lifetime.signal, async (file) => createEnvironmentModuleRuntime(await moduleServer(), moduleEnvironment, environmentApiEnabled).loadModule(file));
|
|
543
|
+
if (registry.length === 0) {
|
|
544
|
+
const missing = async (name) => { throw new Error(`Unknown Fuzor component: ${name}`); };
|
|
545
|
+
return await compileIslands(raw, missing, { signal: lifetime.signal });
|
|
546
|
+
}
|
|
547
|
+
const server = await moduleServer();
|
|
548
|
+
const modules = new Map();
|
|
549
|
+
const renderer = async (name, props, id, mode) => {
|
|
550
|
+
const island = registry.find((entry) => entry.name === name);
|
|
73
551
|
if (!island)
|
|
74
552
|
throw new Error(`Unknown Fuzor island: ${name}`);
|
|
75
|
-
|
|
553
|
+
const key = name;
|
|
554
|
+
let loaded = modules.get(key);
|
|
76
555
|
if (!loaded) {
|
|
77
|
-
loaded = server.
|
|
78
|
-
modules.set(
|
|
556
|
+
loaded = createEnvironmentModuleRuntime(server, moduleEnvironment, environmentApiEnabled).loadModule(island.file);
|
|
557
|
+
modules.set(key, loaded);
|
|
79
558
|
}
|
|
80
559
|
const module = await loaded;
|
|
560
|
+
const staticMount = module.mount;
|
|
561
|
+
if (mode === "static") {
|
|
562
|
+
if (staticMount && !staticMount.framework) {
|
|
563
|
+
throw new Error(`${island.file} exports mount(), which client:none never runs. Remove mount() for a build-only component, or use another client: directive.`);
|
|
564
|
+
}
|
|
565
|
+
if (island.file.endsWith(".vue") || staticMount?.framework) {
|
|
566
|
+
const findings = await analyze(island.file);
|
|
567
|
+
if (findings.length)
|
|
568
|
+
throw new Error(`client:none would drop behavior of ${island.file}. It uses:\n${describeFindings(findings, vite.root)}\nUse client:load, client:idle, client:visible or client:interaction instead.`);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
81
571
|
if (island.file.endsWith(".vue")) {
|
|
82
|
-
const
|
|
572
|
+
const load = createEnvironmentModuleRuntime(server, moduleEnvironment, environmentApiEnabled).loadModule;
|
|
573
|
+
const { createSSRApp, renderToString } = await load("virtual:fuzor/compiler/vue");
|
|
83
574
|
return renderToString(createSSRApp(module.default, props));
|
|
84
575
|
}
|
|
85
576
|
const mount = module.mount;
|
|
86
577
|
if (mount?.framework === "react" && mount.component) {
|
|
87
|
-
const
|
|
88
|
-
|
|
578
|
+
const runtime = runtimes?.scopeOf(island.file)?.key;
|
|
579
|
+
const rendererId = runtime ? `virtual:fuzor/compiler/react@${runtime}` : "virtual:fuzor/compiler/react";
|
|
580
|
+
const load = createEnvironmentModuleRuntime(server, moduleEnvironment, environmentApiEnabled).loadModule;
|
|
581
|
+
const { createElement, renderToString } = await load(rendererId);
|
|
582
|
+
if (mode === "static") {
|
|
583
|
+
const { renderToStaticMarkup } = await load(rendererId);
|
|
584
|
+
return renderToStaticMarkup(createElement(mount.component, props));
|
|
585
|
+
}
|
|
586
|
+
const tree = mount.element ? mount.element(props) : createElement(mount.component, props);
|
|
587
|
+
return renderToString(tree, { identifierPrefix: `fuzor-${id}-` });
|
|
89
588
|
}
|
|
90
589
|
if (mount?.framework === "solid" && mount.component) {
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
590
|
+
const solidRuntime = runtimes?.scopeOf(island.file)?.key;
|
|
591
|
+
const load = createEnvironmentModuleRuntime(server, moduleEnvironment, environmentApiEnabled).loadModule;
|
|
592
|
+
const { createComponent, renderToString, generateHydrationScript } = await load(solidRuntime ? `virtual:fuzor/compiler/solid@${solidRuntime}` : "virtual:fuzor/compiler/solid");
|
|
593
|
+
if (mode === "hydrate")
|
|
594
|
+
solidHydrationScript = generateHydrationScript();
|
|
595
|
+
const html = renderToString(() => createComponent(mount.component, props), { renderId: id });
|
|
596
|
+
// Hydration keys only matter to Solid's client, which a client:none component never loads.
|
|
597
|
+
return mode === "static" ? html.replace(/ data-hk="[^"]*"/g, "") : html;
|
|
598
|
+
}
|
|
599
|
+
// Public adapter contract: any island module may render its preview at build time.
|
|
600
|
+
if (typeof module.render === "function") {
|
|
601
|
+
const html = await module.render(props, { id });
|
|
602
|
+
if (typeof html !== "string")
|
|
603
|
+
throw new Error(`${island.file}: render() must return a string or a promise of one.`);
|
|
604
|
+
return html;
|
|
94
605
|
}
|
|
95
|
-
if (typeof module.render === "function")
|
|
96
|
-
return module.render(props);
|
|
97
606
|
return undefined;
|
|
98
|
-
}
|
|
607
|
+
};
|
|
608
|
+
return await compileIslands(raw, renderer, { signal: lifetime.signal });
|
|
99
609
|
}
|
|
100
610
|
finally {
|
|
101
|
-
|
|
611
|
+
if (owned)
|
|
612
|
+
await (await owned).close();
|
|
613
|
+
if (ownedAnalysis) {
|
|
614
|
+
const analysis = await ownedAnalysis;
|
|
615
|
+
// Client transforms can start dependency pre-bundling (Solid's plugin adds entries); closing before it
|
|
616
|
+
// settles leaves esbuild's service referenced and the build process never exits.
|
|
617
|
+
const client = analysis.environments?.client;
|
|
618
|
+
await client?.waitForRequestsIdle?.();
|
|
619
|
+
await client?.depsOptimizer?.scanProcessing;
|
|
620
|
+
await analysis.close();
|
|
621
|
+
}
|
|
102
622
|
}
|
|
103
623
|
})();
|
|
624
|
+
const published = pending.then(result => {
|
|
625
|
+
if (version !== revision)
|
|
626
|
+
return loadProject();
|
|
627
|
+
hydrationScript = solidHydrationScript;
|
|
628
|
+
if (options.routeTypes !== false)
|
|
629
|
+
void writeRouteTypes(result).catch(error => vite.logger?.warn(`[fuzor] Could not write .fuzor/routes.d.ts: ${String(error)}`));
|
|
630
|
+
project = pathBase === "/" ? result : { ...result,
|
|
631
|
+
routes: result.routes.map(route => ({ ...route, html: applyBaseToLinks(route.html, pathBase) })),
|
|
632
|
+
...(result.boundaries ? { boundaries: result.boundaries.map(boundary => ({ ...boundary, html: applyBaseToLinks(boundary.html, pathBase) })) } : {}) };
|
|
633
|
+
return project;
|
|
634
|
+
}, error => {
|
|
635
|
+
if (version !== revision)
|
|
636
|
+
return loadProject();
|
|
637
|
+
throw error;
|
|
638
|
+
});
|
|
639
|
+
projectPromise = published;
|
|
104
640
|
try {
|
|
105
|
-
return await
|
|
641
|
+
return await published;
|
|
106
642
|
}
|
|
107
643
|
finally {
|
|
108
|
-
projectPromise
|
|
644
|
+
if (projectPromise === published)
|
|
645
|
+
projectPromise = undefined;
|
|
646
|
+
if (compilation === lifetime)
|
|
647
|
+
compilation = undefined;
|
|
109
648
|
}
|
|
110
649
|
};
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
650
|
+
// Dev servers recompile on every change; unchanged pages come from here.
|
|
651
|
+
const compileCache = new CompileCache();
|
|
652
|
+
let writtenTypes = "";
|
|
653
|
+
const writeRouteTypes = async (compiled) => {
|
|
654
|
+
const file = path.join(vite.root, ".fuzor/routes.d.ts");
|
|
655
|
+
// Import specifiers use .js, which TypeScript maps to the .ts source under Bundler and NodeNext resolution.
|
|
656
|
+
const moduleSpecifier = (source) => {
|
|
657
|
+
const relative = path.relative(path.dirname(file), source).split(path.sep).join("/").replace(/\.ts$/, ".js").replace(/\.mts$/, ".mjs");
|
|
658
|
+
return relative.startsWith(".") ? relative : `./${relative}`;
|
|
659
|
+
};
|
|
660
|
+
const content = routeTypes([
|
|
661
|
+
...compiled.routes.map(route => ({ pattern: route.pattern ?? route.path, ...(route.paramsSchema ? { paramsModule: moduleSpecifier(route.paramsSchema) } : {}) })),
|
|
662
|
+
...apiFiles.map(route => route.pattern)
|
|
663
|
+
]);
|
|
664
|
+
if (content === writtenTypes)
|
|
665
|
+
return;
|
|
666
|
+
if (await readFile(file, "utf8").catch(() => "") !== content) {
|
|
667
|
+
await mkdir(path.dirname(file), { recursive: true });
|
|
668
|
+
await writeFile(file, content, "utf8");
|
|
124
669
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
670
|
+
writtenTypes = content;
|
|
671
|
+
};
|
|
672
|
+
const compileRaw = async (signal, loadModule) => {
|
|
673
|
+
let compiled = await compileProject(vite.root, { ...(options.markdown ? { markdown: options.markdown } : {}), ...(options.redirects ? { redirects: options.redirects } : {}), platform: profile.platform, signal, loadModule, cache: compileCache })
|
|
674
|
+
.catch(async (error) => { throw await withViteLocation(error); });
|
|
675
|
+
const entry = options.entry ?? process.env.FUZOR_ENTRY;
|
|
676
|
+
if (entry) {
|
|
677
|
+
if (!inline || target !== "spa")
|
|
678
|
+
throw new Error("An application entry requires an inline SPA build.");
|
|
679
|
+
const scope = routeKey(entry);
|
|
680
|
+
const rootRoute = compiled.routes.find(route => route.path === scope);
|
|
681
|
+
if (!scope || !rootRoute || rootRoute.policy?.navigation !== "spa")
|
|
682
|
+
throw new Error("Application entry must name a declared SPA boundary.");
|
|
683
|
+
const selected = compiled.routes.filter(route => route.path.startsWith(scope) && route.policy?.navigation === "spa" && route.policy.rendering === "static");
|
|
684
|
+
if (selected.some(route => route.serverData))
|
|
685
|
+
throw new Error("Inline application entries cannot use same-origin server-data endpoints. Use an explicitly hosted backend API in client code, or an HTTP rendering deployment.");
|
|
686
|
+
const rebase = (value) => scope === "/" || !value.startsWith(scope) ? value : "/" + value.slice(scope.length);
|
|
687
|
+
compiled = { ...compiled, routes: selected.map(route => ({ ...route, path: rebase(route.path), html: rewriteNavigationLinks(route.html, rebase), policy: { ...route.policy, spaScope: rebase(route.policy.spaScope ?? scope) } })), boundaries: [], redirects: {} };
|
|
688
|
+
if (!compiled.routes.some(route => route.path === "/"))
|
|
689
|
+
throw new Error("Application entry must have a static root template; request-rendered routes require an HTTP rendering deployment.");
|
|
690
|
+
}
|
|
691
|
+
const deployment = options.deployment ?? process.env.FUZOR_DEPLOYMENT;
|
|
692
|
+
const requestRoutes = compiled.routes.filter(route => route.policy?.rendering === "request");
|
|
693
|
+
if (deployment && !["static", "github-pages", "node", "cloudflare"].includes(deployment))
|
|
694
|
+
throw new Error("Unknown Fuzor deployment target: " + deployment);
|
|
695
|
+
if ((deployment === "static" || deployment === "github-pages") && (requestRoutes.length || options.serverComponents?.routes.length))
|
|
696
|
+
throw new Error(`Route ${(requestRoutes[0]?.path ?? options.serverComponents.routes[0])} requires request-time server rendering. ${deployment} supports static files only. Pre-render this route, regenerate and republish its files, or choose node/cloudflare rendering. Remote API calls from static SPAs are allowed.`);
|
|
697
|
+
for (const route of requestRoutes)
|
|
698
|
+
if (route.requestPattern && route.policy?.navigation === "spa" && !options.serverComponents?.routes.some(pattern => makeClientRouteMatcher({ [pattern]: "/" })(route.path)))
|
|
699
|
+
throw new Error(`${route.source}: unenumerated request routes inside an SPA require a server-component renderer. Use navigation=document or register serverComponents.`);
|
|
700
|
+
if (options.routeTree) {
|
|
701
|
+
if (target !== "spa" && !profile.mixed)
|
|
702
|
+
throw new Error("routeTree requires a SPA target.");
|
|
703
|
+
makeRouteMatches(options.routeTree);
|
|
704
|
+
const check = (value, seen = new Set()) => {
|
|
705
|
+
if (value === undefined || value === null || typeof value === "string" || typeof value === "boolean" || (typeof value === "number" && Number.isFinite(value)))
|
|
706
|
+
return;
|
|
707
|
+
if (typeof value !== "object" || seen.has(value))
|
|
708
|
+
throw new Error("routeTree handles must be serializable JSON data.");
|
|
709
|
+
if (!Array.isArray(value) && Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null)
|
|
710
|
+
throw new Error("routeTree handles must be serializable JSON data.");
|
|
711
|
+
seen.add(value);
|
|
712
|
+
for (const child of Object.values(value))
|
|
713
|
+
check(child, seen);
|
|
714
|
+
seen.delete(value);
|
|
715
|
+
};
|
|
716
|
+
check(options.routeTree);
|
|
129
717
|
}
|
|
718
|
+
if (options.clientRoutes && Object.keys(options.clientRoutes).length) {
|
|
719
|
+
if (target !== "spa" || !options.serverComponents && (withServer || apiFiles.length > 0 || serverModuleFiles.length > 0))
|
|
720
|
+
throw new Error("clientRoutes requires a static SPA target.");
|
|
721
|
+
makeClientRouteMatcher(options.clientRoutes);
|
|
722
|
+
for (const target of Object.values(options.clientRoutes)) {
|
|
723
|
+
const route = compiled.routes.find(route => route.path === routeKey(target));
|
|
724
|
+
if (!route)
|
|
725
|
+
throw new Error(`Client route template ${target} is not compiled.`);
|
|
726
|
+
if (route.serverData)
|
|
727
|
+
throw new Error("Client route templates cannot have server data.");
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
for (const warning of compiled.warnings ?? [])
|
|
731
|
+
vite.logger.warn(`[fuzor] ${warning}`);
|
|
732
|
+
const shadowed = apiFiles.length ? compiled.routes.find(route => route.path === "/api/" || route.path.startsWith("/api/")) : undefined;
|
|
733
|
+
if (shadowed)
|
|
734
|
+
throw new Error(`${path.relative(vite.root, shadowed.source)} is below /api/, which belongs to the api/ folder. Move the page.`);
|
|
735
|
+
const extracted = extractPageScripts(compiled, vite.root);
|
|
736
|
+
pageScripts = extracted.scripts;
|
|
737
|
+
scriptRoutes = extracted.routes;
|
|
738
|
+
return extracted.project;
|
|
739
|
+
};
|
|
740
|
+
const scanIslands = async () => {
|
|
741
|
+
return Effect.runPromise(scanIslandModulesEffect(vite.root, Object.keys(options.runtimes ?? {})));
|
|
130
742
|
};
|
|
131
743
|
const refresh = async (server) => {
|
|
744
|
+
const version = ++revision;
|
|
745
|
+
viewBuildId = randomUUID();
|
|
746
|
+
referencesPromise = undefined;
|
|
747
|
+
compilation?.abort();
|
|
132
748
|
project = undefined;
|
|
133
|
-
rawProject = undefined;
|
|
134
749
|
projectPromise = undefined;
|
|
135
|
-
|
|
136
|
-
|
|
750
|
+
hydrationScript = "";
|
|
751
|
+
const nextApi = findApiRoutes(vite.root);
|
|
752
|
+
const nextModules = (options.entry ?? process.env.FUZOR_ENTRY) && inline ? [] : [...findServerModules(vite.root), ...nextApi.map(route => route.relative)];
|
|
753
|
+
const nextProfile = resolveFuzorProfile(options, process.env, nextModules);
|
|
754
|
+
apiFiles = nextApi;
|
|
755
|
+
serverModuleFiles = nextModules;
|
|
756
|
+
profile = nextProfile;
|
|
757
|
+
withServer = profile.server;
|
|
758
|
+
const nextIslands = await scanIslands();
|
|
759
|
+
if (version !== revision)
|
|
760
|
+
return;
|
|
761
|
+
islands = nextIslands;
|
|
137
762
|
await loadProject();
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
763
|
+
if (version !== revision)
|
|
764
|
+
return;
|
|
765
|
+
invalidateEnvironmentModule(server, resolvedVirtualId, environmentNames.client, environmentApiEnabled);
|
|
766
|
+
environmentState.set(environmentNames.server, { revision, ...(project ? { project } : {}) });
|
|
141
767
|
server.ws.send({ type: "full-reload" });
|
|
142
768
|
};
|
|
143
769
|
return {
|
|
144
770
|
name: "fuzor",
|
|
145
771
|
enforce: "pre",
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
772
|
+
api: {
|
|
773
|
+
profile: () => profile,
|
|
774
|
+
project: () => loadProject(),
|
|
775
|
+
apiRoutes: () => apiFiles.map(route => ({ pattern: route.pattern, source: route.relative })),
|
|
776
|
+
environments: () => ({ ...environmentNames }),
|
|
777
|
+
environmentApi: () => environmentCapability
|
|
778
|
+
},
|
|
779
|
+
async config(config) {
|
|
780
|
+
const projectRoot = path.resolve(config.root ?? process.cwd());
|
|
781
|
+
runtimes = createRuntimes(projectRoot, options.runtimes);
|
|
782
|
+
// Dependency pre-bundling resolves imports inside aliased packages with its own bundler.
|
|
783
|
+
const viteModule = runtimes.enabled ? await import("vite") : {};
|
|
784
|
+
const runtimeOptimizer = runtimes.enabled ? (() => {
|
|
785
|
+
const active = runtimes;
|
|
786
|
+
const rootFile = path.join(projectRoot, "package.json");
|
|
787
|
+
// Vite 8 bundles dependencies with Rolldown and exports its version; earlier majors use esbuild.
|
|
788
|
+
if ("rolldownVersion" in viteModule) {
|
|
789
|
+
return { rolldownOptions: { plugins: [{ name: "fuzor:runtimes", async resolveId(source, importer) {
|
|
790
|
+
const runtime = importer ? active.packageScope(importer) : undefined;
|
|
791
|
+
const mapped = runtime && active.mapSpecifier(runtime, source);
|
|
792
|
+
return mapped ? this.resolve(mapped, rootFile, { skipSelf: true }) : null;
|
|
793
|
+
} }] } };
|
|
794
|
+
}
|
|
795
|
+
return { esbuildOptions: { plugins: [{ name: "fuzor:runtimes", setup(build) {
|
|
796
|
+
build.onResolve({ filter: /^[\w@]/ }, async (args) => {
|
|
797
|
+
const runtime = args.importer ? active.packageScope(args.importer) : undefined;
|
|
798
|
+
const mapped = runtime && active.mapSpecifier(runtime, args.path);
|
|
799
|
+
if (!mapped)
|
|
800
|
+
return undefined;
|
|
801
|
+
const result = await build.resolve(mapped, { kind: args.kind, resolveDir: projectRoot });
|
|
802
|
+
return result.errors.length ? { errors: result.errors } : { path: result.path, external: result.external, namespace: result.namespace };
|
|
803
|
+
});
|
|
804
|
+
} }] } };
|
|
805
|
+
})() : {};
|
|
806
|
+
if (nested)
|
|
807
|
+
return { resolve: { dedupe: ["react", "react-dom", "solid-js", "vue"] }, ...(runtimes.enabled ? { optimizeDeps: runtimeOptimizer } : {}) };
|
|
808
|
+
apiFiles = findApiRoutes(path.resolve(config.root ?? process.cwd()));
|
|
809
|
+
serverModuleFiles = (options.entry ?? process.env.FUZOR_ENTRY) && inline ? [] : [...findServerModules(path.resolve(config.root ?? process.cwd())), ...apiFiles.map(route => route.relative)];
|
|
810
|
+
profile = resolveFuzorProfile(options, process.env, serverModuleFiles);
|
|
811
|
+
({ target, inline } = profile);
|
|
812
|
+
withServer = profile.server;
|
|
813
|
+
if (options.clientRoutes && Object.keys(options.clientRoutes).length && (target !== "spa" || withServer && !options.serverComponents))
|
|
814
|
+
throw new Error("clientRoutes requires a static SPA target.");
|
|
815
|
+
const packageJson = await readFile(path.join(path.resolve(config.root ?? process.cwd()), "package.json"), "utf8").then(text => JSON.parse(text), () => ({}));
|
|
816
|
+
const dependencies = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
817
|
+
const include = ["Cause", "Context", "Deferred", "Effect", "Exit", "Fiber", "Layer", "Schema", "Scope", "reactivity/Atom", "reactivity/AtomRegistry"].map(module => `fuzor > effect/${module}`);
|
|
818
|
+
if (dependencies.react && dependencies["react-dom"])
|
|
819
|
+
include.push("react", "react-dom/client", "react/jsx-runtime", "react/jsx-dev-runtime");
|
|
820
|
+
if (dependencies.vue)
|
|
821
|
+
include.push("vue");
|
|
822
|
+
return {
|
|
823
|
+
resolve: { dedupe: ["react", "react-dom", "solid-js", "vue"] },
|
|
824
|
+
// A `*.fragment.html` is a compiled fragment, not a page: Vite's dependency scan would load it as an entry and
|
|
825
|
+
// fail on the virtual module it resolves to. Pages keep Vite's own default of every `.html` file.
|
|
826
|
+
optimizeDeps: { include, ...(config.optimizeDeps?.entries === undefined ? { entries: ["**/*.html", "!**/*.fragment.html"] } : {}), ...runtimeOptimizer },
|
|
827
|
+
// Vite 6.4 accepts named environments in the config hook. This is
|
|
828
|
+
// emitted only for explicit opt-in; Vite 6/7 legacy users are untouched.
|
|
829
|
+
...(options.experimental?.environments ? {
|
|
830
|
+
environments: Object.fromEntries(Object.values(environmentNames).filter(name => name !== "client").map(name => [name, { consumer: "server" }]))
|
|
831
|
+
} : {}),
|
|
832
|
+
build: {
|
|
833
|
+
...(config.build?.outDir === undefined ? { outDir: process.env.FUZOR_STAGE_DIR ? path.join(process.env.FUZOR_STAGE_DIR, profile.outDir) : profile.outDir } : {}),
|
|
834
|
+
...(target === "spa" && inline ? { cssCodeSplit: false, modulePreload: false, assetsInlineLimit: Number.MAX_SAFE_INTEGER } : {})
|
|
835
|
+
}
|
|
836
|
+
};
|
|
157
837
|
},
|
|
158
838
|
async configResolved(config) {
|
|
159
839
|
vite = config;
|
|
160
|
-
|
|
161
|
-
|
|
840
|
+
environmentCapability = detectViteEnvironmentApi({ config });
|
|
841
|
+
pathBase = normalizeBase(config.base);
|
|
842
|
+
if (nested)
|
|
843
|
+
return;
|
|
844
|
+
islands = await scanIslands();
|
|
845
|
+
checkRendererVersions(config.root, islands, options.runtimes);
|
|
846
|
+
if (runtimes?.enabled) {
|
|
847
|
+
const vueRuntime = islands.find(island => island.file.endsWith(".vue") && runtimes.scopeOf(island.file));
|
|
848
|
+
if (vueRuntime)
|
|
849
|
+
throw new Error(`${vueRuntime.file}: runtimes support JSX islands only. Vue's compiler adds its own imports of vue, which Fuzor cannot redirect.`);
|
|
850
|
+
}
|
|
162
851
|
},
|
|
163
|
-
resolveId(id) {
|
|
164
|
-
|
|
852
|
+
async resolveId(id, importer, resolveOptions) {
|
|
853
|
+
if (!resolveOptions.ssr)
|
|
854
|
+
assertBrowserViewImport(id, importer);
|
|
855
|
+
if (id === "fuzor/server-components/server" && !resolveOptions.ssr) {
|
|
856
|
+
throw new Error("The server-component evaluator is server-only. Import browser runtime and protocol separately.");
|
|
857
|
+
}
|
|
858
|
+
if (id.startsWith("virtual:fuzor/route-client/"))
|
|
859
|
+
return `\0${id}`;
|
|
860
|
+
if (id.startsWith("virtual:fuzor/page-script/"))
|
|
861
|
+
return `\0${id}`;
|
|
862
|
+
if (id.startsWith("virtual:fuzor/native-handler/"))
|
|
863
|
+
return `\0${id}`;
|
|
864
|
+
if (importer?.startsWith("\0virtual:fuzor/native-handler/") && id.startsWith(".")) {
|
|
865
|
+
const handler = [...nativeHandlers.values()].find(handler => importer === `\0virtual:fuzor/native-handler/${handler.id}.js`);
|
|
866
|
+
if (handler)
|
|
867
|
+
return this.resolve(path.resolve(path.dirname(handler.source), id), undefined, { skipSelf: true });
|
|
868
|
+
}
|
|
869
|
+
if (importer?.startsWith("\0virtual:fuzor/page-script/")) {
|
|
870
|
+
const script = pageScripts.find(script => `\0${pageScriptId(script)}` === importer);
|
|
871
|
+
if (script)
|
|
872
|
+
return this.resolve(id, script.source, { ...resolveOptions, skipSelf: true });
|
|
873
|
+
}
|
|
874
|
+
if (id.endsWith(".fragment.html")) {
|
|
875
|
+
const file = await this.resolve(id, importer, { ...resolveOptions, skipSelf: true });
|
|
876
|
+
if (file)
|
|
877
|
+
return file.id.startsWith("\0fuzor:fragment:") ? file.id : `\0fuzor:fragment:${file.id}.js`;
|
|
878
|
+
}
|
|
879
|
+
if (id.startsWith("virtual:fuzor/closure/"))
|
|
880
|
+
return `\0fuzor:closure:${id.slice("virtual:fuzor/closure/".length)}.ts`;
|
|
881
|
+
if (id === "virtual:fuzor/views" || id === virtualId || Object.hasOwn(rendererModules, id))
|
|
882
|
+
return `\0${id}`;
|
|
883
|
+
if (id === "fuzor/ui" || id.startsWith("fuzor/ui/")) {
|
|
884
|
+
const projectImporter = importer && !importer.startsWith("\0") ? importer : path.join(vite.root, "package.json");
|
|
885
|
+
const resolved = await this.resolve(id, projectImporter, { ...resolveOptions, skipSelf: true });
|
|
886
|
+
if (resolved)
|
|
887
|
+
return resolved;
|
|
888
|
+
// Virtual docs imports can resolve against Fuzor itself when the host
|
|
889
|
+
// does not expose a workspace link at the project root.
|
|
890
|
+
const fallback = id === "fuzor/ui" ? `fuzor/ui/${resolveOptions.ssr ? "server" : "client"}` : id;
|
|
891
|
+
const local = await this.resolve(fallback, fileURLToPath(import.meta.url), { ...resolveOptions, skipSelf: true });
|
|
892
|
+
if (local)
|
|
893
|
+
return local;
|
|
894
|
+
try {
|
|
895
|
+
return fileURLToPath(import.meta.resolve(fallback));
|
|
896
|
+
}
|
|
897
|
+
catch { }
|
|
898
|
+
}
|
|
899
|
+
if (!runtimes?.enabled)
|
|
900
|
+
return undefined;
|
|
901
|
+
// `virtual:fuzor/compiler/react@react18`: a build-time renderer for one runtime.
|
|
902
|
+
const renderer = /^(virtual:fuzor\/compiler\/(?:react|solid))@([a-z0-9]+)$/.exec(id);
|
|
903
|
+
if (renderer && Object.hasOwn(rendererModules, renderer[1]) && runtimes.keys().includes(renderer[2])) {
|
|
904
|
+
const resolved = `\0${id}`;
|
|
905
|
+
runtimeModules.set(resolved, () => runtimes.renderer(renderer[2], rendererModules[renderer[1]]));
|
|
906
|
+
return resolved;
|
|
907
|
+
}
|
|
908
|
+
const adapter = runtimes.adapter(id);
|
|
909
|
+
if (adapter) {
|
|
910
|
+
runtimeModules.set(adapter.id, adapter.load);
|
|
911
|
+
return adapter.id;
|
|
912
|
+
}
|
|
913
|
+
const scope = runtimes.scopeOf(importer);
|
|
914
|
+
if (!scope || !importer)
|
|
915
|
+
return undefined;
|
|
916
|
+
const insidePackage = runtimes.packageScope(importer.split("?")[0]);
|
|
917
|
+
if (insidePackage) {
|
|
918
|
+
// react-dom-18 importing react must get react-18, which is installed at the project root.
|
|
919
|
+
const mapped = runtimes.mapSpecifier(insidePackage, id);
|
|
920
|
+
return mapped ? this.resolve(mapped, path.join(vite?.root ?? process.cwd(), "package.json"), { ...resolveOptions, skipSelf: true }) : undefined;
|
|
921
|
+
}
|
|
922
|
+
if (!id.startsWith(".") && !id.startsWith("/"))
|
|
923
|
+
return undefined;
|
|
924
|
+
const resolved = await this.resolve(id, importer, { ...resolveOptions, skipSelf: true });
|
|
925
|
+
if (resolved && !resolved.external)
|
|
926
|
+
runtimes.assign(resolved.id.split("?")[0], scope);
|
|
927
|
+
return resolved;
|
|
165
928
|
},
|
|
166
|
-
|
|
929
|
+
transform: {
|
|
930
|
+
order: "pre",
|
|
931
|
+
handler(code, id) {
|
|
932
|
+
if (!/\.[cm]?[jt]sx?$/.test(id.split("?")[0]) || id.includes("/node_modules/"))
|
|
933
|
+
return undefined;
|
|
934
|
+
const workflow = compileWorkflows(code, id);
|
|
935
|
+
if (workflow)
|
|
936
|
+
return workflow;
|
|
937
|
+
if (!runtimes?.enabled || id.startsWith(runtimes.resolvedPrefix))
|
|
938
|
+
return undefined;
|
|
939
|
+
if (!/\.[cm]?[jt]sx?$/.test(id.split("?")[0]))
|
|
940
|
+
return undefined;
|
|
941
|
+
const scope = runtimes.scopeOf(id);
|
|
942
|
+
if (!scope || runtimes.packageScope(id.split("?")[0]))
|
|
943
|
+
return undefined;
|
|
944
|
+
return runtimes.transform(scope, code, id);
|
|
945
|
+
}
|
|
946
|
+
},
|
|
947
|
+
async load(id, loadOptions) {
|
|
948
|
+
if (id.startsWith("\0virtual:fuzor/route-client/")) {
|
|
949
|
+
await loadProject();
|
|
950
|
+
const route = scriptRoutes.find(route => `\0${routeScriptId(route)}` === id);
|
|
951
|
+
if (!route)
|
|
952
|
+
throw new Error("Unknown Fuzor route client entry");
|
|
953
|
+
return `export const bindings = [${route.bindings.map(binding => `{ ...${JSON.stringify(binding)}, load: () => import(${JSON.stringify(pageScriptId(pageScripts.find(script => script.id === binding.id)))}) }`).join(",")}];`;
|
|
954
|
+
}
|
|
955
|
+
if (id.startsWith("\0virtual:fuzor/page-script/")) {
|
|
956
|
+
await loadProject();
|
|
957
|
+
const script = pageScripts.find(script => `\0${pageScriptId(script)}` === id);
|
|
958
|
+
if (!script)
|
|
959
|
+
throw new Error("Unknown Fuzor page script");
|
|
960
|
+
this.addWatchFile(script.source);
|
|
961
|
+
const source = script.code ?? await readFile(script.source, "utf8");
|
|
962
|
+
const native = compileNativeScript(source, script);
|
|
963
|
+
if (native) {
|
|
964
|
+
for (const handler of native.handlers)
|
|
965
|
+
nativeHandlers.set(handler.id, handler);
|
|
966
|
+
return (await import("vite")).transformWithEsbuild(native.code, script.source, { loader: script.language, target: "es2022", sourcefile: script.source });
|
|
967
|
+
}
|
|
968
|
+
const compiled = compilePageScript(source, script);
|
|
969
|
+
return (await import("vite")).transformWithEsbuild(compiled.code, script.source, { loader: script.language, target: "es2022", sourcemap: true, sourcefile: script.source }, compiled.map);
|
|
970
|
+
}
|
|
971
|
+
if (id.startsWith("\0virtual:fuzor/native-handler/")) {
|
|
972
|
+
const handler = [...nativeHandlers.values()].find(handler => id === `\0virtual:fuzor/native-handler/${handler.id}.js`);
|
|
973
|
+
if (!handler)
|
|
974
|
+
throw new Error("Unknown native handler");
|
|
975
|
+
return (await import("vite")).transformWithEsbuild(handler.code, handler.source, { loader: handler.language, target: "es2022" });
|
|
976
|
+
}
|
|
977
|
+
if (id.startsWith("\0fuzor:closure:")) {
|
|
978
|
+
const refs = await references();
|
|
979
|
+
const closure = refs.closures.find(ref => id === `\0fuzor:closure:${ref.id}.ts`);
|
|
980
|
+
if (!closure)
|
|
981
|
+
throw new Error("Unknown resumable closure reference");
|
|
982
|
+
return (await import("vite")).transformWithEsbuild(closure.code, id, { loader: "ts", target: "es2022" }).then(result => result.code);
|
|
983
|
+
}
|
|
984
|
+
if (options.serverComponents?.references) {
|
|
985
|
+
const refs = await references();
|
|
986
|
+
if (id === "\0virtual:fuzor/views") {
|
|
987
|
+
if (loadOptions?.ssr)
|
|
988
|
+
return `export const manifest=${JSON.stringify({ buildId: viewBuildId, templates: refs.templates })}; export const components=${JSON.stringify(refs.clients.map(ref => ref.id))}; export const handlers=${JSON.stringify([...refs.handlers.map(ref => ref.id), ...refs.closures.map(ref => ref.id)])};`;
|
|
989
|
+
return browserReferencesCode(refs, viewBuildId, file => "/" + file);
|
|
990
|
+
}
|
|
991
|
+
if (loadOptions?.ssr) {
|
|
992
|
+
const stub = referenceStub(id.split("?")[0], refs);
|
|
993
|
+
if (stub)
|
|
994
|
+
return stub;
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
if (id.startsWith("\0fuzor:fragment:")) {
|
|
998
|
+
const file = id.slice("\0fuzor:fragment:".length, -3);
|
|
999
|
+
this.addWatchFile(file);
|
|
1000
|
+
return readFile(file, "utf8").then(html => `export default ${JSON.stringify(compileFragment(html))};`);
|
|
1001
|
+
}
|
|
1002
|
+
if (Object.hasOwn(rendererModules, id.slice(1)))
|
|
1003
|
+
return rendererModules[id.slice(1)];
|
|
1004
|
+
const runtimeModule = runtimeModules.get(id);
|
|
1005
|
+
if (runtimeModule)
|
|
1006
|
+
return runtimeModule();
|
|
1007
|
+
if (!loadOptions?.ssr && !nested && vite) {
|
|
1008
|
+
const file = id.split("?")[0];
|
|
1009
|
+
const relative = path.relative(vite.root, file).split(path.sep).join("/");
|
|
1010
|
+
if (options.serverComponents && path.resolve(vite.root, options.serverComponents.server) === file || serverModuleFiles.includes(relative) || relative.startsWith("api/") || /\.server\.[cm]?[jt]sx?$/.test(relative)) {
|
|
1011
|
+
throw new Error(`${relative} is server-only and cannot be imported by browser code. Read its data with <fuzor-data> or routeData() instead.`);
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
167
1014
|
if (id !== resolvedVirtualId)
|
|
168
1015
|
return undefined;
|
|
1016
|
+
await loadProject();
|
|
1017
|
+
const mixedClient = profile.mixed && project?.routes.some(route => route.policy?.navigation === "spa");
|
|
1018
|
+
const scriptRegistry = scriptRoutes.map(route => `${JSON.stringify(route.path)}: () => import(${JSON.stringify(routeScriptId(route))}).catch(reloadOnStaleDeployment)`).join(",\n");
|
|
169
1019
|
const registry = islands.map((island) => {
|
|
170
1020
|
const load = island.file.endsWith(".vue")
|
|
171
|
-
? `Promise.all([import(${JSON.stringify(island.file)}), import("fuzor/islands/vue")]).then(([component, adapter]) => adapter.vueIsland(component.default))`
|
|
172
|
-
: `import(${JSON.stringify(island.file)})`;
|
|
1021
|
+
? `Promise.all([import(${JSON.stringify(island.file)}), import("fuzor/islands/vue")]).then(([component, adapter]) => adapter.vueIsland(component.default)).catch(reloadOnStaleDeployment)`
|
|
1022
|
+
: `import(${JSON.stringify(island.file)}).catch(reloadOnStaleDeployment)`;
|
|
173
1023
|
return `${JSON.stringify(island.name)}: () => ${load}`;
|
|
174
1024
|
}).join(",\n");
|
|
175
|
-
|
|
1025
|
+
const withData = target === "mpa" && !!project?.routes.some(route => route.serverData);
|
|
1026
|
+
const hasDocs = (project?.routes ?? []).some(route => route.path === "/docs/" || route.path.startsWith("/docs/"));
|
|
1027
|
+
const routerModule = profile.electron || options.navigation === "embedded" ? "fuzor/runtime/router/embedded" : options.navigation === "navigation-api" ? "fuzor/runtime/router/navigation-api" : "fuzor/runtime";
|
|
1028
|
+
const imports = [
|
|
1029
|
+
(target === "spa" || mixedClient)
|
|
1030
|
+
? `import { createRouter } from "${routerModule}"; import { reloadOnStaleDeployment } from "fuzor/runtime/islands";`
|
|
1031
|
+
: 'import { mountIslands, islandErrorHandler, reloadOnStaleDeployment } from "fuzor/runtime/islands";',
|
|
1032
|
+
...(target === "mpa" ? ['import { mountPageScripts } from "fuzor/runtime/page-scripts"; import { stripBase } from "fuzor/runtime";'] : []),
|
|
1033
|
+
...(options.serverComponents ? [options.serverComponents.references ? 'import generatedViewOptions from "virtual:fuzor/views";' : "", options.serverComponents.client ? `import suppliedViewOptions from ${JSON.stringify("/" + options.serverComponents.client)};` : "", `const viewOptions = { ${options.serverComponents.references ? "...generatedViewOptions" : ""}${options.serverComponents.references && options.serverComponents.client ? "," : ""}${options.serverComponents.client ? "...suppliedViewOptions" : ""} };`, (target === "spa" || mixedClient) ? 'import { makeClientRouteMatcher } from "fuzor/runtime"; import { serverViewRoutes } from "fuzor/server-components/navigation"; import { createViewRenderer } from "fuzor/server-components/browser";' : 'import { createViewRenderer } from "fuzor/server-components/browser";'] : []),
|
|
1034
|
+
...(mixedClient ? ['import { mountIslands, islandErrorHandler } from "fuzor/runtime/islands";'] : []),
|
|
1035
|
+
...(withData ? ['import { loadRouteData } from "fuzor/runtime/data";'] : []),
|
|
1036
|
+
...(hasDocs ? ['import { mountDocsUi } from "fuzor/runtime/docs-ui";'] : [])
|
|
1037
|
+
];
|
|
1038
|
+
const docsInit = hasDocs ? `let stopDocsUi;
|
|
1039
|
+
let docsDisposed = false;
|
|
1040
|
+
const hideDocs = event => { if (!event.persisted) disposeDocs(); };
|
|
1041
|
+
const disposeDocs = () => {
|
|
1042
|
+
if (docsDisposed) return;
|
|
1043
|
+
docsDisposed = true;
|
|
1044
|
+
window.removeEventListener("pagehide", hideDocs);
|
|
1045
|
+
stopDocsUi?.();
|
|
1046
|
+
};
|
|
1047
|
+
void mountDocsUi({ document, base: import.meta.env.BASE_URL }).then(stop => {
|
|
1048
|
+
stopDocsUi = stop;
|
|
1049
|
+
if (docsDisposed) stop();
|
|
1050
|
+
}, error => console.error(error));
|
|
1051
|
+
window.addEventListener("pagehide", hideDocs);
|
|
1052
|
+
if (import.meta.hot) import.meta.hot.dispose(disposeDocs);
|
|
1053
|
+
` : "";
|
|
1054
|
+
const effectiveViewOptions = `...viewOptions, manifest: { ...viewOptions.manifest, buildId: ${JSON.stringify(viewBuildId)} }`;
|
|
1055
|
+
const spaStart = `export const router = (${mixedClient ? 'outlet.getAttribute("data-fuzor-navigation") === "spa" && ' : ""}!outlet.hasAttribute("data-fuzor-not-found") && !outlet.hasAttribute("data-fuzor-error")) ? createRouter(outlet, { islands, scripts, base: import.meta.env.BASE_URL${options.serverComponents ? `, renderer: serverViewRoutes({ ${effectiveViewOptions}, routes: ${JSON.stringify(options.serverComponents.routes)}, acceptsRoute: path => !${mixedClient} || [...document.querySelectorAll("template[data-fuzor-route]")].some(t => t.getAttribute("data-fuzor-route") === path || t.hasAttribute("data-fuzor-request-pattern") && makeClientRouteMatcher({[t.getAttribute("data-fuzor-request-pattern")]: "/"})(path)), base: import.meta.env.BASE_URL })` : ""}${options.clientRoutes ? `, clientRoutes: ${JSON.stringify(options.clientRoutes)}` : ""}${options.routeTree ? `, routeTree: ${JSON.stringify(options.routeTree)}` : ""}${options.viewTransitions ? ", viewTransitions: true" : ""}${options.prefetch === "intent" ? ', prefetch: "intent"' : ""} }) : undefined;
|
|
1056
|
+
export const ready = router ? router.start() : Promise.resolve(undefined);
|
|
1057
|
+
void ready.catch(error => console.error(error));
|
|
1058
|
+
if (import.meta.hot) import.meta.hot.dispose(() => { void router?.dispose(); });`;
|
|
1059
|
+
const mpaStart = `${withData ? `if (outlet.hasAttribute("data-fuzor-data") && !outlet.hasAttribute("data-fuzor-data-ready")) void loadRouteData(outlet).catch(error => { if (error?.name !== "AbortError") console.error(error); });
|
|
1060
|
+
` : ""}if (!/^https?:$/.test(location.protocol)) console.error("Fuzor MPA builds need an HTTP(S) server: their root-relative links and assets do not resolve over " + location.protocol + " URLs. Use an inline SPA build (fuzor build --target spa --inline) for embedded apps.");
|
|
1061
|
+
const lifetime = new AbortController();
|
|
1062
|
+
let cleanup;
|
|
1063
|
+
const dispose = () => { lifetime.abort(); void cleanup?.(); };
|
|
1064
|
+
${options.serverComponents ? `const viewRenderer = document.querySelector("script[data-fuzor-snapshot]") ? createViewRenderer(outlet, { ${effectiveViewOptions} }) : undefined;
|
|
1065
|
+
const mountComponents = viewRenderer ? viewRenderer.resume().then(() => () => viewRenderer.dispose()) : mountIslands(outlet, islands, islandErrorHandler, { signal: lifetime.signal });` : `const mountComponents = mountIslands(outlet, islands, islandErrorHandler, { signal: lifetime.signal });`}
|
|
1066
|
+
${options.serverComponents ? "const viewRendererActive = !!viewRenderer;" : "const viewRendererActive = false;"}
|
|
1067
|
+
const pathname = stripBase(location.pathname, import.meta.env.BASE_URL) ?? location.pathname;
|
|
1068
|
+
const routePath = pathname.endsWith("/") ? pathname : pathname + "/";
|
|
1069
|
+
const scriptRoute = Object.hasOwn(scripts, routePath) ? routePath : outlet.getAttribute("data-fuzor-pattern") ?? "";
|
|
1070
|
+
const mount = (async () => { const stopComponents = await mountComponents; try { const stopScripts = await mountPageScripts(outlet, viewRendererActive ? {} : scripts, { signal: lifetime.signal, route: scriptRoute }); return async () => { await stopScripts(); await stopComponents(); }; } catch (error) { await stopComponents(); throw error; } })();
|
|
1071
|
+
void mount.then(stop => {
|
|
1072
|
+
cleanup = stop;
|
|
1073
|
+
if (lifetime.signal.aborted) void stop();
|
|
1074
|
+
}, error => { if (!lifetime.signal.aborted) console.error(error); });
|
|
1075
|
+
window.addEventListener("pagehide", event => { if (!event.persisted) dispose(); });
|
|
1076
|
+
if (import.meta.hot) import.meta.hot.dispose(dispose);`;
|
|
1077
|
+
return `${imports.join("\n")}
|
|
176
1078
|
const islands = { ${registry} };
|
|
1079
|
+
const scripts = { ${scriptRegistry} };
|
|
177
1080
|
const outlet = document.querySelector("fuzor-router");
|
|
178
1081
|
if (!outlet) throw new Error("Fuzor outlet is missing");
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
: "void mountIslands(outlet, islands);"}`;
|
|
1082
|
+
window.addEventListener("vite:preloadError", event => { event.preventDefault(); void reloadOnStaleDeployment(event.payload).catch(error => console.error(error)); });
|
|
1083
|
+
${docsInit}${mixedClient ? spaStart + "\nif (!router) {\n" + mpaStart + "\n}" : target === "spa" ? spaStart : mpaStart}`;
|
|
182
1084
|
},
|
|
183
1085
|
transformIndexHtml: {
|
|
184
1086
|
order: "pre",
|
|
185
1087
|
async handler(raw, context) {
|
|
1088
|
+
if (nested)
|
|
1089
|
+
return raw;
|
|
186
1090
|
const compiled = await loadProject();
|
|
187
|
-
const
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
1091
|
+
const requested = new URL(context.path, "http://fuzor.local").pathname;
|
|
1092
|
+
const pathname = stripBase(requested, pathBase) ?? requested;
|
|
1093
|
+
const currentPath = findRoute(compiled, pathname) ? pathname : "/";
|
|
1094
|
+
parseRoutePolicy(raw, path.join(vite.root, "index.html"), false);
|
|
1095
|
+
const shell = compilePlatformBlocks(raw, profile.platform, path.join(vite.root, "index.html"));
|
|
1096
|
+
shellHead = readDocumentHead(shell);
|
|
1097
|
+
let html = applyDocumentMetadata(replaceOutlet(shell, outletFor(compiled, target, currentPath, fallbacks(), profile.mixed)), pageHead(shellHead, findRoute(compiled, currentPath)?.metadata ?? {}));
|
|
1098
|
+
if (inline && target === "spa") {
|
|
1099
|
+
const initial = findRoute(compiled, currentPath);
|
|
1100
|
+
const script = await inlineInitialRouteScript({ base: pathBase, alwaysHash: profile.electron || options.navigation === "embedded", ...(options.clientRoutes ? { clientRoutes: options.clientRoutes } : {}) });
|
|
1101
|
+
// A route never becomes visible until the synchronous selector chooses it.
|
|
1102
|
+
html = html.replace(/<fuzor-router\b[^>]*>[\s\S]*?<\/fuzor-router>/, "<fuzor-router></fuzor-router>");
|
|
1103
|
+
const fallback = `<noscript>${initial?.html ?? ""}<p>JavaScript is required to navigate this single-file app.</p></noscript>`;
|
|
1104
|
+
html = html.replace(outletEnd, () => `${script}${fallback}${outletEnd}`);
|
|
193
1105
|
}
|
|
1106
|
+
if (options.generator !== false)
|
|
1107
|
+
html = applyGeneratorMetadata(html);
|
|
1108
|
+
if (hydrationScript)
|
|
1109
|
+
html = html.replace("</head>", `${hydrationScript}</head>`);
|
|
1110
|
+
if (vite.command === "serve")
|
|
1111
|
+
html = withStaticModuleImports(html);
|
|
194
1112
|
html = html.replace("</head>", `<script type="module">import "${virtualId}";</script></head>`);
|
|
195
1113
|
return html;
|
|
196
1114
|
}
|
|
197
1115
|
},
|
|
198
1116
|
configureServer(server) {
|
|
1117
|
+
if (nested)
|
|
1118
|
+
return;
|
|
199
1119
|
devServer = server;
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
1120
|
+
releaseRuntimeHooks();
|
|
1121
|
+
releaseRuntimeHooks = runtimes?.registerNodeHooks() ?? (() => { });
|
|
1122
|
+
// Install before profile detection changes so adding the first server module works in SPA too.
|
|
1123
|
+
server.middlewares.use(async (request, response, next) => {
|
|
1124
|
+
const requested = new URL(request.url ?? "/", "http://fuzor.local").pathname;
|
|
1125
|
+
const pathname = stripBase(requested, pathBase);
|
|
1126
|
+
if (pathname === undefined)
|
|
1127
|
+
return next();
|
|
1128
|
+
if (pathname === "/search-index.json" && options.searchIndex) {
|
|
1129
|
+
try {
|
|
1130
|
+
response.setHeader("content-type", "application/json; charset=utf-8");
|
|
1131
|
+
response.end(searchIndex(await loadProject(), options.searchIndex));
|
|
1132
|
+
}
|
|
1133
|
+
catch (error) {
|
|
1134
|
+
next(error);
|
|
1135
|
+
}
|
|
1136
|
+
return;
|
|
1137
|
+
}
|
|
1138
|
+
if (!withServer && target === "spa")
|
|
1139
|
+
return next();
|
|
1140
|
+
const dataRequest = pathname.startsWith(`${serverDataPrefix}/`);
|
|
1141
|
+
const apiRequest = apiFiles.length > 0 && (pathname === "/api" || pathname.startsWith("/api/"));
|
|
1142
|
+
// Explicit Vite proxies own their upstream APIs; server views must not turn them into HTML routes.
|
|
1143
|
+
if (!apiRequest && Object.keys(server.config.server.proxy ?? {}).some(prefix => prefix.startsWith("^") ? new RegExp(prefix).test(requested) : requested === prefix || requested.startsWith(prefix + "/")))
|
|
1144
|
+
return next();
|
|
1145
|
+
if (withServer && (dataRequest || apiRequest || !pathname.startsWith("/@") && !pathname.startsWith("/__") && !pathname.includes("."))) {
|
|
1146
|
+
const controller = new AbortController();
|
|
1147
|
+
const abort = () => { if (!response.writableFinished)
|
|
1148
|
+
controller.abort(); };
|
|
1149
|
+
request.once("aborted", abort);
|
|
1150
|
+
response.once("close", abort);
|
|
1151
|
+
try {
|
|
1152
|
+
const onError = (error) => server.config.logger.error(`[fuzor] ${error instanceof Error ? error.stack ?? error.message : String(error)}`);
|
|
1153
|
+
const url = new URL(request.url ?? "/", `http://${request.headers.host ?? "fuzor.local"}`);
|
|
1154
|
+
let result;
|
|
1155
|
+
if (apiRequest) {
|
|
1156
|
+
// Rescanned per request so new endpoint files work without restarting.
|
|
1157
|
+
const api = await loadApiModules(findApiRoutes(vite.root), file => createEnvironmentModuleRuntime(server, moduleEnvironment, environmentApiEnabled).loadModule(file));
|
|
1158
|
+
result = await createServerHandler({ documents: {}, notFoundDocument: "", ...(pathBase === "/" ? {} : { base: pathBase }) }, { api, onError })(toWebRequest(request, { url, signal: controller.signal }));
|
|
1159
|
+
}
|
|
1160
|
+
else {
|
|
205
1161
|
const raw = await readFile(path.join(vite.root, "index.html"), "utf8");
|
|
206
1162
|
const template = await server.transformIndexHtml("/", raw);
|
|
207
1163
|
const compiled = await loadProject();
|
|
208
|
-
const
|
|
209
|
-
const
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
response.end(Buffer.from(await result.arrayBuffer()));
|
|
215
|
-
}
|
|
216
|
-
catch (error) {
|
|
217
|
-
next(error);
|
|
1164
|
+
const manifest = serverManifest(compiled, target, template, pathBase, fallbacks(), withStaticModuleImports, options.clientRoutes, `/${vite.build.assetsDir}/`, profile.mixed);
|
|
1165
|
+
const data = dataRequest || compiled.routes.some(route => route.policy?.rendering === "request") ? await loadRouteDataModules(compiled, file => createEnvironmentModuleRuntime(server, moduleEnvironment, environmentApiEnabled).loadModule(file), vite.root) : undefined;
|
|
1166
|
+
const views = options.serverComponents ? await generatedViews((await createEnvironmentModuleRuntime(server, moduleEnvironment, environmentApiEnabled).loadModule("/" + options.serverComponents.server)).default) : undefined;
|
|
1167
|
+
if (views && JSON.stringify(Object.keys(views.routes).sort()) !== JSON.stringify([...options.serverComponents.routes].sort()))
|
|
1168
|
+
throw new Error("Server view routes must match serverComponents.routes.");
|
|
1169
|
+
result = await createServerHandler(manifest, { ...(data ? { data } : {}), ...(views ? { views: { ...views, manifest: { ...views.manifest, buildId: viewBuildId }, documentPatterns: manifest.requestPatterns ?? {}, document: serverViewDocument(template), documents: Object.fromEntries(Object.entries("documents" in manifest ? manifest.documents : manifest.routeDocuments ?? {}).map(([route, html]) => [route, serverViewDocument(html)])) } } : {}), onError })(toWebRequest(request, { url, signal: controller.signal }));
|
|
218
1170
|
}
|
|
219
|
-
|
|
220
|
-
}
|
|
221
|
-
if (request.method !== "GET")
|
|
222
|
-
return next();
|
|
223
|
-
const normalized = pathname === "/" ? "/" : `${pathname.replace(/\/+$/, "")}/`;
|
|
224
|
-
if (normalized === "/" || !(await loadProject()).routes.some((route) => route.path === normalized))
|
|
225
|
-
return next();
|
|
226
|
-
try {
|
|
227
|
-
const raw = await readFile(path.join(vite.root, "index.html"), "utf8");
|
|
228
|
-
const html = await server.transformIndexHtml(pathname, raw);
|
|
229
|
-
response.setHeader("content-type", "text/html; charset=utf-8");
|
|
230
|
-
response.end(html);
|
|
1171
|
+
await writeWebResponse(response, result, { method: request.method ?? "GET", signal: controller.signal });
|
|
231
1172
|
}
|
|
232
1173
|
catch (error) {
|
|
233
|
-
|
|
1174
|
+
if (!controller.signal.aborted) {
|
|
1175
|
+
if (response.headersSent) {
|
|
1176
|
+
server.config.logger.error(String(error));
|
|
1177
|
+
response.destroy();
|
|
1178
|
+
}
|
|
1179
|
+
else
|
|
1180
|
+
next(error);
|
|
1181
|
+
}
|
|
234
1182
|
}
|
|
235
|
-
|
|
236
|
-
|
|
1183
|
+
finally {
|
|
1184
|
+
request.removeListener("aborted", abort);
|
|
1185
|
+
response.removeListener("close", abort);
|
|
1186
|
+
}
|
|
1187
|
+
return;
|
|
1188
|
+
}
|
|
1189
|
+
if (request.method !== "GET")
|
|
1190
|
+
return next();
|
|
1191
|
+
const normalized = routeKey(pathname);
|
|
1192
|
+
const redirect = normalized === undefined ? undefined : (await loadProject()).redirects?.[normalized];
|
|
1193
|
+
if (redirect !== undefined) {
|
|
1194
|
+
response.writeHead(308, { location: /^https?:\/\//i.test(redirect) ? redirect : withBase(redirect, pathBase) }).end();
|
|
1195
|
+
return;
|
|
1196
|
+
}
|
|
1197
|
+
if (normalized === "/" || !findRoute(await loadProject(), pathname))
|
|
1198
|
+
return next();
|
|
1199
|
+
try {
|
|
1200
|
+
const raw = await readFile(path.join(vite.root, "index.html"), "utf8");
|
|
1201
|
+
const html = await server.transformIndexHtml(requested, raw);
|
|
1202
|
+
response.setHeader("content-type", "text/html; charset=utf-8");
|
|
1203
|
+
response.end(html);
|
|
1204
|
+
}
|
|
1205
|
+
catch (error) {
|
|
1206
|
+
next(error);
|
|
1207
|
+
}
|
|
1208
|
+
});
|
|
237
1209
|
server.watcher.on("add", (file) => {
|
|
238
|
-
if (["/pages/", "/components/", "/layouts/", "/islands/"].some((part) => file.includes(part))) {
|
|
1210
|
+
if (pageScripts.some(script => script.source === file) || options.serverComponents && (file.endsWith(".fragment.html") || options.serverComponents.references && file.startsWith(path.resolve(vite.root, options.serverComponents.references) + path.sep) || file === path.resolve(vite.root, options.serverComponents.server) || options.serverComponents.client && file === path.resolve(vite.root, options.serverComponents.client)) || ["/pages/", "/components/", "/layouts/", "/islands/", "/api/"].some((part) => file.replaceAll("\\", "/").includes(part))) {
|
|
239
1211
|
void refresh(server).catch((error) => server.config.logger.error(String(error)));
|
|
240
1212
|
}
|
|
241
1213
|
});
|
|
242
1214
|
server.watcher.on("unlink", (file) => {
|
|
243
|
-
if (["/pages/", "/components/", "/layouts/", "/islands/"].some((part) => file.includes(part))) {
|
|
1215
|
+
if (pageScripts.some(script => script.source === file) || ["/pages/", "/components/", "/layouts/", "/islands/", "/api/"].some((part) => file.replaceAll("\\", "/").includes(part))) {
|
|
244
1216
|
void refresh(server).catch((error) => server.config.logger.error(String(error)));
|
|
245
1217
|
}
|
|
246
1218
|
});
|
|
247
1219
|
},
|
|
1220
|
+
buildStart() {
|
|
1221
|
+
buildFailed = false;
|
|
1222
|
+
bundleWritten = false;
|
|
1223
|
+
if (!nested && vite.command === "build") {
|
|
1224
|
+
releaseRuntimeHooks();
|
|
1225
|
+
releaseRuntimeHooks = runtimes?.registerNodeHooks() ?? (() => { });
|
|
1226
|
+
}
|
|
1227
|
+
},
|
|
1228
|
+
async generateBundle(_output, bundle) {
|
|
1229
|
+
if (nested || vite.build.ssr)
|
|
1230
|
+
return;
|
|
1231
|
+
if (runtimes?.enabled) {
|
|
1232
|
+
// A module assigned to a runtime but also imported by other code would run with two framework versions.
|
|
1233
|
+
for (const [file, runtime] of runtimes.assigned()) {
|
|
1234
|
+
const importers = this.getModuleInfo(file)?.importers ?? [];
|
|
1235
|
+
const foreign = importers.find(importer => runtimes.scopeOf(importer)?.key !== runtime);
|
|
1236
|
+
if (foreign)
|
|
1237
|
+
this.error(`${path.relative(vite.root, file)} is imported by ${runtime} islands and by ${path.relative(vite.root, foreign)}. Keep modules that use a framework runtime separate from other code.`);
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
// Which files each island downloads, for `fuzor routes` (written outside the output directory).
|
|
1241
|
+
const chunks = Object.values(bundle).filter((item) => item.type === "chunk");
|
|
1242
|
+
inlineModuleFiles = chunks.map(chunk => chunk.fileName);
|
|
1243
|
+
const byName = new Map(chunks.map(chunk => [chunk.fileName, chunk]));
|
|
1244
|
+
const collect = (fileName, seen) => {
|
|
1245
|
+
if (seen.has(fileName))
|
|
1246
|
+
return;
|
|
1247
|
+
seen.add(fileName);
|
|
1248
|
+
for (const imported of byName.get(fileName)?.imports ?? [])
|
|
1249
|
+
collect(imported, seen);
|
|
1250
|
+
};
|
|
1251
|
+
const report = {};
|
|
1252
|
+
islandStyles = {};
|
|
1253
|
+
for (const island of islands) {
|
|
1254
|
+
const chunk = chunks.find(item => item.facadeModuleId === path.join(vite.root, island.file));
|
|
1255
|
+
if (!chunk)
|
|
1256
|
+
continue;
|
|
1257
|
+
const files = new Set();
|
|
1258
|
+
collect(chunk.fileName, files);
|
|
1259
|
+
const css = [...files].flatMap(file => [...(byName.get(file)?.viteMetadata?.importedCss ?? [])]);
|
|
1260
|
+
report[island.name] = { files: [...files], css: [...new Set(css)] };
|
|
1261
|
+
islandStyles[island.name] = report[island.name].css;
|
|
1262
|
+
}
|
|
1263
|
+
const file = path.join(vite.root, ".fuzor", `chunks-${target}${withServer ? "-server" : ""}.json`);
|
|
1264
|
+
await mkdir(path.dirname(file), { recursive: true });
|
|
1265
|
+
await writeFile(file, JSON.stringify({ inline, islands: Object.fromEntries(islands.map(module => [module.name, report[module.name]])) }, null, 2), "utf8");
|
|
1266
|
+
},
|
|
1267
|
+
buildEnd(error) { if (error)
|
|
1268
|
+
buildFailed = true; },
|
|
1269
|
+
// Errors while generating or writing chunks happen after buildEnd; only a written bundle is post-processed.
|
|
1270
|
+
renderError() { buildFailed = true; },
|
|
1271
|
+
writeBundle() { bundleWritten = true; },
|
|
248
1272
|
async closeBundle() {
|
|
249
|
-
|
|
1273
|
+
// Rollup still calls closeBundle after a failed build; post-processing would hide the real error.
|
|
1274
|
+
if (nested)
|
|
250
1275
|
return;
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
1276
|
+
try {
|
|
1277
|
+
if (vite.command !== "build")
|
|
1278
|
+
return;
|
|
1279
|
+
if (buildFailed || !bundleWritten)
|
|
1280
|
+
return;
|
|
1281
|
+
const outDir = path.resolve(vite.root, vite.build.outDir);
|
|
1282
|
+
const compiled = await loadProject();
|
|
1283
|
+
const artifact = { version: 1, buildId: viewBuildId, platform: profile.platform, mode: profile.mixed ? "mixed" : target, inline, backendRequired: compiled.routes.some(route => route.policy?.rendering === "request"), routes: compiled.routes.map(route => ({ path: route.path, ...route.policy, backendData: !!route.serverData, ...(route.requestPattern ? { requestPattern: route.requestPattern } : {}) })) };
|
|
1284
|
+
await mkdir(path.join(vite.root, ".fuzor"), { recursive: true });
|
|
1285
|
+
if (!inline)
|
|
1286
|
+
await writeFile(path.join(outDir, "fuzor.manifest.json"), JSON.stringify(artifact, null, 2) + "\n");
|
|
1287
|
+
if (target === "spa" && inline) {
|
|
1288
|
+
const inlined = await inlineDocumentAssets(await readFile(path.join(outDir, "index.html"), "utf8"), outDir, inlineModuleFiles);
|
|
1289
|
+
const html = inlined.html;
|
|
1290
|
+
const assetFiles = inlined.files;
|
|
1291
|
+
await writeFile(path.join(outDir, "index.html"), html, "utf8");
|
|
1292
|
+
for (const file of assetFiles)
|
|
1293
|
+
await unlink(file);
|
|
1294
|
+
const assetDir = path.join(outDir, "assets");
|
|
1295
|
+
try {
|
|
1296
|
+
const remaining = await readdir(assetDir);
|
|
1297
|
+
if (remaining.length > 0)
|
|
1298
|
+
throw new Error(`SPA inline build left external assets: ${remaining.join(", ")}`);
|
|
1299
|
+
await rmdir(assetDir);
|
|
1300
|
+
}
|
|
1301
|
+
catch (error) {
|
|
1302
|
+
if (error.code !== "ENOENT")
|
|
1303
|
+
throw error;
|
|
1304
|
+
}
|
|
1305
|
+
const remainingFiles = await readdir(outDir);
|
|
1306
|
+
if (remainingFiles.length !== 1 || remainingFiles[0] !== "index.html") {
|
|
1307
|
+
throw new Error(`An inline SPA build must be a single index.html, but these files are outside it: ${remainingFiles.filter((file) => file !== "index.html").join(", ")}. ` +
|
|
1308
|
+
"They usually come from public/, which Vite copies unchanged. Import images and fonts from source files instead (inline builds embed them as data URLs), remove the public files, or use the regular SPA build.");
|
|
1309
|
+
}
|
|
1310
|
+
if (profile.electron)
|
|
1311
|
+
await writeElectronScaffold(outDir);
|
|
1312
|
+
return;
|
|
263
1313
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
1314
|
+
const styled = (html) => withIslandStyles(html, islandStyles, vite.base);
|
|
1315
|
+
const rootHtml = styled(await readFile(path.join(outDir, "index.html"), "utf8"));
|
|
1316
|
+
await writeFile(path.join(outDir, "index.html"), rootHtml, "utf8");
|
|
1317
|
+
if (withServer) {
|
|
1318
|
+
const serverDir = process.env.FUZOR_STAGE_DIR ? path.resolve(process.env.FUZOR_STAGE_DIR, profile.backendOutDir) : path.resolve(vite.root, profile.backendOutDir);
|
|
1319
|
+
const manifest = { ...serverManifest(compiled, target, rootHtml, pathBase, fallbacks(), styled, options.clientRoutes, `/${vite.build.assetsDir}/`, profile.mixed), buildId: viewBuildId };
|
|
1320
|
+
await mkdir(serverDir, { recursive: true });
|
|
1321
|
+
await writeFile(path.join(serverDir, "fuzor.manifest.json"), JSON.stringify({ ...artifact, clientDirectory: path.relative(serverDir, outDir).split(path.sep).join("/") }, null, 2) + "\n");
|
|
1322
|
+
const dataRoutes = compiled.routes.filter(route => route.serverData);
|
|
1323
|
+
const refs = options.serverComponents?.references ? await references() : undefined;
|
|
1324
|
+
if (!dataRoutes.length && !apiFiles.length && !options.serverComponents && !options.serverExternal) {
|
|
1325
|
+
await writeFile(path.join(serverDir, "entry.mjs"), `import { createServerHandler } from "fuzor/server";\n` +
|
|
1326
|
+
`export const manifest = ${JSON.stringify(manifest)};\n` +
|
|
1327
|
+
`export const handler = createServerHandler(manifest);\n`, "utf8");
|
|
1328
|
+
}
|
|
1329
|
+
else {
|
|
1330
|
+
// Server modules are bundled for Node; documents remain precompiled strings in the manifest.
|
|
1331
|
+
const files = [...new Set(dataRoutes.map(route => route.serverData))];
|
|
1332
|
+
const entryId = "virtual:fuzor/server-entry";
|
|
1333
|
+
const code = [
|
|
1334
|
+
`import { createServerHandler, isServerData } from "fuzor/server";`,
|
|
1335
|
+
...(options.serverComponents ? [`import suppliedViews from ${JSON.stringify(path.resolve(vite.root, options.serverComponents.server))};`, `const views = { ...suppliedViews${refs ? `, manifest: ${JSON.stringify({ buildId: viewBuildId, templates: refs.templates })}, components: ${JSON.stringify(refs.clients.map(ref => ref.id))}, handlers: ${JSON.stringify([...refs.handlers.map(ref => ref.id), ...refs.closures.map(ref => ref.id)])}` : ""} };`, `if (JSON.stringify(Object.keys(views.routes).sort()) !== ${JSON.stringify(JSON.stringify([...options.serverComponents.routes].sort()))}) throw new Error("Server view routes must match serverComponents.routes.");`] : []),
|
|
1336
|
+
...files.map((file, index) => `import data${index} from ${JSON.stringify(file)};`),
|
|
1337
|
+
...apiFiles.map((route, index) => `import * as api${index} from ${JSON.stringify(route.file)};`),
|
|
1338
|
+
`const modules = [${files.map((_, index) => `data${index}`).join(", ")}];`,
|
|
1339
|
+
`const sources = ${JSON.stringify(files.map(file => path.relative(vite.root, file).split(path.sep).join("/")))};`,
|
|
1340
|
+
`modules.forEach((module, index) => { if (!isServerData(module)) throw new Error(sources[index] + " must export default defineServerData(...) from \\"fuzor/server\\"."); });`,
|
|
1341
|
+
`export const manifest = ${JSON.stringify(manifest)};`,
|
|
1342
|
+
`const routes = ${JSON.stringify(dataRoutes.map(route => [route.path, files.indexOf(route.serverData), route.params ?? null]))};`,
|
|
1343
|
+
`const api = [${apiFiles.map((route, index) => `{ pattern: ${JSON.stringify(route.pattern)}, segments: ${JSON.stringify(route.segments)}, source: ${JSON.stringify(route.relative)}, module: api${index} }`).join(", ")}];`,
|
|
1344
|
+
`export const handler = createServerHandler(manifest, { data: Object.fromEntries(routes.map(([route, index, params]) => [route, params ? { data: modules[index], params } : { data: modules[index] }])), api${options.serverComponents ? `, views: { ...views, manifest: { ...views.manifest, buildId: ${JSON.stringify(viewBuildId)} }, documentPatterns:${JSON.stringify(manifest.requestPatterns ?? {})}, document: ${JSON.stringify(serverViewDocument(rootHtml))}, documents:${JSON.stringify(Object.fromEntries(Object.entries("documents" in manifest ? manifest.documents : manifest.routeDocuments ?? {}).map(([route, html]) => [route, serverViewDocument(html)])))} }` : ""} });`
|
|
1345
|
+
].join("\n");
|
|
1346
|
+
await nestedServer.run(true, () => viteBuild({
|
|
1347
|
+
root: vite.root, mode: vite.mode, configFile: vite.configFile ?? false, logLevel: "error", publicDir: false,
|
|
1348
|
+
// One runtime copy: the entry and server modules share fuzor/server and effect, either both imported from
|
|
1349
|
+
// node_modules (the default) or, for what `serverExternal` does not name, bundled once into the output.
|
|
1350
|
+
ssr: options.serverExternal ? { external: [...options.serverExternal], noExternal: true } : { external: ["fuzor", "effect"] },
|
|
1351
|
+
plugins: [compiledFragmentsPlugin(), workflowPlugin(), ...(refs ? [{ name: "fuzor:server-references", load: (id) => referenceStub(id, refs) }] : []), { name: "fuzor:server-entry", resolveId: id => id === entryId ? `\0${entryId}` : undefined, load: id => id === `\0${entryId}` ? code : undefined }],
|
|
1352
|
+
build: { ssr: true, outDir: serverDir, emptyOutDir: false, copyPublicDir: false, minify: false,
|
|
1353
|
+
rollupOptions: { input: entryId, output: { entryFileNames: "entry.mjs", chunkFileNames: "chunks/[name]-[hash].mjs", format: "es" } } }
|
|
1354
|
+
}));
|
|
1355
|
+
}
|
|
1356
|
+
// The same finished documents are also written to client/ below, so it can be served by a CDN or
|
|
1357
|
+
// static host with only /api and server data requests reaching the server.
|
|
1358
|
+
if (profile.adapter === "cloudflare")
|
|
1359
|
+
await writeCloudflareOutput(serverDir, vite.root, target, pathBase, outDir, [...compiled.routes.filter(route => route.policy?.rendering === "request").map(route => route.requestPattern ? route.requestPattern.slice(0, route.requestPattern.indexOf(":")) + "*" : route.path), ...(options.serverComponents?.routes ?? []).map(pattern => pattern.includes(":") ? pattern.slice(0, pattern.indexOf(":")) + "*" : pattern)], path.relative(path.resolve(vite.root, profile.backendOutDir), process.env.FUZOR_STAGE_DIR && outDir.startsWith(path.resolve(process.env.FUZOR_STAGE_DIR) + path.sep) ? path.resolve(vite.root, path.relative(process.env.FUZOR_STAGE_DIR, outDir)) : outDir).split(path.sep).join("/"));
|
|
269
1360
|
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
await
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
if (remaining.length > 0)
|
|
277
|
-
throw new Error(`SPA inline build left external assets: ${remaining.join(", ")}`);
|
|
278
|
-
await rmdir(assetDir);
|
|
1361
|
+
const index = searchIndex(compiled, options.searchIndex);
|
|
1362
|
+
if (index)
|
|
1363
|
+
await writeFile(path.join(outDir, "search-index.json"), index, "utf8");
|
|
1364
|
+
const redirects = Object.entries(compiled.redirects ?? {}).map(([from, to]) => [from, /^https?:\/\//i.test(to) ? to : withBase(to, pathBase)]);
|
|
1365
|
+
if (redirects.length) {
|
|
1366
|
+
await writeFile(path.join(outDir, "_redirects"), redirects.map(([from, to]) => `${withBase(from, pathBase)} ${to} 308`).join("\n") + "\n", "utf8");
|
|
279
1367
|
}
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
1368
|
+
// Static hosts read cache rules from _headers (Cloudflare, Netlify); servers send the same values.
|
|
1369
|
+
const lifetimes = compiled.routes.filter(route => route.metadata?.revalidate);
|
|
1370
|
+
if (target === "mpa" && lifetimes.length) {
|
|
1371
|
+
await writeFile(path.join(outDir, "_headers"), lifetimes.map(route => {
|
|
1372
|
+
const seconds = route.metadata.revalidate;
|
|
1373
|
+
return `${withBase(route.path, pathBase)}\n Cache-Control: public, max-age=0, s-maxage=${seconds}, stale-while-revalidate=${seconds}\n`;
|
|
1374
|
+
}).join(""), "utf8");
|
|
283
1375
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
1376
|
+
if (target === "spa")
|
|
1377
|
+
return;
|
|
1378
|
+
for (const [from, to] of redirects) {
|
|
1379
|
+
const outputFile = path.join(outDir, decodeURIComponent(from.slice(1)), "index.html");
|
|
1380
|
+
await mkdir(path.dirname(outputFile), { recursive: true });
|
|
1381
|
+
await writeFile(outputFile, redirectDocument(to), "utf8");
|
|
287
1382
|
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
const
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
1383
|
+
// Static hosts such as Cloudflare Pages and Netlify serve the nearest 404.html for a missing URL.
|
|
1384
|
+
const { notFoundDocument, notFoundDocuments } = serverManifest(compiled, "mpa", rootHtml, pathBase, fallbacks(), styled);
|
|
1385
|
+
for (const [scope, document] of Object.entries(notFoundDocuments ?? { "/": notFoundDocument })) {
|
|
1386
|
+
const outputFile = path.join(outDir, decodeURIComponent(scope.slice(1)), "404.html");
|
|
1387
|
+
await mkdir(path.dirname(outputFile), { recursive: true });
|
|
1388
|
+
await writeFile(outputFile, document, "utf8");
|
|
1389
|
+
}
|
|
1390
|
+
for (const route of compiled.routes) {
|
|
1391
|
+
if (route.path === "/" || route.policy?.rendering === "request")
|
|
1392
|
+
continue;
|
|
1393
|
+
const outputFile = path.join(outDir, decodeURIComponent(route.path.slice(1)), "index.html");
|
|
1394
|
+
await mkdir(path.dirname(outputFile), { recursive: true });
|
|
1395
|
+
await writeFile(outputFile, styled(applyDocumentMetadata(replaceOutlet(rootHtml, outletFor(compiled, "mpa", route.path, fallbacks(), profile.mixed)), pageHead(shellHead, route.metadata ?? {}))), "utf8");
|
|
1396
|
+
}
|
|
1397
|
+
if (compiled.routes.find(route => route.path === "/")?.policy?.rendering === "request")
|
|
1398
|
+
await unlink(path.join(outDir, "index.html"));
|
|
304
1399
|
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
if (route.path === "/")
|
|
309
|
-
continue;
|
|
310
|
-
const outputFile = path.join(outDir, route.path.slice(1), "index.html");
|
|
311
|
-
await mkdir(path.dirname(outputFile), { recursive: true });
|
|
312
|
-
await writeFile(outputFile, replaceOutlet(rootHtml, outletFor(compiled, "mpa", route.path)), "utf8");
|
|
1400
|
+
finally {
|
|
1401
|
+
compilation?.abort();
|
|
1402
|
+
releaseRuntimeHooks();
|
|
313
1403
|
}
|
|
314
1404
|
},
|
|
315
1405
|
async handleHotUpdate(context) {
|
|
316
|
-
if (
|
|
1406
|
+
if (nested)
|
|
1407
|
+
return;
|
|
1408
|
+
const file = context.file.replaceAll("\\", "/");
|
|
1409
|
+
if (pageScripts.some(script => script.source === file) || options.serverComponents && (file.endsWith(".fragment.html") || options.serverComponents.references && file.startsWith(path.resolve(vite.root, options.serverComponents.references) + path.sep) || file === path.resolve(vite.root, options.serverComponents.server) || options.serverComponents.client && file === path.resolve(vite.root, options.serverComponents.client)) || ["/pages/", "/components/", "/layouts/", "/islands/", "/api/"].some((part) => file.includes(part))) {
|
|
1410
|
+
const environment = context.environment?.name;
|
|
1411
|
+
if (environment)
|
|
1412
|
+
invalidateEnvironmentModule(context.server, resolvedVirtualId, environment, environmentApiEnabled);
|
|
317
1413
|
await refresh(context.server);
|
|
318
1414
|
}
|
|
319
1415
|
}
|