{"id":13727038,"url":"https://github.com/ggoodman/nostalgie","last_synced_at":"2025-09-01T03:07:23.129Z","repository":{"id":54295138,"uuid":"314930800","full_name":"ggoodman/nostalgie","owner":"ggoodman","description":"Nostalgie is an opinionated, full-stack, runtime-agnostic framework for building web apps and web pages using react.","archived":false,"fork":false,"pushed_at":"2022-05-10T15:04:55.000Z","size":3304,"stargazers_count":152,"open_issues_count":5,"forks_count":6,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-04-20T10:22:18.741Z","etag":null,"topics":["react","react-router","serverless","ssr"],"latest_commit_sha":null,"homepage":"https://nostalgie.dev","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ggoodman.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"docs/Contributing.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-11-22T00:36:27.000Z","updated_at":"2025-03-02T22:36:53.000Z","dependencies_parsed_at":"2022-08-13T11:10:50.789Z","dependency_job_id":null,"html_url":"https://github.com/ggoodman/nostalgie","commit_stats":null,"previous_names":[],"tags_count":45,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ggoodman%2Fnostalgie","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ggoodman%2Fnostalgie/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ggoodman%2Fnostalgie/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ggoodman%2Fnostalgie/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ggoodman","download_url":"https://codeload.github.com/ggoodman/nostalgie/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251494018,"owners_count":21598218,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["react","react-router","serverless","ssr"],"created_at":"2024-08-03T01:03:36.775Z","updated_at":"2025-04-29T11:32:07.502Z","avatar_url":"https://github.com/ggoodman.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"# Nostalgie\n\n![npm (scoped)](https://img.shields.io/npm/v/nostalgie?style=flat-square)\n![NPM](https://img.shields.io/npm/l/nostalgie?style=flat-square)\n\nNostalgie is an opinionated, full-stack, runtime-agnostic framework for building web apps and web pages using [react](https://reactjs.org).\n\nSee below for our [Vision](#vision).\n\n**Nostalgie is looking for contributions!**\n\nWe've written up a detailed [Contribution Guide](./docs/Contributing.md) to help get acquainted with Nostalgie's codebase and architecture.\n\nWe look forward to seeing you getting involved!\n\n## Getting started\n\nPlease see the [Getting Started](./docs/tutorials/Getting%20Started.md) page for a complete tutorial from nothing to Nostalgie app in 30 seconds.\n\n### Installing `nostalgie`\n\nWe can install it globally to keep things simple. The main entrypoint is a CLI called `nostalgie`.\n\n```sh\nnpm install -g nostalgie\n```\n\nAlternatively, we can use `npx nostalgie` anywhere you see us calling `nostalgie` directly below.\n\n### Project structure\n\nFor now, `nostalgie` doesn't provide any tooling to help scaffold out a project and makes some assumptions about how your project should be structured. Later, we plan to add the ability to allow projects to configure the structure.\n\n#### Application entrypoint\n\n\u003e **Default: `./src/App.[jsx|tsx]`**\n\u003e\n\u003e _Note: This file must exist._\n\nNostalgie expects to find a `./src/App.[jsx|tsx]` file that it will treat as the only entrypoint into your application. It uses `react-router` behind the scenes to unify front- and back-end routing. Nostalgie is _NOT_ organized on the basis of filesystem routing. Instead, it is expected that your application entrypoint makes all routing decisions.\n\nFor example, if you want `/` (home) and `/docs` (docs) routes, you might have an `./src/App.tsx` file like the following. In this example, we've effectively declared two routes and have code-splitting supported between them but we're not married to that sort of thinking.\n\n```tsx\nimport { Switch, Route } from 'nostalgie';\nimport * as React from 'react';\n\nconst LazyDocsPage = React.lazy(() =\u003e import('./pages/Docs'));\nconst LazyHomePage = React.lazy(() =\u003e import('./pages/Home'));\n\nexport default function App() {\n  return (\n    \u003cSwitch\u003e\n      \u003cRoute exact path=\"/\"\u003e\n        \u003cLazyHomePage /\u003e\n      \u003c/Route\u003e\n      \u003cRoute path=\"/docs\"\u003e\n        \u003cLazyDocsPage /\u003e\n      \u003c/Route\u003e\n    \u003c/Switch\u003e\n  );\n}\n```\n\n#### Functions entrypoint\n\n\u003e **Default: `./src/functions.[js|ts]`**\n\u003e\n\u003e _Note: When this file does not exist, function support is disabled._\n\nIn Nostalgie, invoking server-side code has never been easier. Nostalgie abstracts away the complexity of invoking server-side logic from the frontend in a way that these functions can be called either at runtime in the browser, or at render-time on the server.\n\nCreating an exposing a function to your application code is as simple as defining and exporting a function. All server functions _must_ be exported by the functions entrypoint but their actual logic can be imported from other files. You can structure this as you choose.\n\nAuthentication is not yet implemented but the `ctx` argument is already wired up and this will be the place where identity metadata will be made available.\n\n```ts\nimport type { ServerFunctionContext } from 'nostalgie';\n\nconst posts = {\n  {\n    id: 1,\n    title: 'Introducing Nostalgie',\n    body: '...',\n    author: 'ggoodman',\n  },\n  {\n    id: 2,\n    title: 'Introducing MDX support',\n    body: '...',\n    author: 'cooldood42',\n  },\n};\n\nexport function getBlogPosts(ctx: ServerFunctionContext, author?: string) {\n  return author ? posts.filter(post =\u003e post.author === author) : posts;\n}\n```\n\nIf we want to use this function from our application code, we use the `useQueryFunction` hook exposed by `nostalgie/functions`. Note that we also import a reference to the _actual_ function. This might sound surprising because that function often won't be able to execute in the browser context. In fact, we probably don't want it and its dependencies increasing the size of our front-end bundle(s). Have no fear, since Nostalgie is also responsible for packaging applications, it will actually replace the functions entrypoint (and any transient dependencies) with a simple object providing the metadata about which functions exist. Importing a reference to the actual function also has the side benefit of helping us get accurate type hints. When using `useQueryFunction` below, we will be hinted with the names and types of the arguments array. We will also have full type hinting for the `blogPosts` value.\n\nBehind the scenes, the `useQueryFunction` hook is delegating to [`useQuery`](https://react-query.tanstack.com/reference/useQuery) from [react-query](https://github.com/tannerlinsley/react-query). As a result, the returned `blogPosts` object is an observer of the query. In fact, we could have provided a third argument to `useQueryFunction` to set caching and other options as supported by [`useQuery`](https://react-query.tanstack.com/reference/useQuery).\n\n```tsx\nimport * as React from 'react';\nimport { useQueryFunction } from 'nostalgie/functions';\nimport BlogPost from './BlogPost';\nimport { getBlogPosts } from './functions';\n\nexport default function BlogPostList() {\n  const blogPosts = useQueryFunction(getBlogPosts, ['ggoodman']);\n\n  if (blogPosts.isLoading) return 'Loading...';\n\n  if (blogPosts.error) return 'An error has occurred: ' + blogPosts.error.message;\n\n  return (\n    \u003cdiv\u003e\n      {blogPosts.data.map((post) =\u003e (\n        \u003cBlogPost key={post.id} post={post} /\u003e\n      ))}\n    \u003c/div\u003e\n  );\n}\n```\n\n### Development workflow\n\nOnce you've scaffolded your Nostalgie project, you're ready to start developing it. The `nostalgie` cli supports a `dev` command to make this easy. It will build your app and run it. Anytime you make changes to your app, it will stop the server, rebuild your app and restart the server. Because we're using [`esbuild`](https://github.com/evanw/esbuild), compilation should be an order of magnitude faster than tools you might be used to using.\n\n```sh\nnostalgie dev --port 9090 --env development --root-dir ./example\n```\n\nTo see other available options:\n\n```sh\nnostalgie dev --help\n```\n\n### Production workflow\n\nNow that you've built and played with your app locally, it's time to deploy. Nostalgie will eventually support building for many different targets. For the time being, it only supports a node or dockerized node environment.\n\n```sh\nnostalgie build --root-dir ./example\n```\n\nThe above will produce artifacts in the `./example/build` directory, suitable for running the application locally via `node ./example/build` or via docker using the `./example/build/Dockerfile`. Nostalgie build artifacts have no further build steps required and do not require any `node_modules` at runtime.\n\n## Vision\n\nNostalgie removes many of the difficult, contentious decisions from the equation when building for the web. It aims to make it easier than ever to build server-side-rendered (SSR) apps that can be deployed anywhere and that take full advantage of modern facilities like:\n\n- **Code splitting**: React introduced `React.lazy` as the idiomatic way to introduce code splitting boundaries. Unfortunately, it was quite hard to integrate into SSR apps, leaving projects like [loadable components](https://loadable-components.com/) to fill the gap. Nostalgie makes `React.lazy` work out of the box with SSR and Suspense. You decide where you want to split things up using `React.lazy`, using dynamic `import()` expressions and we wire things up so that it _just works_.\n\n- **Routing**: Nested, hierarchical routing using [react-router v5](https://github.com/ReactTraining/react-router) is the future. This lets you ship those glorious top-level page transitions you desperately wanted but couldn't get in your favourite react SSR framework. With Nostalgie, you control the **whole** page.\n\n- **SEO**: Full control over the top-level markup and meta tags rendered by the server using [react-helmet-async](https://github.com/staylor/react-helmet-async). Set your title, meta tags and many others right from within your react components.\n\n- **Styling**: Built-in integration with [tailwind.css](https://tailwindcss.com/) via [`twind`](https://github.com/tw-in-js/twind). Stop worrying about the hard parts of scalable CSS and catch the tropical breeze.\n\n- **Serverless functions**: Expose functions that should run on the back-end directly to the front-end without worrying about http and fetch. You define your back-end functions and call it directly from the front-end using the `useQueryFunction` and `useMutationFunction` hooks. These hooks are automatically wired up to your back-end functions and the built-in authentication system. These delegate to the [`useQuery`]() and [`useMutation`]() hooks exposed by the excellent [`react-query`]() library. Functions results will be automatically included in server-side-rendered pages (up to a configurable time budget deadline). On the client, render while you fetch and move on to getting the business logic shipped.\n\n- **Authentication**: Built-in authentication with any OpenID-compliant issuer. When configured with an OpenID issuer, Nostalgie exposes a `useAuth` hook that provides a `.loginUrl` and `.logoutUrl`. Easily authenticate users and benefit from full awareness of visitor identity both during server-side and client-side rendering. Your server functions will automatically be provided with the identity and authentication state of the visitor and can easily make authorization decisions or authenticated calls to other APIs with the full security of the server-side environment.\n\n## FAQ\n\n### Why React?\n\nWhile we do love alternative libraries (❤️ svelte), _no one ever got fired for choosing React_. This is where the ecosystem and the mind share lives right now. Using anything but React means both: 1) convincing people to use something other than React; and 2) convincing people to try Nostalgie. For now, we decided to focus on the biggest user-base with some ideas to branch out later.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fggoodman%2Fnostalgie","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fggoodman%2Fnostalgie","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fggoodman%2Fnostalgie/lists"}