native-sfc 0.0.2 → 0.0.3

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 CHANGED
@@ -11,6 +11,8 @@ Load a single HTML file as a Web Component.
11
11
  </script>
12
12
  ```
13
13
 
14
+ Use `export default` to declare the component class.
15
+
14
16
  ```html
15
17
  <!-- my-counter.html -->
16
18
  <button @click="setCount(count() + 1)">Count is: {{ count() }}</button>
@@ -21,8 +23,15 @@ Load a single HTML file as a Web Component.
21
23
  const [count, setCount] = signal(0);
22
24
  return { count, setCount };
23
25
  }
24
- connectedCallback() {}
26
+ connectedCallback() {/* TODO */}
25
27
  }
28
+ // OR
29
+ import { defineComponent } from "https://esm.sh/native-sfc";
30
+ export default defineComponent(({ onConnected }) => {
31
+ const [count, setCount] = signal(0);
32
+ onConnected(() => {/* TODO */});
33
+ return { count, setCount };
34
+ });
26
35
  </script>
27
36
  ```
28
37
 
@@ -2071,6 +2071,7 @@ ${code}`,
2071
2071
  on
2072
2072
  };
2073
2073
  Object.preventExtensions(config);
2074
+ var bind = (fn, thisArg) => fn.bind(thisArg);
2074
2075
 
2075
2076
  // src/rewriter.ts
2076
2077
  async function rewriteModule(code, sourceUrl) {
@@ -2222,6 +2223,15 @@ var EffectScope = class {
2222
2223
  }
2223
2224
  };
2224
2225
  var activeScope = null;
2226
+ function untrack(fn) {
2227
+ const prevEffect = activeEffect;
2228
+ activeEffect = null;
2229
+ try {
2230
+ return fn();
2231
+ } finally {
2232
+ activeEffect = prevEffect;
2233
+ }
2234
+ }
2225
2235
  function effectScope(fn) {
2226
2236
  const scope = new EffectScope();
2227
2237
  if (fn) scope.run(fn);
@@ -2374,11 +2384,15 @@ function reactiveNodes(nodes, context) {
2374
2384
  const ctx = typeof context === "object" ? Object.assign({}, context, additionalContext) : additionalContext;
2375
2385
  const keys = Object.keys(ctx);
2376
2386
  const values = Object.values(ctx);
2377
- const func = new Function(...keys, `return ${expr.trimStart()}`);
2378
- return func(...values);
2387
+ try {
2388
+ const func = new Function(...keys, `return ${expr.trimStart()}`);
2389
+ return func(...values);
2390
+ } catch (error) {
2391
+ warn(`Failed to evaluate expression: "${expr}"`, error);
2392
+ }
2379
2393
  };
2380
2394
  const recursive = (nodes2) => {
2381
- for (const node of nodes2) {
2395
+ for (const node of Array.from(nodes2)) {
2382
2396
  if (node.nodeType === Node.ELEMENT_NODE) {
2383
2397
  const element = node;
2384
2398
  const ifAttr = element.getAttribute("#if");
@@ -2447,7 +2461,7 @@ function reactiveNodes(nodes, context) {
2447
2461
  const expr = attr.value;
2448
2462
  effect(() => {
2449
2463
  const value = evalExpr(expr);
2450
- Reflect.set(element, propName, value);
2464
+ untrack(() => Reflect.set(element, propName, value));
2451
2465
  });
2452
2466
  element.removeAttribute(attr.name);
2453
2467
  } else if (attr.name.startsWith(":")) {
@@ -2455,7 +2469,7 @@ function reactiveNodes(nodes, context) {
2455
2469
  const expr = attr.value;
2456
2470
  effect(() => {
2457
2471
  const value = evalExpr(expr);
2458
- element.setAttribute(attrName, value);
2472
+ untrack(() => element.setAttribute(attrName, value));
2459
2473
  });
2460
2474
  element.removeAttribute(attr.name);
2461
2475
  } else if (attr.name.startsWith("@")) {
@@ -2486,7 +2500,7 @@ function reactiveNodes(nodes, context) {
2486
2500
  if (part.type === "dynamic") {
2487
2501
  effect(() => {
2488
2502
  const value = evalExpr(part.content);
2489
- newTextNode.textContent = String(value);
2503
+ untrack(() => newTextNode.textContent = String(value));
2490
2504
  });
2491
2505
  }
2492
2506
  }
@@ -2579,26 +2593,30 @@ function defineComponent(setup) {
2579
2593
  _onConnectedEvents = [];
2580
2594
  _onDisconnectedEvents = [];
2581
2595
  setup() {
2582
- return setup({
2583
- onConnected: (event) => this._onConnectedEvents.push(event),
2584
- onDisconnected: (event) => this._onDisconnectedEvents.push(event)
2596
+ const setup22 = bind(setup, this);
2597
+ return setup22({
2598
+ onConnected: (event) => this._onConnectedEvents.push(bind(event, this)),
2599
+ onDisconnected: (event) => this._onDisconnectedEvents.push(bind(event, this))
2585
2600
  });
2586
2601
  }
2587
2602
  connectedCallback() {
2588
2603
  const root = this.shadowRoot || this.attachShadow({ mode: "open" });
2589
- this._onConnectedEvents.forEach((cb) => cb.call(void 0, root));
2604
+ untrack(() => this._onConnectedEvents.forEach((cb) => cb(root)));
2590
2605
  }
2591
2606
  disconnectedCallback() {
2592
2607
  const root = this.shadowRoot;
2593
- this._onDisconnectedEvents.forEach((cb) => cb.call(void 0, root));
2608
+ untrack(() => this._onDisconnectedEvents.forEach((cb) => cb(root)));
2594
2609
  }
2595
2610
  };
2596
2611
  }
2597
- return setup({
2598
- onConnected: (cb) => cb(document),
2612
+ const setup2 = bind(setup, void 0);
2613
+ const context = setup2({
2614
+ onConnected: (cb) => queueMicrotask(() => cb(document)),
2599
2615
  onDisconnected: () => {
2600
2616
  }
2601
2617
  });
2618
+ reactiveNodes(document.body.childNodes, context);
2619
+ return;
2602
2620
  }
2603
2621
  function filterGlobalStyle(doc) {
2604
2622
  for (const styleElement of doc.querySelectorAll("style")) {
@@ -2687,7 +2705,11 @@ export {
2687
2705
  effect,
2688
2706
  effectScope,
2689
2707
  loadComponent,
2690
- signal
2708
+ signal,
2709
+ untrack
2691
2710
  };
2692
2711
  //! we provide an extra argument to user's component constructor
2693
2712
  //! if the user's constructor does not create a shadow root, we will create one here
2713
+ //! we bind `this` to the setup function, so that users can access `this` in setup, and `this` is the component instance
2714
+ //! `this` is undefined in normal document context's setup function
2715
+ //! make the document.body reactive, just like the web component (defined at `extendsElement`)
package/dist/index.cdn.js CHANGED
@@ -28,6 +28,7 @@ ${code}`,
28
28
  on
29
29
  };
30
30
  Object.preventExtensions(config);
31
+ var bind = (fn, thisArg) => fn.bind(thisArg);
31
32
 
32
33
  // src/rewriter.ts
33
34
  async function rewriteModule(code, sourceUrl) {
@@ -179,6 +180,15 @@ var EffectScope = class {
179
180
  }
180
181
  };
181
182
  var activeScope = null;
183
+ function untrack(fn) {
184
+ const prevEffect = activeEffect;
185
+ activeEffect = null;
186
+ try {
187
+ return fn();
188
+ } finally {
189
+ activeEffect = prevEffect;
190
+ }
191
+ }
182
192
  function effectScope(fn) {
183
193
  const scope = new EffectScope();
184
194
  if (fn) scope.run(fn);
@@ -331,11 +341,15 @@ function reactiveNodes(nodes, context) {
331
341
  const ctx = typeof context === "object" ? Object.assign({}, context, additionalContext) : additionalContext;
332
342
  const keys = Object.keys(ctx);
333
343
  const values = Object.values(ctx);
334
- const func = new Function(...keys, `return ${expr.trimStart()}`);
335
- return func(...values);
344
+ try {
345
+ const func = new Function(...keys, `return ${expr.trimStart()}`);
346
+ return func(...values);
347
+ } catch (error) {
348
+ warn(`Failed to evaluate expression: "${expr}"`, error);
349
+ }
336
350
  };
337
351
  const recursive = (nodes2) => {
338
- for (const node of nodes2) {
352
+ for (const node of Array.from(nodes2)) {
339
353
  if (node.nodeType === Node.ELEMENT_NODE) {
340
354
  const element = node;
341
355
  const ifAttr = element.getAttribute("#if");
@@ -404,7 +418,7 @@ function reactiveNodes(nodes, context) {
404
418
  const expr = attr.value;
405
419
  effect(() => {
406
420
  const value = evalExpr(expr);
407
- Reflect.set(element, propName, value);
421
+ untrack(() => Reflect.set(element, propName, value));
408
422
  });
409
423
  element.removeAttribute(attr.name);
410
424
  } else if (attr.name.startsWith(":")) {
@@ -412,7 +426,7 @@ function reactiveNodes(nodes, context) {
412
426
  const expr = attr.value;
413
427
  effect(() => {
414
428
  const value = evalExpr(expr);
415
- element.setAttribute(attrName, value);
429
+ untrack(() => element.setAttribute(attrName, value));
416
430
  });
417
431
  element.removeAttribute(attr.name);
418
432
  } else if (attr.name.startsWith("@")) {
@@ -443,7 +457,7 @@ function reactiveNodes(nodes, context) {
443
457
  if (part.type === "dynamic") {
444
458
  effect(() => {
445
459
  const value = evalExpr(part.content);
446
- newTextNode.textContent = String(value);
460
+ untrack(() => newTextNode.textContent = String(value));
447
461
  });
448
462
  }
449
463
  }
@@ -536,26 +550,30 @@ function defineComponent(setup) {
536
550
  _onConnectedEvents = [];
537
551
  _onDisconnectedEvents = [];
538
552
  setup() {
539
- return setup({
540
- onConnected: (event) => this._onConnectedEvents.push(event),
541
- onDisconnected: (event) => this._onDisconnectedEvents.push(event)
553
+ const setup22 = bind(setup, this);
554
+ return setup22({
555
+ onConnected: (event) => this._onConnectedEvents.push(bind(event, this)),
556
+ onDisconnected: (event) => this._onDisconnectedEvents.push(bind(event, this))
542
557
  });
543
558
  }
544
559
  connectedCallback() {
545
560
  const root = this.shadowRoot || this.attachShadow({ mode: "open" });
546
- this._onConnectedEvents.forEach((cb) => cb.call(void 0, root));
561
+ untrack(() => this._onConnectedEvents.forEach((cb) => cb(root)));
547
562
  }
548
563
  disconnectedCallback() {
549
564
  const root = this.shadowRoot;
550
- this._onDisconnectedEvents.forEach((cb) => cb.call(void 0, root));
565
+ untrack(() => this._onDisconnectedEvents.forEach((cb) => cb(root)));
551
566
  }
552
567
  };
553
568
  }
554
- return setup({
555
- onConnected: (cb) => cb(document),
569
+ const setup2 = bind(setup, void 0);
570
+ const context = setup2({
571
+ onConnected: (cb) => queueMicrotask(() => cb(document)),
556
572
  onDisconnected: () => {
557
573
  }
558
574
  });
575
+ reactiveNodes(document.body.childNodes, context);
576
+ return;
559
577
  }
560
578
  function filterGlobalStyle(doc) {
561
579
  for (const styleElement of doc.querySelectorAll("style")) {
@@ -644,7 +662,11 @@ export {
644
662
  effect,
645
663
  effectScope,
646
664
  loadComponent,
647
- signal
665
+ signal,
666
+ untrack
648
667
  };
649
668
  //! we provide an extra argument to user's component constructor
650
669
  //! if the user's constructor does not create a shadow root, we will create one here
670
+ //! we bind `this` to the setup function, so that users can access `this` in setup, and `this` is the component instance
671
+ //! `this` is undefined in normal document context's setup function
672
+ //! make the document.body reactive, just like the web component (defined at `extendsElement`)
package/dist/index.d.ts CHANGED
@@ -98,6 +98,9 @@ export type NativeSFCEventsMap = {
98
98
  [K in keyof NativeSFCEvents]: CustomEvent<NativeSFCEvents[K]>;
99
99
  };
100
100
  declare function on<K extends keyof NativeSFCEvents>(eventName: K, listener: (ev: NativeSFCEventsMap[K]) => any): () => void;
101
+ /**
102
+ * The global configuration object for the library.
103
+ */
101
104
  export declare const config: {
102
105
  fetch: typeof fetch;
103
106
  rewriteModule: (code: string, sourceUrl: string) => Awaitable<string>;
@@ -109,6 +112,7 @@ export declare class NativeSFCError extends Error {
109
112
  }
110
113
  export type Getter<T> = () => T;
111
114
  export type Setter<T> = (newValue: T) => void;
115
+ export declare function untrack<T>(fn: () => T): T;
112
116
  export declare function effectScope(fn?: VoidFunction): VoidFunction;
113
117
  export declare function effect(fn: VoidFunction): VoidFunction;
114
118
  export declare function signal<T>(initialValue: T): readonly [
package/dist/index.js CHANGED
@@ -28,6 +28,7 @@ ${code}`,
28
28
  on
29
29
  };
30
30
  Object.preventExtensions(config);
31
+ var bind = (fn, thisArg) => fn.bind(thisArg);
31
32
 
32
33
  // src/rewriter.ts
33
34
  async function rewriteModule(code, sourceUrl) {
@@ -179,6 +180,15 @@ var EffectScope = class {
179
180
  }
180
181
  };
181
182
  var activeScope = null;
183
+ function untrack(fn) {
184
+ const prevEffect = activeEffect;
185
+ activeEffect = null;
186
+ try {
187
+ return fn();
188
+ } finally {
189
+ activeEffect = prevEffect;
190
+ }
191
+ }
182
192
  function effectScope(fn) {
183
193
  const scope = new EffectScope();
184
194
  if (fn) scope.run(fn);
@@ -331,11 +341,15 @@ function reactiveNodes(nodes, context) {
331
341
  const ctx = typeof context === "object" ? Object.assign({}, context, additionalContext) : additionalContext;
332
342
  const keys = Object.keys(ctx);
333
343
  const values = Object.values(ctx);
334
- const func = new Function(...keys, `return ${expr.trimStart()}`);
335
- return func(...values);
344
+ try {
345
+ const func = new Function(...keys, `return ${expr.trimStart()}`);
346
+ return func(...values);
347
+ } catch (error) {
348
+ warn(`Failed to evaluate expression: "${expr}"`, error);
349
+ }
336
350
  };
337
351
  const recursive = (nodes2) => {
338
- for (const node of nodes2) {
352
+ for (const node of Array.from(nodes2)) {
339
353
  if (node.nodeType === Node.ELEMENT_NODE) {
340
354
  const element = node;
341
355
  const ifAttr = element.getAttribute("#if");
@@ -404,7 +418,7 @@ function reactiveNodes(nodes, context) {
404
418
  const expr = attr.value;
405
419
  effect(() => {
406
420
  const value = evalExpr(expr);
407
- Reflect.set(element, propName, value);
421
+ untrack(() => Reflect.set(element, propName, value));
408
422
  });
409
423
  element.removeAttribute(attr.name);
410
424
  } else if (attr.name.startsWith(":")) {
@@ -412,7 +426,7 @@ function reactiveNodes(nodes, context) {
412
426
  const expr = attr.value;
413
427
  effect(() => {
414
428
  const value = evalExpr(expr);
415
- element.setAttribute(attrName, value);
429
+ untrack(() => element.setAttribute(attrName, value));
416
430
  });
417
431
  element.removeAttribute(attr.name);
418
432
  } else if (attr.name.startsWith("@")) {
@@ -443,7 +457,7 @@ function reactiveNodes(nodes, context) {
443
457
  if (part.type === "dynamic") {
444
458
  effect(() => {
445
459
  const value = evalExpr(part.content);
446
- newTextNode.textContent = String(value);
460
+ untrack(() => newTextNode.textContent = String(value));
447
461
  });
448
462
  }
449
463
  }
@@ -536,26 +550,30 @@ function defineComponent(setup) {
536
550
  _onConnectedEvents = [];
537
551
  _onDisconnectedEvents = [];
538
552
  setup() {
539
- return setup({
540
- onConnected: (event) => this._onConnectedEvents.push(event),
541
- onDisconnected: (event) => this._onDisconnectedEvents.push(event)
553
+ const setup22 = bind(setup, this);
554
+ return setup22({
555
+ onConnected: (event) => this._onConnectedEvents.push(bind(event, this)),
556
+ onDisconnected: (event) => this._onDisconnectedEvents.push(bind(event, this))
542
557
  });
543
558
  }
544
559
  connectedCallback() {
545
560
  const root = this.shadowRoot || this.attachShadow({ mode: "open" });
546
- this._onConnectedEvents.forEach((cb) => cb.call(void 0, root));
561
+ untrack(() => this._onConnectedEvents.forEach((cb) => cb(root)));
547
562
  }
548
563
  disconnectedCallback() {
549
564
  const root = this.shadowRoot;
550
- this._onDisconnectedEvents.forEach((cb) => cb.call(void 0, root));
565
+ untrack(() => this._onDisconnectedEvents.forEach((cb) => cb(root)));
551
566
  }
552
567
  };
553
568
  }
554
- return setup({
555
- onConnected: (cb) => cb(document),
569
+ const setup2 = bind(setup, void 0);
570
+ const context = setup2({
571
+ onConnected: (cb) => queueMicrotask(() => cb(document)),
556
572
  onDisconnected: () => {
557
573
  }
558
574
  });
575
+ reactiveNodes(document.body.childNodes, context);
576
+ return;
559
577
  }
560
578
  function filterGlobalStyle(doc) {
561
579
  for (const styleElement of doc.querySelectorAll("style")) {
@@ -644,7 +662,11 @@ export {
644
662
  effect,
645
663
  effectScope,
646
664
  loadComponent,
647
- signal
665
+ signal,
666
+ untrack
648
667
  };
649
668
  //! we provide an extra argument to user's component constructor
650
669
  //! if the user's constructor does not create a shadow root, we will create one here
670
+ //! we bind `this` to the setup function, so that users can access `this` in setup, and `this` is the component instance
671
+ //! `this` is undefined in normal document context's setup function
672
+ //! make the document.body reactive, just like the web component (defined at `extendsElement`)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "native-sfc",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist"