Repository navigation
Expand file tree
/
Copy pathbuild.sh
More file actions
executable file
·147 lines (130 loc) · 6.47 KB
/
Copy pathbuild.sh
File metadata and controls
executable file
·147 lines (130 loc) · 6.47 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
#!/usr/bin/env bash
# Optional build script to minify files
set -e
rm -rf dist
mkdir dist
#make -C src/wasm_solver/
# JS
# tri_solver/ is kept external (not bundled): it contains emscripten modules that
# load their .wasm via import.meta.url and a computed dynamic import() for gmsh,
# neither of which survive bundling into a single outfile. It is lazy-imported
# from app_solver.js only when the triangular backend is selected, and shipped as
# a verbatim tree (copied below).
npx esbuild src/app_solver.js \
--bundle \
--minify \
--format=esm \
--sourcemap \
--platform=node \
--external:./tri_solver/* \
--outfile=dist/app_solver.js
# Solve worker: a second entry point, deliberately not bundled into app_solver.js.
# app_solver constructs it with `new Worker(new URL("solve_worker.js", import.meta.url))`,
# which esbuild leaves alone, the URL is resolved by the browser at runtime, relative to
# the app bundle, so the two files must sit side by side in dist/. It carries its own copy
# of the solver core (both threads need it). The tri_solver tree stays external and shared,
# exactly as for the app bundle.
npx esbuild src/solve_worker.js \
--bundle \
--minify \
--format=esm \
--sourcemap \
--platform=node \
--external:./tri_solver/* \
--outfile=dist/solve_worker.js
# Eye worker: third entry point, constructed by eye/eye_ui.js with
# `new Worker(new URL("eye_worker.js", import.meta.url))`, so it sits next to the app
# bundle. It carries the FFT module, whose fft.wasm is fetched next to it.
npx esbuild src/eye/eye_worker.js \
--bundle \
--minify \
--format=esm \
--sourcemap \
--platform=node \
--outfile=dist/eye_worker.js
# CSS
npx postcss src/solver-style.css \
--use cssnano \
-o dist/solver-style.css
# HTML - swap to CDN first, then minify (order matters!)
# Copy and swap CDN URL first
cp src/field_solver.html dist/field_solver.html
sed -i "s|const PRIMARY_PLOTLY_SRC = 'plotly-3.3.0.min.js';|const PRIMARY_PLOTLY_SRC = 'https://cdn.plot.ly/plotly-3.3.0.min.js';|g" dist/field_solver.html
# Then minify (which will inline the CDN URL)
npx html-minifier-terser \
--collapse-whitespace \
--remove-comments \
--minify-js true \
--minify-css true \
dist/field_solver.html \
-o dist/field_solver.html
# Copy plotly as fallback in case CDN is unreachable
cp src/plotly-3.3.0.min.js dist/
cp src/wasm_solver/solver.wasm dist/solver.wasm
cp src/wasm_solver/fft.wasm dist/fft.wasm
cp src/.htaccess dist/.htaccess
# Full-wave (triangular) backend runtime: shipped as a verbatim ES-module tree —
# NOT bundled, because the emscripten modules locate their .wasm via
# import.meta.url and gmsh is loaded through a computed dynamic import, neither
# of which survives bundling. The WHOLE runtime (tri_solver modules, the shared
# `../` sibling modules, and the eigen/gmsh WASM) lives under ONE content-hashed
# directory, dist/tri-<hash>/, so the immutable cache policy can never serve a
# mixed-version module graph after a deployment: when any file changes, every
# URL in the subtree changes. The only reference from outside is the bundle's
# lazy imports of './tri_solver/*', rewritten below. The layout
# mirrors src/ shifted one level down, so all relative imports resolve inside
# the versioned tree:
# tri-<hash>/complex.js … ← `../foo.js` from tri_solver/*
# tri-<hash>/tri_solver/*.js
# tri-<hash>/wasm_solver/{eigen_solver,gmsh}.{js,wasm}
TRI_STAGE=dist/.tri-stage
mkdir -p "$TRI_STAGE/wasm_solver"
cp -r src/tri_solver "$TRI_STAGE/tri_solver"
rm -f "$TRI_STAGE/tri_solver/_smoke_test.mjs"
# Shared src modules imported as `../*.js` from tri_solver/*.js, and the `./*.js` they
# import in turn, found from the import lines. (They are also inlined into the app
# bundle; the external tree needs standalone copies.)
shared=$(grep -rhoE "from '\.\./[A-Za-z0-9_]+\.js'" src/tri_solver/*.js | grep -oE "[A-Za-z0-9_]+\.js" | sort -u)
while :; do
next=$( { echo "$shared"; for f in $shared; do grep -hoE "from '\./[A-Za-z0-9_]+\.js'" "src/$f" | grep -oE "[A-Za-z0-9_]+\.js"; done; } | sort -u)
[ "$next" = "$shared" ] && break
shared=$next
done
for f in $shared; do cp "src/$f" "$TRI_STAGE/"; done
# Each emscripten module locates its .wasm next to its own .js.
cp src/wasm_solver/eigen_solver.js src/wasm_solver/eigen_solver.wasm \
src/wasm_solver/gmsh.js src/wasm_solver/gmsh.wasm "$TRI_STAGE/wasm_solver/"
TRI_HASH=$(cd "$TRI_STAGE" && find . -type f | LC_ALL=C sort | xargs cat | sha256sum | cut -c1-8)
mv "$TRI_STAGE" "dist/tri-${TRI_HASH}"
# Point both bundles' lazy imports (tri_backend.js, eigen_module.js) at the versioned
# tree. The worker sits next to the app bundle, so the same relative path resolves for both.
sed -i -E "s#([\"'])\./tri_solver/#\1./tri-${TRI_HASH}/tri_solver/#g" \
dist/app_solver.js dist/solve_worker.js
# Cache-busting: append content hashes as query strings so browsers fetch
# new versions when files change. The HTML must be served with no-cache headers
# (e.g. Cache-Control: no-cache) so users always get the latest asset URLs.
BUILD_DATE=$(date -u '+%Y-%m-%d')
GIT_HASH=$(git rev-parse --short HEAD)
sed -i "s|BUILD_VERSION|${BUILD_DATE} (${GIT_HASH})|g" dist/field_solver.html
CSS_HASH=$(sha256sum dist/solver-style.css | cut -c1-8)
WASM_HASH=$(sha256sum dist/solver.wasm | cut -c1-8)
# Inject WASM hash into bundled JS (solver.wasm is fetched at runtime).
# This must happen BEFORE JS_HASH is computed: a solver.wasm-only change must
# alter the bundle (and therefore its URL), or returning users would keep the
# old immutable-cached bundle pointing at the old ?v= and never fetch the new
# WASM.
sed -i "s|\"solver\.wasm\"|\"solver.wasm?v=${WASM_HASH}\"|g" dist/app_solver.js dist/solve_worker.js
# The workers are fetched by URL from inside the app bundle, so their hashes must be
# injected BEFORE the app bundle is hashed — same ordering argument as solver.wasm above.
WORKER_HASH=$(sha256sum dist/solve_worker.js | cut -c1-8)
sed -i "s|\"solve_worker\.js\"|\"solve_worker.js?v=${WORKER_HASH}\"|g" dist/app_solver.js
FFT_HASH=$(sha256sum dist/fft.wasm | cut -c1-8)
sed -i "s|\"fft\.wasm\"|\"fft.wasm?v=${FFT_HASH}\"|g" dist/eye_worker.js
EYE_WORKER_HASH=$(sha256sum dist/eye_worker.js | cut -c1-8)
sed -i "s|\"eye_worker\.js\"|\"eye_worker.js?v=${EYE_WORKER_HASH}\"|g" dist/app_solver.js
JS_HASH=$(sha256sum dist/app_solver.js | cut -c1-8)
# Inject JS and CSS hashes into HTML
sed -i \
-e "s|\"app_solver\.js\"|\"app_solver.js?v=${JS_HASH}\"|g" \
-e "s|\"solver-style\.css\"|\"solver-style.css?v=${CSS_HASH}\"|g" \
dist/field_solver.html