atoms-element v5.0.0
git clone https://git.pyrossh.dev/atoms-element
A simple web component library for defining your custom elements. It works on both client and server.
examples/server.js
| a3cc1df | 1 | import http from 'http'; |
| a3cc1df | 2 | import fs from 'fs'; |
| 4c11234 | 3 | import path from 'path'; |
| a3cc1df | 4 | import { fileURLToPath } from 'url'; |
| 67e0dfd | 5 | import { dirname } from 'path'; |
| 24398b1 | 6 | import renderPage from './pages/index.js'; |
| a3cc1df | 7 | |
| a3cc1df | 8 | const __filename = fileURLToPath(import.meta.url); |
| a3cc1df | 9 | const __dirname = dirname(__filename); |
| 4c11234 | 10 | const rootDir = path.join(__dirname, '..'); |
| a3cc1df | 11 | const port = process.argv[2] || 3000; |
| 24398b1 | 12 | const elements = ['app-counter.js', 'app-total.js']; |
| 67e0dfd | 13 | const srcMap = { |
| 4c11234 | 14 | '/index.js': `${rootDir}/index.js`, |
| a3cc1df | 15 | }; |
| 24398b1 | 16 | elements.forEach((el) => { |
| 24398b1 | 17 | srcMap['/elements/' + el] = `${__dirname}/elements/${el}`; |
| 24398b1 | 18 | }); |
| a3cc1df | 19 | |
| e955350 | 20 | // lit-html and @lit-labs/ssr-client are real npm dependencies (not vendored), |
| e955350 | 21 | // so the browser needs an import map for every bare specifier reachable from |
| e955350 | 22 | // index.js — including ones used by their own internal files, since the |
| e955350 | 23 | // import map is global to the page, not scoped per-package the way Node's |
| e955350 | 24 | // node_modules resolution is. The packages' files are served as-is; their |
| e955350 | 25 | // own internal imports are all relative, so no other wiring is needed. |
| 4c11234 | 26 | const importMap = { |
| 4c11234 | 27 | imports: { |
| 4c11234 | 28 | 'lit-html': '/node_modules/lit-html/lit-html.js', |
| 25308a9 | 29 | 'lit-html/directive.js': '/node_modules/lit-html/directive.js', |
| 4c11234 | 30 | 'lit-html/directive-helpers.js': '/node_modules/lit-html/directive-helpers.js', |
| 25308a9 | 31 | 'lit-html/private-ssr-support.js': '/node_modules/lit-html/private-ssr-support.js', |
| 4c11234 | 32 | 'lit-html/directives/unsafe-html.js': '/node_modules/lit-html/directives/unsafe-html.js', |
| e955350 | 33 | 'lit-html/directives/class-map.js': '/node_modules/lit-html/directives/class-map.js', |
| e955350 | 34 | 'lit-html/directives/style-map.js': '/node_modules/lit-html/directives/style-map.js', |
| 25308a9 | 35 | '@lit-labs/ssr-client': '/node_modules/@lit-labs/ssr-client/index.js', |
| 4c11234 | 36 | }, |
| 4c11234 | 37 | }; |
| 4c11234 | 38 | const nodeModulesDir = path.join(rootDir, 'node_modules'); |
| 4c11234 | 39 | |
| a3cc1df | 40 | http |
| be4ce51 | 41 | .createServer((req, res) => { |
| 649634e | 42 | if (req.url.includes('/api/posts')) { |
| 649634e | 43 | const parts = req.url.split('/'); |
| 649634e | 44 | const id = parts[parts.length - 1]; |
| 649634e | 45 | res.setHeader('Content-type', 'application/json'); |
| 649634e | 46 | res.end( |
| 649634e | 47 | JSON.stringify({ |
| 649634e | 48 | id, |
| 649634e | 49 | title: `post ${id}`, |
| 649634e | 50 | description: ` description ${id}`, |
| 649634e | 51 | }), |
| 649634e | 52 | ); |
| 649634e | 53 | return; |
| 649634e | 54 | } |
| a3cc1df | 55 | if (req.url === '/') { |
| a3cc1df | 56 | res.statusCode = 200; |
| a3cc1df | 57 | res.setHeader('Content-type', 'text/html'); |
| 8f1fc6d | 58 | const html = renderPage({ |
| 8f1fc6d | 59 | lang: 'en', |
| 8f1fc6d | 60 | props: { |
| 8f1fc6d | 61 | config: { lang: 'en', title: 'Counter App' }, |
| 8f1fc6d | 62 | }, |
| 4c11234 | 63 | headScript: `<script type="importmap">${JSON.stringify(importMap)}</script>`, |
| a3cc1df | 64 | bodyScript: ` |
| a3cc1df | 65 | <script type="module"> |
| 24398b1 | 66 | ${elements.map((el) => `import './elements/${el}';`).join('\n')} |
| a3cc1df | 67 | </script> |
| a3cc1df | 68 | `, |
| a3cc1df | 69 | }); |
| a3cc1df | 70 | res.end(html); |
| a3cc1df | 71 | return; |
| a3cc1df | 72 | } |
| 4c11234 | 73 | if (req.url.startsWith('/node_modules/')) { |
| 4c11234 | 74 | const relative = req.url.slice('/node_modules/'.length); |
| 4c11234 | 75 | const filename = path.normalize(path.join(nodeModulesDir, relative)); |
| 4c11234 | 76 | if (filename.startsWith(nodeModulesDir) && fs.existsSync(filename)) { |
| 0000000 | 77 | res.setHeader('Content-type', filename.endsWith('.css') ? 'text/css' : 'application/javascript'); |
| 4c11234 | 78 | res.end(fs.readFileSync(filename)); |
| 4c11234 | 79 | } else { |
| 4c11234 | 80 | res.statusCode = 404; |
| 4c11234 | 81 | res.end(); |
| 4c11234 | 82 | } |
| 4c11234 | 83 | return; |
| 4c11234 | 84 | } |
| 67e0dfd | 85 | const filename = srcMap[req.url]; |
| ba5668f | 86 | if (filename) { |
| ba5668f | 87 | const data = fs.readFileSync(filename); |
| ba5668f | 88 | res.setHeader('Content-type', 'application/javascript'); |
| ba5668f | 89 | res.end(data); |
| 4c11234 | 90 | return; |
| ba5668f | 91 | } |
| 4c11234 | 92 | res.statusCode = 404; |
| 4c11234 | 93 | res.end(); |
| a3cc1df | 94 | }) |
| a3cc1df | 95 | .listen(parseInt(port)); |
| a3cc1df | 96 | |
| 67e0dfd | 97 | console.log(`Server listening on http://localhost:${port}`); |