diff --git a/README.md b/README.md index 89c18ea..71d05eb 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ # greenwood-demo-adapter-vercel -A demonstration repo for deploying a full-stack [**Greenwood**](https://www.greenwoodjs.io/) app with Vercel static hosting and Serverless + Edge functions. +A demonstration repo for deploying a full-stack [**Greenwood**](https://www.greenwoodjs.io/) app using [Lit](https://lit.dev/) SSR with Vercel static hosting and Serverless + Edge functions. + +You can see the live demo at [https://greenwood-demo-adapter-vercel-lit.vercel.app/](https://greenwood-demo-adapter-vercel-lit.vercel.app/). + +> _It is based on [this](https://github.com/ProjectEvergreen/greenwood-demo-adapter-vercel) Greenwood demo._ ## Setup @@ -14,51 +18,13 @@ You can now run these npm scripts > 👉 **Note**: _If deploying to your own Vercel instance, make sure you set the NodeJS version to `18.x` in your Vercel project's General settings_. -## Demo - -This repo aims to demonstrate a couple of Greenwood's features ([API Routes](https://www.greenwoodjs.io/docs/api-routes/) and [SSR pages](https://www.greenwoodjs.io/docs/server-rendering/#routes)) leveraging Netlify's serverless and edge function capabilities, focused on using Web Components (WCC) and Web Standards to deliver the content for the demo. - ## Status |Feature |Greenwood |Serverless|Edge| |---------- |----------|----------|----| |API Routes | ✅ | ✅ | ❓ | -|SSR Pages | ✅ | ✅ | ❓ | - -You can see the live demo at [https://greenwood-demo-adapter-vercel.vercel.app/](https://greenwood-demo-adapter-vercel.vercel.app/). - -## Serverless - -The serverless demos include the following examples: - -### API Routes - -- ✅ [`/api/greeting?name{xxx}`](https://greenwood-demo-adapter-vercel.vercel.app/api/greeting) - An API that returns a JSON response and optionally uses the `name` query param for customization. Otherwise returns a default message. -- ✅ [`/api/fragment`](https://greenwood-demo-adapter-vercel.vercel.app/api/fragment) - An API for returning fragments of server rendered Web Components as HTML, that are then appended to the DOM. The same card component used in SSR also runs on the client to provide interactivity, like event handling. - -### SSR Pages - -- ✅ [`/products/`](https://greenwood-demo-adapter-vercel.vercel.app/products/) - SSR page for rendering Greenwood pages. - -## Edge - -TODO - -### API Routes - -TODO - -### SSR page - -TODO - -## Adapter Implementation Thoughts / Questions +|SSR Pages | 🚫 | ❓ | ❓ | -1. [x] Will need to generate the _api/_ folder on-demand / as part of the build instead of hardcoding, likely from _manifest.json_ -1. [x] How to manage vercel configuration (e.g. redirects for pages)? Auto generate, auto merge into _vercel.json_? -1. [x] How to best manage local dev (runtime "compliance") - just for production builds - - proxy vercel cli dev option? - - should use _src/_ or _public/_? depends on dev vs production mode? Interestingly, the manual way only worked deployed when using _public/_ -1. [x] Make sure to spread all headers / response properties in netlify functions adapter output -1. [ ] Keep it as an experimental feature for 1.0 (or per platform?) -1. [ ] Will SSR pages need access to the request object? \ No newline at end of file +### Known Issues +1. [ ] [Lit SSR does not support `async`` component work](https://github.com/thescientist13/greenwood-demo-adapter-vercel-lit/issues/3) +1. [ ] [Declarative Shadow DOM support](https://github.com/thescientist13/greenwood-demo-adapter-vercel-lit/issues/4) \ No newline at end of file diff --git a/greenwood.config.js b/greenwood.config.js index b4371ef..48506c2 100644 --- a/greenwood.config.js +++ b/greenwood.config.js @@ -1,7 +1,9 @@ import { greenwoodPluginAdapterVercel } from '@greenwood/plugin-adapter-vercel'; +import { greenwoodPluginRendererLit } from '@greenwood/plugin-renderer-lit'; export default { plugins: [ + greenwoodPluginRendererLit(), greenwoodPluginAdapterVercel() ] }; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index ceb67fa..81b0554 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,9 +8,13 @@ "name": "greenwood-demo-adapter-vercel", "version": "1.0.0", "license": "ISC", + "dependencies": { + "lit": "^2.8.0" + }, "devDependencies": { "@greenwood/cli": "~0.29.0-alpha.4", "@greenwood/plugin-adapter-vercel": "~0.29.0-alpha.4", + "@greenwood/plugin-renderer-lit": "^0.29.0-alpha.4", "rimraf": "^5.0.0" } }, @@ -541,6 +545,19 @@ "@greenwood/cli": "^0.28.0" } }, + "node_modules/@greenwood/plugin-renderer-lit": { + "version": "0.29.0-alpha.4", + "resolved": "https://registry.npmjs.org/@greenwood/plugin-renderer-lit/-/plugin-renderer-lit-0.29.0-alpha.4.tgz", + "integrity": "sha512-zKiM/Pz0ctsgcPzUjJj9+kKPjp5fItoGsgLfIP/lp7Ypc+J1I9LHIceV1F2/v6q7ZofHeB+DM1wcqoc5RjpuQw==", + "dev": true, + "dependencies": { + "@lit-labs/ssr": "^2.0.1" + }, + "peerDependencies": { + "@greenwood/cli": "^0.22.1", + "lit": "^2.1.1" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -622,6 +639,124 @@ "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", "dev": true }, + "node_modules/@lit-labs/ssr": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@lit-labs/ssr/-/ssr-2.3.0.tgz", + "integrity": "sha512-uPaJoNf5w3t8DOVDpuI4WR6wo552mZwiiE9n9TpIvinh75lDgvl1ki07wvfrFI6VEbDVPRj4jHiCduBr1dVJ7A==", + "dev": true, + "dependencies": { + "@lit-labs/ssr-client": "^1.0.0", + "@lit/reactive-element": "^1.5.0", + "@parse5/tools": "^0.1.0", + "@types/node": "^16.0.0", + "enhanced-resolve": "^5.10.0", + "lit": "^2.5.0", + "lit-element": "^3.1.0", + "lit-html": "^2.5.0", + "node-fetch": "^3.2.8", + "parse5": "^7.1.1" + }, + "engines": { + "node": ">=13.9.0" + } + }, + "node_modules/@lit-labs/ssr-client": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@lit-labs/ssr-client/-/ssr-client-1.1.4.tgz", + "integrity": "sha512-LJUi1/Run6iLTfE3QlX0aGzuTBWOmvBQet2ushSgc8iE1X5bWFLii2QhpMb9rw3or3OrUmXjEEI/AzWaehbMAg==", + "dev": true, + "dependencies": { + "@lit/reactive-element": "^2.0.0", + "lit": "^3.0.0", + "lit-html": "^3.0.0" + } + }, + "node_modules/@lit-labs/ssr-client/node_modules/@lit/reactive-element": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.0.0.tgz", + "integrity": "sha512-wn+2+uDcs62ROBmVAwssO4x5xue/uKD3MGGZOXL2sMxReTRIT0JXKyMXeu7gh0aJ4IJNEIG/3aOnUaQvM7BMzQ==", + "dev": true, + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.1.2-pre.0" + } + }, + "node_modules/@lit-labs/ssr-client/node_modules/lit": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lit/-/lit-3.0.0.tgz", + "integrity": "sha512-nQ0teRzU1Kdj++VdmttS2WvIen8M79wChJ6guRKIIym2M3Ansg3Adj9O6yuQh2IpjxiUXlNuS81WKlQ4iL3BmA==", + "dev": true, + "dependencies": { + "@lit/reactive-element": "^2.0.0", + "lit-element": "^4.0.0", + "lit-html": "^3.0.0" + } + }, + "node_modules/@lit-labs/ssr-client/node_modules/lit-element": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-4.0.0.tgz", + "integrity": "sha512-N6+f7XgusURHl69DUZU6sTBGlIN+9Ixfs3ykkNDfgfTkDYGGOWwHAYBhDqVswnFGyWgQYR2KiSpu4J76Kccs/A==", + "dev": true, + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.1.2-pre.0", + "@lit/reactive-element": "^2.0.0", + "lit-html": "^3.0.0" + } + }, + "node_modules/@lit-labs/ssr-client/node_modules/lit-html": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.0.0.tgz", + "integrity": "sha512-DNJIE8dNY0dQF2Gs0sdMNUppMQT2/CvV4OVnSdg7BXAsGqkVwsE5bqQ04POfkYH5dBIuGnJYdFz5fYYyNnOxiA==", + "dev": true, + "dependencies": { + "@types/trusted-types": "^2.0.2" + } + }, + "node_modules/@lit-labs/ssr-dom-shim": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.1.2.tgz", + "integrity": "sha512-jnOD+/+dSrfTWYfSXBXlo5l5f0q1UuJo3tkbMDCYA2lKUYq79jaxqtGEvnRoh049nt1vdo1+45RinipU6FGY2g==" + }, + "node_modules/@lit-labs/ssr/node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/@lit/reactive-element": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-1.6.3.tgz", + "integrity": "sha512-QuTgnG52Poic7uM1AN5yJ09QMe0O28e10XzSvWDz02TJiiKee4stsiownEIadWm8nYzyDAyT+gKzUoZmiWQtsQ==", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.0.0" + } + }, + "node_modules/@parse5/tools": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@parse5/tools/-/tools-0.1.0.tgz", + "integrity": "sha512-VB9+4BsFoS+4HdB/Ph9jD4FHQt7GyiWESVNfBSh8Eu54LujWyy+NySGLjg8GZFWSZcESG72F67LjgmKZDZCvPg==", + "dev": true, + "dependencies": { + "parse5": "^7.0.0" + } + }, + "node_modules/@parse5/tools/node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -815,9 +950,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "14.18.33", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.33.tgz", - "integrity": "sha512-qelS/Ra6sacc4loe/3MSjXNL1dNQ/GjxNHVzuChwMfmk7HuycRLVQN2qNY3XahK+fZc5E2szqQSKUyAF0E+2bg==", + "version": "16.18.58", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.58.tgz", + "integrity": "sha512-YGncyA25/MaVtQkjWW9r0EFBukZ+JulsLcVZBlGUfIb96OBMjkoRWwQo5IEWJ8Fj06Go3GHw+bjYDitv6BaGsA==", "dev": true }, "node_modules/@types/parse5": { @@ -868,6 +1003,11 @@ "@types/node": "*" } }, + "node_modules/@types/trusted-types": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.4.tgz", + "integrity": "sha512-IDaobHimLQhjwsQ/NMwRVfa/yL7L/wriQPMhw1ZJall0KX6E1oxk29XMDeilW5qTIg5aoiqf5Udy8U/51aNoQQ==" + }, "node_modules/@types/unist": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz", @@ -1364,6 +1504,15 @@ "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" } }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -1473,6 +1622,31 @@ "node": ">= 0.8" } }, + "node_modules/enhanced-resolve": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/es-module-shims": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/es-module-shims/-/es-module-shims-1.7.2.tgz", @@ -1589,6 +1763,29 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -1635,6 +1832,18 @@ "node": ">=0.4.x" } }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dev": true, + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, "node_modules/formidable": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz", @@ -1785,6 +1994,12 @@ "node": "*" } }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, "node_modules/gray-matter": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-2.1.1.tgz", @@ -2901,6 +3116,34 @@ "node": ">=0.10.0" } }, + "node_modules/lit": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/lit/-/lit-2.8.0.tgz", + "integrity": "sha512-4Sc3OFX9QHOJaHbmTMk28SYgVxLN3ePDjg7hofEft2zWlehFL3LiAuapWc4U/kYwMYJSh2hTCPZ6/LIC7ii0MA==", + "dependencies": { + "@lit/reactive-element": "^1.6.0", + "lit-element": "^3.3.0", + "lit-html": "^2.8.0" + } + }, + "node_modules/lit-element": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-3.3.3.tgz", + "integrity": "sha512-XbeRxmTHubXENkV4h8RIPyr8lXc+Ff28rkcQzw3G6up2xg5E8Zu1IgOWIwBLEQsu3cOVFqdYwiVi0hv0SlpqUA==", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.1.0", + "@lit/reactive-element": "^1.3.0", + "lit-html": "^2.8.0" + } + }, + "node_modules/lit-html": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-2.8.0.tgz", + "integrity": "sha512-o9t+MQM3P4y7M7yNzqAyjp7z+mQGa4NS4CxiyLqFPyFWyc4O+nodLrkrxSaCTrla6M5YOLaT3RpbbqjszB5g3Q==", + "dependencies": { + "@types/trusted-types": "^2.0.2" + } + }, "node_modules/livereload": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/livereload/-/livereload-0.9.3.tgz", @@ -3158,6 +3401,43 @@ "node": ">= 0.6" } }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "dev": true, + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, "node_modules/node-html-parser": { "version": "1.4.9", "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-1.4.9.tgz", @@ -3797,6 +4077,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/terser": { "version": "5.17.3", "resolved": "https://registry.npmjs.org/terser/-/terser-5.17.3.tgz", @@ -4060,6 +4349,15 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/web-streams-polyfill": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", + "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -4594,6 +4892,15 @@ "integrity": "sha512-ru86tXEUO5jB3Slfv+3Tk1T0keHWUOZsDTKlfUIX2/pfqsSKQG2Yd2iDSARBgUlE/JUKFjjmNCpCWgcGcTQsVg==", "dev": true }, + "@greenwood/plugin-renderer-lit": { + "version": "0.29.0-alpha.4", + "resolved": "https://registry.npmjs.org/@greenwood/plugin-renderer-lit/-/plugin-renderer-lit-0.29.0-alpha.4.tgz", + "integrity": "sha512-zKiM/Pz0ctsgcPzUjJj9+kKPjp5fItoGsgLfIP/lp7Ypc+J1I9LHIceV1F2/v6q7ZofHeB+DM1wcqoc5RjpuQw==", + "dev": true, + "requires": { + "@lit-labs/ssr": "^2.0.1" + } + }, "@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -4665,6 +4972,121 @@ } } }, + "@lit-labs/ssr": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@lit-labs/ssr/-/ssr-2.3.0.tgz", + "integrity": "sha512-uPaJoNf5w3t8DOVDpuI4WR6wo552mZwiiE9n9TpIvinh75lDgvl1ki07wvfrFI6VEbDVPRj4jHiCduBr1dVJ7A==", + "dev": true, + "requires": { + "@lit-labs/ssr-client": "^1.0.0", + "@lit/reactive-element": "^1.5.0", + "@parse5/tools": "^0.1.0", + "@types/node": "^16.0.0", + "enhanced-resolve": "^5.10.0", + "lit": "^2.5.0", + "lit-element": "^3.1.0", + "lit-html": "^2.5.0", + "node-fetch": "^3.2.8", + "parse5": "^7.1.1" + }, + "dependencies": { + "parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "requires": { + "entities": "^4.4.0" + } + } + } + }, + "@lit-labs/ssr-client": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@lit-labs/ssr-client/-/ssr-client-1.1.4.tgz", + "integrity": "sha512-LJUi1/Run6iLTfE3QlX0aGzuTBWOmvBQet2ushSgc8iE1X5bWFLii2QhpMb9rw3or3OrUmXjEEI/AzWaehbMAg==", + "dev": true, + "requires": { + "@lit/reactive-element": "^2.0.0", + "lit": "^3.0.0", + "lit-html": "^3.0.0" + }, + "dependencies": { + "@lit/reactive-element": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.0.0.tgz", + "integrity": "sha512-wn+2+uDcs62ROBmVAwssO4x5xue/uKD3MGGZOXL2sMxReTRIT0JXKyMXeu7gh0aJ4IJNEIG/3aOnUaQvM7BMzQ==", + "dev": true, + "requires": { + "@lit-labs/ssr-dom-shim": "^1.1.2-pre.0" + } + }, + "lit": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lit/-/lit-3.0.0.tgz", + "integrity": "sha512-nQ0teRzU1Kdj++VdmttS2WvIen8M79wChJ6guRKIIym2M3Ansg3Adj9O6yuQh2IpjxiUXlNuS81WKlQ4iL3BmA==", + "dev": true, + "requires": { + "@lit/reactive-element": "^2.0.0", + "lit-element": "^4.0.0", + "lit-html": "^3.0.0" + } + }, + "lit-element": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-4.0.0.tgz", + "integrity": "sha512-N6+f7XgusURHl69DUZU6sTBGlIN+9Ixfs3ykkNDfgfTkDYGGOWwHAYBhDqVswnFGyWgQYR2KiSpu4J76Kccs/A==", + "dev": true, + "requires": { + "@lit-labs/ssr-dom-shim": "^1.1.2-pre.0", + "@lit/reactive-element": "^2.0.0", + "lit-html": "^3.0.0" + } + }, + "lit-html": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.0.0.tgz", + "integrity": "sha512-DNJIE8dNY0dQF2Gs0sdMNUppMQT2/CvV4OVnSdg7BXAsGqkVwsE5bqQ04POfkYH5dBIuGnJYdFz5fYYyNnOxiA==", + "dev": true, + "requires": { + "@types/trusted-types": "^2.0.2" + } + } + } + }, + "@lit-labs/ssr-dom-shim": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.1.2.tgz", + "integrity": "sha512-jnOD+/+dSrfTWYfSXBXlo5l5f0q1UuJo3tkbMDCYA2lKUYq79jaxqtGEvnRoh049nt1vdo1+45RinipU6FGY2g==" + }, + "@lit/reactive-element": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-1.6.3.tgz", + "integrity": "sha512-QuTgnG52Poic7uM1AN5yJ09QMe0O28e10XzSvWDz02TJiiKee4stsiownEIadWm8nYzyDAyT+gKzUoZmiWQtsQ==", + "requires": { + "@lit-labs/ssr-dom-shim": "^1.0.0" + } + }, + "@parse5/tools": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@parse5/tools/-/tools-0.1.0.tgz", + "integrity": "sha512-VB9+4BsFoS+4HdB/Ph9jD4FHQt7GyiWESVNfBSh8Eu54LujWyy+NySGLjg8GZFWSZcESG72F67LjgmKZDZCvPg==", + "dev": true, + "requires": { + "parse5": "^7.0.0" + }, + "dependencies": { + "parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "requires": { + "entities": "^4.4.0" + } + } + } + }, "@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -4844,9 +5266,9 @@ "dev": true }, "@types/node": { - "version": "14.18.33", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.33.tgz", - "integrity": "sha512-qelS/Ra6sacc4loe/3MSjXNL1dNQ/GjxNHVzuChwMfmk7HuycRLVQN2qNY3XahK+fZc5E2szqQSKUyAF0E+2bg==", + "version": "16.18.58", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.58.tgz", + "integrity": "sha512-YGncyA25/MaVtQkjWW9r0EFBukZ+JulsLcVZBlGUfIb96OBMjkoRWwQo5IEWJ8Fj06Go3GHw+bjYDitv6BaGsA==", "dev": true }, "@types/parse5": { @@ -4897,6 +5319,11 @@ "@types/node": "*" } }, + "@types/trusted-types": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.4.tgz", + "integrity": "sha512-IDaobHimLQhjwsQ/NMwRVfa/yL7L/wriQPMhw1ZJall0KX6E1oxk29XMDeilW5qTIg5aoiqf5Udy8U/51aNoQQ==" + }, "@types/unist": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz", @@ -5273,6 +5700,12 @@ "source-map-js": "^1.0.1" } }, + "data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "dev": true + }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -5358,6 +5791,22 @@ "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", "dev": true }, + "enhanced-resolve": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + } + }, + "entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true + }, "es-module-shims": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/es-module-shims/-/es-module-shims-1.7.2.tgz", @@ -5451,6 +5900,16 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "dev": true, + "requires": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + } + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -5482,6 +5941,15 @@ "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", "dev": true }, + "formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dev": true, + "requires": { + "fetch-blob": "^3.1.2" + } + }, "formidable": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz", @@ -5605,6 +6073,12 @@ "is-glob": "^4.0.1" } }, + "graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, "gray-matter": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-2.1.1.tgz", @@ -6433,6 +6907,34 @@ } } }, + "lit": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/lit/-/lit-2.8.0.tgz", + "integrity": "sha512-4Sc3OFX9QHOJaHbmTMk28SYgVxLN3ePDjg7hofEft2zWlehFL3LiAuapWc4U/kYwMYJSh2hTCPZ6/LIC7ii0MA==", + "requires": { + "@lit/reactive-element": "^1.6.0", + "lit-element": "^3.3.0", + "lit-html": "^2.8.0" + } + }, + "lit-element": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-3.3.3.tgz", + "integrity": "sha512-XbeRxmTHubXENkV4h8RIPyr8lXc+Ff28rkcQzw3G6up2xg5E8Zu1IgOWIwBLEQsu3cOVFqdYwiVi0hv0SlpqUA==", + "requires": { + "@lit-labs/ssr-dom-shim": "^1.1.0", + "@lit/reactive-element": "^1.3.0", + "lit-html": "^2.8.0" + } + }, + "lit-html": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-2.8.0.tgz", + "integrity": "sha512-o9t+MQM3P4y7M7yNzqAyjp7z+mQGa4NS4CxiyLqFPyFWyc4O+nodLrkrxSaCTrla6M5YOLaT3RpbbqjszB5g3Q==", + "requires": { + "@types/trusted-types": "^2.0.2" + } + }, "livereload": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/livereload/-/livereload-0.9.3.tgz", @@ -6624,6 +7126,23 @@ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "dev": true }, + "node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "dev": true + }, + "node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "dev": true, + "requires": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + } + }, "node-html-parser": { "version": "1.4.9", "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-1.4.9.tgz", @@ -7087,6 +7606,12 @@ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true }, + "tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true + }, "terser": { "version": "5.17.3", "resolved": "https://registry.npmjs.org/terser/-/terser-5.17.3.tgz", @@ -7289,6 +7814,12 @@ "integrity": "sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw==", "dev": true }, + "web-streams-polyfill": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", + "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", + "dev": true + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index 8d83ca0..65bc8a6 100644 --- a/package.json +++ b/package.json @@ -1,14 +1,14 @@ { "name": "greenwood-demo-adapter-vercel", "version": "1.0.0", - "description": "A demonstration repo for deploying a full-stack Greenwood app with Vercel static hosting and Serverless + Edge functions", + "description": "A demonstration repo for deploying a full-stack Greenwood app with Lit SSR, Vercel static hosting and Serverless + Edge functions", "homepage": "https://github.com/ProjectEvergreen/greenwood-demo-adapter-vercel#readme", "author": "Owen Buckley ", "license": "ISC", "type": "module", "repository": { "type": "git", - "url": "git+https://github.com/ProjectEvergreen/greenwood-demo-adapter-vercel.git" + "url": "git+https://github.com/thescientist13/greenwood-demo-adapter-vercel.git" }, "keywords": [ "Greenwood", @@ -17,18 +17,23 @@ "Web Components", "Serverless", "Edge", - "SSR" + "SSR", + "Lit" ], "scripts": { "clean": "rimraf public .greenwood .vercel", "dev": "greenwood develop", - "build": "greenwood build", + "build": "mkdir -p public/api/assets && greenwood build", "serve": "greenwood build && greenwood serve", "start": "npm run serve" }, + "dependencies": { + "lit": "^2.8.0" + }, "devDependencies": { "@greenwood/cli": "~0.29.0-alpha.4", "@greenwood/plugin-adapter-vercel": "~0.29.0-alpha.4", + "@greenwood/plugin-renderer-lit": "^0.29.0-alpha.4", "rimraf": "^5.0.0" } } diff --git a/src/api/fragment.js b/src/api/fragment.js index eea1321..5c4e229 100644 --- a/src/api/fragment.js +++ b/src/api/fragment.js @@ -1,14 +1,18 @@ -import { renderFromHTML } from 'wc-compiler'; +import { render } from '@lit-labs/ssr/lib/render-with-global-dom-shim.js'; +import { html } from 'lit'; +import { unsafeHTML } from 'lit/directives/unsafe-html.js'; import { getProducts } from '../services/products.js'; +import { renderFromHTML } from '../services/render-to-string.js'; +import '../components/card.js'; export async function handler(request) { const params = new URLSearchParams(request.url.slice(request.url.indexOf('?'))); const limit = params.has('limit') ? parseInt(params.get('limit'), 10) : 5; const offset = params.has('offset') ? parseInt(params.get('offset'), 10) : 0; const products = (await getProducts()).slice(offset, offset + limit); - const { html } = await renderFromHTML(` + const body = await renderFromHTML(render(html` ${ - products.map((item, idx) => { + unsafeHTML(products.map((item, idx) => { const { title, thumbnail } = item; return ` @@ -17,13 +21,11 @@ export async function handler(request) { thumbnail="${thumbnail}" > `; - }).join('') + }).join('')) } - `, [ - new URL('../components/card.js', import.meta.url) - ]); + `)); - return new Response(html, { + return new Response(body, { headers: new Headers({ 'Content-Type': 'text/html' }) diff --git a/src/api/greeting.js b/src/api/greeting.js index 48250fe..3549e33 100644 --- a/src/api/greeting.js +++ b/src/api/greeting.js @@ -1,9 +1,7 @@ -import { getMessage } from '../services/message.js'; - export async function handler(request) { const params = new URLSearchParams(request.url.slice(request.url.indexOf('?'))); const name = params.has('name') ? params.get('name') : 'Greenwood'; - const body = { message: getMessage(name) }; + const body = { message: `Hello ${name}!` }; return new Response(JSON.stringify(body), { headers: new Headers({ diff --git a/src/api/search.js b/src/api/search.js index e18aeec..80e7cd2 100644 --- a/src/api/search.js +++ b/src/api/search.js @@ -1,5 +1,9 @@ -import { renderFromHTML } from 'wc-compiler'; +import { render } from '@lit-labs/ssr/lib/render-with-global-dom-shim.js'; +import { html } from 'lit'; +import { unsafeHTML } from 'lit/directives/unsafe-html.js'; import { getProducts } from '../services/products.js'; +import { renderFromHTML } from '../services/render-to-string.js'; +import '../components/card.js'; export async function handler(request) { const formData = await request.formData(); @@ -13,9 +17,9 @@ export async function handler(request) { if (products.length === 0) { body = 'No results found.'; } else { - const { html } = await renderFromHTML(` + body = await renderFromHTML(render(html` ${ - products.map((item, idx) => { + unsafeHTML(products.map((item, idx) => { const { title, thumbnail } = item; return ` @@ -24,13 +28,9 @@ export async function handler(request) { thumbnail="${thumbnail}" > `; - }).join('') + }).join('')) } - `, [ - new URL('../components/card.js', import.meta.url) - ]); - - body = html; + `)); } return new Response(body, { diff --git a/src/components/card.js b/src/components/card.js index 575b2dc..9ca6710 100644 --- a/src/components/card.js +++ b/src/components/card.js @@ -1,68 +1,78 @@ -export default class Card extends HTMLElement { +import { LitElement, html, css } from 'lit'; - selectItem() { - alert(`selected item is => ${this.getAttribute('title')}!`); - } +export class Card extends LitElement { + static properties = { + title: '', + thumbnail: '' + }; + static styles = css` + div { + display: flex; + flex-direction: column; + align-items: center; + gap: 0.5rem; + border: 1px solid #818181; + width: fit-content; + border-radius: 10px; + padding: 2rem 1rem; + height: 680px; + justify-content: space-between; + background-color: #fff; + overflow-x: hidden; + } + button { + background: var(--color-accent); + color: var(--color-white); + padding: 1rem 2rem; + border: 0; + font-size: 1rem; + border-radius: 5px; + cursor: pointer; + } + img { + max-width: 500px; + min-width: 500px; + width: 100%; + } + h3 { + font-size: 1.85rem; + } - connectedCallback() { - if (!this.shadowRoot) { - const thumbnail = this.getAttribute('thumbnail'); - const title = this.getAttribute('title'); - const template = document.createElement('template'); + @media(max-width: 768px) { + img { + max-width: 300px; + min-width: 300px; + } + div { + height: 500px; + } + } + `; - template.innerHTML = ` - -
-

${title}

- ${title} - -
- `; - this.attachShadow({ mode: 'open' }); - this.shadowRoot.appendChild(template.content.cloneNode(true)); + this.title; + this.thumbnail; + } + + selectItem() { + alert(`selected item is => ${this.title}!`); + } + + render() { + const { title, thumbnail } = this; + if(!title && !thumbnail) { + return; } + + return html` +
+

${title}

+ ${title} + +
+ `; } } diff --git a/src/pages/index.html b/src/pages/index.html index c13d3c0..fc7c07b 100644 --- a/src/pages/index.html +++ b/src/pages/index.html @@ -24,7 +24,6 @@ globalThis.document.getElementById('load-products').addEventListener('click', async () => { offset = offset += page; const html = await fetch(`/api/fragment?offset=${offset}&limit=10`).then(resp => resp.text()); - console.log({ html }); document.getElementById('load-products-output').insertAdjacentHTML('beforeend', html); }); diff --git a/src/pages/products.js b/src/pages/products.js deleted file mode 100644 index 3834fc8..0000000 --- a/src/pages/products.js +++ /dev/null @@ -1,29 +0,0 @@ -import '../components/card.js'; -import { getProducts } from '../services/products.js'; - -export default class ProductsPage extends HTMLElement { - async connectedCallback() { - const products = await getProducts(); - const html = products.map((product) => { - const { title, thumbnail } = product; - - return ` - - - `; - }).join(''); - - this.innerHTML = ` -

SSR Page (w/ WCC)

-

This is an example of a Greenwood SSR page route server-rendering Web Components; the same Card component used for the Fragments API demo on the home page in fact! Greenwood is also statically bundling the share template (written in HTML) so that you can still share page templates even within SSR pages.

- -

List of Products: ${products.length}

-
- ${html} -
- `; - } -} \ No newline at end of file diff --git a/src/services/message.js b/src/services/message.js deleted file mode 100644 index 08b7b2e..0000000 --- a/src/services/message.js +++ /dev/null @@ -1,7 +0,0 @@ -function getMessage(name) { - return `Hello ${name}!`; -} - -export { - getMessage -} \ No newline at end of file diff --git a/src/services/render-to-string.js b/src/services/render-to-string.js new file mode 100644 index 0000000..80e9409 --- /dev/null +++ b/src/services/render-to-string.js @@ -0,0 +1,13 @@ +import { Buffer } from 'buffer'; +import { Readable } from 'stream'; + +export async function renderFromHTML(template) { + const stream = Readable.from(template) + const chunks = []; + + for await (let chunk of stream) { + chunks.push(Buffer.from(chunk)); + } + + return Buffer.concat(chunks).toString('utf-8'); +} \ No newline at end of file diff --git a/src/templates/app.html b/src/templates/app.html index 07aad60..e0b495f 100644 --- a/src/templates/app.html +++ b/src/templates/app.html @@ -2,7 +2,7 @@ - Greenwood Demo - Vercel Adapter + Greenwood Demo - Vercel Adapter + Lit SSR @@ -10,7 +10,7 @@ - +