atoms-element v5.0.0

#js

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
import http from 'http';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import { dirname } from 'path';
import renderPage from './pages/index.js';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const rootDir = path.join(__dirname, '..');
const port = process.argv[2] || 3000;
const elements = ['app-counter.js', 'app-total.js'];
const srcMap = {
  '/index.js': `${rootDir}/index.js`,
};
elements.forEach((el) => {
  srcMap['/elements/' + el] = `${__dirname}/elements/${el}`;
});

// lit-html and @lit-labs/ssr-client are real npm dependencies (not vendored),
// so the browser needs an import map for every bare specifier reachable from
// index.js — including ones used by their own internal files, since the
// import map is global to the page, not scoped per-package the way Node's
// node_modules resolution is. The packages' files are served as-is; their
// own internal imports are all relative, so no other wiring is needed.
const importMap = {
  imports: {
    'lit-html': '/node_modules/lit-html/lit-html.js',
    'lit-html/directive.js': '/node_modules/lit-html/directive.js',
    'lit-html/directive-helpers.js': '/node_modules/lit-html/directive-helpers.js',
    'lit-html/private-ssr-support.js': '/node_modules/lit-html/private-ssr-support.js',
    'lit-html/directives/unsafe-html.js': '/node_modules/lit-html/directives/unsafe-html.js',
    'lit-html/directives/class-map.js': '/node_modules/lit-html/directives/class-map.js',
    'lit-html/directives/style-map.js': '/node_modules/lit-html/directives/style-map.js',
    '@lit-labs/ssr-client': '/node_modules/@lit-labs/ssr-client/index.js',
  },
};
const nodeModulesDir = path.join(rootDir, 'node_modules');

http
  .createServer((req, res) => {
    if (req.url.includes('/api/posts')) {
      const parts = req.url.split('/');
      const id = parts[parts.length - 1];
      res.setHeader('Content-type', 'application/json');
      res.end(
        JSON.stringify({
          id,
          title: `post ${id}`,
          description: ` description ${id}`,
        }),
      );
      return;
    }
    if (req.url === '/') {
      res.statusCode = 200;
      res.setHeader('Content-type', 'text/html');
      const html = renderPage({
        lang: 'en',
        props: {
          config: { lang: 'en', title: 'Counter App' },
        },
        headScript: `<script type="importmap">${JSON.stringify(importMap)}</script>`,
        bodyScript: `
          <script type="module">
          ${elements.map((el) => `import './elements/${el}';`).join('\n')}
          </script>
        `,
      });
      res.end(html);
      return;
    }
    if (req.url.startsWith('/node_modules/')) {
      const relative = req.url.slice('/node_modules/'.length);
      const filename = path.normalize(path.join(nodeModulesDir, relative));
      if (filename.startsWith(nodeModulesDir) && fs.existsSync(filename)) {
        res.setHeader('Content-type', filename.endsWith('.css') ? 'text/css' : 'application/javascript');
        res.end(fs.readFileSync(filename));
      } else {
        res.statusCode = 404;
        res.end();
      }
      return;
    }
    const filename = srcMap[req.url];
    if (filename) {
      const data = fs.readFileSync(filename);
      res.setHeader('Content-type', 'application/javascript');
      res.end(data);
      return;
    }
    res.statusCode = 404;
    res.end();
  })
  .listen(parseInt(port));

console.log(`Server listening on http://localhost:${port}`);