@lithent/hmr-parser 0.1.1 → 0.2.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/package.json CHANGED
@@ -1,9 +1,8 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@lithent/hmr-parser",
4
- "version": "0.1.1",
4
+ "version": "0.2.0",
5
5
  "description": "Lithent HMR parser utilities for build tools",
6
- "packageManager": "pnpm@9.12.3",
7
6
  "main": "./dist/lithentHmrParser.umd.js",
8
7
  "module": "./dist/lithentHmrParser.mjs",
9
8
  "types": "./dist/index.d.ts",
@@ -14,12 +13,6 @@
14
13
  "require": "./dist/lithentHmrParser.umd.js"
15
14
  }
16
15
  },
17
- "scripts": {
18
- "build": "vite build",
19
- "watch": "vite build --watch",
20
- "test": "vitest run --reporter verbose",
21
- "test:dev": "vitest"
22
- },
23
16
  "author": "superlucky84",
24
17
  "repository": {
25
18
  "type": "git",
@@ -27,7 +20,11 @@
27
20
  },
28
21
  "homepage": "https://github.com/superlucky84/lithent",
29
22
  "license": "MIT",
30
- "keywords": ["lithent", "hmr", "parser"],
23
+ "keywords": [
24
+ "lithent",
25
+ "hmr",
26
+ "parser"
27
+ ],
31
28
  "dependencies": {
32
29
  "@babel/parser": "^7.26.2",
33
30
  "@babel/types": "^7.26.0",
@@ -38,15 +35,21 @@
38
35
  "src"
39
36
  ],
40
37
  "devDependencies": {
41
- "lithent": "^1.20.0",
42
38
  "@types/babel__traverse": "^7.20.6",
43
39
  "vite": "^5.4.8",
44
40
  "vite-plugin-checker": "^0.8.0",
45
41
  "vite-plugin-dts": "^4.2.1",
46
- "vitest": "^2.1.5"
42
+ "vitest": "^2.1.5",
43
+ "lithent": "1.20.0"
47
44
  },
48
45
  "volta": {
49
46
  "node": "20.3.0",
50
47
  "pnpm": "9.12.3"
48
+ },
49
+ "scripts": {
50
+ "build": "vite build",
51
+ "watch": "vite build --watch",
52
+ "test": "vitest run --reporter verbose",
53
+ "test:dev": "vitest"
51
54
  }
52
- }
55
+ }
@@ -86,11 +86,10 @@ export const collectHeaderInsert = (
86
86
  ast: File,
87
87
  sourceCode: string,
88
88
  boundaryImportSpecifier: string,
89
- tagFunctionImportSpecifier: string
89
+ _tagFunctionImportSpecifier: string
90
90
  ) => {
91
91
  const importsToPrepend: string[] = [];
92
92
  let hasBoundaryImport = false;
93
- let hasTagImport = false;
94
93
  let lastImportEnd = 0;
95
94
  let directiveEnd = 0;
96
95
  let firstImportStart: number | null = null;
@@ -106,20 +105,6 @@ export const collectHeaderInsert = (
106
105
  hasBoundaryImport = true;
107
106
  }
108
107
 
109
- if (node.source.value === tagFunctionImportSpecifier) {
110
- const hasTag = node.specifiers.some(specifier => {
111
- return (
112
- specifier.type === 'ImportSpecifier' &&
113
- specifier.imported.type === 'Identifier' &&
114
- specifier.imported.name === 'TagFunction'
115
- );
116
- });
117
-
118
- if (hasTag) {
119
- hasTagImport = true;
120
- }
121
- }
122
-
123
108
  continue;
124
109
  }
125
110
 
@@ -145,11 +130,10 @@ export const collectHeaderInsert = (
145
130
  );
146
131
  }
147
132
 
148
- if (!hasTagImport) {
149
- importsToPrepend.push(
150
- `import type { TagFunction } from '${tagFunctionImportSpecifier}';`
151
- );
152
- }
133
+ // Note: We don't add TagFunction import anymore since:
134
+ // 1. In enforce:'post', esbuild already removed type imports
135
+ // 2. The type is only used for TypeScript casting, not at runtime
136
+ // 3. Adding "import type" in post-transform breaks browser execution
153
137
 
154
138
  const importInsertionPos = firstImportStart ?? directiveEnd ?? 0;
155
139
  const blockInsertionPos = lastImportEnd || directiveEnd || 0;
package/src/strings.ts CHANGED
@@ -14,17 +14,11 @@ const __lithentBoundaryStoreKey = \`__lithent_hmr_boundary__\${__lithentModuleId
14
14
  const __lithentDisposeStoreKey = \`__lithent_hmr_dispose__\${__lithentModuleId}\`;
15
15
  const __lithentGlobalStore =
16
16
  typeof globalThis === 'object'
17
- ? (globalThis as Record<string, unknown>)
17
+ ? globalThis
18
18
  : undefined;
19
19
 
20
- const __lithentEnsureHotData = (): Record<string, unknown> | undefined => {
21
- const hot =
22
- (import.meta.hot as
23
- | {
24
- data?: Record<string, unknown>;
25
- __lithentData?: Record<string, unknown>;
26
- }
27
- | undefined) ?? undefined;
20
+ const __lithentEnsureHotData = () => {
21
+ const hot = import.meta.hot ?? undefined;
28
22
  if (!hot) return undefined;
29
23
 
30
24
  const existing = hot.data;
@@ -33,7 +27,7 @@ const __lithentEnsureHotData = (): Record<string, unknown> | undefined => {
33
27
  }
34
28
 
35
29
  try {
36
- const target: Record<string, unknown> = {};
30
+ const target = {};
37
31
  hot.data = target;
38
32
  return target;
39
33
  } catch {
@@ -43,11 +37,10 @@ const __lithentEnsureHotData = (): Record<string, unknown> | undefined => {
43
37
  };
44
38
 
45
39
  const __lithentHotData = __lithentEnsureHotData();
46
- type __LithentBoundaryController = ReturnType<typeof createBoundary>;
47
40
 
48
- const counterBoundary: __LithentBoundaryController =
49
- (__lithentHotData?.counterBoundary as __LithentBoundaryController | undefined) ||
50
- (__lithentGlobalStore?.[__lithentBoundaryStoreKey] as __LithentBoundaryController | undefined) ||
41
+ const counterBoundary =
42
+ __lithentHotData?.counterBoundary ||
43
+ __lithentGlobalStore?.[__lithentBoundaryStoreKey] ||
51
44
  createBoundary(__lithentModuleId);
52
45
 
53
46
  if (__lithentHotData) {
@@ -59,18 +52,18 @@ if (__lithentGlobalStore) {
59
52
  }
60
53
 
61
54
  let disposeApp =
62
- (__lithentHotData?.disposeApp as (() => void) | undefined) ||
63
- (__lithentGlobalStore?.[__lithentDisposeStoreKey] as (() => void) | undefined);
55
+ __lithentHotData?.disposeApp ||
56
+ __lithentGlobalStore?.[__lithentDisposeStoreKey];
64
57
 
65
- const __lithentRenderOnce = <T,>(factory: () => T) => {
58
+ const __lithentRenderOnce = (factory) => {
66
59
  if (disposeApp) {
67
- return disposeApp as unknown as T;
60
+ return disposeApp;
68
61
  }
69
62
 
70
63
  const result = factory();
71
64
 
72
65
  if (typeof result === 'function') {
73
- disposeApp = result as unknown as () => void;
66
+ disposeApp = result;
74
67
 
75
68
  if (__lithentHotData) {
76
69
  __lithentHotData.disposeApp = disposeApp;
@@ -87,10 +80,7 @@ const __lithentRenderOnce = <T,>(factory: () => T) => {
87
80
  const __lithentModuleHotStore =
88
81
  __lithentHotData
89
82
  ? ((__lithentHotData.components =
90
- (__lithentHotData.components as Record<
91
- string,
92
- TagFunction | undefined
93
- > | undefined) ?? {}) as Record<string, TagFunction | undefined>)
83
+ __lithentHotData.components ?? {}))
94
84
  : undefined;
95
85
 
96
86
  const __lithentHmrTargets = ${serializedTargets};
@@ -102,8 +92,8 @@ const __lithentSetupHmrHooks = () => {
102
92
 
103
93
  import.meta.hot.accept(mod => {
104
94
  let applied = false;
105
- const nextModule = (mod ?? {}) as Record<string, unknown>;
106
- const missing: string[] = [];
95
+ const nextModule = mod ?? {};
96
+ const missing = [];
107
97
  const knownNames = new Set([
108
98
  ...${JSON.stringify(Array.from(new Set(componentNames)))},
109
99
  ...__lithentHmrTargets,
@@ -112,9 +102,9 @@ const __lithentSetupHmrHooks = () => {
112
102
  for (const name of knownNames) {
113
103
  const nextCtor =
114
104
  name === 'default'
115
- ? (nextModule.default as TagFunction | undefined)
116
- : (nextModule[name] as TagFunction | undefined) ||
117
- (__lithentModuleHotStore?.[name] as TagFunction | undefined);
105
+ ? nextModule.default
106
+ : nextModule[name] ||
107
+ __lithentModuleHotStore?.[name];
118
108
 
119
109
  if (!nextCtor) {
120
110
  missing.push(name);
@@ -131,9 +121,7 @@ const __lithentSetupHmrHooks = () => {
131
121
  queueMicrotask(() => {
132
122
  let retried = false;
133
123
  for (const name of missing) {
134
- const retryCtor = __lithentModuleHotStore?.[name] as
135
- | TagFunction
136
- | undefined;
124
+ const retryCtor = __lithentModuleHotStore?.[name];
137
125
  if (retryCtor && counterBoundary.update(retryCtor)) {
138
126
  retried = true;
139
127
  }
@@ -84,10 +84,7 @@ if (import.meta.vitest) {
84
84
  expect(defaultResult.code).toContain(
85
85
  "import { createBoundary } from 'lithent/devHelper';"
86
86
  );
87
- expect(defaultResult.code).toContain(
88
- "import type { TagFunction } from 'lithent';"
89
- );
90
- expect(defaultResult.code).toContain('import.meta.hot as');
87
+ expect(defaultResult.code).toContain('import.meta.hot');
91
88
  expect(defaultResult.code).toContain(
92
89
  "import { mountCallback, getComponentKey } from 'lithent';"
93
90
  );
@@ -101,18 +98,20 @@ if (import.meta.vitest) {
101
98
  expect(defaultResult.code).toContain('...["App","Secondary"]');
102
99
  expect(defaultResult.code).toContain('...__lithentHmrTargets');
103
100
  expect(defaultResult.code).toContain(
104
- 'const __lithentHotComponent_App = App as unknown as TagFunction;'
101
+ 'const __lithentHotComponent_App = App;'
105
102
  );
106
103
  expect(defaultResult.code).toContain(
107
104
  '__lithentModuleHotStore["App"] = __lithentHotComponent_App;'
108
105
  );
109
106
  expect(defaultResult.code).toContain(
110
- 'const __lithentHotComponent_Secondary = Secondary as unknown as TagFunction;'
107
+ 'const __lithentHotComponent_Secondary = Secondary;'
111
108
  );
112
109
  expect(defaultResult.code).toContain(
113
110
  '__lithentModuleHotStore["Secondary"] = __lithentHotComponent_Secondary;'
114
111
  );
115
- expect(defaultResult.code).toContain('const __lithentRenderOnce = <');
112
+ expect(defaultResult.code).toContain(
113
+ 'const __lithentRenderOnce = (factory)'
114
+ );
116
115
  const registerMatches =
117
116
  defaultResult.code.match(/counterBoundary\.register\(compKey\)/g) ?? [];
118
117
  const unregisterMatches =
@@ -133,18 +132,18 @@ if (import.meta.vitest) {
133
132
  expect(namedResult.code).toContain(
134
133
  'const __lithentHmrTargets = ["Counter","Another"];'
135
134
  );
136
- expect(namedResult.code).toContain('import.meta.hot as');
135
+ expect(namedResult.code).toContain('import.meta.hot');
137
136
  expect(namedResult.code).toContain('const knownNames = new Set([');
138
137
  expect(namedResult.code).toContain('...["Counter","Another"]');
139
138
  expect(namedResult.code).toContain('...__lithentHmrTargets');
140
139
  expect(namedResult.code).toContain(
141
- 'const __lithentHotComponent_Counter = Counter as unknown as TagFunction;'
140
+ 'const __lithentHotComponent_Counter = Counter;'
142
141
  );
143
142
  expect(namedResult.code).toContain(
144
143
  '__lithentModuleHotStore["Counter"] = __lithentHotComponent_Counter;'
145
144
  );
146
145
  expect(namedResult.code).toContain(
147
- 'const __lithentHotComponent_Another = Another as unknown as TagFunction;'
146
+ 'const __lithentHotComponent_Another = Another;'
148
147
  );
149
148
  expect(namedResult.code).toContain(
150
149
  '__lithentModuleHotStore["Another"] = __lithentHotComponent_Another;'
@@ -65,9 +65,7 @@ if (import.meta.vitest) {
65
65
  expect(result.code.includes('...["Demo","Another"]')).toBe(true);
66
66
  expect(result.code.includes('...__lithentHmrTargets')).toBe(true);
67
67
  expect(
68
- result.code.includes(
69
- 'const __lithentHotComponent_Demo = Demo as unknown as TagFunction;'
70
- )
68
+ result.code.includes('const __lithentHotComponent_Demo = Demo;')
71
69
  ).toBe(true);
72
70
  expect(
73
71
  result.code.includes(
@@ -75,16 +73,16 @@ if (import.meta.vitest) {
75
73
  )
76
74
  ).toBe(true);
77
75
  expect(
78
- result.code.includes(
79
- 'const __lithentHotComponent_Another = Another as unknown as TagFunction;'
80
- )
76
+ result.code.includes('const __lithentHotComponent_Another = Another;')
81
77
  ).toBe(true);
82
78
  expect(
83
79
  result.code.includes(
84
80
  '__lithentModuleHotStore["Another"] = __lithentHotComponent_Another;'
85
81
  )
86
82
  ).toBe(true);
87
- expect(result.code.includes('const __lithentRenderOnce = <')).toBe(true);
83
+ expect(
84
+ result.code.includes('const __lithentRenderOnce = (factory)')
85
+ ).toBe(true);
88
86
  expect(/__lithentRenderOnce\(\(\) =>\s*render\(/.test(result.code)).toBe(
89
87
  true
90
88
  );
@@ -39,7 +39,7 @@ export const stitchComponentRegistration = (
39
39
  if (componentName) {
40
40
  const hotStoreVar = `__lithentHotComponent_${componentName}`;
41
41
  const storeSnippet = `
42
- const ${hotStoreVar} = ${componentName} as unknown as TagFunction;
42
+ const ${hotStoreVar} = ${componentName};
43
43
  if (__lithentModuleHotStore) {
44
44
  __lithentModuleHotStore["${componentName}"] = ${hotStoreVar};
45
45
  }