@eighty4/dank 0.0.4-1 → 0.0.4-3
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/client/client.js +1 -0
- package/lib/bin.ts +8 -11
- package/lib/build.ts +41 -70
- package/lib/build_tag.ts +3 -3
- package/lib/config.ts +372 -11
- package/lib/dank.ts +21 -150
- package/lib/define.ts +6 -4
- package/lib/developer.ts +146 -0
- package/lib/dirs.ts +83 -0
- package/lib/errors.ts +6 -0
- package/lib/esbuild.ts +19 -29
- package/lib/flags.ts +15 -121
- package/lib/html.ts +196 -112
- package/lib/http.ts +59 -43
- package/lib/public.ts +10 -10
- package/lib/{metadata.ts → registry.ts} +216 -83
- package/lib/serve.ts +118 -270
- package/lib/services.ts +8 -8
- package/lib/watch.ts +39 -0
- package/lib_js/bin.js +79 -85
- package/lib_js/build.js +63 -86
- package/lib_js/build_tag.js +20 -21
- package/lib_js/config.js +237 -18
- package/lib_js/dank.js +5 -122
- package/lib_js/define.js +8 -5
- package/lib_js/dirs.js +61 -0
- package/lib_js/errors.js +9 -0
- package/lib_js/esbuild.js +155 -167
- package/lib_js/flags.js +30 -123
- package/lib_js/html.js +280 -231
- package/lib_js/http.js +176 -195
- package/lib_js/public.js +45 -46
- package/lib_js/registry.js +260 -0
- package/lib_js/serve.js +109 -251
- package/lib_js/services.js +152 -171
- package/lib_js/watch.js +35 -0
- package/lib_types/dank.d.ts +13 -1
- package/package.json +10 -4
- package/client/esbuild.js +0 -91
- package/lib_js/metadata.js +0 -210
package/lib/dank.ts
CHANGED
|
@@ -13,6 +13,8 @@ export type DankConfig = {
|
|
|
13
13
|
// cdn url rewriting can be simulated with PageMapping
|
|
14
14
|
pages: Record<`/${string}`, `${string}.html` | PageMapping>
|
|
15
15
|
|
|
16
|
+
devPages?: Record<`/__${string}`, `${string}.html` | DevPageMapping>
|
|
17
|
+
|
|
16
18
|
// port of `dank serve` frontend dev server
|
|
17
19
|
// used for `dan serve --preview` if previewPort not specified
|
|
18
20
|
port?: number
|
|
@@ -32,6 +34,11 @@ export type PageMapping = {
|
|
|
32
34
|
webpage: `${string}.html`
|
|
33
35
|
}
|
|
34
36
|
|
|
37
|
+
export type DevPageMapping = {
|
|
38
|
+
label: string
|
|
39
|
+
webpage: `${string}.html`
|
|
40
|
+
}
|
|
41
|
+
|
|
35
42
|
export type DevService = {
|
|
36
43
|
command: string
|
|
37
44
|
cwd?: string
|
|
@@ -66,157 +73,21 @@ export type EsbuildLoader =
|
|
|
66
73
|
| 'json'
|
|
67
74
|
| 'text'
|
|
68
75
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
throw Error('DankConfig.port must be a number')
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
if (c.previewPort !== null && typeof c.previewPort !== 'undefined') {
|
|
78
|
-
if (typeof c.previewPort !== 'number') {
|
|
79
|
-
throw Error('DankConfig.previewPort must be a number')
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
validatePages(c.pages)
|
|
83
|
-
validateDevServices(c.services)
|
|
84
|
-
validateEsbuildConfig(c.esbuild)
|
|
85
|
-
normalizePagePaths(c.pages!)
|
|
86
|
-
return c as DankConfig
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function validateEsbuildConfig(esbuild?: EsbuildConfig) {
|
|
90
|
-
if (esbuild?.loaders !== null && typeof esbuild?.loaders !== 'undefined') {
|
|
91
|
-
if (typeof esbuild.loaders !== 'object') {
|
|
92
|
-
throw Error(
|
|
93
|
-
'DankConfig.esbuild.loaders must be a map of extensions to esbuild loaders',
|
|
94
|
-
)
|
|
95
|
-
} else {
|
|
96
|
-
for (const [ext, loader] of Object.entries(esbuild.loaders)) {
|
|
97
|
-
if (typeof loader !== 'string') {
|
|
98
|
-
throw Error(
|
|
99
|
-
`DankConfig.esbuild.loaders['${ext}'] must be a string of a loader name`,
|
|
100
|
-
)
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
if (esbuild?.plugins !== null && typeof esbuild?.plugins !== 'undefined') {
|
|
106
|
-
if (!Array.isArray(esbuild.plugins)) {
|
|
107
|
-
throw Error(
|
|
108
|
-
'DankConfig.esbuild.plugins must be an array of esbuild plugins',
|
|
109
|
-
)
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
if (esbuild?.port !== null && typeof esbuild?.port !== 'undefined') {
|
|
113
|
-
if (typeof esbuild.port !== 'number') {
|
|
114
|
-
throw Error('DankConfig.esbuild.port must be a number')
|
|
115
|
-
}
|
|
116
|
-
}
|
|
76
|
+
// DankConfigFunction arg details about a dank process used when building DankConfig
|
|
77
|
+
export type DankDetails = {
|
|
78
|
+
dev: boolean
|
|
79
|
+
production: boolean
|
|
80
|
+
mode: 'build' | 'serve'
|
|
117
81
|
}
|
|
118
82
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
typeof pages === 'undefined' ||
|
|
123
|
-
Object.keys(pages).length === 0
|
|
124
|
-
) {
|
|
125
|
-
throw Error('DankConfig.pages is required')
|
|
126
|
-
}
|
|
127
|
-
for (const [urlPath, mapping] of Object.entries(pages)) {
|
|
128
|
-
if (typeof mapping === 'string' && mapping.endsWith('.html')) {
|
|
129
|
-
continue
|
|
130
|
-
}
|
|
131
|
-
if (typeof mapping === 'object') {
|
|
132
|
-
validatePageMapping(urlPath, mapping)
|
|
133
|
-
continue
|
|
134
|
-
}
|
|
135
|
-
throw Error(
|
|
136
|
-
`DankConfig.pages['${urlPath}'] must configure an html file`,
|
|
137
|
-
)
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
function validatePageMapping(urlPath: string, mapping: PageMapping) {
|
|
142
|
-
if (
|
|
143
|
-
mapping.webpage === null ||
|
|
144
|
-
typeof mapping.webpage !== 'string' ||
|
|
145
|
-
!mapping.webpage.endsWith('.html')
|
|
146
|
-
) {
|
|
147
|
-
throw Error(
|
|
148
|
-
`DankConfig.pages['${urlPath}'].webpage must configure an html file`,
|
|
149
|
-
)
|
|
150
|
-
}
|
|
151
|
-
if (mapping.pattern === null || typeof mapping.pattern === 'undefined') {
|
|
152
|
-
return
|
|
153
|
-
}
|
|
154
|
-
if (
|
|
155
|
-
typeof mapping.pattern === 'object' &&
|
|
156
|
-
mapping.pattern.constructor.name === 'RegExp'
|
|
157
|
-
) {
|
|
158
|
-
return
|
|
159
|
-
}
|
|
160
|
-
throw Error(`DankConfig.pages['${urlPath}'].pattern must be a RegExp`)
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
function validateDevServices(services: DankConfig['services']) {
|
|
164
|
-
if (services === null || typeof services === 'undefined') {
|
|
165
|
-
return
|
|
166
|
-
}
|
|
167
|
-
if (!Array.isArray(services)) {
|
|
168
|
-
throw Error(`DankConfig.services must be an array`)
|
|
169
|
-
}
|
|
170
|
-
for (let i = 0; i < services.length; i++) {
|
|
171
|
-
const s = services[i]
|
|
172
|
-
if (s.command === null || typeof s.command === 'undefined') {
|
|
173
|
-
throw Error(`DankConfig.services[${i}].command is required`)
|
|
174
|
-
} else if (typeof s.command !== 'string' || s.command.length === 0) {
|
|
175
|
-
throw Error(
|
|
176
|
-
`DankConfig.services[${i}].command must be a non-empty string`,
|
|
177
|
-
)
|
|
178
|
-
}
|
|
179
|
-
if (s.cwd !== null && typeof s.cwd !== 'undefined') {
|
|
180
|
-
if (typeof s.cwd !== 'string' || s.cwd.trim().length === 0) {
|
|
181
|
-
throw Error(
|
|
182
|
-
`DankConfig.services[${i}].cwd must be a non-empty string`,
|
|
183
|
-
)
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
if (s.env !== null && typeof s.env !== 'undefined') {
|
|
187
|
-
if (typeof s.env !== 'object') {
|
|
188
|
-
throw Error(
|
|
189
|
-
`DankConfig.services[${i}].env must be an env variable map`,
|
|
190
|
-
)
|
|
191
|
-
}
|
|
192
|
-
for (const [k, v] of Object.entries(s.env)) {
|
|
193
|
-
if (typeof v !== 'string') {
|
|
194
|
-
throw Error(
|
|
195
|
-
`DankConfig.services[${i}].env[${k}] must be a string`,
|
|
196
|
-
)
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
if (s.http !== null && typeof s.http !== 'undefined') {
|
|
201
|
-
if (typeof s.http.port !== 'number') {
|
|
202
|
-
throw Error(
|
|
203
|
-
`DankConfig.services[${i}].http.port must be a number`,
|
|
204
|
-
)
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
function normalizePagePaths(pages: DankConfig['pages']) {
|
|
211
|
-
for (const [pageUrl, mapping] of Object.entries(pages)) {
|
|
212
|
-
if (typeof mapping === 'string') {
|
|
213
|
-
pages[pageUrl as `/${string}`] = normalizePagePath(mapping)
|
|
214
|
-
} else {
|
|
215
|
-
mapping.webpage = normalizePagePath(mapping.webpage)
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
}
|
|
83
|
+
export type DankConfigFunction = (
|
|
84
|
+
dank: DankDetails,
|
|
85
|
+
) => Partial<DankConfig> | Promise<Partial<DankConfig>>
|
|
219
86
|
|
|
220
|
-
function
|
|
221
|
-
|
|
87
|
+
export function defineConfig(config: Partial<DankConfig>): Partial<DankConfig>
|
|
88
|
+
export function defineConfig(config: DankConfigFunction): DankConfigFunction
|
|
89
|
+
export function defineConfig(
|
|
90
|
+
config: Partial<DankConfig> | DankConfigFunction,
|
|
91
|
+
): Partial<DankConfig> | DankConfigFunction {
|
|
92
|
+
return config
|
|
222
93
|
}
|
package/lib/define.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ResolvedDankConfig } from './config.ts'
|
|
2
2
|
|
|
3
3
|
export type DankGlobal = {
|
|
4
4
|
IS_DEV: boolean
|
|
@@ -9,9 +9,11 @@ type DefineDankGlobalKey = 'dank.IS_DEV' | 'dank.IS_PROD'
|
|
|
9
9
|
|
|
10
10
|
export type DefineDankGlobal = Record<DefineDankGlobalKey, string>
|
|
11
11
|
|
|
12
|
-
export function createGlobalDefinitions(
|
|
12
|
+
export function createGlobalDefinitions(
|
|
13
|
+
c: ResolvedDankConfig,
|
|
14
|
+
): DefineDankGlobal {
|
|
13
15
|
return {
|
|
14
|
-
'dank.IS_DEV': JSON.stringify(!
|
|
15
|
-
'dank.IS_PROD': JSON.stringify(
|
|
16
|
+
'dank.IS_DEV': JSON.stringify(!c.flags.production),
|
|
17
|
+
'dank.IS_PROD': JSON.stringify(c.flags.production),
|
|
16
18
|
}
|
|
17
19
|
}
|
package/lib/developer.ts
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { createWriteStream, type WriteStream } from 'node:fs'
|
|
2
|
+
import { mkdir, rm } from 'node:fs/promises'
|
|
3
|
+
import os from 'node:os'
|
|
4
|
+
import { dirname, resolve } from 'node:path'
|
|
5
|
+
import packageJson from '../package.json' with { type: 'json' }
|
|
6
|
+
|
|
7
|
+
const CONSOLE =
|
|
8
|
+
process.env.DANK_LOG_CONSOLE === '1' ||
|
|
9
|
+
process.env.DANK_LOG_CONSOLE === 'true'
|
|
10
|
+
const FILE = process.env.DANK_LOG_FILE
|
|
11
|
+
const ROLLING =
|
|
12
|
+
process.env.DANK_LOG_ROLLING === '1' ||
|
|
13
|
+
process.env.DANK_LOG_ROLLING === 'true'
|
|
14
|
+
|
|
15
|
+
const logs: Array<string> = []
|
|
16
|
+
let initialized = false
|
|
17
|
+
let preparing: Promise<void>
|
|
18
|
+
let stream: WriteStream
|
|
19
|
+
|
|
20
|
+
export type LogEvent = {
|
|
21
|
+
realm:
|
|
22
|
+
| 'build'
|
|
23
|
+
| 'serve'
|
|
24
|
+
| 'assets'
|
|
25
|
+
| 'config'
|
|
26
|
+
| 'html'
|
|
27
|
+
| 'registry'
|
|
28
|
+
| 'services'
|
|
29
|
+
message: string
|
|
30
|
+
data?: Record<string, LogEventData>
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
type LogEventData =
|
|
34
|
+
| LogEventDatum
|
|
35
|
+
| Array<LogEventDatum>
|
|
36
|
+
| Set<LogEventDatum>
|
|
37
|
+
| Record<string, LogEventDatum>
|
|
38
|
+
|
|
39
|
+
type LogEventDatum = boolean | number | string | null | undefined
|
|
40
|
+
|
|
41
|
+
function toStringLogEvent(logEvent: LogEvent): string {
|
|
42
|
+
const when = new Date().toISOString()
|
|
43
|
+
const message = `[${logEvent.realm}] ${logEvent.message}\n${when}\n`
|
|
44
|
+
if (!logEvent.data) {
|
|
45
|
+
return message
|
|
46
|
+
}
|
|
47
|
+
let data = ''
|
|
48
|
+
for (const k of Object.keys(logEvent.data).sort()) {
|
|
49
|
+
data += `\n ${k} = ${toStringData(logEvent.data[k])}`
|
|
50
|
+
}
|
|
51
|
+
return `${message}${data}\n`
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function toStringData(datum: LogEventData): string {
|
|
55
|
+
if (datum instanceof Set) {
|
|
56
|
+
datum = Array.from(datum)
|
|
57
|
+
}
|
|
58
|
+
if (
|
|
59
|
+
datum !== null &&
|
|
60
|
+
typeof datum === 'object' &&
|
|
61
|
+
datum.constructor.name === 'Object'
|
|
62
|
+
) {
|
|
63
|
+
datum = Object.entries(datum).map(([k, v]) => `${k} = ${v}`)
|
|
64
|
+
}
|
|
65
|
+
if (Array.isArray(datum)) {
|
|
66
|
+
if (datum.length === 0) {
|
|
67
|
+
return '[]'
|
|
68
|
+
} else {
|
|
69
|
+
return `[\n ${datum.join('\n ')}\n ]`
|
|
70
|
+
}
|
|
71
|
+
} else {
|
|
72
|
+
return `${datum}`
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function logToConsoleAndFile(out: string) {
|
|
77
|
+
logToConsole(out)
|
|
78
|
+
logToFile(out)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function logToConsole(out: string) {
|
|
82
|
+
console.log('\n' + out)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function logToFile(out: string) {
|
|
86
|
+
logs.push(out)
|
|
87
|
+
if (!initialized) {
|
|
88
|
+
initialized = true
|
|
89
|
+
preparing = prepareLogFile().catch(onPrepareLogFileError)
|
|
90
|
+
}
|
|
91
|
+
preparing.then(syncLogs)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async function prepareLogFile() {
|
|
95
|
+
const path = resolve(FILE!)
|
|
96
|
+
if (!ROLLING) {
|
|
97
|
+
await rm(path, { force: true })
|
|
98
|
+
}
|
|
99
|
+
await mkdir(dirname(path), { recursive: true })
|
|
100
|
+
stream = createWriteStream(path, { flags: 'a' })
|
|
101
|
+
console.log('debug logging to', FILE)
|
|
102
|
+
logSystemDetails()
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function logSystemDetails() {
|
|
106
|
+
stream.write(`\
|
|
107
|
+
---
|
|
108
|
+
os: ${os.type()}
|
|
109
|
+
build: ${os.version()}
|
|
110
|
+
cpu: ${os.arch()}
|
|
111
|
+
cores: ${os.availableParallelism()}
|
|
112
|
+
${process.versions.bun ? `bun ${process.versions.bun}` : `node ${process.version}`}
|
|
113
|
+
dank: ${packageJson.version}
|
|
114
|
+
\n`)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function syncLogs() {
|
|
118
|
+
if (!logs.length) return
|
|
119
|
+
const content = logs.join('\n') + '\n'
|
|
120
|
+
logs.length = 0
|
|
121
|
+
stream.write(content)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function onPrepareLogFileError(e: any) {
|
|
125
|
+
console.error(`init log file \`${FILE}\` error: ${e.message}`)
|
|
126
|
+
process.exit(1)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function makeLogger(
|
|
130
|
+
logDelegate: (out: string) => void,
|
|
131
|
+
): (logEvent: LogEvent) => void {
|
|
132
|
+
return logEvent => logDelegate(toStringLogEvent(logEvent))
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export const LOG = (function resolveLogFn() {
|
|
136
|
+
if (CONSOLE && FILE?.length) {
|
|
137
|
+
return makeLogger(logToConsoleAndFile)
|
|
138
|
+
}
|
|
139
|
+
if (CONSOLE) {
|
|
140
|
+
return makeLogger(logToConsole)
|
|
141
|
+
}
|
|
142
|
+
if (FILE?.length) {
|
|
143
|
+
return makeLogger(logToFile)
|
|
144
|
+
}
|
|
145
|
+
return () => {}
|
|
146
|
+
})()
|
package/lib/dirs.ts
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { realpath } from 'node:fs/promises'
|
|
2
|
+
import { dirname, isAbsolute, join, resolve } from 'node:path'
|
|
3
|
+
import { cwd } from 'node:process'
|
|
4
|
+
|
|
5
|
+
export type DankDirectories = {
|
|
6
|
+
buildRoot: string
|
|
7
|
+
// output dir of html during `dank serve`
|
|
8
|
+
buildWatch: string
|
|
9
|
+
buildDist: string
|
|
10
|
+
pages: string
|
|
11
|
+
pagesResolved: string
|
|
12
|
+
projectResolved: string
|
|
13
|
+
projectRootAbs: string
|
|
14
|
+
public: string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export async function defaultProjectDirs(
|
|
18
|
+
projectRootAbs: string,
|
|
19
|
+
): Promise<Readonly<DankDirectories>> {
|
|
20
|
+
if (!projectRootAbs) {
|
|
21
|
+
projectRootAbs = cwd()
|
|
22
|
+
} else if (!isAbsolute(projectRootAbs)) {
|
|
23
|
+
throw Error()
|
|
24
|
+
}
|
|
25
|
+
const projectResolved = await realpath(projectRootAbs)
|
|
26
|
+
const pages = 'pages'
|
|
27
|
+
const pagesResolved = join(projectResolved, pages)
|
|
28
|
+
return Object.freeze({
|
|
29
|
+
buildRoot: 'build',
|
|
30
|
+
buildDist: join('build', 'dist'),
|
|
31
|
+
buildWatch: join('build', 'watch'),
|
|
32
|
+
pages,
|
|
33
|
+
pagesResolved,
|
|
34
|
+
projectResolved,
|
|
35
|
+
projectRootAbs,
|
|
36
|
+
public: 'public',
|
|
37
|
+
})
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type ResolveError = 'outofbounds'
|
|
41
|
+
|
|
42
|
+
export class Resolver {
|
|
43
|
+
#dirs: DankDirectories
|
|
44
|
+
|
|
45
|
+
constructor(dirs: DankDirectories) {
|
|
46
|
+
this.#dirs = dirs
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// cross platform safe absolute path resolution from pages dir
|
|
50
|
+
absPagesPath(...p: Array<string>): string {
|
|
51
|
+
return join(this.#dirs.projectRootAbs, this.#dirs.pages, ...p)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// cross platform safe absolute path resolution from project root
|
|
55
|
+
absProjectPath(...p: Array<string>): string {
|
|
56
|
+
return join(this.#dirs.projectRootAbs, ...p)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// `p` is expected to be a relative path resolvable from the project dir
|
|
60
|
+
isProjectSubpathInPagesDir(p: string): boolean {
|
|
61
|
+
return resolve(join(this.#dirs.projectResolved, p)).startsWith(
|
|
62
|
+
this.#dirs.pagesResolved,
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// `p` is expected to be a relative path resolvable from the pages dir
|
|
67
|
+
isPagesSubpathInPagesDir(p: string): boolean {
|
|
68
|
+
return this.isProjectSubpathInPagesDir(join(this.#dirs.pages, p))
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// resolve a pages subpath from a resource within the pages directory by a relative href
|
|
72
|
+
// `from` is expected to be a pages resource fs path starting with `pages/` and ending with filename
|
|
73
|
+
// the result will be a pages subpath and will not have the pages dir prefix
|
|
74
|
+
// returns 'outofbounds' if the relative path does not resolve to a file within the pages dir
|
|
75
|
+
resolveHrefInPagesDir(from: string, href: string): string | ResolveError {
|
|
76
|
+
const p = join(dirname(from), href)
|
|
77
|
+
if (this.isProjectSubpathInPagesDir(p)) {
|
|
78
|
+
return p
|
|
79
|
+
} else {
|
|
80
|
+
return 'outofbounds'
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
package/lib/errors.ts
ADDED
package/lib/esbuild.ts
CHANGED
|
@@ -9,45 +9,39 @@ import esbuild, {
|
|
|
9
9
|
type Plugin,
|
|
10
10
|
type PluginBuild,
|
|
11
11
|
} from 'esbuild'
|
|
12
|
-
import type { EsbuildConfig } from './dank.ts'
|
|
13
12
|
import type { DefineDankGlobal } from './define.ts'
|
|
14
|
-
import type {
|
|
15
|
-
import type { BuildRegistry, WebsiteRegistry } from './metadata.ts'
|
|
13
|
+
import type { BuildRegistry, WebsiteRegistry } from './registry.ts'
|
|
16
14
|
|
|
17
15
|
export type EntryPoint = { in: string; out: string }
|
|
18
16
|
|
|
19
17
|
export async function esbuildDevContext(
|
|
20
|
-
b: DankBuild,
|
|
21
18
|
r: WebsiteRegistry,
|
|
22
19
|
define: DefineDankGlobal,
|
|
23
20
|
entryPoints: Array<EntryPoint>,
|
|
24
|
-
c?: EsbuildConfig,
|
|
25
21
|
): Promise<BuildContext> {
|
|
26
22
|
return await esbuild.context({
|
|
27
23
|
define,
|
|
28
24
|
entryNames: '[dir]/[name]',
|
|
29
25
|
entryPoints: mapEntryPointPaths(entryPoints),
|
|
30
|
-
outdir:
|
|
31
|
-
...commonBuildOptions(
|
|
26
|
+
outdir: r.config.dirs.buildWatch,
|
|
27
|
+
...commonBuildOptions(r),
|
|
32
28
|
splitting: false,
|
|
33
29
|
write: false,
|
|
34
30
|
})
|
|
35
31
|
}
|
|
36
32
|
|
|
37
33
|
export async function esbuildWebpages(
|
|
38
|
-
b: DankBuild,
|
|
39
34
|
r: WebsiteRegistry,
|
|
40
35
|
define: DefineDankGlobal,
|
|
41
36
|
entryPoints: Array<EntryPoint>,
|
|
42
|
-
c?: EsbuildConfig,
|
|
43
37
|
): Promise<void> {
|
|
44
38
|
try {
|
|
45
39
|
await esbuild.build({
|
|
46
40
|
define,
|
|
47
41
|
entryNames: '[dir]/[name]-[hash]',
|
|
48
42
|
entryPoints: mapEntryPointPaths(entryPoints),
|
|
49
|
-
outdir:
|
|
50
|
-
...commonBuildOptions(
|
|
43
|
+
outdir: r.config.dirs.buildDist,
|
|
44
|
+
...commonBuildOptions(r),
|
|
51
45
|
})
|
|
52
46
|
} catch (ignore) {
|
|
53
47
|
process.exit(1)
|
|
@@ -55,19 +49,17 @@ export async function esbuildWebpages(
|
|
|
55
49
|
}
|
|
56
50
|
|
|
57
51
|
export async function esbuildWorkers(
|
|
58
|
-
b: DankBuild,
|
|
59
52
|
r: WebsiteRegistry,
|
|
60
53
|
define: DefineDankGlobal,
|
|
61
54
|
entryPoints: Array<EntryPoint>,
|
|
62
|
-
c?: EsbuildConfig,
|
|
63
55
|
): Promise<void> {
|
|
64
56
|
try {
|
|
65
57
|
await esbuild.build({
|
|
66
58
|
define,
|
|
67
59
|
entryNames: '[dir]/[name]-[hash]',
|
|
68
60
|
entryPoints: mapEntryPointPaths(entryPoints),
|
|
69
|
-
outdir:
|
|
70
|
-
...commonBuildOptions(
|
|
61
|
+
outdir: r.config.dirs.buildDist,
|
|
62
|
+
...commonBuildOptions(r),
|
|
71
63
|
splitting: false,
|
|
72
64
|
metafile: true,
|
|
73
65
|
write: true,
|
|
@@ -78,22 +70,19 @@ export async function esbuildWorkers(
|
|
|
78
70
|
}
|
|
79
71
|
}
|
|
80
72
|
|
|
81
|
-
function commonBuildOptions(
|
|
82
|
-
b: DankBuild,
|
|
83
|
-
r: WebsiteRegistry,
|
|
84
|
-
c?: EsbuildConfig,
|
|
85
|
-
): BuildOptions {
|
|
73
|
+
function commonBuildOptions(r: WebsiteRegistry): BuildOptions {
|
|
86
74
|
const p = workersPlugin(r.buildRegistry())
|
|
87
75
|
return {
|
|
88
|
-
absWorkingDir: b.dirs.projectRootAbs,
|
|
89
76
|
assetNames: 'assets/[name]-[hash]',
|
|
90
77
|
bundle: true,
|
|
91
78
|
format: 'esm',
|
|
92
|
-
loader:
|
|
79
|
+
loader: r.config.esbuild?.loaders || defaultLoaders(),
|
|
93
80
|
metafile: true,
|
|
94
|
-
minify:
|
|
81
|
+
minify: r.config.flags.minify,
|
|
95
82
|
platform: 'browser',
|
|
96
|
-
plugins:
|
|
83
|
+
plugins: r.config.esbuild?.plugins?.length
|
|
84
|
+
? [p, ...r.config.esbuild?.plugins]
|
|
85
|
+
: [p],
|
|
97
86
|
splitting: true,
|
|
98
87
|
treeShaking: true,
|
|
99
88
|
write: true,
|
|
@@ -127,11 +116,8 @@ export function workersPlugin(r: BuildRegistry): Plugin {
|
|
|
127
116
|
return {
|
|
128
117
|
name: '@eighty4/dank/esbuild/workers',
|
|
129
118
|
setup(build: PluginBuild) {
|
|
130
|
-
if (!build.initialOptions.absWorkingDir)
|
|
131
|
-
throw TypeError('plugin requires absWorkingDir')
|
|
132
119
|
if (!build.initialOptions.metafile)
|
|
133
120
|
throw TypeError('plugin requires metafile')
|
|
134
|
-
const { absWorkingDir } = build.initialOptions
|
|
135
121
|
|
|
136
122
|
build.onLoad({ filter: /\.(t|m?j)s$/ }, async args => {
|
|
137
123
|
let contents = await readFile(args.path, 'utf8')
|
|
@@ -158,7 +144,7 @@ export function workersPlugin(r: BuildRegistry): Plugin {
|
|
|
158
144
|
continue
|
|
159
145
|
}
|
|
160
146
|
const clientScript = args.path
|
|
161
|
-
.replace(
|
|
147
|
+
.replace(r.dirs.projectResolved, '')
|
|
162
148
|
.substring(1)
|
|
163
149
|
const workerUrl = workerCtorMatch.groups!.url.substring(
|
|
164
150
|
1,
|
|
@@ -182,10 +168,13 @@ export function workersPlugin(r: BuildRegistry): Plugin {
|
|
|
182
168
|
)
|
|
183
169
|
continue
|
|
184
170
|
}
|
|
171
|
+
const workerCtor = workerCtorMatch.groups!.ctor as
|
|
172
|
+
| 'Worker'
|
|
173
|
+
| 'SharedWorker'
|
|
185
174
|
const workerUrlPlaceholder = workerEntryPoint
|
|
186
175
|
.replace(/^pages/, '')
|
|
187
176
|
.replace(/\.(t|m?j)s$/, '.js')
|
|
188
|
-
const workerCtorReplacement = `new ${
|
|
177
|
+
const workerCtorReplacement = `new ${workerCtor}('${workerUrlPlaceholder}'${workerCtorMatch.groups!.end}`
|
|
189
178
|
contents =
|
|
190
179
|
contents.substring(0, workerCtorMatch.index + offset) +
|
|
191
180
|
workerCtorReplacement +
|
|
@@ -199,6 +188,7 @@ export function workersPlugin(r: BuildRegistry): Plugin {
|
|
|
199
188
|
r.addWorker({
|
|
200
189
|
clientScript,
|
|
201
190
|
workerEntryPoint,
|
|
191
|
+
workerCtor,
|
|
202
192
|
workerUrl,
|
|
203
193
|
workerUrlPlaceholder,
|
|
204
194
|
})
|