@mantou/gem 2.2.5 → 2.2.6
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/dist/gem.js +1 -1
- package/dist/gem.mjs +4 -4
- package/helper/hmr.d.ts.map +1 -1
- package/helper/hmr.js +114 -110
- package/helper/hmr.js.map +1 -1
- package/lib/history.d.ts.map +1 -1
- package/lib/history.js +1 -1
- package/lib/history.js.map +1 -1
- package/lib/lit-html.d.ts.map +1 -1
- package/lib/lit-html.js +11 -0
- package/lib/lit-html.js.map +1 -1
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +1 -1
- package/src/helper/hmr.ts +130 -125
- package/src/lib/history.ts +3 -1
- package/src/lib/lit-html.ts +9 -0
- package/src/lib/version.ts +1 -1
- package/src/test/lit-html.test.ts +19 -0
package/src/helper/hmr.ts
CHANGED
|
@@ -5,7 +5,10 @@ import { Logger } from './logger';
|
|
|
5
5
|
|
|
6
6
|
const logger = new Logger('HMR');
|
|
7
7
|
|
|
8
|
-
const nativeDefineElement =
|
|
8
|
+
const nativeDefineElement =
|
|
9
|
+
typeof window === 'undefined' || !window.customElements
|
|
10
|
+
? undefined
|
|
11
|
+
: window.customElements.define.bind(window.customElements);
|
|
9
12
|
|
|
10
13
|
const cache = new Map<string, Element[]>();
|
|
11
14
|
function updateElement(name: string, fn: (ele: Element) => void) {
|
|
@@ -160,147 +163,149 @@ declare global {
|
|
|
160
163
|
}
|
|
161
164
|
}
|
|
162
165
|
|
|
163
|
-
window
|
|
164
|
-
window.
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
addInitializer
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
if (!existed) {
|
|
171
|
-
window._hmrClassRegistry.set(name, cls);
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
logger.info(`class <${name}> update,`, { existed, cls });
|
|
176
|
-
|
|
177
|
-
let current: any[] = [existed, cls];
|
|
178
|
-
while (current) {
|
|
179
|
-
const [oldClass, newClass] = current;
|
|
180
|
-
if (oldClass === newClass || current.some((e) => e === GemElement || e === Function.prototype)) break;
|
|
181
|
-
if (current.some((e) => !e) || checkClassNeedReload(oldClass, newClass)) {
|
|
182
|
-
location.reload();
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
166
|
+
if (typeof window !== 'undefined' && nativeDefineElement && !window._hmrClassRegistry) {
|
|
167
|
+
window._hmrClassRegistry = new Map();
|
|
168
|
+
window._hmrRegisterClass =
|
|
169
|
+
(name: string) =>
|
|
170
|
+
(cls: HasFieldsRecordClass, { addInitializer }: ClassDecoratorContext) => {
|
|
171
|
+
addInitializer(() => {
|
|
172
|
+
const existed = window._hmrClassRegistry.get(name);
|
|
185
173
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
const isOldInstance = instance instanceof oldClass;
|
|
189
|
-
if (isOldInstance) return true;
|
|
190
|
-
setProperty(newClass, Symbol.hasInstance, undefined);
|
|
191
|
-
const isNew = instance instanceof newClass;
|
|
192
|
-
setProperty(newClass, Symbol.hasInstance, hasInstance);
|
|
193
|
-
return isNew;
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
const oldMetadata = getMetadata(oldClass);
|
|
197
|
-
const newMetadata = getMetadata(newClass);
|
|
198
|
-
|
|
199
|
-
if (checkMetadataNeedReload(oldMetadata, newMetadata)) {
|
|
200
|
-
location.reload();
|
|
174
|
+
if (!existed) {
|
|
175
|
+
window._hmrClassRegistry.set(name, cls);
|
|
201
176
|
return;
|
|
202
177
|
}
|
|
203
178
|
|
|
204
|
-
|
|
179
|
+
logger.info(`class <${name}> update,`, { existed, cls });
|
|
180
|
+
|
|
181
|
+
let current: any[] = [existed, cls];
|
|
182
|
+
while (current) {
|
|
183
|
+
const [oldClass, newClass] = current;
|
|
184
|
+
if (oldClass === newClass || current.some((e) => e === GemElement || e === Function.prototype)) break;
|
|
185
|
+
if (current.some((e) => !e) || checkClassNeedReload(oldClass, newClass)) {
|
|
186
|
+
location.reload();
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// 修正 `instanceof`
|
|
191
|
+
setProperty(newClass, Symbol.hasInstance, function hasInstance(instance: any) {
|
|
192
|
+
const isOldInstance = instance instanceof oldClass;
|
|
193
|
+
if (isOldInstance) return true;
|
|
194
|
+
setProperty(newClass, Symbol.hasInstance, undefined);
|
|
195
|
+
const isNew = instance instanceof newClass;
|
|
196
|
+
setProperty(newClass, Symbol.hasInstance, hasInstance);
|
|
197
|
+
return isNew;
|
|
198
|
+
});
|
|
205
199
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
return;
|
|
209
|
-
}
|
|
200
|
+
const oldMetadata = getMetadata(oldClass);
|
|
201
|
+
const newMetadata = getMetadata(newClass);
|
|
210
202
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
203
|
+
if (checkMetadataNeedReload(oldMetadata, newMetadata)) {
|
|
204
|
+
location.reload();
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const fields = getFields(oldClass, newClass);
|
|
209
|
+
|
|
210
|
+
if (checkFieldsNeedReload(fields)) {
|
|
211
|
+
location.reload();
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
Object.entries(fields.staticFields).forEach(([type, { remove, add }]) => {
|
|
216
|
+
remove.forEach((prop) => {
|
|
217
|
+
if (safeProp.has(type)) {
|
|
218
|
+
deleteProperty(oldClass, prop.name);
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
add.forEach((prop) => {
|
|
222
|
+
if (safeProp.has(type)) {
|
|
223
|
+
setProperty(oldClass, prop.name, getProperty(newClass, prop.name));
|
|
224
|
+
}
|
|
225
|
+
});
|
|
231
226
|
});
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
227
|
+
|
|
228
|
+
const instanceFieldsEntries = Object.entries(fields.instanceFields);
|
|
229
|
+
// 删除的属性重新加回来要先清除占位值
|
|
230
|
+
instanceFieldsEntries.forEach(([type, { add }]) => {
|
|
235
231
|
add.forEach((prop) => {
|
|
236
232
|
if (type in descMap) {
|
|
237
|
-
(
|
|
238
|
-
name: prop.name,
|
|
239
|
-
metadata: oldMetadata,
|
|
240
|
-
addInitializer: (fn: () => void) => fn.apply(element),
|
|
241
|
-
} as ClassMemberDecoratorContext);
|
|
233
|
+
deleteProperty(oldClass.prototype, prop.name);
|
|
242
234
|
}
|
|
243
235
|
});
|
|
236
|
+
});
|
|
237
|
+
updateElement(name, (element) => {
|
|
238
|
+
instanceFieldsEntries.forEach(([type, { add, remove }]) => {
|
|
239
|
+
add.forEach((prop) => {
|
|
240
|
+
if (type in descMap) {
|
|
241
|
+
(descMap as any)[type](undefined, {
|
|
242
|
+
name: prop.name,
|
|
243
|
+
metadata: oldMetadata,
|
|
244
|
+
addInitializer: (fn: () => void) => fn.apply(element),
|
|
245
|
+
} as ClassMemberDecoratorContext);
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
remove.forEach((prop) => {
|
|
249
|
+
setProperty(element, prop.name, undefined);
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
// 删除的属性在 proto 上添加占位符
|
|
254
|
+
instanceFieldsEntries.forEach(([type, { remove }]) => {
|
|
244
255
|
remove.forEach((prop) => {
|
|
245
|
-
|
|
256
|
+
if (type in descMap) {
|
|
257
|
+
// attribute 映射 prop 没有移除
|
|
258
|
+
setProperty(oldClass.prototype, prop.name, undefined);
|
|
259
|
+
}
|
|
246
260
|
});
|
|
247
261
|
});
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
262
|
+
|
|
263
|
+
setArrValue(oldMetadata, 'definedParts', newMetadata.definedParts);
|
|
264
|
+
setArrValue(oldMetadata, 'definedSlots', newMetadata.definedSlots);
|
|
265
|
+
setArrValue(oldMetadata, 'observedProperties', newMetadata.observedProperties);
|
|
266
|
+
setArrValue(oldMetadata, 'observedAttributes', newMetadata.observedAttributes);
|
|
267
|
+
setArrValue(oldMetadata, 'definedEvents', newMetadata.definedEvents);
|
|
268
|
+
setArrValue(oldMetadata, 'definedCSSStates', newMetadata.definedCSSStates);
|
|
269
|
+
setArrValue(oldMetadata, 'adoptedStyleSheets', newMetadata.adoptedStyleSheets);
|
|
270
|
+
setArrValue(oldClass, '_defined_fields_', newClass._defined_fields_);
|
|
271
|
+
|
|
272
|
+
[
|
|
273
|
+
[oldClass, newClass],
|
|
274
|
+
[oldClass.prototype, newClass.prototype],
|
|
275
|
+
].forEach(([existedObj, newObj]) => {
|
|
276
|
+
Object.assign(
|
|
277
|
+
existedObj,
|
|
278
|
+
Object.fromEntries(
|
|
279
|
+
getHmrMethodKeys(newObj)
|
|
280
|
+
.filter((key) => existedObj[key].toString() !== newObj[key].toString())
|
|
281
|
+
.map((key) => [key, newObj[key]]),
|
|
282
|
+
),
|
|
283
|
+
);
|
|
256
284
|
});
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
setArrValue(oldMetadata, 'definedParts', newMetadata.definedParts);
|
|
260
|
-
setArrValue(oldMetadata, 'definedSlots', newMetadata.definedSlots);
|
|
261
|
-
setArrValue(oldMetadata, 'observedProperties', newMetadata.observedProperties);
|
|
262
|
-
setArrValue(oldMetadata, 'observedAttributes', newMetadata.observedAttributes);
|
|
263
|
-
setArrValue(oldMetadata, 'definedEvents', newMetadata.definedEvents);
|
|
264
|
-
setArrValue(oldMetadata, 'definedCSSStates', newMetadata.definedCSSStates);
|
|
265
|
-
setArrValue(oldMetadata, 'adoptedStyleSheets', newMetadata.adoptedStyleSheets);
|
|
266
|
-
setArrValue(oldClass, '_defined_fields_', newClass._defined_fields_);
|
|
267
|
-
|
|
268
|
-
[
|
|
269
|
-
[oldClass, newClass],
|
|
270
|
-
[oldClass.prototype, newClass.prototype],
|
|
271
|
-
].forEach(([existedObj, newObj]) => {
|
|
272
|
-
Object.assign(
|
|
273
|
-
existedObj,
|
|
274
|
-
Object.fromEntries(
|
|
275
|
-
getHmrMethodKeys(newObj)
|
|
276
|
-
.filter((key) => existedObj[key].toString() !== newObj[key].toString())
|
|
277
|
-
.map((key) => [key, newObj[key]]),
|
|
278
|
-
),
|
|
279
|
-
);
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
current = [getPrototypeOf(oldClass), getPrototypeOf(newClass)];
|
|
283
|
-
}
|
|
284
|
-
});
|
|
285
|
-
};
|
|
286
285
|
|
|
287
|
-
|
|
288
|
-
|
|
286
|
+
current = [getPrototypeOf(oldClass), getPrototypeOf(newClass)];
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
};
|
|
289
290
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
291
|
+
window.customElements.define = (name: string, cls: CustomElementConstructor) => {
|
|
292
|
+
const existed = customElements.get(name);
|
|
293
|
+
|
|
294
|
+
if (!existed) {
|
|
295
|
+
nativeDefineElement(name, cls);
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
294
298
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
299
|
+
// 等待类更新
|
|
300
|
+
queueMicrotask(() => {
|
|
301
|
+
logger.info(`<${name}> update,`, { cls });
|
|
298
302
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
303
|
+
updateElement(name, (element) => {
|
|
304
|
+
// 触发样式更新,支持 Light DOM
|
|
305
|
+
element.after(element);
|
|
306
|
+
// 重新渲染
|
|
307
|
+
(element as any)[UpdateToken]?.();
|
|
308
|
+
});
|
|
304
309
|
});
|
|
305
|
-
}
|
|
306
|
-
}
|
|
310
|
+
};
|
|
311
|
+
}
|
package/src/lib/history.ts
CHANGED
|
@@ -213,7 +213,8 @@ if (!globalThis._GEMHISTORY) {
|
|
|
213
213
|
// 初始化 historyState
|
|
214
214
|
const { protocol, pathname, search, hash } = location;
|
|
215
215
|
// 支持在 `data:` `blob:` 中 `import`
|
|
216
|
-
if (protocol.startsWith('http')
|
|
216
|
+
if (protocol.startsWith('http') || protocol.startsWith('tauri'))
|
|
217
|
+
gemHistory.replace({ path: pathname, query: search, hash });
|
|
217
218
|
} else if (nativeHistory.state.$hasCloseHandle) {
|
|
218
219
|
store(nativeHistory.state);
|
|
219
220
|
const params = normalizeParams({ title: document.title });
|
|
@@ -315,4 +316,5 @@ if (!globalThis._GEMHISTORY) {
|
|
|
315
316
|
}
|
|
316
317
|
|
|
317
318
|
const { history, titleStore, basePathStore } = globalThis._GEMHISTORY;
|
|
319
|
+
|
|
318
320
|
export { basePathStore, history, titleStore };
|
package/src/lib/lit-html.ts
CHANGED
|
@@ -615,9 +615,11 @@ export class TemplateInstance implements Disconnectable {
|
|
|
615
615
|
}
|
|
616
616
|
}
|
|
617
617
|
|
|
618
|
+
const conditionMap = new Map<Element, ConditionChain>();
|
|
618
619
|
ifMap.forEach((idx, element) => {
|
|
619
620
|
const chain = new ConditionChain(element, idx);
|
|
620
621
|
this._$conditions.push(chain);
|
|
622
|
+
conditionMap.set(element, chain);
|
|
621
623
|
let ele: Element | null = element;
|
|
622
624
|
while ((ele = ele.nextElementSibling)) {
|
|
623
625
|
const pos = elseIfMap.get(ele);
|
|
@@ -625,6 +627,13 @@ export class TemplateInstance implements Disconnectable {
|
|
|
625
627
|
chain.push(ele, pos);
|
|
626
628
|
}
|
|
627
629
|
});
|
|
630
|
+
// A ChildPart can use the following conditional element as its end boundary.
|
|
631
|
+
// Point it to the persistent chain marker before v-if can remove that element.
|
|
632
|
+
for (const part of this._$parts) {
|
|
633
|
+
if (part?.type !== CHILD_PART) continue;
|
|
634
|
+
const chain = conditionMap.get(part._$endNode as Element);
|
|
635
|
+
if (chain) part._$endNode = chain.mark;
|
|
636
|
+
}
|
|
628
637
|
|
|
629
638
|
// We need to set the currentNode away from the cloned tree so that we
|
|
630
639
|
// don't hold onto the tree even if the tree is detached and should be
|
package/src/lib/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '2.2.
|
|
1
|
+
export const version = '2.2.6';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { html, render } from '../lib/lit-html';
|
|
2
|
+
import { expect } from './utils';
|
|
3
|
+
|
|
4
|
+
describe('lit-html', () => {
|
|
5
|
+
it('updates an iterable before a removed v-if element', () => {
|
|
6
|
+
const container = document.createElement('div');
|
|
7
|
+
const view = (messages: string[], permissionRequest: boolean) =>
|
|
8
|
+
html`${messages.map((message) => html`<p>${message}</p>`)}<div v-if=${permissionRequest}>Permission request</div>`;
|
|
9
|
+
|
|
10
|
+
render(view(['Message 1'], false), container);
|
|
11
|
+
expect(container.textContent?.trim()).to.equal('Message 1');
|
|
12
|
+
|
|
13
|
+
expect(() => render(view(['Message 1', 'Message 2'], false), container)).not.to.throw();
|
|
14
|
+
expect(container.textContent?.replace(/\s/g, '')).to.equal('Message1Message2');
|
|
15
|
+
|
|
16
|
+
render(view(['Message 1', 'Message 2'], true), container);
|
|
17
|
+
expect(container.textContent?.replace(/\s/g, '')).to.equal('Message1Message2Permissionrequest');
|
|
18
|
+
});
|
|
19
|
+
});
|