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
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}`);