Skip to content

Commit 88aea39

Browse files
authored
feat: add generator (#9)
* chore: inline generator * chore: remove inline * chore: remove bindingMetadata * chore: fix sourcemap * chore: remove prefixIdentifiers * refactor: optimize bundle size
1 parent 72e94d9 commit 88aea39

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+2536
-381
lines changed

docs/introduction/getting-started.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ We assume you are already familiar with the basic usages of Vue before you conti
2525
pnpm add vue-jsx-vapor
2626

2727
# runtime
28-
pnpm add https://pkg.pr.new/vue@715b798
28+
pnpm add https://pkg.pr.new/vue@51677cd
2929
```
3030

3131
The Vue Vapor runtime is not release, so we use [pkg.pr.new](https://github.com/stackblitz-labs/pkg.pr.new) to install.

packages/babel/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
"@babel/traverse": "catalog:",
4747
"@babel/types": "catalog:",
4848
"@vue-jsx-vapor/compiler": "workspace:*",
49-
"source-map-js": "^1.2.1"
49+
"source-map-js": "catalog:"
5050
},
5151
"devDependencies": {
5252
"@types/babel__core": "catalog:",

packages/babel/src/index.ts

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ export type Options = {
1414
filename: string
1515
importSet: Set<string>
1616
delegateEventSet: Set<string>
17-
preambleMap: Map<string, string>
18-
preambleIndex: number
17+
templates: string[]
1918
file: BabelFile
2019
roots: {
2120
node: JSXElement | JSXFragment
@@ -43,8 +42,7 @@ export default (): {
4342
enter: (path, state) => {
4443
state.importSet = new Set<string>()
4544
state.delegateEventSet = new Set<string>()
46-
state.preambleMap = new Map<string, string>()
47-
state.preambleIndex = 0
45+
state.templates = []
4846
state.roots = []
4947
const collectRoot: VisitNodeFunction<
5048
Node,
@@ -78,20 +76,24 @@ export default (): {
7876
})
7977
},
8078
exit: (path, state) => {
81-
const { delegateEventSet, importSet, preambleMap } = state
79+
const { delegateEventSet, importSet, templates } = state
8280

8381
const statements: string[] = []
8482
if (delegateEventSet.size) {
8583
statements.unshift(
86-
`_delegateEvents(${Array.from(delegateEventSet).join(', ')});`,
84+
`_delegateEvents("${Array.from(delegateEventSet).join('", "')}");`,
8785
)
8886
}
8987

90-
if (preambleMap.size) {
91-
let preambleResult = ''
92-
for (const [value, key] of preambleMap) {
93-
preambleResult += `const ${key} = ${value}\n`
94-
}
88+
if (templates.length) {
89+
let preambleResult = 'const '
90+
const definedTemplates: Record<string, string> = {}
91+
templates.forEach((template, index) => {
92+
preambleResult += `t${index} = ${
93+
definedTemplates[template] || template
94+
}${templates.length - 1 === index ? ';' : ','}\n`
95+
definedTemplates[template] = `t${index}`
96+
})
9597
statements.unshift(preambleResult)
9698
}
9799

packages/babel/src/transform.ts

Lines changed: 4 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -19,37 +19,18 @@ export const transformJSX: VisitNodeFunction<
1919
if (!root || !root.inVaporComponent) return
2020

2121
const isTS = state.filename?.endsWith('tsx')
22-
let { code, helpers, preamble, map } = compile(root.node, {
22+
const { code, map, helpers, templates, delegates } = compile(root.node, {
2323
isTS,
2424
filename: state.filename,
2525
sourceMap: !!state.file.opts.sourceMaps,
2626
source: ' '.repeat(root.node.start || 0) + root.source,
27+
templates: state.templates.slice(),
2728
...state.opts.compile,
2829
})
2930

3031
helpers.forEach((helper) => state.importSet.add(helper))
31-
32-
preamble = preamble.replaceAll(
33-
/(?<=const )t(?=(\d))/g,
34-
`_t${state.preambleIndex}`,
35-
)
36-
code = code.replaceAll(/(?<== )t(?=\d)/g, `_t${state.preambleIndex}`)
37-
state.preambleIndex++
38-
39-
for (const [, key, value] of preamble.matchAll(
40-
/const (_t\d+) = (_template\(.*\))/g,
41-
)) {
42-
const result = state.preambleMap.get(value)
43-
if (result) {
44-
code = code.replaceAll(key, result)
45-
} else {
46-
state.preambleMap.set(value, key)
47-
}
48-
}
49-
50-
for (const [, events] of preamble.matchAll(/_delegateEvents\((.*)\)/g)) {
51-
events.split(', ').forEach((event) => state.delegateEventSet.add(event))
52-
}
32+
delegates.forEach((delegate) => state.delegateEventSet.add(delegate))
33+
state.templates.push(...templates.slice(state.templates.length))
5334

5435
const ast = parse(`(() => {${code}})()`, {
5536
sourceFilename: state.filename,
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2+
3+
exports[`transform > transform multiple components 1`] = `
4+
"import { template as _template } from 'vue';
5+
const t0 = _template("<div></div>", true),
6+
t1 = t0,
7+
t2 = t1;
8+
const A = defineComponent(() => {
9+
defineVaporComponent(() => (() => {
10+
const n0 = t0();
11+
return n0;
12+
})());
13+
return () => <div />;
14+
});
15+
const B = defineVaporComponent(() => {
16+
const C = defineComponent(() => <div />);
17+
const D = (() => {
18+
const n0 = t1();
19+
return n0;
20+
})();
21+
return (() => {
22+
const n0 = t2();
23+
return n0;
24+
})();
25+
});"
26+
`;
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2+
3+
exports[`transform > transform multiple components 1`] = `
4+
"import { child as _child, delegateEvents as _delegateEvents, template as _template, createIf as _createIf } from 'vue';
5+
import { setNodes as _setNodes } from 'vue-jsx-vapor/runtime';
6+
const t0 = _template("<div> </div>", true),
7+
t1 = _template("<div>Hello</div>"),
8+
t2 = _template("<div>World</div>");
9+
_delegateEvents("click", "dblclick");
10+
const a = (() => {
11+
const n0 = t0();
12+
const x0 = _child(n0);
13+
_setNodes(x0, () => Hello);
14+
n0.$evtclick = e => onClick(e);
15+
return n0;
16+
})();
17+
const b = (() => {
18+
const n0 = _createIf(() => foo, () => {
19+
const n2 = t1();
20+
n2.$evtclick = e => onClick(e);
21+
return n2;
22+
}, () => {
23+
const n4 = t2();
24+
n4.$evtdblclick = e => onDblclick(e);
25+
return n4;
26+
});
27+
return n0;
28+
})();"
29+
`;

packages/babel/test/interop.spec.ts

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,27 +19,6 @@ describe('transform', () => {
1919
plugins: [[jsx, { interop: true }]],
2020
},
2121
)!
22-
expect(code).toMatchInlineSnapshot(`
23-
"import { template as _template } from 'vue';
24-
const _t00 = _template("<div></div>", true);
25-
const A = defineComponent(() => {
26-
defineVaporComponent(() => (() => {
27-
const n0 = _t00();
28-
return n0;
29-
})());
30-
return () => <div />;
31-
});
32-
const B = defineVaporComponent(() => {
33-
const C = defineComponent(() => <div />);
34-
const D = (() => {
35-
const n0 = _t00();
36-
return n0;
37-
})();
38-
return (() => {
39-
const n0 = _t00();
40-
return n0;
41-
})();
42-
});"
43-
`)
22+
expect(code).matchSnapshot()
4423
})
4524
})

packages/babel/test/transform.spec.ts

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -12,32 +12,6 @@ describe('transform', () => {
1212
plugins: [[jsx]],
1313
},
1414
)!
15-
expect(code).toMatchInlineSnapshot(`
16-
"import { child as _child, delegateEvents as _delegateEvents, template as _template, createIf as _createIf } from 'vue';
17-
import { setNodes as _setNodes } from 'vue-jsx-vapor/runtime';
18-
const _t00 = _template("<div> </div>", true);
19-
const _t10 = _template("<div>Hello</div>");
20-
const _t11 = _template("<div>World</div>");
21-
_delegateEvents("click", "dblclick");
22-
const a = (() => {
23-
const n0 = _t00();
24-
const x0 = _child(n0);
25-
_setNodes(x0, () => Hello);
26-
n0.$evtclick = e => onClick(e);
27-
return n0;
28-
})();
29-
const b = (() => {
30-
const n0 = _createIf(() => foo, () => {
31-
const n2 = _t10();
32-
n2.$evtclick = e => onClick(e);
33-
return n2;
34-
}, () => {
35-
const n4 = _t11();
36-
n4.$evtdblclick = e => onDblclick(e);
37-
return n4;
38-
});
39-
return n0;
40-
})();"
41-
`)
15+
expect(code).matchSnapshot()
4216
})
4317
})

packages/compiler/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@
4343
"@babel/parser": "catalog:",
4444
"@babel/types": "catalog:",
4545
"@vue/compiler-dom": "catalog:",
46-
"@vue/compiler-vapor": "catalog:",
47-
"@vue/shared": "catalog:"
46+
"@vue/shared": "catalog:",
47+
"ast-kit": "^2.1.1",
48+
"source-map-js": "catalog:"
4849
}
4950
}

packages/compiler/src/compile.ts

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,7 @@
11
import { parse } from '@babel/parser'
2-
import {
3-
generate,
4-
type VaporCodegenResult as BaseVaporCodegenResult,
5-
} from '@vue/compiler-vapor'
62
import { extend, isString } from '@vue/shared'
7-
import { customGenOperation } from './generate'
8-
9-
import {
10-
IRNodeTypes,
11-
type HackOptions,
12-
type RootIRNode,
13-
type RootNode,
14-
} from './ir'
3+
import { generate, type VaporCodegenResult } from './generate'
4+
import { IRNodeTypes, type HackOptions, type RootNode } from './ir'
155
import {
166
transform,
177
type DirectiveTransform,
@@ -35,22 +25,12 @@ import { transformVText } from './transforms/vText'
3525
import type { ExpressionStatement, JSXElement, JSXFragment } from '@babel/types'
3626
import type { CompilerOptions as BaseCompilerOptions } from '@vue/compiler-dom'
3727

38-
export { generate }
39-
40-
export interface VaporCodegenResult
41-
extends Omit<BaseVaporCodegenResult, 'ast'> {
42-
ast: RootIRNode
43-
customHelpers: Set<string>
44-
}
45-
4628
// code/AST -> IR (transform) -> JS (generate)
4729
export function compile(
4830
source: JSXElement | JSXFragment | string,
4931
options: CompilerOptions = {},
5032
): VaporCodegenResult {
5133
const resolvedOptions = extend({}, options, {
52-
inline: true,
53-
prefixIdentifiers: false,
5434
expressionPlugins: options.expressionPlugins || ['jsx'],
5535
})
5636
if (!resolvedOptions.source && isString(source)) {
@@ -101,14 +81,12 @@ export function compile(
10181
}),
10282
)
10383

104-
return generate(ir as any, {
105-
...resolvedOptions,
106-
customGenOperation,
107-
}) as unknown as VaporCodegenResult
84+
return generate(ir, resolvedOptions)
10885
}
10986

11087
export type CompilerOptions = HackOptions<BaseCompilerOptions> & {
11188
source?: string
89+
templates?: string[]
11290
}
11391
export type TransformPreset = [
11492
NodeTransform[],

0 commit comments

Comments
 (0)