⚡ 📺 finlizes routing and improves bs
This commit is contained in:
+10
-4
@@ -4,9 +4,6 @@ This project uses [jaandrle/bs: The simplest possible build system using executa
|
||||
## Available executables
|
||||
If it makes sense, arguments are passed to internally used commands (e.g. `tsc`), e. g. `--help`.
|
||||
|
||||
### bs/lint
|
||||
This lints the project using `tsc`.
|
||||
|
||||
### bs/test
|
||||
This lints the project and runs tests using `wtr`.
|
||||
|
||||
@@ -19,8 +16,17 @@ This builds the project using `rollup`.
|
||||
### bs/analyze
|
||||
This analyze Custom Element manifest using the `@custom-elements-manifest/analyzer`.
|
||||
|
||||
### bs/dev/assets
|
||||
Copies assets using `cp` into proper destination in `.tmp`.
|
||||
|
||||
### bs/dev/tsc
|
||||
Builds typescript files using `tsc`.
|
||||
|
||||
### bs/dev/lint
|
||||
Lints the project using `tsc`.
|
||||
|
||||
### bs/npm/lint
|
||||
Linted projects’ npm dependencies.
|
||||
Lints projects’ npm dependencies.
|
||||
|
||||
### bs/npm/update
|
||||
Updates projects’ npm dependencies.
|
||||
|
||||
+7
-3
@@ -5,8 +5,12 @@ set -eo pipefail # this can be harmful, see https://www.youtube.com/watch?v=4Jo3
|
||||
exit 1;
|
||||
}
|
||||
# depends on
|
||||
declare -r app='src/app-cfpodcasts.ts'
|
||||
declare -r cem='node_modules/.bin/cem'
|
||||
declare -r app=(
|
||||
'src/**/c-*.ts'
|
||||
'src/**/app-*/index.ts'
|
||||
'src/index.ts'
|
||||
)
|
||||
declare -r cem='node_modules/.bin/custom-elements-manifest'
|
||||
|
||||
help(){
|
||||
if ! isHelp "${@}"; then return 0; fi
|
||||
@@ -17,7 +21,7 @@ help(){
|
||||
}
|
||||
main(){
|
||||
help "${@}"
|
||||
$cem analyze --litelement --globs "$app" "${@}"
|
||||
$cem analyze --litelement --globs "${app[@]}" "${@}"
|
||||
}
|
||||
|
||||
main "${@}"
|
||||
|
||||
@@ -5,7 +5,8 @@ set -eo pipefail # this can be harmful, see https://www.youtube.com/watch?v=4Jo3
|
||||
exit 1;
|
||||
}
|
||||
# depends on
|
||||
declare -r lint='bs/lint'
|
||||
declare -r tsc='bs/dev/tsc'
|
||||
declare -r assets='bs/dev/assets'
|
||||
declare -r rollup='node_modules/.bin/rollup'
|
||||
declare -r analyze='bs/analyze'
|
||||
declare -r config='rollup.config.js'
|
||||
@@ -21,7 +22,8 @@ help(){
|
||||
main(){
|
||||
help "${@}"
|
||||
|
||||
$lint
|
||||
$tsc
|
||||
$assets
|
||||
rm -rf "$dist"
|
||||
$rollup -c $config "${@}"
|
||||
$analyze --exclude "$dist"
|
||||
|
||||
Executable
+26
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail # this can be harmful, see https://www.youtube.com/watch?v=4Jo3Ml53kvc
|
||||
. bs/.common || {
|
||||
echo 'Please run this script from the project root directory' >&2;
|
||||
exit 1;
|
||||
}
|
||||
# depends on
|
||||
declare -r paths='bs/dev/paths.js'
|
||||
declare -r assets="$($paths 'src')/**/assets"
|
||||
declare -r target="$($paths 'tscoutput')"
|
||||
|
||||
help(){
|
||||
if ! isHelp "${@}"; then return 0; fi
|
||||
echoReadmeInfo
|
||||
echo
|
||||
exit 0
|
||||
}
|
||||
main(){
|
||||
help "${@}"
|
||||
shopt -s globstar nullglob
|
||||
for dir in $assets; do
|
||||
cp -r "$dir" "$target/$dir"
|
||||
done
|
||||
}
|
||||
|
||||
main "${@}"
|
||||
@@ -6,21 +6,17 @@ set -eo pipefail # this can be harmful, see https://www.youtube.com/watch?v=4Jo3
|
||||
}
|
||||
# depends on
|
||||
declare -r tsc='node_modules/.bin/tsc'
|
||||
declare -r tscAlias='node_modules/.bin/tsc-alias'
|
||||
|
||||
help(){
|
||||
if ! isHelp "${@}"; then return 0; fi
|
||||
echoReadmeInfo
|
||||
echo
|
||||
$tsc --help
|
||||
$tscAlias --help
|
||||
exit 0
|
||||
}
|
||||
main(){
|
||||
help "${@}"
|
||||
$tsc "${@}"
|
||||
echo "$tscAlias ${@}"
|
||||
$tscAlias "${@}"
|
||||
$tsc --noEmit "${@}"
|
||||
}
|
||||
|
||||
main "${@}"
|
||||
Executable
+44
@@ -0,0 +1,44 @@
|
||||
#!/bin/env node
|
||||
import tsconfig from "../../tsconfig.json" with { type: "json" };
|
||||
export const paths = {
|
||||
/** code source */
|
||||
src: "src",
|
||||
/** code processed by tsc */
|
||||
tscoutput: tsconfig.compilerOptions.outDir,
|
||||
/** code processed by tsc and rollup */
|
||||
dist: "dist",
|
||||
/** tempral results of tsc, tests, … */
|
||||
tmp: ".tmp",
|
||||
};
|
||||
export default paths;
|
||||
|
||||
import { argv, exit } from "node:process";
|
||||
import { fileURLToPath } from "node:url";
|
||||
const [ _, script ] = argv;
|
||||
if (script === fileURLToPath(import.meta.url))
|
||||
main(argv.slice(2));
|
||||
|
||||
function main(args) {
|
||||
if(args.includes("--help") || args.includes("-h")){
|
||||
console.log(`
|
||||
Usage: ${script} [options]
|
||||
|
||||
Options:
|
||||
[type] … if omitted, echo all
|
||||
`);
|
||||
exit(0);
|
||||
}
|
||||
if(args.length === 0){
|
||||
console.log(paths);
|
||||
exit(0);
|
||||
}
|
||||
for(const arg of args){
|
||||
const path = paths[arg];
|
||||
if(!path){
|
||||
console.error(`Unknown path: ${arg}`);
|
||||
exit(1);
|
||||
}
|
||||
console.log(path);
|
||||
}
|
||||
}
|
||||
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail # this can be harmful, see https://www.youtube.com/watch?v=4Jo3Ml53kvc
|
||||
. bs/.common || {
|
||||
echo 'Please run this script from the project root directory' >&2;
|
||||
exit 1;
|
||||
}
|
||||
# depends on
|
||||
declare -r tsc='node_modules/.bin/tsc'
|
||||
declare -r tscAlias='node_modules/.bin/tsc-alias'
|
||||
|
||||
help(){
|
||||
if ! isHelp "${@}"; then return 0; fi
|
||||
echoReadmeInfo
|
||||
echo
|
||||
$tsc --help
|
||||
$tscAlias --help
|
||||
exit 0
|
||||
}
|
||||
main(){
|
||||
help "${@}"
|
||||
$tsc "${@}"
|
||||
$tscAlias "${@}"
|
||||
}
|
||||
|
||||
main "${@}"
|
||||
@@ -6,7 +6,9 @@ set -eo pipefail # this can be harmful, see https://www.youtube.com/watch?v=4Jo3
|
||||
}
|
||||
# depends on
|
||||
declare -r server='node_modules/.bin/web-dev-server'
|
||||
declare -r lint='bs/lint'
|
||||
declare -r lint='bs/dev/lint'
|
||||
declare -r tsc='bs/dev/tsc'
|
||||
declare -r assets='bs/dev/assets'
|
||||
declare -r server_config='web-dev-server.config.js'
|
||||
|
||||
help(){
|
||||
@@ -25,12 +27,14 @@ EOF
|
||||
main(){
|
||||
help "${@}"
|
||||
|
||||
$lint
|
||||
local -r target="${1:-./src}" # ./src or ./dist
|
||||
if [[ "$target" =~ 'dist' ]]; then
|
||||
# console warns because of config file, use npx serve?
|
||||
$server "${@}"
|
||||
else
|
||||
$lint --watch --preserveWatchOutput &
|
||||
$assets
|
||||
$tsc --watch --preserveWatchOutput &
|
||||
$server "${@}" &
|
||||
wait
|
||||
fi
|
||||
|
||||
@@ -5,8 +5,8 @@ set -eo pipefail # this can be harmful, see https://www.youtube.com/watch?v=4Jo3
|
||||
exit 1;
|
||||
}
|
||||
# depends on
|
||||
declare -r lint='bs/lint'
|
||||
declare -r wtr='node_modules/.bin/wtr'
|
||||
declare -r tsc='bs/dev/tsc'
|
||||
declare -r wtr='node_modules/.bin/web-test-runner'
|
||||
|
||||
help(){
|
||||
if ! isHelp "${@}"; then return 0; fi
|
||||
@@ -20,12 +20,12 @@ EOF
|
||||
main(){
|
||||
help "$1"
|
||||
if [[ "$1" != "--watch" ]]; then
|
||||
$lint
|
||||
$tsc
|
||||
$wtr "$@" --coverage
|
||||
exit
|
||||
fi
|
||||
|
||||
$lint --watch --preserveWatchOutput &
|
||||
$tsc --watch --preserveWatchOutput &
|
||||
$wtr "${*}" &
|
||||
wait
|
||||
}
|
||||
|
||||
+2
-2
@@ -5,7 +5,7 @@
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
|
||||
<meta name="Description" content="Put your description here.">
|
||||
<link rel="icon" type="image/svg+xml" href="./assets/logo.svg">
|
||||
<link rel="icon" type="image/svg+xml" href="./.tmp/tsc/src/assets/logo.svg">
|
||||
<base href="/">
|
||||
|
||||
<style>
|
||||
@@ -23,7 +23,7 @@
|
||||
<body>
|
||||
<app-cfpodcasts></app-cfpodcasts>
|
||||
|
||||
<script type="module" src="./out-tsc/src/index.js"></script>
|
||||
<script type="module" src="./.tmp/tsc/src/index.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
+6
-4
@@ -4,8 +4,10 @@ import { rollupPluginHTML as html } from "@web/rollup-plugin-html";
|
||||
import { importMetaAssets } from "@web/rollup-plugin-import-meta-assets";
|
||||
import esbuild from "rollup-plugin-esbuild";
|
||||
import { generateSW } from "rollup-plugin-workbox";
|
||||
import { paths } from "./bs/dev/paths.js";
|
||||
import { join } from "node:path";
|
||||
|
||||
const pathDist = join.bind(null, paths.dist);
|
||||
export default {
|
||||
input: "index.html",
|
||||
output: {
|
||||
@@ -13,7 +15,7 @@ export default {
|
||||
chunkFileNames: "[hash].js",
|
||||
assetFileNames: "[hash][extname]",
|
||||
format: "es",
|
||||
dir: "dist",
|
||||
dir: pathDist(),
|
||||
},
|
||||
preserveEntrySignatures: false,
|
||||
|
||||
@@ -22,7 +24,7 @@ export default {
|
||||
html({
|
||||
minify: true,
|
||||
injectServiceWorker: true,
|
||||
serviceWorkerPath: "dist/sw.js",
|
||||
serviceWorkerPath: pathDist("sw.js"),
|
||||
}),
|
||||
/** Resolve bare module imports */
|
||||
nodeResolve(),
|
||||
@@ -59,9 +61,9 @@ export default {
|
||||
globIgnores: ["polyfills/*.js", "nomodule-*.js"],
|
||||
navigateFallback: "/index.html",
|
||||
// where to output the generated sw
|
||||
swDest: join("dist", "sw.js"),
|
||||
swDest: pathDist("sw.js"),
|
||||
// directory to match patterns against to be precached
|
||||
globDirectory: join("dist"),
|
||||
globDirectory: pathDist(),
|
||||
// cache any html js and css by default
|
||||
globPatterns: ["**/*.{html,js,css,webmanifest}"],
|
||||
skipWaiting: true,
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { route } from "@/core/route.js";
|
||||
import { html } from "lit";
|
||||
|
||||
export const path = "/episodes" as const;
|
||||
export const path = "/episodes/" as const;
|
||||
export const routes = route(
|
||||
{
|
||||
path: "/episodes/:id",
|
||||
path: "/episodes/:id/",
|
||||
async enter() {
|
||||
await import("./index.js");
|
||||
return true;
|
||||
|
||||
@@ -2,7 +2,7 @@ import { route } from "@/core/route.js";
|
||||
import { routes as routeEpisode } from "./:id/routes.js";
|
||||
import { html } from "lit";
|
||||
|
||||
export const path = "/episodes" as const;
|
||||
export const path = "/episodes/" as const;
|
||||
export const routes = route(
|
||||
{
|
||||
path,
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import { css } from "lit";
|
||||
export const styles = css`
|
||||
:host {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
`;
|
||||
@@ -0,0 +1,22 @@
|
||||
import { html } from "lit";
|
||||
import { fixture, expect } from "@open-wc/testing";
|
||||
|
||||
import type { AppHome } from "./index.js";
|
||||
import "./index.js";
|
||||
|
||||
describe("AppHome", () => {
|
||||
let element: AppHome;
|
||||
beforeEach(async () => {
|
||||
element = await fixture(html`<app-home></app-home>`);
|
||||
});
|
||||
|
||||
it("renders a h1", () => {
|
||||
const h1 = element.shadowRoot!.querySelector('h1')!;
|
||||
expect(h1).to.exist;
|
||||
expect(h1.textContent).to.equal('My app');
|
||||
});
|
||||
|
||||
it("passes the a11y audit", async () => {
|
||||
await expect(element).shadowDom.to.be.accessible();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
import { LitElement, html } from "lit";
|
||||
import { customElement } from "lit/decorators.js";
|
||||
import { styles } from "./index.css.js";
|
||||
|
||||
@customElement("app-home")
|
||||
export class AppHome extends LitElement {
|
||||
static override styles = styles;
|
||||
override render() {
|
||||
return html`
|
||||
<h1>My app</h1>
|
||||
<p>Hello world</p>
|
||||
<a href="/episodes">Episode</a>
|
||||
`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { route } from "@/core/route.js";
|
||||
import { html } from "lit";
|
||||
|
||||
export const path = "/" as const;
|
||||
export const routes = route(
|
||||
{
|
||||
path,
|
||||
async enter() {
|
||||
await import("./index.js");
|
||||
return true;
|
||||
},
|
||||
render(){
|
||||
return html`<app-home></app-home>`;
|
||||
},
|
||||
},
|
||||
);
|
||||
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
+3
-1
@@ -5,9 +5,11 @@ export function route(...routes: (PathRouteConfig|PathRouteConfig[])[]): PathRou
|
||||
if (Array.isArray(route)) // already processed
|
||||
return route;
|
||||
const { path, ...rest }= route;
|
||||
if (!path.endsWith("/"))
|
||||
throw new Error("path must end with „/”!");
|
||||
return [
|
||||
{ path, ...rest },
|
||||
{ path: path + "/", rest },
|
||||
{ path: path.slice(0, -1), ...rest },
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import { html } from "lit";
|
||||
import { fixture, expect } from "@open-wc/testing";
|
||||
|
||||
import type { AppCfpodcasts } from "./index.js";
|
||||
import "./index.js";
|
||||
|
||||
describe("App", () => {
|
||||
let element: AppCfpodcasts;
|
||||
let nav: HTMLElement;
|
||||
beforeEach(async () => {
|
||||
element = await fixture(html`<app-cfpodcasts></app-cfpodcasts>`);
|
||||
nav = element.shadowRoot!.querySelector("nav")!;
|
||||
});
|
||||
|
||||
it("renders <main>", () => {
|
||||
const content = element.shadowRoot!.querySelector('main')!;
|
||||
expect(content).to.exist;
|
||||
});
|
||||
|
||||
it("has all pages", async () => {
|
||||
const links = nav.querySelectorAll("a");
|
||||
await expect(links.length).to.equal(2);
|
||||
});
|
||||
it("passes the a11y audit", async () => {
|
||||
await expect(nav).shadowDom.to.be.accessible();
|
||||
});
|
||||
});
|
||||
+4
-3
@@ -3,16 +3,17 @@ import { customElement } from "lit/decorators.js";
|
||||
import { styles } from "./index.css.js";
|
||||
import { Router } from "@lit-labs/router";
|
||||
|
||||
import * as routeHome from "./app-home/routes.js";
|
||||
import * as routeEpisodes from "./app-episodes/routes.js";
|
||||
|
||||
import "./components/c-sronly.js";
|
||||
const logo = new URL("../../assets/logo.svg", import.meta.url);
|
||||
const logo = new URL("./assets/logo.svg", import.meta.url);
|
||||
|
||||
@customElement("app-cfpodcasts")
|
||||
export class AppCfpodcasts extends LitElement {
|
||||
static override styles = styles;
|
||||
private _routes = new Router(this, [
|
||||
{ path: "/", render: () => html`Hello world` },
|
||||
...routeHome.routes,
|
||||
...routeEpisodes.routes,
|
||||
]);
|
||||
override render() {
|
||||
@@ -24,7 +25,7 @@ export class AppCfpodcasts extends LitElement {
|
||||
href="${this._routes.link("/")}"
|
||||
title="Home"
|
||||
>
|
||||
<img src=${logo} />
|
||||
<img alt="" src=${logo} />
|
||||
<c-sronly>Home</c-sronly>
|
||||
</a>
|
||||
<a
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
import { html } from 'lit';
|
||||
import { fixture, expect } from '@open-wc/testing';
|
||||
|
||||
import type { AppCfpodcasts } from '../src/index.js';
|
||||
import '../src/index.js';
|
||||
|
||||
describe('AppCfpodcasts', () => {
|
||||
let element: AppCfpodcasts;
|
||||
beforeEach(async () => {
|
||||
element = await fixture(html`<app-cfpodcasts></app-cfpodcasts>`);
|
||||
});
|
||||
|
||||
it('renders a h1', () => {
|
||||
const h1 = element.shadowRoot!.querySelector('h1')!;
|
||||
expect(h1).to.exist;
|
||||
expect(h1.textContent).to.equal('My app');
|
||||
});
|
||||
|
||||
it('passes the a11y audit', async () => {
|
||||
await expect(element).shadowDom.to.be.accessible();
|
||||
});
|
||||
});
|
||||
+1
-1
@@ -26,7 +26,7 @@
|
||||
|
||||
"noErrorTruncation": false,
|
||||
|
||||
"outDir": "out-tsc",
|
||||
"outDir": ".tmp/tsc",
|
||||
"sourceMap": true,
|
||||
"inlineSources": true,
|
||||
"rootDir": "./",
|
||||
|
||||
@@ -3,14 +3,18 @@
|
||||
/** Use Hot Module replacement by adding --watch to the start command */
|
||||
//const hmr = process.argv.includes("--watch");
|
||||
const [ mode ] = process.argv.slice(2);
|
||||
import { paths } from "./bs/dev/paths.js";
|
||||
import { join } from "node:path";
|
||||
|
||||
const pathDist = join.bind(null, paths.dist);
|
||||
const target = mode !== "dist" // OR "src"
|
||||
? {
|
||||
rootDir: ".",
|
||||
appIndex: "./index.html",
|
||||
appIndex: "index.html",
|
||||
}
|
||||
: {
|
||||
rootDir: "./dist",
|
||||
appIndex: "./dist/index.html",
|
||||
rootDir: pathDist(),
|
||||
appIndex: pathDist("index.html"),
|
||||
};
|
||||
|
||||
export default /** @type {import("@web/dev-server").DevServerConfig} */ ({
|
||||
|
||||
+35
-29
@@ -1,41 +1,47 @@
|
||||
// import { playwrightLauncher } from '@web/test-runner-playwright';
|
||||
|
||||
const filteredLogs = ['Running in dev mode', 'Lit is in dev mode'];
|
||||
const filteredLogs = ["Running in dev mode", "Lit is in dev mode"];
|
||||
import { paths } from "./bs/dev/paths.js";
|
||||
import { join } from "node:path";
|
||||
|
||||
export default /** @type {import("@web/test-runner").TestRunnerConfig} */ ({
|
||||
/** Test files to run */
|
||||
files: 'out-tsc/test/**/*.test.js',
|
||||
/** Test files to run */
|
||||
files: join(paths.tscoutput, "src/**/*.test.js"),
|
||||
|
||||
/** Resolve bare module imports */
|
||||
nodeResolve: {
|
||||
exportConditions: ['browser', 'development'],
|
||||
},
|
||||
/** Resolve bare module imports */
|
||||
nodeResolve: {
|
||||
exportConditions: ["browser", "development"],
|
||||
},
|
||||
|
||||
/** Filter out lit dev mode logs */
|
||||
filterBrowserLogs(log) {
|
||||
for (const arg of log.args) {
|
||||
if (typeof arg === 'string' && filteredLogs.some(l => arg.includes(l))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
/** Filter out lit dev mode logs */
|
||||
filterBrowserLogs(log) {
|
||||
for (const arg of log.args) {
|
||||
if (typeof arg === "string" && filteredLogs.some(l => arg.includes(l))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
/** Compile JS for older browsers. Requires @web/dev-server-esbuild plugin */
|
||||
// esbuildTarget: 'auto',
|
||||
coverageConfig: {
|
||||
reportDir: join(paths.tmp, "coverage"),
|
||||
},
|
||||
|
||||
/** Amount of browsers to run concurrently */
|
||||
// concurrentBrowsers: 2,
|
||||
/** Compile JS for older browsers. Requires @web/dev-server-esbuild plugin */
|
||||
// esbuildTarget: 'auto',
|
||||
|
||||
/** Amount of test files per browser to test concurrently */
|
||||
// concurrency: 1,
|
||||
/** Amount of browsers to run concurrently */
|
||||
// concurrentBrowsers: 2,
|
||||
|
||||
/** Browsers to run tests on */
|
||||
// browsers: [
|
||||
// playwrightLauncher({ product: 'chromium' }),
|
||||
// playwrightLauncher({ product: 'firefox' }),
|
||||
// playwrightLauncher({ product: 'webkit' }),
|
||||
// ],
|
||||
/** Amount of test files per browser to test concurrently */
|
||||
// concurrency: 1,
|
||||
|
||||
// See documentation for all available options
|
||||
/** Browsers to run tests on */
|
||||
// browsers: [
|
||||
// playwrightLauncher({ product: 'chromium' }),
|
||||
// playwrightLauncher({ product: 'firefox' }),
|
||||
// playwrightLauncher({ product: 'webkit' }),
|
||||
// ],
|
||||
|
||||
// See documentation for all available options
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user