From 1ceb95757f1151e9f08cebd992447fb67b470957 Mon Sep 17 00:00:00 2001 From: Yusuke Wada Date: Sun, 15 Sep 2024 10:07:35 +0900 Subject: [PATCH] feat: `@hono/vite-build` (#177) * feat: `@hono/vite-build` * `statiRoot` * add adapters * update * tweak * remove not used files * vitest/globals * update readme * add changeset * add CI * look dist dir * update gitignore * update readme * make it as `major` release --- .changeset/honest-adults-complain.md | 5 + .github/workflows/ci-build.yml | 38 ++ packages/build/README.md | 221 ++++++++ packages/build/package.json | 85 +++ packages/build/src/adapter/bun/index.ts | 32 ++ .../src/adapter/cloudflare-pages/index.ts | 61 ++ .../src/adapter/cloudflare-workers/index.ts | 16 + packages/build/src/adapter/node/index.ts | 40 ++ packages/build/src/base.ts | 127 +++++ packages/build/src/entry/index.ts | 75 +++ packages/build/src/entry/serve-static.ts | 12 + packages/build/src/index.ts | 5 + packages/build/test/.gitignore | 1 + packages/build/test/basic.test.ts | 30 + packages/build/test/bun.test.ts | 39 ++ packages/build/test/cloudflare-pages.test.ts | 85 +++ .../public-routes-json/_routes.json | 1 + .../mocks/app-static-files/public/foo.txt | 1 + .../app-static-files/public/js/client.js | 1 + .../test/mocks/app-static-files/src/server.ts | 7 + packages/build/test/mocks/app/src/server.ts | 7 + packages/build/tsconfig.build.json | 12 + packages/build/tsconfig.json | 15 + packages/build/tsup.config.ts | 17 + packages/build/vitest.config.ts | 7 + packages/dev-server/package.json | 2 +- yarn.lock | 526 +++++++++++++++++- 27 files changed, 1465 insertions(+), 3 deletions(-) create mode 100644 .changeset/honest-adults-complain.md create mode 100644 .github/workflows/ci-build.yml create mode 100644 packages/build/README.md create mode 100644 packages/build/package.json create mode 100644 packages/build/src/adapter/bun/index.ts create mode 100644 packages/build/src/adapter/cloudflare-pages/index.ts create mode 100644 packages/build/src/adapter/cloudflare-workers/index.ts create mode 100644 packages/build/src/adapter/node/index.ts create mode 100644 packages/build/src/base.ts create mode 100644 packages/build/src/entry/index.ts create mode 100644 packages/build/src/entry/serve-static.ts create mode 100644 packages/build/src/index.ts create mode 100644 packages/build/test/.gitignore create mode 100644 packages/build/test/basic.test.ts create mode 100644 packages/build/test/bun.test.ts create mode 100644 packages/build/test/cloudflare-pages.test.ts create mode 100644 packages/build/test/mocks/app-static-files/public-routes-json/_routes.json create mode 100644 packages/build/test/mocks/app-static-files/public/foo.txt create mode 100644 packages/build/test/mocks/app-static-files/public/js/client.js create mode 100644 packages/build/test/mocks/app-static-files/src/server.ts create mode 100644 packages/build/test/mocks/app/src/server.ts create mode 100644 packages/build/tsconfig.build.json create mode 100644 packages/build/tsconfig.json create mode 100644 packages/build/tsup.config.ts create mode 100644 packages/build/vitest.config.ts diff --git a/.changeset/honest-adults-complain.md b/.changeset/honest-adults-complain.md new file mode 100644 index 0000000..3edb317 --- /dev/null +++ b/.changeset/honest-adults-complain.md @@ -0,0 +1,5 @@ +--- +'@hono/vite-build': major +--- + +Initial release diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml new file mode 100644 index 0000000..4ec8514 --- /dev/null +++ b/.github/workflows/ci-build.yml @@ -0,0 +1,38 @@ +name: ci-build +on: + push: + branches: [main] + paths: + - 'packages/build/**' + pull_request: + branches: ['*'] + paths: + - 'packages/build/**' + +jobs: + ci: + runs-on: ubuntu-latest + defaults: + run: + working-directory: ./packages/build + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20.x + - run: yarn install + - run: yarn build + - run: yarn test + + ci-windows: + runs-on: windows-latest + defaults: + run: + working-directory: ./packages/build + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20.x + - run: yarn install + - run: yarn test diff --git a/packages/build/README.md b/packages/build/README.md new file mode 100644 index 0000000..d8c69a3 --- /dev/null +++ b/packages/build/README.md @@ -0,0 +1,221 @@ +# @hono/vite-build + +`@hono/vite-build` is a set of Vite plugins for building Hono applications with Vite. It supports multiple runtimes and platforms, allowing you to build a project that includes JavaScript files for these platforms from a Hono app. + +Here are the modules included: + +- `@hono/vite-build/base` +- `@hono/vite-build/cloudflare-pages` +- `@hono/vite-build/cloudflare-workers` +- `@hono/vite-build/bun` +- `@hono/vite-build/node` + +## Usage + +### Install + +You can install `vite` and `@hono/vite-build` via the npm. + +```bash +npm i -D vite @hono/vite-build +``` + +Or you can install them with Bun. + +```bash +bun add -D vite @hono/vite-build +``` + +### Settings + +Add `"type": "module"` to your package.json. Then, create `vite.config.ts` and edit it. The following is for Bun. + +```ts +import { defineConfig } from 'vite' +import build from '@hono/vite-build/bun' +// import build from '@hono/vite-build/cloudflare-pages' +// import build from '@hono/vite-build/cloudflare-workers' +// import build from '@hono/vite-build/node' + +export default defineConfig({ + plugins: [ + build({ + // Defaults are `src/index.ts`,`./src/index.tsx`,`./app/server.ts` + entry: './src/index.tsx', + }), + ], +}) +``` + +### Build + +Just run `vite build`. + +```bash +npm exec vite build +``` + +Or + +```bash +bunx --bun vite build +``` + +### Run + +Run with the command on your runtime. For examples: + +Cloudflare Pages: + +```bash +wrangler pages dev ./dist +``` + +Bun: + +```bash +cd ./dist +bun run ./index.js +``` + +Node.js: + +```bash +cd ./dist +node ./index.js +``` + +## Common Options + +```ts +type BuildOptions = { + entry?: string | string[] + output?: string + outputDir?: string + external?: string[] + minify?: boolean + emptyOutDir?: boolean +} +``` + +Default values: + +```ts +export const defaultOptions = { + entry: ['src/index.ts', './src/index.tsx', './app/server.ts'], + output: 'index.js', + outputDir: './dist', + external: [], + minify: true, + emptyOutDir: false, + staticPaths: [], +} +``` + +## Platform specific things + +### Cloudflare Pages + +This plugin generates `_routes.json` automatically. The automatic generation can be overridden by creating a `public/_routes.json`. See [Create a `_routes.json` file](https://developers.cloudflare.com/pages/functions/routing/#create-a-_routesjson-file) on Cloudflare Docs for more details. + +## Example project + +`src/index.tsx`: + +```tsx +import { Hono } from 'hono' + +const app = new Hono() + +app.get('/', (c) => { + return c.html( + + + + + +

Hello!

+ + + ) +}) + +export default app +``` + +`public/static/style.css`: + +```css +h1 { + font-family: Arial, Helvetica, sans-serif; +} +``` + +The project with those file will be built to the following files with `@hono/vite-build/bun`: + +```txt +dist +├── index.js +└── static + └── style.css +``` + +## Build a client + +If you also want to build a client-side script, you can configure it as follows. + +```ts +export default defineConfig(({ mode }) => { + if (mode === 'client') { + return { + build: { + rollupOptions: { + input: './src/client.ts', + output: { + dir: './dist/static', + entryFileNames: 'client.js', + }, + }, + copyPublicDir: false, + }, + } + } else { + return { + plugins: [build()], + } + } +}) +``` + +The build command: + +```bash +vite build --mode client && vite build +``` + +`import.meta.env.PROD` is helpful in detecting whether it is in development or production mode if you are using it on a Vite dev server. + +```tsx +app.get('/', (c) => { + return c.html( + + + {import.meta.env.PROD ? ( + + ) : ( + + )} + + Hello! + + ) +}) +``` + +## Authors + +- Yusuke Wada + +## License + +MIT diff --git a/packages/build/package.json b/packages/build/package.json new file mode 100644 index 0000000..ded32a1 --- /dev/null +++ b/packages/build/package.json @@ -0,0 +1,85 @@ +{ + "name": "@hono/vite-build", + "description": "Vite plugin to build your Hono app", + "version": "0.0.0", + "types": "dist/index.d.ts", + "module": "dist/index.js", + "type": "module", + "scripts": { + "test": "vitest --run", + "build": "rimraf dist && tsup && publint", + "watch": "tsup --watch", + "prerelease": "yarn build", + "release": "yarn publish" + }, + "files": [ + "dist" + ], + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js" + }, + "./bun": { + "types": "./dist/adapter/bun/index.d.ts", + "import": "./dist/adapter/bun/index.js" + }, + "./node": { + "types": "./dist/adapter/node/index.d.ts", + "import": "./dist/adapter/node/index.js" + }, + "./cloudflare-pages": { + "types": "./dist/adapter/cloudflare-pages/index.d.ts", + "import": "./dist/adapter/cloudflare-pages/index.js" + }, + "./cloudflare-workers": { + "types": "./dist/adapter/cloudflare-workers/index.d.ts", + "import": "./dist/adapter/cloudflare-workers/index.js" + } + }, + "typesVersions": { + "*": { + "types": [ + "./dist/types" + ], + "bun": [ + "./dist/adapter/bun/index.d.ts" + ], + "node": [ + "./dist/adapter/node/index.d.ts" + ], + "cloudflare-pages": [ + "./dist/adapter/cloudflare-pages/index.d.ts" + ], + "cloudflare-workers": [ + "./dist/adapter/cloudflare-workers/index.d.ts" + ] + } + }, + "author": "Yusuke Wada (https://github.com/yusukebe)", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/honojs/vite-plugins.git" + }, + "publishConfig": { + "registry": "https://registry.npmjs.org", + "access": "public" + }, + "homepage": "https://github.com/honojs/vite-plugins", + "devDependencies": { + "glob": "^10.3.10", + "hono": "^4.6.1", + "publint": "^0.1.12", + "rimraf": "^5.0.1", + "tsup": "^7.2.0", + "vite": "^5.4.5", + "vitest": "^2.1.1" + }, + "peerDependencies": { + "hono": "*" + }, + "engines": { + "node": ">=18.14.1" + } +} diff --git a/packages/build/src/adapter/bun/index.ts b/packages/build/src/adapter/bun/index.ts new file mode 100644 index 0000000..0562558 --- /dev/null +++ b/packages/build/src/adapter/bun/index.ts @@ -0,0 +1,32 @@ +import type { Plugin } from 'vite' +import type { BuildOptions } from '../../base.js' +import buildPlugin from '../../base.js' +import { serveStaticHook } from '../../entry/serve-static.js' + +export type BunBuildOptions = { + staticRoot?: string | undefined +} & BuildOptions + +const bunBuildPlugin = (pluginOptions?: BunBuildOptions): Plugin => { + return { + ...buildPlugin({ + ...{ + entryContentBeforeHooks: [ + async (appName, options) => { + // eslint-disable-next-line quotes + let code = "import { serveStatic } from 'hono/bun'\n" + code += serveStaticHook(appName, { + filePaths: options?.staticPaths, + root: pluginOptions?.staticRoot, + }) + return code + }, + ], + }, + ...pluginOptions, + }), + name: '@hono/vite-build/bun', + } +} + +export default bunBuildPlugin diff --git a/packages/build/src/adapter/cloudflare-pages/index.ts b/packages/build/src/adapter/cloudflare-pages/index.ts new file mode 100644 index 0000000..d632019 --- /dev/null +++ b/packages/build/src/adapter/cloudflare-pages/index.ts @@ -0,0 +1,61 @@ +import { readdir, writeFile } from 'node:fs/promises' +import { resolve } from 'node:path' +import type { Plugin, ResolvedConfig } from 'vite' +import type { BuildOptions } from '../../base.js' +import buildPlugin, { defaultOptions } from '../../base.js' + +export type CloudflarePagesBuildOptions = BuildOptions + +const WORKER_JS_NAME = '_worker.js' +const ROUTES_JSON_NAME = '_routes.json' + +type StaticRoutes = { version: number; include: string[]; exclude: string[] } + +const cloudflarePagesBuildPlugin = (pluginOptions?: CloudflarePagesBuildOptions): Plugin => { + let config: ResolvedConfig + const staticPaths: string[] = [] + + return { + ...buildPlugin({ + ...pluginOptions, + output: WORKER_JS_NAME, + }), + configResolved: async (resolvedConfig) => { + config = resolvedConfig + }, + writeBundle: async () => { + const paths = await readdir(resolve(config.root, config.build.outDir), { + withFileTypes: true, + }) + // If _routes.json already exists, don't create it + if (paths.some((p) => p.name === ROUTES_JSON_NAME)) { + return + } else { + paths.forEach((p) => { + if (p.isDirectory()) { + staticPaths.push(`/${p.name}/*`) + } else { + if (p.name === WORKER_JS_NAME) { + return + } + staticPaths.push(`/${p.name}`) + } + }) + const staticRoutes: StaticRoutes = { + version: 1, + include: ['/*'], + exclude: staticPaths, + } + const path = resolve( + config.root, + pluginOptions?.outputDir ?? defaultOptions.outputDir, + '_routes.json' + ) + await writeFile(path, JSON.stringify(staticRoutes)) + } + }, + name: '@hono/vite-build/cloudflare-pages', + } +} + +export default cloudflarePagesBuildPlugin diff --git a/packages/build/src/adapter/cloudflare-workers/index.ts b/packages/build/src/adapter/cloudflare-workers/index.ts new file mode 100644 index 0000000..fbce7c0 --- /dev/null +++ b/packages/build/src/adapter/cloudflare-workers/index.ts @@ -0,0 +1,16 @@ +import type { Plugin } from 'vite' +import type { BuildOptions } from '../../base.js' +import buildPlugin from '../../base.js' + +export type CloudflareWorkersBuildOptions = BuildOptions + +const cloudflareWorkersBuildPlugin = (pluginOptions?: CloudflareWorkersBuildOptions): Plugin => { + return { + ...buildPlugin({ + ...pluginOptions, + }), + name: '@hono/vite-build/cloudflare-workers', + } +} + +export default cloudflareWorkersBuildPlugin diff --git a/packages/build/src/adapter/node/index.ts b/packages/build/src/adapter/node/index.ts new file mode 100644 index 0000000..4c6b338 --- /dev/null +++ b/packages/build/src/adapter/node/index.ts @@ -0,0 +1,40 @@ +import type { Plugin } from 'vite' +import type { BuildOptions } from '../../base.js' +import buildPlugin from '../../base.js' +import { serveStaticHook } from '../../entry/serve-static.js' + +export type NodeBuildOptions = { + staticRoot?: string | undefined +} & BuildOptions + +const nodeBuildPlugin = (pluginOptions?: NodeBuildOptions): Plugin => { + return { + ...buildPlugin({ + ...{ + entryContentBeforeHooks: [ + async (appName, options) => { + // eslint-disable-next-line quotes + let code = "import { serveStatic } from '@hono/node-server/serve-static'\n" + code += serveStaticHook(appName, { + filePaths: options?.staticPaths, + root: pluginOptions?.staticRoot, + }) + return code + }, + ], + entryContentAfterHooks: [ + async (appName) => { + // eslint-disable-next-line quotes + let code = "import { serve } from '@hono/node-server'\n" + code += `serve(${appName})` + return code + }, + ], + }, + ...pluginOptions, + }), + name: '@hono/vite-build/node', + } +} + +export default nodeBuildPlugin diff --git a/packages/build/src/base.ts b/packages/build/src/base.ts new file mode 100644 index 0000000..5a51d99 --- /dev/null +++ b/packages/build/src/base.ts @@ -0,0 +1,127 @@ +import { builtinModules } from 'module' +import { readdirSync } from 'node:fs' +import path, { resolve } from 'node:path' +import type { ConfigEnv, Plugin, ResolvedConfig, UserConfig } from 'vite' +import { getEntryContent } from './entry/index.js' +import type { GetEntryContentOptions } from './entry/index.js' + +export type BuildOptions = { + /** + * @default ['src/index.ts', './src/index.tsx', './app/server.ts'] + */ + entry?: string | string[] + /** + * @default './dist' + */ + output?: string + outputDir?: string + external?: string[] + /** + * @default true + */ + minify?: boolean + emptyOutDir?: boolean + apply?: ((this: void, config: UserConfig, env: ConfigEnv) => boolean) | undefined +} & Omit + +export const defaultOptions: Required< + Omit +> = { + entry: ['src/index.ts', './src/index.tsx', './app/server.ts'], + output: 'index.js', + outputDir: './dist', + external: [], + minify: true, + emptyOutDir: false, + apply: (_config, { command, mode }) => { + if (command === 'build' && mode !== 'client') { + return true + } + return false + }, + staticPaths: [], +} + +const buildPlugin = (options: BuildOptions): Plugin => { + const virtualEntryId = 'virtual:build-entry-module' + const resolvedVirtualEntryId = '\0' + virtualEntryId + let config: ResolvedConfig + + const output = options.output ?? defaultOptions.output + + return { + name: '@hono/vite-build', + configResolved: async (resolvedConfig) => { + config = resolvedConfig + }, + resolveId(id) { + if (id === virtualEntryId) { + return resolvedVirtualEntryId + } + }, + async load(id) { + if (id === resolvedVirtualEntryId) { + let staticPaths: string[] = [] + const direntPaths = [] + try { + const publicDirPaths = readdirSync(resolve(config.root, config.publicDir), { + withFileTypes: true, + }) + direntPaths.push(...publicDirPaths) + const buildOutDirPaths = readdirSync(resolve(config.root, config.build.outDir), { + withFileTypes: true, + }) + direntPaths.push(...buildOutDirPaths) + } catch {} + + const uniqueStaticPaths = new Set() + + direntPaths.forEach((p) => { + if (p.isDirectory()) { + uniqueStaticPaths.add(`/${p.name}/*`) + } else { + if (p.name === output) { + return + } + uniqueStaticPaths.add(`/${p.name}`) + } + }) + + staticPaths = Array.from(uniqueStaticPaths) + + const entry = options.entry ?? defaultOptions.entry + return await getEntryContent({ + entry: Array.isArray(entry) ? entry : [entry], + entryContentBeforeHooks: options.entryContentBeforeHooks, + entryContentAfterHooks: options.entryContentAfterHooks, + staticPaths, + }) + } + }, + apply: options?.apply ?? defaultOptions.apply, + config: async (): Promise => { + return { + ssr: { + external: options?.external ?? defaultOptions.external, + noExternal: true, + target: 'webworker', + }, + build: { + outDir: options?.outputDir ?? defaultOptions.outputDir, + emptyOutDir: options?.emptyOutDir ?? defaultOptions.emptyOutDir, + minify: options?.minify ?? defaultOptions.minify, + ssr: true, + rollupOptions: { + external: [...builtinModules, /^node:/], + input: virtualEntryId, + output: { + entryFileNames: output, + }, + }, + }, + } + }, + } +} + +export default buildPlugin diff --git a/packages/build/src/entry/index.ts b/packages/build/src/entry/index.ts new file mode 100644 index 0000000..9103dae --- /dev/null +++ b/packages/build/src/entry/index.ts @@ -0,0 +1,75 @@ +import { normalize } from 'node:path' + +export type EntryContentHookOptions = { + staticPaths: string[] +} + +export type EntryContentHook = ( + appName: string, + options?: EntryContentHookOptions +) => string | Promise + +export type GetEntryContentOptions = { + entry: string[] + entryContentBeforeHooks?: EntryContentHook[] + entryContentAfterHooks?: EntryContentHook[] + staticPaths?: string[] +} + +const normalizePaths = (paths: string[]) => { + return paths.map((p) => { + let normalizedPath = normalize(p).replace(/\\/g, '/') + if (normalizedPath.startsWith('./')) { + normalizedPath = normalizedPath.substring(2) + } + return '/' + normalizedPath + }) +} + +export const getEntryContent = async (options: GetEntryContentOptions) => { + const staticPaths = options.staticPaths ?? [''] + const globStr = normalizePaths(options.entry) + .map((e) => `'${e}'`) + .join(',') + + const hooksToString = async (appName: string, hooks?: EntryContentHook[]) => { + if (hooks) { + const str = ( + await Promise.all( + hooks.map((hook) => { + return hook(appName, { + staticPaths, + }) + }) + ) + ).join('\n') + return str + } + return '' + } + + const appStr = `const modules = import.meta.glob([${globStr}], { import: 'default', eager: true }) + let added = false + for (const [, app] of Object.entries(modules)) { + if (app) { + mainApp.route('/', app) + mainApp.notFound(app.notFoundHandler) + added = true + } + } + if (!added) { + throw new Error("Can't import modules from [${globStr}]") + }` + + const mainAppStr = `import { Hono } from 'hono' +const mainApp = new Hono() + +${await hooksToString('mainApp', options.entryContentBeforeHooks)} + +${appStr} + +${await hooksToString('mainApp', options.entryContentAfterHooks)} + +export default mainApp` + return mainAppStr +} diff --git a/packages/build/src/entry/serve-static.ts b/packages/build/src/entry/serve-static.ts new file mode 100644 index 0000000..2de7fec --- /dev/null +++ b/packages/build/src/entry/serve-static.ts @@ -0,0 +1,12 @@ +type ServeStaticHookOptions = { + filePaths?: string[] + root?: string +} + +export const serveStaticHook = (appName: string, options: ServeStaticHookOptions) => { + let code = '' + for (const path of options.filePaths ?? []) { + code += `${appName}.use('${path}', serveStatic({ root: '${options.root ?? './'}' }))\n` + } + return code +} diff --git a/packages/build/src/index.ts b/packages/build/src/index.ts new file mode 100644 index 0000000..679d9d5 --- /dev/null +++ b/packages/build/src/index.ts @@ -0,0 +1,5 @@ +import { defaultOptions } from './base.js' +export { defaultOptions } + +import basePlugin from './base.js' +export default basePlugin diff --git a/packages/build/test/.gitignore b/packages/build/test/.gitignore new file mode 100644 index 0000000..21099fe --- /dev/null +++ b/packages/build/test/.gitignore @@ -0,0 +1 @@ +mocks/app-static-files/customDir \ No newline at end of file diff --git a/packages/build/test/basic.test.ts b/packages/build/test/basic.test.ts new file mode 100644 index 0000000..bdfd35e --- /dev/null +++ b/packages/build/test/basic.test.ts @@ -0,0 +1,30 @@ +import { existsSync, readFileSync, rmSync } from 'node:fs' +import { build } from 'vite' +import buildPlugin from '../src/base' + +describe('Base Plugin', () => { + const testDir = './test/mocks/app' + const entry = './src/server.ts' + + afterAll(() => { + rmSync(`${testDir}/dist`, { recursive: true, force: true }) + }) + + it('Should build the project correctly with the plugin', async () => { + const outputFile = `${testDir}/dist/index.js` + + await build({ + root: testDir, + plugins: [ + buildPlugin({ + entry, + }), + ], + }) + + expect(existsSync(outputFile)).toBe(true) + + const output = readFileSync(outputFile, 'utf-8') + expect(output).toContain('Hello World') + }) +}) diff --git a/packages/build/test/bun.test.ts b/packages/build/test/bun.test.ts new file mode 100644 index 0000000..415f634 --- /dev/null +++ b/packages/build/test/bun.test.ts @@ -0,0 +1,39 @@ +import { existsSync, readFileSync, rmSync } from 'node:fs' +import { build } from 'vite' +import bunBuildPlugin from '../src/adapter/bun' + +describe('Build Plugin with Bun Adapter', () => { + const testDir = './test/mocks/app-static-files' + const entry = './src/server.ts' + + afterAll(() => { + rmSync(`${testDir}/dist`, { recursive: true, force: true }) + }) + + it('Should build the project correctly with the plugin', async () => { + const outputFile = `${testDir}/dist/index.js` + + await build({ + root: testDir, + plugins: [ + bunBuildPlugin({ + entry, + }), + ], + }) + + expect(existsSync(outputFile)).toBe(true) + + const output = readFileSync(outputFile, 'utf-8') + expect(output).toContain('Hello World') + expect(output).toContain('use("/foo.txt"') + expect(output).toContain('use("/js/*"') + + const outputFooTxt = readFileSync(`${testDir}/dist/foo.txt`, 'utf-8') + expect(outputFooTxt).toContain('foo') + + const outputJsClientJs = readFileSync(`${testDir}/dist/js/client.js`, 'utf-8') + // eslint-disable-next-line quotes + expect(outputJsClientJs).toContain("console.log('foo')") + }) +}) diff --git a/packages/build/test/cloudflare-pages.test.ts b/packages/build/test/cloudflare-pages.test.ts new file mode 100644 index 0000000..8ef83a6 --- /dev/null +++ b/packages/build/test/cloudflare-pages.test.ts @@ -0,0 +1,85 @@ +import { existsSync, readFileSync, rmSync } from 'node:fs' +import { build } from 'vite' +import cloudflarePagesPlugin from '../src/adapter/cloudflare-pages' + +describe('Build Plugin with Cloudflare Pages Adapter', () => { + const testDir = './test/mocks/app-static-files' + + afterAll(() => { + rmSync(`${testDir}/dist`, { recursive: true, force: true }) + }) + + it('Should build the project correctly with the plugin', async () => { + const outputFile = `${testDir}/dist/_worker.js` + const routesFile = `${testDir}/dist/_routes.json` + + await build({ + root: testDir, + plugins: [ + cloudflarePagesPlugin({ + entry: 'src/server.ts', + }), + ], + }) + + expect(existsSync(outputFile)).toBe(true) + expect(existsSync(routesFile)).toBe(true) + + const output = readFileSync(outputFile, 'utf-8') + expect(output).toContain('Hello World') + + const routes = readFileSync(routesFile, 'utf-8') + expect(routes).toContain('{"version":1,"include":["/*"],"exclude":["/foo.txt","/js/*"]}') + }) + + it('Should build the project correctly with custom output directory', async () => { + const outputFile = `${testDir}/customDir/_worker.js` + const routesFile = `${testDir}/customDir/_routes.json` + + await build({ + root: testDir, + plugins: [ + cloudflarePagesPlugin({ + outputDir: 'customDir', + entry: 'src/server.ts', + }), + ], + build: { + emptyOutDir: true, + }, + }) + + expect(existsSync(outputFile)).toBe(true) + expect(existsSync(routesFile)).toBe(true) + + const output = readFileSync(outputFile, 'utf-8') + expect(output).toContain('Hello World') + + const routes = readFileSync(routesFile, 'utf-8') + expect(routes).toContain('{"version":1,"include":["/*"],"exclude":["/foo.txt","/js/*"]}') + }) + + it('Should not create a new _routes.json when _routes.json on output directory.', async () => { + const outputFile = `${testDir}/dist/_worker.js` + const routesFile = `${testDir}/dist/_routes.json` + + await build({ + publicDir: 'public-routes-json', + root: testDir, + plugins: [ + cloudflarePagesPlugin({ + entry: 'src/server.ts', + }), + ], + }) + + expect(existsSync(outputFile)).toBe(true) + expect(existsSync(routesFile)).toBe(true) + + const output = readFileSync(outputFile, 'utf-8') + expect(output).toContain('Hello World') + + const routes = readFileSync(routesFile, 'utf-8') + expect(routes).toContain('{"version":1,"include":["/"],"exclude":["/customRoute"]}') + }) +}) diff --git a/packages/build/test/mocks/app-static-files/public-routes-json/_routes.json b/packages/build/test/mocks/app-static-files/public-routes-json/_routes.json new file mode 100644 index 0000000..2a43272 --- /dev/null +++ b/packages/build/test/mocks/app-static-files/public-routes-json/_routes.json @@ -0,0 +1 @@ +{"version":1,"include":["/"],"exclude":["/customRoute"]} \ No newline at end of file diff --git a/packages/build/test/mocks/app-static-files/public/foo.txt b/packages/build/test/mocks/app-static-files/public/foo.txt new file mode 100644 index 0000000..1910281 --- /dev/null +++ b/packages/build/test/mocks/app-static-files/public/foo.txt @@ -0,0 +1 @@ +foo \ No newline at end of file diff --git a/packages/build/test/mocks/app-static-files/public/js/client.js b/packages/build/test/mocks/app-static-files/public/js/client.js new file mode 100644 index 0000000..a5b9709 --- /dev/null +++ b/packages/build/test/mocks/app-static-files/public/js/client.js @@ -0,0 +1 @@ +console.log('foo') diff --git a/packages/build/test/mocks/app-static-files/src/server.ts b/packages/build/test/mocks/app-static-files/src/server.ts new file mode 100644 index 0000000..c2381bb --- /dev/null +++ b/packages/build/test/mocks/app-static-files/src/server.ts @@ -0,0 +1,7 @@ +import { Hono } from 'hono' + +const app = new Hono() + +app.get('/', (c) => c.text('Hello World')) + +export default app diff --git a/packages/build/test/mocks/app/src/server.ts b/packages/build/test/mocks/app/src/server.ts new file mode 100644 index 0000000..c2381bb --- /dev/null +++ b/packages/build/test/mocks/app/src/server.ts @@ -0,0 +1,7 @@ +import { Hono } from 'hono' + +const app = new Hono() + +app.get('/', (c) => c.text('Hello World')) + +export default app diff --git a/packages/build/tsconfig.build.json b/packages/build/tsconfig.build.json new file mode 100644 index 0000000..563f9b1 --- /dev/null +++ b/packages/build/tsconfig.build.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "rootDir": "./src/" + }, + "include": [ + "src/**/*.ts" + ], + "exclude": [ + "src/**/*.test.ts" + ] +} \ No newline at end of file diff --git a/packages/build/tsconfig.json b/packages/build/tsconfig.json new file mode 100644 index 0000000..c50cfde --- /dev/null +++ b/packages/build/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "../../tsconfig.base.json", + "include": [ + "src", + "test" + ], + "compilerOptions": { + "module": "ES2022", + "target": "ES2022", + "types": [ + "vitest/globals", + "vite/client" + ] + }, +} \ No newline at end of file diff --git a/packages/build/tsup.config.ts b/packages/build/tsup.config.ts new file mode 100644 index 0000000..db5ddae --- /dev/null +++ b/packages/build/tsup.config.ts @@ -0,0 +1,17 @@ +import { glob } from 'glob' +import { defineConfig } from 'tsup' + +const entryPoints = glob.sync('./src/**/*.+(ts|tsx|json)', { + ignore: ['./src/**/*.test.+(ts|tsx)'], +}) + +export default defineConfig({ + entry: entryPoints, + dts: true, + tsconfig: './tsconfig.build.json', + splitting: false, + minify: false, + format: ['esm'], + bundle: false, + platform: 'node', +}) diff --git a/packages/build/vitest.config.ts b/packages/build/vitest.config.ts new file mode 100644 index 0000000..47cdb03 --- /dev/null +++ b/packages/build/vitest.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vitest/config' + +export default defineConfig({ + test: { + globals: true, + }, +}) diff --git a/packages/dev-server/package.json b/packages/dev-server/package.json index 4055ad4..a7dc333 100644 --- a/packages/dev-server/package.json +++ b/packages/dev-server/package.json @@ -108,4 +108,4 @@ "@hono/node-server": "^1.12.0", "minimatch": "^9.0.3" } -} \ No newline at end of file +} diff --git a/yarn.lock b/yarn.lock index 0bf1054..aa3d257 100644 --- a/yarn.lock +++ b/yarn.lock @@ -907,6 +907,22 @@ __metadata: languageName: node linkType: hard +"@hono/vite-build@workspace:packages/build": + version: 0.0.0-use.local + resolution: "@hono/vite-build@workspace:packages/build" + dependencies: + glob: ^10.3.10 + hono: ^4.6.1 + publint: ^0.1.12 + rimraf: ^5.0.1 + tsup: ^7.2.0 + vite: ^5.4.5 + vitest: ^2.1.1 + peerDependencies: + hono: "*" + languageName: unknown + linkType: soft + "@hono/vite-cloudflare-pages@workspace:packages/cloudflare-pages": version: 0.0.0-use.local resolution: "@hono/vite-cloudflare-pages@workspace:packages/cloudflare-pages" @@ -1050,6 +1066,13 @@ __metadata: languageName: node linkType: hard +"@jridgewell/sourcemap-codec@npm:^1.5.0": + version: 1.5.0 + resolution: "@jridgewell/sourcemap-codec@npm:1.5.0" + checksum: 05df4f2538b3b0f998ea4c1cd34574d0feba216fa5d4ccaef0187d12abf82eafe6021cec8b49f9bb4d90f2ba4582ccc581e72986a5fcf4176ae0cfeb04cf52ec + languageName: node + linkType: hard + "@jridgewell/trace-mapping@npm:0.3.9": version: 0.3.9 resolution: "@jridgewell/trace-mapping@npm:0.3.9" @@ -1170,6 +1193,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-android-arm-eabi@npm:4.21.3": + version: 4.21.3 + resolution: "@rollup/rollup-android-arm-eabi@npm:4.21.3" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + "@rollup/rollup-android-arm64@npm:4.18.0": version: 4.18.0 resolution: "@rollup/rollup-android-arm64@npm:4.18.0" @@ -1177,6 +1207,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-android-arm64@npm:4.21.3": + version: 4.21.3 + resolution: "@rollup/rollup-android-arm64@npm:4.21.3" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + "@rollup/rollup-darwin-arm64@npm:4.18.0": version: 4.18.0 resolution: "@rollup/rollup-darwin-arm64@npm:4.18.0" @@ -1184,6 +1221,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-darwin-arm64@npm:4.21.3": + version: 4.21.3 + resolution: "@rollup/rollup-darwin-arm64@npm:4.21.3" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + "@rollup/rollup-darwin-x64@npm:4.18.0": version: 4.18.0 resolution: "@rollup/rollup-darwin-x64@npm:4.18.0" @@ -1191,6 +1235,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-darwin-x64@npm:4.21.3": + version: 4.21.3 + resolution: "@rollup/rollup-darwin-x64@npm:4.21.3" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + "@rollup/rollup-linux-arm-gnueabihf@npm:4.18.0": version: 4.18.0 resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.18.0" @@ -1198,6 +1249,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-linux-arm-gnueabihf@npm:4.21.3": + version: 4.21.3 + resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.21.3" + conditions: os=linux & cpu=arm & libc=glibc + languageName: node + linkType: hard + "@rollup/rollup-linux-arm-musleabihf@npm:4.18.0": version: 4.18.0 resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.18.0" @@ -1205,6 +1263,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-linux-arm-musleabihf@npm:4.21.3": + version: 4.21.3 + resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.21.3" + conditions: os=linux & cpu=arm & libc=musl + languageName: node + linkType: hard + "@rollup/rollup-linux-arm64-gnu@npm:4.18.0": version: 4.18.0 resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.18.0" @@ -1212,6 +1277,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-linux-arm64-gnu@npm:4.21.3": + version: 4.21.3 + resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.21.3" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + "@rollup/rollup-linux-arm64-musl@npm:4.18.0": version: 4.18.0 resolution: "@rollup/rollup-linux-arm64-musl@npm:4.18.0" @@ -1219,6 +1291,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-linux-arm64-musl@npm:4.21.3": + version: 4.21.3 + resolution: "@rollup/rollup-linux-arm64-musl@npm:4.21.3" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + "@rollup/rollup-linux-powerpc64le-gnu@npm:4.18.0": version: 4.18.0 resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.18.0" @@ -1226,6 +1305,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-linux-powerpc64le-gnu@npm:4.21.3": + version: 4.21.3 + resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.21.3" + conditions: os=linux & cpu=ppc64 & libc=glibc + languageName: node + linkType: hard + "@rollup/rollup-linux-riscv64-gnu@npm:4.18.0": version: 4.18.0 resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.18.0" @@ -1233,6 +1319,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-linux-riscv64-gnu@npm:4.21.3": + version: 4.21.3 + resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.21.3" + conditions: os=linux & cpu=riscv64 & libc=glibc + languageName: node + linkType: hard + "@rollup/rollup-linux-s390x-gnu@npm:4.18.0": version: 4.18.0 resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.18.0" @@ -1240,6 +1333,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-linux-s390x-gnu@npm:4.21.3": + version: 4.21.3 + resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.21.3" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + "@rollup/rollup-linux-x64-gnu@npm:4.18.0": version: 4.18.0 resolution: "@rollup/rollup-linux-x64-gnu@npm:4.18.0" @@ -1247,6 +1347,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-linux-x64-gnu@npm:4.21.3": + version: 4.21.3 + resolution: "@rollup/rollup-linux-x64-gnu@npm:4.21.3" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + "@rollup/rollup-linux-x64-musl@npm:4.18.0": version: 4.18.0 resolution: "@rollup/rollup-linux-x64-musl@npm:4.18.0" @@ -1254,6 +1361,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-linux-x64-musl@npm:4.21.3": + version: 4.21.3 + resolution: "@rollup/rollup-linux-x64-musl@npm:4.21.3" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + "@rollup/rollup-win32-arm64-msvc@npm:4.18.0": version: 4.18.0 resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.18.0" @@ -1261,6 +1375,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-win32-arm64-msvc@npm:4.21.3": + version: 4.21.3 + resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.21.3" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + "@rollup/rollup-win32-ia32-msvc@npm:4.18.0": version: 4.18.0 resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.18.0" @@ -1268,6 +1389,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-win32-ia32-msvc@npm:4.21.3": + version: 4.21.3 + resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.21.3" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + "@rollup/rollup-win32-x64-msvc@npm:4.18.0": version: 4.18.0 resolution: "@rollup/rollup-win32-x64-msvc@npm:4.18.0" @@ -1275,6 +1403,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-win32-x64-msvc@npm:4.21.3": + version: 4.21.3 + resolution: "@rollup/rollup-win32-x64-msvc@npm:4.21.3" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@sinclair/typebox@npm:^0.27.8": version: 0.27.8 resolution: "@sinclair/typebox@npm:0.27.8" @@ -1503,6 +1638,47 @@ __metadata: languageName: node linkType: hard +"@vitest/expect@npm:2.1.1": + version: 2.1.1 + resolution: "@vitest/expect@npm:2.1.1" + dependencies: + "@vitest/spy": 2.1.1 + "@vitest/utils": 2.1.1 + chai: ^5.1.1 + tinyrainbow: ^1.2.0 + checksum: d86bdd36c6968ca2745767e1bc03db4f69cc193534f6d92a4a1f4e12166b37b9184cfd35d1ff06a9ffce1c5bf906b3640cbdf8ff2d345a0594a0094aa39c9d1a + languageName: node + linkType: hard + +"@vitest/mocker@npm:2.1.1": + version: 2.1.1 + resolution: "@vitest/mocker@npm:2.1.1" + dependencies: + "@vitest/spy": ^2.1.0-beta.1 + estree-walker: ^3.0.3 + magic-string: ^0.30.11 + peerDependencies: + "@vitest/spy": 2.1.1 + msw: ^2.3.5 + vite: ^5.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + checksum: d797428efe30d7b1e2183a3827e2423a70183053f570a5872a5533974c21fb5390e5db9b33fc42484bd68ed5d9342c7a0be52b79799eb21d7714fbed2bde2a7e + languageName: node + linkType: hard + +"@vitest/pretty-format@npm:2.1.1, @vitest/pretty-format@npm:^2.1.1": + version: 2.1.1 + resolution: "@vitest/pretty-format@npm:2.1.1" + dependencies: + tinyrainbow: ^1.2.0 + checksum: acc327b4d097719adf01762c22fa6aa59536cef916b7f1e1cbb91179f513ac056aaf023ba07fd86966a241c3157ee8a9c99b52f6899ee61bc1028c7f0117ca14 + languageName: node + linkType: hard + "@vitest/runner@npm:0.34.6": version: 0.34.6 resolution: "@vitest/runner@npm:0.34.6" @@ -1525,6 +1701,16 @@ __metadata: languageName: node linkType: hard +"@vitest/runner@npm:2.1.1": + version: 2.1.1 + resolution: "@vitest/runner@npm:2.1.1" + dependencies: + "@vitest/utils": 2.1.1 + pathe: ^1.1.2 + checksum: b2c82fc364574bb61475c4197c7facff179d199d6ee2fbe297518255686c301606edf9180ead050d112bb5f12901ba6d86405bf8d3ea3dd5b10cedc46f4d1beb + languageName: node + linkType: hard + "@vitest/snapshot@npm:0.34.6": version: 0.34.6 resolution: "@vitest/snapshot@npm:0.34.6" @@ -1547,6 +1733,17 @@ __metadata: languageName: node linkType: hard +"@vitest/snapshot@npm:2.1.1": + version: 2.1.1 + resolution: "@vitest/snapshot@npm:2.1.1" + dependencies: + "@vitest/pretty-format": 2.1.1 + magic-string: ^0.30.11 + pathe: ^1.1.2 + checksum: d913fa14430d02e38d9c6a14326658be4ce871c8df82f9aa2f33f7c7ac6ab1a341a7b43585d72e8e159482578567865beffe561da218a18ee10110ce9008e0e5 + languageName: node + linkType: hard + "@vitest/spy@npm:0.34.6": version: 0.34.6 resolution: "@vitest/spy@npm:0.34.6" @@ -1565,6 +1762,15 @@ __metadata: languageName: node linkType: hard +"@vitest/spy@npm:2.1.1, @vitest/spy@npm:^2.1.0-beta.1": + version: 2.1.1 + resolution: "@vitest/spy@npm:2.1.1" + dependencies: + tinyspy: ^3.0.0 + checksum: 87d680dc905b80ced10a5ae8a019772b6b31b7cd928a21ae7043cd06b163ff39eee37dbb3a8033d80e1496200b2990aa13600fccae9b3bf234a65485a4f3f71b + languageName: node + linkType: hard + "@vitest/utils@npm:0.34.6": version: 0.34.6 resolution: "@vitest/utils@npm:0.34.6" @@ -1588,6 +1794,17 @@ __metadata: languageName: node linkType: hard +"@vitest/utils@npm:2.1.1": + version: 2.1.1 + resolution: "@vitest/utils@npm:2.1.1" + dependencies: + "@vitest/pretty-format": 2.1.1 + loupe: ^3.1.1 + tinyrainbow: ^1.2.0 + checksum: 13ffb30e17fcdcb8bc0c3c64db5eca9b670da4f80fd6bab4a9d387f6a534886fb447e45274db44375703d909aab9ebe123accd8d7159f90a8c9852e7f758e420 + languageName: node + linkType: hard + "abbrev@npm:^2.0.0": version: 2.0.0 resolution: "abbrev@npm:2.0.0" @@ -1840,6 +2057,13 @@ __metadata: languageName: node linkType: hard +"assertion-error@npm:^2.0.1": + version: 2.0.1 + resolution: "assertion-error@npm:2.0.1" + checksum: a0789dd882211b87116e81e2648ccb7f60340b34f19877dd020b39ebb4714e475eb943e14ba3e22201c221ef6645b7bfe10297e76b6ac95b48a9898c1211ce66 + languageName: node + linkType: hard + "available-typed-arrays@npm:^1.0.7": version: 1.0.7 resolution: "available-typed-arrays@npm:1.0.7" @@ -1990,6 +2214,19 @@ __metadata: languageName: node linkType: hard +"chai@npm:^5.1.1": + version: 5.1.1 + resolution: "chai@npm:5.1.1" + dependencies: + assertion-error: ^2.0.1 + check-error: ^2.1.1 + deep-eql: ^5.0.1 + loupe: ^3.1.0 + pathval: ^2.0.0 + checksum: 1e0a5e1b5febdfa8ceb97b9aff608286861ecb86533863119b2f39f07c08fb59f3c1791ab554947f009b9d71d509b9e4e734fb12133cb81f231c2c2ee7c1e738 + languageName: node + linkType: hard + "chalk@npm:^2.1.0": version: 2.4.2 resolution: "chalk@npm:2.4.2" @@ -2027,6 +2264,13 @@ __metadata: languageName: node linkType: hard +"check-error@npm:^2.1.1": + version: 2.1.1 + resolution: "check-error@npm:2.1.1" + checksum: d785ed17b1d4a4796b6e75c765a9a290098cf52ff9728ce0756e8ffd4293d2e419dd30c67200aee34202463b474306913f2fcfaf1890641026d9fc6966fea27a + languageName: node + linkType: hard + "chokidar@npm:^3.5.1, chokidar@npm:^3.5.3": version: 3.6.0 resolution: "chokidar@npm:3.6.0" @@ -2231,6 +2475,18 @@ __metadata: languageName: node linkType: hard +"debug@npm:^4.3.6": + version: 4.3.7 + resolution: "debug@npm:4.3.7" + dependencies: + ms: ^2.1.3 + peerDependenciesMeta: + supports-color: + optional: true + checksum: 822d74e209cd910ef0802d261b150314bbcf36c582ccdbb3e70f0894823c17e49a50d3e66d96b633524263975ca16b6a833f3e3b7e030c157169a5fabac63160 + languageName: node + linkType: hard + "deep-eql@npm:^4.1.3": version: 4.1.4 resolution: "deep-eql@npm:4.1.4" @@ -2240,6 +2496,13 @@ __metadata: languageName: node linkType: hard +"deep-eql@npm:^5.0.1": + version: 5.0.2 + resolution: "deep-eql@npm:5.0.2" + checksum: 6aaaadb4c19cbce42e26b2bbe5bd92875f599d2602635dc97f0294bae48da79e89470aedee05f449e0ca8c65e9fd7e7872624d1933a1db02713d99c2ca8d1f24 + languageName: node + linkType: hard + "deep-is@npm:^0.1.3": version: 0.1.4 resolution: "deep-is@npm:0.1.4" @@ -3594,6 +3857,13 @@ __metadata: languageName: node linkType: hard +"hono@npm:^4.6.1": + version: 4.6.1 + resolution: "hono@npm:4.6.1" + checksum: 8b8a996013ad44019a326723fed8435e590d1696d46ae5d1297c5057794766c7d54832446f08f22113e144e7dfa491fddb52146bc4e7ab708089049d004d0a16 + languageName: node + linkType: hard + "http-cache-semantics@npm:^4.1.1": version: 4.1.1 resolution: "http-cache-semantics@npm:4.1.1" @@ -4194,6 +4464,15 @@ __metadata: languageName: node linkType: hard +"loupe@npm:^3.1.0, loupe@npm:^3.1.1": + version: 3.1.1 + resolution: "loupe@npm:3.1.1" + dependencies: + get-func-name: ^2.0.1 + checksum: c7efa6bc6d71f25ca03eb13c9a069e35ed86799e308ca27a7a3eff8cdf9500e7c22d1f2411468d154a8e960e91e5e685e0c6c83e96db748f177c1adf30811153 + languageName: node + linkType: hard + "lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0": version: 10.2.2 resolution: "lru-cache@npm:10.2.2" @@ -4229,6 +4508,15 @@ __metadata: languageName: node linkType: hard +"magic-string@npm:^0.30.11": + version: 0.30.11 + resolution: "magic-string@npm:0.30.11" + dependencies: + "@jridgewell/sourcemap-codec": ^1.5.0 + checksum: e041649453c9a3f31d2e731fc10e38604d50e20d3585cd48bc7713a6e2e1a3ad3012105929ca15750d59d0a3f1904405e4b95a23b7e69dc256db3c277a73a3ca + languageName: node + linkType: hard + "make-fetch-happen@npm:^13.0.0": version: 13.0.1 resolution: "make-fetch-happen@npm:13.0.1" @@ -4480,7 +4768,7 @@ __metadata: languageName: node linkType: hard -"ms@npm:^2.1.1": +"ms@npm:^2.1.1, ms@npm:^2.1.3": version: 2.1.3 resolution: "ms@npm:2.1.3" checksum: aa92de608021b242401676e35cfa5aa42dd70cbdc082b916da7fb925c542173e36bce97ea3e804923fe92c0ad991434e4a38327e15a1b5b5f945d66df615ae6d @@ -4941,6 +5229,13 @@ __metadata: languageName: node linkType: hard +"pathval@npm:^2.0.0": + version: 2.0.0 + resolution: "pathval@npm:2.0.0" + checksum: 682b6a6289de7990909effef7dae9aa7bb6218c0426727bccf66a35b34e7bfbc65615270c5e44e3c9557a5cb44b1b9ef47fc3cb18bce6ad3ba92bcd28467ed7d + languageName: node + linkType: hard + "picocolors@npm:^1.0.0, picocolors@npm:^1.0.1": version: 1.0.1 resolution: "picocolors@npm:1.0.1" @@ -5049,6 +5344,17 @@ __metadata: languageName: node linkType: hard +"postcss@npm:^8.4.43": + version: 8.4.45 + resolution: "postcss@npm:8.4.45" + dependencies: + nanoid: ^3.3.7 + picocolors: ^1.0.1 + source-map-js: ^1.2.0 + checksum: 3223cdad4a9392c0b334ee3ee7e4e8041c631cb6160609cef83c18d2b2580e931dd8068ab13cc6000c1a254d57492ac6c38717efc397c5dcc9756d06bc9c44f3 + languageName: node + linkType: hard + "preferred-pm@npm:^3.0.0": version: 3.1.3 resolution: "preferred-pm@npm:3.1.3" @@ -5425,6 +5731,69 @@ __metadata: languageName: node linkType: hard +"rollup@npm:^4.20.0": + version: 4.21.3 + resolution: "rollup@npm:4.21.3" + dependencies: + "@rollup/rollup-android-arm-eabi": 4.21.3 + "@rollup/rollup-android-arm64": 4.21.3 + "@rollup/rollup-darwin-arm64": 4.21.3 + "@rollup/rollup-darwin-x64": 4.21.3 + "@rollup/rollup-linux-arm-gnueabihf": 4.21.3 + "@rollup/rollup-linux-arm-musleabihf": 4.21.3 + "@rollup/rollup-linux-arm64-gnu": 4.21.3 + "@rollup/rollup-linux-arm64-musl": 4.21.3 + "@rollup/rollup-linux-powerpc64le-gnu": 4.21.3 + "@rollup/rollup-linux-riscv64-gnu": 4.21.3 + "@rollup/rollup-linux-s390x-gnu": 4.21.3 + "@rollup/rollup-linux-x64-gnu": 4.21.3 + "@rollup/rollup-linux-x64-musl": 4.21.3 + "@rollup/rollup-win32-arm64-msvc": 4.21.3 + "@rollup/rollup-win32-ia32-msvc": 4.21.3 + "@rollup/rollup-win32-x64-msvc": 4.21.3 + "@types/estree": 1.0.5 + fsevents: ~2.3.2 + dependenciesMeta: + "@rollup/rollup-android-arm-eabi": + optional: true + "@rollup/rollup-android-arm64": + optional: true + "@rollup/rollup-darwin-arm64": + optional: true + "@rollup/rollup-darwin-x64": + optional: true + "@rollup/rollup-linux-arm-gnueabihf": + optional: true + "@rollup/rollup-linux-arm-musleabihf": + optional: true + "@rollup/rollup-linux-arm64-gnu": + optional: true + "@rollup/rollup-linux-arm64-musl": + optional: true + "@rollup/rollup-linux-powerpc64le-gnu": + optional: true + "@rollup/rollup-linux-riscv64-gnu": + optional: true + "@rollup/rollup-linux-s390x-gnu": + optional: true + "@rollup/rollup-linux-x64-gnu": + optional: true + "@rollup/rollup-linux-x64-musl": + optional: true + "@rollup/rollup-win32-arm64-msvc": + optional: true + "@rollup/rollup-win32-ia32-msvc": + optional: true + "@rollup/rollup-win32-x64-msvc": + optional: true + fsevents: + optional: true + bin: + rollup: dist/bin/rollup + checksum: 19689840d25ced3924124b012d7e0048f2b0844a0765a5dde0804ae9961af1103657c2ec3e90f7a19876ebe40b3fa2c33f53fca071d46639c57bd327b82aba22 + languageName: node + linkType: hard + "run-parallel@npm:^1.1.9": version: 1.2.0 resolution: "run-parallel@npm:1.2.0" @@ -5707,7 +6076,7 @@ __metadata: languageName: node linkType: hard -"std-env@npm:^3.3.3, std-env@npm:^3.5.0": +"std-env@npm:^3.3.3, std-env@npm:^3.5.0, std-env@npm:^3.7.0": version: 3.7.0 resolution: "std-env@npm:3.7.0" checksum: 4f489d13ff2ab838c9acd4ed6b786b51aa52ecacdfeaefe9275fcb220ff2ac80c6e95674723508fd29850a694569563a8caaaea738eb82ca16429b3a0b50e510 @@ -5944,6 +6313,20 @@ __metadata: languageName: node linkType: hard +"tinybench@npm:^2.9.0": + version: 2.9.0 + resolution: "tinybench@npm:2.9.0" + checksum: 1ab00d7dfe0d1f127cbf00822bacd9024f7a50a3ecd1f354a8168e0b7d2b53a639a24414e707c27879d1adc0f5153141d51d76ebd7b4d37fe245e742e5d91fe8 + languageName: node + linkType: hard + +"tinyexec@npm:^0.3.0": + version: 0.3.0 + resolution: "tinyexec@npm:0.3.0" + checksum: e55473d249b8fc94bc5b1461d8e368dfe0ba23dcfca4f9069fe25418b17772e50110a1d33cd7ac8ff26456e5b609e0528cce7660e35246fad9b00bd094f3f444 + languageName: node + linkType: hard + "tinypool@npm:^0.7.0": version: 0.7.0 resolution: "tinypool@npm:0.7.0" @@ -5958,6 +6341,20 @@ __metadata: languageName: node linkType: hard +"tinypool@npm:^1.0.0": + version: 1.0.1 + resolution: "tinypool@npm:1.0.1" + checksum: 5cd6b8cbccd9b88d461f400c9599e69f66563ddf75a2b8ab6b48250481f1b254d180a68ee735f379fa6eb88f11c3b1814735bb1f3306b1a860bf6d8f08074d6b + languageName: node + linkType: hard + +"tinyrainbow@npm:^1.2.0": + version: 1.2.0 + resolution: "tinyrainbow@npm:1.2.0" + checksum: d1e2cb5400032c0092be00e4a3da5450bea8b4fad58bfb5d3c58ca37ff5c5e252f7fcfb9af247914854af79c46014add9d1042fe044358c305a129ed55c8be35 + languageName: node + linkType: hard + "tinyspy@npm:^2.1.1, tinyspy@npm:^2.2.0": version: 2.2.1 resolution: "tinyspy@npm:2.2.1" @@ -5965,6 +6362,13 @@ __metadata: languageName: node linkType: hard +"tinyspy@npm:^3.0.0": + version: 3.0.2 + resolution: "tinyspy@npm:3.0.2" + checksum: 5db671b2ff5cd309de650c8c4761ca945459d7204afb1776db9a04fb4efa28a75f08517a8620c01ee32a577748802231ad92f7d5b194dc003ee7f987a2a06337 + languageName: node + linkType: hard + "tmp@npm:^0.0.33": version: 0.0.33 resolution: "tmp@npm:0.0.33" @@ -6288,6 +6692,20 @@ __metadata: languageName: node linkType: hard +"vite-node@npm:2.1.1": + version: 2.1.1 + resolution: "vite-node@npm:2.1.1" + dependencies: + cac: ^6.7.14 + debug: ^4.3.6 + pathe: ^1.1.2 + vite: ^5.0.0 + bin: + vite-node: vite-node.mjs + checksum: b44cad7c82d2101ab9e6f3c90f27fed879c0bc8001493ca138d38984795b27393ecaef904a4d8d70abb0f7215b8eb05de15be6cc261134ca7c72d23017571551 + languageName: node + linkType: hard + "vite@npm:^3.0.0 || ^4.0.0 || ^5.0.0-0, vite@npm:^3.1.0 || ^4.0.0 || ^5.0.0-0, vite@npm:^5.0.0, vite@npm:^5.2.10": version: 5.3.1 resolution: "vite@npm:5.3.1" @@ -6328,6 +6746,49 @@ __metadata: languageName: node linkType: hard +"vite@npm:^5.4.5": + version: 5.4.5 + resolution: "vite@npm:5.4.5" + dependencies: + esbuild: ^0.21.3 + fsevents: ~2.3.3 + postcss: ^8.4.43 + rollup: ^4.20.0 + peerDependencies: + "@types/node": ^18.0.0 || >=20.0.0 + less: "*" + lightningcss: ^1.21.0 + sass: "*" + sass-embedded: "*" + stylus: "*" + sugarss: "*" + terser: ^5.4.0 + dependenciesMeta: + fsevents: + optional: true + peerDependenciesMeta: + "@types/node": + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + bin: + vite: bin/vite.js + checksum: 19e7aa49cd72f93d4e152f23b736ff3de4fc4bccf81d99970b3e88bf399138cf1807314fde1f5ee6251f2007292d491bad97e444fb9d4d5628be4bf6cae62a42 + languageName: node + linkType: hard + "vitest@npm:^0.34.6": version: 0.34.6 resolution: "vitest@npm:0.34.6" @@ -6438,6 +6899,55 @@ __metadata: languageName: node linkType: hard +"vitest@npm:^2.1.1": + version: 2.1.1 + resolution: "vitest@npm:2.1.1" + dependencies: + "@vitest/expect": 2.1.1 + "@vitest/mocker": 2.1.1 + "@vitest/pretty-format": ^2.1.1 + "@vitest/runner": 2.1.1 + "@vitest/snapshot": 2.1.1 + "@vitest/spy": 2.1.1 + "@vitest/utils": 2.1.1 + chai: ^5.1.1 + debug: ^4.3.6 + magic-string: ^0.30.11 + pathe: ^1.1.2 + std-env: ^3.7.0 + tinybench: ^2.9.0 + tinyexec: ^0.3.0 + tinypool: ^1.0.0 + tinyrainbow: ^1.2.0 + vite: ^5.0.0 + vite-node: 2.1.1 + why-is-node-running: ^2.3.0 + peerDependencies: + "@edge-runtime/vm": "*" + "@types/node": ^18.0.0 || >=20.0.0 + "@vitest/browser": 2.1.1 + "@vitest/ui": 2.1.1 + happy-dom: "*" + jsdom: "*" + peerDependenciesMeta: + "@edge-runtime/vm": + optional: true + "@types/node": + optional: true + "@vitest/browser": + optional: true + "@vitest/ui": + optional: true + happy-dom: + optional: true + jsdom: + optional: true + bin: + vitest: vitest.mjs + checksum: cf8e2ff098464287729ef62da83b016ed1398642959ef947669401316a70c12d6a4de9b8962220b3fc133f88ce2c153c5c3944f4ad6d360d5bca8cfa2cec0243 + languageName: node + linkType: hard + "webidl-conversions@npm:^3.0.0": version: 3.0.1 resolution: "webidl-conversions@npm:3.0.1" @@ -6554,6 +7064,18 @@ __metadata: languageName: node linkType: hard +"why-is-node-running@npm:^2.3.0": + version: 2.3.0 + resolution: "why-is-node-running@npm:2.3.0" + dependencies: + siginfo: ^2.0.0 + stackback: 0.0.2 + bin: + why-is-node-running: cli.js + checksum: 58ebbf406e243ace97083027f0df7ff4c2108baf2595bb29317718ef207cc7a8104e41b711ff65d6fa354f25daa8756b67f2f04931a4fd6ba9d13ae8197496fb + languageName: node + linkType: hard + "word-wrap@npm:^1.2.5": version: 1.2.5 resolution: "word-wrap@npm:1.2.5"