@adonisjs/vite 0.0.1-0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +9 -0
- package/README.md +36 -0
- package/build/configure.d.ts +3 -0
- package/build/configure.d.ts.map +1 -0
- package/build/configure.js +13 -0
- package/build/index.d.ts +5 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +4 -0
- package/build/providers/vite_provider.d.ts +10 -0
- package/build/providers/vite_provider.d.ts.map +1 -0
- package/build/providers/vite_provider.js +48 -0
- package/build/services/vite.d.ts +4 -0
- package/build/services/vite.d.ts.map +1 -0
- package/build/services/vite.js +6 -0
- package/build/src/backend/types/extended.d.ts +7 -0
- package/build/src/backend/types/extended.d.ts.map +1 -0
- package/build/src/backend/types/extended.js +1 -0
- package/build/src/backend/types/main.d.ts +9 -0
- package/build/src/backend/types/main.d.ts.map +1 -0
- package/build/src/backend/types/main.js +1 -0
- package/build/src/backend/utils.d.ts +2 -0
- package/build/src/backend/utils.d.ts.map +1 -0
- package/build/src/backend/utils.js +7 -0
- package/build/src/backend/vite.d.ts +19 -0
- package/build/src/backend/vite.d.ts.map +1 -0
- package/build/src/backend/vite.js +182 -0
- package/build/src/vite_plugin/config.d.ts +5 -0
- package/build/src/vite_plugin/config.d.ts.map +1 -0
- package/build/src/vite_plugin/config.js +47 -0
- package/build/src/vite_plugin/config_resolver.d.ts +9 -0
- package/build/src/vite_plugin/config_resolver.d.ts.map +1 -0
- package/build/src/vite_plugin/config_resolver.js +27 -0
- package/build/src/vite_plugin/helpers/inertia.d.ts +2 -0
- package/build/src/vite_plugin/helpers/inertia.d.ts.map +1 -0
- package/build/src/vite_plugin/helpers/inertia.js +11 -0
- package/build/src/vite_plugin/hot_file.d.ts +9 -0
- package/build/src/vite_plugin/hot_file.d.ts.map +1 -0
- package/build/src/vite_plugin/hot_file.js +30 -0
- package/build/src/vite_plugin/index.d.ts +4 -0
- package/build/src/vite_plugin/index.d.ts.map +1 -0
- package/build/src/vite_plugin/index.js +16 -0
- package/build/src/vite_plugin/types/index.d.ts +10 -0
- package/build/src/vite_plugin/types/index.d.ts.map +1 -0
- package/build/src/vite_plugin/types/index.js +1 -0
- package/build/src/vite_plugin/utils.d.ts +5 -0
- package/build/src/vite_plugin/utils.d.ts.map +1 -0
- package/build/src/vite_plugin/utils.js +16 -0
- package/build/stubs/index.d.ts +2 -0
- package/build/stubs/index.d.ts.map +1 -0
- package/build/stubs/index.js +2 -0
- package/build/stubs/vite/vite_config.stub +14 -0
- package/configure.ts +30 -0
- package/index.ts +15 -0
- package/package.json +147 -0
- package/providers/vite_provider.ts +89 -0
- package/services/vite.ts +23 -0
- package/src/backend/types/extended.ts +19 -0
- package/src/backend/types/main.ts +31 -0
- package/src/backend/utils.ts +19 -0
- package/src/backend/vite.ts +367 -0
- package/src/vite_plugin/config.ts +97 -0
- package/src/vite_plugin/config_resolver.ts +62 -0
- package/src/vite_plugin/helpers/inertia.ts +27 -0
- package/src/vite_plugin/hot_file.ts +59 -0
- package/src/vite_plugin/index.ts +38 -0
- package/src/vite_plugin/types/index.ts +56 -0
- package/src/vite_plugin/utils.ts +40 -0
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/vite
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { join } from 'node:path'
|
|
11
|
+
import type { Manifest } from 'vite'
|
|
12
|
+
import { fileURLToPath } from 'node:url'
|
|
13
|
+
import { HotFile, SetAttributes } from './types/main.js'
|
|
14
|
+
import { existsSync, readFileSync } from 'node:fs'
|
|
15
|
+
import { ApplicationService } from '@adonisjs/core/types'
|
|
16
|
+
import { uniqBy } from './utils.js'
|
|
17
|
+
|
|
18
|
+
export class Vite {
|
|
19
|
+
/**
|
|
20
|
+
* Path to the build directory
|
|
21
|
+
*
|
|
22
|
+
* @default 'public/assets'
|
|
23
|
+
*/
|
|
24
|
+
#buildDirectory: string
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Path to the hotfile
|
|
28
|
+
*
|
|
29
|
+
* @default 'public/assets/hot.json'
|
|
30
|
+
*/
|
|
31
|
+
#hotFile: string
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Manifest file name
|
|
35
|
+
*/
|
|
36
|
+
#manifestFilename = 'manifest.json'
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Assets URL
|
|
40
|
+
*/
|
|
41
|
+
#assetsUrl = ''
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* We cache the manifest file content in production
|
|
45
|
+
* to avoid reading the file multiple times
|
|
46
|
+
*/
|
|
47
|
+
#manifestCache: Manifest | null = null
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Attributes to be set on the style tags
|
|
51
|
+
*/
|
|
52
|
+
#styleAttributes: SetAttributes = {}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Attributes to be set on the script tags
|
|
56
|
+
*/
|
|
57
|
+
#scriptAttributes: SetAttributes = {}
|
|
58
|
+
|
|
59
|
+
constructor(private application: ApplicationService) {
|
|
60
|
+
this.#buildDirectory = this.application.publicPath('assets')
|
|
61
|
+
this.#hotFile = join(this.#buildDirectory, 'hot.json')
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Checks if the application is running in hot mode
|
|
66
|
+
*/
|
|
67
|
+
#isRunningHot(): boolean {
|
|
68
|
+
return existsSync(this.#hotFile)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Reads the file contents as JSON
|
|
73
|
+
*/
|
|
74
|
+
#readFileAsJSON(filePath: string) {
|
|
75
|
+
return JSON.parse(readFileSync(filePath, 'utf-8'))
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Returns the parsed hot file content
|
|
80
|
+
*/
|
|
81
|
+
#readHotFile(): HotFile {
|
|
82
|
+
return this.#readFileAsJSON(this.#hotFile)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Get the path to an asset when running in hot mode
|
|
87
|
+
*/
|
|
88
|
+
#hotAsset(asset: string) {
|
|
89
|
+
return this.#readHotFile().url + '/' + asset
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Returns the script needed for the HMR working with Vite
|
|
94
|
+
*/
|
|
95
|
+
#getViteHmrScript(): string {
|
|
96
|
+
if (!this.#isRunningHot()) {
|
|
97
|
+
return ''
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return `<script type="module" src="${this.#hotAsset('@vite/client')}"></script>`
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Generate style and script tags for the given entrypoints
|
|
105
|
+
* Also add the @vite/client script
|
|
106
|
+
*/
|
|
107
|
+
#generateEntryPointsTagsForHotmode(entryPoints: string[]): string {
|
|
108
|
+
const viteHmr = this.#getViteHmrScript()
|
|
109
|
+
const tags = entryPoints.map((entrypoint) => this.#generateTag(entrypoint))
|
|
110
|
+
|
|
111
|
+
return [viteHmr, ...tags].join('\n')
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Generate style and script tags for the given entrypoints
|
|
116
|
+
* using the manifest file
|
|
117
|
+
*/
|
|
118
|
+
#generateEntryPointsTagsWithManifest(entryPoints: string[]): string {
|
|
119
|
+
const manifest = this.manifest()
|
|
120
|
+
const tags: { path: string; tag: string }[] = []
|
|
121
|
+
|
|
122
|
+
for (const entryPoint of entryPoints) {
|
|
123
|
+
const chunk = this.#chunk(manifest, entryPoint)
|
|
124
|
+
tags.push({ path: chunk.file, tag: this.#generateTag(chunk.file) })
|
|
125
|
+
|
|
126
|
+
for (const css of chunk.css || []) {
|
|
127
|
+
const cssChunk = this.#chunkByFile(manifest, css)
|
|
128
|
+
tags.push({ path: cssChunk.file, tag: this.#generateTag(cssChunk.file) })
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return uniqBy(tags, 'path')
|
|
133
|
+
.sort((a) => (a.path.endsWith('.css') ? -1 : 1))
|
|
134
|
+
.map((preload) => preload.tag)
|
|
135
|
+
.join('\n')
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Generate tags for the entry points
|
|
140
|
+
*/
|
|
141
|
+
generateEntryPointsTags(entryPoints: string[] | string): string {
|
|
142
|
+
entryPoints = Array.isArray(entryPoints) ? entryPoints : [entryPoints]
|
|
143
|
+
|
|
144
|
+
if (this.#isRunningHot()) {
|
|
145
|
+
return this.#generateEntryPointsTagsForHotmode(entryPoints)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return this.#generateEntryPointsTagsWithManifest(entryPoints)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Get a chunk from the manifest file for a given file name
|
|
153
|
+
*/
|
|
154
|
+
#chunk(manifest: Manifest, fileName: string) {
|
|
155
|
+
const chunk = manifest[fileName]
|
|
156
|
+
|
|
157
|
+
if (!chunk) {
|
|
158
|
+
throw new Error(`Cannot find "${fileName}" chunk in the manifest file`)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return chunk
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Get a chunk from the manifest file for a given hashed file name
|
|
166
|
+
*/
|
|
167
|
+
#chunkByFile(manifest: Manifest, fileName: string) {
|
|
168
|
+
const chunk = Object.values(manifest).find((c) => c.file === fileName)
|
|
169
|
+
|
|
170
|
+
if (!chunk) {
|
|
171
|
+
throw new Error(`Cannot find "${fileName}" chunk in the manifest file`)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return chunk
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Check if the given path is a CSS path
|
|
179
|
+
*/
|
|
180
|
+
#isCssPath(path: string) {
|
|
181
|
+
return path.match(/\.(css|less|sass|scss|styl|stylus|pcss|postcss)$/) !== null
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Generate a HTML tag for the given asset
|
|
186
|
+
*/
|
|
187
|
+
#generateTag(asset: string): string {
|
|
188
|
+
let url = ''
|
|
189
|
+
if (this.#isRunningHot()) {
|
|
190
|
+
url = this.#hotAsset(asset)
|
|
191
|
+
} else {
|
|
192
|
+
url = `${this.#assetsUrl}/assets/${asset}`
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (this.#isCssPath(asset)) {
|
|
196
|
+
return this.#makeStyleTag(asset, url)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return this.#makeScriptTag(asset, url)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Unwrap attributes from the user defined function or return
|
|
204
|
+
* the attributes as it is
|
|
205
|
+
*/
|
|
206
|
+
#unwrapAttributes(src: string, url: string, attributes: SetAttributes) {
|
|
207
|
+
if (typeof attributes === 'function') {
|
|
208
|
+
return attributes({ src, url })
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return attributes
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Convert Record of attributes to a valid HTML string
|
|
216
|
+
*/
|
|
217
|
+
#makeAttributes(attributes: Record<string, string | boolean>) {
|
|
218
|
+
return Object.keys(attributes)
|
|
219
|
+
.map((key) => {
|
|
220
|
+
const value = attributes[key]
|
|
221
|
+
if (value === true) return key
|
|
222
|
+
if (value === false) return null
|
|
223
|
+
|
|
224
|
+
return `${key}="${value}"`
|
|
225
|
+
})
|
|
226
|
+
.filter((attr) => attr !== null)
|
|
227
|
+
.join(' ')
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Create a script tag for the given path
|
|
232
|
+
*/
|
|
233
|
+
#makeScriptTag(src: string, url: string) {
|
|
234
|
+
const customAttributes = this.#unwrapAttributes(src, url, this.#scriptAttributes)
|
|
235
|
+
const attributes = { type: 'module', ...customAttributes }
|
|
236
|
+
|
|
237
|
+
return `<script ${this.#makeAttributes(attributes)} src="${url}"></script>`
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Create a style tag for the given path
|
|
242
|
+
*/
|
|
243
|
+
#makeStyleTag(src: string, url: string) {
|
|
244
|
+
const customAttributes = this.#unwrapAttributes(src, url, this.#styleAttributes)
|
|
245
|
+
const attributes = { rel: 'stylesheet', ...customAttributes }
|
|
246
|
+
|
|
247
|
+
return `<link ${this.#makeAttributes(attributes)} href="${url}">`
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Returns path to a given asset file
|
|
252
|
+
*/
|
|
253
|
+
assetPath(asset: string) {
|
|
254
|
+
if (this.#isRunningHot()) {
|
|
255
|
+
return this.#hotAsset(asset)
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const chunk = this.#chunk(this.manifest(), asset)
|
|
259
|
+
return `${this.#assetsUrl}/assets/${chunk.file}`
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Returns the manifest file content
|
|
264
|
+
*
|
|
265
|
+
* @throws Will throw an exception when running in hot mode
|
|
266
|
+
*/
|
|
267
|
+
manifest(): Manifest {
|
|
268
|
+
if (this.#isRunningHot()) {
|
|
269
|
+
throw new Error('Cannot read the manifest file when running in hot mode')
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Use in-memory cache when available
|
|
274
|
+
*/
|
|
275
|
+
if (this.#manifestCache) {
|
|
276
|
+
return this.#manifestCache
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const manifest = this.#readFileAsJSON(join(this.#buildDirectory, this.#manifestFilename))
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Cache the manifest in production to avoid re-reading the file from disk
|
|
283
|
+
*/
|
|
284
|
+
if (this.application.inProduction) {
|
|
285
|
+
this.#manifestCache = manifest
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
return manifest
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Returns the script needed for the HMR working with React
|
|
293
|
+
*
|
|
294
|
+
* This method is called automatically when using edge tag `@viteReactRefresh`
|
|
295
|
+
*/
|
|
296
|
+
getReactHmrScript(): string {
|
|
297
|
+
if (!this.#isRunningHot()) {
|
|
298
|
+
return ''
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
return `
|
|
302
|
+
<script type="module">
|
|
303
|
+
import RefreshRuntime from '${this.#hotAsset('@react-refresh')}'
|
|
304
|
+
RefreshRuntime.injectIntoGlobalHook(window)
|
|
305
|
+
window.$RefreshReg$ = () => {}
|
|
306
|
+
window.$RefreshSig$ = () => (type) => type
|
|
307
|
+
window.__vite_plugin_react_preamble_installed__ = true
|
|
308
|
+
</script>
|
|
309
|
+
`
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Set the path to the hotfile
|
|
314
|
+
*
|
|
315
|
+
* You must also set the `hotFile` option in the vite plugin config
|
|
316
|
+
*/
|
|
317
|
+
setHotFilePath(path: string) {
|
|
318
|
+
this.#hotFile = join(fileURLToPath(this.application.appRoot), path)
|
|
319
|
+
return this
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Set the manifest filename
|
|
324
|
+
*
|
|
325
|
+
* You must also set the `build.manifest` option in your vite configuration
|
|
326
|
+
*/
|
|
327
|
+
setManifestFilename(name: string) {
|
|
328
|
+
this.#manifestFilename = name
|
|
329
|
+
return this
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Set the build directory. Subdirectory of the AdonisJs public directory
|
|
334
|
+
*
|
|
335
|
+
* You must also set the `buildDirectory` option in the vite plugin config
|
|
336
|
+
*/
|
|
337
|
+
setBuildDirectory(path: string) {
|
|
338
|
+
this.#buildDirectory = this.application.publicPath(path)
|
|
339
|
+
return this
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Set the assets url
|
|
344
|
+
*
|
|
345
|
+
* You must also set the `assetsUrl` option in the vite plugin config
|
|
346
|
+
*/
|
|
347
|
+
setAssetsUrl(url: string) {
|
|
348
|
+
this.#assetsUrl = url.endsWith('/') ? url : `${url}/`
|
|
349
|
+
return this
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Include additional attributes to each script tag generated
|
|
354
|
+
*/
|
|
355
|
+
setScriptAttributes(attributes: SetAttributes) {
|
|
356
|
+
this.#scriptAttributes = attributes
|
|
357
|
+
return this
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Include additional attributes to each style tag generated
|
|
362
|
+
*/
|
|
363
|
+
setStyleAttributes(attributes: SetAttributes) {
|
|
364
|
+
this.#styleAttributes = attributes
|
|
365
|
+
return this
|
|
366
|
+
}
|
|
367
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/vite
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { defu } from 'defu'
|
|
11
|
+
import { AddressInfo } from 'node:net'
|
|
12
|
+
import { ConfigEnv, Plugin, UserConfig } from 'vite'
|
|
13
|
+
import { PluginFullOptions } from './types/index.js'
|
|
14
|
+
import { resolveDevServerUrl } from './utils.js'
|
|
15
|
+
import { HotFile } from './hot_file.js'
|
|
16
|
+
import { ConfigResolver } from './config_resolver.js'
|
|
17
|
+
import { join } from 'node:path'
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Vite config hook
|
|
21
|
+
*/
|
|
22
|
+
export const configHook = (
|
|
23
|
+
options: PluginFullOptions,
|
|
24
|
+
userConfig: UserConfig,
|
|
25
|
+
{ command }: ConfigEnv
|
|
26
|
+
): UserConfig => {
|
|
27
|
+
const config: UserConfig = {
|
|
28
|
+
publicDir: userConfig.publicDir ?? false,
|
|
29
|
+
base: ConfigResolver.resolveBase(userConfig, options, command),
|
|
30
|
+
resolve: { alias: ConfigResolver.resolveAlias(userConfig) },
|
|
31
|
+
|
|
32
|
+
server: {
|
|
33
|
+
/**
|
|
34
|
+
* Will allow to rewrite the URL to the public path
|
|
35
|
+
* in dev mode
|
|
36
|
+
*/
|
|
37
|
+
origin: '__adonis_vite__',
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
build: {
|
|
41
|
+
assetsDir: '',
|
|
42
|
+
manifest: userConfig.build?.manifest ?? true,
|
|
43
|
+
emptyOutDir: true,
|
|
44
|
+
outDir: ConfigResolver.resolveOutDir(userConfig, options),
|
|
45
|
+
|
|
46
|
+
rollupOptions: {
|
|
47
|
+
input: options.entrypoints.map((entrypoint) => join(userConfig.root || '', entrypoint)),
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return defu(config, userConfig)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Update the user vite config to match the Adonis requirements
|
|
57
|
+
*/
|
|
58
|
+
export const config = (options: PluginFullOptions): Plugin => {
|
|
59
|
+
let devServerUrl: string
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
name: 'vite-plugin-adonis:config',
|
|
63
|
+
config: configHook.bind(null, options),
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Store the dev server url for further usage when rewriting URLs
|
|
67
|
+
*/
|
|
68
|
+
configureServer(server) {
|
|
69
|
+
const hotfile = new HotFile(options.hotFile)
|
|
70
|
+
|
|
71
|
+
server.httpServer?.once('listening', async () => {
|
|
72
|
+
devServerUrl = resolveDevServerUrl(
|
|
73
|
+
server.httpServer!.address() as AddressInfo,
|
|
74
|
+
server.config
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
await hotfile.write({ url: devServerUrl })
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
server.httpServer?.on('close', () => hotfile.clean())
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Rewrite URL to the public path in dev mode
|
|
85
|
+
*
|
|
86
|
+
* See : https://nystudio107.com/blog/using-vite-js-next-generation-frontend-tooling-with-craft-cms#vite-processed-assets
|
|
87
|
+
*/
|
|
88
|
+
transform: (code) => ({
|
|
89
|
+
code: code.replace(/__adonis_vite__/g, devServerUrl),
|
|
90
|
+
map: null,
|
|
91
|
+
}),
|
|
92
|
+
|
|
93
|
+
configResolved: async (resolvedConfig) => {
|
|
94
|
+
ConfigResolver.resolvedConfig = resolvedConfig
|
|
95
|
+
},
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/vite
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { ResolvedConfig, UserConfig, AliasOptions } from 'vite'
|
|
11
|
+
import { addTrailingSlash } from './utils.js'
|
|
12
|
+
import { PluginFullOptions } from './types/index.js'
|
|
13
|
+
import { join } from 'node:path'
|
|
14
|
+
|
|
15
|
+
export class ConfigResolver {
|
|
16
|
+
static resolvedConfig?: ResolvedConfig
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Resolve the `config.base` value
|
|
20
|
+
*/
|
|
21
|
+
static resolveBase(
|
|
22
|
+
config: UserConfig,
|
|
23
|
+
options: PluginFullOptions,
|
|
24
|
+
command: 'build' | 'serve'
|
|
25
|
+
): string {
|
|
26
|
+
if (config.base) {
|
|
27
|
+
return config.base
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (command === 'build') {
|
|
31
|
+
return addTrailingSlash(options.assetsUrl) + addTrailingSlash(options.buildDirectory)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return '/'
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Resolve the `config.resolve.alias` value
|
|
39
|
+
*
|
|
40
|
+
* Basically we are merging the user defined alias with the
|
|
41
|
+
* default alias.
|
|
42
|
+
*/
|
|
43
|
+
static resolveAlias(config: UserConfig): AliasOptions {
|
|
44
|
+
const defaultAlias = { '@/': `/resources/js/` }
|
|
45
|
+
|
|
46
|
+
if (Array.isArray(config.resolve?.alias)) {
|
|
47
|
+
return [
|
|
48
|
+
...(config.resolve?.alias ?? []),
|
|
49
|
+
Object.entries(defaultAlias).map(([find, replacement]) => ({ find, replacement })),
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return { ...defaultAlias, ...config.resolve?.alias }
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Resolve the `config.build.outDir` value
|
|
58
|
+
*/
|
|
59
|
+
static resolveOutDir(config: UserConfig, options: PluginFullOptions): string {
|
|
60
|
+
return config.build?.outDir ?? join(options.publicDirectory, options.buildDirectory)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/vite
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Resolves a page component.
|
|
12
|
+
*/
|
|
13
|
+
export async function resolvePageComponent(name: string, pages: Record<string, any>) {
|
|
14
|
+
const path = Object.keys(pages)
|
|
15
|
+
.sort((a, b) => a.length - b.length)
|
|
16
|
+
.find((filepath) => filepath.endsWith(name))
|
|
17
|
+
|
|
18
|
+
if (!path) {
|
|
19
|
+
throw new Error(`Page component "${name}" could not be found.`)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
let component = typeof pages[path] === 'function' ? await pages[path]() : pages[path]
|
|
23
|
+
|
|
24
|
+
component = component.default ?? component
|
|
25
|
+
|
|
26
|
+
return component
|
|
27
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/vite
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { existsSync, rmSync } from 'node:fs'
|
|
11
|
+
import { mkdir, writeFile } from 'node:fs/promises'
|
|
12
|
+
import { dirname, join } from 'node:path'
|
|
13
|
+
import { ConfigResolver } from './config_resolver.js'
|
|
14
|
+
|
|
15
|
+
export class HotFile {
|
|
16
|
+
/**
|
|
17
|
+
* Path to the hot file
|
|
18
|
+
*/
|
|
19
|
+
#path: string
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Register hooks to clean the hot file on exit
|
|
23
|
+
*/
|
|
24
|
+
#cleanHotFileOnExit() {
|
|
25
|
+
const clean = this.clean.bind(this)
|
|
26
|
+
|
|
27
|
+
process.on('exit', clean)
|
|
28
|
+
|
|
29
|
+
process.on('SIGINT', process.exit)
|
|
30
|
+
process.on('SIGTERM', process.exit)
|
|
31
|
+
process.on('SIGHUP', process.exit)
|
|
32
|
+
process.on('SIGBREAK', process.exit)
|
|
33
|
+
process.on('SIGKILL', process.exit)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
constructor(path: string) {
|
|
37
|
+
this.#path = join(ConfigResolver.resolvedConfig!.root, path)
|
|
38
|
+
this.#cleanHotFileOnExit()
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Write the hot file
|
|
43
|
+
*/
|
|
44
|
+
async write(data: { url: string }) {
|
|
45
|
+
await mkdir(dirname(this.#path), { recursive: true })
|
|
46
|
+
await writeFile(this.#path, JSON.stringify(data, null, 2))
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Delete the hot file
|
|
51
|
+
*/
|
|
52
|
+
clean() {
|
|
53
|
+
if (!existsSync(this.#path)) {
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
rmSync(this.#path)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/vite
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { defu } from 'defu'
|
|
11
|
+
import { PluginOption } from 'vite'
|
|
12
|
+
import { config } from './config.js'
|
|
13
|
+
import { PluginFullOptions, PluginOptions } from './types/index.js'
|
|
14
|
+
import PluginRestart from 'vite-plugin-restart'
|
|
15
|
+
import { join } from 'node:path'
|
|
16
|
+
|
|
17
|
+
const VitePluginRestart = PluginRestart as any as typeof PluginRestart.default
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Vite plugin for AdonisJS
|
|
21
|
+
*/
|
|
22
|
+
export default function Adonis(options: PluginOptions): PluginOption[] {
|
|
23
|
+
const hotfileDefaultDestination = join(
|
|
24
|
+
options.publicDirectory || 'public',
|
|
25
|
+
options.buildDirectory || 'assets',
|
|
26
|
+
'hot.json'
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
const fullOptions = defu<PluginFullOptions, [Partial<PluginOptions>]>(options, {
|
|
30
|
+
publicDirectory: 'public',
|
|
31
|
+
buildDirectory: 'assets',
|
|
32
|
+
assetsUrl: '',
|
|
33
|
+
hotFile: hotfileDefaultDestination,
|
|
34
|
+
reload: ['./resources/views/**/*.edge'],
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
return [VitePluginRestart({ reload: fullOptions.reload }), config(fullOptions)]
|
|
38
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/vite
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Possible plugin options
|
|
12
|
+
*/
|
|
13
|
+
export type PluginOptions = {
|
|
14
|
+
/**
|
|
15
|
+
* Path to the hot file
|
|
16
|
+
*
|
|
17
|
+
* @default public/hot.json
|
|
18
|
+
*/
|
|
19
|
+
hotFile?: string
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Paths to the entrypoints files
|
|
23
|
+
*/
|
|
24
|
+
entrypoints: string[]
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Path to your AdonisJS public directory
|
|
28
|
+
*
|
|
29
|
+
* @default 'public'
|
|
30
|
+
*/
|
|
31
|
+
publicDirectory?: string
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The URL where the assets will be served. This is particularly
|
|
35
|
+
* useful if you are using a CDN to deploy your assets.
|
|
36
|
+
*
|
|
37
|
+
* @default ''
|
|
38
|
+
*/
|
|
39
|
+
assetsUrl?: string
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Public subdirectory where the assets will be compiled.
|
|
43
|
+
*
|
|
44
|
+
* @default 'assets'
|
|
45
|
+
*/
|
|
46
|
+
buildDirectory?: string
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Files that should trigger a page reload when changed.
|
|
50
|
+
*
|
|
51
|
+
* @default ['./resources/views/** /*.edge']
|
|
52
|
+
*/
|
|
53
|
+
reload?: string[]
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export type PluginFullOptions = Required<PluginOptions>
|