Skip to content

Commit

Permalink
Merge pull request #154 from supercharge/vite-refactorings
Browse files Browse the repository at this point in the history
Vite refactorings
  • Loading branch information
marcuspoehls authored Dec 11, 2023
2 parents b1c7356 + 85b1e04 commit 4163ece
Show file tree
Hide file tree
Showing 23 changed files with 857 additions and 367 deletions.
2 changes: 2 additions & 0 deletions packages/contracts/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,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>
}
2 changes: 1 addition & 1 deletion packages/vite/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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 4163ece

Please sign in to comment.