Skip to content

Commit 8d14f03

Browse files
authored
Merge pull request #62 from jviide/megamix
Implement HTM without eval, with optional mini version
2 parents 8f8a3a7 + 10edc74 commit 8d14f03

File tree

7 files changed

+223
-152
lines changed

7 files changed

+223
-152
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ node_modules
22
package-lock.json
33
/preact
44
dist
5+
mini
56
yarn.lock

package.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@
66
"umd:main": "dist/htm.umd.js",
77
"module": "dist/htm.mjs",
88
"scripts": {
9-
"build": "npm run -s build:main && npm run -s build:preact && npm run -s build:babel && npm run -s build:babel-transform-jsx",
9+
"build": "npm run -s build:main && npm run -s build:mini && npm run -s build:preact && npm run -s build:babel && npm run -s build:babel-transform-jsx",
1010
"build:main": "microbundle src/index.mjs -f es,umd --no-sourcemap --target web && microbundle src/cjs.mjs -f iife --no-sourcemap --target web",
11+
"build:mini": "microbundle src/index.mjs -o ./mini/index.js -f es,umd --no-sourcemap --target web --alias ./constants=./constants-mini && microbundle src/cjs.mjs -o ./mini/index.js -f iife --no-sourcemap --target web --alias ./constants=./constants-mini",
1112
"build:preact": "cd src/integrations/preact && npm run build",
1213
"build:babel": "cd packages/babel-plugin-htm && npm run build",
1314
"build:babel-transform-jsx": "cd packages/babel-plugin-transform-jsx-to-htm && npm run build",
@@ -16,14 +17,17 @@
1617
},
1718
"files": [
1819
"dist",
20+
"mini",
1921
"preact",
2022
"src"
2123
],
2224
"eslintConfig": {
2325
"extends": "developit",
2426
"rules": {
2527
"prefer-const": 0,
26-
"no-fallthrough": 0
28+
"prefer-spread": 0,
29+
"prefer-rest-params": 0,
30+
"func-style": 0
2731
}
2832
},
2933
"jest": {

packages/babel-plugin-htm/index.mjs

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ export default function htmBabelPlugin({ types: t }, options = {}) {
1414
const useBuiltIns = options.useBuiltIns;
1515
const inlineVNodes = options.monomorphic || pragma===false;
1616

17+
const symbol = Symbol();
18+
1719
function dottedIdentifier(keypath) {
1820
const path = keypath.split('.');
1921
let out;
@@ -73,7 +75,26 @@ export default function htmBabelPlugin({ types: t }, options = {}) {
7375
return t.callExpression(pragma, [tag, props].concat(children));
7476
}
7577

78+
function flatten(props, result = []) {
79+
const { [symbol]: head, ...tail } = props;
80+
if (head) head.forEach(obj => {
81+
flatten(obj, result);
82+
});
83+
if (Object.keys(tail).length > 0) {
84+
result.push(tail);
85+
}
86+
return result;
87+
}
88+
7689
function spreadNode(args, state) {
90+
if (args.length > 0 && t.isNode(args[0])) {
91+
args.unshift({});
92+
}
93+
94+
// 'Object.assign(x)', can be collapsed to 'x'.
95+
if (args.length === 1) {
96+
return propsNode(args[0]);
97+
}
7798
// 'Object.assign({}, x)', can be collapsed to 'x'.
7899
if (args.length === 2 && !t.isNode(args[0]) && Object.keys(args[0]).length === 0) {
79100
return propsNode(args[1]);
@@ -83,8 +104,6 @@ export default function htmBabelPlugin({ types: t }, options = {}) {
83104
}
84105

85106
function propsNode(props) {
86-
if (props == null) return t.nullLiteral();
87-
88107
return t.isNode(props) ? props : t.objectExpression(
89108
Object.keys(props).map(key => {
90109
let value = props[key];
@@ -111,7 +130,7 @@ export default function htmBabelPlugin({ types: t }, options = {}) {
111130
return t.isNode(child) ? child : transform(child, state);
112131
}
113132
const newTag = typeof tag === 'string' ? t.stringLiteral(tag) : tag;
114-
const newProps = !Array.isArray(props) ? propsNode(props) : spreadNode(props, state);
133+
const newProps = props ? spreadNode(flatten(props), state) : t.nullLiteral();
115134
const newChildren = t.arrayExpression(children.map(childMapper));
116135
return createVNode(newTag, newProps, newChildren);
117136
}
@@ -125,7 +144,7 @@ export default function htmBabelPlugin({ types: t }, options = {}) {
125144
function treeify(statics, expr) {
126145
const assign = Object.assign;
127146
try {
128-
Object.assign = function(...objs) { return objs; };
147+
Object.assign = function(...objs) { return { [symbol]: objs }; };
129148
return html(statics, ...expr);
130149
}
131150
finally {
@@ -147,7 +166,10 @@ export default function htmBabelPlugin({ types: t }, options = {}) {
147166
const expr = path.node.quasi.expressions;
148167

149168
const tree = treeify(statics, expr);
150-
path.replaceWith(transform(tree, state));
169+
const node = !Array.isArray(tree)
170+
? transform(tree, state)
171+
: t.arrayExpression(tree.map(root => transform(root, state)));
172+
path.replaceWith(node);
151173
}
152174
}
153175
}

src/constants-mini.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const MINI = true;

src/constants.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const MINI = false;

0 commit comments

Comments
 (0)