@zerodep-dev/vue-tsx-pro-tsx 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +44 -2
- package/dist/compile-worker.d.ts +1 -0
- package/dist/compile-worker.js +23 -0
- package/dist/compiler-BDi92tYb.js +1647 -0
- package/dist/compiler.d.ts +104 -0
- package/dist/compiler.js +1 -0
- package/dist/detect-s3UM7xuN.js +17 -0
- package/dist/index.d.ts +140 -0
- package/dist/index.js +283 -0
- package/dist/module--rQ2-rvm.js +194 -0
- package/dist/ssr-register-CZ_lIN2f.js +17 -0
- package/dist/state-YxL7IqUO.js +108 -0
- package/dist/styles.d.ts +15402 -0
- package/dist/styles.js +1282 -0
- package/dist/vite.d.ts +31 -0
- package/dist/vite.js +509 -0
- package/package.json +98 -3
- package/types/jsx-runtime.d.ts +174 -0
- package/types/runes.d.ts +100 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { n as SSR_REGISTER_ID } from "./ssr-register-CZ_lIN2f.js";
|
|
2
|
+
import { n as compile } from "./compiler-BDi92tYb.js";
|
|
3
|
+
import { hash } from "node:crypto";
|
|
4
|
+
import { relative } from "node:path";
|
|
5
|
+
import { types } from "@babel/core";
|
|
6
|
+
//#region \0rolldown/runtime.js
|
|
7
|
+
var __defProp = Object.defineProperty;
|
|
8
|
+
var __exportAll = (all, no_symbols) => {
|
|
9
|
+
let target = {};
|
|
10
|
+
for (var name in all) __defProp(target, name, {
|
|
11
|
+
get: all[name],
|
|
12
|
+
enumerable: true
|
|
13
|
+
});
|
|
14
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
15
|
+
return target;
|
|
16
|
+
};
|
|
17
|
+
//#endregion
|
|
18
|
+
//#region src/vite/hmr.ts
|
|
19
|
+
/**
|
|
20
|
+
* 组件的热更新、tree-shaking 标注与 SSR 登记,取自 @vitejs/plugin-vue-jsx 5.1(MIT):
|
|
21
|
+
* - 开发时:顶层声明或导出的组件(_component / defineComponent 的结果)登记到 Vue 的热更新运行时,
|
|
22
|
+
* 文件改了只重新加载这些组件;export default 的组件先赋给变量才能登记。工厂函数做的组件
|
|
23
|
+
* (export const Toolbar = createFlex('nav'),大写开头、由调用得到)运行时确认是组件才登记(同 React Refresh 的判断)。
|
|
24
|
+
* 模块还导出了组件以外的值(函数、常量)时,改动后让导入方重新执行(invalidate),它们才拿到新值
|
|
25
|
+
* - 构建时:组件调用标为纯调用,没用到的组件能被去掉
|
|
26
|
+
* - SSR:组件登记到 ssrContext.modules,服务端据此预加载用到的模块
|
|
27
|
+
*/
|
|
28
|
+
/** 组件边界:第一个参数是 setup 函数、结果是组件的调用 */
|
|
29
|
+
const COMPONENT_FACTORIES = ["defineComponent", "_component"];
|
|
30
|
+
/**
|
|
31
|
+
* 编译的第 2 遍末尾加的 Babel 插件。
|
|
32
|
+
* 要登记组件时(热更新、SSR):`export default _component(…)` 改成先赋给 `__default__` 再导出;
|
|
33
|
+
* 否则(构建):组件调用标为纯调用
|
|
34
|
+
*/
|
|
35
|
+
function componentMarkers(register) {
|
|
36
|
+
return {
|
|
37
|
+
name: "vue-tsx-pro-components",
|
|
38
|
+
visitor: register ? { ExportDefaultDeclaration(path) {
|
|
39
|
+
const declaration = unwrapTypeAssertion(path.node.declaration);
|
|
40
|
+
if (!isComponentCall(declaration)) return;
|
|
41
|
+
const [variable] = path.replaceWithMultiple([types.variableDeclaration("const", [types.variableDeclarator(types.identifier("__default__"), types.callExpression(declaration.callee, declaration.arguments))]), types.exportDefaultDeclaration(types.identifier("__default__"))]);
|
|
42
|
+
path.scope.registerDeclaration(variable);
|
|
43
|
+
} } : { CallExpression(path) {
|
|
44
|
+
if (isComponentCall(path.node)) path.addComment("leading", "#__PURE__");
|
|
45
|
+
} }
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/** 文件顶层声明或导出的组件,以及有没有导出组件以外的值(本文件里定义的,转出别处的不算) */
|
|
49
|
+
function exportedComponents(ast, id) {
|
|
50
|
+
const declared = /* @__PURE__ */ new Map();
|
|
51
|
+
const components = [];
|
|
52
|
+
let otherExports = false;
|
|
53
|
+
const add = (local, exported, maybe) => components.push({
|
|
54
|
+
local,
|
|
55
|
+
exported,
|
|
56
|
+
id: hash("sha256", id + exported, "hex").slice(0, 8),
|
|
57
|
+
maybe
|
|
58
|
+
});
|
|
59
|
+
for (const node of ast.program.body) {
|
|
60
|
+
if (types.isVariableDeclaration(node)) for (const [name, maybe] of componentDeclarations(node)) declared.set(name, maybe);
|
|
61
|
+
if (types.isExportNamedDeclaration(node)) {
|
|
62
|
+
if (node.source) continue;
|
|
63
|
+
if (types.isVariableDeclaration(node.declaration)) {
|
|
64
|
+
const found = componentDeclarations(node.declaration);
|
|
65
|
+
for (const [name, maybe] of found) add(name, name, maybe);
|
|
66
|
+
if (found.size < node.declaration.declarations.length) otherExports = true;
|
|
67
|
+
} else if (node.declaration) otherExports = true;
|
|
68
|
+
else for (const specifier of node.specifiers) {
|
|
69
|
+
if (!types.isExportSpecifier(specifier) || !types.isIdentifier(specifier.local)) continue;
|
|
70
|
+
const maybe = declared.get(specifier.local.name);
|
|
71
|
+
if (maybe !== void 0 && types.isIdentifier(specifier.exported)) add(specifier.local.name, specifier.exported.name, maybe);
|
|
72
|
+
else otherExports = true;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (types.isExportDefaultDeclaration(node)) {
|
|
76
|
+
const maybe = types.isIdentifier(node.declaration) ? declared.get(node.declaration.name) : void 0;
|
|
77
|
+
if (maybe !== void 0) add(node.declaration.name, "default", maybe);
|
|
78
|
+
else if (isComponentCall(unwrapTypeAssertion(node.declaration))) add("__default__", "default", false);
|
|
79
|
+
else otherExports = true;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
components,
|
|
84
|
+
otherExports
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/** 运行时判断是不是组件(工厂函数的结果):有 setup 或 render 的对象 */
|
|
88
|
+
const IS_COMPONENT = "const __isComponent = (c) => !!c && typeof c === 'object' && (typeof c.setup === 'function' || typeof c.render === 'function')";
|
|
89
|
+
/**
|
|
90
|
+
* 登记到热更新运行时,文件更新时重新加载这些组件;还导出了别的值时让导入方重新执行。
|
|
91
|
+
* 有样式骨架(compiler/style-hot.ts)时:新模块的骨架没变说明只改了样式,新模块执行时已经原地改好规则,
|
|
92
|
+
* 不重新加载组件、也不让导入方重新执行
|
|
93
|
+
*/
|
|
94
|
+
function hmrCode(components, otherExports, skeleton) {
|
|
95
|
+
const records = components.map(({ local, id, maybe }) => {
|
|
96
|
+
const record = `\n${local}.__hmrId = "${id}"\n__VUE_HMR_RUNTIME__.createRecord("${id}", ${local})`;
|
|
97
|
+
return maybe ? `\nif (__isComponent(${local})) {${record}}` : record;
|
|
98
|
+
});
|
|
99
|
+
const reloads = components.map(({ exported, id, maybe }) => {
|
|
100
|
+
const reload = `\n__VUE_HMR_RUNTIME__.reload("${id}", __${exported})`;
|
|
101
|
+
return maybe ? `\nif (__isComponent(__${exported})) {${reload}} else __other = true` : reload;
|
|
102
|
+
});
|
|
103
|
+
const parameters = components.map(({ exported }) => `${exported}: __${exported}`).join(",");
|
|
104
|
+
const helper = components.some(({ maybe }) => maybe) ? `\n${IS_COMPONENT}` : "";
|
|
105
|
+
const styleOnly = skeleton ? `\nif (__mod && __mod.__styleSkeleton === ${JSON.stringify(skeleton)}) return` : "";
|
|
106
|
+
return [
|
|
107
|
+
helper,
|
|
108
|
+
...records,
|
|
109
|
+
`\nimport.meta.hot.accept((__mod) => {${styleOnly}\nconst {${parameters}} = __mod\nlet __other = ${otherExports}`,
|
|
110
|
+
...reloads,
|
|
111
|
+
"\nif (__other) import.meta.hot.invalidate('还导出了组件以外的值,导入方重新执行')\n})"
|
|
112
|
+
].join("");
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* 有顶层样式的模块导出骨架(去掉样式参数后的源码哈希);不是组件模块时再自己接住更新:
|
|
116
|
+
* 骨架没变就原地生效,变了(改了样式以外的代码)让导入方重新执行,同没有接住时一样
|
|
117
|
+
*/
|
|
118
|
+
function styleHotCode(skeleton, accepted) {
|
|
119
|
+
const value = JSON.stringify(skeleton);
|
|
120
|
+
const code = `\nexport const __styleSkeleton = ${value}`;
|
|
121
|
+
if (accepted) return code;
|
|
122
|
+
return `${code}\nimport.meta.hot.accept((__mod) => {\nif (!__mod || __mod.__styleSkeleton !== ${value}) import.meta.hot.invalidate('改了样式以外的代码,导入方重新执行')\n})`;
|
|
123
|
+
}
|
|
124
|
+
/** SSR:组件渲染时把模块路径(相对项目根目录)记进 ssrContext */
|
|
125
|
+
function ssrCode(components, id, root) {
|
|
126
|
+
const moduleId = relative(root, id).split("\\").join("/");
|
|
127
|
+
const registers = components.map(({ local, maybe }) => maybe ? `\nif (${local} && typeof ${local} === 'object' && 'setup' in ${local}) ssrRegisterHelper(${local}, __moduleId)` : `\nssrRegisterHelper(${local}, __moduleId)`);
|
|
128
|
+
return `\nimport { ssrRegisterHelper } from "${SSR_REGISTER_ID}"\nconst __moduleId = ${JSON.stringify(moduleId)}${registers.join("")}`;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* 声明里的组件:名字 → 是否只是“可能”(工厂函数的结果)。_component / defineComponent 的结果一定是;
|
|
132
|
+
* 大写开头、由别的调用得到的(createFlex('nav')、createPresetIconButton(…))运行时再确认
|
|
133
|
+
*/
|
|
134
|
+
function componentDeclarations(node) {
|
|
135
|
+
const found = /* @__PURE__ */ new Map();
|
|
136
|
+
for (const declarator of node.declarations) {
|
|
137
|
+
if (!types.isIdentifier(declarator.id)) continue;
|
|
138
|
+
const init = unwrapTypeAssertion(declarator.init);
|
|
139
|
+
if (isComponentCall(init)) found.set(declarator.id.name, false);
|
|
140
|
+
else if (/^[A-Z]/.test(declarator.id.name) && types.isCallExpression(init)) found.set(declarator.id.name, true);
|
|
141
|
+
}
|
|
142
|
+
return found;
|
|
143
|
+
}
|
|
144
|
+
function isComponentCall(node) {
|
|
145
|
+
return types.isCallExpression(node) && types.isIdentifier(node.callee) && COMPONENT_FACTORIES.includes(node.callee.name);
|
|
146
|
+
}
|
|
147
|
+
function unwrapTypeAssertion(node) {
|
|
148
|
+
let current = node;
|
|
149
|
+
while (types.isTSAsExpression(current) || types.isTSSatisfiesExpression(current) || types.isTSTypeAssertion(current)) current = current.expression;
|
|
150
|
+
return current;
|
|
151
|
+
}
|
|
152
|
+
//#endregion
|
|
153
|
+
//#region src/vite/module.ts
|
|
154
|
+
/**
|
|
155
|
+
* 编译一个模块:compile(compiler/compile.ts)加上组件的热更新、SSR 登记。
|
|
156
|
+
* 主线程(index.ts)与编译线程(compile-worker.ts)共用;设置要能在线程之间复制,所以只放数据。
|
|
157
|
+
*/
|
|
158
|
+
var module_exports = /* @__PURE__ */ __exportAll({ compileModule: () => compileModule });
|
|
159
|
+
/** 编译一个模块;什么都不用做时返回 null */
|
|
160
|
+
async function compileModule(request, setup) {
|
|
161
|
+
const { code, id, file, lang, own, ssr } = request;
|
|
162
|
+
const jsx = lang === "tsx" || lang === "jsx";
|
|
163
|
+
const styleHot = own && setup.hmr && !ssr;
|
|
164
|
+
const result = await compile(code, {
|
|
165
|
+
filename: file,
|
|
166
|
+
lang,
|
|
167
|
+
runes: own,
|
|
168
|
+
optimize: setup.optimize,
|
|
169
|
+
styleBindings: own,
|
|
170
|
+
styleHot: styleHot ? relative(setup.root, file).split("\\").join("/") : void 0,
|
|
171
|
+
jsx: setup.jsx,
|
|
172
|
+
plugins: jsx ? [() => componentMarkers(setup.hmr || ssr)] : void 0
|
|
173
|
+
});
|
|
174
|
+
if (!result) return null;
|
|
175
|
+
let output = result.code;
|
|
176
|
+
const skeleton = result.styleSkeleton;
|
|
177
|
+
let accepted = false;
|
|
178
|
+
if (jsx && (setup.hmr || ssr)) {
|
|
179
|
+
const { components, otherExports } = exportedComponents(result.ast, id);
|
|
180
|
+
if (components.length && setup.hmr && !ssr && !/\?vue&type=script/.test(id)) {
|
|
181
|
+
output += hmrCode(components, otherExports, skeleton);
|
|
182
|
+
accepted = true;
|
|
183
|
+
}
|
|
184
|
+
if (components.length && ssr) output += ssrCode(components, id, setup.root);
|
|
185
|
+
}
|
|
186
|
+
if (skeleton) output += styleHotCode(skeleton, accepted);
|
|
187
|
+
return {
|
|
188
|
+
code: output,
|
|
189
|
+
map: result.map,
|
|
190
|
+
warnings: result.warnings.map((warning) => warning.frame)
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
//#endregion
|
|
194
|
+
export { module_exports as n, compileModule as t };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/vite/ssr-register.ts
|
|
2
|
+
/** SSR 登记组件模块用的虚拟模块:id 与代码(不依赖 Babel,预设入口要用;生成登记代码见 hmr.ts 的 ssrCode) */
|
|
3
|
+
/** SSR 时登记组件模块的虚拟模块 */
|
|
4
|
+
const SSR_REGISTER_ID = "/__vue-jsx-ssr-register-helper";
|
|
5
|
+
/** SSR_REGISTER_ID 的代码:包一层 setup,渲染时把模块记进 ssrContext.modules */
|
|
6
|
+
const SSR_REGISTER_CODE = `import { useSSRContext } from "vue";
|
|
7
|
+
export function ssrRegisterHelper(comp, filename) {
|
|
8
|
+
const setup = comp.setup;
|
|
9
|
+
comp.setup = (props, ctx) => {
|
|
10
|
+
const ssrContext = useSSRContext();
|
|
11
|
+
(ssrContext.modules || (ssrContext.modules = new Set())).add(filename);
|
|
12
|
+
if (setup) return setup(props, ctx);
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
`;
|
|
16
|
+
//#endregion
|
|
17
|
+
export { SSR_REGISTER_ID as n, SSR_REGISTER_CODE as t };
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { ReactiveEffect, computed, customRef, effectScope, isRef, toRaw, watch } from "vue";
|
|
2
|
+
//#region src/runtime/state.ts
|
|
3
|
+
/**
|
|
4
|
+
* 编译产物使用的状态工具(作者不直接调用):
|
|
5
|
+
* - overridable:let 声明的 _derived、组件的普通 prop
|
|
6
|
+
* - snapshot:_state.snapshot(x)
|
|
7
|
+
* - untrack:_untrack(x)
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* 跟随来源、可以临时覆盖的值(同 Svelte 5.25 的可覆盖派生):
|
|
11
|
+
* 读取时是 getter 的结果;写入后读到写入的值,直到 getter 的结果变化,再回到跟随来源。
|
|
12
|
+
*
|
|
13
|
+
* let likes = _derived(post.likes) 乐观更新:likes += 1,post.likes 一变就以它为准
|
|
14
|
+
* ({ value }) => … value = x 普通 prop:只改组件本地,父级传入新值时以父级为准
|
|
15
|
+
*/
|
|
16
|
+
function overridable(getter) {
|
|
17
|
+
const source = computed(getter);
|
|
18
|
+
let override;
|
|
19
|
+
return customRef((track, trigger) => {
|
|
20
|
+
watch(source, () => {
|
|
21
|
+
override = void 0;
|
|
22
|
+
trigger();
|
|
23
|
+
}, { flush: "sync" });
|
|
24
|
+
return {
|
|
25
|
+
get() {
|
|
26
|
+
track();
|
|
27
|
+
const value = source.value;
|
|
28
|
+
return override ? override.value : value;
|
|
29
|
+
},
|
|
30
|
+
set(value) {
|
|
31
|
+
override = { value };
|
|
32
|
+
trigger();
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
/** untrack 共用的读取 effect(第一次用时建在独立的作用域里,不随哪个组件停掉) */
|
|
38
|
+
let reader;
|
|
39
|
+
/** 正在 untrack 里:嵌套的 untrack 直接执行(外层已经不追踪) */
|
|
40
|
+
let reading = false;
|
|
41
|
+
const noop = () => {};
|
|
42
|
+
/**
|
|
43
|
+
* 读取但不追踪(同 Svelte 的 untrack):在共用的读取 effect 里执行,读到的响应式值记在它身上、
|
|
44
|
+
* 变化时什么也不做,外层的 _effect、_derived、渲染函数不会因此依赖它们。用 Vue 公开的 ReactiveEffect,不碰内部 API。
|
|
45
|
+
* 渲染里会频繁调用(样式的响应式绑定每次渲染取一次值),所以复用同一个 effect,不每次新建作用域与 effect
|
|
46
|
+
*/
|
|
47
|
+
function untrack(read) {
|
|
48
|
+
if (reading) return read();
|
|
49
|
+
reader ??= effectScope(true).run(() => {
|
|
50
|
+
const effect = new ReactiveEffect(noop);
|
|
51
|
+
effect.scheduler = noop;
|
|
52
|
+
return effect;
|
|
53
|
+
});
|
|
54
|
+
reading = true;
|
|
55
|
+
reader.fn = read;
|
|
56
|
+
try {
|
|
57
|
+
return reader.run();
|
|
58
|
+
} finally {
|
|
59
|
+
reader.fn = noop;
|
|
60
|
+
reading = false;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* 去掉响应式代理的静态深拷贝(同 Svelte 的 $state.snapshot),交给 structuredClone、第三方库或日志。
|
|
65
|
+
* 普通对象、数组、Map、Set 逐层拷贝,Date、类型化数组、ArrayBuffer 复制一份,有 toJSON 的取它的结果,
|
|
66
|
+
* 其他值(类实例、函数等)原样保留。
|
|
67
|
+
*/
|
|
68
|
+
function snapshot(value) {
|
|
69
|
+
return clone(value, /* @__PURE__ */ new Map());
|
|
70
|
+
}
|
|
71
|
+
function clone(value, seen) {
|
|
72
|
+
const raw = toRaw(value);
|
|
73
|
+
if (isRef(raw)) return clone(raw.value, seen);
|
|
74
|
+
if (typeof raw !== "object" || raw === null) return raw;
|
|
75
|
+
if (seen.has(raw)) return seen.get(raw);
|
|
76
|
+
if (Array.isArray(raw)) {
|
|
77
|
+
const copy = [];
|
|
78
|
+
seen.set(raw, copy);
|
|
79
|
+
for (const item of raw) copy.push(clone(item, seen));
|
|
80
|
+
return copy;
|
|
81
|
+
}
|
|
82
|
+
if (raw instanceof Map) {
|
|
83
|
+
const copy = /* @__PURE__ */ new Map();
|
|
84
|
+
seen.set(raw, copy);
|
|
85
|
+
for (const [key, item] of raw) copy.set(clone(key, seen), clone(item, seen));
|
|
86
|
+
return copy;
|
|
87
|
+
}
|
|
88
|
+
if (raw instanceof Set) {
|
|
89
|
+
const copy = /* @__PURE__ */ new Set();
|
|
90
|
+
seen.set(raw, copy);
|
|
91
|
+
for (const item of raw) copy.add(clone(item, seen));
|
|
92
|
+
return copy;
|
|
93
|
+
}
|
|
94
|
+
if (raw instanceof Date) return new Date(raw);
|
|
95
|
+
if (raw instanceof ArrayBuffer) return raw.slice(0);
|
|
96
|
+
if (ArrayBuffer.isView(raw)) return raw instanceof DataView ? new DataView(raw.buffer.slice(raw.byteOffset, raw.byteOffset + raw.byteLength)) : raw.slice();
|
|
97
|
+
const prototype = Object.getPrototypeOf(raw);
|
|
98
|
+
if (prototype === Object.prototype || prototype === null) {
|
|
99
|
+
const copy = {};
|
|
100
|
+
seen.set(raw, copy);
|
|
101
|
+
for (const [key, item] of Object.entries(raw)) copy[key] = clone(item, seen);
|
|
102
|
+
return copy;
|
|
103
|
+
}
|
|
104
|
+
const json = raw.toJSON;
|
|
105
|
+
return typeof json === "function" ? clone(json.call(raw), seen) : raw;
|
|
106
|
+
}
|
|
107
|
+
//#endregion
|
|
108
|
+
export { snapshot as n, untrack as r, overridable as t };
|