Skip to content
This repository has been archived by the owner on Nov 23, 2023. It is now read-only.

Commit

Permalink
Merge pull request #37 from fastify/solid-ts
Browse files Browse the repository at this point in the history
feat(solid): TypeScript support, starter template
  • Loading branch information
galvez authored Jul 9, 2022
2 parents c2cdcbb + 97e4f92 commit a09c36b
Show file tree
Hide file tree
Showing 33 changed files with 781 additions and 15 deletions.
6 changes: 5 additions & 1 deletion packages/fastify-dx-solid/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,19 @@
"type": "module",
"main": "index.js",
"name": "fastify-dx-solid",
"version": "0.0.3",
"version": "0.0.4",
"files": [
"virtual/create.jsx",
"virtual/create.tsx",
"virtual/root.jsx",
"virtual/root.tsx",
"virtual/route.jsx",
"virtual/layouts.js",
"virtual/layouts/default.jsx",
"virtual/context.js",
"virtual/context.ts",
"virtual/mount.js",
"virtual/mount.ts",
"virtual/core.js",
"virtual/routes.js",
"index.js",
Expand Down
6 changes: 5 additions & 1 deletion packages/fastify-dx-solid/plugin.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,23 @@ const { fileURLToPath } = require('url')
function viteSolidFastifyDX (config = {}) {
const prefix = /^\/?dx:/
const routing = Object.assign({
globPattern: '/pages/**/*.jsx',
globPattern: '/pages/**/*.(jsx|tsx)',
paramPattern: /\[(\w+)\]/,
}, config)
const virtualRoot = resolve(__dirname, 'virtual')
const virtualModules = [
'mount.js',
'mount.ts',
'resource.js',
'routes.js',
'layouts.js',
'create.jsx',
'create.tsx',
'root.jsx',
'root.tsx',
'layouts/',
'context.js',
'context.ts',
'route.jsx',
'core.js'
]
Expand Down
4 changes: 4 additions & 0 deletions packages/fastify-dx-solid/virtual/context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// This file serves as a placeholder
// if no context.js file is provided

export default () => {}
5 changes: 5 additions & 0 deletions packages/fastify-dx-solid/virtual/create.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import Root from '/dx:root.tsx'

export default function create ({ url, payload }) {
return () => <Root url={url} payload={payload} />
}
6 changes: 4 additions & 2 deletions packages/fastify-dx-solid/virtual/layouts.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import DefaultLayout from '/dx:layouts/default.jsx'

const appLayouts = import.meta.globEager('/layouts/*.jsx')
const appLayouts = import.meta.globEager('/layouts/*.(jsx|tsx)')

appLayouts['/layouts/default.jsx'] ??= DefaultLayout
if (!appLayouts['/layouts/default.jsx'] && !appLayouts['/layouts/default.tsx']) {
appLayouts['/layouts/default.jsx'] = DefaultLayout
}

export default Object.fromEntries(
Object.keys(appLayouts).map((path) => {
Expand Down
5 changes: 1 addition & 4 deletions packages/fastify-dx-solid/virtual/layouts/default.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import { children } from 'solid-js'

export default function Default (props) {
const c = children(() => props.children)
return (
<div class="contents">{c()}</div>
<div class="contents">{props.children}</div>
)
}
48 changes: 48 additions & 0 deletions packages/fastify-dx-solid/virtual/mount.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import Head from 'unihead/client'
import { render, hydrate } from 'solid-js/web'

import create from '/dx:create.tsx'
import routesPromise from '/dx:routes.js'

mount('main')

async function mount (target) {
if (typeof target === 'string') {
target = document.querySelector(target)
}
const context = await import('/dx:context.js')
const serverRoute = await extendContext(window.route, context)
const head = new Head(window.route.head, window.document)
const resolvedRoutes = await routesPromise
const routeMap = Object.fromEntries(
resolvedRoutes.map((route) => [route.path, route]),
)
const app = create({
payload: {
head,
serverRoute,
routes: window.routes,
routeMap,
},
})
if (serverRoute.clientOnly) {
render(() => app, target)
} else {
hydrate(() => app, target)
}
}

async function extendContext (ctx, {
// The route context initialization function
default: setter,
// We destructure state here just to discard it from extra
state,
// Other named exports from context.js
...extra
}) {
Object.assign(ctx, extra)
if (setter) {
await setter(ctx)
}
return ctx
}
28 changes: 28 additions & 0 deletions packages/fastify-dx-solid/virtual/root.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { createMutable } from 'solid-js/store'
import { Router, Routes, Route } from 'solid-app-router'
import DXRoute from '/dx:route.jsx'
import { isServer } from '/dx:core.js'

export default function Root (props) {
// eslint-disable-next-line solid/reactivity
props.payload.serverRoute.state = isServer
? props.payload.serverRoute.state
: createMutable(props.payload.serverRoute.state)
// This is so we can serialize state into the hydration payload after SSR is done
return (
<Router url={props.url}>
<Routes>{
// eslint-disable-next-line solid/prefer-for
props.payload.routes.map(route =>
<Route path={route.path} element={
<DXRoute
state={props.payload.serverRoute.state}
path={route.path}
payload={props.payload}
component={route.component} />
} />,
)
}</Routes>
</Router>
)
}
1 change: 1 addition & 0 deletions starters/solid-ts/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dist
19 changes: 19 additions & 0 deletions starters/solid-ts/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
parser: '@typescript-eslint/parser',
plugins: ['solid'],
extends: [
'eslint:recommended',
'standard-with-typescript',
'plugin:solid/typescript'
],
parserOptions: {
project: './tsconfig.json'
},
rules: {
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/strict-boolean-expressions': 'off',
'solid/reactivity': 'off',
'comma-dangle': ['error', 'always-multiline'],
'import/no-absolute-path': 'off',
},
}
84 changes: 84 additions & 0 deletions starters/solid-ts/client/assets/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
56 changes: 56 additions & 0 deletions starters/solid-ts/client/base.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
:root {
--color-base: #f1f1f1;
--color-highlight: #ff80ff;
}
html {
background: #222;
}
main {
width: 800px;
margin: 0 auto;
padding: 2em;
box-shadow: 5px 5px 30px rgba(0,0,0,0.4);
border-radius: 10px;
background-color: rgba(255, 255, 255, 0.1);
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: var(--color-base);
margin-top: 60px;
& a {
color: var(--color-highlight);
text-decoration: none;
font-weight: bold;
border-bottom: 1px solid var(--color-highlight);
&:hover {
color: #ffde00;
}
&:active {
color: #eecf00
}
}
& p {
font-size: 1.2em;
}
& ul {
& li {
&:not(:last-child) {
margin-bottom: 0.5em;
}
break-inside: avoid;
font-size: 1em;
}
}
& code {
color: #ffde00;
font-weight: bold;
font-family: 'Consolas', 'Andale Mono', monospace;
font-size: 0.9em;
}
& img {
width: 14em;
}
& button {
margin: 0 0.5em;
}
}
57 changes: 57 additions & 0 deletions starters/solid-ts/client/context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import ky from 'ky-universal'

interface User {
authenticated: boolean | null
}

interface State {
message: string | null
user: User | null
todoList: string[] | null
}

// This will eventually be provided by fastify-dx's core package
interface RouteContext {
server?: any
req?: any
reply?: any
actions: object
data: any
state: State
}

export default (ctx: RouteContext): void => {
if (ctx.server) {
ctx.state.todoList = ctx.server.db.todoList
}
}

export const $fetch = ky.extend({
prefixUrl: 'http://localhost:3000',
})

export const state = (): State => ({
message: null,
user: {
authenticated: false,
},
todoList: null,
})

export const actions = {
authenticate (state: State) {
state.user.authenticated = true
},
async addTodoItem (state: State, item) {
await $fetch.put('api/todo/items', {
json: { item },
})
state.todoList.push(item)
},
async removeTodoItem (state: State, index) {
await $fetch.delete('api/todo/items', {
json: { index },
})
state.todoList.splice(index, 1)
},
}
14 changes: 14 additions & 0 deletions starters/solid-ts/client/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="./base.css">
<!-- head -->
<!-- hydrationScript -->
</head>
<body>
<main><!-- element --></main>
</body>
<!-- hydration -->
<script type="module" src="/dx:mount.ts"></script>
</html>
Loading

0 comments on commit a09c36b

Please sign in to comment.