coralite-scripts 0.38.6 → 0.40.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/bin/index.js +20 -161
- package/dist/libs/config.d.ts.map +1 -1
- package/libs/assets.js +55 -0
- package/libs/commands/build.js +286 -0
- package/libs/config.js +23 -0
- package/libs/load-config.js +6 -10
- package/package.json +5 -5
package/bin/index.js
CHANGED
|
@@ -3,14 +3,11 @@
|
|
|
3
3
|
import loadConfig from '../libs/load-config.js'
|
|
4
4
|
import { Command, Argument } from 'commander'
|
|
5
5
|
import server from '../libs/server.js'
|
|
6
|
-
import colours from 'kleur'
|
|
7
6
|
import pkg from '../package.json' with { type: 'json' }
|
|
8
|
-
import
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import { mkdir, writeFile } from 'node:fs/promises'
|
|
13
|
-
import ora from 'ora'
|
|
7
|
+
import { join } from 'node:path'
|
|
8
|
+
import { mkdir } from 'node:fs/promises'
|
|
9
|
+
import { buildCommand } from '../libs/commands/build.js'
|
|
10
|
+
import { parseAssetMapping, mergeAssets } from '../libs/assets.js'
|
|
14
11
|
|
|
15
12
|
// remove all Node warnings before doing anything else
|
|
16
13
|
process.removeAllListeners('warning')
|
|
@@ -22,7 +19,9 @@ program
|
|
|
22
19
|
.description(pkg.description)
|
|
23
20
|
.version(pkg.version)
|
|
24
21
|
.addArgument(new Argument('<mode>', 'Run mode: dev (development server) or build (production compilation)').choices(['dev', 'build']).default('dev'))
|
|
25
|
-
.option('-v --verbose', 'Enable verbose logging output')
|
|
22
|
+
.option('-v, --verbose', 'Enable verbose logging output')
|
|
23
|
+
.option('-c, --clean', 'Clear the output directory before building')
|
|
24
|
+
.option('-a, --assets <mapping...>', 'Static assets to copy during build. Format: pkg:path:dest or src:dest')
|
|
26
25
|
|
|
27
26
|
program.parse(process.argv)
|
|
28
27
|
program.on('error', (err) => {
|
|
@@ -31,171 +30,31 @@ program.on('error', (err) => {
|
|
|
31
30
|
|
|
32
31
|
const options = program.opts()
|
|
33
32
|
const mode = program.args[0]
|
|
34
|
-
const config = await loadConfig()
|
|
33
|
+
const config = await loadConfig(process.cwd())
|
|
35
34
|
|
|
36
35
|
if (!config) {
|
|
37
36
|
process.exit(1)
|
|
38
37
|
}
|
|
39
38
|
|
|
39
|
+
if (options.assets) {
|
|
40
|
+
try {
|
|
41
|
+
const cliAssets = options.assets.map(parseAssetMapping)
|
|
42
|
+
config.assets = mergeAssets(config.assets, cliAssets)
|
|
43
|
+
} catch (err) {
|
|
44
|
+
console.error(`\n Error: ${err.message}\n`)
|
|
45
|
+
process.exit(1)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
40
49
|
if (mode === 'dev') {
|
|
41
50
|
config.output = join(process.cwd(), '.coralite')
|
|
42
51
|
await mkdir(config.output, { recursive: true })
|
|
43
52
|
|
|
44
53
|
await server(config, options)
|
|
45
54
|
} else if (mode === 'build') {
|
|
46
|
-
const PAD = ' '
|
|
47
|
-
const border = '─'.repeat(Math.min(process.stdout.columns, 36) / 2)
|
|
48
|
-
const dash = colours.gray(' ─ ')
|
|
49
|
-
|
|
50
|
-
if (options.verbose) {
|
|
51
|
-
// log the response time and status code
|
|
52
|
-
process.stdout.write('\n' + PAD + colours.yellow('Compiling Coralite... \n\n'))
|
|
53
|
-
process.stdout.write(border + colours.inverse(` LOGS `) + border + '\n\n')
|
|
54
|
-
} else {
|
|
55
|
-
process.stdout.write('\n' + PAD + colours.yellow('Compiling Coralite... \n\n'))
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// delete old output files
|
|
59
|
-
deleteDirectoryRecursive(config.output)
|
|
60
|
-
|
|
61
|
-
// start coralite
|
|
62
|
-
const coralite = await createCoralite({
|
|
63
|
-
components: config.components,
|
|
64
|
-
pages: config.pages,
|
|
65
|
-
plugins: config.plugins,
|
|
66
|
-
assets: config.assets,
|
|
67
|
-
externalStyles: config.styles?.input?.map(input => {
|
|
68
|
-
const ext = input.split('.').pop()
|
|
69
|
-
return '/assets/css/' + input.split('/').pop().replace(`.${ext}`, '.css')
|
|
70
|
-
}),
|
|
71
|
-
baseURL: config.baseURL,
|
|
72
|
-
output: config.output,
|
|
73
|
-
mode: 'production',
|
|
74
|
-
onError: ({ level, message, error }) => {
|
|
75
|
-
if (level === 'ERR') {
|
|
76
|
-
displayError(message, error)
|
|
77
|
-
} else if (level === 'WARN') {
|
|
78
|
-
displayWarning(message)
|
|
79
|
-
} else {
|
|
80
|
-
displayInfo(message)
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
let spinner
|
|
86
|
-
let pageCount = 0
|
|
87
|
-
let skippedCount = 0
|
|
88
|
-
|
|
89
55
|
try {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
if (!options.verbose) {
|
|
93
|
-
spinner = ora('Building pages...').start()
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const updateSpinnerText = () => {
|
|
97
|
-
if (skippedCount > 0) {
|
|
98
|
-
spinner.text = `Building pages... (${pageCount} completed, ${skippedCount} skipped)`
|
|
99
|
-
} else {
|
|
100
|
-
spinner.text = `Building pages... (${pageCount} completed)`
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// compile website
|
|
105
|
-
await coralite.build(async (result) => {
|
|
106
|
-
if (result.status === 'skipped') {
|
|
107
|
-
skippedCount++
|
|
108
|
-
if (!options.verbose) {
|
|
109
|
-
updateSpinnerText()
|
|
110
|
-
}
|
|
111
|
-
return
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const relativeDir = relative(config.pages, result.path.dirname)
|
|
115
|
-
const outDir = join(config.output, relativeDir)
|
|
116
|
-
const outFile = join(outDir, result.path.filename)
|
|
117
|
-
|
|
118
|
-
await mkdir(outDir, { recursive: true })
|
|
119
|
-
await writeFile(outFile, result.content)
|
|
120
|
-
|
|
121
|
-
if (options.verbose) {
|
|
122
|
-
process.stdout.write(toTime() + toMS(result.duration) + dash + result.path.pathname + '\n')
|
|
123
|
-
} else {
|
|
124
|
-
pageCount++
|
|
125
|
-
updateSpinnerText()
|
|
126
|
-
}
|
|
127
|
-
})
|
|
128
|
-
|
|
129
|
-
// Write ESM script assets generated during the build phase
|
|
130
|
-
if (coralite.outputFiles) {
|
|
131
|
-
const assetsDir = join(config.output, 'assets', 'js')
|
|
132
|
-
|
|
133
|
-
const assetWrites = Object.values(coralite.outputFiles).map(async (file) => {
|
|
134
|
-
const outFile = join(assetsDir, file.hashedPath)
|
|
135
|
-
await mkdir(dirname(outFile), { recursive: true })
|
|
136
|
-
await writeFile(outFile, file.text)
|
|
137
|
-
if (options.verbose) {
|
|
138
|
-
const dash = colours.gray(' ─ ')
|
|
139
|
-
process.stdout.write(toTime() + toMS(0) + dash + outFile + '\n')
|
|
140
|
-
}
|
|
141
|
-
})
|
|
142
|
-
|
|
143
|
-
await Promise.all(assetWrites)
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
if (!options.verbose) {
|
|
147
|
-
if (skippedCount > 0) {
|
|
148
|
-
spinner.succeed(`Pages built (${pageCount} completed, ${skippedCount} skipped)`)
|
|
149
|
-
} else {
|
|
150
|
-
spinner.succeed(`Pages built (${pageCount} completed)`)
|
|
151
|
-
}
|
|
152
|
-
if (componentCount > 0) {
|
|
153
|
-
ora(`Components built (${componentCount} completed)`).succeed()
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const publicDir = config.public
|
|
158
|
-
|
|
159
|
-
if (publicDir) {
|
|
160
|
-
if (!options.verbose) {
|
|
161
|
-
spinner = ora('Copying public directory...').start()
|
|
162
|
-
}
|
|
163
|
-
await copyDirectory(publicDir, config.output)
|
|
164
|
-
if (!options.verbose) {
|
|
165
|
-
spinner.succeed('Public directory copied')
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
if (config.styles && config.styles.input) {
|
|
170
|
-
if (!options.verbose) {
|
|
171
|
-
spinner = ora('Building styles...').start()
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
const results = await buildStyles({
|
|
175
|
-
input: config.styles.input,
|
|
176
|
-
output: join(config.output, 'assets', 'css'),
|
|
177
|
-
processors: config.styles.processors,
|
|
178
|
-
minify: mode === 'build',
|
|
179
|
-
sourcemap: mode !== 'build'
|
|
180
|
-
})
|
|
181
|
-
|
|
182
|
-
for (let i = 0; i < results.length; i++) {
|
|
183
|
-
const result = results[i]
|
|
184
|
-
|
|
185
|
-
if (options.verbose) {
|
|
186
|
-
process.stdout.write(toTime() + toMS(result.duration) + dash + result.output + '\n')
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
if (!options.verbose) {
|
|
191
|
-
spinner.succeed('Styles built')
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
} catch (error) {
|
|
195
|
-
if (spinner) {
|
|
196
|
-
spinner.fail('Build failed')
|
|
197
|
-
}
|
|
198
|
-
displayError('Build failed', error)
|
|
56
|
+
await buildCommand(config, options)
|
|
57
|
+
} catch {
|
|
199
58
|
process.exit(1)
|
|
200
59
|
}
|
|
201
60
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../libs/config.js"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,sCAzBW,oBAAoB,GAClB,oBAAoB,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../libs/config.js"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,sCAzBW,oBAAoB,GAClB,oBAAoB,CA2KhC;0CArLsC,mBAAmB"}
|
package/libs/assets.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @import { CoraliteStaticAsset } from 'coralite'
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Parses an asset mapping string into an asset object.
|
|
7
|
+
*
|
|
8
|
+
* @param {string} mapping - The mapping string (pkg:path:dest or src:dest).
|
|
9
|
+
* @returns {CoraliteStaticAsset} The parsed asset object.
|
|
10
|
+
* @throws {Error} If the mapping format is invalid.
|
|
11
|
+
*/
|
|
12
|
+
export function parseAssetMapping (mapping) {
|
|
13
|
+
const parts = mapping.split(':')
|
|
14
|
+
|
|
15
|
+
if (parts.length === 3) {
|
|
16
|
+
// pkg:path:dest
|
|
17
|
+
return {
|
|
18
|
+
pkg: parts[0],
|
|
19
|
+
path: parts[1],
|
|
20
|
+
dest: parts[2]
|
|
21
|
+
}
|
|
22
|
+
} else if (parts.length === 2) {
|
|
23
|
+
// src:dest
|
|
24
|
+
const src = parts[0]
|
|
25
|
+
if (!src.startsWith('.') && !src.startsWith('/') && !src.startsWith('..')) {
|
|
26
|
+
throw new Error(`Invalid asset mapping "${mapping}". Local paths must start with ".", "..", or "/". NPM package mappings require 3 parts (pkg:path:dest).`)
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
src,
|
|
30
|
+
dest: parts[1]
|
|
31
|
+
}
|
|
32
|
+
} else {
|
|
33
|
+
throw new Error(`Invalid asset mapping "${mapping}". Expected format: pkg:path:dest or src:dest`)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Merges a list of CLI assets into an existing assets array, with CLI assets taking precedence on destination collisions.
|
|
39
|
+
*
|
|
40
|
+
* @param {CoraliteStaticAsset[]} baseAssets - The existing assets array.
|
|
41
|
+
* @param {CoraliteStaticAsset[]} cliAssets - The new assets to merge.
|
|
42
|
+
* @returns {CoraliteStaticAsset[]} The merged assets array.
|
|
43
|
+
*/
|
|
44
|
+
export function mergeAssets (baseAssets = [], cliAssets = []) {
|
|
45
|
+
const merged = [...baseAssets]
|
|
46
|
+
for (const cliAsset of cliAssets) {
|
|
47
|
+
const index = merged.findIndex(a => a.dest === cliAsset.dest)
|
|
48
|
+
if (index !== -1) {
|
|
49
|
+
merged[index] = cliAsset
|
|
50
|
+
} else {
|
|
51
|
+
merged.push(cliAsset)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return merged
|
|
55
|
+
}
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import colours from 'kleur'
|
|
2
|
+
import buildStyles from '../build-styles.js'
|
|
3
|
+
import { join, relative, dirname } from 'node:path'
|
|
4
|
+
import { existsSync, readdirSync, rmdirSync, statSync, unlinkSync } from 'node:fs'
|
|
5
|
+
import { deleteDirectoryRecursive, copyDirectory, toMS, toTime, displayError, displayWarning, displayInfo } from '../build-utils.js'
|
|
6
|
+
import { createCoralite } from 'coralite'
|
|
7
|
+
import { mkdir, writeFile } from 'node:fs/promises'
|
|
8
|
+
import ora from 'ora'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {import('../../types/index.js').CoraliteScriptConfig} config - The configuration object.
|
|
12
|
+
* @param {any} options - The CLI options.
|
|
13
|
+
* @param {any} logger - The logger object.
|
|
14
|
+
*/
|
|
15
|
+
export async function buildCommand (config, options, logger = null) {
|
|
16
|
+
const mode = 'build'
|
|
17
|
+
const PAD = ' '
|
|
18
|
+
const border = '─'.repeat(Math.min(process.stdout.columns || 36, 36) / 2)
|
|
19
|
+
const dash = colours.gray(' ─ ')
|
|
20
|
+
|
|
21
|
+
const log = (msg) => {
|
|
22
|
+
if (logger && logger.write) {
|
|
23
|
+
logger.write(msg)
|
|
24
|
+
} else {
|
|
25
|
+
process.stdout.write(msg)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const createSpinner = (text) => {
|
|
30
|
+
if (logger && logger.spinner) {
|
|
31
|
+
return logger.spinner(text)
|
|
32
|
+
}
|
|
33
|
+
return ora(text)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const internalLogger = {
|
|
37
|
+
info: (msg) => {
|
|
38
|
+
return logger && logger.info ? logger.info(msg) : displayInfo(msg)
|
|
39
|
+
},
|
|
40
|
+
warn: (msg) => {
|
|
41
|
+
return logger && logger.warn ? logger.warn(msg) : displayWarning(msg)
|
|
42
|
+
},
|
|
43
|
+
error: (msg, err) => {
|
|
44
|
+
return logger && logger.error ? logger.error(msg, err) : displayError(msg, err)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (options.verbose) {
|
|
49
|
+
log('\n' + PAD + colours.yellow('Compiling Coralite... \n\n'))
|
|
50
|
+
log(border + colours.inverse(` LOGS `) + border + '\n\n')
|
|
51
|
+
} else {
|
|
52
|
+
log('\n' + PAD + colours.yellow('Compiling Coralite... \n\n'))
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (options.clean) {
|
|
56
|
+
deleteDirectoryRecursive(config.output)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const validFiles = new Set()
|
|
60
|
+
|
|
61
|
+
const coralite = await createCoralite({
|
|
62
|
+
components: config.components,
|
|
63
|
+
pages: config.pages,
|
|
64
|
+
plugins: config.plugins,
|
|
65
|
+
assets: config.assets,
|
|
66
|
+
externalStyles: config.styles?.input?.map(input => {
|
|
67
|
+
const ext = input.split('.').pop()
|
|
68
|
+
return '/assets/css/' + input.split('/').pop().replace(`.${ext}`, '.css')
|
|
69
|
+
}),
|
|
70
|
+
baseURL: config.baseURL,
|
|
71
|
+
output: config.output,
|
|
72
|
+
mode: 'production',
|
|
73
|
+
onError: ({ level, message, error }) => {
|
|
74
|
+
if (level === 'ERR') {
|
|
75
|
+
internalLogger.error(message, error)
|
|
76
|
+
} else if (level === 'WARN') {
|
|
77
|
+
internalLogger.warn(message)
|
|
78
|
+
} else {
|
|
79
|
+
internalLogger.info(message)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
let spinner
|
|
85
|
+
let pageCount = 0
|
|
86
|
+
let skippedCount = 0
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
const componentCount = 0
|
|
90
|
+
|
|
91
|
+
if (!options.verbose) {
|
|
92
|
+
spinner = createSpinner('Building pages...').start()
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const updateSpinnerText = () => {
|
|
96
|
+
if (skippedCount > 0) {
|
|
97
|
+
spinner.text = `Building pages... (${pageCount} completed, ${skippedCount} skipped)`
|
|
98
|
+
} else {
|
|
99
|
+
spinner.text = `Building pages... (${pageCount} completed)`
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
await coralite.build(async (result) => {
|
|
104
|
+
const relativeDir = relative(config.pages, result.path.dirname)
|
|
105
|
+
const outDir = join(config.output, relativeDir)
|
|
106
|
+
const outFile = join(outDir, result.path.filename)
|
|
107
|
+
|
|
108
|
+
validFiles.add(outFile)
|
|
109
|
+
|
|
110
|
+
if (result.status === 'skipped') {
|
|
111
|
+
skippedCount++
|
|
112
|
+
if (!options.verbose) {
|
|
113
|
+
updateSpinnerText()
|
|
114
|
+
}
|
|
115
|
+
return
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
await mkdir(outDir, { recursive: true })
|
|
119
|
+
await writeFile(outFile, result.content)
|
|
120
|
+
|
|
121
|
+
if (options.verbose) {
|
|
122
|
+
log(toTime() + toMS(result.duration) + dash + result.path.pathname + '\n')
|
|
123
|
+
} else {
|
|
124
|
+
pageCount++
|
|
125
|
+
updateSpinnerText()
|
|
126
|
+
}
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
if (coralite.outputFiles) {
|
|
130
|
+
const assetsJsDir = join(config.output, 'assets', 'js')
|
|
131
|
+
const assetsCssDir = join(config.output, 'assets', 'css')
|
|
132
|
+
|
|
133
|
+
const assetWrites = Object.values(coralite.outputFiles).map(async (file) => {
|
|
134
|
+
const isCSS = (file.path || file.hashedPath)?.endsWith('.css')
|
|
135
|
+
const baseAssetsDir = isCSS ? assetsCssDir : assetsJsDir
|
|
136
|
+
const outFile = join(baseAssetsDir, file.hashedPath)
|
|
137
|
+
|
|
138
|
+
validFiles.add(outFile)
|
|
139
|
+
|
|
140
|
+
await mkdir(dirname(outFile), { recursive: true })
|
|
141
|
+
await writeFile(outFile, file.text)
|
|
142
|
+
if (options.verbose) {
|
|
143
|
+
const dash = colours.gray(' ─ ')
|
|
144
|
+
log(toTime() + toMS(0) + dash + outFile + '\n')
|
|
145
|
+
}
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
await Promise.all(assetWrites)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Track assets from config to prevent them from being deleted as stale files
|
|
152
|
+
if (config.assets) {
|
|
153
|
+
for (const asset of config.assets) {
|
|
154
|
+
const fullDestPath = join(config.output, asset.dest)
|
|
155
|
+
if (existsSync(fullDestPath)) {
|
|
156
|
+
const stat = statSync(fullDestPath)
|
|
157
|
+
if (stat.isDirectory()) {
|
|
158
|
+
const trackFiles = (dir) => {
|
|
159
|
+
const files = readdirSync(dir)
|
|
160
|
+
for (const file of files) {
|
|
161
|
+
const fullPath = join(dir, file)
|
|
162
|
+
if (statSync(fullPath).isDirectory()) {
|
|
163
|
+
trackFiles(fullPath)
|
|
164
|
+
} else {
|
|
165
|
+
validFiles.add(fullPath)
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
trackFiles(fullDestPath)
|
|
170
|
+
} else {
|
|
171
|
+
validFiles.add(fullDestPath)
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (!options.verbose) {
|
|
178
|
+
if (skippedCount > 0) {
|
|
179
|
+
spinner.succeed(`Pages built (${pageCount} completed, ${skippedCount} skipped)`)
|
|
180
|
+
} else {
|
|
181
|
+
spinner.succeed(`Pages built (${pageCount} completed)`)
|
|
182
|
+
}
|
|
183
|
+
if (componentCount > 0) {
|
|
184
|
+
createSpinner(`Components built (${componentCount} completed)`).succeed()
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const publicDir = config.public
|
|
189
|
+
|
|
190
|
+
if (publicDir) {
|
|
191
|
+
if (!options.verbose) {
|
|
192
|
+
spinner = createSpinner('Copying public directory...').start()
|
|
193
|
+
}
|
|
194
|
+
await copyDirectory(publicDir, config.output)
|
|
195
|
+
|
|
196
|
+
const trackPublicFiles = (dir, baseDir) => {
|
|
197
|
+
const files = readdirSync(dir)
|
|
198
|
+
for (const file of files) {
|
|
199
|
+
const fullPath = join(dir, file)
|
|
200
|
+
const stat = statSync(fullPath)
|
|
201
|
+
|
|
202
|
+
if (stat.isDirectory()) {
|
|
203
|
+
trackPublicFiles(fullPath, baseDir)
|
|
204
|
+
} else {
|
|
205
|
+
const relativePath = relative(baseDir, fullPath)
|
|
206
|
+
validFiles.add(join(config.output, relativePath))
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
trackPublicFiles(publicDir, publicDir)
|
|
211
|
+
|
|
212
|
+
if (!options.verbose) {
|
|
213
|
+
spinner.succeed('Public directory copied')
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (config.styles && config.styles.input) {
|
|
218
|
+
if (!options.verbose) {
|
|
219
|
+
spinner = createSpinner('Building styles...').start()
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const results = await buildStyles({
|
|
223
|
+
input: config.styles.input,
|
|
224
|
+
output: join(config.output, 'assets', 'css'),
|
|
225
|
+
processors: config.styles.processors,
|
|
226
|
+
minify: mode === 'build',
|
|
227
|
+
sourcemap: mode !== 'build'
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
for (let i = 0; i < results.length; i++) {
|
|
231
|
+
const result = results[i]
|
|
232
|
+
validFiles.add(result.output)
|
|
233
|
+
|
|
234
|
+
if (options.verbose) {
|
|
235
|
+
log(toTime() + toMS(result.duration) + dash + result.output + '\n')
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (!options.verbose) {
|
|
240
|
+
spinner.succeed('Styles built')
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (!options.clean) {
|
|
245
|
+
if (!options.verbose) {
|
|
246
|
+
spinner = createSpinner('Cleaning up stale files...').start()
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const cleanupStaleFiles = (dir) => {
|
|
250
|
+
if (!existsSync(dir)) {
|
|
251
|
+
return
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
const files = readdirSync(dir)
|
|
255
|
+
for (const file of files) {
|
|
256
|
+
const fullPath = join(dir, file)
|
|
257
|
+
const stat = statSync(fullPath)
|
|
258
|
+
|
|
259
|
+
if (stat.isDirectory()) {
|
|
260
|
+
cleanupStaleFiles(fullPath)
|
|
261
|
+
if (readdirSync(fullPath).length === 0) {
|
|
262
|
+
rmdirSync(fullPath)
|
|
263
|
+
}
|
|
264
|
+
} else if (!validFiles.has(fullPath)) {
|
|
265
|
+
unlinkSync(fullPath)
|
|
266
|
+
|
|
267
|
+
if (options.verbose) {
|
|
268
|
+
log(toTime() + colours.gray('Deleted stale file: ') + fullPath + '\n')
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
cleanupStaleFiles(config.output)
|
|
274
|
+
|
|
275
|
+
if (!options.verbose) {
|
|
276
|
+
spinner.succeed('Cleanup complete')
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
} catch (error) {
|
|
280
|
+
if (spinner) {
|
|
281
|
+
spinner.fail('Build failed')
|
|
282
|
+
}
|
|
283
|
+
internalLogger.error('Build failed', error)
|
|
284
|
+
throw error
|
|
285
|
+
}
|
|
286
|
+
}
|
package/libs/config.js
CHANGED
|
@@ -154,6 +154,29 @@ export function defineConfig (options) {
|
|
|
154
154
|
if (!Array.isArray(options.assets)) {
|
|
155
155
|
throw new Error('Configuration "assets" must be an array')
|
|
156
156
|
}
|
|
157
|
+
|
|
158
|
+
for (const asset of options.assets) {
|
|
159
|
+
if (typeof asset !== 'object' || asset === null) {
|
|
160
|
+
throw new Error('Configuration "assets" items must be objects')
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (!asset.dest || typeof asset.dest !== 'string') {
|
|
164
|
+
throw new Error('Configuration "assets" items must have a string "dest" property')
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (asset.src) {
|
|
168
|
+
if (typeof asset.src !== 'string') {
|
|
169
|
+
throw new Error('Configuration "assets" items "src" property must be a string')
|
|
170
|
+
}
|
|
171
|
+
} else {
|
|
172
|
+
if (!asset.pkg || typeof asset.pkg !== 'string') {
|
|
173
|
+
throw new Error('Configuration "assets" items must have a string "pkg" property when "src" is not provided')
|
|
174
|
+
}
|
|
175
|
+
if (!asset.path || typeof asset.path !== 'string') {
|
|
176
|
+
throw new Error('Configuration "assets" items must have a string "path" property when "src" is not provided')
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
157
180
|
}
|
|
158
181
|
|
|
159
182
|
return options
|
package/libs/load-config.js
CHANGED
|
@@ -19,9 +19,10 @@ import { defineConfig } from './config.js'
|
|
|
19
19
|
*
|
|
20
20
|
* const config = await loadConfig()
|
|
21
21
|
* ```
|
|
22
|
+
* @param {string} [cwd=process.cwd()] - The current working directory.
|
|
22
23
|
*/
|
|
23
|
-
async function loadConfig () {
|
|
24
|
-
const configPath = pathToFileURL(join(
|
|
24
|
+
async function loadConfig (cwd = process.cwd()) {
|
|
25
|
+
const configPath = pathToFileURL(join(cwd, 'coralite.config.js'))
|
|
25
26
|
|
|
26
27
|
try {
|
|
27
28
|
await access(configPath)
|
|
@@ -42,15 +43,10 @@ async function loadConfig () {
|
|
|
42
43
|
return null
|
|
43
44
|
}
|
|
44
45
|
|
|
45
|
-
|
|
46
|
-
return defineConfig(config.default)
|
|
47
|
-
} catch (err) {
|
|
48
|
-
displayError('Invalid configuration', err.message)
|
|
49
|
-
return null
|
|
50
|
-
}
|
|
46
|
+
return defineConfig(config.default)
|
|
51
47
|
} catch (error) {
|
|
52
|
-
displayError('Failed to load configuration file', error)
|
|
53
|
-
|
|
48
|
+
displayError('Failed to load configuration file', error.message || error)
|
|
49
|
+
throw error
|
|
54
50
|
}
|
|
55
51
|
}
|
|
56
52
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "coralite-scripts",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.40.0",
|
|
4
4
|
"description": "Configuration and scripts for Create Coralite.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -61,11 +61,11 @@
|
|
|
61
61
|
"portfinder": "^1.0.38",
|
|
62
62
|
"postcss": "^8.5.15",
|
|
63
63
|
"sass": "^1.101.0",
|
|
64
|
-
"coralite": "0.
|
|
64
|
+
"coralite": "0.40.0"
|
|
65
65
|
},
|
|
66
66
|
"scripts": {
|
|
67
|
-
"build": "premove dist && pnpm build
|
|
68
|
-
"build
|
|
69
|
-
"test
|
|
67
|
+
"build": "premove dist && pnpm build:types",
|
|
68
|
+
"build:types": "tsc",
|
|
69
|
+
"test:unit": "node --test tests/**/*.spec.js"
|
|
70
70
|
}
|
|
71
71
|
}
|