@sealcode/sealgen 0.14.3 → 0.14.5
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/@types/src/builder.d.ts +36 -0
- package/@types/src/embeddable-file-extensions.d.ts +1 -0
- package/@types/src/esbuild-plugins/load-assets.d.ts +4 -0
- package/@types/src/esbuild-plugins/rewrite-asset-imports.d.ts +4 -0
- package/@types/src/generate-stimulus.d.ts +1 -0
- package/@types/src/page/stateful-page.d.ts +1 -1
- package/@types/src/templates/stimulus-controller.d.ts +1 -0
- package/dist/build.js +29 -213
- package/dist/builder.js +145 -0
- package/dist/cli.js +3 -1
- package/dist/embeddable-file-extensions.js +5 -0
- package/dist/esbuild-plugins/load-assets.js +67 -0
- package/dist/esbuild-plugins/rewrite-asset-imports.js +30 -0
- package/dist/find-css-includes.js +2 -2
- package/dist/generate-components.js +1 -3
- package/dist/generate-stimulus.js +41 -0
- package/dist/page/stateful-page.js +3 -2
- package/dist/templates/stimulus-controller.js +21 -0
- package/package.json +1 -1
- package/src/build.ts +30 -234
- package/src/builder.ts +176 -0
- package/src/cli.ts +3 -1
- package/src/embeddable-file-extensions.ts +1 -0
- package/src/esbuild-plugins/load-assets.ts +68 -0
- package/src/esbuild-plugins/rewrite-asset-imports.ts +29 -0
- package/src/find-css-includes.ts +17 -15
- package/src/generate-components.ts +3 -3
- package/src/generate-stimulus.ts +52 -0
- package/src/page/stateful-page.ts +8 -3
- package/src/templates/stimulus-controller.ts +18 -0
|
@@ -16,7 +16,8 @@ class StatefulPage extends Mountable {
|
|
|
16
16
|
this.wrapInForm(
|
|
17
17
|
state,
|
|
18
18
|
await original_render(ctx, state, inputs)
|
|
19
|
-
)
|
|
19
|
+
),
|
|
20
|
+
state
|
|
20
21
|
);
|
|
21
22
|
};
|
|
22
23
|
}
|
|
@@ -123,7 +124,7 @@ class StatefulPage extends Mountable {
|
|
|
123
124
|
options
|
|
124
125
|
);
|
|
125
126
|
} else if (target.indexOf(item) === -1) {
|
|
126
|
-
destination
|
|
127
|
+
destination[index] = item;
|
|
127
128
|
}
|
|
128
129
|
});
|
|
129
130
|
return destination;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { toKebabCase, toPascalCase } from "js-convert-case";
|
|
2
|
+
function jddComponentTemplate(controller_name) {
|
|
3
|
+
return `import { Controller } from "stimulus";
|
|
4
|
+
|
|
5
|
+
export default class ${toPascalCase(controller_name)} extends Controller {
|
|
6
|
+
|
|
7
|
+
connect() {
|
|
8
|
+
console.warn(
|
|
9
|
+
"Remove ${toKebabCase(
|
|
10
|
+
controller_name
|
|
11
|
+
)}.stimulus.ts file if your JDD component doesn't need any browser-side logic"
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
`;
|
|
17
|
+
}
|
|
18
|
+
export {
|
|
19
|
+
jddComponentTemplate
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=stimulus-controller.js.map
|
package/package.json
CHANGED
package/src/build.ts
CHANGED
|
@@ -1,21 +1,16 @@
|
|
|
1
|
-
import { build, BuildContext, context } from "esbuild";
|
|
2
1
|
import { promises as fs } from "fs";
|
|
3
2
|
import * as chokidar from "chokidar";
|
|
4
|
-
import { default as glob } from "tiny-glob";
|
|
5
|
-
import { generate_css_includes } from "./find-css-includes.js";
|
|
6
|
-
import { sleep } from "./utils/sleep.js";
|
|
7
|
-
import { generateCollections } from "./generate-collections.js";
|
|
8
|
-
import { generateRoutes } from "./generate-routes.js";
|
|
9
|
-
import { generateComponents } from "./generate-components.js";
|
|
10
3
|
import { make_notifier } from "./notifier.js";
|
|
11
4
|
import getPort from "get-port";
|
|
12
|
-
import { removeNamedImports } from "../remove-named-imports.js";
|
|
13
|
-
import md5 from "md5";
|
|
14
5
|
|
|
15
6
|
import _locreq from "locreq";
|
|
16
|
-
|
|
17
|
-
import {
|
|
18
|
-
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
BackendTSBuilder,
|
|
10
|
+
CSSBuilder,
|
|
11
|
+
FontsBuilder,
|
|
12
|
+
FrontendTSBuilder,
|
|
13
|
+
} from "./builder.js";
|
|
19
14
|
const target_locreq = _locreq(process.cwd());
|
|
20
15
|
|
|
21
16
|
async function get_notifier_port() {
|
|
@@ -33,229 +28,37 @@ async function write_notifier_config(watch: boolean, port?: number) {
|
|
|
33
28
|
);
|
|
34
29
|
}
|
|
35
30
|
|
|
36
|
-
function
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
target_locreq.resolve(path.resolve(public_dir, public_url))
|
|
49
|
-
);
|
|
50
|
-
return "/" + public_url;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async function build_ts() {
|
|
54
|
-
await Promise.all([
|
|
55
|
-
generateCollections(),
|
|
56
|
-
generateRoutes(),
|
|
57
|
-
generateComponents(),
|
|
58
|
-
]);
|
|
59
|
-
const embeddable_file_extensions = ["svg", "png", "jpg", "jpeg", "webp"];
|
|
60
|
-
const entryPoints = (
|
|
61
|
-
await glob(
|
|
62
|
-
`./src/back/**/*.{ts,tsx,${embeddable_file_extensions.join(",")}}`
|
|
63
|
-
)
|
|
64
|
-
).filter((path) => !path.includes(".#"));
|
|
65
|
-
try {
|
|
66
|
-
await build({
|
|
67
|
-
entryPoints,
|
|
68
|
-
sourcemap: true,
|
|
69
|
-
bundle: false,
|
|
70
|
-
jsxFactory: "TempstreamJSX.createElement",
|
|
71
|
-
outdir: "./dist/back",
|
|
72
|
-
logLevel: "info",
|
|
73
|
-
platform: "node",
|
|
74
|
-
target: "es2022",
|
|
75
|
-
format: "esm",
|
|
76
|
-
loader: Object.fromEntries(
|
|
77
|
-
embeddable_file_extensions.map((ext) => ["." + ext, "js"])
|
|
78
|
-
),
|
|
79
|
-
plugins: [
|
|
80
|
-
{
|
|
81
|
-
name: "sealgen-rewrite-asset-imports",
|
|
82
|
-
setup(build) {
|
|
83
|
-
build.onLoad(
|
|
84
|
-
{ filter: /\.tsx?$/ },
|
|
85
|
-
async (args: any) => {
|
|
86
|
-
let contents = await fs.readFile(
|
|
87
|
-
args.path,
|
|
88
|
-
"utf8"
|
|
89
|
-
);
|
|
90
|
-
for (const ext of embeddable_file_extensions) {
|
|
91
|
-
const regex = new RegExp(
|
|
92
|
-
`^import (\\w+|{[^}]+}) from "([^"]+.${ext})";`,
|
|
93
|
-
"gm"
|
|
94
|
-
);
|
|
95
|
-
contents = contents.replaceAll(
|
|
96
|
-
regex,
|
|
97
|
-
(line) => {
|
|
98
|
-
return line.replace(
|
|
99
|
-
`.${ext}"`,
|
|
100
|
-
'.js"'
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
contents = removeNamedImports(contents);
|
|
107
|
-
|
|
108
|
-
return {
|
|
109
|
-
contents,
|
|
110
|
-
loader:
|
|
111
|
-
extname(args.path) === ".tsx"
|
|
112
|
-
? "tsx"
|
|
113
|
-
: "ts",
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
);
|
|
117
|
-
},
|
|
118
|
-
},
|
|
119
|
-
{
|
|
120
|
-
name: "sealgen-load-assets",
|
|
121
|
-
setup(build) {
|
|
122
|
-
build.onLoad(
|
|
123
|
-
{
|
|
124
|
-
filter: new RegExp(
|
|
125
|
-
`\\.(${embeddable_file_extensions.join(
|
|
126
|
-
"|"
|
|
127
|
-
)})$`
|
|
128
|
-
),
|
|
129
|
-
},
|
|
130
|
-
async (args: any) => {
|
|
131
|
-
let contents = `export const url = "${await makeResourceURL(
|
|
132
|
-
args.path
|
|
133
|
-
)}";
|
|
134
|
-
|
|
135
|
-
import fs from "fs";
|
|
136
|
-
let buffer_promise = null;
|
|
137
|
-
|
|
138
|
-
export const getBuffer = function(){
|
|
139
|
-
if(buffer_promise) return buffer_promise;
|
|
140
|
-
buffer_promise = fs.promises.readFile("${args.path}");
|
|
141
|
-
return buffer_promise;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
export const getContent = async function(){
|
|
145
|
-
const buffer = await getBuffer();
|
|
146
|
-
return buffer.toString("utf-8");
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
export const getBase64 = async function(){
|
|
150
|
-
const buffer = await getBuffer();
|
|
151
|
-
return buffer.toString("base64");
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
export default { getContent, url, getBase64, getBuffer };
|
|
155
|
-
`;
|
|
156
|
-
return {
|
|
157
|
-
contents,
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
);
|
|
161
|
-
},
|
|
162
|
-
},
|
|
163
|
-
],
|
|
164
|
-
});
|
|
165
|
-
} catch (e) {
|
|
166
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
167
|
-
console.error(e.message);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
async function complex_build(watch: boolean): Promise<void> {
|
|
172
|
-
const loader = Object.fromEntries(
|
|
173
|
-
(<const>["png", "svg", "jpg", "gif", "jpeg", "otf", "ttf"]).map(
|
|
174
|
-
(ext) => <const>["." + ext, "file"]
|
|
175
|
-
)
|
|
176
|
-
);
|
|
177
|
-
let css_build: BuildContext = await context({
|
|
178
|
-
entryPoints: ["./src/main.css"],
|
|
179
|
-
sourcemap: true,
|
|
180
|
-
bundle: true,
|
|
181
|
-
outdir: "./public/dist",
|
|
182
|
-
logLevel: "info",
|
|
183
|
-
// plugins: [sassPlugin()],
|
|
184
|
-
loader,
|
|
185
|
-
});
|
|
186
|
-
let ongoing_fonts = false;
|
|
187
|
-
let ongoing_ts = false;
|
|
188
|
-
let ongoing_css = false;
|
|
189
|
-
let ongoing_ts_promise: Promise<any> | null = null;
|
|
31
|
+
async function build(watch: boolean): Promise<void> {
|
|
32
|
+
const fonts_builder = new FontsBuilder();
|
|
33
|
+
const backend_ts_builder = new BackendTSBuilder();
|
|
34
|
+
const frontend_ts_builder = new FrontendTSBuilder();
|
|
35
|
+
const css_builder = new CSSBuilder();
|
|
36
|
+
const builders = [
|
|
37
|
+
fonts_builder,
|
|
38
|
+
backend_ts_builder,
|
|
39
|
+
css_builder,
|
|
40
|
+
frontend_ts_builder,
|
|
41
|
+
];
|
|
42
|
+
await Promise.all(builders.map((b) => b.build()));
|
|
190
43
|
if (watch) {
|
|
191
44
|
const watcher = chokidar.watch("src", { ignoreInitial: true });
|
|
192
45
|
const port = await get_notifier_port();
|
|
193
46
|
const notifier = make_notifier(port);
|
|
194
47
|
await write_notifier_config(watch, port);
|
|
195
|
-
watcher.on("all", async (_,
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
if (
|
|
200
|
-
|
|
201
|
-
await getFonts();
|
|
202
|
-
ongoing_fonts = false;
|
|
203
|
-
}
|
|
204
|
-
return;
|
|
205
|
-
}
|
|
206
|
-
if (path.endsWith(".css") && !path.endsWith("/includes.css")) {
|
|
207
|
-
if (ongoing_css) {
|
|
208
|
-
return;
|
|
209
|
-
}
|
|
210
|
-
ongoing_css = true;
|
|
211
|
-
// refresh the list of all css files in includes.css
|
|
212
|
-
await generate_css_includes();
|
|
213
|
-
try {
|
|
214
|
-
await css_build?.rebuild?.();
|
|
215
|
-
console.log(`Built main.css [on ${path}]`);
|
|
216
|
-
} catch (e) {
|
|
217
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
218
|
-
console.error(e.message);
|
|
219
|
-
await sleep(200);
|
|
220
|
-
css_build
|
|
221
|
-
?.rebuild?.()
|
|
222
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
223
|
-
.catch((e) => console.error(e?.message));
|
|
48
|
+
watcher.on("all", async (_, file_path) => {
|
|
49
|
+
console.log("Detected a change!", file_path);
|
|
50
|
+
builders.forEach((builder) => {
|
|
51
|
+
const owns_a_file = builder.ownsFile(file_path);
|
|
52
|
+
if (owns_a_file) {
|
|
53
|
+
builder.build(notifier);
|
|
224
54
|
}
|
|
225
|
-
|
|
226
|
-
await ongoing_ts_promise;
|
|
227
|
-
}
|
|
228
|
-
notifier("css");
|
|
229
|
-
ongoing_css = false;
|
|
230
|
-
}
|
|
231
|
-
if (
|
|
232
|
-
(path.endsWith(".ts") || path.endsWith(".tsx")) &&
|
|
233
|
-
!path.endsWith("src/back/collections/collections.ts") &&
|
|
234
|
-
!path.endsWith("src/back/routes/routes.ts") &&
|
|
235
|
-
!path.endsWith("src/back/routes/urls.ts")
|
|
236
|
-
) {
|
|
237
|
-
if (ongoing_ts) {
|
|
238
|
-
return;
|
|
239
|
-
}
|
|
240
|
-
ongoing_ts = true;
|
|
241
|
-
ongoing_ts_promise = build_ts();
|
|
242
|
-
await ongoing_ts_promise;
|
|
243
|
-
notifier("ts");
|
|
244
|
-
ongoing_ts_promise = null;
|
|
245
|
-
console.log(`Finished TS build [on ${path}]`);
|
|
246
|
-
ongoing_ts = false;
|
|
247
|
-
}
|
|
55
|
+
});
|
|
248
56
|
});
|
|
249
57
|
} else {
|
|
250
58
|
await write_notifier_config(watch);
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
await Promise.all([css_build.rebuild(), build_ts()]);
|
|
255
|
-
if (watch) {
|
|
256
|
-
css_build?.rebuild?.();
|
|
257
|
-
} else {
|
|
258
|
-
css_build.dispose();
|
|
59
|
+
builders.forEach((builder) => {
|
|
60
|
+
builder.dispose();
|
|
61
|
+
});
|
|
259
62
|
}
|
|
260
63
|
}
|
|
261
64
|
|
|
@@ -265,14 +68,7 @@ export async function buildProject({
|
|
|
265
68
|
watch: boolean;
|
|
266
69
|
}): Promise<void> {
|
|
267
70
|
try {
|
|
268
|
-
await build(
|
|
269
|
-
entryPoints: ["./src/front/index.ts"],
|
|
270
|
-
sourcemap: true,
|
|
271
|
-
outfile: "./public/dist/bundle.js",
|
|
272
|
-
logLevel: "info",
|
|
273
|
-
bundle: true,
|
|
274
|
-
});
|
|
275
|
-
await complex_build(watch);
|
|
71
|
+
await build(watch);
|
|
276
72
|
} catch (e) {
|
|
277
73
|
console.log("CAUGHT!");
|
|
278
74
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
package/src/builder.ts
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { build, BuildContext, context } from "esbuild";
|
|
2
|
+
import glob from "tiny-glob";
|
|
3
|
+
import { embeddable_file_extensions } from "./embeddable-file-extensions.js";
|
|
4
|
+
import { load_assets_plugin } from "./esbuild-plugins/load-assets.js";
|
|
5
|
+
import { rewrite_asset_imports_plugin } from "./esbuild-plugins/rewrite-asset-imports.js";
|
|
6
|
+
import { generate_css_includes } from "./find-css-includes.js";
|
|
7
|
+
import { generateCollections } from "./generate-collections.js";
|
|
8
|
+
import { generateComponents } from "./generate-components.js";
|
|
9
|
+
import { generateRoutes } from "./generate-routes.js";
|
|
10
|
+
import { generateStimulusControllers } from "./generate-stimulus.js";
|
|
11
|
+
import { FONTS_CONFIG_PATH, getFonts } from "./get-fonts.js";
|
|
12
|
+
|
|
13
|
+
export abstract class Builder {
|
|
14
|
+
abstract ownsFile(file_path: string): boolean;
|
|
15
|
+
abstract getName(): string;
|
|
16
|
+
abstract _build(): Promise<void>;
|
|
17
|
+
abstract dispose(): Promise<void>;
|
|
18
|
+
|
|
19
|
+
constructor() {}
|
|
20
|
+
|
|
21
|
+
public ongoing_build: Promise<void> | null = null;
|
|
22
|
+
|
|
23
|
+
public build(notifier?: (message: string) => void) {
|
|
24
|
+
if (!this.ongoing_build) {
|
|
25
|
+
const build = this._build()
|
|
26
|
+
.catch((err) => {
|
|
27
|
+
console.error(err);
|
|
28
|
+
})
|
|
29
|
+
.then(() => {
|
|
30
|
+
notifier?.(this.getName());
|
|
31
|
+
this.ongoing_build = null;
|
|
32
|
+
});
|
|
33
|
+
this.ongoing_build = build;
|
|
34
|
+
}
|
|
35
|
+
return this.ongoing_build;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export class CSSBuilder extends Builder {
|
|
40
|
+
getName(): string {
|
|
41
|
+
return "css";
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
private context_promise: Promise<BuildContext> | null;
|
|
45
|
+
|
|
46
|
+
ownsFile(file_path: string) {
|
|
47
|
+
return (
|
|
48
|
+
file_path.endsWith(".css") && !file_path.endsWith("/includes.css")
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async dispose(): Promise<void> {
|
|
53
|
+
return (await this.getBuildContext()).dispose();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async getBuildContext(): Promise<BuildContext> {
|
|
57
|
+
if (!this.context_promise) {
|
|
58
|
+
const loader = Object.fromEntries(
|
|
59
|
+
(<const>["png", "svg", "jpg", "gif", "jpeg", "otf", "ttf"]).map(
|
|
60
|
+
(ext) => <const>["." + ext, "file"]
|
|
61
|
+
)
|
|
62
|
+
);
|
|
63
|
+
const context_promise = context({
|
|
64
|
+
entryPoints: ["./src/main.css"],
|
|
65
|
+
sourcemap: true,
|
|
66
|
+
bundle: true,
|
|
67
|
+
outdir: "./public/dist",
|
|
68
|
+
logLevel: "info",
|
|
69
|
+
// plugins: [sassPlugin()],
|
|
70
|
+
loader,
|
|
71
|
+
});
|
|
72
|
+
this.context_promise = context_promise;
|
|
73
|
+
return context_promise;
|
|
74
|
+
} else {
|
|
75
|
+
return this.context_promise;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async _build() {
|
|
80
|
+
const context = await this.getBuildContext();
|
|
81
|
+
await generate_css_includes();
|
|
82
|
+
await context.rebuild();
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export class FontsBuilder extends Builder {
|
|
87
|
+
getName(): string {
|
|
88
|
+
return "fonts";
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
ownsFile(file_path: string) {
|
|
92
|
+
return file_path == FONTS_CONFIG_PATH;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async dispose(): Promise<void> {}
|
|
96
|
+
|
|
97
|
+
async _build() {
|
|
98
|
+
return getFonts();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export class BackendTSBuilder extends Builder {
|
|
103
|
+
getName(): string {
|
|
104
|
+
return "backend-ts";
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
ownsFile(file_path: string) {
|
|
108
|
+
return (
|
|
109
|
+
(file_path.endsWith(".ts") || file_path.endsWith(".tsx")) &&
|
|
110
|
+
!file_path.endsWith("src/back/collections/collections.ts") &&
|
|
111
|
+
!file_path.endsWith("src/back/routes/routes.ts") &&
|
|
112
|
+
!file_path.endsWith("src/back/routes/urls.ts") &&
|
|
113
|
+
!file_path.endsWith("stimulus.ts") &&
|
|
114
|
+
!file_path.startsWith("src/front")
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async dispose(): Promise<void> {}
|
|
119
|
+
|
|
120
|
+
async _build(): Promise<void> {
|
|
121
|
+
await Promise.all([
|
|
122
|
+
generateCollections(),
|
|
123
|
+
generateRoutes(),
|
|
124
|
+
generateComponents(),
|
|
125
|
+
]);
|
|
126
|
+
const entryPoints = (
|
|
127
|
+
await glob(
|
|
128
|
+
`./src/back/**/*.{ts,tsx,${embeddable_file_extensions.join(
|
|
129
|
+
","
|
|
130
|
+
)}}`
|
|
131
|
+
)
|
|
132
|
+
).filter((path) => !path.includes(".#"));
|
|
133
|
+
await build({
|
|
134
|
+
entryPoints,
|
|
135
|
+
sourcemap: true,
|
|
136
|
+
bundle: false,
|
|
137
|
+
jsxFactory: "TempstreamJSX.createElement",
|
|
138
|
+
outdir: "./dist/back",
|
|
139
|
+
logLevel: "info",
|
|
140
|
+
platform: "node",
|
|
141
|
+
target: "es2022",
|
|
142
|
+
format: "esm",
|
|
143
|
+
loader: Object.fromEntries(
|
|
144
|
+
embeddable_file_extensions.map((ext) => ["." + ext, "js"])
|
|
145
|
+
),
|
|
146
|
+
plugins: [rewrite_asset_imports_plugin, load_assets_plugin],
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export class FrontendTSBuilder extends Builder {
|
|
152
|
+
getName(): string {
|
|
153
|
+
return "frontend-ts";
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
ownsFile(file_path: string) {
|
|
157
|
+
return (
|
|
158
|
+
file_path.startsWith("src/front") ||
|
|
159
|
+
file_path.endsWith(".stimulus.ts")
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
async dispose(): Promise<void> {}
|
|
164
|
+
|
|
165
|
+
async _build(): Promise<void> {
|
|
166
|
+
await generateStimulusControllers();
|
|
167
|
+
await build({
|
|
168
|
+
entryPoints: ["./src/front/index.ts"],
|
|
169
|
+
sourcemap: true,
|
|
170
|
+
outfile: "./public/dist/bundle.js",
|
|
171
|
+
logLevel: "info",
|
|
172
|
+
bundle: true,
|
|
173
|
+
minify: true,
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
}
|
package/src/cli.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { generateRoutes } from "./generate-routes.js";
|
|
|
10
10
|
import { makeEnv } from "./make-env.js";
|
|
11
11
|
import yargs from "yargs/yargs";
|
|
12
12
|
import { getFonts } from "./get-fonts.js";
|
|
13
|
+
import { generateStimulusControllers } from "./generate-stimulus.js";
|
|
13
14
|
|
|
14
15
|
const actions: Record<
|
|
15
16
|
string,
|
|
@@ -32,7 +33,8 @@ const actions: Record<
|
|
|
32
33
|
},
|
|
33
34
|
"make-env": makeEnv,
|
|
34
35
|
"add-component": addJDDComponent,
|
|
35
|
-
|
|
36
|
+
"get-fonts": getFonts,
|
|
37
|
+
"generate-stimulus": generateStimulusControllers,
|
|
36
38
|
};
|
|
37
39
|
|
|
38
40
|
void (async function () {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const embeddable_file_extensions = ["svg", "png", "jpg", "jpeg", "webp"];
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { copyFile } from "fs/promises";
|
|
2
|
+
import { promises as fs } from "fs";
|
|
3
|
+
import md5 from "md5";
|
|
4
|
+
import path, { basename } from "node:path";
|
|
5
|
+
|
|
6
|
+
import _locreq from "locreq";
|
|
7
|
+
import { embeddable_file_extensions } from "../embeddable-file-extensions.js";
|
|
8
|
+
const target_locreq = _locreq(process.cwd());
|
|
9
|
+
|
|
10
|
+
function addSuffix(filename: string, suffix: string) {
|
|
11
|
+
return filename.replace(/(\.[a-zA-Z0-9]+)?$/, suffix + "$1");
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async function makeResourceURL(file_path: string) {
|
|
15
|
+
const hash_base = file_path + (await fs.stat(file_path)).mtimeMs;
|
|
16
|
+
const hash = md5(hash_base);
|
|
17
|
+
const public_url =
|
|
18
|
+
"dist/" + addSuffix(basename(file_path), "-" + hash.slice(0, 8));
|
|
19
|
+
const public_dir = "public";
|
|
20
|
+
await copyFile(
|
|
21
|
+
file_path,
|
|
22
|
+
target_locreq.resolve(path.resolve(public_dir, public_url))
|
|
23
|
+
);
|
|
24
|
+
return "/" + public_url;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const load_assets_plugin = {
|
|
28
|
+
name: "sealgen-load-assets",
|
|
29
|
+
setup(build: any) {
|
|
30
|
+
build.onLoad(
|
|
31
|
+
{
|
|
32
|
+
filter: new RegExp(
|
|
33
|
+
`\\.(${embeddable_file_extensions.join("|")})$`
|
|
34
|
+
),
|
|
35
|
+
},
|
|
36
|
+
async (args: any) => {
|
|
37
|
+
let contents = `export const url = "${await makeResourceURL(
|
|
38
|
+
args.path
|
|
39
|
+
)}";
|
|
40
|
+
|
|
41
|
+
import fs from "fs";
|
|
42
|
+
let buffer_promise = null;
|
|
43
|
+
|
|
44
|
+
export const getBuffer = function(){
|
|
45
|
+
if(buffer_promise) return buffer_promise;
|
|
46
|
+
buffer_promise = fs.promises.readFile("${args.path}");
|
|
47
|
+
return buffer_promise;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export const getContent = async function(){
|
|
51
|
+
const buffer = await getBuffer();
|
|
52
|
+
return buffer.toString("utf-8");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export const getBase64 = async function(){
|
|
56
|
+
const buffer = await getBuffer();
|
|
57
|
+
return buffer.toString("base64");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export default { getContent, url, getBase64, getBuffer };
|
|
61
|
+
`;
|
|
62
|
+
return {
|
|
63
|
+
contents,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
);
|
|
67
|
+
},
|
|
68
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { promises as fs } from "fs";
|
|
2
|
+
import { extname } from "node:path";
|
|
3
|
+
import { embeddable_file_extensions } from "../embeddable-file-extensions.js";
|
|
4
|
+
import { removeNamedImports } from "../../remove-named-imports.js";
|
|
5
|
+
|
|
6
|
+
export const rewrite_asset_imports_plugin = {
|
|
7
|
+
name: "sealgen-rewrite-asset-imports",
|
|
8
|
+
setup(build: any) {
|
|
9
|
+
build.onLoad({ filter: /\.tsx?$/ }, async (args: any) => {
|
|
10
|
+
let contents = await fs.readFile(args.path, "utf8");
|
|
11
|
+
for (const ext of embeddable_file_extensions) {
|
|
12
|
+
const regex_assets = new RegExp(
|
|
13
|
+
`^import (\\w+|{[^}]+}) from "([^"]+.${ext})";`,
|
|
14
|
+
"gm"
|
|
15
|
+
);
|
|
16
|
+
contents = contents.replaceAll(regex_assets, (line) => {
|
|
17
|
+
return line.replace(`.${ext}"`, '.js"');
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
contents = removeNamedImports(contents);
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
contents,
|
|
25
|
+
loader: extname(args.path) === ".tsx" ? "tsx" : "ts",
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
},
|
|
29
|
+
};
|
package/src/find-css-includes.ts
CHANGED
|
@@ -6,21 +6,23 @@ import { walkDir } from "./utils/walk.js";
|
|
|
6
6
|
const target_locreq = _locreq(process.cwd());
|
|
7
7
|
|
|
8
8
|
export async function generate_css_includes(): Promise<void> {
|
|
9
|
-
const files =
|
|
10
|
-
|
|
11
|
-
.
|
|
12
|
-
(
|
|
13
|
-
f
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
9
|
+
const files = (
|
|
10
|
+
await Promise.all(
|
|
11
|
+
(await walkDir(target_locreq.resolve("src/")))
|
|
12
|
+
.filter(
|
|
13
|
+
(f) =>
|
|
14
|
+
f.endsWith(".css") &&
|
|
15
|
+
!f.endsWith("/main.css") &&
|
|
16
|
+
!f.endsWith("\\main.css") &&
|
|
17
|
+
!f.endsWith("/includes.css") &&
|
|
18
|
+
!f.endsWith("\\includes.css") &&
|
|
19
|
+
!f.includes(".#")
|
|
20
|
+
)
|
|
21
|
+
.map((fullpath) =>
|
|
22
|
+
relative(target_locreq.resolve("src/"), fullpath)
|
|
23
|
+
)
|
|
24
|
+
)
|
|
25
|
+
).sort();
|
|
24
26
|
|
|
25
27
|
await fs.writeFile(
|
|
26
28
|
target_locreq.resolve("src/includes.css"),
|
|
@@ -13,9 +13,9 @@ const target_locreq = _locreq(process.cwd());
|
|
|
13
13
|
export async function generateComponents(): Promise<void> {
|
|
14
14
|
const components_dir = target_locreq.resolve("src/back/jdd-components");
|
|
15
15
|
await mkdir(components_dir, { recursive: true });
|
|
16
|
-
const component_names = (await recursive(components_dir))
|
|
17
|
-
c.endsWith(".jdd.tsx")
|
|
18
|
-
|
|
16
|
+
const component_names = (await recursive(components_dir))
|
|
17
|
+
.filter((c) => c.endsWith(".jdd.tsx"))
|
|
18
|
+
.sort();
|
|
19
19
|
const component_data = component_names
|
|
20
20
|
.map(
|
|
21
21
|
(p) =>
|