-
Notifications
You must be signed in to change notification settings - Fork 34
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(cloudflare-pages): generate _routes.json
#121
Conversation
🦋 Changeset detectedLatest commit: 84b90c4 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Hey @yudai-nkt, @nakasyou, @ryuapp! I've created this PR to resolve both #110 and #116. With this PR, static file paths will automatically be added to I think this is great. Can you review it? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
basically LGTM but left one minor nitpicking. thanks for tackling this!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi, @yusukebe
Thank you for nice PR!
I would like to leave just a few comments.
staticRoutes = { | ||
version: 1, | ||
include: ['/*'], | ||
exclude: staticPaths, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This approach is fine for minimal projects, but we can't use no more than 100 include/exclude rules combined.
https://developers.cloudflare.com/pages/functions/routing/#limits
It will be required to optimized in the future.
Of course, we can set routesJson
to false
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This approach is fine for minimal projects, but we can't use no more than 100 include/exclude rules combined.
You are right. One of the best practices is to create a directory like /static
on the top level because it will be written as /static/*
. We can write about it on README.
|
||
return { | ||
name: '@hono/vite-cloudflare-pages', | ||
configResolved: async (resolvedConfig) => { | ||
config = resolvedConfig | ||
const paths = await readdir(config.publicDir, { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const paths = await readdir(config.publicDir, { | |
const paths = await readdir(config.build.outDir, { |
I tried this plugin on local and found a bug.
JS and CSS files generated by vite are not included in exclude
, so they can't be loaded.
We need to look at an output directory.
PS: This may not be enough and you may need to check after all files have been built.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch! (in my prototype implementation mentioned above, Vite only generated server-side bundle so publicDir
was enough)
IIUC, build.outDir
will be empty on the configResolved
hook of the initial vite build
run, so I suppose readdir
should be called in later hooks like writeBundle
. Correct me if I'm wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@yudai-nkt
You are right!
Calling readdir
on the writeBundle
hook works by excluding _worker.js
.
Codes I tried
return {
name: "@hono/vite-cloudflare-pages",
configResolved: async (resolvedConfig) => {
config = resolvedConfig;
- const paths = await readdir(config.publicDir, {
- withFileTypes: true
- });
- paths.forEach((p) => {
- if (p.isDirectory()) {
- staticPaths.push(`/${p.name}/*`);
- } else if (p.name !== "_worker.js") {
- staticPaths.push(`/${p.name}`);
- }
});
},
resolveId(id) {
if (id === virtualEntryId) {
return resolvedVirtualEntryId;
}
},
async load(id) {
if (id === resolvedVirtualEntryId) {
return await getEntryContent({
entry: options?.entry ? Array.isArray(options.entry) ? options.entry : [options.entry] : [...defaultOptions.entry],
staticPaths
});
}
},
writeBundle: async () => {
+ const paths = await readdir(config.build.outDir, {
+ withFileTypes: true
+ });
+ paths.forEach((p) => {
+ if (p.isDirectory()) {
+ staticPaths.push(`/${p.name}/*`);
+ } else if (p.name !== "_worker.js") {
+ staticPaths.push(`/${p.name}`);
+ }
+ });
staticRoutes = {
version: 1,
include: ["/*"],
exclude: staticPaths
};
However, HonoX generate .vite/manifest.json
in out dir.
If it's static build, shouldn't it be output?
I think this needs to be fixed in HonoX.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As you said, you should specify config.build.outDir
if you built the JS or CSS files before build server-side with this plugin. But, if you did not build some front files before executing this, the config.build.outDir
does not exist, and it should be a different directory, e.g., public
So, I've created the serveStaticDir
option:
The default value is config.build.outDir
, but the user can specify it themselves. This is good. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIUC,
build.outDir
will be empty on theconfigResolved
hook of the initialvite build
run, so I supposereaddir
should be called in later hooks likewriteBundle.
Correct me if I'm wrong.
Indeed, it will be empty. But, this plugin for server-side. If we use it with client-side files, e.g., JS or CSS, we should build it in a separate build phase like the below:
vite build --mode client && vite build"
So, if we build client things first, config.build.outDir
exists, and we don't have to write readdir
in writeBundle
. And if we call readdir
in writeBundle
, the test will fail because the staticPaths
are empty when getEntryContent
is executed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It appears that the css imported from 3d09e1c is no longer being loaded.
I'm trying with vite-plugin
branch of the following repository:
https://github.com/ryuapp/honox-tailwind-template/tree/vite-plugin
"now"
{"version":1,"include":["/*"],"exclude":["/.vite/*","/humans.txt","/static/*"]}
"ideal"
{"version":1,"include":["/*"],"exclude":["/.vite/*","/humans.txt","/static/*","/style-BMTRAcdn.css"]}
As you said, you should specify config.build.outDir if you built the JS or CSS files before build server-side with this plugin. But, if you did not build some front files before executing this, the config.build.outDir does not exist, and it should be a different directory, e.g., public So, I've created the serveStaticDir option:
The default value is config.build.outDir, but the user can specify it themselves. This is good. What do you think?
I'm sorry I didn't explain it well.
What I have a problem with is just .vite/manifest.json
in an output directory.
However, I had misunderstood manifest.json
; thus that was not an issue to discuss here...
Regarding the option, I don't think it' necessary.
This is because creating _routes.json
from config.build.outDir is simpler and easier to understand.
If we want to handle _routes.json
freely, I think that if we have _routes.json
in public, we should give priority to that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for your explanation! Understood well.
I've added the change: 84b90c4
- Move
readdir
intowriteBundle
. - Remove
serveStaticDir
androutesJson
options. - Use
config.build.outDir
. - Don't write
serveStatic
code on_worker.js
.
The point is that it does not add serveStatic
on _worker.js
and should generate _routes.json
. The serverStatic
is not necessary if it has _routes.json
, and it will be simpler rather than if both are set.
What do you think of this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@yusukebe
Great! This PR works well in my project :)
I agree with all your opinions. I have no more questions.
Thank you very much for your great work!
Sorry for being super late. I've updated it. Could you review this? |
_routes.json
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM🎈
Thank you! I'll merge this now. Let's go with it! |
Fixes #110, #116
With this PR, the Vite plugin detects static files in the
public
directory and adds paths forserveStatic()
inworker.js
. And, this will emit_routes.json
as a default.The function that detects static files automatically is heavily inspired by @yudai-nkt 's https://github.com/yudai-nkt/awesome-hono/blob/main/vite-plugins/auto-exclude-static-routes.ts. I'll make @yudai-nkt a co-author.