honojs / honox Goto Github PK
View Code? Open in Web Editor NEWHonoX - Hono based meta framework
Home Page: https://hono.dev
License: MIT License
HonoX - Hono based meta framework
Home Page: https://hono.dev
License: MIT License
My previous Hono app used the @hono/vite-dev-server
package to setup local Cloudflare services. HonoX includes this, and it is all configured via the honox
plugin, but the docs don't make this immediately obvious.
import { defineConfig } from 'vite';
import client from 'honox/vite/client';
import honox from 'honox/vite';
import pages from '@hono/vite-cloudflare-pages';
export default defineConfig(({ mode }) => {
if (mode === 'client') {
return {
plugins: [client()],
};
} else {
return {
plugins: [
honox({
devServer: {
cf: {
d1Databases: { TORCH_DATABASE: 'TORCH_DATABASE' },
d1Persist: '../../.wrangler/state/v3/d1',
r2Buckets: ['TORCH_R2'],
r2Persist: '../../.wrangler/state/v3/r2',
kvNamespaces: ['TORCH_AUTH'],
kvPersist: '../../.wrangler/state/v3/kv',
},
},
}),
pages(),
],
};
}
});
For example, you want to remove the script tags on a page if the page does not load islands.
Like:
<script honox-only-has-islands />
And also, we can write this:
<script honox-only-env-prod />
0.1.0
Put the route file on app/routes/posts/index.get.tsx
:
And export app:
import { Hono } from 'hono'
const app = new Hono()
app.get((c) => {
return c.render('GET!')
})
export default app
The routing will be:
GET /posts/index.get
OR 404.
GET /posts/.get
No response
0.1.3+2
Use dev container to setup environment, and bun i
then bun dev
in the container.
Here's my boilerplate to reproduce the bug.
https://github.com/ryuujo1573/blue/tree/a23b3b0099b9be3043116c33c18f2431f0dcf077
Everything should be ok, as it is fine in my wsl2 host (ubuntu focal).
No response
No response
It looks like for now honox only supports building for cloudflare. I looked into the codebase and couldn't find a vite plugin to build for node or bun. Or at least instructions.
Now, in order to use tailwindcss with HonoX, we need to configure it with vite and add link tags for dev and prod envs in head.
This seems a bit troublesome.
It would be good if we could just import it as following:
import "../style.css"
If there is already a way to achieve this, please comment it.
I would like to do directory-based routing like SvelteKit and Next.js App Router.
Either in a way like (+)page.ts
or separate files for each HTTP method and route them like +get.ts
and +post.ts
.
Hi!
How about that re-export <Style />
in hono/css
from honox/server
?
The Script
and Style
are provided from separate sources, which would be confusing if you were set up without a template.
I agree that hono/css
itself is not an essential package for honox, so I would prefer to distribute it from a separate location.
I posted the issue to see if there is some other better way to distribute the information, even if it is not this way.
like this:
import { Script, Style } from 'honox/server'
I found the @hono/zod-openapi
to be great for producing OpenApi documentation fairly painlessly. The current HonoX API is very close to what @hono/zod-openapi
does.
https://github.com/honojs/middleware/tree/main/packages/swagger-ui#with-openapihono-usage
Is it possible to get the same behavior in HonoX? I know you can declare routes in the "classic" Hono fashion to make use of this, but I was wondering if there is a way to make this a first-class feature of HonoX.
[email protected], [email protected]
bun create hono my-app
// select x-basic
cd my-app
bun run build
No warnings.
Export "use" of module "node_modules/hono/dist/jsx/hooks/index.js" was reexported through module "node_modules/hono/dist/jsx/dom/index.js" while both modules are dependencies of each other and will end up in different chunks by current Rollup settings. This scenario is not well supported at the moment as it will produce a circular dependency between chunks and will likely lead to broken execution order.
Either change the import in "node_modules/honox/dist/client/runtime.js" to point directly to the exporting module or reconfigure "output.manualChunks" to ensure these modules end up in the same chunk.
No response
Would it be possible to create a _middleware.ts
file that would automatically add the middleware to routes at and below it? Cumulative _middleware
declarations would be merged, with higher ones taking precedence in the ordering.
//_middleware.ts
import { someMiddleware } from '../middleware/someMiddleware'
import { someOtherMiddleware } from '../middleware/someOtherMiddleware'
// middleware would be ran in the order declared here
exports default [ someMiddleware, someOtherMiddleware ]
This would make it unnecessary to have to redeclare the middleware pipeline for each route, or manually create a Hono router just to gain access to the use
method.
Directory structure would look like:
.
└── app/
└── routes/
├── some-path/
│ ├── uses-middleware/
│ │ └── index.ts <--uses _middleware
│ ├── _middleware.ts
│ └── index.ts <--uses _middleware
└── index.ts
(update) Does not work even with the steps written in the README , there is no client bundles!
Currently, @hono/vite-ssg
and honox/vite/client
combination cannot work in naive way.
vite build --mode client && vite build
results the latter build cleanups the former.vite build
. A generated client script referenced by Script
component cannot resolve by Vite.// vite.config.ts
import honox from "honox/vite";
import client from "honox/vite/client";
import { defineConfig } from "vite";
import ssg from "@hono/vite-ssg";
const entry = "./app/server.ts";
export default defineConfig(({ mode, command }) => {
const plugins =
mode === "client"
? [client()]
: [honox(), ssg({ entry })];
return {
build: {
rollupOptions: {
input: ["./app/style.css"],
output: {
assetFileNames: "static/assets/[name].[ext]",
},
}
},
plugins,
};
});
Error: [vite]: Rollup failed to resolve import "/static/client-qvhPWvF1.js" from "(repo-root)/.hono/index.html".
This is most likely unintended because it can break your application at runtime.
If you do want to externalize this module explicitly add it to
`build.rollupOptions.external`
at viteWarn (file://(repo-root)/node_modules/vite/dist/node/chunks/dep-94_H5fT6.js:67040:27)
at onRollupWarning (file://(repo-root)/node_modules/vite/dist/node/chunks/dep-94_H5fT6.js:67068:9)
at onwarn (file://(repo-root)/node_modules/vite/dist/node/chunks/dep-94_H5fT6.js:66777:13)
at file://(repo-root)/node_modules/rollup/dist/es/shared/node-entry.js:17457:13
at Object.logger [as onLog] (file://(repo-root)/node_modules/rollup/dist/es/shared/node-entry.js:19117:9)
at ModuleLoader.handleInvalidResolvedId (file://(repo-root)/node_modules/rollup/dist/es/shared/node-entry.js:18061:26)
at file://(repo-root)/node_modules/rollup/dist/es/shared/node-entry.js:18019:26
error: script "build" exited with code 1
Use of build.rollupOptions.external
does not work. A generated script element will be removed in a generated HTML.
WORKAROUND for 1: Write a custom plugin that build.emptyOutDir set to false.
This derives from build.emptyOutDir set to true by @hono/vite-ssg .
WORKAROUND for 2: Use resolve.alias.
// vite.config.ts
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import honox from "honox/vite";
import client from "honox/vite/client";
import { defineConfig } from "vite";
import ssg from "@hono/vite-ssg";
const entry = "./app/server.ts";
export default defineConfig(({ mode, command }) => {
const plugins =
mode === "client"
? [client()]
: [
honox({ entry }),
ssg({ entry }),
{
config() {
return { build: { emptyOutDir: false } };
},
},
];
return {
build: {
rollupOptions: {
input: ["./app/style.css"],
output: {
assetFileNames: "static/assets/[name].[ext]",
},
}
},
plugins,
resolve: {
alias: [
{
find: /^\/static\/(.*?)\.js/,
replacement: resolve(
// Node 18 support, for 20 or upper, `import.meta.dirname` also works
dirname(fileURLToPath(import.meta.url)),
"dist/static/$1.js"
),
},
],
},
};
});
0.1.3 / Hono: 4.0.3
npm install && npm run dev
.The UI
The issue occurs with a very specific condition.
hasLabel
in the code)str
) is NOT rendered in a sibling element of the input element. (form.tsx
vs form2.tsx
)The input cursor stays in the input element so that you can type more than one character at a time.
The input cursor gets kicked out, hence, you can only type one character at a time. You need to click on the input element every time you type in it.
No response
Hi there! Really loving honox!
I'm experimenting with using it as a react renderer and am running into issues with islands sharing context or state. Specifically I'm trying to wrap some islands that use react query with a parent island that sets the query client context.
Should this be possible or am I misunderstanding now islands should behave?
Thanks so much!
Note
You can ignore if you can not get this issue clearly.
I understand this honox project is alpha version.
I need type suggestion for path parameter(c.req.param()
) in createRoute.
0.1.0
create a new project via pnpm create@hono and x-basic
add a directory structure with 2 dynamic path parameters (app/routes/companies/[companyId]/[postId]/index.ts)
When I type c.req.param('
then the VSCode(TS Server) suggest 'companyId' and 'postId'
When I type c.req.param('
then the VSCode(TS Server) suggest nothing
example code
app/routes/companies/[companyId]/[postId]/index.ts
import { zValidator } from '@hono/zod-validator'
import { createRoute } from 'honox/factory'
import { object, string } from 'zod'
const paramsSchema = object({
companyId: string(),
postId: string(),
})
// before route.get('companies/:companyId/:postId',async (c) => {
// try const GET = createRoute<{ in: { param: ParamSchema } }>(async (c) => {
const GET = createRoute(zValidator('param', paramsSchema), async (c) => {
// no suggestion for 'companyId' because param<any>(key: string) is any Generics
const companyId = c.req.param('companyId')
const postId = c.req.param('postId')
return c.json({})
})
// biome-ignore lint/style/noDefaultExport: Router specification
export default GET
// type
const GET: [H<Env, any, {
in: {
param: {
companyId: string;
postId: string;
};
};
out: {
param: {
companyId: string;
postId: string;
};
};
}, Promise<Response & TypedResponse<...>>>, H<...>]
0.1.1
npx create hono@latest
, select "x-basic"
createRoute
and use disableSSG
from "hono/ssg"
build.ts
that runs https://github.com/honojs/vite-plugins/blob/55e3abfb8017c7ee9606458da665e3f09e0d428f/packages/ssg/src/ssg.ts#L34-L50 , or use "@hono/vite-ssg"Not even a text file containing "SSG is disabled" is left behind, and nothing is generated from the disableSSG
route.
Text files that contains "SSG is disabled"
This is runtime agnostic issue. Reproduced in Node v21.6.0, Bun 1.0.23, Deno 1.39.4
I looked through the documentation and I did not see anywhere documenting how to use ENVs. I checked VITE and saw that I can use ENV by creating an .env
file and adding the VITE_
prefix to the env name. Sample VITE_HELLO=WORLD
.
Is this the best way or is there another?
Thank you for developing a great framework!
Currently, I am developing using Honox. I've set the routes directory to src/app/routes
, and to accommodate this, I made the following changes in src/app/server.ts:
const app = createApp({
root: "/src/app/routes",
RENDERER: import.meta.glob("/src/app/routes/**/_renderer.tsx", {
eager: true,
}),
ROUTES: import.meta.glob("/src/app/routes/**/[!_]*.(ts|tsx|mdx)", {
eager: true,
}),
});
Even though root is set, I found it inconvenient that changes to RENDERER
and ROUTES
are required for pages to reflect.
Upon inspecting the source code, I noticed that all four strings ROUTES
, RENDERER
, NOT_FOUND
, and ERROR
contain /app/routes
. Therefore, if root is set in the config, how about we automatically insert root into these parts unless there's specific config for ROUTES
, RENDERER
, NOT_FOUND
, and ERROR
?
For example, for NOT_FOUND_FILE
:
const NOT_FOUND_FILE =
options?.NOT_FOUND ??
import.meta.glob<NotFoundFile>(`${root}/**/_404.(ts|tsx)`, {
eager: true,
})
Not sure if this goes here or over at Vite, since the problem stems from their side. See the following discussion post I made over there:
I wasn't sure if it was possible to alter the globbing pattern or add an additional one from the context of this plugin to additionally add those hidden/dot files back in.
I don't know how flexible fast-glob
is, but could something similar to this work?
https://askubuntu.com/a/1452417
One work-around here is to just create a Hono router in the directory and manually create the path (avoiding using directories), so there is a path forward if this cannot be fixed at this level.
Great work on this regardless!
0.1.3
Clone the examples repository https://github.com/yusukebe/honox-examples/tree/main/projects/blog
cd to projects/blog
run npx wrangler d1 execute hono-blog-demo --local --file=./blog.sql
run yarn dev
Local DB is created and when you launch the app it works with seeded db from blog.sql
D1_ERROR: no such table: articles
the local db is being created in .wrangler, the vite dev plugin is looking in .mf
If you run build and then wrangler pages dev ./dist
this works, as the wrangler command shims the database in .wrangler and is available to honox
It seems there needs to be something tweaked with the miniflare setup to pickup local d1 correctly
This is like a note for the development of HonoX. It will be edited.
patch
0.1.0
Follow the example below to set up react and run npm run dev
.
https://github.com/honojs/honox?tab=readme-ov-file#byor---bring-your-own-renderer
no error
[vite] Internal server error: module is not defined
at eval (/.../node_modules/react/jsx-dev-runtime.js:8:3)
at instantiateModule (file:///.../node_modules/vite/dist/node/chunks/dep-stQc5rCc.js:54696:15)
The following changes were made to avoid this
diff --git a/src/vite/index.ts b/src/vite/index.ts
index 2318e86..e9bd409 100644
--- a/src/vite/index.ts
+++ b/src/vite/index.ts
@@ -47,7 +47,7 @@ function honox(options?: Options): PluginOption[] {
config: () => {
return {
ssr: {
- noExternal: true,
+ noExternal: ['honox'],
},
}
},
This is like a bug.
The dev server does not restart/reload the app when adding/removing a route file. This is a @hono/vite-dev-server matter. I have some ideas to resolve this issue, but these are not super smart ways. Anyway, I'll add a change as like work-around.
create-hono version 0.4.0
I've tried creating a x-basic hono app with Deno, yarn and npm but I still get the same error. I'd run npm create hono@latest
or yarn create hono my-app
or deno run -A npm:create-hono my-app
Create an x-basic starter file like this
├── app
│ ├── global.d.ts // global type definitions
│ ├── routes
│ │ ├── _404.tsx // not found page
│ │ ├── _error.tsx // error page
│ │ ├── _renderer.tsx // renderer definition
│ │ ├── about
│ │ │ └── [name].tsx // matches /about/:name
│ │ └── index.tsx // matches /
│ └── server.ts // server entry file
├── package.json
├── tsconfig.json
└── vite.config.ts
`C:\Users\fredr\AppData\Local\npm-cache_npx\6bbb1d6f54609fb5\node_modules\create-hono\bin:9918
this[_onError](new ZlibError(err));
^
ZlibError: zlib: unexpected end of file
at Unzip.write (C:\Users\fredr\AppData\Local\npm-cache_npx\6bbb1d6f54609fb5\node_modules\create-hono\bin:9918:26)
at Unzip.flush (C:\Users\fredr\AppData\Local\npm-cache_npx\6bbb1d6f54609fb5\node_modules\create-hono\bin:9883:14)
at Unzip.end (C:\Users\fredr\AppData\Local\npm-cache_npx\6bbb1d6f54609fb5\node_modules\create-hono\bin:9888:14)
at Unpack.end (C:\Users\fredr\AppData\Local\npm-cache_npx\6bbb1d6f54609fb5\node_modules\create-hono\bin:12740:25)
at Pipe.end (C:\Users\fredr\AppData\Local\npm-cache_npx\6bbb1d6f54609fb5\node_modules\create-hono\bin:9338:21)
at [emitEnd2] (C:\Users\fredr\AppData\Local\npm-cache_npx\6bbb1d6f54609fb5\node_modules\create-hono\bin:9699:13)
at [emitEnd] (C:\Users\fredr\AppData\Local\npm-cache_npx\6bbb1d6f54609fb5\node_modules\create-hono\bin:9686:25)
at ReadStream.emit (C:\Users\fredr\AppData\Local\npm-cache_npx\6bbb1d6f54609fb5\node_modules\create-hono\bin:9643:31)
at ReadStream.emit (C:\Users\fredr\AppData\Local\npm-cache_npx\6bbb1d6f54609fb5\node_modules\create-hono\bin:12103:26)
at [maybeEmitEnd] (C:\Users\fredr\AppData\Local\npm-cache_npx\6bbb1d6f54609fb5\node_modules\create-hono\bin:9629:16) {
code: 'Z_BUF_ERROR',
errno: -5,
recoverable: false,
file: 'C:\Users\fredr\.degit\github\honojs\starter/cb09fdcd58830a1ef005be1e418a0f235c9e69d3.tar.gz',
cwd: 'C:/Users/fredr/OneDrive/Desktop/WORKSPACE/Honox/my-app',
tarCode: 'TAR_ABORT'
}
Node.js v20.9.0
npm ERR! code 1
npm ERR! path C:\Users\fredr\OneDrive\Desktop\WORKSPACE\Honox
npm ERR! command failed
npm ERR! command C:\WINDOWS\system32\cmd.exe /d /s /c create-hono my-app`
Node version - 20.9.0
OS - Windows 10 pro Build 19045
I'm trying to get a basic example of file-based routing working. The README provides a basic vite.config.ts
file, but it doesn't describe the changes needed in package.json
to use Vite. I tried changing the "dev" script to just run "vite". But when I run that script with bun dev
I get the following error:
Error: Cannot find module @rollup/rollup-darwin-x64. npm has a bug related to optional dependencies (https://github.com/npm/cli/issues/4828). Please try `npm i` again after removing both package-lock.json and node_modules directory.
Doing what it suggests didn't fix the error for me. I'm running in macOS.
requires honojs/hono#2162
Import jsx from "hono/jsx/dom/jsx-runtime" to reduce the client size.
createElement
Since different versions of jsx transformer have different arguments, it is difficult to define the type, but since honox does not currently use either children or keys, I think we can just assume that there are two arguments.
I can't make a PR because I can't fork, so I'll just put up a patch for now.
diff --git a/README.md b/README.md
index ff646d9..827aab6 100644
--- a/README.md
+++ b/README.md
@@ -403,9 +403,9 @@ createClient({
const { hydrateRoot } = await import('react-dom/client')
hydrateRoot(root, elem)
},
- createElement: async (type: any, props: any, ...children: any[]) => {
+ createElement: async (type: any, props: any) => {
const { createElement } = await import('react')
- return createElement(type, props, ...children)
+ return createElement(type, props)
},
})
diff --git a/src/client/client.ts b/src/client/client.ts
index 3d11cda..810d0c3 100644
--- a/src/client/client.ts
+++ b/src/client/client.ts
@@ -1,5 +1,5 @@
-import { jsx as jsxFn } from 'hono/jsx'
import { render } from 'hono/jsx/dom'
+import { jsx as jsxFn } from 'hono/jsx/dom/jsx-runtime'
import { COMPONENT_NAME, DATA_SERIALIZED_PROPS } from '../constants.js'
import type { CreateElement, Hydrate } from '../types.js'
diff --git a/src/types.ts b/src/types.ts
index 214acb5..1149d51 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/** JSX */
-export type CreateElement = (type: any, props: any, ...children: any[]) => Node | Promise<Node>
+export type CreateElement = (type: any, props: any) => Node | Promise<Node>
export type Hydrate = (children: Node, parent: Element) => void | Promise<void>
0.1.0
npm create@hono
and x-basic
I would expect any number of dynamic path parameters to work correctly
Hono crashes
[vite] Internal server error: Invalid regular expression: /^/:arg1]/[arg2(?:|/.*)$/: Unterminated character class
In either case (and possibly more) declaring more than one dynamic path parameter causes an error.
// double nested directories
.
└── app/
└── routes/
├── [arg1]/
│ └── [arg2]/
│ └── index.tsx
└── index.ts
// nested directory with dynamic path on the file
.
└── app/
└── routes/
├── [arg1]/
│ └── [arg2].tsx
└── index.ts
The issue can be worked around by exporting a Hono router and manually writing the paths
Using the x-basic
template and running npm run build
followed by npm run preview
result in an error. Inspection of the dist/_worker.js
file shows that none of the JSX is present within it (search for div
, etc).
The current readme is getting pretty long. Can we get a formal documentation repo (similar to Hono) to start moving some of this stuff over?
Or perhaps add a section to the Hono docs specifically for HonoX.
0.1.5
react
and react-dom
to vite config on ssr.external
npm run build
npm run preview
Client component should be found and work
GET /static/client.js net::ERR_ABORTED 404 (Not Found)
Repo to reproduce: https://github.com/iamyuu/play-honox-react
npm create hono@latest
x-basic
server.ts
to include some middleware://app/server.ts
import { cors } from 'hono/cors';
import { createApp } from 'honox/server';
import { poweredBy } from 'hono/powered-by';
import { secureHeaders } from 'hono/secure-headers';
import { showRoutes } from 'hono/dev';
import { timing } from 'hono/timing';
const app = createApp();
app.use(
cors(),
secureHeaders(),
timing(),
poweredBy(),
(ctx, next) => {
console.log('middleware!');
return next();
}
);
showRoutes(app);
export default app;
Upon running, none of the middleware seems to be working. None of the response headers are altered per the middleware. This can also be verified because the middleware!
text is never logged to the output.
I'm hitting a wall trying to make my server do the stuff I need it to do with packages that are written in commonjs using require.
I'm not super familiar with vite's bundling process so there's little I can investigate here.
The error I'm getting is:
[vite] Internal server error: require is not defined
Current HasIsland
component only detects islands in a route file.
If in a non-route component could detect using island, it could be something similar to "use client" in React.
We often want to use components with interactions at the end of the tree. It's not something we can immediately judge based on the route.
0.1.4
I attempted to set up the React renderer as described in the README, but encountered a type error.
Write ./app/client.ts
.
import { createClient } from "honox/client";
createClient({
hydrate: async (elem, root) => {
const { hydrateRoot } = await import("react-dom/client");
hydrateRoot(root, elem);
},
createElement: async (type: any, props: any) => {
const { createElement } = await import("react");
return createElement(type, props);
},
});
hydrateRoot(root, elem);
Argument of type 'Node' is not assignable to parameter of type 'ReactNode'.
createElement
Type '(type: any, props: any) => Promise<React.CElement<any, React.Component<any, any, any>>>' is not assignable to type 'CreateElement'.
Type 'Promise<CElement<any, Component<any, any, any>>>' is not assignable to type 'Node | Promise<Node>'.
Type 'Promise<CElement<any, Component<any, any, any>>>' is not assignable to type 'Promise<Node>'.
Type 'ComponentElement<any, Component<any, any, any>>' is missing the following properties from type 'Node': baseURI, childNodes, firstChild, isConnected, and 46 more.
I expect that no type errors will occur.
No response
It seems the same issue occurs at https://github.com/yusukebe/honox-playground/tree/main/projects/react.
If necessary, I can create a minimal sandbox to reproduce the issue.
Related to sonikjs/sonik#19
Current islands component can not render children
in the client side.
If we were achieve this, it means we have "Donut Components" pattern.
One of the reasons is that the child is not passed in this part, but in addition to this, it seems necessary to modify the hydrate process when an island exists within an island.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.