@eighty4/dank 0.0.4 → 0.0.5-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/lib/config.ts +3 -2
- package/lib/dirs.ts +28 -5
- package/lib/esbuild.ts +9 -3
- package/lib/html.ts +2 -1
- package/lib/registry.ts +4 -6
- package/lib/serve.ts +8 -1
- package/lib_js/config.js +1 -1
- package/lib_js/dirs.js +22 -4
- package/lib_js/esbuild.js +5 -2
- package/lib_js/html.js +2 -1
- package/lib_js/registry.js +3 -3
- package/lib_js/serve.js +1 -1
- package/package.json +2 -2
package/lib/config.ts
CHANGED
|
@@ -45,14 +45,15 @@ export async function loadConfig(
|
|
|
45
45
|
throw Error()
|
|
46
46
|
}
|
|
47
47
|
const modulePath = resolve(projectRootAbs, DEFAULT_CONFIG_PATH)
|
|
48
|
+
const dirs = await defaultProjectDirs(projectRootAbs)
|
|
48
49
|
LOG({
|
|
49
50
|
realm: 'config',
|
|
50
51
|
message: 'loading config module',
|
|
51
52
|
data: {
|
|
53
|
+
dirs,
|
|
52
54
|
modulePath,
|
|
53
55
|
},
|
|
54
56
|
})
|
|
55
|
-
const dirs = await defaultProjectDirs(projectRootAbs)
|
|
56
57
|
const c = new DankConfigInternal(mode, modulePath, dirs)
|
|
57
58
|
await c.reload()
|
|
58
59
|
return c
|
|
@@ -149,7 +150,7 @@ async function resolveConfig(
|
|
|
149
150
|
modulePath: string,
|
|
150
151
|
details: DankDetails,
|
|
151
152
|
): Promise<DankConfig> {
|
|
152
|
-
const module = await import(
|
|
153
|
+
const module = await import(`file:${modulePath}?${Date.now()}`)
|
|
153
154
|
const c: Partial<DankConfig> =
|
|
154
155
|
typeof module.default === 'function'
|
|
155
156
|
? await module.default(details)
|
package/lib/dirs.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { realpath } from 'node:fs/promises'
|
|
2
2
|
import { dirname, isAbsolute, join, resolve } from 'node:path'
|
|
3
|
-
import { cwd } from 'node:process'
|
|
4
3
|
|
|
5
4
|
export type DankDirectories = {
|
|
6
5
|
buildRoot: string
|
|
@@ -17,9 +16,7 @@ export type DankDirectories = {
|
|
|
17
16
|
export async function defaultProjectDirs(
|
|
18
17
|
projectRootAbs: string,
|
|
19
18
|
): Promise<Readonly<DankDirectories>> {
|
|
20
|
-
if (!projectRootAbs) {
|
|
21
|
-
projectRootAbs = cwd()
|
|
22
|
-
} else if (!isAbsolute(projectRootAbs)) {
|
|
19
|
+
if (!isAbsolute(projectRootAbs)) {
|
|
23
20
|
throw Error()
|
|
24
21
|
}
|
|
25
22
|
const projectResolved = await realpath(projectRootAbs)
|
|
@@ -40,9 +37,17 @@ export async function defaultProjectDirs(
|
|
|
40
37
|
export type ResolveError = 'outofbounds'
|
|
41
38
|
|
|
42
39
|
export class Resolver {
|
|
40
|
+
static create(dirs: DankDirectories): Resolver {
|
|
41
|
+
if (process.platform === 'win32') {
|
|
42
|
+
return new WindowsResolver(dirs)
|
|
43
|
+
} else {
|
|
44
|
+
return new Resolver(dirs)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
43
48
|
#dirs: DankDirectories
|
|
44
49
|
|
|
45
|
-
constructor(dirs: DankDirectories) {
|
|
50
|
+
protected constructor(dirs: DankDirectories) {
|
|
46
51
|
this.#dirs = dirs
|
|
47
52
|
}
|
|
48
53
|
|
|
@@ -68,6 +73,10 @@ export class Resolver {
|
|
|
68
73
|
return this.isProjectSubpathInPagesDir(join(this.#dirs.pages, p))
|
|
69
74
|
}
|
|
70
75
|
|
|
76
|
+
projectPathFromAbsolute(p: string) {
|
|
77
|
+
return p.replace(this.#dirs.projectRootAbs, '').substring(1)
|
|
78
|
+
}
|
|
79
|
+
|
|
71
80
|
// resolve a pages subpath from a resource within the pages directory by a relative href
|
|
72
81
|
// `from` is expected to be a pages resource fs path starting with `pages/` and ending with filename
|
|
73
82
|
// the result will be a pages subpath and will not have the pages dir prefix
|
|
@@ -81,3 +90,17 @@ export class Resolver {
|
|
|
81
90
|
}
|
|
82
91
|
}
|
|
83
92
|
}
|
|
93
|
+
|
|
94
|
+
class WindowsResolver extends Resolver {
|
|
95
|
+
constructor(dirs: DankDirectories) {
|
|
96
|
+
super(dirs)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
projectPathFromAbsolute(p: string): string {
|
|
100
|
+
return super.projectPathFromAbsolute(p).replaceAll('\\', '/')
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
resolveHrefInPagesDir(from: string, href: string): string | ResolveError {
|
|
104
|
+
return super.resolveHrefInPagesDir(from, href).replaceAll('\\', '/')
|
|
105
|
+
}
|
|
106
|
+
}
|
package/lib/esbuild.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises'
|
|
2
|
+
// import { sep as windowsSep } from 'node:path/win32'
|
|
3
|
+
// import { sep as posixSep } from 'node:path/posix'
|
|
2
4
|
import esbuild, {
|
|
3
5
|
type BuildContext,
|
|
4
6
|
type BuildOptions,
|
|
@@ -123,6 +125,7 @@ export function workersPlugin(r: BuildRegistry): Plugin {
|
|
|
123
125
|
let contents = await readFile(args.path, 'utf8')
|
|
124
126
|
let offset = 0
|
|
125
127
|
let errors: Array<PartialMessage> | undefined = undefined
|
|
128
|
+
let clientScript: string | undefined = undefined
|
|
126
129
|
for (const workerCtorMatch of contents.matchAll(
|
|
127
130
|
WORKER_CTOR_REGEX,
|
|
128
131
|
)) {
|
|
@@ -143,9 +146,11 @@ export function workersPlugin(r: BuildRegistry): Plugin {
|
|
|
143
146
|
if (isIndexCommented(contents, workerCtorMatch.index)) {
|
|
144
147
|
continue
|
|
145
148
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
+
if (!clientScript) {
|
|
150
|
+
clientScript = r.resolver.projectPathFromAbsolute(
|
|
151
|
+
args.path,
|
|
152
|
+
)
|
|
153
|
+
}
|
|
149
154
|
const workerUrl = workerCtorMatch.groups!.url.substring(
|
|
150
155
|
1,
|
|
151
156
|
workerCtorMatch.groups!.url.length - 1,
|
|
@@ -174,6 +179,7 @@ export function workersPlugin(r: BuildRegistry): Plugin {
|
|
|
174
179
|
const workerUrlPlaceholder = workerEntryPoint
|
|
175
180
|
.replace(/^pages/, '')
|
|
176
181
|
.replace(/\.(t|m?j)s$/, '.js')
|
|
182
|
+
.replaceAll('\\', '/')
|
|
177
183
|
const workerCtorReplacement = `new ${workerCtor}('${workerUrlPlaceholder}'${workerCtorMatch.groups!.end}`
|
|
178
184
|
contents =
|
|
179
185
|
contents.substring(0, workerCtorMatch.index + offset) +
|
package/lib/html.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import EventEmitter from 'node:events'
|
|
2
2
|
import { readFile } from 'node:fs/promises'
|
|
3
|
-
import { dirname, isAbsolute,
|
|
3
|
+
import { dirname, isAbsolute, relative, resolve } from 'node:path'
|
|
4
|
+
import { join } from 'node:path/posix'
|
|
4
5
|
import { extname } from 'node:path/posix'
|
|
5
6
|
import {
|
|
6
7
|
defaultTreeAdapter,
|
package/lib/registry.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import EventEmitter from 'node:events'
|
|
2
2
|
import { writeFile } from 'node:fs/promises'
|
|
3
|
-
import { join } from 'node:path'
|
|
3
|
+
import { join } from 'node:path/posix'
|
|
4
4
|
import type { BuildResult } from 'esbuild'
|
|
5
5
|
import type { ResolvedDankConfig } from './config.ts'
|
|
6
|
+
import type { PageMapping } from './dank.ts'
|
|
6
7
|
import { LOG } from './developer.ts'
|
|
7
8
|
import { Resolver, type DankDirectories } from './dirs.ts'
|
|
8
9
|
import type { EntryPoint } from './esbuild.ts'
|
|
9
10
|
import { HtmlEntrypoint } from './html.ts'
|
|
10
|
-
import type { PageMapping } from './dank.ts'
|
|
11
11
|
|
|
12
12
|
// summary of a website build
|
|
13
13
|
export type WebsiteManifest = {
|
|
@@ -80,7 +80,7 @@ export class WebsiteRegistry extends EventEmitter<WebsiteRegistryEvents> {
|
|
|
80
80
|
constructor(config: ResolvedDankConfig) {
|
|
81
81
|
super()
|
|
82
82
|
this.#c = config
|
|
83
|
-
this.#resolver =
|
|
83
|
+
this.#resolver = Resolver.create(config.dirs)
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
get config(): ResolvedDankConfig {
|
|
@@ -257,6 +257,7 @@ export class WebsiteRegistry extends EventEmitter<WebsiteRegistryEvents> {
|
|
|
257
257
|
this.#setWebpageBundles(html.url, entrypoints),
|
|
258
258
|
)
|
|
259
259
|
this.emit('webpage', html)
|
|
260
|
+
html.emit('change')
|
|
260
261
|
}
|
|
261
262
|
|
|
262
263
|
#configPageUpdate(urlPath: `/${string}`, mapping: PageMapping) {
|
|
@@ -399,9 +400,7 @@ export class BuildRegistry {
|
|
|
399
400
|
return this.#resolver
|
|
400
401
|
}
|
|
401
402
|
|
|
402
|
-
// resolve web worker imported by a webpage module
|
|
403
403
|
addWorker(worker: Omit<WorkerManifest, 'dependentEntryPoint'>) {
|
|
404
|
-
// todo normalize path
|
|
405
404
|
if (!this.#workers) {
|
|
406
405
|
this.#workers = [worker]
|
|
407
406
|
} else {
|
|
@@ -433,7 +432,6 @@ export class BuildRegistry {
|
|
|
433
432
|
}
|
|
434
433
|
}
|
|
435
434
|
}
|
|
436
|
-
|
|
437
435
|
this.#onComplete({
|
|
438
436
|
bundles,
|
|
439
437
|
workers,
|
package/lib/serve.ts
CHANGED
|
@@ -66,7 +66,14 @@ async function startDevMode(signal: AbortSignal) {
|
|
|
66
66
|
await mkdir(c.dirs.buildWatch, { recursive: true })
|
|
67
67
|
let buildContext: BuildContextState = null
|
|
68
68
|
|
|
69
|
-
watch('dank.config.ts', signal, async
|
|
69
|
+
watch('dank.config.ts', signal, async filename => {
|
|
70
|
+
LOG({
|
|
71
|
+
realm: 'serve',
|
|
72
|
+
message: 'config watch event',
|
|
73
|
+
data: {
|
|
74
|
+
file: filename,
|
|
75
|
+
},
|
|
76
|
+
})
|
|
70
77
|
try {
|
|
71
78
|
await c.reload()
|
|
72
79
|
} catch (ignore) {
|
package/lib_js/config.js
CHANGED
|
@@ -84,7 +84,7 @@ function resolveEsbuildPort(flags, userConfig) {
|
|
|
84
84
|
return flags.esbuildPort || userConfig.esbuild?.port || DEFAULT_ESBUILD_PORT;
|
|
85
85
|
}
|
|
86
86
|
async function resolveConfig(modulePath, details) {
|
|
87
|
-
const module = await import(__rewriteRelativeImportExtension(
|
|
87
|
+
const module = await import(__rewriteRelativeImportExtension(`file:${modulePath}?${Date.now()}`));
|
|
88
88
|
const c = typeof module.default === "function" ? await module.default(details) : module.default;
|
|
89
89
|
validateDankConfig(c);
|
|
90
90
|
return c;
|
package/lib_js/dirs.js
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { realpath } from "node:fs/promises";
|
|
2
2
|
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
3
|
-
import { cwd } from "node:process";
|
|
4
3
|
async function defaultProjectDirs(projectRootAbs) {
|
|
5
|
-
if (!projectRootAbs) {
|
|
6
|
-
projectRootAbs = cwd();
|
|
7
|
-
} else if (!isAbsolute(projectRootAbs)) {
|
|
4
|
+
if (!isAbsolute(projectRootAbs)) {
|
|
8
5
|
throw Error();
|
|
9
6
|
}
|
|
10
7
|
const projectResolved = await realpath(projectRootAbs);
|
|
@@ -22,6 +19,13 @@ async function defaultProjectDirs(projectRootAbs) {
|
|
|
22
19
|
});
|
|
23
20
|
}
|
|
24
21
|
class Resolver {
|
|
22
|
+
static create(dirs) {
|
|
23
|
+
if (process.platform === "win32") {
|
|
24
|
+
return new WindowsResolver(dirs);
|
|
25
|
+
} else {
|
|
26
|
+
return new Resolver(dirs);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
25
29
|
#dirs;
|
|
26
30
|
constructor(dirs) {
|
|
27
31
|
this.#dirs = dirs;
|
|
@@ -42,6 +46,9 @@ class Resolver {
|
|
|
42
46
|
isPagesSubpathInPagesDir(p) {
|
|
43
47
|
return this.isProjectSubpathInPagesDir(join(this.#dirs.pages, p));
|
|
44
48
|
}
|
|
49
|
+
projectPathFromAbsolute(p) {
|
|
50
|
+
return p.replace(this.#dirs.projectRootAbs, "").substring(1);
|
|
51
|
+
}
|
|
45
52
|
// resolve a pages subpath from a resource within the pages directory by a relative href
|
|
46
53
|
// `from` is expected to be a pages resource fs path starting with `pages/` and ending with filename
|
|
47
54
|
// the result will be a pages subpath and will not have the pages dir prefix
|
|
@@ -55,6 +62,17 @@ class Resolver {
|
|
|
55
62
|
}
|
|
56
63
|
}
|
|
57
64
|
}
|
|
65
|
+
class WindowsResolver extends Resolver {
|
|
66
|
+
constructor(dirs) {
|
|
67
|
+
super(dirs);
|
|
68
|
+
}
|
|
69
|
+
projectPathFromAbsolute(p) {
|
|
70
|
+
return super.projectPathFromAbsolute(p).replaceAll("\\", "/");
|
|
71
|
+
}
|
|
72
|
+
resolveHrefInPagesDir(from, href) {
|
|
73
|
+
return super.resolveHrefInPagesDir(from, href).replaceAll("\\", "/");
|
|
74
|
+
}
|
|
75
|
+
}
|
|
58
76
|
export {
|
|
59
77
|
Resolver,
|
|
60
78
|
defaultProjectDirs
|
package/lib_js/esbuild.js
CHANGED
|
@@ -83,6 +83,7 @@ function workersPlugin(r) {
|
|
|
83
83
|
let contents = await readFile(args.path, "utf8");
|
|
84
84
|
let offset = 0;
|
|
85
85
|
let errors = void 0;
|
|
86
|
+
let clientScript = void 0;
|
|
86
87
|
for (const workerCtorMatch of contents.matchAll(WORKER_CTOR_REGEX)) {
|
|
87
88
|
if (!WORKER_URL_REGEX.test(workerCtorMatch.groups.url)) {
|
|
88
89
|
if (!errors)
|
|
@@ -93,7 +94,9 @@ function workersPlugin(r) {
|
|
|
93
94
|
if (isIndexCommented(contents, workerCtorMatch.index)) {
|
|
94
95
|
continue;
|
|
95
96
|
}
|
|
96
|
-
|
|
97
|
+
if (!clientScript) {
|
|
98
|
+
clientScript = r.resolver.projectPathFromAbsolute(args.path);
|
|
99
|
+
}
|
|
97
100
|
const workerUrl = workerCtorMatch.groups.url.substring(1, workerCtorMatch.groups.url.length - 1);
|
|
98
101
|
const workerEntryPoint = r.resolver.resolveHrefInPagesDir(clientScript, workerUrl);
|
|
99
102
|
if (workerEntryPoint === "outofbounds") {
|
|
@@ -103,7 +106,7 @@ function workersPlugin(r) {
|
|
|
103
106
|
continue;
|
|
104
107
|
}
|
|
105
108
|
const workerCtor = workerCtorMatch.groups.ctor;
|
|
106
|
-
const workerUrlPlaceholder = workerEntryPoint.replace(/^pages/, "").replace(/\.(t|m?j)s$/, ".js");
|
|
109
|
+
const workerUrlPlaceholder = workerEntryPoint.replace(/^pages/, "").replace(/\.(t|m?j)s$/, ".js").replaceAll("\\", "/");
|
|
107
110
|
const workerCtorReplacement = `new ${workerCtor}('${workerUrlPlaceholder}'${workerCtorMatch.groups.end}`;
|
|
108
111
|
contents = contents.substring(0, workerCtorMatch.index + offset) + workerCtorReplacement + contents.substring(workerCtorMatch.index + workerCtorMatch[0].length + offset);
|
|
109
112
|
offset += workerCtorReplacement.length - workerCtorMatch[0].length;
|
package/lib_js/html.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import EventEmitter from "node:events";
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
|
-
import { dirname, isAbsolute,
|
|
3
|
+
import { dirname, isAbsolute, relative, resolve } from "node:path";
|
|
4
|
+
import { join } from "node:path/posix";
|
|
4
5
|
import { extname } from "node:path/posix";
|
|
5
6
|
import { defaultTreeAdapter, parse, parseFragment, serialize } from "parse5";
|
|
6
7
|
import { DankError } from "./errors.js";
|
package/lib_js/registry.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import EventEmitter from "node:events";
|
|
2
2
|
import { writeFile } from "node:fs/promises";
|
|
3
|
-
import { join } from "node:path";
|
|
3
|
+
import { join } from "node:path/posix";
|
|
4
4
|
import { Resolver } from "./dirs.js";
|
|
5
5
|
import { HtmlEntrypoint } from "./html.js";
|
|
6
6
|
class WebsiteRegistry extends EventEmitter {
|
|
@@ -17,7 +17,7 @@ class WebsiteRegistry extends EventEmitter {
|
|
|
17
17
|
constructor(config) {
|
|
18
18
|
super();
|
|
19
19
|
this.#c = config;
|
|
20
|
-
this.#resolver =
|
|
20
|
+
this.#resolver = Resolver.create(config.dirs);
|
|
21
21
|
}
|
|
22
22
|
get config() {
|
|
23
23
|
return this.#c;
|
|
@@ -132,6 +132,7 @@ class WebsiteRegistry extends EventEmitter {
|
|
|
132
132
|
};
|
|
133
133
|
html.on("entrypoints", (entrypoints) => this.#setWebpageBundles(html.url, entrypoints));
|
|
134
134
|
this.emit("webpage", html);
|
|
135
|
+
html.emit("change");
|
|
135
136
|
}
|
|
136
137
|
#configPageUpdate(urlPath, mapping) {
|
|
137
138
|
const existingRegistration = this.#pages[urlPath];
|
|
@@ -218,7 +219,6 @@ class BuildRegistry {
|
|
|
218
219
|
get resolver() {
|
|
219
220
|
return this.#resolver;
|
|
220
221
|
}
|
|
221
|
-
// resolve web worker imported by a webpage module
|
|
222
222
|
addWorker(worker) {
|
|
223
223
|
if (!this.#workers) {
|
|
224
224
|
this.#workers = [worker];
|
package/lib_js/serve.js
CHANGED
|
@@ -36,7 +36,7 @@ async function startDevMode(signal) {
|
|
|
36
36
|
const registry = new WebsiteRegistry(c);
|
|
37
37
|
await mkdir(c.dirs.buildWatch, { recursive: true });
|
|
38
38
|
let buildContext = null;
|
|
39
|
-
watch("dank.config.ts", signal, async () => {
|
|
39
|
+
watch("dank.config.ts", signal, async (filename) => {
|
|
40
40
|
try {
|
|
41
41
|
await c.reload();
|
|
42
42
|
} catch (ignore) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eighty4/dank",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5-0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Adam McKee Bennett <adam.be.g84d@gmail.com>",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"build": "pnpm build:client && pnpm build:lib",
|
|
47
47
|
"build:client": "node scripts/build_client.ts",
|
|
48
48
|
"build:lib": "tsc && tsc -p tsconfig.exports.json",
|
|
49
|
-
"build:release": "pnpm build &&
|
|
49
|
+
"build:release": "pnpm build && node scripts/prepare_release.ts",
|
|
50
50
|
"fmt": "prettier --write .",
|
|
51
51
|
"fmtcheck": "prettier --check .",
|
|
52
52
|
"test": "node --test \"test/**/*.test.ts\"",
|