coralite-scripts 0.31.4 → 0.31.6
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/libs/server.js +143 -29
- package/package.json +2 -2
package/libs/server.js
CHANGED
|
@@ -5,7 +5,7 @@ import chokidar from 'chokidar'
|
|
|
5
5
|
import buildSass from './build-sass.js'
|
|
6
6
|
import { displayError, displayInfo, displayWarning, displaySuccess, toCode, toMS, toTime, deleteDirectoryRecursive } from './build-utils.js'
|
|
7
7
|
import { extname, join, normalize, relative, sep } from 'path'
|
|
8
|
-
import { access, constants, mkdir, writeFile } from 'fs/promises'
|
|
8
|
+
import { access, constants, mkdir, readFile, writeFile } from 'fs/promises'
|
|
9
9
|
import Coralite from 'coralite'
|
|
10
10
|
import buildCSS from './build-css.js'
|
|
11
11
|
import { existsSync, mkdirSync } from 'fs'
|
|
@@ -32,39 +32,125 @@ async function server (config, options) {
|
|
|
32
32
|
const memoryPageSource = new Map()
|
|
33
33
|
|
|
34
34
|
// start coralite
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
35
|
+
let coralite
|
|
36
|
+
let currentConfig = config
|
|
37
|
+
const pluginPaths = new Set()
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Asynchronously extracts relative plugin paths from the `coralite.config.js` file.
|
|
41
|
+
* This function clears the existing `pluginPaths` Set, reads the configuration file
|
|
42
|
+
* (if it exists), and parses it line-by-line to find `import ... from '...'` statements.
|
|
43
|
+
* Any relative paths found in these imports are resolved against the current working
|
|
44
|
+
* directory and added to the `pluginPaths` Set.
|
|
45
|
+
*
|
|
46
|
+
* @returns {Promise<void>} A promise that resolves when the file has been processed.
|
|
47
|
+
* Fails silently if the file does not exist or cannot be read.
|
|
48
|
+
*/
|
|
49
|
+
const extractPluginPaths = async () => {
|
|
50
|
+
pluginPaths.clear()
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
const configPath = join(process.cwd(), 'coralite.config.js')
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
await access(configPath, constants.F_OK)
|
|
57
|
+
} catch (err) {
|
|
58
|
+
return
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const configContent = await readFile(configPath, 'utf-8')
|
|
62
|
+
const lines = configContent.split('\n')
|
|
63
|
+
|
|
64
|
+
for (const line of lines) {
|
|
65
|
+
if (line.trim().startsWith('import ') && line.includes(' from ')) {
|
|
66
|
+
const match = line.match(/from\s+['"]([^'"]+)['"]/)
|
|
67
|
+
if (match && match[1]) {
|
|
68
|
+
const importPath = match[1]
|
|
69
|
+
|
|
70
|
+
// If it's a relative path, resolve it
|
|
71
|
+
if (importPath.startsWith('.')) {
|
|
72
|
+
pluginPaths.add(join(process.cwd(), importPath))
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
53
76
|
}
|
|
77
|
+
} catch (error) {
|
|
78
|
+
// ignore any other unexpected errors during reading/parsing
|
|
54
79
|
}
|
|
55
|
-
}
|
|
56
|
-
await coralite.initialise()
|
|
57
|
-
displaySuccess('Coralite initialized successfully')
|
|
80
|
+
}
|
|
58
81
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
82
|
+
let originalAppRouter
|
|
83
|
+
/**
|
|
84
|
+
* Asynchronously initializes or re-initializes the Coralite instance.
|
|
85
|
+
* This function performs a complete setup/teardown cycle, making it suitable
|
|
86
|
+
* for Hot Module Replacement (HMR) or development live-reloading. Its key operations include:
|
|
87
|
+
* 1. Backing up the original Express application router state.
|
|
88
|
+
* 2. Clearing the page cache.
|
|
89
|
+
* 3. Creating and initializing a new `Coralite` instance with the current configuration.
|
|
90
|
+
* 4. Resetting the Express router stack to remove stale plugin routes.
|
|
91
|
+
* 5. Re-registering server-side plugin routes.
|
|
92
|
+
* 6. Broadcasting a 'reload' signal to all connected clients via Server-Sent Events (SSE).
|
|
93
|
+
*
|
|
94
|
+
* @returns {Promise<void>} Resolves when the Coralite instance, plugins, and routing have been fully initialized.
|
|
95
|
+
*/
|
|
96
|
+
const initCoralite = async () => {
|
|
97
|
+
if (!originalAppRouter && app._router) {
|
|
98
|
+
originalAppRouter = Object.assign({}, app._router)
|
|
99
|
+
originalAppRouter.stack = [...app._router.stack]
|
|
100
|
+
}
|
|
101
|
+
displayInfo('Initializing Coralite...')
|
|
102
|
+
|
|
103
|
+
pageCache.clear()
|
|
104
|
+
|
|
105
|
+
coralite = new Coralite({
|
|
106
|
+
components: currentConfig.components,
|
|
107
|
+
pages: currentConfig.pages,
|
|
108
|
+
plugins: currentConfig.plugins,
|
|
109
|
+
assets: currentConfig.assets,
|
|
110
|
+
baseURL: currentConfig.baseURL,
|
|
111
|
+
ignoreByAttribute: currentConfig.ignoreByAttribute,
|
|
112
|
+
skipRenderByAttribute: currentConfig.skipRenderByAttribute,
|
|
113
|
+
mode: 'development',
|
|
114
|
+
output: currentConfig.output,
|
|
115
|
+
onError: ({ level, message, error }) => {
|
|
116
|
+
if (level === 'ERR') {
|
|
117
|
+
displayError(message, error)
|
|
118
|
+
} else if (level === 'WARN') {
|
|
119
|
+
displayWarning(message)
|
|
120
|
+
} else {
|
|
121
|
+
displayInfo(message)
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
await coralite.initialise()
|
|
127
|
+
|
|
128
|
+
displaySuccess('Coralite initialized successfully')
|
|
129
|
+
|
|
130
|
+
// Reset express routing to remove old plugin routes before adding new ones
|
|
131
|
+
if (originalAppRouter && originalAppRouter.stack) {
|
|
132
|
+
// Splice the router stack back to its original length to remove newly added routes
|
|
133
|
+
app._router.stack.splice(originalAppRouter.stack.length)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (currentConfig.plugins) {
|
|
137
|
+
extractPluginPaths()
|
|
138
|
+
for (const plugin of currentConfig.plugins) {
|
|
139
|
+
if (typeof plugin.server === 'function') {
|
|
140
|
+
await plugin.server(app, coralite)
|
|
141
|
+
}
|
|
63
142
|
}
|
|
64
143
|
}
|
|
144
|
+
|
|
145
|
+
clients.forEach(client => {
|
|
146
|
+
client.write(`data: reload\n\n`)
|
|
147
|
+
})
|
|
65
148
|
}
|
|
66
149
|
|
|
150
|
+
await initCoralite()
|
|
151
|
+
|
|
67
152
|
const watchPath = [
|
|
153
|
+
process.cwd() + '/coralite.config.js',
|
|
68
154
|
config.public,
|
|
69
155
|
config.pages,
|
|
70
156
|
config.components
|
|
@@ -360,6 +446,8 @@ async function server (config, options) {
|
|
|
360
446
|
let compileTimeout = null
|
|
361
447
|
let isCompiling = false
|
|
362
448
|
const pendingChanges = new Set()
|
|
449
|
+
const configPathStr = join(process.cwd(), 'coralite.config.js')
|
|
450
|
+
|
|
363
451
|
|
|
364
452
|
// Helper function to debounce compilations
|
|
365
453
|
const debounceCompile = () => {
|
|
@@ -384,8 +472,33 @@ async function server (config, options) {
|
|
|
384
472
|
const componentChanges = changes.filter(p => p.startsWith(componentPath))
|
|
385
473
|
const sassChanges = changes.filter(p => p.endsWith('.scss') || p.endsWith('.sass'))
|
|
386
474
|
const cssChanges = changes.filter(p => p.endsWith('.css'))
|
|
475
|
+
const configChanges = changes.filter(p => p === configPathStr || Array.from(pluginPaths).some(pluginPath => p === pluginPath))
|
|
387
476
|
|
|
388
477
|
try {
|
|
478
|
+
// Handle config changes
|
|
479
|
+
if (configChanges.length > 0) {
|
|
480
|
+
displayInfo('Configuration changed, reloading Coralite...')
|
|
481
|
+
// Append cache busting param to reload properly
|
|
482
|
+
const { pathToFileURL } = await import('url')
|
|
483
|
+
const bust = '?t=' + Date.now()
|
|
484
|
+
|
|
485
|
+
try {
|
|
486
|
+
const freshConfigModule = await import(pathToFileURL(configPathStr).toString() + bust)
|
|
487
|
+
const { defineConfig } = await import('./config.js')
|
|
488
|
+
|
|
489
|
+
if (freshConfigModule.default) {
|
|
490
|
+
currentConfig = defineConfig(freshConfigModule.default)
|
|
491
|
+
currentConfig.output = config.output
|
|
492
|
+
currentConfig.server = config.server
|
|
493
|
+
|
|
494
|
+
// Re-initialize Coralite with new config
|
|
495
|
+
await initCoralite()
|
|
496
|
+
}
|
|
497
|
+
} catch (err) {
|
|
498
|
+
displayError('Failed to reload configuration', err)
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
389
502
|
// Handle component changes
|
|
390
503
|
for (const path of componentChanges) {
|
|
391
504
|
await coralite.components.setItem(path)
|
|
@@ -423,7 +536,8 @@ async function server (config, options) {
|
|
|
423
536
|
if (pagesChanges.length > 0
|
|
424
537
|
|| componentChanges.length > 0
|
|
425
538
|
|| sassChanges.length > 0
|
|
426
|
-
|| cssChanges.length > 0
|
|
539
|
+
|| cssChanges.length > 0
|
|
540
|
+
|| configChanges.length > 0) {
|
|
427
541
|
clients.forEach(client => {
|
|
428
542
|
client.write(`data: reload\n\n`)
|
|
429
543
|
})
|
|
@@ -449,7 +563,7 @@ async function server (config, options) {
|
|
|
449
563
|
}
|
|
450
564
|
})
|
|
451
565
|
.on('change', async (path) => {
|
|
452
|
-
//
|
|
566
|
+
// We only want to trigger for things we care about or are in watchPath (but sometimes chokidar watches the whole dir)
|
|
453
567
|
pendingChanges.add(path)
|
|
454
568
|
debounceCompile()
|
|
455
569
|
})
|
|
@@ -458,7 +572,7 @@ async function server (config, options) {
|
|
|
458
572
|
if (path.startsWith(componentPath)) {
|
|
459
573
|
// set component item
|
|
460
574
|
coralite.components.setItem(path)
|
|
461
|
-
} else if (path.endsWith('.scss') || path.endsWith('.sass')) {
|
|
575
|
+
} else if (path.endsWith('.scss') || path.endsWith('.sass') || path === configPathStr || Array.from(pluginPaths).some(pluginPath => path === pluginPath)) {
|
|
462
576
|
// Add to pending changes and trigger debounced compilation
|
|
463
577
|
pendingChanges.add(path)
|
|
464
578
|
debounceCompile()
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "coralite-scripts",
|
|
3
|
-
"version": "0.31.
|
|
3
|
+
"version": "0.31.6",
|
|
4
4
|
"description": "Configuration and scripts for Create Coralite.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"portfinder": "^1.0.38",
|
|
59
59
|
"postcss": "^8.5.6",
|
|
60
60
|
"sass": "^1.91.0",
|
|
61
|
-
"coralite": "0.31.
|
|
61
|
+
"coralite": "0.31.6"
|
|
62
62
|
},
|
|
63
63
|
"scripts": {
|
|
64
64
|
"build": "premove dist && pnpm build-types",
|