honox 0.1.10 → 0.1.12
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 +11 -6
- package/dist/client/client.js +5 -2
- package/dist/server/server.js +9 -3
- package/dist/utils/file.js +1 -5
- package/dist/utils/file.test.d.ts +2 -0
- package/dist/utils/file.test.js +123 -0
- package/dist/vite/inject-importing-islands.js +1 -1
- package/dist/vite/island-components.js +3 -3
- package/dist/vite/island-components.test.d.ts +2 -0
- package/dist/vite/island-components.test.js +102 -0
- package/package.json +13 -15
package/README.md
CHANGED
|
@@ -241,7 +241,7 @@ Let's create an application that includes a client side. Here, we will use hono/
|
|
|
241
241
|
|
|
242
242
|
### Project Structure
|
|
243
243
|
|
|
244
|
-
|
|
244
|
+
Below is the project structure of a minimal application including a client side:
|
|
245
245
|
|
|
246
246
|
```txt
|
|
247
247
|
.
|
|
@@ -261,7 +261,7 @@ The below is the project structure of a minimal application including a client s
|
|
|
261
261
|
|
|
262
262
|
### Renderer
|
|
263
263
|
|
|
264
|
-
This is a `_renderer.tsx`, which will load the `/app/client.ts` entry file for the client. It will load the JavaScript file for
|
|
264
|
+
This is a `_renderer.tsx`, which will load the `/app/client.ts` entry file for the client. It will load the JavaScript file for production according to the variable `import.meta.env.PROD`. And renders the inside of `<HasIslands />` if there are islands on that page.
|
|
265
265
|
|
|
266
266
|
```tsx
|
|
267
267
|
// app/routes/_renderer.tsx
|
|
@@ -324,7 +324,12 @@ createClient()
|
|
|
324
324
|
|
|
325
325
|
### Interactions
|
|
326
326
|
|
|
327
|
-
|
|
327
|
+
If you want to add interactions to your page, create Island components. Islands components should be:
|
|
328
|
+
|
|
329
|
+
- Placed under `app/islands` directory or named with `_` prefix and `island.tsx` suffix like `_componentName.island.tsx`.
|
|
330
|
+
- Should `default export function`.
|
|
331
|
+
|
|
332
|
+
For example, you can write an interactive component such as the following counter:
|
|
328
333
|
|
|
329
334
|
```tsx
|
|
330
335
|
// app/islands/counter.tsx
|
|
@@ -341,7 +346,7 @@ export default function Counter() {
|
|
|
341
346
|
}
|
|
342
347
|
```
|
|
343
348
|
|
|
344
|
-
When you load the component in a route file, it is rendered as Server-Side rendering and JavaScript is also
|
|
349
|
+
When you load the component in a route file, it is rendered as Server-Side rendering and JavaScript is also sent to the client side.
|
|
345
350
|
|
|
346
351
|
```tsx
|
|
347
352
|
// app/routes/index.tsx
|
|
@@ -358,7 +363,7 @@ export default createRoute((c) => {
|
|
|
358
363
|
})
|
|
359
364
|
```
|
|
360
365
|
|
|
361
|
-
**Note**: You cannot access a Context object in Island components. Therefore, you should pass the value from components outside of Island.
|
|
366
|
+
**Note**: You cannot access a Context object in Island components. Therefore, you should pass the value from components outside of the Island.
|
|
362
367
|
|
|
363
368
|
```ts
|
|
364
369
|
import { useRequestContext } from 'hono/jsx-renderer'
|
|
@@ -779,7 +784,7 @@ Build command (including a client):
|
|
|
779
784
|
vite build --mode client && vite build
|
|
780
785
|
```
|
|
781
786
|
|
|
782
|
-
Deploy with the following commands after build. Ensure you have [Wrangler](https://developers.cloudflare.com/workers/wrangler/) installed:
|
|
787
|
+
Deploy with the following commands after the build. Ensure you have [Wrangler](https://developers.cloudflare.com/workers/wrangler/) installed:
|
|
783
788
|
|
|
784
789
|
```txt
|
|
785
790
|
wrangler pages deploy ./dist
|
package/dist/client/client.js
CHANGED
|
@@ -2,8 +2,11 @@ import { render } from "hono/jsx/dom";
|
|
|
2
2
|
import { jsx as jsxFn } from "hono/jsx/dom/jsx-runtime";
|
|
3
3
|
import { COMPONENT_NAME, DATA_HONO_TEMPLATE, DATA_SERIALIZED_PROPS } from "../constants.js";
|
|
4
4
|
const createClient = async (options) => {
|
|
5
|
-
const FILES = options?.ISLAND_FILES ??
|
|
6
|
-
|
|
5
|
+
const FILES = options?.ISLAND_FILES ?? {
|
|
6
|
+
...import.meta.glob("/app/islands/**/[a-zA-Z0-9[-]+.(tsx|ts)"),
|
|
7
|
+
...import.meta.glob("/app/routes/**/_[a-zA-Z0-9[-]+.island.(tsx|ts)")
|
|
8
|
+
};
|
|
9
|
+
const root = options?.island_root ?? "/app";
|
|
7
10
|
const hydrateComponent = async (document2) => {
|
|
8
11
|
const filePromises = Object.keys(FILES).map(async (filePath) => {
|
|
9
12
|
const componentName = filePath.replace(root, "");
|
package/dist/server/server.js
CHANGED
|
@@ -13,6 +13,7 @@ const METHODS = ["GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"];
|
|
|
13
13
|
const createApp = (options) => {
|
|
14
14
|
const root = options.root;
|
|
15
15
|
const rootRegExp = new RegExp(`^${root}`);
|
|
16
|
+
const getRootPath = (dir) => filePathToPath(dir.replace(rootRegExp, ""));
|
|
16
17
|
const app = options.app ?? new Hono();
|
|
17
18
|
const trailingSlash = options.trailingSlash ?? false;
|
|
18
19
|
if (options.init) {
|
|
@@ -69,8 +70,6 @@ const createApp = (options) => {
|
|
|
69
70
|
subApp.use(...middleware.default);
|
|
70
71
|
}
|
|
71
72
|
}
|
|
72
|
-
let rootPath = dir.replace(rootRegExp, "");
|
|
73
|
-
rootPath = filePathToPath(rootPath);
|
|
74
73
|
for (const [filename, route] of Object.entries(content)) {
|
|
75
74
|
const importingIslands = route[IMPORTING_ISLANDS_ID];
|
|
76
75
|
const setInnerMeta = createMiddleware(async function innerMeta(c, next) {
|
|
@@ -101,14 +100,21 @@ const createApp = (options) => {
|
|
|
101
100
|
});
|
|
102
101
|
}
|
|
103
102
|
}
|
|
104
|
-
applyNotFound(subApp, dir, notFoundMap);
|
|
105
103
|
applyError(subApp, dir, errorMap);
|
|
104
|
+
let rootPath = getRootPath(dir);
|
|
106
105
|
if (trailingSlash) {
|
|
107
106
|
rootPath = /\/$/.test(rootPath) ? rootPath : rootPath + "/";
|
|
108
107
|
}
|
|
109
108
|
app.route(rootPath, subApp);
|
|
110
109
|
}
|
|
111
110
|
}
|
|
111
|
+
for (const map of routesMap.reverse()) {
|
|
112
|
+
const dir = Object.entries(map)[0][0];
|
|
113
|
+
const subApp = new Hono();
|
|
114
|
+
applyNotFound(subApp, dir, notFoundMap);
|
|
115
|
+
const rootPath = getRootPath(dir);
|
|
116
|
+
app.route(rootPath, subApp);
|
|
117
|
+
}
|
|
112
118
|
return app;
|
|
113
119
|
};
|
|
114
120
|
function applyNotFound(app, dir, map) {
|
package/dist/utils/file.js
CHANGED
|
@@ -33,12 +33,8 @@ const sortDirectoriesByDepth = (directories) => {
|
|
|
33
33
|
const sortedKeys = Object.keys(directories).sort((a, b) => {
|
|
34
34
|
const depthA = a.split("/").length;
|
|
35
35
|
const depthB = b.split("/").length;
|
|
36
|
-
return depthA - depthB;
|
|
36
|
+
return depthA - depthB || b.localeCompare(a);
|
|
37
37
|
});
|
|
38
|
-
if (sortedKeys.find((x) => /.*\/routes$/.test(x))) {
|
|
39
|
-
sortedKeys.push(sortedKeys[0]);
|
|
40
|
-
sortedKeys.shift();
|
|
41
|
-
}
|
|
42
38
|
return sortedKeys.map((key) => ({
|
|
43
39
|
[key]: directories[key]
|
|
44
40
|
}));
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import {
|
|
2
|
+
filePathToPath,
|
|
3
|
+
groupByDirectory,
|
|
4
|
+
listByDirectory,
|
|
5
|
+
pathToDirectoryPath,
|
|
6
|
+
sortDirectoriesByDepth
|
|
7
|
+
} from "./file";
|
|
8
|
+
describe("filePathToPath", () => {
|
|
9
|
+
it("Should return a correct path", () => {
|
|
10
|
+
expect(filePathToPath("index.tsx")).toBe("/");
|
|
11
|
+
expect(filePathToPath("index.get.tsx")).toBe("/index.get");
|
|
12
|
+
expect(filePathToPath("about.tsx")).toBe("/about");
|
|
13
|
+
expect(filePathToPath("about/index.tsx")).toBe("/about");
|
|
14
|
+
expect(filePathToPath("about/me")).toBe("/about/me");
|
|
15
|
+
expect(filePathToPath("about/me/index.tsx")).toBe("/about/me");
|
|
16
|
+
expect(filePathToPath("about/me/address.tsx")).toBe("/about/me/address");
|
|
17
|
+
expect(filePathToPath("/index.tsx")).toBe("/");
|
|
18
|
+
expect(filePathToPath("/index.get.tsx")).toBe("/index.get");
|
|
19
|
+
expect(filePathToPath("/about.tsx")).toBe("/about");
|
|
20
|
+
expect(filePathToPath("/about/index.tsx")).toBe("/about");
|
|
21
|
+
expect(filePathToPath("/about/me")).toBe("/about/me");
|
|
22
|
+
expect(filePathToPath("/about/me/index.tsx")).toBe("/about/me");
|
|
23
|
+
expect(filePathToPath("/about/me/address.tsx")).toBe("/about/me/address");
|
|
24
|
+
expect(filePathToPath("/about/[name].tsx")).toBe("/about/:name");
|
|
25
|
+
expect(filePathToPath("/about/[...foo].tsx")).toBe("/about/*");
|
|
26
|
+
expect(filePathToPath("/about/[name]/address.tsx")).toBe("/about/:name/address");
|
|
27
|
+
expect(filePathToPath("/about/[arg1]/[arg2]")).toBe("/about/:arg1/:arg2");
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
describe("groupByDirectory", () => {
|
|
31
|
+
const files = {
|
|
32
|
+
"/app/routes/index.tsx": "file1",
|
|
33
|
+
"/app/routes/about.tsx": "file2",
|
|
34
|
+
"/app/routes/blog/index.tsx": "file3",
|
|
35
|
+
"/app/routes/blog/about.tsx": "file4",
|
|
36
|
+
"/app/routes/blog/posts/index.tsx": "file5",
|
|
37
|
+
"/app/routes/blog/posts/comments.tsx": "file6"
|
|
38
|
+
};
|
|
39
|
+
it("Should group by directories", () => {
|
|
40
|
+
expect(groupByDirectory(files)).toEqual({
|
|
41
|
+
"/app/routes": {
|
|
42
|
+
"index.tsx": "file1",
|
|
43
|
+
"about.tsx": "file2"
|
|
44
|
+
},
|
|
45
|
+
"/app/routes/blog": {
|
|
46
|
+
"index.tsx": "file3",
|
|
47
|
+
"about.tsx": "file4"
|
|
48
|
+
},
|
|
49
|
+
"/app/routes/blog/posts": {
|
|
50
|
+
"index.tsx": "file5",
|
|
51
|
+
"comments.tsx": "file6"
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
describe("sortDirectoriesByDepth", () => {
|
|
57
|
+
it("Should sort directories by the depth", () => {
|
|
58
|
+
expect(
|
|
59
|
+
sortDirectoriesByDepth({
|
|
60
|
+
"/dir": {
|
|
61
|
+
"index.tsx": "file1"
|
|
62
|
+
},
|
|
63
|
+
"/dir/blog/[id]": {
|
|
64
|
+
"index.tsx": "file2"
|
|
65
|
+
},
|
|
66
|
+
"/dir/blog/posts": {
|
|
67
|
+
"index.tsx": "file3"
|
|
68
|
+
},
|
|
69
|
+
"/dir/blog": {
|
|
70
|
+
"index.tsx": "file4"
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
).toStrictEqual([
|
|
74
|
+
{
|
|
75
|
+
"/dir": {
|
|
76
|
+
"index.tsx": "file1"
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"/dir/blog": {
|
|
81
|
+
"index.tsx": "file4"
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"/dir/blog/posts": {
|
|
86
|
+
"index.tsx": "file3"
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"/dir/blog/[id]": {
|
|
91
|
+
"index.tsx": "file2"
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
]);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
describe("listByDirectory", () => {
|
|
98
|
+
it("Should list files by their directory", () => {
|
|
99
|
+
const files = {
|
|
100
|
+
"/app/routes/blog/posts/_renderer.tsx": "foo3",
|
|
101
|
+
"/app/routes/_renderer.tsx": "foo",
|
|
102
|
+
"/app/routes/blog/_renderer.tsx": "foo2"
|
|
103
|
+
};
|
|
104
|
+
const result = listByDirectory(files);
|
|
105
|
+
expect(result).toEqual({
|
|
106
|
+
"/app/routes": ["/app/routes/_renderer.tsx"],
|
|
107
|
+
"/app/routes/blog": ["/app/routes/blog/_renderer.tsx", "/app/routes/_renderer.tsx"],
|
|
108
|
+
"/app/routes/blog/posts": [
|
|
109
|
+
"/app/routes/blog/posts/_renderer.tsx",
|
|
110
|
+
"/app/routes/blog/_renderer.tsx",
|
|
111
|
+
"/app/routes/_renderer.tsx"
|
|
112
|
+
]
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
describe("pathToDirectoryPath", () => {
|
|
117
|
+
it("Should return the directory path", () => {
|
|
118
|
+
expect(pathToDirectoryPath("/")).toBe("/");
|
|
119
|
+
expect(pathToDirectoryPath("/about.tsx")).toBe("/");
|
|
120
|
+
expect(pathToDirectoryPath("/posts/index.tsx")).toBe("/posts/");
|
|
121
|
+
expect(pathToDirectoryPath("/posts/authors/index.tsx")).toBe("/posts/authors/");
|
|
122
|
+
});
|
|
123
|
+
});
|
|
@@ -7,7 +7,7 @@ import { normalizePath } from "vite";
|
|
|
7
7
|
import { IMPORTING_ISLANDS_ID } from "../constants.js";
|
|
8
8
|
const generate = _generate.default ?? _generate;
|
|
9
9
|
async function injectImportingIslands() {
|
|
10
|
-
const isIslandRegex = new RegExp(
|
|
10
|
+
const isIslandRegex = new RegExp(/(\/islands\/|\_[a-zA-Z0-9[-]+\.island\.[tj]sx$)/);
|
|
11
11
|
const fileRegex = new RegExp(/(routes|_renderer|_error|_404)\/.*\.[tj]sx$/);
|
|
12
12
|
const cache = {};
|
|
13
13
|
const walkDependencyTree = async (baseFile, dependencyFile) => {
|
|
@@ -160,16 +160,16 @@ function islandComponents(options) {
|
|
|
160
160
|
},
|
|
161
161
|
async load(id) {
|
|
162
162
|
const defaultIsIsland = (id2) => {
|
|
163
|
-
const islandDirectoryPath = path.join(root, "app
|
|
163
|
+
const islandDirectoryPath = path.join(root, "app");
|
|
164
164
|
return path.resolve(id2).startsWith(islandDirectoryPath);
|
|
165
165
|
};
|
|
166
166
|
const matchIslandPath = options?.isIsland ?? defaultIsIsland;
|
|
167
167
|
if (!matchIslandPath(id)) {
|
|
168
168
|
return;
|
|
169
169
|
}
|
|
170
|
-
const match = id.match(
|
|
170
|
+
const match = id.match(/(\/islands\/.+?\.tsx$)|(\/routes\/.*\_[a-zA-Z0-9[-]+\.island\.tsx$)/);
|
|
171
171
|
if (match) {
|
|
172
|
-
const componentName = match[
|
|
172
|
+
const componentName = match[0];
|
|
173
173
|
const contents = await fs.readFile(id, "utf-8");
|
|
174
174
|
const code = transformJsxTags(contents, componentName);
|
|
175
175
|
if (code) {
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { transformJsxTags } from "./island-components";
|
|
2
|
+
describe("transformJsxTags", () => {
|
|
3
|
+
it("Should add component-wrapper and component-name attribute", () => {
|
|
4
|
+
const code = `export default function Badge() {
|
|
5
|
+
return <h1>Hello</h1>
|
|
6
|
+
}`;
|
|
7
|
+
const result = transformJsxTags(code, "Badge.tsx");
|
|
8
|
+
expect(result).toBe(
|
|
9
|
+
`const BadgeOriginal = function () {
|
|
10
|
+
return <h1>Hello</h1>;
|
|
11
|
+
};
|
|
12
|
+
const WrappedBadge = function (props) {
|
|
13
|
+
return import.meta.env.SSR ? <honox-island component-name="Badge.tsx" data-serialized-props={JSON.stringify(Object.fromEntries(Object.entries(props).filter(([key]) => key !== "children")))}><BadgeOriginal {...props}></BadgeOriginal>{props.children ? <template data-hono-template="">{props.children}</template> : null}</honox-island> : <BadgeOriginal {...props}></BadgeOriginal>;
|
|
14
|
+
};
|
|
15
|
+
export default WrappedBadge;`
|
|
16
|
+
);
|
|
17
|
+
});
|
|
18
|
+
it("Should not transform if it is blank", () => {
|
|
19
|
+
const code = transformJsxTags("", "Badge.tsx");
|
|
20
|
+
expect(code).toBe("");
|
|
21
|
+
});
|
|
22
|
+
it("async", () => {
|
|
23
|
+
const code = `export default async function AsyncComponent() {
|
|
24
|
+
return <h1>Hello</h1>
|
|
25
|
+
}`;
|
|
26
|
+
const result = transformJsxTags(code, "AsyncComponent.tsx");
|
|
27
|
+
expect(result).toBe(
|
|
28
|
+
`const AsyncComponentOriginal = async function () {
|
|
29
|
+
return <h1>Hello</h1>;
|
|
30
|
+
};
|
|
31
|
+
const WrappedAsyncComponent = function (props) {
|
|
32
|
+
return import.meta.env.SSR ? <honox-island component-name="AsyncComponent.tsx" data-serialized-props={JSON.stringify(Object.fromEntries(Object.entries(props).filter(([key]) => key !== "children")))}><AsyncComponentOriginal {...props}></AsyncComponentOriginal>{props.children ? <template data-hono-template="">{props.children}</template> : null}</honox-island> : <AsyncComponentOriginal {...props}></AsyncComponentOriginal>;
|
|
33
|
+
};
|
|
34
|
+
export default WrappedAsyncComponent;`
|
|
35
|
+
);
|
|
36
|
+
});
|
|
37
|
+
it("unnamed", () => {
|
|
38
|
+
const code = `export default async function() {
|
|
39
|
+
return <h1>Hello</h1>
|
|
40
|
+
}`;
|
|
41
|
+
const result = transformJsxTags(code, "UnnamedComponent.tsx");
|
|
42
|
+
expect(result).toBe(
|
|
43
|
+
`const __HonoIsladComponent__Original = async function () {
|
|
44
|
+
return <h1>Hello</h1>;
|
|
45
|
+
};
|
|
46
|
+
const Wrapped__HonoIsladComponent__ = function (props) {
|
|
47
|
+
return import.meta.env.SSR ? <honox-island component-name="UnnamedComponent.tsx" data-serialized-props={JSON.stringify(Object.fromEntries(Object.entries(props).filter(([key]) => key !== "children")))}><__HonoIsladComponent__Original {...props}></__HonoIsladComponent__Original>{props.children ? <template data-hono-template="">{props.children}</template> : null}</honox-island> : <__HonoIsladComponent__Original {...props}></__HonoIsladComponent__Original>;
|
|
48
|
+
};
|
|
49
|
+
export default Wrapped__HonoIsladComponent__;`
|
|
50
|
+
);
|
|
51
|
+
});
|
|
52
|
+
it("arrow - block", () => {
|
|
53
|
+
const code = `export default () => {
|
|
54
|
+
return <h1>Hello</h1>
|
|
55
|
+
}`;
|
|
56
|
+
const result = transformJsxTags(code, "UnnamedComponent.tsx");
|
|
57
|
+
expect(result).toBe(
|
|
58
|
+
`const __HonoIsladComponent__Original = () => {
|
|
59
|
+
return <h1>Hello</h1>;
|
|
60
|
+
};
|
|
61
|
+
const Wrapped__HonoIsladComponent__ = function (props) {
|
|
62
|
+
return import.meta.env.SSR ? <honox-island component-name="UnnamedComponent.tsx" data-serialized-props={JSON.stringify(Object.fromEntries(Object.entries(props).filter(([key]) => key !== "children")))}><__HonoIsladComponent__Original {...props}></__HonoIsladComponent__Original>{props.children ? <template data-hono-template="">{props.children}</template> : null}</honox-island> : <__HonoIsladComponent__Original {...props}></__HonoIsladComponent__Original>;
|
|
63
|
+
};
|
|
64
|
+
export default Wrapped__HonoIsladComponent__;`
|
|
65
|
+
);
|
|
66
|
+
});
|
|
67
|
+
it("arrow - expression", () => {
|
|
68
|
+
const code = "export default () => <h1>Hello</h1>";
|
|
69
|
+
const result = transformJsxTags(code, "UnnamedComponent.tsx");
|
|
70
|
+
expect(result).toBe(
|
|
71
|
+
`const __HonoIsladComponent__Original = () => <h1>Hello</h1>;
|
|
72
|
+
const Wrapped__HonoIsladComponent__ = function (props) {
|
|
73
|
+
return import.meta.env.SSR ? <honox-island component-name="UnnamedComponent.tsx" data-serialized-props={JSON.stringify(Object.fromEntries(Object.entries(props).filter(([key]) => key !== "children")))}><__HonoIsladComponent__Original {...props}></__HonoIsladComponent__Original>{props.children ? <template data-hono-template="">{props.children}</template> : null}</honox-island> : <__HonoIsladComponent__Original {...props}></__HonoIsladComponent__Original>;
|
|
74
|
+
};
|
|
75
|
+
export default Wrapped__HonoIsladComponent__;`
|
|
76
|
+
);
|
|
77
|
+
});
|
|
78
|
+
it("export via variable", () => {
|
|
79
|
+
const code = "export default ExportViaVariable";
|
|
80
|
+
const result = transformJsxTags(code, "ExportViaVariable.tsx");
|
|
81
|
+
expect(result).toBe(
|
|
82
|
+
`const WrappedExportViaVariable = function (props) {
|
|
83
|
+
return import.meta.env.SSR ? <honox-island component-name="ExportViaVariable.tsx" data-serialized-props={JSON.stringify(Object.fromEntries(Object.entries(props).filter(([key]) => key !== "children")))}><ExportViaVariable {...props}></ExportViaVariable>{props.children ? <template data-hono-template="">{props.children}</template> : null}</honox-island> : <ExportViaVariable {...props}></ExportViaVariable>;
|
|
84
|
+
};
|
|
85
|
+
export default WrappedExportViaVariable;`
|
|
86
|
+
);
|
|
87
|
+
});
|
|
88
|
+
it("export via specifier", () => {
|
|
89
|
+
const code = `const utilityFn = () => {}
|
|
90
|
+
const ExportViaVariable = () => <h1>Hello</h1>
|
|
91
|
+
export { utilityFn, ExportViaVariable as default }`;
|
|
92
|
+
const result = transformJsxTags(code, "ExportViaVariable.tsx");
|
|
93
|
+
expect(result).toBe(
|
|
94
|
+
`const utilityFn = () => {};
|
|
95
|
+
const ExportViaVariable = () => <h1>Hello</h1>;
|
|
96
|
+
const WrappedExportViaVariable = function (props) {
|
|
97
|
+
return import.meta.env.SSR ? <honox-island component-name="ExportViaVariable.tsx" data-serialized-props={JSON.stringify(Object.fromEntries(Object.entries(props).filter(([key]) => key !== "children")))}><ExportViaVariable {...props}></ExportViaVariable>{props.children ? <template data-hono-template="">{props.children}</template> : null}</honox-island> : <ExportViaVariable {...props}></ExportViaVariable>;
|
|
98
|
+
};
|
|
99
|
+
export { utilityFn, WrappedExportViaVariable as default };`
|
|
100
|
+
);
|
|
101
|
+
});
|
|
102
|
+
});
|
package/package.json
CHANGED
|
@@ -1,24 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "honox",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.12",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"test": "bun typecheck && bun test:unit && bun test:integration && bun test:e2e",
|
|
8
|
-
"test:unit": "vitest --run
|
|
9
|
-
"test:integration": "bun test:integration:api && bun test:integration:
|
|
10
|
-
"test:integration:
|
|
11
|
-
"test:integration:
|
|
12
|
-
"test:
|
|
13
|
-
"test:e2e": "playwright test -c ./test/hono-jsx/playwright.config.ts ./test/hono-jsx/e2e.test.ts",
|
|
14
|
-
"test:yarn": "yarn test:unit && yarn test:integration:api && yarn test:integration:hono-jsx && yarn test:e2e",
|
|
8
|
+
"test:unit": "vitest --run ./src",
|
|
9
|
+
"test:integration": "bun test:integration:api && bun test:integration:apps",
|
|
10
|
+
"test:integration:api": "vitest --run ./test-integration/api.test.ts",
|
|
11
|
+
"test:integration:apps": "vitest --run -c ./test-integration/vitest.config.ts ./test-integration/apps.test.ts",
|
|
12
|
+
"test:e2e": "playwright test -c ./test-e2e/playwright.config.ts ./test-e2e/e2e.test.ts",
|
|
15
13
|
"typecheck": "tsc --noEmit",
|
|
16
14
|
"build": "tsup && publint",
|
|
17
15
|
"watch": "tsup --watch",
|
|
18
|
-
"lint": "eslint --ext js,ts src test",
|
|
19
|
-
"lint:fix": "eslint --ext js,ts src test --fix",
|
|
20
|
-
"format": "prettier --check \"src/**/*.{js,ts}\" \"
|
|
21
|
-
"format:fix": "prettier --write \"src/**/*.{js,ts}\" \"
|
|
16
|
+
"lint": "eslint --ext js,ts src mocks test-integration test-e2e",
|
|
17
|
+
"lint:fix": "eslint --ext js,ts src mocks test-integration test-e2e --fix",
|
|
18
|
+
"format": "prettier --check \"src/**/*.{js,ts}\" \"mocks/**/*.{js,ts}\" \"test-*/**/*.{js,ts}\"",
|
|
19
|
+
"format:fix": "prettier --write \"src/**/*.{js,ts}\" \"mocks/**/*.{js,ts}\" \"test-*/**/*.{js,ts}\"",
|
|
22
20
|
"prerelease": "bun run test && bun run build",
|
|
23
21
|
"release": "np"
|
|
24
22
|
},
|
|
@@ -107,7 +105,7 @@
|
|
|
107
105
|
"@babel/parser": "^7.23.6",
|
|
108
106
|
"@babel/traverse": "^7.23.6",
|
|
109
107
|
"@babel/types": "^7.23.6",
|
|
110
|
-
"@hono/vite-dev-server": "^0.
|
|
108
|
+
"@hono/vite-dev-server": "^0.11.0",
|
|
111
109
|
"precinct": "^11.0.5"
|
|
112
110
|
},
|
|
113
111
|
"peerDependencies": {
|
|
@@ -128,8 +126,8 @@
|
|
|
128
126
|
"publint": "^0.2.7",
|
|
129
127
|
"tsup": "^8.0.1",
|
|
130
128
|
"typescript": "^5.3.3",
|
|
131
|
-
"vite": "^5.
|
|
132
|
-
"vitest": "^1.
|
|
129
|
+
"vite": "^5.2.8",
|
|
130
|
+
"vitest": "^1.4.0"
|
|
133
131
|
},
|
|
134
132
|
"engines": {
|
|
135
133
|
"node": ">=18.14.1"
|