Skip to content

Instantly share code, notes, and snippets.

@tricoder42
Last active February 10, 2023 08:54
Show Gist options
  • Save tricoder42/bbfcc9a946db105cf2d13b51d78b268c to your computer and use it in GitHub Desktop.
Save tricoder42/bbfcc9a946db105cf2d13b51d78b268c to your computer and use it in GitHub Desktop.

Revisions

  1. tricoder42 revised this gist May 14, 2019. 1 changed file with 6 additions and 0 deletions.
    6 changes: 6 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -77,12 +77,18 @@ export default () => {
    ## Summary

    ✅ this can be build on top of current Next.js API

    ✅ centralized route config with minimal footprint in bundle

    ✅ global server handler is used only for development. Pages in production can be served in serverless fashion.

    🚫 requires extra compile step to prepare `now.json` and `links.ts`


    ## Implementation details

    Current implementation of helpers which I use in previous examples. Not important for the concept.

    ### `makeRouteConfig`

    Little helper to create routeConfig object.
  2. tricoder42 revised this gist May 14, 2019. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -7,7 +7,7 @@ I believe the automation is the last step to make it completely seamless.

    This is the only file that needs to be wrote manually.

    ```
    ```ts
    //route.config.ts

    const routeConfig = {
    @@ -52,10 +52,10 @@ declare const ArticleLink = React.ElementType<CustomLinkProps<AboutLinkParams>>

    ```json
    {
    "routes": {
    "routes": [
    { "src": "/about", "dest": "/about.js" },
    { "src": "/article/(?<id>[^/]*)", "dest": "/article.js?id=$id" },
    }
    ]
    }
    ```

  3. tricoder42 created this gist May 14, 2019.
    143 changes: 143 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,143 @@
    I'm using this approach to have centralized route config in Next.js. I don't have the fully automated solution.
    Right now I'm writing route configs and links manually to figure out if it works and what are the drawbacks.

    I believe the automation is the last step to make it completely seamless.

    ## 1. Define routes in centralized config

    This is the only file that needs to be wrote manually.

    ```
    //route.config.ts
    const routeConfig = {
    // url: filename inside `pages`
    '/about': '/about',
    '/article/:id': '/article',
    }
    ```

    ## 2. Links and route configs are generated

    Only imported Links/routes are included in bundle, everything else is stripped down using tree-shaking.

    Each route is transformed into `routeConfig` and custom `Link` component. `routeConfig`
    can be used for imperative routing (e.g. `Router.push`), while custom `Link` is
    used in JSX for declarative routing.

    ```ts
    // links.ts
    // generated from route.config.ts

    export const about = makeRouteConfig("/about")
    export const AboutLink = makeLink(about)

    export const article = makeRouteConfig("/article/:id", "/article")
    export const ArticleLink = makeLink(article)
    ```

    As a bonus, links can be typechecked:

    ```ts
    // links.d.ts
    interface CustomLinkProps<Params> extends LinkProps {
    params: Params
    }

    interface ArticleLinkParams {}
    declare const ArticleLink = React.ElementType<CustomLinkProps<AboutLinkParams>>
    ```

    ## 3. now.json is generated as well

    ```json
    {
    "routes": {
    { "src": "/about", "dest": "/about.js" },
    { "src": "/article/(?<id>[^/]*)", "dest": "/article.js?id=$id" },
    }
    }
    ```

    ## 4. Example

    ```ts
    // pages/index.ts

    import { AboutLink, ArticleLink } from "../links"

    export default () => {
    <nav>
    <AboutLink>About</AboutLink>
    <ArticleLink params={{id: "42"}}>Answering the ultimate question</ArticleLink>
    </nav>
    }
    ```

    ## Summary

    ✅ this can be build on top of current Next.js API
    ✅ centralized route config with minimal footprint in bundle
    ✅ global server handler is used only for development. Pages in production can be served in serverless fashion.
    🚫 requires extra compile step to prepare `now.json` and `links.ts`

    ## Implementation details

    ### `makeRouteConfig`

    Little helper to create routeConfig object.

    ```ts
    export interface RouteConfig {
    path: string
    as: string
    }

    export function makeRouteConfig(as: string, path?: string): RouteConfig {
    if (process.env.NODE_ENV !== "production") {
    if (!as.startsWith("/")) {
    throw Error(`path ${as} should start with /`)
    }
    }

    return {
    as,
    path: path != null ? path : as
    }
    }
    ```

    ### `makeLink`

    Factory to make custom `Link` with `href` and `as` attributes
    filled automatically based on `routeConfig` object

    ```ts
    import * as React from "react"
    import Link, { LinkProps } from "next/link"
    import { reverse, RouteConfig } from "accent/core/routes"

    export interface RouteLinkProps extends LinkProps {
    params?: { [key: string]: string }
    }

    // Create customized Link component, which fills `href` and `as` props based on routeConfig
    export const makeLink = (routeConfig: RouteConfig) => ({
    params,
    children,
    ...linkProps
    }: RouteLinkProps) => {
    const href = {
    pathname: routeConfig.path,
    query: params
    }

    const as = params == null ? routeConfig.as : reverse(routeConfig, params)

    return (
    <Link href={href} as={as} {...linkProps}>
    {children}
    </Link>
    )
    }
    ```