ember-vite-hmr 2.3.0 → 2.4.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/README.md +31 -0
- package/dist/instance-initializers/setup-hmr-manager.js +42 -3
- package/dist/instance-initializers/setup-hmr-manager.js.map +1 -1
- package/dist/lib/babel-plugin/private-members.d.ts +3 -0
- package/dist/lib/babel-plugin/private-members.js +291 -0
- package/dist/lib/babel-plugin/service-proxy.d.ts +3 -0
- package/dist/lib/babel-plugin/service-proxy.js +300 -0
- package/dist/lib/babel-plugin/template-imports.d.ts +46 -0
- package/dist/lib/babel-plugin/template-imports.js +250 -0
- package/dist/lib/babel-plugin.d.ts +3 -31
- package/dist/lib/babel-plugin.js +45 -419
- package/dist/lib/hmr.js +312 -123
- package/package.json +2 -1
package/dist/lib/babel-plugin.js
CHANGED
|
@@ -1,143 +1,27 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
var _a;
|
|
25
|
-
if (process.env.EMBER_VITE_HMR_ENABLED !== 'true') {
|
|
26
|
-
return {
|
|
27
|
-
visitor: {},
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
if ((_a = env.filename) === null || _a === void 0 ? void 0 : _a.includes('node_modules')) {
|
|
31
|
-
return {
|
|
32
|
-
visitor: {},
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
const meta = this.meta;
|
|
36
|
-
const importVar = env.meta.jsutils.bindExpression(meta.importVar || 'null', null, {
|
|
37
|
-
nameHint: 'template__imports__',
|
|
38
|
-
});
|
|
39
|
-
meta.importVar = meta.importVar || importVar;
|
|
40
|
-
return {
|
|
41
|
-
visitor: Object.assign({}, this.buildVisitor({
|
|
42
|
-
importVar,
|
|
43
|
-
importBindings: meta.importBindings,
|
|
44
|
-
babelProgram: meta.babelProgram,
|
|
45
|
-
})),
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
buildVisitor({ importVar, importBindings, babelProgram, }) {
|
|
49
|
-
const findImport = function findImport(specifier) {
|
|
50
|
-
return babelProgram.body.find((b) => b.type === 'ImportDeclaration' &&
|
|
51
|
-
b.specifiers.some((s) => s.local.name === specifier));
|
|
52
|
-
};
|
|
53
|
-
const findBlockParams = function (expression, p) {
|
|
54
|
-
if (p.node.type === 'Template') {
|
|
55
|
-
return false;
|
|
56
|
-
}
|
|
57
|
-
if (p.node &&
|
|
58
|
-
p.node.type === 'BlockStatement' &&
|
|
59
|
-
p.node.program.blockParams.includes(expression)) {
|
|
60
|
-
return true;
|
|
61
|
-
}
|
|
62
|
-
const node = p.node;
|
|
63
|
-
if (node && node.blockParams && node.blockParams.includes(expression)) {
|
|
64
|
-
return true;
|
|
65
|
-
}
|
|
66
|
-
if (!p.parent)
|
|
67
|
-
return false;
|
|
68
|
-
return findBlockParams(expression, p.parent);
|
|
69
|
-
};
|
|
70
|
-
const visitor = {
|
|
71
|
-
PathExpression: (node, p) => {
|
|
72
|
-
var _a, _b;
|
|
73
|
-
if ((((_a = p.parentNode) === null || _a === void 0 ? void 0 : _a.type) === 'SubExpression' ||
|
|
74
|
-
((_b = p.parentNode) === null || _b === void 0 ? void 0 : _b.type) === 'MustacheStatement') &&
|
|
75
|
-
p.parentNode.params.includes(node)) {
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
const original = node.original.split('.')[0];
|
|
79
|
-
if (original === 'this')
|
|
80
|
-
return;
|
|
81
|
-
if (original.startsWith('@'))
|
|
82
|
-
return;
|
|
83
|
-
if (original === 'block')
|
|
84
|
-
return;
|
|
85
|
-
if (original.startsWith('this.'))
|
|
86
|
-
return;
|
|
87
|
-
if (findBlockParams(original, p))
|
|
88
|
-
return;
|
|
89
|
-
if (node.original === 'helper' ||
|
|
90
|
-
node.original === 'component' ||
|
|
91
|
-
node.original === 'modifier') {
|
|
92
|
-
// node.original;
|
|
93
|
-
const parent = p.parentNode;
|
|
94
|
-
if (typeof parent.params[0].original !==
|
|
95
|
-
'string') {
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
const original = parent.params[0].original.split('.')[0];
|
|
99
|
-
if (original && findBlockParams(original, p))
|
|
100
|
-
return;
|
|
101
|
-
if (original === null || original === void 0 ? void 0 : original.includes('.'))
|
|
102
|
-
return;
|
|
103
|
-
if (!original)
|
|
104
|
-
return;
|
|
105
|
-
if (findImport(original)) {
|
|
106
|
-
const param = glimmer.builders.path(`${importVar}.${original}`);
|
|
107
|
-
parent.params.splice(0, 1, param);
|
|
108
|
-
importBindings.add(original);
|
|
109
|
-
}
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
if (importVar) {
|
|
113
|
-
if (findImport(node.original)) {
|
|
114
|
-
node.original = `${importVar}.${node.original}`;
|
|
115
|
-
node.parts = node.original.split('.');
|
|
116
|
-
importBindings.add(original);
|
|
117
|
-
}
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
},
|
|
121
|
-
ElementNode: (element, p) => {
|
|
122
|
-
const original = element.tag.split('.')[0];
|
|
123
|
-
if (findBlockParams(original, p))
|
|
124
|
-
return;
|
|
125
|
-
if (importVar) {
|
|
126
|
-
if (findImport(original)) {
|
|
127
|
-
element.tag = `${importVar}.${original}`;
|
|
128
|
-
p.node.tag = element.tag;
|
|
129
|
-
importBindings.add(original);
|
|
130
|
-
}
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
},
|
|
134
|
-
};
|
|
135
|
-
return visitor;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
export const hotAstProcessor = new HotAstProcessor();
|
|
1
|
+
import { hotAstProcessor, finalizeTemplateImports, hmrImportMetadataCache, normalizeHmrCacheFilename, } from './babel-plugin/template-imports.js';
|
|
2
|
+
import { renamePrivateClassMembers } from './babel-plugin/private-members.js';
|
|
3
|
+
import { transformServiceExport } from './babel-plugin/service-proxy.js';
|
|
4
|
+
// `ember-vite-hmr/lib/babel-plugin` is a published subpath import (see
|
|
5
|
+
// test-app/babel.config.mjs), so this file's module path and its exports
|
|
6
|
+
// (this default export, and the `hotAstProcessor` / `hmrImportMetadataCache`
|
|
7
|
+
// / `normalizeHmrCacheFilename` re-exports below) have to keep resolving
|
|
8
|
+
// exactly as-is -- the actual logic lives in ./babel-plugin/*, split by
|
|
9
|
+
// concern:
|
|
10
|
+
// - template-imports.ts: rewrites template references to imported
|
|
11
|
+
// components/helpers/modifiers through a per-module tracked class, so
|
|
12
|
+
// swapping which module a virtual HMR wrapper resolves to is visible to
|
|
13
|
+
// templates (registered separately as an ember-template-compilation
|
|
14
|
+
// transform via the `hotAstProcessor` export below), and shares the
|
|
15
|
+
// computed import metadata with lib/hmr.ts via `hmrImportMetadataCache`.
|
|
16
|
+
// - private-members.ts: rewrites every native `#private` class member the
|
|
17
|
+
// app's own source declares to a plain, uniquely-named property, so it
|
|
18
|
+
// reads/writes correctly through the service proxy below regardless of
|
|
19
|
+
// what `this` is at the call site.
|
|
20
|
+
// - service-proxy.ts: rewrites `export default class X extends Service`
|
|
21
|
+
// into a generated HMR proxy class that swaps its delegate instance on
|
|
22
|
+
// every accepted update.
|
|
23
|
+
export { hotAstProcessor, hmrImportMetadataCache, normalizeHmrCacheFilename };
|
|
139
24
|
export default function hotReplaceAst(babel) {
|
|
140
|
-
const t = babel.types;
|
|
141
25
|
return {
|
|
142
26
|
name: 'a-hot-reload-imports',
|
|
143
27
|
pre(file) {
|
|
@@ -145,269 +29,31 @@ export default function hotReplaceAst(babel) {
|
|
|
145
29
|
hotAstProcessor.meta.babelProgram = file.ast.program;
|
|
146
30
|
},
|
|
147
31
|
visitor: {
|
|
148
|
-
|
|
149
|
-
|
|
32
|
+
// Runs on *every* class the app's own source defines, independent of
|
|
33
|
+
// whether it's a service, a service's ancestor, or unrelated to the
|
|
34
|
+
// HMR proxy machinery entirely -- see `renamePrivateClassMembers`'s
|
|
35
|
+
// own doc comment for why this can't be scoped any tighter than that
|
|
36
|
+
// without whole-program analysis. This also visits the `proxyClass`
|
|
37
|
+
// (and, for an inline export, the `originalClass` copy)
|
|
38
|
+
// `transformServiceExport` generates below -- harmless today only
|
|
39
|
+
// because generated proxy classes never declare private members of
|
|
40
|
+
// their own; if that ever changes, this visitor would rename them
|
|
41
|
+
// too.
|
|
42
|
+
Class(path, state) {
|
|
43
|
+
var _a;
|
|
150
44
|
if (process.env.EMBER_VITE_HMR_ENABLED !== 'true') {
|
|
151
45
|
return;
|
|
152
46
|
}
|
|
153
47
|
if ((_a = state.filename) === null || _a === void 0 ? void 0 : _a.includes('node_modules')) {
|
|
154
48
|
return;
|
|
155
49
|
}
|
|
156
|
-
// Check if this is a service file (normalize path for cross-platform compatibility)
|
|
157
|
-
const normalizedFilename = (_b = state.filename) === null || _b === void 0 ? void 0 : _b.replace(/\\/g, '/');
|
|
158
|
-
if (!(normalizedFilename === null || normalizedFilename === void 0 ? void 0 : normalizedFilename.includes('/services/'))) {
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
const declaration = path.node.declaration;
|
|
162
|
-
// Handle both inline class declaration and identifier reference
|
|
163
|
-
let classDeclaration = null;
|
|
164
|
-
let classIdentifier = null;
|
|
165
|
-
if (declaration.type === 'ClassDeclaration' && declaration.id) {
|
|
166
|
-
// Case 1: export default class MyService extends Service { ... }
|
|
167
|
-
classDeclaration = declaration;
|
|
168
|
-
classIdentifier = declaration.id;
|
|
169
|
-
}
|
|
170
|
-
else if (declaration.type === 'Identifier') {
|
|
171
|
-
// Case 2: class MyService extends Service { ... } \n export default MyService;
|
|
172
|
-
const binding = path.scope.getBinding(declaration.name);
|
|
173
|
-
if (binding && binding.path.isClassDeclaration()) {
|
|
174
|
-
classDeclaration = binding.path
|
|
175
|
-
.node;
|
|
176
|
-
classIdentifier = classDeclaration.id;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
if (!classDeclaration || !classIdentifier) {
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
if (classIdentifier.name.endsWith('HmrProxy')) {
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
// Check if it extends Service
|
|
186
|
-
const superClass = classDeclaration.superClass;
|
|
187
|
-
if (!superClass ||
|
|
188
|
-
((superClass.type !== 'Identifier' ||
|
|
189
|
-
superClass.name !== 'Service') &&
|
|
190
|
-
superClass.type !== 'MemberExpression')) {
|
|
191
|
-
return;
|
|
192
|
-
}
|
|
193
|
-
// Get the program path for ImportUtil
|
|
194
50
|
const programPath = path.findParent((p) => p.isProgram());
|
|
195
51
|
if (!programPath) {
|
|
196
52
|
return;
|
|
197
53
|
}
|
|
198
|
-
|
|
199
|
-
const tracked = util.import(programPath, '@glimmer/tracking', 'tracked');
|
|
200
|
-
const Service = util.import(programPath, '@ember/service', 'default');
|
|
201
|
-
const originalClassName = classIdentifier.name;
|
|
202
|
-
const proxyClassName = `${originalClassName}HmrProxy`;
|
|
203
|
-
// Keep the original class as-is, just remove it from export
|
|
204
|
-
// We'll add it back as a non-exported class
|
|
205
|
-
const babelTemplate = babel.template;
|
|
206
|
-
// The live proxy instance and the latest accepted implementation must
|
|
207
|
-
// live on `import.meta.hot.data`, not in a module-scope `let`: Vite
|
|
208
|
-
// guarantees that object (and only that object) survives across a
|
|
209
|
-
// module's hot re-evaluations. A component's `@service` injection can
|
|
210
|
-
// end up constructing the proxy against a *later* re-evaluation of
|
|
211
|
-
// this module than the one whose `import.meta.hot.accept` closure
|
|
212
|
-
// captured a module-scope variable — the closure and the constructor
|
|
213
|
-
// would then silently operate on two disconnected variable bindings
|
|
214
|
-
// (a duplicate-module symptom), and the HMR swap would never reach
|
|
215
|
-
// the instance actually rendered.
|
|
216
|
-
const ctorBody = babelTemplate.statements(`
|
|
217
|
-
super(...args);
|
|
218
|
-
this._owner = args[0];
|
|
219
|
-
const Impl = (import.meta.hot && import.meta.hot.data._impl) || ${proxyClassName}.Impl;
|
|
220
|
-
this._delegate = new Impl(this._owner);
|
|
221
|
-
if (import.meta.hot) {
|
|
222
|
-
import.meta.hot.data._proxy = this;
|
|
223
|
-
}
|
|
224
|
-
// Bound methods are cached per-delegate (not per-proxy) so identity
|
|
225
|
-
// stays stable across repeated reads of the same delegate (e.g.
|
|
226
|
-
// {{on "click" this.svc.handler}} comparing args by reference), while
|
|
227
|
-
// naturally invalidating once a delegate is swapped out on HMR accept.
|
|
228
|
-
const boundMethods = new WeakMap();
|
|
229
|
-
return new Proxy(this, {
|
|
230
|
-
get(target, prop, receiver) {
|
|
231
|
-
if (prop === '_delegate') {
|
|
232
|
-
return target._delegate;
|
|
233
|
-
}
|
|
234
|
-
// A subclass of this service (see the Reflect.get fallback
|
|
235
|
-
// below) may override a method the base delegate class also
|
|
236
|
-
// defines. Since 'prop in delegate' walks the delegate's
|
|
237
|
-
// *entire* prototype chain, it would match the base
|
|
238
|
-
// implementation before the subclass's own override ever
|
|
239
|
-
// gets a chance -- so look for an own property between
|
|
240
|
-
// target's dynamic prototype and this proxy's own prototype
|
|
241
|
-
// first, and prefer it over the delegate.
|
|
242
|
-
let proto = Object.getPrototypeOf(target);
|
|
243
|
-
while (proto && proto !== ${proxyClassName}.prototype) {
|
|
244
|
-
if (Object.prototype.hasOwnProperty.call(proto, prop)) {
|
|
245
|
-
return Reflect.get(target, prop, receiver);
|
|
246
|
-
}
|
|
247
|
-
proto = Object.getPrototypeOf(proto);
|
|
248
|
-
}
|
|
249
|
-
const delegate = target._delegate;
|
|
250
|
-
// Methods invoked via normal member-call syntax (service.method())
|
|
251
|
-
// bind 'this' to whatever object the property access happened on
|
|
252
|
-
// -- the proxy, here -- not to the delegate. That breaks native
|
|
253
|
-
// private fields, whose storage lives only on the concrete
|
|
254
|
-
// delegate instance, so delegate-owned methods are explicitly
|
|
255
|
-
// bound to the delegate.
|
|
256
|
-
if (prop in delegate) {
|
|
257
|
-
const value = delegate[prop];
|
|
258
|
-
if (typeof value === 'function') {
|
|
259
|
-
let cache = boundMethods.get(delegate);
|
|
260
|
-
if (!cache) {
|
|
261
|
-
cache = new Map();
|
|
262
|
-
boundMethods.set(delegate, cache);
|
|
263
|
-
}
|
|
264
|
-
let bound = cache.get(prop);
|
|
265
|
-
if (!bound) {
|
|
266
|
-
bound = value.bind(delegate);
|
|
267
|
-
cache.set(prop, bound);
|
|
268
|
-
}
|
|
269
|
-
return bound;
|
|
270
|
-
}
|
|
271
|
-
return value;
|
|
272
|
-
}
|
|
273
|
-
// Not on the delegate: fall through to the proxy's own real
|
|
274
|
-
// prototype chain, which covers methods declared on a subclass
|
|
275
|
-
// of this service (the subclass never went through this babel
|
|
276
|
-
// transform itself, since it doesn't extend Service directly).
|
|
277
|
-
return Reflect.get(target, prop, receiver);
|
|
278
|
-
},
|
|
279
|
-
set(target, prop, value) {
|
|
280
|
-
target._delegate[prop] = value;
|
|
281
|
-
return true;
|
|
282
|
-
},
|
|
283
|
-
defineProperty(target, prop, descriptor) {
|
|
284
|
-
// A subclass's own class fields are installed via
|
|
285
|
-
// [[DefineOwnProperty]] against whatever 'this' super() returned
|
|
286
|
-
// (this proxy), bypassing the 'set' trap entirely. Route them to
|
|
287
|
-
// the delegate too, so subclass state lives alongside the rest
|
|
288
|
-
// of the service's state instead of stranded on the proxy target.
|
|
289
|
-
return Reflect.defineProperty(target._delegate, prop, descriptor);
|
|
290
|
-
},
|
|
291
|
-
});
|
|
292
|
-
`)();
|
|
293
|
-
const willDestroyBody = babelTemplate.statements(`
|
|
294
|
-
super.willDestroy();
|
|
295
|
-
this._delegate.willDestroy();
|
|
296
|
-
if (import.meta.hot && import.meta.hot.data._proxy === this) {
|
|
297
|
-
import.meta.hot.data._proxy = undefined;
|
|
298
|
-
}
|
|
299
|
-
`)();
|
|
300
|
-
// Create the HMR proxy service class
|
|
301
|
-
const proxyClass = t.classDeclaration(t.identifier(proxyClassName), Service, t.classBody([
|
|
302
|
-
// static Impl = OriginalService (reference to the original class)
|
|
303
|
-
t.classProperty(t.identifier('Impl'), t.identifier(originalClassName), null, null, false, true),
|
|
304
|
-
// @tracked _delegate
|
|
305
|
-
t.classProperty(t.identifier('_delegate'), null, null, [t.decorator(tracked)], false, false),
|
|
306
|
-
t.classMethod('constructor', t.identifier('constructor'), [t.restElement(t.identifier('args'))], t.blockStatement(ctorBody)),
|
|
307
|
-
t.classMethod('method', t.identifier('willDestroy'), [], t.blockStatement(willDestroyBody)),
|
|
308
|
-
]));
|
|
309
|
-
// For Case 1 (inline class), we need to keep the class as non-exported
|
|
310
|
-
// For Case 2 (separate declaration), the class already exists, so we don't recreate it
|
|
311
|
-
if (declaration.type === 'ClassDeclaration') {
|
|
312
|
-
// Case 1: Inline class export - create a non-exported version
|
|
313
|
-
const originalClass = t.classDeclaration(classIdentifier, classDeclaration.superClass, classDeclaration.body, classDeclaration.decorators || []);
|
|
314
|
-
// Replace the export with all the necessary declarations
|
|
315
|
-
// IMPORTANT: Class must be declared BEFORE the proxy class that references it
|
|
316
|
-
path.replaceWithMultiple([
|
|
317
|
-
originalClass, // The original class (no longer exported) - MUST BE FIRST
|
|
318
|
-
t.exportDefaultDeclaration(proxyClass), // Export the proxy class
|
|
319
|
-
]);
|
|
320
|
-
}
|
|
321
|
-
else {
|
|
322
|
-
// Case 2: Separate declaration - class already exists, just replace the export
|
|
323
|
-
path.replaceWithMultiple([
|
|
324
|
-
t.exportDefaultDeclaration(proxyClass), // Export the proxy class
|
|
325
|
-
]);
|
|
326
|
-
}
|
|
327
|
-
// Add HMR code after the export using babel template
|
|
328
|
-
if (programPath) {
|
|
329
|
-
const hmrCode = `
|
|
330
|
-
if (import.meta.hot) {
|
|
331
|
-
import.meta.hot.accept((newModule) => {
|
|
332
|
-
const NewImpl = newModule?.default?.Impl;
|
|
333
|
-
if (!NewImpl) {
|
|
334
|
-
return;
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
// Remember the latest accepted implementation so a proxy
|
|
338
|
-
// constructed *after* this update (its instantiation raced
|
|
339
|
-
// behind the HMR swap) still picks up the new class instead
|
|
340
|
-
// of the stale one captured at module-evaluation time.
|
|
341
|
-
import.meta.hot.data._impl = NewImpl;
|
|
342
|
-
|
|
343
|
-
const proxy = import.meta.hot.data._proxy;
|
|
344
|
-
if (!proxy) {
|
|
345
|
-
// No instance has been created yet; the next construction
|
|
346
|
-
// will read import.meta.hot.data._impl above.
|
|
347
|
-
return;
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
const oldDelegate = proxy._delegate;
|
|
351
|
-
const newDelegate = new NewImpl(proxy._owner);
|
|
352
|
-
proxy._delegate = newDelegate;
|
|
353
|
-
|
|
354
|
-
// Sync state from old to new while keeping new implementation defaults
|
|
355
|
-
for (const key in oldDelegate) {
|
|
356
|
-
const descriptor =
|
|
357
|
-
Object.getOwnPropertyDescriptor(oldDelegate, key) ||
|
|
358
|
-
Object.getOwnPropertyDescriptor(Object.getPrototypeOf(oldDelegate), key);
|
|
359
|
-
const hasOwnDefault = Object.prototype.hasOwnProperty.call(newDelegate, key);
|
|
360
|
-
const currentValue = newDelegate[key];
|
|
361
|
-
const previousValue = oldDelegate[key];
|
|
362
|
-
|
|
363
|
-
// Skip Service instances - they should not be synced
|
|
364
|
-
if (previousValue instanceof Service) {
|
|
365
|
-
continue;
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
// Skip function properties that the new implementation also
|
|
369
|
-
// declares (a fresh redefinition should win over the old
|
|
370
|
-
// one). But a function-valued property the new
|
|
371
|
-
// implementation *doesn't* declare at all isn't a stale
|
|
372
|
-
// redefinition -- it's state a subclass installed on the
|
|
373
|
-
// delegate directly (subclasses of this service never go
|
|
374
|
-
// through this transform themselves, since their
|
|
375
|
-
// superclass isn't literally named Service; their own
|
|
376
|
-
// class fields land on the delegate via the proxy's
|
|
377
|
-
// defineProperty trap instead). Dropping it here would
|
|
378
|
-
// silently break e.g. an arrow-function class field on a
|
|
379
|
-
// subclass across a base-class HMR swap.
|
|
380
|
-
if (typeof previousValue === 'function' && hasOwnDefault) {
|
|
381
|
-
continue;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
const shouldSync =
|
|
385
|
-
!!descriptor &&
|
|
386
|
-
(descriptor.writable || descriptor.set || Object.prototype.hasOwnProperty.call(oldDelegate, key)) &&
|
|
387
|
-
(!hasOwnDefault || currentValue === previousValue);
|
|
388
|
-
|
|
389
|
-
if (shouldSync) {
|
|
390
|
-
try {
|
|
391
|
-
newDelegate[key] = previousValue;
|
|
392
|
-
} catch (e) {
|
|
393
|
-
// Skip non-writable properties
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
newDelegate._hmrAccepted?.(oldDelegate);
|
|
399
|
-
|
|
400
|
-
if (oldDelegate.willDestroy) {
|
|
401
|
-
oldDelegate.willDestroy();
|
|
402
|
-
}
|
|
403
|
-
});
|
|
404
|
-
}
|
|
405
|
-
`;
|
|
406
|
-
const template = babel.template.statements(hmrCode);
|
|
407
|
-
programPath.pushContainer('body', template());
|
|
408
|
-
}
|
|
54
|
+
renamePrivateClassMembers(babel, path, programPath);
|
|
409
55
|
},
|
|
410
|
-
|
|
56
|
+
ExportDefaultDeclaration(path, state) {
|
|
411
57
|
var _a;
|
|
412
58
|
if (process.env.EMBER_VITE_HMR_ENABLED !== 'true') {
|
|
413
59
|
return;
|
|
@@ -415,37 +61,17 @@ export default function hotReplaceAst(babel) {
|
|
|
415
61
|
if ((_a = state.filename) === null || _a === void 0 ? void 0 : _a.includes('node_modules')) {
|
|
416
62
|
return;
|
|
417
63
|
}
|
|
418
|
-
|
|
419
|
-
|
|
64
|
+
transformServiceExport(babel, path, state);
|
|
65
|
+
},
|
|
66
|
+
Program(path, state) {
|
|
67
|
+
var _a;
|
|
68
|
+
if (process.env.EMBER_VITE_HMR_ENABLED !== 'true') {
|
|
420
69
|
return;
|
|
421
70
|
}
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
util.import(path, '@glimmer/component', 'default');
|
|
425
|
-
const klass = t.classExpression(path.scope.generateUidIdentifier('Imports'), null, t.classBody([]));
|
|
426
|
-
const bindings = [...hotAstProcessor.meta.importBindings].sort();
|
|
427
|
-
for (const local of bindings) {
|
|
428
|
-
klass.body.body.push(t.classProperty(t.identifier(local), t.identifier(local), null, [
|
|
429
|
-
t.decorator(tracked),
|
|
430
|
-
]));
|
|
71
|
+
if ((_a = state.filename) === null || _a === void 0 ? void 0 : _a.includes('node_modules')) {
|
|
72
|
+
return;
|
|
431
73
|
}
|
|
432
|
-
|
|
433
|
-
const assign = t.assignmentExpression('=', t.identifier(hotAstProcessor.meta.importVar), newExp);
|
|
434
|
-
const varDeclaration = path.node.body.findIndex((e) => e.type === 'VariableDeclaration' &&
|
|
435
|
-
e.declarations[0].id.name ===
|
|
436
|
-
hotAstProcessor.meta.importVar) + 1;
|
|
437
|
-
const lastImportIndex = path.node.body.findLastIndex((e) => e.type === 'ImportDeclaration') + 1;
|
|
438
|
-
path.node.body.splice(Math.max(varDeclaration, lastImportIndex), 0, t.expressionStatement(assign));
|
|
439
|
-
// Export metadata about tracked imports for hmr.ts to use
|
|
440
|
-
const importMetadata = t.variableDeclaration('const', [
|
|
441
|
-
t.variableDeclarator(t.identifier('__hmr_import_metadata__'), t.objectExpression([
|
|
442
|
-
t.objectProperty(t.identifier('importVar'), t.stringLiteral(hotAstProcessor.meta.importVar)),
|
|
443
|
-
t.objectProperty(t.identifier('bindings'), t.arrayExpression(bindings.map((b) => t.stringLiteral(b)))),
|
|
444
|
-
])),
|
|
445
|
-
]);
|
|
446
|
-
const exportMetadata = t.exportNamedDeclaration(importMetadata, []);
|
|
447
|
-
path.node.body.push(exportMetadata);
|
|
448
|
-
path.scope.crawl();
|
|
74
|
+
finalizeTemplateImports(babel, path, state.filename);
|
|
449
75
|
},
|
|
450
76
|
},
|
|
451
77
|
};
|