Skip to content

Commit

Permalink
Merge branch 'main' into add-renderable-error-contract
Browse files Browse the repository at this point in the history
  • Loading branch information
marcuspoehls committed Dec 11, 2023
2 parents 0cba632 + 3a35dbb commit ec18a61
Show file tree
Hide file tree
Showing 26 changed files with 873 additions and 369 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
strategy:
fail-fast: true
matrix:
node-version: [20.x, 21.2]
node-version: [20.x, 21.4]

name: Node ${{ matrix.node-version }}

Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,24 @@
- `get<R extends string> (key: string, defaultValue: R): R`
- `@supercharge/contracts`
- allow users to define only selected hashing driver constructros in `HashConfig#drivers`
- export a `ViteConfig` interface
- `@supercharge/core`
- bypass import cache when dynamically importing routes from file path
- `@supercharge/vite`
- create `vite` container binding
- add a `ViteConfig` instance wrapping a Vite configuration JS object (will be used by a config/vite.ts file)
- throw `InertiaPageNotFoundError` error when a given component is missing
- support `attributes` in the `vite` Handlebars helper: `{{ vite input="resources/js/app.js" attributes='data-turbo-track="reload" async' }}`

### Updated
- bump dependencies
- `@supercharge/vite`
- add Vite `^5.0.0` as a peer dependency

### Breaking Changes
- `@supercharge/vite`
- require Vite `>=4.0.0` as a peer dependency


## [4.0.0-alpha.1](https://github.com/supercharge/framework/compare/v4.0.0-alpha.0...v4.0.0-alpha.1) - 2023-11-18

Expand Down
2 changes: 2 additions & 0 deletions packages/contracts/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,5 @@ export { ViewConfigBuilder } from './view/config-builder.js'
export { ViewEngine, ViewSharedData } from './view/engine.js'
export { ViewBuilderCallback } from './view/response.js'
export { ViewResponseConfig } from './view/response-config.js'

export { ViteConfig } from './vite/config.js'
39 changes: 39 additions & 0 deletions packages/contracts/src/vite/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@

export interface ViteConfig {
/**
* Stores the URL used as a prefix when creating asset URLs. This could be a
* CDN URL for production builds. If empty, the created asset URL starts
* with a leading slash to serve it locally from the running server.
*
* @default `/build`
*/
assetsUrl?: string

/**
* Stores the path to the hot-reload file, relative from the application’s base directory.
*
* @default `<assetsUrl>/.vite/hot.json`
*/
hotReloadFilePath?: string

/**
* Stores the Vite manifest file path, relative from the application’s base directory.
*
* @default `<assetsUrl>/.vite/manifest.json`
*/
manifestFilePath?: string

/**
* Stores an object of attributes to apply on all HTML `script` tags.
*
* @default `{}`
*/
scriptAttributes?: Record<string, string | boolean>

/**
* Stores an object of attributes to apply on all HTML `style` tags.
*
* @default `{}`
*/
styleAttributes?: Record<string, string | boolean>
}
4 changes: 2 additions & 2 deletions packages/vite/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"supertest": "~6.3.3",
"typescript": "~5.3.3",
"uvu": "~0.5.6",
"vite": "~5.0.6"
"vite": "~5.0.7"
},
"engines": {
"node": ">=20"
Expand All @@ -49,7 +49,7 @@
],
"license": "MIT",
"peerDependencies": {
"vite": "^3.0.0 || ^4.0.0 || ^5.0.0"
"vite": ">=4.0.0"
},
"publishConfig": {
"access": "public"
Expand Down
113 changes: 113 additions & 0 deletions packages/vite/src/backend/vite-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@

import Path from 'node:path'
import { Str } from '@supercharge/strings'
import { ViteConfig as ViteConfigContract } from '@supercharge/contracts'

export class ViteConfig {
/**
* Stores the Vite config object.
*/
private readonly config: Required<ViteConfigContract>

/**
* Create a new instance.
*/
constructor (config: ViteConfigContract) {
this.config = this.createConfigFrom(config ?? {})
}

/**
* Returns a new instance for the given Vite `config`.
*/
static from (config: ViteConfigContract): ViteConfig {
return new this(config)
}

/**
* Returns the resolved Vite config.
*/
private createConfigFrom (config: Partial<ViteConfigContract> = {}): Required<ViteConfigContract> {
const assetsUrl = Str(
this.isCdnUrl(config.assetsUrl)
? config.assetsUrl
: Str(config.assetsUrl ?? '/build')
.ltrim('/')
.start('/')
)
.rtrim('/')
.get()

return {
assetsUrl,
hotReloadFilePath: config.hotReloadFilePath ?? Path.join(assetsUrl, '/.vite/hot.json'),
manifestFilePath: config.manifestFilePath ?? Path.join(assetsUrl, '.vite/manifest.json'),
styleAttributes: { ...config.styleAttributes },
scriptAttributes: { ...config.scriptAttributes },
}
}

/**
* Determine whether the given `assetsUrl` is a full URL.
*/
private isCdnUrl (assetsUrl: ViteConfigContract['assetsUrl']): assetsUrl is string {
if (!assetsUrl) {
return false
}

try {
const url = new URL(assetsUrl)

return url.protocol.startsWith('http')
} catch (error) {
return false
}
}

/**
* Returns the Vite config object.
*/
toJSON (): ViteConfigContract {
return {
assetsUrl: this.assetsUrl(),
hotReloadFilePath: this.hotReloadFilePath(),
manifestFilePath: this.manifestFilePath(),
styleAttributes: this.styleAttributes(),
scriptAttributes: this.scriptAttributes(),
}
}

/**
* Returns the Vite hot-reload file path. The hot-reload file contains the Vite dev server URL.
*/
hotReloadFilePath (): string {
return this.config.hotReloadFilePath
}

/**
* Returns the Vite manifest file path.
*/
manifestFilePath (): string {
return this.config.manifestFilePath
}

/**
* Returns the assets URL.
*/
assetsUrl (): string {
return this.config.assetsUrl
}

/**
* Returns the default attributes assigned to every `script` tag.
*/
scriptAttributes (): ViteConfigContract['scriptAttributes'] {
return this.config.scriptAttributes
}

/**
* Returns the default attributes assigned to every `style` tag.
*/
styleAttributes (): ViteConfigContract['styleAttributes'] {
return this.config.styleAttributes
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@

import { Vite } from './vite.js'
import { HelperOptions } from 'handlebars'
import { Application } from '@supercharge/contracts'

export class ViteHandlebarsHelper {
/**
* Stores the application instance.
* Stores the Vite config instance.
*/
private readonly app: Application
private readonly vite: Vite

/**
* Stores the Vite entrypoints for which we should generate HTML tags.
Expand All @@ -19,8 +18,11 @@ export class ViteHandlebarsHelper {
*/
private readonly handlebarsOptions: HelperOptions

constructor (app: Application, ...args: any[] | any[][]) {
this.app = app
/**
* Create a new instance.
*/
constructor (vite: Vite, ...args: any[] | any[][]) {
this.vite = vite
this.handlebarsOptions = args.pop()
this.entrypoints = this.findEntrypoints(...args)
}
Expand Down Expand Up @@ -57,15 +59,31 @@ export class ViteHandlebarsHelper {
* Splits the given `input` at the comma character and trims each value in the result.
*/
private resolveStringInput (input: string): string[] {
return input.split(',').map(entry => {
return entry.trim()
})
return input
.split(',')
.map(entry => entry.trim())
}

/**
* Generate the Vite CSS and JavaScript tags for the HTML header.
*/
generateTags (): string {
return Vite.generateTags(this.app, this.entrypoints)
return this.vite
.generateTagsFromEntrypoints(
this.entrypoints,
this.attributesFromOptionsHash()
)
.toString()
}

/**
* Returns the configured attributes from the Handlebars helper’s `attributes` hash object.
*/
private attributesFromOptionsHash (): string {
const attributes = this.handlebarsOptions.hash.attributes

return typeof attributes === 'string'
? attributes
: String(attributes ?? '')
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export class ViteManifest {
const chunk = this.manifest[entrypoint]

if (!chunk) {
throw new Error(`Entrypoint not found in manifest: ${entrypoint}`)
throw new Error(`Entrypoint not found in manifest: "${entrypoint}"`)
}

return chunk
Expand Down
Loading

0 comments on commit ec18a61

Please sign in to comment.