-
Notifications
You must be signed in to change notification settings - Fork 35
Expand file tree
/
Copy pathvite.config.mjs
More file actions
134 lines (119 loc) · 5.01 KB
/
Copy pathvite.config.mjs
File metadata and controls
134 lines (119 loc) · 5.01 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
import { defineConfig, loadEnv } from "vite";
import elmPlugin from "vite-plugin-elm";
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import { createFilter } from 'vite'
// The elm compiler that vite-plugin-elm spawns reads its packages from
// ELM_HOME. The Makefile exports it, so `make serve` gets the patched
// elm-safe-virtual-dom clones — but `npm run dev`/`npx vite` does not, and elm
// then silently resolves the unpatched registry packages from ~/.elm. Pin it
// here so the entry point stops mattering.
process.env.ELM_HOME ??= path.resolve(path.dirname(fileURLToPath(import.meta.url)), 'elm_packages')
function envReplacePlugin(options = {}) {
const filter = createFilter(options.include || /\.(js|ts)$/, options.exclude)
return {
name: 'vite-plugin-env-replace',
transform(code, id) {
if (!filter(id)) return
return {
code: replacePlaceholders(code),
map: null
}
}
}
}
function replacePlaceholders(code) {
const envVars = loadEnv(process.env.NODE_ENV, process.cwd())
const placeholderRegex = /\{\{([A-Za-z_][A-Za-z0-9_]*)\}\}/g
return code.replace(placeholderRegex, (match, placeholder) => {
return envVars[placeholder] !== undefined
? envVars[placeholder]
: match
})
}
// Elm's `_Platform_initialize` renders the first frame synchronously inside
// `var stepper = stepperBuilder(sendToApp, model);`. If that first render
// synchronously dispatches a DOM event back into the app (e.g. an iframe
// firing `load` on append, or a custom element dispatching from its
// `connectedCallback`), `sendToApp` runs before `stepper` is assigned and
// crashes with "TypeError: stepper is not a function", aborting the render
// mid-patch. This surfaced on hard reloads of the case-connect UI.
// Rewriting the compiled bundle here (instead of patching elm/core in
// ELM_HOME) survives package re-downloads and needs no artifacts.dat
// cache-busting; the message is processed normally and the view step is
// deferred to a microtask, by which time `stepper` exists.
function elmStepperGuardPlugin() {
const needle = 'stepper(model = pair.a, viewMetadata);'
const guard =
'model = pair.a;\n' +
'\t\t// GS_STEPPER_GUARD (injected by vite, see vite.config.mjs)\n' +
'\t\tif (stepper) { stepper(model, viewMetadata); }\n' +
'\t\telse { Promise.resolve().then(function () { stepper(model, viewMetadata); }); }'
const filter = createFilter(/\.elm$/)
return {
name: 'vite-plugin-elm-stepper-guard',
transform(code, id) {
if (!filter(id)) return
if (!code.includes(needle)) {
if (code.includes('_Platform_initialize')) {
this.warn('elm-stepper-guard: kernel pattern not found — the stepper race is NOT patched (elm/core kernel changed?)')
}
return
}
return { code: code.replaceAll(needle, guard), map: null }
}
}
}
// The Makefile (`virtual-dom-fix`) clones elm-safe-virtual-dom over elm's
// virtual-dom/html/browser/elm-css, so the app survives DOM changes made by
// browser extensions. Nothing else notices when those clones do not reach the
// compiler — an elm upgrade moves the package cache to a new directory, a
// stale elm-stuff keeps the old artifacts — and the app is then one extension
// away from "Node.removeChild: Argument 1 is not an object". So: check.
function elmSafeVirtualDomCheckPlugin() {
const marker = '_VirtualDom_createTNode'
const filter = createFilter(/\.elm$/)
return {
name: 'vite-plugin-elm-safe-virtual-dom-check',
transform(code, id) {
if (!filter(id)) return
if (!code.includes(marker)) {
this.warn('elm-safe-virtual-dom is NOT in this build — run `make virtual-dom-fix` (it may be cloned into the package directory of an older elm version, or elm-stuff may be stale)')
}
}
}
}
/** @type {import('vite').Plugin} */
const base64Loader = {
name: 'base64-loader',
transform(code, id) {
const [path, query] = id.split('?');
if (query != 'raw-base64')
return null;
const data = fs.readFileSync(path);
const hex = data.toString('base64');
return `export default '${hex}';`;
}
};
export default defineConfig(({ command }) => ({
// The Elm time-travel debugger (dev only, never in builds) crashes on large
// models: its Expando walks the whole model on every update and overflows
// the stack in Firefox ("InternalError: too much recursion",
// https://github.com/elm/virtual-dom/issues/80), freezing the app. If that
// bites you, disable it with ELM_DEBUGGER=false.
plugins: [elmPlugin({ debug: command === 'serve' && process.env.ELM_DEBUGGER !== 'false' }), elmStepperGuardPlugin(), elmSafeVirtualDomCheckPlugin(), base64Loader, envReplacePlugin({include: [/\.elm$/, /src\/main\.js$/], exclude: /node_modules/})],
server: {
host: '0.0.0.0',
port: 3000,
hmr : { overlay : true }
},
worker: { format: 'es' },
publicDir: "generated/public",
build: {
manifest: true,
outDir: 'dist',
minify: 'terser',
sourcemap: false
},
}));