exta2 0.0.1-beta.29

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 ADDED
@@ -0,0 +1,43 @@
1
+ # Exta
2
+
3
+ SSG Framework for React
4
+
5
+ ## Features
6
+
7
+ - **File-based Routing**: Generates routes based on file names.
8
+
9
+ - **Fast startup**: Runs with the speed of Vite and Esbuild.
10
+
11
+ - **Vite-based**: Leverages Vite's broad ecosystem within exta.
12
+
13
+ - **`.tsx`, `.jsx` support**: Build type-safe apps with TypeScript.
14
+
15
+ ## Getting Started
16
+
17
+ - **Download Template**
18
+
19
+ You can download the current application template from [this repository](https://github.com/do4ng/exta-template).
20
+
21
+ ```bash
22
+ git clone https://github.com/do4ng/exta-template my-app
23
+ ```
24
+
25
+ - **Start Manually**
26
+
27
+ exta is provided as a Vite plugin.
28
+ Install the exta core package and the Vite React plugin to apply exta to an existing project.
29
+
30
+ ```ts
31
+ import { defineConfig } from 'vite';
32
+ import react from '@vitejs/plugin-react';
33
+
34
+ import { exta } from 'exta';
35
+
36
+ export default defineConfig({
37
+ plugins: [react(), exta()],
38
+ });
39
+ ```
40
+
41
+ ## LICENSE
42
+
43
+ MIT
@@ -0,0 +1,2 @@
1
+
2
+ export { };
package/dist/client.js ADDED
@@ -0,0 +1,169 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __copyProps = (to, from, except, desc) => {
8
+ if (from && typeof from === "object" || typeof from === "function") {
9
+ for (let key of __getOwnPropNames(from))
10
+ if (!__hasOwnProp.call(to, key) && key !== except)
11
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
12
+ }
13
+ return to;
14
+ };
15
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
16
+ // If the importer is in node compatibility mode or this is not an ESM
17
+ // file that has been converted to a CommonJS file using a Babel-
18
+ // compatible transform (i.e. "__esModule" has not been set), then set
19
+ // "default" to the CommonJS "module.exports" for node compatibility.
20
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
21
+ mod
22
+ ));
23
+ var import_react = __toESM(require("react"), 1);
24
+ var import_client = __toESM(require("react-dom/client"), 1);
25
+ var import_exta_router = require("$exta-router");
26
+ var import_react2 = __toESM(require("react"), 1);
27
+ const import_meta = {};
28
+ function matchUrlToRoute(url, routeResult) {
29
+ let { regex, params } = routeResult, match = regex.exec(url);
30
+ if (!match)
31
+ return null;
32
+ let result = {};
33
+ for (let i = 0; i < params.length; i++) {
34
+ let paramName = params[i], capturedValue = match[i + 1];
35
+ if (paramName.startsWith("..."))
36
+ throw new Error(
37
+ "[... file names are not supported due to static data generation issues."
38
+ );
39
+ result[paramName] = capturedValue;
40
+ }
41
+ return result;
42
+ }
43
+ var overlayEl = null;
44
+ function ensureOverlay(style = "") {
45
+ overlayEl || (overlayEl = document.createElement("div"), overlayEl.className = "__exta_overlay", overlayEl.style.cssText = `
46
+ min-width: 100px;
47
+ position: fixed;
48
+ bottom: 16px;
49
+ left: 16px;
50
+ z-index: 99999;
51
+ font-family: Consolas, "Courier New", monospace;
52
+ background: rgba(0,0,0,0.78);
53
+ color: #fff;
54
+ padding: 10px 14px;
55
+ border-radius: 10px;
56
+ box-shadow: rgba(0, 0, 0, 0.12) 0px 1px 3px, rgba(0, 0, 0, 0.24) 0px 1px 2px;
57
+ font-size: 14px;
58
+ line-height: 1.35;
59
+ max-width: 320px;
60
+ backdrop-filter: blur(4px);
61
+ transition: opacity 400ms ease, transform 400ms ease;
62
+ opacity: 0;
63
+ transform: translateY(-6px) scale(0.98);
64
+ display: none;
65
+ ${style}
66
+ `, document.body.appendChild(overlayEl), overlayEl.addEventListener("transitionend", () => {
67
+ overlayEl.style.opacity === "0" && (overlayEl.style.display = "none");
68
+ }));
69
+ }
70
+ function show(text, error) {
71
+ ensureOverlay(error === true ? "color: #ff3c3c" : ""), error === true && import_meta.env.PROD && (text = "An internal client error occurred. See the console for details."), text && (overlayEl.textContent = text), overlayEl.style.display = "block", requestAnimationFrame(() => {
72
+ overlayEl.style.opacity = "1", overlayEl.style.transform = "translateY(0) scale(1)";
73
+ });
74
+ }
75
+ function setText(text) {
76
+ ensureOverlay(), overlayEl.textContent = text;
77
+ }
78
+ function hide() {
79
+ overlayEl && (overlayEl.style.opacity = "0", overlayEl.style.transform = "translateY(-6px) scale(0.98)");
80
+ }
81
+ typeof window < "u" && (window.__overlay__ = {
82
+ show,
83
+ setText,
84
+ hide
85
+ });
86
+ var ErrorBoundary = class extends import_react2.default.Component {
87
+ state = { hasError: false, error: null };
88
+ static getDerivedStateFromError(error) {
89
+ return { hasError: true, error };
90
+ }
91
+ componentDidCatch(error, info) {
92
+ this.props.onError ? this.props.onError(error, info) : console.error(error, info);
93
+ }
94
+ render() {
95
+ if (this.state.hasError) {
96
+ let ErrorComp = this.props.errorComponent;
97
+ return ErrorComp && this.state.error ? import_react2.default.createElement(ErrorComp, {
98
+ error: this.state.error,
99
+ status: "Client Error",
100
+ message: this.state.error.message
101
+ }) : import_react2.default.createElement("div", null, "Something went wrong.");
102
+ }
103
+ return import_react2.default.createElement(import_react2.default.Fragment, null, this.props.children);
104
+ }
105
+ }, error_default = ErrorBoundary;
106
+ function prettyURL(path) {
107
+ return path === "." && (path = ""), path.startsWith("/") || (path = `/${path}`), path.endsWith("/") && (path = path.slice(0, -1)), path;
108
+ }
109
+ function App() {
110
+ let isFirstRender = (0, import_react.useRef)(true), location = (0, import_exta_router.usePathname)(), search = (0, import_exta_router.useSearchQuery)(), url = decodeURIComponent(new URL(location, window.location.origin).pathname), props = import_exta_router.router.data.get(prettyURL(url).toLowerCase()), page = import_exta_router.router.findPage(url), Layout = import_exta_router.router.layout._page, rootElement = document.getElementById("_app");
111
+ (0, import_react.useEffect)(() => {
112
+ if (isFirstRender.current) {
113
+ isFirstRender.current = false;
114
+ return;
115
+ }
116
+ window.scrollTo({ top: 0, behavior: "instant" }), rootElement && rootElement.scrollTo({ top: 0, behavior: "instant" });
117
+ }, [location, search]);
118
+ let createError = (props2) => import_react.default.createElement(
119
+ Layout,
120
+ null,
121
+ import_react.default.createElement(import_exta_router.router.error._page, {
122
+ key: location,
123
+ ...props2
124
+ })
125
+ );
126
+ if (!page || props?.status === 404)
127
+ return createError({
128
+ key: location,
129
+ status: 404,
130
+ message: "Page not found"
131
+ });
132
+ if (props?.status === 500)
133
+ return show(`ERROR: ${props.detail}`, true), createError({
134
+ key: location,
135
+ status: 500,
136
+ message: "Internal Server Error"
137
+ });
138
+ let Page = import_exta_router.router.modules[page.path]._page, params = matchUrlToRoute(url, { params: page.params, regex: page.regexp });
139
+ return import_react.default.createElement(
140
+ Layout,
141
+ null,
142
+ import_react.default.createElement(Page, { key: location, ...props, params })
143
+ );
144
+ }
145
+ var compilingInterval;
146
+ if (import_meta.env.DEV) {
147
+ let intervalIndex = 0;
148
+ compilingInterval = setInterval(() => {
149
+ if (intervalIndex * 250 >= 250) {
150
+ let num = intervalIndex % 3 + 1;
151
+ show(`compiling${".".repeat(num)}`);
152
+ }
153
+ intervalIndex += 1;
154
+ }, 250);
155
+ }
156
+ import_exta_router.router.goto(window.location.href).then(() => {
157
+ let mainComponent = import_react.default.createElement(
158
+ // Error Catcher
159
+ error_default,
160
+ {
161
+ errorComponent: import_exta_router.router.error._page,
162
+ onError(error) {
163
+ console.error(error), import_meta.env.PROD ? show("An internal client error occurred. See the console for details.", true) : show(`ERROR: ${error.message}`, true);
164
+ }
165
+ },
166
+ import_react.default.createElement(App, null)
167
+ );
168
+ import_meta.env.PROD ? import_client.default.hydrateRoot(document.getElementById("_app"), mainComponent) : (import_client.default.createRoot(document.getElementById("_app")).render(mainComponent), clearInterval(compilingInterval), hide());
169
+ });
@@ -0,0 +1,155 @@
1
+ // packages/exta/src/client/client.ts
2
+ import React2, { useEffect, useRef } from "react";
3
+ import ReactDOM from "react-dom/client";
4
+ import { router, usePathname, useSearchQuery } from "$exta-router";
5
+
6
+ // packages/exta/src/utils/params.ts
7
+ function matchUrlToRoute(url, routeResult) {
8
+ let { regex, params } = routeResult, match = regex.exec(url);
9
+ if (!match)
10
+ return null;
11
+ let result = {};
12
+ for (let i = 0; i < params.length; i++) {
13
+ let paramName = params[i], capturedValue = match[i + 1];
14
+ if (paramName.startsWith("..."))
15
+ throw new Error(
16
+ "[... file names are not supported due to static data generation issues."
17
+ );
18
+ result[paramName] = capturedValue;
19
+ }
20
+ return result;
21
+ }
22
+
23
+ // packages/exta/src/client/overlay.ts
24
+ var overlayEl = null;
25
+ function ensureOverlay(style = "") {
26
+ overlayEl || (overlayEl = document.createElement("div"), overlayEl.className = "__exta_overlay", overlayEl.style.cssText = `
27
+ min-width: 100px;
28
+ position: fixed;
29
+ bottom: 16px;
30
+ left: 16px;
31
+ z-index: 99999;
32
+ font-family: Consolas, "Courier New", monospace;
33
+ background: rgba(0,0,0,0.78);
34
+ color: #fff;
35
+ padding: 10px 14px;
36
+ border-radius: 10px;
37
+ box-shadow: rgba(0, 0, 0, 0.12) 0px 1px 3px, rgba(0, 0, 0, 0.24) 0px 1px 2px;
38
+ font-size: 14px;
39
+ line-height: 1.35;
40
+ max-width: 320px;
41
+ backdrop-filter: blur(4px);
42
+ transition: opacity 400ms ease, transform 400ms ease;
43
+ opacity: 0;
44
+ transform: translateY(-6px) scale(0.98);
45
+ display: none;
46
+ ${style}
47
+ `, document.body.appendChild(overlayEl), overlayEl.addEventListener("transitionend", () => {
48
+ overlayEl.style.opacity === "0" && (overlayEl.style.display = "none");
49
+ }));
50
+ }
51
+ function show(text, error) {
52
+ ensureOverlay(error === !0 ? "color: #ff3c3c" : ""), error === !0 && import.meta.env.PROD && (text = "An internal client error occurred. See the console for details."), text && (overlayEl.textContent = text), overlayEl.style.display = "block", requestAnimationFrame(() => {
53
+ overlayEl.style.opacity = "1", overlayEl.style.transform = "translateY(0) scale(1)";
54
+ });
55
+ }
56
+ function setText(text) {
57
+ ensureOverlay(), overlayEl.textContent = text;
58
+ }
59
+ function hide() {
60
+ overlayEl && (overlayEl.style.opacity = "0", overlayEl.style.transform = "translateY(-6px) scale(0.98)");
61
+ }
62
+ typeof window < "u" && (window.__overlay__ = {
63
+ show,
64
+ setText,
65
+ hide
66
+ });
67
+
68
+ // packages/exta/src/client/components/error.ts
69
+ import React from "react";
70
+ var ErrorBoundary = class extends React.Component {
71
+ state = { hasError: !1, error: null };
72
+ static getDerivedStateFromError(error) {
73
+ return { hasError: !0, error };
74
+ }
75
+ componentDidCatch(error, info) {
76
+ this.props.onError ? this.props.onError(error, info) : console.error(error, info);
77
+ }
78
+ render() {
79
+ if (this.state.hasError) {
80
+ let ErrorComp = this.props.errorComponent;
81
+ return ErrorComp && this.state.error ? React.createElement(ErrorComp, {
82
+ error: this.state.error,
83
+ status: "Client Error",
84
+ message: this.state.error.message
85
+ }) : React.createElement("div", null, "Something went wrong.");
86
+ }
87
+ return React.createElement(React.Fragment, null, this.props.children);
88
+ }
89
+ }, error_default = ErrorBoundary;
90
+
91
+ // packages/exta/src/client/client.ts
92
+ function prettyURL(path) {
93
+ return path === "." && (path = ""), path.startsWith("/") || (path = `/${path}`), path.endsWith("/") && (path = path.slice(0, -1)), path;
94
+ }
95
+ function App() {
96
+ let isFirstRender = useRef(!0), location = usePathname(), search = useSearchQuery(), url = decodeURIComponent(new URL(location, window.location.origin).pathname), props = router.data.get(prettyURL(url).toLowerCase()), page = router.findPage(url), Layout = router.layout._page, rootElement = document.getElementById("_app");
97
+ useEffect(() => {
98
+ if (isFirstRender.current) {
99
+ isFirstRender.current = !1;
100
+ return;
101
+ }
102
+ window.scrollTo({ top: 0, behavior: "instant" }), rootElement && rootElement.scrollTo({ top: 0, behavior: "instant" });
103
+ }, [location, search]);
104
+ let createError = (props2) => React2.createElement(
105
+ Layout,
106
+ null,
107
+ React2.createElement(router.error._page, {
108
+ key: location,
109
+ ...props2
110
+ })
111
+ );
112
+ if (!page || props?.status === 404)
113
+ return createError({
114
+ key: location,
115
+ status: 404,
116
+ message: "Page not found"
117
+ });
118
+ if (props?.status === 500)
119
+ return show(`ERROR: ${props.detail}`, !0), createError({
120
+ key: location,
121
+ status: 500,
122
+ message: "Internal Server Error"
123
+ });
124
+ let Page = router.modules[page.path]._page, params = matchUrlToRoute(url, { params: page.params, regex: page.regexp });
125
+ return React2.createElement(
126
+ Layout,
127
+ null,
128
+ React2.createElement(Page, { key: location, ...props, params })
129
+ );
130
+ }
131
+ var compilingInterval;
132
+ if (import.meta.env.DEV) {
133
+ let intervalIndex = 0;
134
+ compilingInterval = setInterval(() => {
135
+ if (intervalIndex * 250 >= 250) {
136
+ let num = intervalIndex % 3 + 1;
137
+ show(`compiling${".".repeat(num)}`);
138
+ }
139
+ intervalIndex += 1;
140
+ }, 250);
141
+ }
142
+ router.goto(window.location.href).then(() => {
143
+ let mainComponent = React2.createElement(
144
+ // Error Catcher
145
+ error_default,
146
+ {
147
+ errorComponent: router.error._page,
148
+ onError(error) {
149
+ console.error(error), import.meta.env.PROD ? show("An internal client error occurred. See the console for details.", !0) : show(`ERROR: ${error.message}`, !0);
150
+ }
151
+ },
152
+ React2.createElement(App, null)
153
+ );
154
+ import.meta.env.PROD ? ReactDOM.hydrateRoot(document.getElementById("_app"), mainComponent) : (ReactDOM.createRoot(document.getElementById("_app")).render(mainComponent), clearInterval(compilingInterval), hide());
155
+ });
@@ -0,0 +1,23 @@
1
+ import React, { ReactElement } from 'react';
2
+
3
+ type AnchorBaseProps = Omit<React.ComponentPropsWithoutRef<'a'>, 'href' | 'onClick'> & {
4
+ href: string;
5
+ /**
6
+ * Download the data for that page in advance.
7
+ */
8
+ prefetch?: boolean;
9
+ /**
10
+ * Load page data from the SSR stage.
11
+ */
12
+ preload?: boolean;
13
+ onClick?: (e: React.MouseEvent<HTMLAnchorElement>) => void | Promise<void>;
14
+ };
15
+ declare function Link({ href, onClick, prefetch, preload, ...props }: AnchorBaseProps): React.JSX.Element;
16
+
17
+ declare function Image({ src, ...props }: React.ComponentPropsWithoutRef<'img'>): React.JSX.Element;
18
+
19
+ declare function Head({ children }: {
20
+ children: ReactElement | ReactElement[];
21
+ }): any;
22
+
23
+ export { Head, Image, Link };
@@ -0,0 +1,96 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+ var components_exports = {};
29
+ __export(components_exports, {
30
+ Head: () => Head,
31
+ Image: () => Image,
32
+ Link: () => Link
33
+ });
34
+ module.exports = __toCommonJS(components_exports);
35
+ var import_react = __toESM(require("react"), 1);
36
+ var import_react2 = __toESM(require("react"), 1);
37
+ var import_react3 = require("react");
38
+ var import_server = require("react-dom/server");
39
+ function isExternal(url) {
40
+ try {
41
+ return new URL(url, window.location.href).origin !== window.location.origin;
42
+ } catch {
43
+ return false;
44
+ }
45
+ }
46
+ function Link({ href, onClick, prefetch, preload, ...props }) {
47
+ if (typeof window > "u")
48
+ return preload && global.__EXTA_SSR_DATA__.head.push({ type: "preload-data-link", data: href }), /* @__PURE__ */ import_react.default.createElement("a", { ...props, href }, props.children);
49
+ let useRouter = window._exta_useRouter, extaRouter = window._exta_router, router = useRouter();
50
+ if (!isExternal(href) && prefetch !== false) {
51
+ let url = new URL(href, window.location.origin);
52
+ extaRouter.prefetch(url.pathname);
53
+ }
54
+ return /* @__PURE__ */ import_react.default.createElement("a", { ...props, href, onClick: async (e) => {
55
+ if (e.defaultPrevented || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || props.target === "_blank")
56
+ return;
57
+ let current = window.location, target = new URL(href, current.href), isHashOnly = href.startsWith("#"), isSamePath = target.pathname === current.pathname, isHashChange = target.hash && target.hash !== current.hash;
58
+ if (!(isHashOnly || isSamePath && isHashChange) && (e.preventDefault(), e.stopPropagation(), !(onClick && (await onClick(e), e.defaultPrevented)))) {
59
+ if (isExternal(href)) {
60
+ window.location.href = href;
61
+ return;
62
+ }
63
+ await extaRouter.goto(target.pathname), router.push(target.pathname + target.search + target.hash);
64
+ }
65
+ } }, props.children);
66
+ }
67
+ function Image({ src, ...props }) {
68
+ return /* @__PURE__ */ import_react2.default.createElement("img", { ...props, src }, props.children);
69
+ }
70
+ function Head({ children }) {
71
+ if (typeof window > "u") {
72
+ if (global.__EXTA_SSR_DATA__) {
73
+ let wrapped = Array.isArray(children) ? children.map(
74
+ (c, i) => (0, import_react3.cloneElement)(c, { "data-ssr-head": "", key: i })
75
+ ) : (0, import_react3.cloneElement)(children, {
76
+ "data-ssr-head": ""
77
+ });
78
+ global.__EXTA_SSR_DATA__.head.push({
79
+ type: "html",
80
+ data: (0, import_server.renderToStaticMarkup)(wrapped).replace(/data-ssr-head=""/g, "data-ssr-head")
81
+ });
82
+ }
83
+ return null;
84
+ }
85
+ return (0, import_react3.useEffect)(() => {
86
+ document.head.querySelectorAll("[data-ssr-head]").forEach((el) => el.parentNode?.removeChild(el));
87
+ let html = (0, import_server.renderToStaticMarkup)(children), template = document.createElement("template");
88
+ template.innerHTML = html;
89
+ let nodes = Array.from(template.content.childNodes);
90
+ return nodes.forEach((node) => document.head.appendChild(node)), () => {
91
+ nodes.forEach((node) => {
92
+ document.head.contains(node) && document.head.removeChild(node);
93
+ });
94
+ };
95
+ }, [children]), null;
96
+ }
@@ -0,0 +1,72 @@
1
+ // packages/exta/src/components/Link.tsx
2
+ import React from "react";
3
+ function isExternal(url) {
4
+ try {
5
+ return new URL(url, window.location.href).origin !== window.location.origin;
6
+ } catch {
7
+ return !1;
8
+ }
9
+ }
10
+ function Link({ href, onClick, prefetch, preload, ...props }) {
11
+ if (typeof window > "u")
12
+ return preload && global.__EXTA_SSR_DATA__.head.push({ type: "preload-data-link", data: href }), /* @__PURE__ */ React.createElement("a", { ...props, href }, props.children);
13
+ let useRouter = window._exta_useRouter, extaRouter = window._exta_router, router = useRouter();
14
+ if (!isExternal(href) && prefetch !== !1) {
15
+ let url = new URL(href, window.location.origin);
16
+ extaRouter.prefetch(url.pathname);
17
+ }
18
+ return /* @__PURE__ */ React.createElement("a", { ...props, href, onClick: async (e) => {
19
+ if (e.defaultPrevented || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || props.target === "_blank")
20
+ return;
21
+ let current = window.location, target = new URL(href, current.href), isHashOnly = href.startsWith("#"), isSamePath = target.pathname === current.pathname, isHashChange = target.hash && target.hash !== current.hash;
22
+ if (!(isHashOnly || isSamePath && isHashChange) && (e.preventDefault(), e.stopPropagation(), !(onClick && (await onClick(e), e.defaultPrevented)))) {
23
+ if (isExternal(href)) {
24
+ window.location.href = href;
25
+ return;
26
+ }
27
+ await extaRouter.goto(target.pathname), router.push(target.pathname + target.search + target.hash);
28
+ }
29
+ } }, props.children);
30
+ }
31
+
32
+ // packages/exta/src/components/Image.tsx
33
+ import React2 from "react";
34
+ function Image({ src, ...props }) {
35
+ return /* @__PURE__ */ React2.createElement("img", { ...props, src }, props.children);
36
+ }
37
+
38
+ // packages/exta/src/components/Head.tsx
39
+ import { useEffect, cloneElement } from "react";
40
+ import { renderToStaticMarkup } from "react-dom/server";
41
+ function Head({ children }) {
42
+ if (typeof window > "u") {
43
+ if (global.__EXTA_SSR_DATA__) {
44
+ let wrapped = Array.isArray(children) ? children.map(
45
+ (c, i) => cloneElement(c, { "data-ssr-head": "", key: i })
46
+ ) : cloneElement(children, {
47
+ "data-ssr-head": ""
48
+ });
49
+ global.__EXTA_SSR_DATA__.head.push({
50
+ type: "html",
51
+ data: renderToStaticMarkup(wrapped).replace(/data-ssr-head=""/g, "data-ssr-head")
52
+ });
53
+ }
54
+ return null;
55
+ }
56
+ return useEffect(() => {
57
+ document.head.querySelectorAll("[data-ssr-head]").forEach((el) => el.parentNode?.removeChild(el));
58
+ let html = renderToStaticMarkup(children), template = document.createElement("template");
59
+ template.innerHTML = html;
60
+ let nodes = Array.from(template.content.childNodes);
61
+ return nodes.forEach((node) => document.head.appendChild(node)), () => {
62
+ nodes.forEach((node) => {
63
+ document.head.contains(node) && document.head.removeChild(node);
64
+ });
65
+ };
66
+ }, [children]), null;
67
+ }
68
+ export {
69
+ Head,
70
+ Image,
71
+ Link
72
+ };
@@ -0,0 +1,52 @@
1
+ import { Plugin } from 'vite';
2
+
3
+ interface BaseConfig {
4
+ compileOptions?: CompileOptions;
5
+ }
6
+ interface CompileOptions {
7
+ /** @default {true} */
8
+ ignoreSideEffects?: boolean;
9
+ preserveSideEffects?: string[];
10
+ outdir?: string;
11
+ assetsExtensions?: string[];
12
+ }
13
+
14
+ declare function exta(options?: BaseConfig): Plugin[];
15
+
16
+ interface ErrorProps {
17
+ status?: number | string;
18
+ message?: string;
19
+ }
20
+
21
+ declare const PAGE_STATIC_DATA_FUNCTION = "getStaticProps";
22
+ declare const PAGE_STATIC_PARAMS_FUNCTION = "getStaticParams";
23
+
24
+ interface StaticPropsContext {
25
+ params: Record<string, string>;
26
+ }
27
+ type StaticParamsOutput<T> = Array<T>;
28
+ type StaticPropsFC<T = any> = (ctx: StaticPropsContext) => Promise<T> | T;
29
+ type StaticParamsFC<T = Record<string, string>> = () => Promise<StaticParamsOutput<T>> | StaticParamsOutput<T>;
30
+ type ServerModule = {
31
+ [PAGE_STATIC_DATA_FUNCTION]: StaticPropsFC;
32
+ [PAGE_STATIC_PARAMS_FUNCTION]: StaticParamsFC;
33
+ };
34
+ interface PageProps<PropsType = any, ParamsType = Record<string, string>> {
35
+ params: ParamsType;
36
+ props: PropsType;
37
+ }
38
+ type ExtaPage<PropsType = any, ParamsType = Record<string, string>> = (props: PageProps<PropsType, ParamsType>) => React.ReactNode;
39
+ type ExtaLayout = (props: {
40
+ children: React.ReactNode;
41
+ }) => React.ReactNode;
42
+ type ExtaErrorComponent = (props: ErrorProps) => React.ReactNode;
43
+
44
+ declare function compilePage(filename: string, options: CompileOptions, ignoreAssets: boolean): Promise<{
45
+ outfiles: {
46
+ client: string;
47
+ server: string;
48
+ };
49
+ }>;
50
+
51
+ export { compilePage, exta };
52
+ export type { ExtaErrorComponent, ExtaLayout, ExtaPage, PageProps, ServerModule, StaticParamsFC, StaticParamsOutput, StaticPropsContext, StaticPropsFC };