@fastify/react 0.1.0 → 0.2.0-rc.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
@@ -1,90 +1,5 @@
1
- # fastify-dx-react [![NPM version](https://img.shields.io/npm/v/fastify-dx-react.svg?style=flat)](https://www.npmjs.com/package/fastify-dx-react) [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](https://standardjs.com/)
1
+ <br>
2
2
 
3
- - [**Introduction**](https://github.com/fastify/fastify-dx/blob/main/packages/fastify-dx-react/README.md#introduction)
4
- - [**Quick Start**](https://github.com/fastify/fastify-dx/blob/main/packages/fastify-dx-react/README.md#quick-start)
5
- - [**Package Scripts**](https://github.com/fastify/fastify-dx/blob/main/packages/fastify-dx-react/README.md#package-scripts)
6
- - [**Basic Setup**](https://github.com/fastify/fastify-dx/blob/main/docs/react/basic-setup.md)
7
- - [**Project Structure**](https://github.com/fastify/fastify-dx/blob/main/docs/react/project-structure.md)
8
- - [**Rendering Modes**](https://github.com/fastify/fastify-dx/blob/main/docs/react/rendering-modes.md)
9
- - [**Routing Configuration**](https://github.com/fastify/fastify-dx/blob/main/docs/react/routing-config.md)
10
- - [**Data Prefetching**](https://github.com/fastify/fastify-dx/blob/main/docs/react/data-prefetching.md)
11
- - [**Route Layouts**](https://github.com/fastify/fastify-dx/blob/main/docs/react/route-layouts.md)
12
- - [**Route Context**](https://github.com/fastify/fastify-dx/blob/main/docs/react/route-context.md)
13
- - [**Route Enter Event**](https://github.com/fastify/fastify-dx/blob/main/docs/react/route-enter.md)
14
- - [**Virtual Modules**](https://github.com/fastify/fastify-dx/blob/main/docs/react/virtual-modules.md)
3
+ **`@fastify/react`** is the official [**`@fastify/vite`**](https://fastify-vite.dev) renderer for React.
15
4
 
16
- ## Introduction
17
-
18
- **Fastify DX for React** is a renderer adapter for [**fastify-vite**](https://github.com/fastify/fastify-vite).
19
-
20
- It is a **fast**, **lightweight** alternative to Next.js and Remix packed with **Developer Experience** features.
21
-
22
- It has an extremely small core (~1k LOC total) and is built on top of [Fastify](https://github.com/fastify/fastify), [Vite](https://vitejs.dev/), [React Router](https://reactrouter.com/docs/en/v6) and [Valtio](https://github.com/pmndrs/valtio).
23
-
24
- [**See the release notes for the 0.0.1 alpha release**](https://github.com/fastify/fastify-dx/releases/tag/v0.0.1).
25
-
26
- > At this stage this project is mostly a [**one-man show**](https://github.com/sponsors/galvez), who's devoting all his free time to its completion. Contributions are extremely welcome, as well as bug reports for any issues you may find.
27
-
28
- In this first alpha release it's still missing a test suite. The same is true for [**fastify-vite**]().
29
-
30
- It'll move into **beta** status when test suites are added to both packages.
31
-
32
- ## Quick Start
33
-
34
- Ensure you have **Node v16+**.
35
-
36
- Make a copy of [**starters/react**](https://github.com/fastify/fastify-dx/tree/dev/starters/react). If you have [`degit`](https://github.com/Rich-Harris/degit), run the following from a new directory:
37
-
38
- ```bash
39
- degit fastify/fastify-dx/starters/react
40
- ```
41
-
42
- > **If you're starting a project from scratch**, you'll need these packages installed.
43
- >
44
- > ```bash
45
- > npm i fastify fastify-vite fastify-dx-react -P
46
- > npm i @vitejs/plugin-react -D
47
- > ```
48
-
49
-
50
- Run `npm install`.
51
-
52
- Run `npm run dev`.
53
-
54
- Visit `http://localhost:3000/`.
55
-
56
- ## What's Included
57
-
58
- That will get you a **starter template** with:
59
-
60
- - A minimal [Fastify](https://github.com/fastify/fastify) server.
61
- - Some dummy API routes.
62
- - A `pages/` folder with some [demo routes](https://github.com/fastify/fastify-dx/tree/dev/starters/react/client/pages).
63
- - All configuration files.
64
-
65
- It also includes some _**opinionated**_ essentials:
66
-
67
- - [**PostCSS Preset Env**](https://www.npmjs.com/package/postcss-preset-env) by [**Jonathan Neal**](https://github.com/jonathantneal), which enables [several modern CSS features](https://preset-env.cssdb.org/), such as [**CSS Nesting**](https://www.w3.org/TR/css-nesting-1/).
68
-
69
- - [**UnoCSS**](https://github.com/unocss/unocss) by [**Anthony Fu**](https://antfu.me/), which supports all [Tailwind utilities](https://uno.antfu.me/) and many other goodies through its [default preset](https://github.com/unocss/unocss/tree/main/packages/preset-uno).
70
-
71
- - [**Valtio**](https://github.com/pmndrs/valtio) by [**Daishi Kato**](https://blog.axlight.com/), with a global and SSR-ready store which you can use anywhere.
72
-
73
-
74
- ## Package Scripts
75
-
76
- `npm run dev` boots the development server.
77
-
78
- `npm run build` creates the production bundle.
79
-
80
- `npm run serve` serves the production bundle.
81
-
82
- ## Meta
83
-
84
- Created by [Jonas Galvez](https://github.com/sponsors/galvez), **Engineering Manager** and **Open Sourcerer** at [NearForm](https://nearform.com).
85
-
86
- ## Sponsors
87
-
88
- <a href="https://nearform.com"><img width="200px" src="https://user-images.githubusercontent.com/12291/172310344-594669fd-da4c-466b-a250-a898569dfea3.svg"></a>
89
-
90
- Also [**Duc-Thien Bui**](https://github.com/aecea) and [**Tom Preston-Werner**](https://github.com/mojombo) [via GitHub Sponsors](https://github.com/sponsors/galvez). _Thank you!_
5
+ See the [documentation suite](https://fastify-vite.dev) to learn more.
package/index.js CHANGED
@@ -4,11 +4,11 @@ import { Readable } from 'stream'
4
4
  // fastify-vite's minimal HTML templating function,
5
5
  // which extracts interpolation variables from comments
6
6
  // and returns a function with the generated code
7
- import { createHtmlTemplateFunction } from '@fastify/vite'
7
+ import { createHtmlTemplateFunction } from '@fastify/vite/utils'
8
8
 
9
9
  // Used to safely serialize JavaScript into
10
10
  // <script> tags, preventing a few types of attack
11
- import devalue from 'devalue'
11
+ import * as devalue from 'devalue'
12
12
 
13
13
  // Small SSR-ready library used to generate
14
14
  // <title>, <meta> and <link> elements
@@ -75,10 +75,10 @@ export function createHtmlFunction (source, scope, config) {
75
75
  ...!context.serverOnly && {
76
76
  hydration: (
77
77
  '<script>\n' +
78
- `window.route = ${devalue(context.toJSON())}\n` +
79
- `window.routes = ${devalue(routes.toJSON())}\n` +
78
+ `window.route = ${devalue.uneval(context.toJSON())}\n` +
79
+ `window.routes = ${devalue.uneval(routes.toJSON())}\n` +
80
80
  '</script>'
81
- )
81
+ ),
82
82
  },
83
83
  }),
84
84
  }))
package/package.json CHANGED
@@ -1,11 +1,9 @@
1
1
  {
2
- "scripts": {
3
- "lint": "eslint . --ext .js,.jsx --fix"
4
- },
5
2
  "type": "module",
6
3
  "main": "index.js",
7
4
  "name": "@fastify/react",
8
- "version": "0.1.0",
5
+ "description": "The official @fastify/vite renderer for React",
6
+ "version": "0.2.0-rc.1",
9
7
  "files": [
10
8
  "virtual/create.jsx",
11
9
  "virtual/create.tsx",
@@ -31,27 +29,32 @@
31
29
  "./plugin": "./plugin.cjs"
32
30
  },
33
31
  "dependencies": {
34
- "devalue": "^2.0.1",
35
- "history": "^5.3.0",
36
- "minipass": "^3.3.4",
32
+ "devalue": "latest",
33
+ "history": "latest",
34
+ "minipass": "latest",
37
35
  "react": "^18.2.0",
38
- "react-dom": "^18.2.0",
39
- "react-router-dom": "^6.4.3",
40
- "unihead": "^0.0.6",
41
- "valtio": "^1.7.2"
36
+ "react-dom": "latest",
37
+ "react-router-dom": "latest",
38
+ "unihead": "latest",
39
+ "valtio": "latest"
42
40
  },
43
41
  "devDependencies": {
44
- "@babel/eslint-parser": "^7.16.0",
45
- "@babel/preset-react": "^7.16.0",
46
- "@vitejs/plugin-react": "^2.2.0",
47
- "eslint": "^7.32.0",
48
- "eslint-config-standard": "^16.0.2",
49
- "eslint-plugin-import": "^2.22.1",
50
- "eslint-plugin-node": "^11.1.0",
51
- "eslint-plugin-promise": "^4.3.1",
52
- "eslint-plugin-react": "^7.29.4"
42
+ "@babel/eslint-parser": "latest",
43
+ "@babel/preset-react": "latest",
44
+ "eslint": "latest",
45
+ "eslint-config-standard": "latest",
46
+ "eslint-plugin-import": "latest",
47
+ "eslint-plugin-node": "latest",
48
+ "eslint-plugin-promise": "latest",
49
+ "eslint-plugin-react": "latest"
50
+ },
51
+ "peerDependencies": {
52
+ "@fastify/vite": "^5.0.2"
53
53
  },
54
54
  "publishConfig": {
55
55
  "access": "public"
56
+ },
57
+ "scripts": {
58
+ "lint": "eslint . --ext .js,.jsx --fix"
56
59
  }
57
- }
60
+ }
package/plugin.cjs CHANGED
@@ -3,7 +3,7 @@ const { dirname, join, resolve } = require('path')
3
3
  const { fileURLToPath } = require('url')
4
4
 
5
5
  function viteReactFastifyDX (config = {}) {
6
- const prefix = /^\/?dx:/
6
+ const prefix = /^\/:/
7
7
  const routing = Object.assign({
8
8
  globPattern: '/pages/**/*.(jsx|tsx)',
9
9
  paramPattern: /\[(\w+)\]/,
@@ -11,18 +11,13 @@ function viteReactFastifyDX (config = {}) {
11
11
  const virtualRoot = resolve(__dirname, 'virtual')
12
12
  const virtualModules = [
13
13
  'mount.js',
14
- 'mount.ts',
15
14
  'resource.js',
16
- 'resource.ts',
17
15
  'routes.js',
18
16
  'layouts.js',
19
17
  'create.jsx',
20
- 'create.tsx',
21
18
  'root.jsx',
22
- 'root.tsx',
23
19
  'layouts/',
24
20
  'context.js',
25
- 'context.ts',
26
21
  'core.jsx'
27
22
  ]
28
23
  virtualModules.includes = function (virtual) {
@@ -79,7 +74,7 @@ function viteReactFastifyDX (config = {}) {
79
74
  }
80
75
 
81
76
  return {
82
- name: 'vite-plugin-react-fastify-dx',
77
+ name: 'vite-plugin-fastify-react',
83
78
  config (config, { command }) {
84
79
  if (command === 'build' && config.build?.ssr) {
85
80
  config.build.rollupOptions = {
package/server/context.js CHANGED
@@ -1,4 +1,3 @@
1
-
2
1
  const routeContextInspect = Symbol.for('nodejs.util.inspect.custom')
3
2
 
4
3
  export default class RouteContext {
package/server/stream.js CHANGED
@@ -1,7 +1,6 @@
1
-
2
1
  // Helper to make the stream returned renderToPipeableStream()
3
2
  // behave like an event emitter and facilitate error handling in Fastify
4
- import Minipass from 'minipass'
3
+ import { Minipass } from 'minipass'
5
4
 
6
5
  // React 18's preferred server-side rendering function,
7
6
  // which enables the combination of React.lazy() and Suspense
package/virtual/core.jsx CHANGED
@@ -1,10 +1,10 @@
1
1
  import { createContext, useContext, useEffect } from 'react'
2
- import { useLocation, BrowserRouter, Routes, Route } from 'react-router-dom'
2
+ import { useLocation, BrowserRouter } from 'react-router-dom'
3
3
  import { StaticRouter } from 'react-router-dom/server.mjs'
4
4
  import { createPath } from 'history'
5
5
  import { proxy, useSnapshot } from 'valtio'
6
- import { waitResource, waitFetch } from '/dx:resource.js'
7
- import layouts from '/dx:layouts.js'
6
+ import { waitResource, waitFetch } from '/:resource.js'
7
+ import layouts from '/:layouts.js'
8
8
 
9
9
  export const isServer = import.meta.env.SSR
10
10
  export const Router = isServer ? StaticRouter : BrowserRouter
@@ -14,41 +14,13 @@ export function useRouteContext () {
14
14
  const routeContext = useContext(RouteContext)
15
15
  if (routeContext.state) {
16
16
  routeContext.snapshot = isServer
17
- ? routeContext.state
18
- : useSnapshot(routeContext.state)
17
+ ? routeContext.state ?? {}
18
+ : useSnapshot(routeContext.state ?? {})
19
19
  }
20
20
  return routeContext
21
21
  }
22
22
 
23
- export function DXApp ({
24
- url,
25
- routes,
26
- head,
27
- routeMap,
28
- ctxHydration,
29
- }) {
30
- return (
31
- <Router location={url}>
32
- <Routes>{
33
- routes.map(({ path, component: Component }) =>
34
- <Route
35
- key={path}
36
- path={path}
37
- element={
38
- <DXRoute
39
- head={head}
40
- ctxHydration={ctxHydration}
41
- ctx={routeMap[path]}>
42
- <Component />
43
- </DXRoute>
44
- } />,
45
- )
46
- }</Routes>
47
- </Router>
48
- )
49
- }
50
-
51
- export function DXRoute ({ head, ctxHydration, ctx, children }) {
23
+ export function AppRoute ({ head, ctxHydration, ctx, children }) {
52
24
  // If running on the server, assume all data
53
25
  // functions have already ran through the preHandler hook
54
26
  if (isServer) {
@@ -58,8 +30,8 @@ export function DXRoute ({ head, ctxHydration, ctx, children }) {
58
30
  ...ctx,
59
31
  ...ctxHydration,
60
32
  state: isServer
61
- ? ctxHydration.state
62
- : proxy(ctxHydration.state),
33
+ ? ctxHydration.state ?? {}
34
+ : proxy(ctxHydration.state ?? {}),
63
35
  }}>
64
36
  <Layout>
65
37
  {children}
@@ -134,8 +106,8 @@ export function DXRoute ({ head, ctxHydration, ctx, children }) {
134
106
  ...ctxHydration,
135
107
  ...ctx,
136
108
  state: isServer
137
- ? ctxHydration.state
138
- : proxy(ctxHydration.state),
109
+ ? ctxHydration.state ?? {}
110
+ : proxy(ctxHydration.state ?? {}),
139
111
  }}>
140
112
  <Layout>
141
113
  {children}
@@ -1,4 +1,4 @@
1
- import Root from '/dx:root.jsx'
1
+ import Root from '/:root.jsx'
2
2
 
3
3
  export default function create ({ url, ...serverInit }) {
4
4
  return (
@@ -1,6 +1,6 @@
1
1
  import { lazy } from 'react'
2
2
 
3
- const DefaultLayout = () => import('/dx:layouts/default.jsx')
3
+ const DefaultLayout = () => import('/:layouts/default.jsx')
4
4
 
5
5
  const appLayouts = import.meta.glob('/layouts/*.jsx')
6
6
 
package/virtual/mount.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import Head from 'unihead/client'
2
2
  import { createRoot, hydrateRoot } from 'react-dom/client'
3
3
 
4
- import create from '/dx:create.jsx'
5
- import routesPromise from '/dx:routes.js'
4
+ import create from '/:create.jsx'
5
+ import routesPromise from '/:routes.js'
6
6
 
7
7
  mount('main')
8
8
 
@@ -10,7 +10,7 @@ async function mount (target) {
10
10
  if (typeof target === 'string') {
11
11
  target = document.querySelector(target)
12
12
  }
13
- const context = await import('/dx:context.js')
13
+ const context = await import('/:context.js')
14
14
  const ctxHydration = await extendContext(window.route, context)
15
15
  const head = new Head(window.route.head, window.document)
16
16
  const resolvedRoutes = await routesPromise
@@ -1,4 +1,3 @@
1
-
2
1
  const fetchMap = new Map()
3
2
  const resourceMap = new Map()
4
3
 
package/virtual/root.jsx CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Suspense } from 'react'
2
2
  import { Routes, Route } from 'react-router-dom'
3
- import { Router, DXRoute } from '/dx:core.jsx'
3
+ import { Router, AppRoute } from '/:core.jsx'
4
4
 
5
5
  export default function Root ({ url, routes, head, ctxHydration, routeMap }) {
6
6
  return (
@@ -12,16 +12,16 @@ export default function Root ({ url, routes, head, ctxHydration, routeMap }) {
12
12
  key={path}
13
13
  path={path}
14
14
  element={
15
- <DXRoute
15
+ <AppRoute
16
16
  head={head}
17
17
  ctxHydration={ctxHydration}
18
18
  ctx={routeMap[path]}>
19
19
  <Component />
20
- </DXRoute>
20
+ </AppRoute>
21
21
  } />,
22
22
  )
23
23
  }</Routes>
24
24
  </Router>
25
25
  </Suspense>
26
26
  )
27
- }
27
+ }
@@ -1,4 +0,0 @@
1
- // This file serves as a placeholder
2
- // if no context.js file is provided
3
-
4
- export default () => {}
@@ -1,7 +0,0 @@
1
- import Root from '/dx:root.tsx'
2
-
3
- export default function create ({ url, ...serverInit }) {
4
- return (
5
- <Root url={url} {...serverInit} />
6
- )
7
- }
package/virtual/mount.ts DELETED
@@ -1,47 +0,0 @@
1
- import Head from 'unihead/client'
2
- import { createRoot, hydrateRoot } from 'react-dom/client'
3
-
4
- import create from '/dx:create.tsx'
5
- import routesPromise from '/dx:routes.js'
6
-
7
- mount('main')
8
-
9
- async function mount (target) {
10
- if (typeof target === 'string') {
11
- target = document.querySelector(target)
12
- }
13
- const context = await import('/dx:context.ts')
14
- const ctxHydration = await extendContext(window.route, context)
15
- const head = new Head(window.route.head, window.document)
16
- const resolvedRoutes = await routesPromise
17
- const routeMap = Object.fromEntries(
18
- resolvedRoutes.map((route) => [route.path, route]),
19
- )
20
-
21
- const app = create({
22
- head,
23
- ctxHydration,
24
- routes: window.routes,
25
- routeMap,
26
- })
27
- if (ctxHydration.clientOnly) {
28
- createRoot(target).render(app)
29
- } else {
30
- hydrateRoot(target, app)
31
- }
32
- }
33
-
34
- async function extendContext (ctx, {
35
- // The route context initialization function
36
- default: setter,
37
- // We destructure state here just to discard it from extra
38
- state,
39
- // Other named exports from context.js
40
- ...extra
41
- }) {
42
- Object.assign(ctx, extra)
43
- if (setter) {
44
- await setter(ctx)
45
- }
46
- return ctx
47
- }
package/virtual/root.tsx DELETED
@@ -1,27 +0,0 @@
1
- import { Suspense } from 'react'
2
- import { Routes, Route } from 'react-router-dom'
3
- import { Router, DXRoute } from '/dx:core.jsx'
4
-
5
- export default function Root ({ url, routes, head, ctxHydration, routeMap }) {
6
- return (
7
- <Suspense>
8
- <Router location={url}>
9
- <Routes>{
10
- routes.map(({ path, component: Component }) =>
11
- <Route
12
- key={path}
13
- path={path}
14
- element={
15
- <DXRoute
16
- head={head}
17
- ctxHydration={ctxHydration}
18
- ctx={routeMap[path]}>
19
- <Component />
20
- </DXRoute>
21
- } />,
22
- )
23
- }</Routes>
24
- </Router>
25
- </Suspense>
26
- )
27
- }