Skip to content

Commit

Permalink
✨ feat(minor): add bud.spa single page application facade
Browse files Browse the repository at this point in the history
  • Loading branch information
kellymears committed Jul 28, 2024
1 parent 2e69ec6 commit e8d270c
Show file tree
Hide file tree
Showing 8 changed files with 184 additions and 16 deletions.
16 changes: 16 additions & 0 deletions sources/@repo/docs/content/reference/bud.spa/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
title: bud.spa
description: Configure the development server for single page applications
custom_edit_url: 'https://github.com/roots/bud/tree/main/sources/@roots/bud-api/docs/spa'
tags:
- dev
---

import Overview from '@site/../../@roots/bud-api/docs/spa/overview.md'
import Usage from '@site/../../@roots/bud-api/docs/spa/usage.md'

<Overview />

## Usage

<Usage />
32 changes: 16 additions & 16 deletions sources/@repo/yarn-plugin-bud/bundles/@yarnpkg/plugin-bud.js

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions sources/@roots/bud-api/docs/spa/overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
title: bud.spa
---

**bud.spa** configures the development server for single page applications using client routers (like React Router).
39 changes: 39 additions & 0 deletions sources/@roots/bud-api/docs/spa/usage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
title: Usage
---

Call **bud.spa** to enable configure bud.js for single page applications.

It is fine to call **bud.spa** with no parameters. bud.js will use a default port:

```ts title=bud.config.ts
export default async bud => {
bud.spa()
}
```

If you want to configure beyond the defaults you may do so using a string, number or URL.

Using a string:

```ts title=bud.config.ts
export default async bud => {
bud.spa(`http://localhost:3030`)
}
```

Using a [URL](https://developer.mozilla.org/en-US/docs/Web/API/URL):

```ts title=bud.config.ts
export default async bud => {
bud.spa(new URL(`http://localhost:3030`))
}
```

Using a number:

```ts title=bud.config.ts
export default async bud => {
bud.spa(3030)
}
```
8 changes: 8 additions & 0 deletions sources/@roots/bud-api/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import type * as SetProxyUrl from '@roots/bud-api/methods/setProxyUrl'
import type * as SetPublicProxyUrl from '@roots/bud-api/methods/setPublicProxyUrl'
import type * as SetPublicUrl from '@roots/bud-api/methods/setPublicUrl'
import type * as SetUrl from '@roots/bud-api/methods/setUrl'
import type * as Spa from '@roots/bud-api/methods/spa'
import type * as SplitChunks from '@roots/bud-api/methods/splitChunks'
import type * as Use from '@roots/bud-api/methods/use'
import type * as Watch from '@roots/bud-api/methods/watch'
Expand Down Expand Up @@ -328,6 +329,13 @@ declare module '@roots/bud-framework' {
*/
setUrl(...params: SetUrl.Parameters): Bud

/**
* ## bud.spa
*
* {@link https://bud.js.org/docs/bud.spa 📕 Documentation}
*/
spa(...params: Spa.Parameters): Bud

/**
* ## bud.splitChunks
*
Expand Down
1 change: 1 addition & 0 deletions sources/@roots/bud-api/src/methods/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export {setProxyUrl} from '@roots/bud-api/methods/setProxyUrl'
export {setPublicProxyUrl} from '@roots/bud-api/methods/setPublicProxyUrl'
export {setPublicUrl} from '@roots/bud-api/methods/setPublicUrl'
export {setUrl} from '@roots/bud-api/methods/setUrl'
export {spa} from '@roots/bud-api/methods/spa'
export {splitChunks} from '@roots/bud-api/methods/splitChunks'
export {use} from '@roots/bud-api/methods/use'
export {watch} from '@roots/bud-api/methods/watch'
23 changes: 23 additions & 0 deletions sources/@roots/bud-api/src/methods/spa/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import {Bud} from '@roots/bud-framework'

export type Parameters = [(number | string | URL)?]

export interface spa {
(...parameters: Parameters): Bud
}

export const spa: spa = function (this: Bud, devUrl) {
if (!this.isDevelopment) {
return this
}

let serverUrl = devUrl ?? this.server?.url.toString() ?? 3000

this.api.logger.log(`bud.spa:`, `configured with`, devUrl)

this.setUrl(serverUrl)
this.setProxyUrl(serverUrl)
this.hooks.on(`dev.middleware.proxy.options.ignorePath`, true)

return this
}
76 changes: 76 additions & 0 deletions sources/@roots/bud-api/test/spa.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import {beforeEach, describe, expect, it, vi} from 'vitest'

import {spa as spaFn} from '../src/methods/spa'

describe(`@roots/bud-api/methods/spa`, () => {
let bud: any
let spa: spaFn

beforeEach(async () => {
bud = {
api: {
logger: {
log: vi.fn(() => null),
},
},
hooks: {
on: vi.fn(() => null),
},
isDevelopment: true,
server: {
url: `http://0.0.0.0:3000`,
},
setProxyUrl: vi.fn(() => null),
setUrl: vi.fn(() => null),
}

spa = spaFn.bind(bud)
})

it(`should call bud.setUrl`, () => {
spa(`https://example.com:3030`)
expect(bud.setUrl).toHaveBeenCalledWith(`https://example.com:3030`)

spa(3030)
expect(bud.setUrl).toHaveBeenCalledWith(3030)

const url = new URL(`https://example.com`)
spa(url)
expect(bud.setUrl).toHaveBeenCalledWith(url)

spa()
expect(bud.setUrl).toHaveBeenCalledWith(bud.server.url)
})

it(`should call bud.setProxyUrl`, () => {
spa(`https://example.com:3030`)
expect(bud.setProxyUrl).toHaveBeenCalledWith(
`https://example.com:3030`,
)

spa(3030)
expect(bud.setProxyUrl).toHaveBeenCalledWith(3030)

const url = new URL(`https://example.com:3030`)
spa(url)
expect(bud.setProxyUrl).toHaveBeenCalledWith(url)
})

it(`should call bud.hooks.on`, () => {
spa()

expect(bud.hooks.on).toHaveBeenCalledWith(
`dev.middleware.proxy.options.ignorePath`,
true,
)
})

it(`should bail when bud.isDevelopment is false`, () => {
bud.isDevelopment = false
spa()

expect(bud.setUrl).not.toHaveBeenCalled()
expect(bud.setProxyUrl).not.toHaveBeenCalled()
expect(bud.hooks.on).not.toHaveBeenCalled()
})
})

0 comments on commit e8d270c

Please sign in to comment.