Support children inside of components (#72)

* chore(examples): add kitchen-sink

* feat: support children in rendered components

* feat: add support for rendering children in Svelte

* fix: cleanup p/react fragment children

* chore: add @ts-nocheck to svelte files

* chore: update lockfiles

* fix: types

* feat: memoize frontend/renderer/utils

* fix: disable eslint for compiled SvelteWrapper

* fix: add missing dep

Co-authored-by: Nate Moore <nate@skypack.dev>
This commit is contained in:
Nate Moore 2021-04-15 10:55:50 -05:00 committed by GitHub
parent ea33d7b2ab
commit 22ca9e0aac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 6444 additions and 286 deletions

View file

@ -0,0 +1,6 @@
export default {
extensions: {
'.jsx': 'react',
'.tsx': 'preact',
}
};

View file

@ -0,0 +1,20 @@
import { h, Fragment } from 'preact';
import { useState } from 'preact/hooks';
/** a counter written in Preact */
export default function PreactCounter({ children }) {
const [count, setCount] = useState(0)
const add = () => setCount(i => i + 1);
const subtract = () => setCount(i => i - 1);
return <>
<div className="counter">
<button onClick={subtract}>-</button>
<pre>{count}</pre>
<button onClick={add}>+</button>
</div>
<div className="children">
{children}
</div>
</>
}

View file

@ -0,0 +1,19 @@
import React, { useState } from 'react';
/** a counter written in React */
export default function ReactCounter({ children }) {
const [count, setCount] = useState(0)
const add = () => setCount(i => i + 1);
const subtract = () => setCount(i => i - 1);
return <>
<div className="counter">
<button onClick={subtract}>-</button>
<pre>{count}</pre>
<button onClick={add}>+</button>
</div>
<div className="children">
{children}
</div>
</>
}

View file

@ -0,0 +1,22 @@
<script>
let children;
let count = 0;
function add() {
count += 1;
}
function subtract() {
count -= 1;
}
</script>
<div class="counter">
<button on:click={subtract}>-</button>
<pre>{ count }</pre>
<button on:click={add}>+</button>
</div>
<div class="children">
<slot />
</div>

View file

@ -0,0 +1,27 @@
<template>
<div class="counter">
<button @click="subtract()">-</button>
<pre>{{ count }}</pre>
<button @click="add()">+</button>
</div>
<div class="children">
<slot />
</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const count = ref(0)
const add = () => count.value = count.value + 1;
const subtract = () => count.value = count.value - 1;
return {
count,
add,
subtract
}
}
}
</script>

View file

@ -0,0 +1,51 @@
---
import ReactCounter from '../components/ReactCounter.jsx';
import PreactCounter from '../components/PreactCounter.tsx';
import VueCounter from '../components/VueCounter.vue';
import SvelteCounter from '../components/SvelteCounter.svelte';
---
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<style>
:global(:root) {
font-family: system-ui;
padding: 2em 0;
}
:global(.counter) {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
place-items: center;
font-size: 2em;
margin-top: 2em;
}
:global(.children) {
display: grid;
place-items: center;
margin-bottom: 2em;
}
</style>
</head>
<body>
<main>
<ReactCounter:load>
<h1>Hello React!</h1>
<p>What's up?</p>
</ReactCounter:load>
<PreactCounter:load>
<h1>Hello Preact!</h1>
</PreactCounter:load>
<VueCounter:load>
<h1>Hello Vue!</h1>
</VueCounter:load>
<SvelteCounter:load>
<h1>Hello Svelte!</h1>
</SvelteCounter:load>
</main>
</body>
</html>

5408
examples/kitchen-sink/package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,14 @@
{
"name": "kitchen-sink",
"private": true,
"version": "1.0.0",
"scripts": {
"start": "nodemon -w ../../lib -x 'astro dev .'",
"build": "astro build"
},
"dependencies": {},
"devDependencies": {
"astro": "file:../../",
"nodemon": "^2.0.7"
}
}

File diff suppressed because it is too large Load diff

230
package-lock.json generated
View file

@ -295,6 +295,14 @@
"integrity": "sha512-J/rMZa7RqiH/rT29TEVZO4nBoDP9XJOjnbbIofg7GQKs4JIduEO3WLpte+6WeUz/TcrXKlY+bM7FYrp8yFB+3g==",
"dev": true
},
"@types/hast": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.1.tgz",
"integrity": "sha512-viwwrB+6xGzw+G1eWpF9geV3fnsDgXqHG+cqgiHrvQfDUW5hzhCyV7Sy3UJxhfRFBsgky2SSW33qi/YrIkjX5Q==",
"requires": {
"@types/unist": "*"
}
},
"@types/json-schema": {
"version": "7.0.7",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz",
@ -312,6 +320,11 @@
"integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==",
"dev": true
},
"@types/parse5": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-5.0.3.tgz",
"integrity": "sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw=="
},
"@types/prop-types": {
"version": "15.7.3",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz",
@ -532,32 +545,6 @@
"source-map": "^0.6.1"
},
"dependencies": {
"@vue/compiler-core": {
"version": "3.0.11",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.0.11.tgz",
"integrity": "sha512-6sFj6TBac1y2cWCvYCA8YzHJEbsVkX7zdRs/3yK/n1ilvRqcn983XvpBbnN3v4mZ1UiQycTvOiajJmOgN9EVgw==",
"requires": {
"@babel/parser": "^7.12.0",
"@babel/types": "^7.12.0",
"@vue/shared": "3.0.11",
"estree-walker": "^2.0.1",
"source-map": "^0.6.1"
}
},
"@vue/compiler-dom": {
"version": "3.0.11",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.0.11.tgz",
"integrity": "sha512-+3xB50uGeY5Fv9eMKVJs2WSRULfgwaTJsy23OIltKgMrynnIj8hTYY2UL97HCoz78aDw1VDXdrBQ4qepWjnQcw==",
"requires": {
"@vue/compiler-core": "3.0.11",
"@vue/shared": "3.0.11"
}
},
"@vue/shared": {
"version": "3.0.11",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.0.11.tgz",
"integrity": "sha512-b+zB8A2so8eCE0JsxjL24J7vdGl8rzPQ09hZNhystm+KqSbKcAej1A+Hbva1rCMmTTqA+hFnUSDc5kouEo0JzA=="
},
"estree-walker": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
@ -741,6 +728,11 @@
"postcss-value-parser": "^4.1.0"
}
},
"bail": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz",
"integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ=="
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
@ -946,6 +938,11 @@
"resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz",
"integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w=="
},
"comma-separated-tokens": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz",
"integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw=="
},
"commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
@ -1505,6 +1502,11 @@
}
}
},
"extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
},
"extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
@ -1525,6 +1527,11 @@
"integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==",
"dev": true
},
"fast-equals": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-2.0.0.tgz",
"integrity": "sha512-u6RBd8cSiLLxAiC04wVsLV6GBFDOXcTCgWkd3wEoFXgidPSoAJENqC9m7Jb2vewSvjBIfXV6icKeh3GTKfIaXA=="
},
"fast-glob": {
"version": "3.2.5",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz",
@ -1703,6 +1710,11 @@
}
}
},
"globalyzer": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz",
"integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q=="
},
"globby": {
"version": "11.0.2",
"resolved": "https://registry.npmjs.org/globby/-/globby-11.0.2.tgz",
@ -1717,6 +1729,11 @@
"slash": "^3.0.0"
}
},
"globrex": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz",
"integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg=="
},
"good-listener": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz",
@ -1755,6 +1772,50 @@
"resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-2.0.0.tgz",
"integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg=="
},
"hast-to-hyperscript": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/hast-to-hyperscript/-/hast-to-hyperscript-9.0.1.tgz",
"integrity": "sha512-zQgLKqF+O2F72S1aa4y2ivxzSlko3MAvxkwG8ehGmNiqd98BIN3JM1rAJPmplEyLmGLO2QZYJtIneOSZ2YbJuA==",
"requires": {
"@types/unist": "^2.0.3",
"comma-separated-tokens": "^1.0.0",
"property-information": "^5.3.0",
"space-separated-tokens": "^1.0.0",
"style-to-object": "^0.3.0",
"unist-util-is": "^4.0.0",
"web-namespaces": "^1.0.0"
}
},
"hast-util-from-parse5": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-6.0.1.tgz",
"integrity": "sha512-jeJUWiN5pSxW12Rh01smtVkZgZr33wBokLzKLwinYOUfSzm1Nl/c3GUGebDyOKjdsRgMvoVbV0VpAcpjF4NrJA==",
"requires": {
"@types/parse5": "^5.0.0",
"hastscript": "^6.0.0",
"property-information": "^5.0.0",
"vfile": "^4.0.0",
"vfile-location": "^3.2.0",
"web-namespaces": "^1.0.0"
}
},
"hast-util-parse-selector": {
"version": "2.2.5",
"resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz",
"integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ=="
},
"hastscript": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz",
"integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==",
"requires": {
"@types/hast": "^2.0.0",
"comma-separated-tokens": "^1.0.0",
"hast-util-parse-selector": "^2.0.0",
"property-information": "^5.0.0",
"space-separated-tokens": "^1.0.0"
}
},
"hosted-git-info": {
"version": "2.8.8",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz",
@ -1862,6 +1923,11 @@
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
},
"inline-style-parser": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz",
"integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q=="
},
"is-alphabetical": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz",
@ -1890,6 +1956,11 @@
"binary-extensions": "^2.0.0"
}
},
"is-buffer": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz",
"integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ=="
},
"is-core-module": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz",
@ -1942,6 +2013,11 @@
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
},
"is-plain-obj": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
"integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA=="
},
"is-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz",
@ -2133,6 +2209,11 @@
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
"dev": true
},
"micro-memoize": {
"version": "4.0.9",
"resolved": "https://registry.npmjs.org/micro-memoize/-/micro-memoize-4.0.9.tgz",
"integrity": "sha512-Z2uZi/IUMGQDCXASdujXRqrXXEwSY0XffUrAOllhqzQI3wpUyZbiZTiE2JuYC0HSG2G7DbCS5jZmsEKEGZuemg=="
},
"micromark": {
"version": "2.11.4",
"resolved": "https://registry.npmjs.org/micromark/-/micromark-2.11.4.tgz",
@ -2246,6 +2327,15 @@
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
},
"moize": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/moize/-/moize-6.0.1.tgz",
"integrity": "sha512-Bl91P98A6Xba35mn9XoAW9DuGoQb3HyoY888TxrvQbMr9+1v3dzBzi9n4Guh5Lne8ENdqbXjQ0a8mf7UUvZ9wg==",
"requires": {
"fast-equals": "2.0.0",
"micro-memoize": "4.0.9"
}
},
"mri": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/mri/-/mri-1.1.6.tgz",
@ -2657,6 +2747,14 @@
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
"dev": true
},
"property-information": {
"version": "5.6.0",
"resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz",
"integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==",
"requires": {
"xtend": "^4.0.0"
}
},
"punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
@ -2730,6 +2828,15 @@
"integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==",
"dev": true
},
"rehype-parse": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-7.0.1.tgz",
"integrity": "sha512-fOiR9a9xH+Le19i4fGzIEowAbwG7idy2Jzs4mOrFWBSJ0sNUgy0ev871dwWnbOo371SjgjG4pwzrbgSVrKxecw==",
"requires": {
"hast-util-from-parse5": "^6.0.0",
"parse5": "^6.0.0"
}
},
"require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
@ -2975,6 +3082,11 @@
"resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
"integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA=="
},
"space-separated-tokens": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz",
"integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA=="
},
"spawn-command": {
"version": "0.0.2-1",
"resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz",
@ -3069,6 +3181,14 @@
"min-indent": "^1.0.0"
}
},
"style-to-object": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz",
"integrity": "sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==",
"requires": {
"inline-style-parser": "0.1.1"
}
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
@ -3159,6 +3279,15 @@
"integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==",
"optional": true
},
"tiny-glob": {
"version": "0.2.8",
"resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.8.tgz",
"integrity": "sha512-vkQP7qOslq63XRX9kMswlby99kyO5OvKptw7AMwBVMjXEI7Tb61eoI5DydyEMOseyGS5anDN1VPoVxEvH01q8w==",
"requires": {
"globalyzer": "0.1.0",
"globrex": "^0.1.2"
}
},
"to-fast-properties": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
@ -3184,6 +3313,11 @@
"integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
"dev": true
},
"trough": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz",
"integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA=="
},
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
@ -3220,11 +3354,29 @@
"integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==",
"dev": true
},
"unified": {
"version": "9.2.1",
"resolved": "https://registry.npmjs.org/unified/-/unified-9.2.1.tgz",
"integrity": "sha512-juWjuI8Z4xFg8pJbnEZ41b5xjGUWGHqXALmBZ3FC3WX0PIx1CZBIIJ6mXbYMcf6Yw4Fi0rFUTA1cdz/BglbOhA==",
"requires": {
"bail": "^1.0.0",
"extend": "^3.0.0",
"is-buffer": "^2.0.0",
"is-plain-obj": "^2.0.0",
"trough": "^1.0.0",
"vfile": "^4.0.0"
}
},
"uniq": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz",
"integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8="
},
"unist-util-is": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz",
"integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg=="
},
"unist-util-stringify-position": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz",
@ -3276,6 +3428,22 @@
"spdx-expression-parse": "^3.0.0"
}
},
"vfile": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz",
"integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==",
"requires": {
"@types/unist": "^2.0.0",
"is-buffer": "^2.0.0",
"unist-util-stringify-position": "^2.0.0",
"vfile-message": "^2.0.0"
}
},
"vfile-location": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-3.2.0.tgz",
"integrity": "sha512-aLEIZKv/oxuCDZ8lkJGhuhztf/BW4M+iHdCwglA/eWc+vtuRFJj8EtgceYFX4LRjOhCAAiNHsKGssC6onJ+jbA=="
},
"vfile-message": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz",
@ -3295,6 +3463,11 @@
"@vue/shared": "3.0.11"
}
},
"web-namespaces": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-1.1.4.tgz",
"integrity": "sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw=="
},
"which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@ -3343,6 +3516,11 @@
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true
},
"xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
},
"y18n": {
"version": "5.0.5",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz",

View file

@ -35,7 +35,7 @@
"@snowpack/plugin-sass": "^1.4.0",
"@snowpack/plugin-svelte": "^3.6.0",
"@snowpack/plugin-vue": "^2.4.0",
"@vue/server-renderer": "^3.0.11",
"@vue/server-renderer": "^3.0.10",
"acorn": "^7.4.0",
"autoprefixer": "^10.2.5",
"cheerio": "^1.0.0-rc.5",
@ -46,6 +46,7 @@
"find-up": "^5.0.0",
"github-slugger": "^1.3.0",
"gray-matter": "^4.0.2",
"hast-to-hyperscript": "^9.0.1",
"kleur": "^4.1.4",
"locate-character": "^2.0.5",
"magic-string": "^0.25.3",
@ -53,6 +54,7 @@
"micromark-extension-gfm": "^0.3.3",
"micromark-extension-mdx-expression": "^0.3.2",
"micromark-extension-mdx-jsx": "^0.3.3",
"moize": "^6.0.1",
"node-fetch": "^2.6.1",
"picomatch": "^2.2.3",
"postcss": "^8.2.8",
@ -62,12 +64,15 @@
"prismjs": "^1.23.0",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"rehype-parse": "^7.0.1",
"rollup": "^2.43.1",
"rollup-plugin-terser": "^7.0.2",
"sass": "^1.32.8",
"snowpack": "^3.2.2",
"svelte": "^3.35.0",
"vue": "^3.0.11",
"tiny-glob": "^0.2.8",
"unified": "^9.2.1",
"vue": "^3.0.10",
"yargs-parser": "^20.2.7"
},
"devDependencies": {

View file

@ -11,6 +11,8 @@ export interface DynamicRenderContext {
export interface ComponentRenderer<T> {
renderStatic: StaticRendererGenerator<T>;
jsxPragma?: (...args: any) => any;
jsxPragmaName?: string;
render(context: { root: string; Component: string; props: string; [key: string]: string }): string;
imports?: Record<string, string[]>;
}

View file

@ -208,6 +208,9 @@ function getComponentWrapper(_name: string, { type, plugin, url }: ComponentInfo
wrapper: `__svelte_${kind}(${name}, ${JSON.stringify({
componentUrl: getComponentUrl('.svelte.js'),
componentExport: 'default',
frameworkUrls: {
'astro/frontend/runtime/svelte': internalImport('runtime/svelte.js'),
},
})})`,
wrapperImport: `import {__svelte_${kind}} from '${internalImport('render/svelte.js')}';`,
};

View file

@ -0,0 +1,7 @@
<script>
const { __astro_component: Component, __astro_children, ...props } = $$props;
</script>
<Component {...props}>
{@html __astro_children}
</Component>

View file

@ -0,0 +1,168 @@
/* eslint-disable */
// @ts-nocheck
// TODO: don't precompile this, but it works for now
import {
HtmlTag,
SvelteComponentDev,
assign,
claim_component,
create_component,
destroy_component,
detach_dev,
dispatch_dev,
empty,
exclude_internal_props,
get_spread_object,
get_spread_update,
init,
insert_dev,
mount_component,
noop,
not_equal,
transition_in,
transition_out,
validate_slots
} from "svelte/internal";
const file = "App.svelte";
// (5:0) <Component {...props}>
function create_default_slot(ctx) {
let html_tag;
let html_anchor;
const block = {
c: function create() {
html_anchor = empty();
this.h();
},
l: function claim(nodes) {
html_anchor = empty();
this.h();
},
h: function hydrate() {
html_tag = new HtmlTag(html_anchor);
},
m: function mount(target, anchor) {
html_tag.m(/*__astro_children*/ ctx[1], target, anchor);
insert_dev(target, html_anchor, anchor);
},
p: noop,
d: function destroy(detaching) {
if (detaching) detach_dev(html_anchor);
if (detaching) html_tag.d();
}
};
dispatch_dev("SvelteRegisterBlock", {
block,
id: create_default_slot.name,
type: "slot",
source: "(5:0) <Component {...props}>",
ctx
});
return block;
}
function create_fragment(ctx) {
let component;
let current;
const component_spread_levels = [/*props*/ ctx[2]];
let component_props = {
$$slots: { default: [create_default_slot] },
$$scope: { ctx }
};
for (let i = 0; i < component_spread_levels.length; i += 1) {
component_props = assign(component_props, component_spread_levels[i]);
}
component = new /*Component*/ ctx[0]({ props: component_props, $$inline: true });
const block = {
c: function create() {
create_component(component.$$.fragment);
},
l: function claim(nodes) {
claim_component(component.$$.fragment, nodes);
},
m: function mount(target, anchor) {
mount_component(component, target, anchor);
current = true;
},
p: function update(ctx, [dirty]) {
const component_changes = (dirty & /*props*/ 4)
? get_spread_update(component_spread_levels, [get_spread_object(/*props*/ ctx[2])])
: {};
if (dirty & /*$$scope*/ 16) {
component_changes.$$scope = { dirty, ctx };
}
component.$set(component_changes);
},
i: function intro(local) {
if (current) return;
transition_in(component.$$.fragment, local);
current = true;
},
o: function outro(local) {
transition_out(component.$$.fragment, local);
current = false;
},
d: function destroy(detaching) {
destroy_component(component, detaching);
}
};
dispatch_dev("SvelteRegisterBlock", {
block,
id: create_fragment.name,
type: "component",
source: "",
ctx
});
return block;
}
function instance($$self, $$props, $$invalidate) {
let { $$slots: slots = {}, $$scope } = $$props;
validate_slots("App", slots, []);
const { __astro_component: Component, __astro_children, ...props } = $$props;
$$self.$$set = $$new_props => {
$$invalidate(3, $$props = assign(assign({}, $$props), exclude_internal_props($$new_props)));
};
$$self.$capture_state = () => ({ Component, __astro_children, props });
$$self.$inject_state = $$new_props => {
$$invalidate(3, $$props = assign(assign({}, $$props), $$new_props));
};
if ($$props && "$$inject" in $$props) {
$$self.$inject_state($$props.$$inject);
}
$$props = exclude_internal_props($$props);
return [Component, __astro_children, props];
}
class App extends SvelteComponentDev {
constructor(options) {
super(options);
init(this, options, instance, create_fragment, not_equal, {});
dispatch_dev("SvelteRegisterComponent", {
component: this,
tagName: "App",
options,
id: create_fragment.name
});
}
}
export default App;

View file

@ -0,0 +1,12 @@
/* eslint-disable */
// @ts-nocheck
// TODO: don't precompile this, but it works for now
/* App.svelte generated by Svelte v3.37.0 */
import { create_ssr_component, validate_component } from "svelte/internal";
const App = create_ssr_component(($$result, $$props, $$bindings, slots) => {
const { __astro_component: Component, __astro_children, ...props } = $$props;
return `${validate_component(Component, "Component").$$render($$result, Object.assign(props), {}, { default: () => `${__astro_children}` })}`;
});
export default App;

View file

@ -1,5 +1,6 @@
import { h, render, ComponentType } from 'preact';
import { renderToString } from 'preact-render-to-string';
import { childrenToVnodes } from './utils';
import type { ComponentRenderer } from '../../@types/renderer';
import { createRenderer } from './renderer';
@ -7,14 +8,18 @@ import { createRenderer } from './renderer';
Function.prototype(render);
const Preact: ComponentRenderer<ComponentType> = {
jsxPragma: h,
jsxPragmaName: 'h',
renderStatic(Component) {
return async (props, ...children) => renderToString(h(Component, props, ...children));
return async (props, ...children) => {
return renderToString(h(Component, props, childrenToVnodes(h, children)));
}
},
imports: {
preact: ['render', 'h'],
preact: ['render', 'Fragment', 'h'],
},
render({ Component, root, props }) {
return `render(h(${Component}, ${props}), ${root})`;
render({ Component, root, props, children }) {
return `render(h(${Component}, ${props}, h(Fragment, null, ...${children})), ${root})`;
},
};

View file

@ -2,17 +2,22 @@ import type { ComponentRenderer } from '../../@types/renderer';
import React, { ComponentType } from 'react';
import ReactDOMServer from 'react-dom/server';
import { createRenderer } from './renderer';
import { childrenToVnodes } from './utils';
const ReactRenderer: ComponentRenderer<ComponentType> = {
jsxPragma: React.createElement,
jsxPragmaName: 'React.createElement',
renderStatic(Component) {
return async (props, ...children) => ReactDOMServer.renderToString(React.createElement(Component, props, children));
return async (props, ...children) => {
return ReactDOMServer.renderToString(React.createElement(Component, props, childrenToVnodes(React.createElement, children)));
}
},
imports: {
react: ['default: React'],
'react-dom': ['default: ReactDOM'],
},
render({ Component, root, props }) {
return `ReactDOM.render(React.createElement(${Component}, ${props}), ${root})`;
render({ Component, root, children, props }) {
return `ReactDOM.hydrate(React.createElement(${Component}, ${props}, React.createElement(React.Fragment, null, ...${children})), ${root})`;
},
};

View file

@ -1,4 +1,5 @@
import type { DynamicRenderContext, DynamicRendererGenerator, SupportedComponentRenderer, StaticRendererGenerator } from '../../@types/renderer';
import { childrenToH } from './utils';
/** Initialize Astro Component renderer for Static and Dynamic components */
export function createRenderer(renderer: SupportedComponentRenderer) {
@ -16,7 +17,7 @@ export function createRenderer(renderer: SupportedComponentRenderer) {
.join(',');
return `const [{${context.componentExport}: Component}, ${values}] = await Promise.all([import("${context.componentUrl}")${renderer.imports ? ', ' + libs : ''}]);`;
};
const serializeProps = (props: Record<string, any>) => JSON.stringify(props);
const serializeProps = ({ children: _, ...props }: Record<string, any>) => JSON.stringify(props);
const createContext = () => {
const astroId = `${Math.floor(Math.random() * 1e16)}`;
return { ['data-astro-id']: astroId, root: `document.querySelector('[data-astro-id="${astroId}"]')`, Component: 'Component' };
@ -32,10 +33,19 @@ export function createRenderer(renderer: SupportedComponentRenderer) {
}
value = `<div data-astro-id="${innerContext['data-astro-id']}">${value}</div>`;
return `${value}\n<script type="module">${typeof wrapperStart === 'function' ? wrapperStart(innerContext) : wrapperStart}\n${_imports(renderContext)}\n${renderer.render({
...innerContext,
props: serializeProps(props),
})}\n${typeof wrapperEnd === 'function' ? wrapperEnd(innerContext) : wrapperEnd}</script>`;
const script = `
${typeof wrapperStart === 'function' ? wrapperStart(innerContext) : wrapperStart}
${_imports(renderContext)}
${renderer.render({
...innerContext,
props: serializeProps(props),
children: `[${childrenToH(renderer, children) ?? ''}]`,
childrenAsString: `\`${children}\``
})}
${typeof wrapperEnd === 'function' ? wrapperEnd(innerContext) : wrapperEnd}
`;
return [value, `<script type="module">${script.trim()}</script>`].join('\n');
};
};
@ -45,7 +55,7 @@ export function createRenderer(renderer: SupportedComponentRenderer) {
idle: createDynamicRender('requestIdleCallback(async () => {', '})'),
visible: createDynamicRender(
'const o = new IntersectionObserver(async ([entry]) => { if (!entry.isIntersecting) { return; } o.disconnect();',
({ root }) => `}); o.observe(${root})`
({ root }) => `}); Array.from(${root}.item(0).children).forEach(child => o.observe(child))`
),
};
}

View file

@ -1,20 +1,20 @@
import type { ComponentRenderer } from '../../@types/renderer';
import type { SvelteComponent } from 'svelte';
import { createRenderer } from './renderer';
import SvelteWrapper from '../SvelteWrapper.svelte.server';
const SvelteRenderer: ComponentRenderer<SvelteComponent> = {
renderStatic(Component) {
return async (props, ...children) => {
const { html } = Component.render(props);
const { html } = SvelteWrapper.render({ __astro_component: Component, __astro_children: children.join('\n'), ...props });
return html;
};
},
render({ Component, root, props }) {
return `new ${Component}({
target: ${root},
props: ${props},
hydrate: true
})`;
imports: {
'astro/frontend/runtime/svelte': ['default: render']
},
render({ Component, root, props, childrenAsString }) {
return `render(${root}, ${Component}, ${props}, ${childrenAsString});`;
},
};

View file

@ -0,0 +1,47 @@
import unified from 'unified';
import parse from 'rehype-parse';
import toH from 'hast-to-hyperscript';
import { ComponentRenderer } from '../../@types/renderer';
import moize from 'moize';
/** @internal */
function childrenToTree(children: string[]) {
return children.map(child => (unified().use(parse, { fragment: true }).parse(child) as any).children.pop());
}
/**
* Converts an HTML fragment string into vnodes for rendering via provided framework
* @param h framework's `createElement` function
* @param children the HTML string children
*/
export const childrenToVnodes = moize.deep(function childrenToVnodes(h: any, children: string[]) {
const tree = childrenToTree(children);
const vnodes = tree.map(subtree => toH(h, subtree));
return vnodes;
})
/**
* Converts an HTML fragment string into h function calls as a string
* @param h framework's `createElement` function
* @param children the HTML string children
*/
export const childrenToH = moize.deep(function childrenToH(renderer: ComponentRenderer<any>, children: string[]): any {
if (!renderer.jsxPragma) return;
const tree = childrenToTree(children);
const innerH = (name: any, attrs: Record<string, any>|null = null, _children: string[]|null = null) => {
const vnode = renderer.jsxPragma?.(name, attrs, _children);
const childStr = _children ? `, [${_children.map(child => serializeChild(child)).join(',')}]` : '';
/* fix(react): avoid hard-coding keys into the serialized tree */
if (attrs && attrs.key) attrs.key = undefined;
const __SERIALIZED = `${renderer.jsxPragmaName}("${name}", ${attrs ? JSON.stringify(attrs) : 'null'}${childStr})` as string;
return { ...vnode, __SERIALIZED }
}
const serializeChild = (child: unknown) => {
if (typeof child === 'string') return `\`${child}\``;
if (typeof child === 'number' || typeof child === 'boolean') return `${child}`;
if (child === null) return `null`;
if ((child as any).__SERIALIZED) return (child as any).__SERIALIZED;
return innerH(child).__SERIALIZED;
}
return tree.map(subtree => toH(innerH, subtree).__SERIALIZED);
})

View file

@ -1,20 +1,45 @@
import type { ComponentRenderer } from '../../@types/renderer';
import type { Component as VueComponent } from 'vue';
import { renderToString } from '@vue/server-renderer';
import { createSSRApp, h as createElement } from 'vue';
import { defineComponent, createSSRApp, h as createElement } from 'vue';
import { createRenderer } from './renderer';
/**
* Users might attempt to use :vueAttribute syntax to pass primitive values.
* If so, try to JSON.parse them to get the primitives
*/
function cleanPropsForVue(obj: Record<string, any>) {
let cleaned = {} as any;
for (let [key, value] of Object.entries(obj)) {
if (key.startsWith(':')) {
key = key.slice(1);
if (typeof value === 'string') {
try {
value = JSON.parse(value);
} catch (e) {}
}
}
cleaned[key] = value;
}
return cleaned;
}
const Vue: ComponentRenderer<VueComponent> = {
jsxPragma: createElement,
jsxPragmaName: 'createElement',
renderStatic(Component) {
return async (props, ...children) => {
const app = createSSRApp({
const App = defineComponent({
components: {
Component,
Component
},
render() {
return createElement(Component as any, props);
data() {
return { props }
},
template: `<Component v-bind="props">${children.join('\n')}</Component>`
});
const app = createSSRApp(App);
const html = await renderToString(app);
return html;
};
@ -22,8 +47,9 @@ const Vue: ComponentRenderer<VueComponent> = {
imports: {
vue: ['createApp', 'h: createElement'],
},
render({ Component, root, props }) {
return `const App = { render() { return createElement(${Component}, ${props} )} };
render({ Component, root, props, children }) {
const vueProps = cleanPropsForVue(JSON.parse(props));
return `const App = { render: () => createElement(${Component}, ${JSON.stringify(vueProps)}, { default: () => ${children} }) };
createApp(App).mount(${root});`;
},
};

View file

@ -0,0 +1,10 @@
import SvelteWrapper from '../SvelteWrapper.svelte.client';
import type { SvelteComponent } from 'svelte';
export default (target: Element, component: SvelteComponent, props: any, children: string) => {
new SvelteWrapper({
target,
props: { __astro_component: component, __astro_children: children, ...props },
hydrate: true
})
}

View file

@ -261,7 +261,7 @@ async function createSnowpack(astroConfig: AstroConfig, env: Record<string, any>
plugins: [
[fileURLToPath(new URL('../snowpack-plugin.cjs', import.meta.url)), astroPlugOptions],
require.resolve('@snowpack/plugin-sass'),
require.resolve('@snowpack/plugin-svelte'),
[require.resolve('@snowpack/plugin-svelte'), { compilerOptions: { hydratable: true }}],
require.resolve('@snowpack/plugin-vue'),
],
devOptions: {