@eighty4/dank 0.0.3 → 0.0.4-1
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/esbuild.js +8 -5
- package/lib/build.ts +133 -72
- package/lib/{tag.ts → build_tag.ts} +3 -3
- package/lib/dank.ts +147 -11
- package/lib/define.ts +4 -5
- package/lib/esbuild.ts +239 -60
- package/lib/flags.ts +154 -10
- package/lib/html.ts +320 -116
- package/lib/http.ts +195 -47
- package/lib/metadata.ts +309 -0
- package/lib/public.ts +21 -13
- package/lib/serve.ts +205 -144
- package/lib/services.ts +28 -4
- package/lib_js/build.js +82 -57
- package/lib_js/{tag.js → build_tag.js} +2 -3
- package/lib_js/dank.js +73 -5
- package/lib_js/define.js +3 -5
- package/lib_js/esbuild.js +166 -54
- package/lib_js/flags.js +123 -8
- package/lib_js/html.js +197 -87
- package/lib_js/http.js +111 -30
- package/lib_js/metadata.js +210 -0
- package/lib_js/public.js +19 -11
- package/lib_js/serve.js +135 -110
- package/lib_js/services.js +13 -2
- package/lib_types/dank.d.ts +18 -1
- package/package.json +7 -1
- package/lib/manifest.ts +0 -61
- package/lib_js/manifest.js +0 -37
package/client/esbuild.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
new EventSource('http://127.0.0.1:
|
|
2
|
-
const
|
|
3
|
-
const
|
|
1
|
+
new EventSource('http://127.0.0.1:3995/esbuild').addEventListener('change', (e) => {
|
|
2
|
+
const { updated } = JSON.parse(e.data);
|
|
3
|
+
const changes = new Set();
|
|
4
|
+
for (const c of updated)
|
|
5
|
+
changes.add(c);
|
|
6
|
+
const cssUpdates = Array.from(changes).filter(p => p.endsWith('.css'));
|
|
4
7
|
if (cssUpdates.length) {
|
|
5
8
|
console.log('esbuild css updates', cssUpdates);
|
|
6
9
|
const cssLinks = {};
|
|
@@ -27,8 +30,8 @@ new EventSource('http://127.0.0.1:2999/esbuild').addEventListener('change', (e)
|
|
|
27
30
|
addCssUpdateIndicator();
|
|
28
31
|
}
|
|
29
32
|
}
|
|
30
|
-
if (cssUpdates.length <
|
|
31
|
-
const jsUpdates =
|
|
33
|
+
if (cssUpdates.length < changes.size) {
|
|
34
|
+
const jsUpdates = Array.from(changes).filter(p => !p.endsWith('.css'));
|
|
32
35
|
const jsScripts = new Set();
|
|
33
36
|
for (const elem of document.getElementsByTagName('script')) {
|
|
34
37
|
if (elem.src.length) {
|
package/lib/build.ts
CHANGED
|
@@ -1,26 +1,22 @@
|
|
|
1
|
-
import { mkdir, rm } from 'node:fs/promises'
|
|
1
|
+
import { mkdir, readFile, rm, writeFile } from 'node:fs/promises'
|
|
2
2
|
import { join } from 'node:path'
|
|
3
|
+
import { createBuildTag } from './build_tag.ts'
|
|
3
4
|
import type { DankConfig } from './dank.ts'
|
|
4
|
-
import { isProductionBuild, willMinify } from './flags.ts'
|
|
5
|
-
import { copyAssets } from './public.ts'
|
|
6
|
-
import { createBuildTag } from './tag.ts'
|
|
7
|
-
import { writeBuildManifest, writeMetafile } from './manifest.ts'
|
|
8
5
|
import { type DefineDankGlobal, createGlobalDefinitions } from './define.ts'
|
|
6
|
+
import { esbuildWebpages, esbuildWorkers, type EntryPoint } from './esbuild.ts'
|
|
7
|
+
import { resolveBuildFlags, type DankBuild } from './flags.ts'
|
|
9
8
|
import { HtmlEntrypoint } from './html.ts'
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
export type DankBuild = {
|
|
13
|
-
dir: string
|
|
14
|
-
files: Set<string>
|
|
15
|
-
}
|
|
9
|
+
import { type WebsiteManifest, WebsiteRegistry } from './metadata.ts'
|
|
10
|
+
import { copyAssets } from './public.ts'
|
|
16
11
|
|
|
17
|
-
export async function buildWebsite(
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
12
|
+
export async function buildWebsite(
|
|
13
|
+
c: DankConfig,
|
|
14
|
+
build: DankBuild = resolveBuildFlags(),
|
|
15
|
+
): Promise<WebsiteManifest> {
|
|
16
|
+
const buildTag = await createBuildTag(build)
|
|
21
17
|
console.log(
|
|
22
|
-
|
|
23
|
-
?
|
|
18
|
+
build.minify
|
|
19
|
+
? build.production
|
|
24
20
|
? 'minified production'
|
|
25
21
|
: 'minified'
|
|
26
22
|
: 'unminified',
|
|
@@ -28,71 +24,136 @@ export async function buildWebsite(c: DankConfig): Promise<DankBuild> {
|
|
|
28
24
|
buildTag,
|
|
29
25
|
'building in ./build/dist',
|
|
30
26
|
)
|
|
31
|
-
await rm(
|
|
32
|
-
await mkdir(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const buildUrls: Array<string> = []
|
|
36
|
-
buildUrls.push(
|
|
37
|
-
...(await buildWebpages(distDir, createGlobalDefinitions(), c.pages)),
|
|
38
|
-
)
|
|
39
|
-
if (staticAssets) {
|
|
40
|
-
buildUrls.push(...staticAssets)
|
|
41
|
-
}
|
|
42
|
-
const result = new Set(buildUrls)
|
|
43
|
-
await writeBuildManifest(buildTag, result)
|
|
44
|
-
return {
|
|
45
|
-
dir: distDir,
|
|
46
|
-
files: result,
|
|
27
|
+
await rm(build.dirs.buildRoot, { recursive: true, force: true })
|
|
28
|
+
await mkdir(build.dirs.buildDist, { recursive: true })
|
|
29
|
+
for (const subdir of Object.keys(c.pages).filter(url => url !== '/')) {
|
|
30
|
+
await mkdir(join(build.dirs.buildDist, subdir), { recursive: true })
|
|
47
31
|
}
|
|
32
|
+
await mkdir(join(build.dirs.buildRoot, 'metafiles'), { recursive: true })
|
|
33
|
+
const registry = new WebsiteRegistry(build)
|
|
34
|
+
registry.pageUrls = Object.keys(c.pages)
|
|
35
|
+
registry.copiedAssets = await copyAssets(build)
|
|
36
|
+
await buildWebpages(c, registry, build, createGlobalDefinitions(build))
|
|
37
|
+
return await registry.writeManifest(buildTag)
|
|
48
38
|
}
|
|
49
39
|
|
|
40
|
+
// builds all webpage entrypoints in one esbuild.build context
|
|
41
|
+
// to support code splitting
|
|
42
|
+
// returns all built assets URLs and webpage URLs from DankConfig.pages
|
|
50
43
|
async function buildWebpages(
|
|
51
|
-
|
|
44
|
+
c: DankConfig,
|
|
45
|
+
registry: WebsiteRegistry,
|
|
46
|
+
build: DankBuild,
|
|
52
47
|
define: DefineDankGlobal,
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
const
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
48
|
+
) {
|
|
49
|
+
// create HtmlEntrypoint for each webpage and collect awaitable esbuild entrypoints
|
|
50
|
+
const loadingEntryPoints: Array<Promise<Array<EntryPoint>>> = []
|
|
51
|
+
const htmlEntrypoints: Array<HtmlEntrypoint> = []
|
|
52
|
+
for (const [urlPath, mapping] of Object.entries(c.pages)) {
|
|
53
|
+
const fsPath = typeof mapping === 'string' ? mapping : mapping.webpage
|
|
54
|
+
const html = new HtmlEntrypoint(
|
|
55
|
+
build,
|
|
56
|
+
registry.resolver,
|
|
57
|
+
urlPath,
|
|
58
|
+
fsPath,
|
|
59
|
+
)
|
|
60
|
+
loadingEntryPoints.push(new Promise(res => html.on('entrypoints', res)))
|
|
61
|
+
htmlEntrypoints.push(html)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// collect esbuild entrypoints from every HtmlEntrypoint
|
|
65
|
+
const uniqueEntryPoints: Set<string> = new Set()
|
|
66
|
+
const buildEntryPoints: Array<EntryPoint> = []
|
|
67
|
+
for (const pageEntryPoints of await Promise.all(loadingEntryPoints)) {
|
|
68
|
+
for (const entryPoint of pageEntryPoints) {
|
|
69
|
+
if (!uniqueEntryPoints.has(entryPoint.in)) {
|
|
70
|
+
buildEntryPoints.push(entryPoint)
|
|
66
71
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
await esbuildWebpages(build, registry, define, buildEntryPoints, c.esbuild)
|
|
76
|
+
|
|
77
|
+
// todo recursively build workers on building workers that create workers
|
|
78
|
+
const workerEntryPoints = registry.workerEntryPoints()
|
|
79
|
+
if (workerEntryPoints?.length) {
|
|
80
|
+
await esbuildWorkers(
|
|
81
|
+
build,
|
|
82
|
+
registry,
|
|
83
|
+
define,
|
|
84
|
+
workerEntryPoints,
|
|
85
|
+
c.esbuild,
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
await rewriteWorkerUrls(build, registry)
|
|
89
|
+
|
|
90
|
+
// write out html output with rewritten hrefs
|
|
91
|
+
await Promise.all(
|
|
92
|
+
htmlEntrypoints.map(async html => {
|
|
93
|
+
await writeFile(
|
|
94
|
+
join(build.dirs.buildDist, html.url, 'index.html'),
|
|
95
|
+
html.output(registry),
|
|
96
|
+
)
|
|
77
97
|
}),
|
|
78
98
|
)
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
)
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export async function rewriteWorkerUrls(
|
|
102
|
+
build: DankBuild,
|
|
103
|
+
registry: WebsiteRegistry,
|
|
104
|
+
) {
|
|
105
|
+
const workers = registry.workers()
|
|
106
|
+
if (!workers) {
|
|
107
|
+
return
|
|
108
|
+
}
|
|
109
|
+
const dependentBundlePaths = workers.map(w =>
|
|
110
|
+
registry.mappedHref(w.dependentEntryPoint),
|
|
111
|
+
)
|
|
112
|
+
const bundleOutputs: Record<string, string> = {}
|
|
113
|
+
|
|
114
|
+
// collect all js file contents concurrently
|
|
115
|
+
const readingFiles = Promise.all(
|
|
116
|
+
dependentBundlePaths.map(async p => {
|
|
117
|
+
bundleOutputs[p] = await readFile(
|
|
118
|
+
join(build.dirs.projectRootAbs, build.dirs.buildDist, p),
|
|
119
|
+
'utf8',
|
|
120
|
+
)
|
|
121
|
+
}),
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
// build regex replacements during file reads
|
|
125
|
+
const rewriteChains: Record<string, Array<(s: string) => string>> = {}
|
|
126
|
+
for (const p of dependentBundlePaths) rewriteChains[p] = []
|
|
127
|
+
for (const w of workers) {
|
|
128
|
+
rewriteChains[registry.mappedHref(w.dependentEntryPoint)].push(s =>
|
|
129
|
+
s.replace(
|
|
130
|
+
createWorkerRegex(w.workerUrlPlaceholder),
|
|
131
|
+
`new Worker('${registry.mappedHref(w.workerEntryPoint)}')`,
|
|
132
|
+
),
|
|
133
|
+
)
|
|
90
134
|
}
|
|
135
|
+
|
|
136
|
+
// wait for file reads
|
|
137
|
+
await readingFiles
|
|
138
|
+
|
|
139
|
+
// run rewrite regex chain and write back to dist
|
|
91
140
|
await Promise.all(
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
141
|
+
Object.entries(bundleOutputs).map(async ([p, content]) => {
|
|
142
|
+
let result = content
|
|
143
|
+
for (const rewriteFn of rewriteChains[p]) {
|
|
144
|
+
result = rewriteFn(result)
|
|
145
|
+
}
|
|
146
|
+
await writeFile(
|
|
147
|
+
join(build.dirs.projectRootAbs, build.dirs.buildDist, p),
|
|
148
|
+
result,
|
|
149
|
+
)
|
|
95
150
|
}),
|
|
96
151
|
)
|
|
97
|
-
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export function createWorkerRegex(workerUrl: string): RegExp {
|
|
155
|
+
return new RegExp(
|
|
156
|
+
`new(?:\\s|\\r?\\n)+Worker(?:\\s|\\r?\\n)*\\((?:\\s|\\r?\\n)*['"]${workerUrl}['"](?:\\s|\\r?\\n)*\\)`,
|
|
157
|
+
'g',
|
|
158
|
+
)
|
|
98
159
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { exec } from 'node:child_process'
|
|
2
|
-
import {
|
|
2
|
+
import type { DankBuild } from './flags.ts'
|
|
3
3
|
|
|
4
|
-
export async function createBuildTag(): Promise<string> {
|
|
4
|
+
export async function createBuildTag(build: DankBuild): Promise<string> {
|
|
5
5
|
const now = new Date()
|
|
6
6
|
const ms =
|
|
7
7
|
now.getUTCMilliseconds() +
|
|
@@ -11,7 +11,7 @@ export async function createBuildTag(): Promise<string> {
|
|
|
11
11
|
const date = now.toISOString().substring(0, 10)
|
|
12
12
|
const time = String(ms).padStart(8, '0')
|
|
13
13
|
const when = `${date}-${time}`
|
|
14
|
-
if (
|
|
14
|
+
if (build.production) {
|
|
15
15
|
const gitHash = await new Promise((res, rej) =>
|
|
16
16
|
exec('git rev-parse --short HEAD', (err, stdout) => {
|
|
17
17
|
if (err) rej(err)
|
package/lib/dank.ts
CHANGED
|
@@ -1,27 +1,121 @@
|
|
|
1
|
+
import type { Plugin as EsbuildPlugin } from 'esbuild'
|
|
2
|
+
|
|
1
3
|
export type DankConfig = {
|
|
2
4
|
// used for releases and service worker caching
|
|
3
5
|
// buildTag?: (() => Promise<string> | string) | string
|
|
4
|
-
// mapping url to fs paths of webpages to build
|
|
5
|
-
pages: Record<`/${string}`, `${string}.html`>
|
|
6
6
|
|
|
7
|
+
// customize esbuild configs
|
|
8
|
+
esbuild?: EsbuildConfig
|
|
9
|
+
|
|
10
|
+
// mapping url to html files in the project pages dir
|
|
11
|
+
// page url (map key) represents html output path in build dir
|
|
12
|
+
// regardless of the html path in the pages dir
|
|
13
|
+
// cdn url rewriting can be simulated with PageMapping
|
|
14
|
+
pages: Record<`/${string}`, `${string}.html` | PageMapping>
|
|
15
|
+
|
|
16
|
+
// port of `dank serve` frontend dev server
|
|
17
|
+
// used for `dan serve --preview` if previewPort not specified
|
|
18
|
+
port?: number
|
|
19
|
+
|
|
20
|
+
// port used for `dank serve --preview` frontend dev server
|
|
21
|
+
previewPort?: number
|
|
22
|
+
|
|
23
|
+
// dev services launched during `dank serve`
|
|
7
24
|
services?: Array<DevService>
|
|
8
25
|
}
|
|
9
26
|
|
|
27
|
+
// extend an html entrypoint with url rewriting similar to cdn configurations
|
|
28
|
+
// after trying all webpage, bundle and asset paths, mapping patterns
|
|
29
|
+
// will be tested in the alphabetical order of the webpage paths
|
|
30
|
+
export type PageMapping = {
|
|
31
|
+
pattern?: RegExp
|
|
32
|
+
webpage: `${string}.html`
|
|
33
|
+
}
|
|
34
|
+
|
|
10
35
|
export type DevService = {
|
|
11
36
|
command: string
|
|
12
37
|
cwd?: string
|
|
13
38
|
env?: Record<string, string>
|
|
39
|
+
http?: {
|
|
40
|
+
port: number
|
|
41
|
+
}
|
|
14
42
|
}
|
|
15
43
|
|
|
44
|
+
export type EsbuildConfig = {
|
|
45
|
+
// mapping of extensions to loaders
|
|
46
|
+
// if not specified, defaults to support WOFF/WOFF2 fonts
|
|
47
|
+
// with `{'.woff': 'file', '.woff2': 'file'}`
|
|
48
|
+
loaders?: Record<`.${string}`, EsbuildLoader>
|
|
49
|
+
|
|
50
|
+
// documented on https://esbuild.github.io/plugins
|
|
51
|
+
plugins?: Array<EsbuildPlugin>
|
|
52
|
+
|
|
53
|
+
// port used by esbuild.context() during `dank serve`
|
|
54
|
+
// defaults to 3995
|
|
55
|
+
port?: number
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// documented on https://esbuild.github.io/content-types
|
|
59
|
+
export type EsbuildLoader =
|
|
60
|
+
| 'base64'
|
|
61
|
+
| 'binary'
|
|
62
|
+
| 'copy'
|
|
63
|
+
| 'dataurl'
|
|
64
|
+
| 'empty'
|
|
65
|
+
| 'file'
|
|
66
|
+
| 'json'
|
|
67
|
+
| 'text'
|
|
68
|
+
|
|
16
69
|
export async function defineConfig(
|
|
17
70
|
c: Partial<DankConfig>,
|
|
18
71
|
): Promise<DankConfig> {
|
|
72
|
+
if (c.port !== null && typeof c.port !== 'undefined') {
|
|
73
|
+
if (typeof c.port !== 'number') {
|
|
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
|
+
}
|
|
19
82
|
validatePages(c.pages)
|
|
20
83
|
validateDevServices(c.services)
|
|
21
|
-
|
|
84
|
+
validateEsbuildConfig(c.esbuild)
|
|
85
|
+
normalizePagePaths(c.pages!)
|
|
22
86
|
return c as DankConfig
|
|
23
87
|
}
|
|
24
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
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
25
119
|
function validatePages(pages?: DankConfig['pages']) {
|
|
26
120
|
if (
|
|
27
121
|
pages === null ||
|
|
@@ -30,15 +124,42 @@ function validatePages(pages?: DankConfig['pages']) {
|
|
|
30
124
|
) {
|
|
31
125
|
throw Error('DankConfig.pages is required')
|
|
32
126
|
}
|
|
33
|
-
for (const [urlPath,
|
|
34
|
-
if (typeof
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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
|
|
38
134
|
}
|
|
135
|
+
throw Error(
|
|
136
|
+
`DankConfig.pages['${urlPath}'] must configure an html file`,
|
|
137
|
+
)
|
|
39
138
|
}
|
|
40
139
|
}
|
|
41
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
|
+
|
|
42
163
|
function validateDevServices(services: DankConfig['services']) {
|
|
43
164
|
if (services === null || typeof services === 'undefined') {
|
|
44
165
|
return
|
|
@@ -76,11 +197,26 @@ function validateDevServices(services: DankConfig['services']) {
|
|
|
76
197
|
}
|
|
77
198
|
}
|
|
78
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
|
+
}
|
|
79
207
|
}
|
|
80
208
|
}
|
|
81
209
|
|
|
82
|
-
function normalizePagePaths(pages:
|
|
83
|
-
for (const
|
|
84
|
-
|
|
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
|
+
}
|
|
85
217
|
}
|
|
86
218
|
}
|
|
219
|
+
|
|
220
|
+
function normalizePagePath(p: `${string}.html`): `${string}.html` {
|
|
221
|
+
return p.replace(/^\.\//, '') as `${string}.html`
|
|
222
|
+
}
|
package/lib/define.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { DankBuild } from './flags.ts'
|
|
2
2
|
|
|
3
3
|
export type DankGlobal = {
|
|
4
4
|
IS_DEV: boolean
|
|
@@ -9,10 +9,9 @@ type DefineDankGlobalKey = 'dank.IS_DEV' | 'dank.IS_PROD'
|
|
|
9
9
|
|
|
10
10
|
export type DefineDankGlobal = Record<DefineDankGlobalKey, string>
|
|
11
11
|
|
|
12
|
-
export function createGlobalDefinitions(): DefineDankGlobal {
|
|
13
|
-
const isProduction = isProductionBuild()
|
|
12
|
+
export function createGlobalDefinitions(build: DankBuild): DefineDankGlobal {
|
|
14
13
|
return {
|
|
15
|
-
'dank.IS_DEV': JSON.stringify(!
|
|
16
|
-
'dank.IS_PROD': JSON.stringify(
|
|
14
|
+
'dank.IS_DEV': JSON.stringify(!build.production),
|
|
15
|
+
'dank.IS_PROD': JSON.stringify(build.production),
|
|
17
16
|
}
|
|
18
17
|
}
|