Skip to content

Commit 605946d

Browse files
authored
Merge branch 'master' into perf-test-harness
2 parents 3d55e58 + 8d14f03 commit 605946d

File tree

15 files changed

+781
-195
lines changed

15 files changed

+781
-195
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

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ Here's some ergonomic features you get for free that aren't present in JSX:
4141
- **No transpiler necessary**
4242
- HTML's optional quotes: `<div class=foo>`
4343
- Component end-tags: `<${Footer}>footer content<//>`
44-
- Syntax highlighting and language support via the [lit-html VSCode extension].
44+
- Syntax highlighting and language support via the [lit-html VSCode extension] and [vim-jsx-pretty plugin].
4545

4646
## Installation
4747

@@ -219,6 +219,7 @@ As of 2.0.0, `htm` is stable, well-tested and ready for production use.
219219
[lit-html]: https://github.com/Polymer/lit-html
220220
[babel-plugin-htm]: https://github.com/developit/htm/tree/master/packages/babel-plugin-htm
221221
[lit-html VSCode extension]: https://marketplace.visualstudio.com/items?itemName=bierner.lit-html
222+
[vim-jsx-pretty plugin]: https://github.com/MaxMEllon/vim-jsx-pretty
222223
[vhtml]: https://github.com/developit/vhtml
223224
[jsxobj]: https://github.com/developit/jsxobj
224225
[hyperscript]: https://github.com/hyperhype/hyperscript

babel.config.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module.exports = {
2+
presets: [
3+
[
4+
'@babel/preset-env',
5+
{
6+
targets: {
7+
node: 'current'
8+
}
9+
}
10+
]
11+
]
12+
};

package.json

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,29 @@
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",
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",
14+
"build:babel-transform-jsx": "cd packages/babel-plugin-transform-jsx-to-htm && npm run build",
1315
"test": "eslint src/**/*.mjs test/**/*.mjs && npm run build && jest test",
1416
"test:perf": "v8 test/__perftest.mjs",
1517
"release": "npm t && git commit -am \"$npm_package_version\" && git tag $npm_package_version && git push && git push --tags && npm publish"
1618
},
1719
"files": [
1820
"dist",
21+
"mini",
1922
"preact",
2023
"src"
2124
],
2225
"eslintConfig": {
2326
"extends": "developit",
2427
"rules": {
2528
"prefer-const": 0,
26-
"no-fallthrough": 0
29+
"prefer-spread": 0,
30+
"prefer-rest-params": 0,
31+
"func-style": 0
2732
}
2833
},
2934
"jest": {
@@ -40,16 +45,12 @@
4045
"js"
4146
],
4247
"moduleNameMapper": {
48+
"^babel-plugin-transform-jsx-to-htm$": "<rootDir>/packages/babel-plugin-transform-jsx-to-htm/index.mjs",
4349
"^babel-plugin-htm$": "<rootDir>/packages/babel-plugin-htm/index.mjs",
4450
"^htm$": "<rootDir>/src/index.mjs",
4551
"^htm/preact$": "<rootDir>/src/integrations/preact/index.mjs"
4652
}
4753
},
48-
"babel": {
49-
"presets": [
50-
"env"
51-
]
52-
},
5354
"repository": "developit/htm",
5455
"keywords": [
5556
"Hyperscript Tagged Markup",
@@ -67,13 +68,16 @@
6768
"devDependencies": {
6869
"@babel/core": "^7.2.2",
6970
"@babel/preset-env": "^7.1.6",
70-
"babel-jest": "^23.6.0",
71+
"babel-jest": "^24.1.0",
7172
"babel-preset-env": "^1.7.0",
7273
"eslint": "^5.2.0",
7374
"eslint-config-developit": "^1.1.1",
74-
"jest": "^23.4.2",
75-
"microbundle": "^0.8.3",
76-
"preact": "^8.2.9"
75+
"jest": "^24.1.0",
76+
"microbundle": "^0.10.1",
77+
"preact": "^8.4.2"
7778
},
78-
"dependencies": {}
79+
"dependencies": {},
80+
"peerDependencies": {
81+
"preact": "*"
82+
}
7983
}

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
}

packages/babel-plugin-htm/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,6 @@
3232
"htm": "^2.0.0"
3333
},
3434
"devDependencies": {
35-
"microbundle": "^0.8.3"
35+
"microbundle": "^0.10.1"
3636
}
3737
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# babel-plugin-transform-jsx-to-htm
2+
3+
This plugin converts JSX into Tagged Templates that work with [htm].
4+
5+
```js
6+
// INPUT:
7+
const Foo = () => <h1>Hello</h1>
8+
9+
// OUTPUT:
10+
const Foo = () => html`<h1>Hello</h1>`
11+
```
12+
13+
## Installation
14+
15+
Grab it from npm:
16+
17+
```sh
18+
npm i -D babel-plugin-transform-jsx-to-htm
19+
```
20+
21+
... then add it to your Babel config (eg: `.babelrc`):
22+
23+
```js
24+
"plugins": [
25+
"babel-plugin-transform-jsx-to-htm"
26+
]
27+
```
28+
29+
## Options
30+
31+
The following options are available:
32+
33+
| Option | Type | Default | Description
34+
|--------|---------|----------|------------
35+
| `tag` | String | `"html"` | The "tag" function to prefix [Tagged Templates] with.
36+
| `import` | `false`\|String\|Object | `false` | Auto-import a tag function, off by default.<br>_See [Auto-importing a tag function](#auto-importing-the-tag) for an example._
37+
38+
Options are passed to a Babel plugin using a nested Array:
39+
40+
```js
41+
"plugins": [
42+
["babel-plugin-transform-jsx-to-htm", {
43+
"tag": "$$html"
44+
}]
45+
]
46+
```
47+
48+
## Auto-importing the tag
49+
50+
Want to automatically import `html` into any file that uses JSX?
51+
Just use the `import` option:
52+
53+
```js
54+
"plugins": [
55+
["babel-plugin-transform-jsx-to-htm", {
56+
"tag": "$$html",
57+
"import": {
58+
// the module to import:
59+
"module": "htm/preact",
60+
// a named export to use from that module:
61+
"export": "html"
62+
}
63+
}]
64+
]
65+
```
66+
67+
The above will produce files that look like:
68+
69+
```js
70+
import { html as $$html } from 'htm/preact';
71+
72+
export default $$html`<h1>hello</h1>`
73+
```
74+
75+
### License
76+
77+
Apache 2
78+
79+
[htm]: https://github.com/developit/htm

0 commit comments

Comments
 (0)