@resolid/dev 0.1.0 → 0.1.1

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 CHANGED
@@ -17,6 +17,82 @@ yarn add @resolid/dev
17
17
  bun add @resolid/dev
18
18
  ```
19
19
 
20
+ ## What is included
21
+
22
+ - `defineDevConfig` (`@resolid/dev`): generate unified `vitePluginOptions` and `reactRouterConfig`.
23
+ - `resolidVite` (`@resolid/dev/vite`): combine Resolid plugin behavior with React Router Vite plugin.
24
+ - Route helpers (`@resolid/dev/routes`): `relativeFactory`, `prefix`, `route`, `layout`, `index`.
25
+ - Router helpers (`@resolid/dev/router`): `mergeMeta`.
26
+ - Server-side router helpers (`@resolid/dev/router.server`):
27
+ `createRequestIdMiddleware`, `httpNotFound`, `getClientIp`, `getRequestOrigin`.
28
+ - Server adapters (`@resolid/dev/server`): `createServer`, `nodeConfig`, `netlifyConfig`, `vercelConfig`.
29
+
30
+
31
+ ## Usage patterns (same as website)
32
+
33
+ ### 1) Central config
34
+
35
+ ```ts
36
+ // resolid.config.ts
37
+ import { defineDevConfig } from "@resolid/dev";
38
+ import { env } from "node:process";
39
+
40
+ export const { vitePluginOptions, reactRouterConfig } = defineDevConfig({
41
+ appDirectory: "src",
42
+ nodeVersion: 24,
43
+ platform: env.VERCEL == 1 ? "vercel" : env.NETLIFY ? "netlify" : "node",
44
+ reactRouterConfig: {
45
+ future: {
46
+ unstable_optimizeDeps: true,
47
+ },
48
+ },
49
+ });
50
+ ```
51
+
52
+ ### 2) Vite config
53
+
54
+ ```ts
55
+ // vite.config.ts
56
+ import { resolidVite } from "@resolid/dev/vite";
57
+ import { defineConfig } from "vite";
58
+ import { vitePluginOptions } from "./resolid.config";
59
+
60
+ export default defineConfig({
61
+ plugins: [resolidVite(vitePluginOptions)],
62
+ });
63
+ ```
64
+
65
+ ### 3) React Router config
66
+
67
+ ```ts
68
+ // react-router.config.ts
69
+ import { reactRouterConfig } from "./resolid.config";
70
+
71
+ export default reactRouterConfig;
72
+ ```
73
+
74
+ ### 4) Server entry
75
+
76
+ ```ts
77
+ // src/server.ts
78
+ import { createServer, netlifyConfig, nodeConfig, vercelConfig } from "@resolid/dev/server";
79
+
80
+ export default await createServer((platform) => {
81
+ switch (platform) {
82
+ case "vercel":
83
+ return vercelConfig({});
84
+ case "netlify":
85
+ return netlifyConfig({});
86
+ default:
87
+ return nodeConfig({});
88
+ }
89
+ });
90
+ ```
91
+
92
+ ### 5) React Router document
93
+
94
+ Visit: https://reactrouter.com/home
95
+
20
96
  ## License
21
97
 
22
98
  MIT License (MIT). Please see [LICENSE](./LICENSE) for more information.
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import{cp as e,mkdir as t,readFile as n,readdir as r,realpath as i,rm as a,stat as o,symlink as s,writeFile as c}from"node:fs/promises";import{basename as l,dirname as u,join as d,relative as f}from"node:path";import p from"fast-glob";import{existsSync as m}from"node:fs";import{build as h}from"rolldown";import{esmExternalRequirePlugin as g}from"rolldown/plugins";import{searchForWorkspaceRoot as _}from"vite";var v=`@resolid/dev`,y=`0.1.0`;async function b({includeFiles:t=[],nodeVersion:r=22,buildManifest:i,reactRouterConfig:o,viteConfig:s,buildStart:c,buildBundleEnd:l}){let m=s.root,_=s.build.assetsDir??`assets`,v=JSON.parse(await n(d(m,`package.json`),`utf8`)),y=x(v.dependencies??{},s.ssr.external),b=d(o.buildDirectory,`server`),C=i?.serverBundles??{site:{id:`site`,file:f(m,d(b,o.serverBuildFile))}},w=t?.length>0?await p(t,{cwd:m}):[],T=await c();await Promise.all(Object.entries(C).map(async([,t])=>{let n=t.id,i=d(m,t.file),o=u(i);await S(d(o,`package.json`),v,y,r),console.log(`Bundle file for ${n}...`);let s=d(o,`server.mjs`);await h({input:i,output:{file:s,codeSplitting:!1,legalComments:`none`},platform:`node`,transform:{define:{"process.env.NODE_ENV":JSON.stringify(`production`),"import.meta.env.NODE_ENV":JSON.stringify(`production`)},target:`node${r}`},external:[`vite`,...Object.keys(y)],plugins:[g({external:[`vite`,...Object.keys(y)],skipDuplicateCheck:!0})]}),await a(d(o,_),{force:!0,recursive:!0}),await a(i,{force:!0}),await Promise.all(w.map(t=>e(t,d(b,t),{recursive:!0}))),await l?.(T,o,n,s,y)}))}function x(e,t){let n=Array.isArray(t)?t.filter(e=>![`react-router`,`react-router-dom`,`@react-router/architect`,`@react-router/cloudflare`,`@react-router/dev`,`@react-router/express`,`@react-router/node`,`@react-router/serve`].includes(e)):t;return Object.keys(e).filter(e=>n===void 0?!1:n===!0?!0:n.includes(e)).reduce((t,n)=>(t[n]=e[n]??``,t),{})}async function S(e,t,n,r){let i={name:t.name,type:t.type,version:t.version,scripts:{postinstall:t.scripts?.postinstall??``},dependencies:n,engines:{node:`${r}.x`}};await c(e,JSON.stringify(i,null,2),`utf8`)}async function C(e,n=!1){let r=d(...e);return n&&await a(r,{recursive:!0,force:!0}),await t(r,{recursive:!0}),r}function w(e){if(e?.routeIdToServerBundleId){let t=Object.values(e.routes).filter(e=>e.id!=`root`).map(t=>{let n=[...T(e.routes,t.parentId),t.path].join(`/`);return{id:t.id,path:`/${n}`}}),n={};for(let[r,i]of Object.entries(e?.routeIdToServerBundleId)){n[i]||(n[i]=[]);for(let e of t)e.id==r&&n[i].push(e.path)}let r={};for(let[e,t]of Object.entries(n)){t.sort((e,t)=>e.length<t.length?-1:1);for(let n of t)!r[n]&&!Object.keys(r).find(t=>r[t].bundleId==e&&n.startsWith(r[t].path))&&(r[n]={path:n,bundleId:e})}let i=Object.values(r).map(e=>({path:e.path.endsWith(`/`)?e.path.slice(0,-1):e.path,bundleId:e.bundleId}));return i.sort((e,t)=>e.path.length>t.path.length?-1:1),i}return[{path:``,bundleId:`site`}]}function T(e,t){if(t==null)return[];let n=[],r=t=>{let i=e[t];i.parentId&&r(i.parentId),i.path&&n.push(i.path)};return r(t),n}async function E(n,a,c){let p=_(n),{nodeFileTrace:h}=await import(`@vercel/nft`),g=await h([n],{base:p,cache:c}),v=Array.from(g.fileList).map(e=>d(p,e)),y=u(v[0]);for(let e of v.slice(1))for(;!e.startsWith(y);)y=u(y);return await Promise.all(v.map(async c=>{let p=d(a,f(y,c)),h=await i(c),g=h!==c,_=(await o(c)).isDirectory();if(await t(u(p),{recursive:!0}),c==n){let t=u(n),i=u(p);await Promise.all((await r(t)).filter(e=>e!==l(n)).map(n=>e(d(t,n),d(i,n),{recursive:!0})))}g?m(p)||await s(f(u(p),d(a,f(y,h))),p,_?`dir`:`file`):_||await e(c,p)})),f(y,n)}const D=e=>{let{nodeVersion:t}=e;return{name:`@resolid/react-router-hono-netlify-preset`,reactRouterConfig:()=>({buildEnd:async({buildManifest:n,reactRouterConfig:r,viteConfig:i})=>{await b({includeFiles:e.includeFiles,nodeVersion:t,buildManifest:n,reactRouterConfig:r,viteConfig:i,buildStart:async()=>{let e=await C([i.root,`.netlify`,`v1`],!0);return await O(i.build.assetsDir??`assets`,d(e,`config.json`)),{netlifyRoot:e,netlifyFunctionDir:await C([e,`functions`]),serverRoutes:w(n),nftCache:{}}},buildBundleEnd:async(e,n,r,i)=>{console.log(`Coping Netlify function files for ${r}...`);let a=await E(i,await C([e.netlifyFunctionDir,r],!0),e.nftCache),o=e.serverRoutes.find(e=>e.bundleId==r)?.path,s=o?[o,`${o}/*`]:`/*`;await c(d(e.netlifyFunctionDir,`${r}.mjs`),`export { default } from "./${d(r,a)}";
1
+ import{cp as e,mkdir as t,readFile as n,readdir as r,realpath as i,rm as a,stat as o,symlink as s,writeFile as c}from"node:fs/promises";import{basename as l,dirname as u,join as d,relative as f}from"node:path";import p from"fast-glob";import{existsSync as m}from"node:fs";import{build as h}from"rolldown";import{esmExternalRequirePlugin as g}from"rolldown/plugins";import{searchForWorkspaceRoot as _}from"vite";var v=`@resolid/dev`,y=`0.1.1`;async function b({includeFiles:t=[],nodeVersion:r=22,buildManifest:i,reactRouterConfig:o,viteConfig:s,buildStart:c,buildBundleEnd:l}){let m=s.root,_=s.build.assetsDir??`assets`,v=JSON.parse(await n(d(m,`package.json`),`utf8`)),y=x(v.dependencies??{},s.ssr.external),b=d(o.buildDirectory,`server`),C=i?.serverBundles??{site:{id:`site`,file:f(m,d(b,o.serverBuildFile))}},w=t?.length>0?await p(t,{cwd:m}):[],T=await c();await Promise.all(Object.entries(C).map(async([,t])=>{let n=t.id,i=d(m,t.file),o=u(i);await S(d(o,`package.json`),v,y,r),console.log(`Bundle file for ${n}...`);let s=d(o,`server.mjs`);await h({input:i,output:{file:s,codeSplitting:!1,legalComments:`none`},platform:`node`,transform:{define:{"process.env.NODE_ENV":JSON.stringify(`production`),"import.meta.env.NODE_ENV":JSON.stringify(`production`)},target:`node${r}`},external:[`vite`,...Object.keys(y)],plugins:[g({external:[`vite`,...Object.keys(y)],skipDuplicateCheck:!0})]}),await a(d(o,_),{force:!0,recursive:!0}),await a(i,{force:!0}),await Promise.all(w.map(t=>e(t,d(b,t),{recursive:!0}))),await l?.(T,o,n,s,y)}))}function x(e,t){let n=Array.isArray(t)?t.filter(e=>![`react-router`,`react-router-dom`,`@react-router/architect`,`@react-router/cloudflare`,`@react-router/dev`,`@react-router/express`,`@react-router/node`,`@react-router/serve`].includes(e)):t;return Object.keys(e).filter(e=>n===void 0?!1:n===!0?!0:n.includes(e)).reduce((t,n)=>(t[n]=e[n]??``,t),{})}async function S(e,t,n,r){let i={name:t.name,type:t.type,version:t.version,scripts:{postinstall:t.scripts?.postinstall??``},dependencies:n,engines:{node:`${r}.x`}};await c(e,JSON.stringify(i,null,2),`utf8`)}async function C(e,n=!1){let r=d(...e);return n&&await a(r,{recursive:!0,force:!0}),await t(r,{recursive:!0}),r}function w(e){if(e?.routeIdToServerBundleId){let t=Object.values(e.routes).filter(e=>e.id!=`root`).map(t=>{let n=[...T(e.routes,t.parentId),t.path].join(`/`);return{id:t.id,path:`/${n}`}}),n={};for(let[r,i]of Object.entries(e?.routeIdToServerBundleId)){n[i]||(n[i]=[]);for(let e of t)e.id==r&&n[i].push(e.path)}let r={};for(let[e,t]of Object.entries(n)){t.sort((e,t)=>e.length<t.length?-1:1);for(let n of t)!r[n]&&!Object.keys(r).find(t=>r[t].bundleId==e&&n.startsWith(r[t].path))&&(r[n]={path:n,bundleId:e})}let i=Object.values(r).map(e=>({path:e.path.endsWith(`/`)?e.path.slice(0,-1):e.path,bundleId:e.bundleId}));return i.sort((e,t)=>e.path.length>t.path.length?-1:1),i}return[{path:``,bundleId:`site`}]}function T(e,t){if(t==null)return[];let n=[],r=t=>{let i=e[t];i.parentId&&r(i.parentId),i.path&&n.push(i.path)};return r(t),n}async function E(n,a,c){let p=_(n),{nodeFileTrace:h}=await import(`@vercel/nft`),g=await h([n],{base:p,cache:c}),v=Array.from(g.fileList).map(e=>d(p,e)),y=u(v[0]);for(let e of v.slice(1))for(;!e.startsWith(y);)y=u(y);return await Promise.all(v.map(async c=>{let p=d(a,f(y,c)),h=await i(c),g=h!==c,_=(await o(c)).isDirectory();if(await t(u(p),{recursive:!0}),c==n){let t=u(n),i=u(p);await Promise.all((await r(t)).filter(e=>e!==l(n)).map(n=>e(d(t,n),d(i,n),{recursive:!0})))}g?m(p)||await s(f(u(p),d(a,f(y,h))),p,_?`dir`:`file`):_||await e(c,p)})),f(y,n)}const D=e=>{let{nodeVersion:t}=e;return{name:`@resolid/react-router-hono-netlify-preset`,reactRouterConfig:()=>({buildEnd:async({buildManifest:n,reactRouterConfig:r,viteConfig:i})=>{await b({includeFiles:e.includeFiles,nodeVersion:t,buildManifest:n,reactRouterConfig:r,viteConfig:i,buildStart:async()=>{let e=await C([i.root,`.netlify`,`v1`],!0);return await O(i.build.assetsDir??`assets`,d(e,`config.json`)),{netlifyRoot:e,netlifyFunctionDir:await C([e,`functions`]),serverRoutes:w(n),nftCache:{}}},buildBundleEnd:async(e,n,r,i)=>{console.log(`Coping Netlify function files for ${r}...`);let a=await E(i,await C([e.netlifyFunctionDir,r],!0),e.nftCache),o=e.serverRoutes.find(e=>e.bundleId==r)?.path,s=o?[o,`${o}/*`]:`/*`;await c(d(e.netlifyFunctionDir,`${r}.mjs`),`export { default } from "./${d(r,a)}";
2
2
 
3
3
  export const config = {
4
4
  path: ${Array.isArray(s)?JSON.stringify(s):`"${s}"`},
package/dist/server.d.mts CHANGED
@@ -51,4 +51,4 @@ declare const netlifyConfig: PlatformConfig<HonoNetlifyServerOptions>;
51
51
  declare const vercelConfig: PlatformConfig<HonoVercelServerOptions>;
52
52
  declare const createServer: (factory: (platform: Platform) => HonoNodeServerOptions | HonoNetlifyServerOptions | HonoVercelServerOptions | undefined) => Promise<((req: Request, context: NetlifyContext) => Response | Promise<Response>) | ((incoming: IncomingMessage | Http2ServerRequest, outgoing: ServerResponse | Http2ServerResponse) => Promise<void>) | Hono<NodeEnv>>;
53
53
  //#endregion
54
- export { type Hono, type HonoContext, type NetlifyContext, type NodeEnv, cacheControl, createServer, netlifyConfig, nodeConfig, vercelConfig };
54
+ export { type Hono, type HonoContext, type NetlifyContext, type NodeEnv, type Platform, cacheControl, createServer, netlifyConfig, nodeConfig, vercelConfig };
package/env.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ interface ImportMetaEnv {
2
+ readonly RESOLID_PLATFORM: "node" | "vercel" | "netlify";
3
+ }
4
+
5
+ interface ImportMeta {
6
+ readonly env: ImportMetaEnv;
7
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@resolid/dev",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "private": false,
5
5
  "description": "Development utils for Resolid applications",
6
6
  "keywords": [
@@ -27,7 +27,8 @@
27
27
  },
28
28
  "files": [
29
29
  "cli",
30
- "dist"
30
+ "dist",
31
+ "env.d.ts"
31
32
  ],
32
33
  "type": "module",
33
34
  "sideEffects": false,
@@ -37,6 +38,9 @@
37
38
  "types": "./dist/index.d.mts",
38
39
  "import": "./dist/index.mjs"
39
40
  },
41
+ "./env": {
42
+ "types": "./env.d.ts"
43
+ },
40
44
  "./routes": {
41
45
  "types": "./dist/routes.d.mts",
42
46
  "import": "./dist/routes.mjs"
@@ -56,17 +60,13 @@
56
60
  "./vite": {
57
61
  "types": "./dist/vite.d.mts",
58
62
  "import": "./dist/vite.mjs"
59
- }
63
+ },
64
+ "./package.json": "./package.json"
60
65
  },
61
66
  "publishConfig": {
62
67
  "access": "public",
63
68
  "provenance": true
64
69
  },
65
- "scripts": {
66
- "build": "tsdown",
67
- "lint": "oxlint",
68
- "typecheck": "tsc --noEmit"
69
- },
70
70
  "dependencies": {
71
71
  "@hono/node-server": "^1.19.9",
72
72
  "@react-router/dev": "^7.13.1",
@@ -89,5 +89,10 @@
89
89
  },
90
90
  "engines": {
91
91
  "node": "^22.13.0 || >=24"
92
+ },
93
+ "scripts": {
94
+ "build": "tsdown",
95
+ "lint": "oxlint",
96
+ "typecheck": "tsc --noEmit"
92
97
  }
93
- }
98
+ }