@eighty4/dank 0.0.4-2 → 0.0.4
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 +43 -70
- package/lib/build_tag.ts +3 -3
- package/lib/config.ts +184 -29
- package/lib/dank.ts +7 -0
- package/lib/define.ts +6 -4
- package/lib/developer.ts +33 -4
- package/lib/dirs.ts +83 -0
- package/lib/errors.ts +6 -0
- package/lib/esbuild.ts +19 -29
- package/lib/flags.ts +16 -122
- 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 +101 -336
- package/lib/services.ts +8 -8
- package/lib/watch.ts +39 -0
- package/lib_js/bin.js +8 -10
- package/lib_js/build.js +31 -45
- package/lib_js/build_tag.js +2 -2
- package/lib_js/config.js +108 -29
- package/lib_js/define.js +3 -3
- package/lib_js/dirs.js +61 -0
- package/lib_js/errors.js +9 -0
- package/lib_js/esbuild.js +17 -19
- package/lib_js/flags.js +9 -98
- package/lib_js/html.js +127 -64
- package/lib_js/http.js +18 -18
- package/lib_js/public.js +9 -9
- package/lib_js/{metadata.js → registry.js} +121 -51
- package/lib_js/serve.js +53 -177
- package/lib_js/services.js +6 -6
- package/lib_js/watch.js +35 -0
- package/lib_types/dank.d.ts +5 -0
- package/package.json +6 -4
- package/client/esbuild.js +0 -1
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
|
})
|
package/lib/flags.ts
CHANGED
|
@@ -1,84 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export type DankBuild = {
|
|
6
|
-
dirs: ProjectDirs
|
|
7
|
-
minify: boolean
|
|
8
|
-
production: boolean
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export type ProjectDirs = {
|
|
12
|
-
buildRoot: string
|
|
13
|
-
buildWatch: string
|
|
14
|
-
buildDist: string
|
|
15
|
-
pages: string
|
|
16
|
-
pagesResolved: string
|
|
17
|
-
projectResolved: string
|
|
18
|
-
projectRootAbs: string
|
|
19
|
-
public: string
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function resolveBuildFlags(): DankBuild {
|
|
23
|
-
const flags: DankBuild = {
|
|
24
|
-
dirs: defaultProjectDirs(cwd()),
|
|
25
|
-
minify: willMinify(),
|
|
26
|
-
production: isProductionBuild(),
|
|
27
|
-
}
|
|
28
|
-
return {
|
|
29
|
-
get dirs(): ProjectDirs {
|
|
30
|
-
return flags.dirs
|
|
31
|
-
},
|
|
32
|
-
get minify(): boolean {
|
|
33
|
-
return flags.minify
|
|
34
|
-
},
|
|
35
|
-
get production(): boolean {
|
|
36
|
-
return flags.production
|
|
37
|
-
},
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export type DankServe = DankBuild & {
|
|
42
|
-
dankPort: number
|
|
43
|
-
esbuildPort: number
|
|
1
|
+
export type DankFlags = {
|
|
2
|
+
dankPort?: number
|
|
3
|
+
esbuildPort?: number
|
|
44
4
|
logHttp: boolean
|
|
5
|
+
minify: boolean
|
|
45
6
|
preview: boolean
|
|
7
|
+
production: boolean
|
|
46
8
|
}
|
|
47
9
|
|
|
48
|
-
export function
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
dankPort: dankPort(c, preview),
|
|
53
|
-
esbuildPort: esbuildPort(c),
|
|
10
|
+
export function resolveFlags(): Readonly<DankFlags> {
|
|
11
|
+
return Object.freeze({
|
|
12
|
+
dankPort: resolveDankPort(),
|
|
13
|
+
esbuildPort: resolveEsbuildPort(),
|
|
54
14
|
logHttp: willLogHttp(),
|
|
55
15
|
minify: willMinify(),
|
|
56
|
-
preview,
|
|
16
|
+
preview: isPreviewBuild(),
|
|
57
17
|
production: isProductionBuild(),
|
|
58
|
-
}
|
|
59
|
-
return {
|
|
60
|
-
get dirs(): ProjectDirs {
|
|
61
|
-
return flags.dirs
|
|
62
|
-
},
|
|
63
|
-
get dankPort(): number {
|
|
64
|
-
return flags.dankPort
|
|
65
|
-
},
|
|
66
|
-
get esbuildPort(): number {
|
|
67
|
-
return flags.esbuildPort
|
|
68
|
-
},
|
|
69
|
-
get logHttp(): boolean {
|
|
70
|
-
return flags.logHttp
|
|
71
|
-
},
|
|
72
|
-
get minify(): boolean {
|
|
73
|
-
return flags.minify
|
|
74
|
-
},
|
|
75
|
-
get preview(): boolean {
|
|
76
|
-
return flags.preview
|
|
77
|
-
},
|
|
78
|
-
get production(): boolean {
|
|
79
|
-
return flags.production
|
|
80
|
-
},
|
|
81
|
-
}
|
|
18
|
+
})
|
|
82
19
|
}
|
|
83
20
|
|
|
84
21
|
// `dank serve` will pre-bundle and use service worker
|
|
@@ -87,24 +24,21 @@ const isPreviewBuild = () =>
|
|
|
87
24
|
|
|
88
25
|
// `dank build` will minify sources and append git release tag to build tag
|
|
89
26
|
// `dank serve` will pre-bundle with service worker and minify
|
|
90
|
-
|
|
27
|
+
const isProductionBuild = () =>
|
|
91
28
|
process.env.PRODUCTION === 'true' || process.argv.includes('--production')
|
|
92
29
|
|
|
93
|
-
// `dank serve`
|
|
94
|
-
|
|
95
|
-
function dankPort(c: DankConfig, preview: boolean): number {
|
|
30
|
+
// `dank serve` port for frontend webserver
|
|
31
|
+
function resolveDankPort(): number | undefined {
|
|
96
32
|
if (process.env.DANK_PORT?.length) {
|
|
97
33
|
return parsePortEnvVar('DANK_PORT')
|
|
98
34
|
}
|
|
99
|
-
return preview ? c.previewPort || c.port || 4000 : c.port || 3000
|
|
100
35
|
}
|
|
101
36
|
|
|
102
|
-
// `dank serve`
|
|
103
|
-
function
|
|
37
|
+
// `dank serve` port for esbuild bundler integration
|
|
38
|
+
function resolveEsbuildPort(): number | undefined {
|
|
104
39
|
if (process.env.ESBUILD_PORT?.length) {
|
|
105
40
|
return parsePortEnvVar('ESBUILD_PORT')
|
|
106
41
|
}
|
|
107
|
-
return c.esbuild?.port || 3995
|
|
108
42
|
}
|
|
109
43
|
|
|
110
44
|
function parsePortEnvVar(name: string): number {
|
|
@@ -116,46 +50,6 @@ function parsePortEnvVar(name: string): number {
|
|
|
116
50
|
}
|
|
117
51
|
}
|
|
118
52
|
|
|
119
|
-
export function defaultProjectDirs(projectRootAbs: string): ProjectDirs {
|
|
120
|
-
const pages = 'pages'
|
|
121
|
-
const dirs: ProjectDirs = {
|
|
122
|
-
buildRoot: 'build',
|
|
123
|
-
buildDist: join('build', 'dist'),
|
|
124
|
-
buildWatch: join('build', 'watch'),
|
|
125
|
-
pages,
|
|
126
|
-
pagesResolved: resolve(join(projectRootAbs, pages)),
|
|
127
|
-
projectResolved: resolve(projectRootAbs),
|
|
128
|
-
projectRootAbs,
|
|
129
|
-
public: 'public',
|
|
130
|
-
}
|
|
131
|
-
return {
|
|
132
|
-
get buildRoot(): string {
|
|
133
|
-
return dirs.buildRoot
|
|
134
|
-
},
|
|
135
|
-
get buildDist(): string {
|
|
136
|
-
return dirs.buildDist
|
|
137
|
-
},
|
|
138
|
-
get buildWatch(): string {
|
|
139
|
-
return dirs.buildWatch
|
|
140
|
-
},
|
|
141
|
-
get pages(): string {
|
|
142
|
-
return dirs.pages
|
|
143
|
-
},
|
|
144
|
-
get pagesResolved(): string {
|
|
145
|
-
return dirs.pagesResolved
|
|
146
|
-
},
|
|
147
|
-
get projectResolved(): string {
|
|
148
|
-
return dirs.projectResolved
|
|
149
|
-
},
|
|
150
|
-
get projectRootAbs(): string {
|
|
151
|
-
return dirs.projectRootAbs
|
|
152
|
-
},
|
|
153
|
-
get public(): string {
|
|
154
|
-
return dirs.public
|
|
155
|
-
},
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
53
|
const willMinify = () =>
|
|
160
54
|
isProductionBuild() ||
|
|
161
55
|
process.env.MINIFY === 'true' ||
|