forked from rdfjs/Yasgui
-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathesbuild.config.js
More file actions
211 lines (186 loc) · 6.38 KB
/
Copy pathesbuild.config.js
File metadata and controls
211 lines (186 loc) · 6.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
import * as esbuild from "esbuild";
import { sassPlugin } from "esbuild-sass-plugin";
import * as fs from "fs";
import * as path from "path";
import postcss from "postcss";
import autoprefixer from "autoprefixer";
import { execSync } from "child_process";
const isProd = process.env.NODE_ENV === "production";
// Clean build directory
if (fs.existsSync("./build")) {
fs.rmSync("./build", { recursive: true, force: true });
}
// Create build directory
fs.mkdirSync("./build", { recursive: true });
// Copy static files
function copyDir(src, dest) {
if (!fs.existsSync(src)) return;
fs.mkdirSync(dest, { recursive: true });
const entries = fs.readdirSync(src, { withFileTypes: true });
for (const entry of entries) {
const srcPath = path.join(src, entry.name);
const destPath = path.join(dest, entry.name);
if (entry.isDirectory()) {
copyDir(srcPath, destPath);
} else {
fs.copyFileSync(srcPath, destPath);
}
}
}
// Copy static assets
copyDir("packages/yasgui/static", "build/packages/yasgui/static");
// Copy HTML files for testing (from build-templates, not dev)
const htmlFiles = ["index.html", "yasgui.html", "yasqe.html", "yasr.html"];
for (const file of htmlFiles) {
const src = path.join("build-templates", file);
const dest = path.join("build", file);
if (fs.existsSync(src)) {
fs.copyFileSync(src, dest);
}
}
/**
* The esbuild-sass-plugin follows the `/* src/yasgui-compat.css *\/` sourcemap comment
* that the geo plugin's dist CSS starts with, causing esbuild to load the src/ version
* which has broken relative PNG paths. This plugin intercepts that load and returns
* the dist/ version instead (which already has the images inlined as base64 data URIs).
*/
const geoPluginCssFix = {
name: "geo-plugin-css-fix",
setup(build) {
build.onLoad({ filter: /yasgui-geo-plugin[/\\]src[/\\]yasgui-compat\.css$/ }, (args) => {
const distPath = args.path.replace(/([/\\])src([/\\])/, "$1dist$2");
const contents = fs.readFileSync(distPath, "utf-8");
return { contents, loader: "css" };
});
},
};
const commonConfig = {
bundle: true,
sourcemap: true,
target: "es2020",
minify: isProd,
plugins: [
geoPluginCssFix,
sassPlugin({
async transform(source, resolveDir) {
const { css } = await postcss([autoprefixer]).process(source, { from: undefined });
return css;
},
}),
],
loader: {
".png": "file",
".jpg": "file",
".svg": "dataurl",
".woff": "file",
".woff2": "file",
".ttf": "file",
".eot": "file",
},
external: [],
define: {
__DEVELOPMENT__: JSON.stringify(!isProd),
},
};
// Rename the CSS output emitted by a build to the canonical `<name>.min.css`.
function extractCss(result, name) {
if (!result.metafile) return;
const cssOutput = Object.keys(result.metafile.outputs).find((o) => o.endsWith(".css"));
if (!cssOutput || !fs.existsSync(cssOutput)) return;
const targetCss = `build/${name}.min.css`;
const sourceMap = `${cssOutput}.map`;
const targetMap = `${targetCss}.map`;
if (cssOutput !== targetCss) {
fs.renameSync(cssOutput, targetCss);
if (fs.existsSync(sourceMap)) fs.renameSync(sourceMap, targetMap);
// Keep the sourcemap reference consistent with the renamed file.
const css = fs.readFileSync(targetCss, "utf8");
const updated = css.replace(/sourceMappingURL=.*?\*\//, `sourceMappingURL=${path.basename(targetMap)} */`);
if (updated !== css) fs.writeFileSync(targetCss, updated);
}
}
// Remove the CSS (and its sourcemap) emitted by a build. The ESM/CJS bundles
// import the same styles as the IIFE build, so a single `<name>.min.css` is kept.
function removeExtraCss(result) {
if (!result.metafile) return;
for (const output of Object.keys(result.metafile.outputs)) {
if (output.endsWith(".css") || output.endsWith(".css.map")) {
if (fs.existsSync(output)) fs.rmSync(output);
}
}
}
async function buildPackage(name, entryPoint, globalName) {
// IIFE build: exposes a browser global (e.g. `window.Yasgui`) for <script> usage.
const iifeResult = await esbuild.build({
...commonConfig,
entryPoints: [entryPoint],
outfile: `build/${name}.min.js`,
format: "iife",
globalName: globalName,
platform: "browser",
metafile: true,
footer: {
// Unwrap default export for IIFE format to make constructor available as global
js: `if (typeof ${globalName} !== 'undefined' && ${globalName}?.default) { ${globalName} = ${globalName}.default; }`,
},
});
extractCss(iifeResult, name);
// ESM build: consumed by bundlers (vite/webpack/esbuild) and Node via `import`.
// Uses the `.mjs` extension so it is always treated as an ES module.
const esmResult = await esbuild.build({
...commonConfig,
entryPoints: [entryPoint],
outfile: `build/${name}.mjs`,
format: "esm",
platform: "browser",
metafile: true,
});
removeExtraCss(esmResult);
// CJS build: consumed by Node's `require`. Uses the `.cjs` extension so it is
// always treated as CommonJS regardless of the nearest package.json `type`.
const cjsResult = await esbuild.build({
...commonConfig,
entryPoints: [entryPoint],
outfile: `build/${name}.cjs`,
format: "cjs",
platform: "browser",
metafile: true,
});
removeExtraCss(cjsResult);
}
async function buildTypeDeclarations() {
console.log("Building TypeScript declarations...");
try {
execSync("tsc -p tsconfig-build.json", { stdio: "inherit" });
} catch (error) {
console.warn("TypeScript declaration build had errors, continuing...");
}
}
async function updateVersion() {
console.log("Updating version.ts...");
try {
execSync("node updateVersion.js", { stdio: "inherit" });
} catch (error) {
console.warn("Failed to update version.ts, continuing...");
}
}
async function build() {
try {
// Update version.ts from package.json
await updateVersion();
// Build TypeScript declarations first
await buildTypeDeclarations();
// Build all packages
await Promise.all([
buildPackage("yasgui", "packages/yasgui/src/index.ts", "Yasgui"),
buildPackage("yasqe", "packages/yasqe/src/index.ts", "Yasqe"),
buildPackage("yasr", "packages/yasr/src/index.ts", "Yasr"),
buildPackage("utils", "packages/utils/src/index.ts", "Utils"),
]);
console.log("✓ Build complete!");
} catch (error) {
console.error("Build failed:", error);
process.exit(1);
}
}
build();