Use TS with gulp

This commit is contained in:
Wendelin 2025-05-09 08:23:53 +02:00
parent e1b099e88b
commit ff3b65605e
No known key found for this signature in database
33 changed files with 325 additions and 200 deletions

View File

@ -1,13 +1,13 @@
const path = require("path");
const env = require("./env.cjs");
const paths = require("./paths.cjs");
const { dependencies } = require("../package.json");
import path from "path";
import { dependencies } from "../package.json";
import env from "./env";
import paths from "./paths";
const BABEL_PLUGINS = path.join(__dirname, "babel-plugins");
// GitHub base URL to use for production source maps
// Nightly builds use the commit SHA, otherwise assumes there is a tag that matches the version
module.exports.sourceMapURL = () => {
export const sourceMapURL = () => {
const ref = env.version().endsWith("dev")
? process.env.GITHUB_SHA || "dev"
: env.version();
@ -15,10 +15,10 @@ module.exports.sourceMapURL = () => {
};
// Files from NPM Packages that should not be imported
module.exports.ignorePackages = () => [];
export const ignorePackages = () => [];
// Files from NPM packages that we should replace with empty file
module.exports.emptyPackages = ({ isHassioBuild }) =>
export const emptyPackages = ({ isHassioBuild }) =>
[
require.resolve("@vaadin/vaadin-material-styles/typography.js"),
require.resolve("@vaadin/vaadin-material-styles/font-icons.js"),
@ -33,7 +33,7 @@ module.exports.emptyPackages = ({ isHassioBuild }) =>
),
].filter(Boolean);
module.exports.definedVars = ({ isProdBuild, latestBuild, defineOverlay }) => ({
export const definedVars = ({ isProdBuild, latestBuild, defineOverlay }) => ({
__DEV__: !isProdBuild,
__BUILD__: JSON.stringify(latestBuild ? "modern" : "legacy"),
__VERSION__: JSON.stringify(env.version()),
@ -53,7 +53,7 @@ module.exports.definedVars = ({ isProdBuild, latestBuild, defineOverlay }) => ({
...defineOverlay,
});
module.exports.htmlMinifierOptions = {
export const htmlMinifierOptions = {
caseSensitive: true,
collapseWhitespace: true,
conservativeCollapse: true,
@ -65,7 +65,7 @@ module.exports.htmlMinifierOptions = {
},
};
module.exports.terserOptions = ({ latestBuild, isTestBuild }) => ({
export const terserOptions = ({ latestBuild, isTestBuild }) => ({
safari10: !latestBuild,
ecma: latestBuild ? 2015 : 5,
module: latestBuild,
@ -74,7 +74,7 @@ module.exports.terserOptions = ({ latestBuild, isTestBuild }) => ({
});
/** @type {import('@rspack/core').SwcLoaderOptions} */
module.exports.swcOptions = () => ({
export const swcOptions = () => ({
jsc: {
loose: true,
externalHelpers: true,
@ -86,7 +86,7 @@ module.exports.swcOptions = () => ({
},
});
module.exports.babelOptions = ({
export const babelOptions = ({
latestBuild,
isProdBuild,
isTestBuild,
@ -221,7 +221,7 @@ const publicPath = (latestBuild, root = "") =>
}
*/
module.exports.config = {
export const config = {
app({ isProdBuild, latestBuild, isStatsBuild, isTestBuild, isWDS }) {
return {
name: "frontend" + nameSuffix(latestBuild),
@ -273,6 +273,7 @@ module.exports.config = {
};
if (latestBuild) {
// @ts-ignore
entry.receiver = path.resolve(
paths.cast_dir,
"src/receiver/entrypoint.ts"

View File

@ -1,10 +1,10 @@
const fs = require("fs");
const path = require("path");
const paths = require("./paths.cjs");
import fs from "fs";
import path from "path";
import paths from "./paths";
const isTrue = (value) => value === "1" || value?.toLowerCase() === "true";
module.exports = {
export default {
isProdBuild() {
return (
process.env.NODE_ENV === "production" || module.exports.isStatsBuild()

View File

@ -1,19 +1,20 @@
// eslint-disable-next-line import/no-extraneous-dependencies
import gulp from "gulp";
import env from "../env.cjs";
import "./clean.js";
import "./compress.js";
import "./entry-html.js";
import "./gather-static.js";
import "./gen-icons-json.js";
import "./locale-data.js";
import "./service-worker.js";
import "./translations.js";
import "./rspack.js";
import "./clean.ts";
import "./compress.ts";
import env from "../env";
import "./entry-html.ts";
import "./gather-static.ts";
import "./gen-icons-json.ts";
import "./locale-data.ts";
import "./rspack.ts";
import "./service-worker.ts";
import "./translations.ts";
gulp.task(
"develop-app",
gulp.series(
async function setEnv() {
async () => {
process.env.NODE_ENV = "development";
},
"clean",
@ -32,7 +33,7 @@ gulp.task(
gulp.task(
"build-app",
gulp.series(
async function setEnv() {
async () => {
process.env.NODE_ENV = "production";
},
"clean",
@ -48,7 +49,7 @@ gulp.task(
gulp.task(
"analyze-app",
gulp.series(
async function setEnv() {
async () => {
process.env.STATS = "1";
},
"clean",

View File

@ -1,15 +1,16 @@
/* eslint-disable import/no-extraneous-dependencies */
import gulp from "gulp";
import "./clean.js";
import "./entry-html.js";
import "./gather-static.js";
import "./service-worker.js";
import "./translations.js";
import "./rspack.js";
import "./clean.ts";
import "./entry-html.ts";
import "./gather-static.ts";
import "./rspack.ts";
import "./service-worker.ts";
import "./translations.ts";
gulp.task(
"develop-cast",
gulp.series(
async function setEnv() {
async () => {
process.env.NODE_ENV = "development";
},
"clean-cast",
@ -24,7 +25,7 @@ gulp.task(
gulp.task(
"build-cast",
gulp.series(
async function setEnv() {
async () => {
process.env.NODE_ENV = "production";
},
"clean-cast",

View File

@ -1,6 +1,6 @@
import { deleteSync } from "del";
import gulp from "gulp";
import paths from "../paths.cjs";
import paths from "../paths";
import "./translations.js";
gulp.task(

View File

@ -1,10 +1,10 @@
// Tasks to compress
import { constants } from "node:zlib";
import gulp from "gulp";
import brotli from "gulp-brotli";
import zopfli from "gulp-zopfli-green";
import paths from "../paths.cjs";
import { constants } from "node:zlib";
import paths from "../paths";
const filesGlob = "*.{js,json,css,svg,xml}";
const brotliOptions = {

View File

@ -1,10 +1,10 @@
import { LokaliseApi } from "@lokalise/node-api";
import fs from "fs/promises";
import gulp from "gulp";
import path from "path";
import mapStream from "map-stream";
import transform from "gulp-json-transform";
import { LokaliseApi } from "@lokalise/node-api";
import JSZip from "jszip";
import mapStream from "map-stream";
import path from "path";
const inDir = "translations";
const inDirFrontend = `${inDir}/frontend`;
@ -16,7 +16,7 @@ function hasHtml(data) {
return /<\S*>/i.test(data);
}
function recursiveCheckHasHtml(file, data, errors, recKey) {
function recursiveCheckHasHtml(file, data, errors: string[], recKey?: string) {
Object.keys(data).forEach(function (key) {
if (typeof data[key] === "object") {
const nextRecKey = recKey ? `${recKey}.${key}` : key;
@ -80,7 +80,7 @@ gulp.task("check-translations-html", function () {
gulp.task("check-all-files-exist", async function () {
const file = await fs.readFile(srcMeta, { encoding });
const meta = JSON.parse(file);
const writings = [];
const writings: Promise<void>[] = [];
Object.keys(meta).forEach((lang) => {
writings.push(
fs.writeFile(`${inDirFrontend}/${lang}.json`, JSON.stringify({}), {

View File

@ -10,8 +10,8 @@ import gulp from "gulp";
import { minify } from "html-minifier-terser";
import template from "lodash.template";
import { dirname, extname, resolve } from "node:path";
import { htmlMinifierOptions, terserOptions } from "../bundle.cjs";
import paths from "../paths.cjs";
import { htmlMinifierOptions, terserOptions } from "../bundle";
import paths from "../paths";
// macOS companion app has no way to obtain the Safari version used by WKWebView,
// and it is not in the default user agent string. So we add an additional regex
@ -36,7 +36,7 @@ const getCommonTemplateVars = () => {
});
const minSafariVersion = browserRegexes.find(
(regex) => regex.family === "safari"
)?.matchedVersions[0][0];
)?.matchedVersions[0][0] ?? 18;
const minMacOSVersion = SAFARI_TO_MACOS[minSafariVersion];
if (!minMacOSVersion) {
throw Error(
@ -106,10 +106,10 @@ const genPagesDevTask =
resolve(inputRoot, inputSub, `${page}.template`),
{
...commonVars,
latestEntryJS: entries.map(
latestEntryJS: (entries as string[]).map(
(entry) => `${publicRoot}/frontend_latest/${entry}.js`
),
es5EntryJS: entries.map(
es5EntryJS: (entries as string[]).map(
(entry) => `${publicRoot}/frontend_es5/${entry}.js`
),
latestCustomPanelJS: `${publicRoot}/frontend_latest/custom-panel.js`,
@ -128,7 +128,7 @@ const genPagesProdTask =
inputRoot,
outputRoot,
outputLatest,
outputES5,
outputES5?: string,
inputSub = "src/html"
) =>
async () => {
@ -139,14 +139,14 @@ const genPagesProdTask =
? fs.readJsonSync(resolve(outputES5, "manifest.json"))
: {};
const commonVars = getCommonTemplateVars();
const minifiedHTML = [];
const minifiedHTML: Promise<void>[] = [];
for (const [page, entries] of Object.entries(pageEntries)) {
const content = renderTemplate(
resolve(inputRoot, inputSub, `${page}.template`),
{
...commonVars,
latestEntryJS: entries.map((entry) => latestManifest[`${entry}.js`]),
es5EntryJS: entries.map((entry) => es5Manifest[`${entry}.js`]),
latestEntryJS: (entries as string[]).map((entry) => latestManifest[`${entry}.js`]),
es5EntryJS: (entries as string[]).map((entry) => es5Manifest[`${entry}.js`]),
latestCustomPanelJS: latestManifest["custom-panel.js"],
es5CustomPanelJS: es5Manifest["custom-panel.js"],
}

View File

@ -54,7 +54,7 @@ gulp.task("fetch-nightly-translations", async function () {
// To store file writing promises
const createExtractDir = mkdir(EXTRACT_DIR, { recursive: true });
const writings = [];
const writings: Promise<void>[] = [];
// Authenticate to GitHub using GitHub action token if it exists,
// otherwise look for a saved user token or generate a new one if none
@ -87,7 +87,7 @@ gulp.task("fetch-nightly-translations", async function () {
});
tokenAuth = await auth({ type: "oauth" });
writings.push(
createExtractDir.then(
createExtractDir.then(() =>
writeFile(TOKEN_FILE, JSON.stringify(tokenAuth, null, 2))
)
);
@ -131,13 +131,13 @@ gulp.task("fetch-nightly-translations", async function () {
throw Error("Latest nightly workflow run has no translations artifact");
}
writings.push(
createExtractDir.then(
createExtractDir.then(() =>
writeFile(ARTIFACT_FILE, JSON.stringify(latestArtifact, null, 2))
)
);
// Remove the current translations
const deleteCurrent = Promise.all(writings).then(
const deleteCurrent = Promise.all(writings).then(() =>
deleteAsync([`${EXTRACT_DIR}/*`, `!${ARTIFACT_FILE}`, `!${TOKEN_FILE}`])
);
@ -148,13 +148,14 @@ gulp.task("fetch-nightly-translations", async function () {
artifact_id: latestArtifact.id,
archive_format: "zip",
});
// @ts-ignore
if (downloadResponse.status !== 200) {
throw Error("Failure downloading translations artifact");
}
// Artifact is a tarball, but GitHub adds it to a zip file
console.log("Unpacking downloaded translations...");
const zip = await jszip.loadAsync(downloadResponse.data);
const zip = await jszip.loadAsync(downloadResponse.data as any);
await deleteCurrent;
const extractStream = zip.file(/.*/)[0].nodeStream().pipe(extract());
await new Promise((resolve, reject) => {

View File

@ -4,14 +4,14 @@ import gulp from "gulp";
import yaml from "js-yaml";
import { marked } from "marked";
import path from "path";
import paths from "../paths.cjs";
import paths from "../paths";
import "./clean.js";
import "./entry-html.js";
import "./gather-static.js";
import "./gen-icons-json.js";
import "./rspack";
import "./service-worker.js";
import "./translations.js";
import "./rspack.js";
gulp.task("gather-gallery-pages", async function gatherPages() {
const pageDir = path.resolve(paths.gallery_dir, "src/pages");
@ -22,7 +22,7 @@ gulp.task("gather-gallery-pages", async function gatherPages() {
let content = "export const PAGES = {\n";
const processed = new Set();
const processed = new Set<string>();
for (const file of files) {
if (fs.lstatSync(file).isDirectory()) {
@ -47,7 +47,9 @@ gulp.task("gather-gallery-pages", async function gatherPages() {
if (descriptionContent.startsWith("---")) {
const metadataEnd = descriptionContent.indexOf("---", 3);
metadata = yaml.load(descriptionContent.substring(3, metadataEnd));
metadata = yaml.load(
descriptionContent.substring(3, metadataEnd)
) as any;
descriptionContent = descriptionContent
.substring(metadataEnd + 3)
.trim();
@ -57,7 +59,9 @@ gulp.task("gather-gallery-pages", async function gatherPages() {
if (descriptionContent === "") {
hasDescription = false;
} else {
descriptionContent = marked(descriptionContent).replace(/`/g, "\\`");
// eslint-disable-next-line no-await-in-loop
descriptionContent = await marked(descriptionContent);
descriptionContent = descriptionContent.replace(/`/g, "\\`");
fs.mkdirSync(path.resolve(galleryBuild, category), { recursive: true });
fs.writeFileSync(
path.resolve(galleryBuild, `${pageId}-description.ts`),
@ -95,7 +99,7 @@ gulp.task("gather-gallery-pages", async function gatherPages() {
pagesToProcess[category].add(page);
}
for (const group of Object.values(sidebar)) {
for (const group of Object.values(sidebar) as Array<{ category: string; pages?: string[] }>) {
const toProcess = pagesToProcess[group.category];
delete pagesToProcess[group.category];
@ -118,7 +122,7 @@ gulp.task("gather-gallery-pages", async function gatherPages() {
group.pages = [];
}
for (const page of Array.from(toProcess).sort()) {
group.pages.push(page);
group.pages.push(page as string);
}
}
@ -126,7 +130,7 @@ gulp.task("gather-gallery-pages", async function gatherPages() {
sidebar.push({
category,
header: category,
pages: Array.from(pages).sort(),
pages: Array.from(pages as Set<string>).sort(),
});
}

View File

@ -3,7 +3,7 @@
import fs from "fs-extra";
import gulp from "gulp";
import path from "path";
import paths from "../paths.cjs";
import paths from "../paths";
const npmPath = (...parts) =>
path.resolve(paths.root_dir, "node_modules", ...parts);

View File

@ -2,7 +2,7 @@ import fs from "fs";
import gulp from "gulp";
import hash from "object-hash";
import path from "path";
import paths from "../paths.cjs";
import paths from "../paths";
const ICON_PACKAGE_PATH = path.resolve("node_modules/@mdi/svg/");
const META_PATH = path.resolve(ICON_PACKAGE_PATH, "meta.json");
@ -21,7 +21,7 @@ const getMeta = () => {
encoding,
});
return {
path: svg.match(/ d="([^"]+)"/)[1],
path: svg.match(/ d="([^"]+)"/)?.[1],
name: icon.name,
tags: icon.tags,
aliases: icon.aliases,
@ -55,14 +55,14 @@ const orderMeta = (meta) => {
};
const splitBySize = (meta) => {
const chunks = [];
const chunks: any[] = [];
const CHUNK_SIZE = 50000;
let curSize = 0;
let startKey;
let icons = [];
let icons: any[] = [];
Object.values(meta).forEach((icon) => {
Object.values(meta).forEach((icon: any) => {
if (startKey === undefined) {
startKey = icon.name;
}
@ -94,7 +94,7 @@ const findDifferentiator = (curString, prevString) => {
return curString.substring(0, i + 1);
}
}
throw new Error("Cannot find differentiator", curString, prevString);
throw new Error(`Cannot find differentiator; ${curString}; ${prevString}`);
};
gulp.task("gen-icons-json", (done) => {
@ -106,7 +106,7 @@ gulp.task("gen-icons-json", (done) => {
if (!fs.existsSync(OUTPUT_DIR)) {
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
}
const parts = [];
const parts: any[] = [];
let lastEnd;
split.forEach((chunk) => {

View File

@ -1,12 +1,12 @@
import gulp from "gulp";
import env from "../env.cjs";
import env from "../env";
import "./clean.js";
import "./compress.js";
import "./entry-html.js";
import "./gather-static.js";
import "./gen-icons-json.js";
import "./translations.js";
import "./rspack.js";
import "./translations.js";
gulp.task(
"develop-hassio",

View File

@ -1,17 +0,0 @@
import "./app.js";
import "./cast.js";
import "./clean.js";
import "./compress.js";
import "./demo.js";
import "./download-translations.js";
import "./entry-html.js";
import "./fetch-nightly-translations.js";
import "./gallery.js";
import "./gather-static.js";
import "./gen-icons-json.js";
import "./hassio.js";
import "./landing-page.js";
import "./locale-data.js";
import "./rspack.js";
import "./service-worker.js";
import "./translations.js";

View File

@ -0,0 +1,17 @@
import "./app.ts";
import "./cast.ts";
import "./clean.ts";
import "./compress.ts";
import "./demo.ts";
import "./download-translations.ts";
import "./entry-html.ts";
import "./fetch-nightly-translations.ts";
import "./gallery.ts";
import "./gather-static.ts";
import "./gen-icons-json.ts";
import "./hassio.ts";
import "./landing-page.ts";
import "./locale-data.ts";
import "./rspack.ts";
import "./service-worker.ts";
import "./translations.ts";

View File

@ -4,8 +4,8 @@ import "./compress.js";
import "./entry-html.js";
import "./gather-static.js";
import "./gen-icons-json.js";
import "./translations.js";
import "./rspack.js";
import "./translations.js";
gulp.task(
"develop-landing-page",

View File

@ -2,7 +2,7 @@ import { deleteSync } from "del";
import { mkdir, readFile, writeFile } from "fs/promises";
import gulp from "gulp";
import { join, resolve } from "node:path";
import paths from "../paths.cjs";
import paths from "../paths";
const formatjsDir = join(paths.root_dir, "node_modules", "@formatjs");
const outDir = join(paths.build_dir, "locale-data");
@ -31,7 +31,7 @@ const convertToJSON = async (
join(formatjsDir, pkg, subDir, `${language}.js`),
"utf-8"
);
} catch (e) {
} catch (e: any) {
// Ignore if language is missing (i.e. not supported by @formatjs)
if (e.code === "ENOENT" && skipMissing) {
console.warn(`Skipped missing data for language ${lang} from ${pkg}`);
@ -63,7 +63,7 @@ gulp.task("create-locale-data", async () => {
"utf-8"
)
);
const conversions = [];
const conversions: any[] = [];
for (const pkg of Object.keys(INTL_POLYFILLS)) {
// eslint-disable-next-line no-await-in-loop
await mkdir(join(outDir, pkg), { recursive: true });

View File

@ -1,13 +1,13 @@
// Tasks to run rspack.
import fs from "fs";
import path from "path";
import log from "fancy-log";
import gulp from "gulp";
import rspack from "@rspack/core";
import { RspackDevServer } from "@rspack/dev-server";
import env from "../env.cjs";
import paths from "../paths.cjs";
import log from "fancy-log";
import fs from "fs";
import gulp from "gulp";
import path from "path";
import env from "../env";
import paths from "../paths";
import {
createAppConfig,
createCastConfig,
@ -15,7 +15,7 @@ import {
createGalleryConfig,
createHassioConfig,
createLandingPageConfig,
} from "../rspack.cjs";
} from "../rspack";
const bothBuilds = (createConfigFunc, params) => [
createConfigFunc({ ...params, latestBuild: true }),
@ -29,6 +29,14 @@ const isWsl =
.toLocaleLowerCase()
.includes("microsoft");
interface RunDevServer {
compiler: any;
contentBase: string;
port: number;
listenHost?: string;
proxy: any;
}
/**
* @param {{
* compiler: import("@rspack/core").Compiler,
@ -43,7 +51,7 @@ const runDevServer = async ({
port,
listenHost = undefined,
proxy = undefined,
}) => {
}: RunDevServer) => {
if (listenHost === undefined) {
// For dev container, we need to listen on all hosts
listenHost = env.isDevContainer() ? "0.0.0.0" : "localhost";
@ -68,7 +76,7 @@ const runDevServer = async ({
log("[rspack-dev-server]", `Project is running at http://localhost:${port}`);
};
const doneHandler = (done) => (err, stats) => {
const doneHandler = (done?: (value?: unknown) => void) => (err, stats) => {
if (err) {
log.error(err.stack || err);
if (err.details) {

View File

@ -5,7 +5,7 @@ import gulp from "gulp";
import { mkdir, readFile, symlink, writeFile } from "node:fs/promises";
import { basename, join, relative } from "node:path";
import { injectManifest } from "workbox-build";
import paths from "../paths.cjs";
import paths from "../paths";
const SW_MAP = {
[paths.app_output_latest]: "modern",

View File

@ -1,3 +1,4 @@
/* eslint-disable import/no-extraneous-dependencies */
/* eslint-disable max-classes-per-file */
import { deleteAsync } from "del";
@ -10,9 +11,9 @@ import { mkdir, readFile } from "node:fs/promises";
import { basename, join } from "node:path";
import { PassThrough, Transform } from "node:stream";
import { finished } from "node:stream/promises";
import env from "../env.cjs";
import paths from "../paths.cjs";
import "./fetch-nightly-translations.js";
import env from "../env";
import paths from "../paths";
import "./fetch-nightly-translations.ts";
const inFrontendDir = "translations/frontend";
const inBackendDir = "translations/backend";
@ -111,11 +112,12 @@ const testReviver = (_key, value) =>
const KEY_REFERENCE = /\[%key:([^%]+)%\]/;
const lokaliseTransform = (data, path, original = data) => {
const output = {};
for (const [key, value] of Object.entries(data)) {
for (const entry of Object.entries(data)) {
const [key, value] = entry as [string, string];
if (typeof value === "object") {
output[key] = lokaliseTransform(value, path, original);
} else {
output[key] = value.replace(KEY_REFERENCE, (_match, lokalise_key) => {
output[key] = value?.replace(KEY_REFERENCE, (_match, lokalise_key) => {
const replace = lokalise_key.split("::").reduce((tr, k) => {
if (!tr) {
throw Error(`Invalid key placeholder ${lokalise_key} in ${path}`);
@ -248,7 +250,7 @@ const createTranslations = async () => {
for (const translationFile of translationFiles) {
const locale = basename(translationFile, ".json");
const subtags = locale.split("-");
const mergeFiles = [];
const mergeFiles: string[] = [];
for (let i = 1; i <= subtags.length; i++) {
const lang = subtags.slice(0, i).join("-");
if (lang === TEST_LOCALE) {

View File

@ -1,14 +1,17 @@
#!/usr/bin/env node
// Script to print Babel plugins and Core JS polyfills that will be used by browserslist environments
/* eslint-disable import/no-extraneous-dependencies */
/* eslint-disable no-console */
import { version as babelVersion } from "@babel/core";
import presetEnv from "@babel/preset-env";
import compilationTargets from "@babel/helper-compilation-targets";
import coreJSCompat from "core-js-compat";
// eslint-disable-next-line import/extensions
import { logPlugin } from "@babel/preset-env/lib/debug.js";
// eslint-disable-next-line import/no-relative-packages
// eslint-disable-next-line import/no-relative-packages, import/extensions
import shippedPolyfills from "../node_modules/babel-plugin-polyfill-corejs3/lib/shipped-proposals.js";
import { babelOptions } from "./bundle.cjs";
import { babelOptions } from "./bundle";
const detailsOpen = (heading) =>
`<details>\n<summary><h4>${heading}</h4></summary>\n`;
@ -49,6 +52,12 @@ for (const buildType of ["Modern", "Legacy"]) {
const browserslistEnv = buildType.toLowerCase();
const babelOpts = babelOptions({ latestBuild: browserslistEnv === "modern" });
const presetEnvOpts = babelOpts.presets[0][1];
if (typeof presetEnvOpts !== "object") {
throw new Error(
"The first preset in babelOptions is not an object. This is unexpected."
);
}
// Invoking preset-env in debug mode will log the included plugins
console.log(detailsOpen(`${buildType} Build Babel Plugins`));

View File

@ -1,6 +1,6 @@
const path = require("path");
import path from "path";
module.exports = {
export default {
root_dir: path.resolve(__dirname, ".."),
build_dir: path.resolve(__dirname, "../build"),

View File

@ -1,20 +1,17 @@
const { existsSync } = require("fs");
const path = require("path");
const rspack = require("@rspack/core");
// eslint-disable-next-line @typescript-eslint/naming-convention
const { RsdoctorRspackPlugin } = require("@rsdoctor/rspack-plugin");
// eslint-disable-next-line @typescript-eslint/naming-convention
const { StatsWriterPlugin } = require("webpack-stats-plugin");
const filterStats = require("@bundle-stats/plugin-webpack-filter");
// eslint-disable-next-line @typescript-eslint/naming-convention
const TerserPlugin = require("terser-webpack-plugin");
// eslint-disable-next-line @typescript-eslint/naming-convention
const { WebpackManifestPlugin } = require("rspack-manifest-plugin");
const log = require("fancy-log");
// eslint-disable-next-line @typescript-eslint/naming-convention
const WebpackBar = require("webpackbar/rspack");
const paths = require("./paths.cjs");
const bundle = require("./bundle.cjs");
/* eslint-disable import/no-extraneous-dependencies */
/* eslint-disable import/no-import-module-exports */
import filterStats from "@bundle-stats/plugin-webpack-filter";
import { RsdoctorRspackPlugin } from "@rsdoctor/rspack-plugin";
import * as rspack from "@rspack/core";
import log from "fancy-log";
import { existsSync } from "fs";
import path from "path";
import { WebpackManifestPlugin } from "rspack-manifest-plugin";
import TerserPlugin from "terser-webpack-plugin";
import { StatsWriterPlugin } from "webpack-stats-plugin";
import WebpackBar from "webpackbar/rspack";
import * as bundle from "./bundle";
import * as paths from "./paths";
class LogStartCompilePlugin {
ignoredFirst = false;
@ -30,7 +27,7 @@ class LogStartCompilePlugin {
}
}
const createRspackConfig = ({
export const createRspackConfig = ({
name,
entry,
outputPath,
@ -263,7 +260,7 @@ const createRspackConfig = ({
};
};
const createAppConfig = ({
export const createAppConfig = ({
isProdBuild,
latestBuild,
isStatsBuild,
@ -273,15 +270,15 @@ const createAppConfig = ({
bundle.config.app({ isProdBuild, latestBuild, isStatsBuild, isTestBuild })
);
const createDemoConfig = ({ isProdBuild, latestBuild, isStatsBuild }) =>
export const createDemoConfig = ({ isProdBuild, latestBuild, isStatsBuild }) =>
createRspackConfig(
bundle.config.demo({ isProdBuild, latestBuild, isStatsBuild })
);
const createCastConfig = ({ isProdBuild, latestBuild }) =>
export const createCastConfig = ({ isProdBuild, latestBuild }) =>
createRspackConfig(bundle.config.cast({ isProdBuild, latestBuild }));
const createHassioConfig = ({
export const createHassioConfig = ({
isProdBuild,
latestBuild,
isStatsBuild,
@ -296,18 +293,8 @@ const createHassioConfig = ({
})
);
const createGalleryConfig = ({ isProdBuild, latestBuild }) =>
export const createGalleryConfig = ({ isProdBuild, latestBuild }) =>
createRspackConfig(bundle.config.gallery({ isProdBuild, latestBuild }));
const createLandingPageConfig = ({ isProdBuild, latestBuild }) =>
createRspackConfig(bundle.config.landingPage({ isProdBuild, latestBuild }));
module.exports = {
createAppConfig,
createDemoConfig,
createCastConfig,
createHassioConfig,
createGalleryConfig,
createRspackConfig,
createLandingPageConfig,
};
export const createLandingPageConfig = ({ isProdBuild, latestBuild }) =>
createRspackConfig(bundle.config.landingPage({ isProdBuild, latestBuild }));

View File

@ -54,15 +54,6 @@ export default tseslint.config(
},
},
},
settings: {
"import/resolver": {
webpack: {
config: "./rspack.config.cjs",
},
},
},
rules: {
"class-methods-use-this": "off",
"new-cap": "off",

View File

@ -1,4 +0,0 @@
import { availableParallelism } from "node:os";
import "./build-scripts/gulp/index.mjs";
process.env.UV_THREADPOOL_SIZE = availableParallelism();

4
gulpfile.ts Normal file
View File

@ -0,0 +1,4 @@
import { availableParallelism } from "node:os";
import "./build-scripts/gulp/index.ts";
process.env.UV_THREADPOOL_SIZE = availableParallelism().toString();

View File

@ -20,7 +20,8 @@
"prepack": "pinst --disable",
"postpack": "pinst --enable",
"test": "vitest run --config test/vitest.config.ts",
"test:coverage": "vitest run --config test/vitest.config.ts --coverage"
"test:coverage": "vitest run --config test/vitest.config.ts --coverage",
"gulp": "node --import ./ts-node-register.js node_modules/gulp/bin/gulp.js"
},
"author": "Paulus Schoutsen <Paulus@PaulusSchoutsen.nl> (http://paulusschoutsen.nl)",
"license": "Apache-2.0",
@ -175,6 +176,7 @@
"@types/lodash.merge": "4.6.9",
"@types/luxon": "3.6.2",
"@types/mocha": "10.0.10",
"@types/node": "22.15.16",
"@types/qrcode": "1.5.5",
"@types/sortablejs": "1.15.8",
"@types/tar": "6.1.13",
@ -188,7 +190,6 @@
"eslint": "9.26.0",
"eslint-config-airbnb-base": "15.0.0",
"eslint-config-prettier": "10.1.2",
"eslint-import-resolver-webpack": "0.13.10",
"eslint-plugin-import": "2.31.0",
"eslint-plugin-lit": "2.1.1",
"eslint-plugin-lit-a11y": "4.1.4",
@ -218,6 +219,7 @@
"tar": "7.4.3",
"terser-webpack-plugin": "5.3.14",
"ts-lit-plugin": "2.0.2",
"ts-node": "10.9.2",
"typescript": "5.8.3",
"typescript-eslint": "8.31.1",
"vite-tsconfig-paths": "5.1.4",

View File

@ -1,28 +0,0 @@
/* eslint-disable @typescript-eslint/no-require-imports */
// Needs to remain CommonJS until eslint-import-resolver-webpack supports ES modules
const rspack = require("./build-scripts/rspack.cjs");
const env = require("./build-scripts/env.cjs");
// This file exists because we haven't migrated the stats script yet
const configs = [
rspack.createAppConfig({
isProdBuild: env.isProdBuild(),
isStatsBuild: env.isStatsBuild(),
isTestBuild: env.isTestBuild(),
latestBuild: true,
}),
];
if (env.isProdBuild() && !env.isStatsBuild()) {
configs.push(
rspack.createAppConfig({
isProdBuild: env.isProdBuild(),
isStatsBuild: env.isStatsBuild(),
isTestBuild: env.isTestBuild(),
latestBuild: false,
})
);
}
module.exports = configs;

5
ts-node-register.js Normal file
View File

@ -0,0 +1,5 @@
// ts-node-register.js
import { register } from "node:module";
import { pathToFileURL } from "node:url";
register("ts-node/esm", pathToFileURL("./"));

View File

@ -78,5 +78,8 @@
"./node_modules/@lit-labs/observers/resize-controller.js"
]
}
},
"ts-node": {
"esm": true
}
}

144
yarn.lock
View File

@ -1253,6 +1253,15 @@ __metadata:
languageName: node
linkType: hard
"@cspotcode/source-map-support@npm:^0.8.0":
version: 0.8.1
resolution: "@cspotcode/source-map-support@npm:0.8.1"
dependencies:
"@jridgewell/trace-mapping": "npm:0.3.9"
checksum: 10/b6e38a1712fab242c86a241c229cf562195aad985d0564bd352ac404be583029e89e93028ffd2c251d2c407ecac5fb0cbdca94a2d5c10f29ac806ede0508b3ff
languageName: node
linkType: hard
"@csstools/color-helpers@npm:^5.0.2":
version: 5.0.2
resolution: "@csstools/color-helpers@npm:5.0.2"
@ -2053,7 +2062,7 @@ __metadata:
languageName: node
linkType: hard
"@jridgewell/resolve-uri@npm:^3.1.0":
"@jridgewell/resolve-uri@npm:^3.0.3, @jridgewell/resolve-uri@npm:^3.1.0":
version: 3.1.2
resolution: "@jridgewell/resolve-uri@npm:3.1.2"
checksum: 10/97106439d750a409c22c8bff822d648f6a71f3aa9bc8e5129efdc36343cd3096ddc4eeb1c62d2fe48e9bdd4db37b05d4646a17114ecebd3bbcacfa2de51c3c1d
@ -2084,6 +2093,16 @@ __metadata:
languageName: node
linkType: hard
"@jridgewell/trace-mapping@npm:0.3.9":
version: 0.3.9
resolution: "@jridgewell/trace-mapping@npm:0.3.9"
dependencies:
"@jridgewell/resolve-uri": "npm:^3.0.3"
"@jridgewell/sourcemap-codec": "npm:^1.4.10"
checksum: 10/83deafb8e7a5ca98993c2c6eeaa93c270f6f647a4c0dc00deb38c9cf9b2d3b7bf15e8839540155247ef034a052c0ec4466f980bf0c9e2ab63b97d16c0cedd3ff
languageName: node
linkType: hard
"@jridgewell/trace-mapping@npm:^0.3.23, @jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25":
version: 0.3.25
resolution: "@jridgewell/trace-mapping@npm:0.3.25"
@ -4186,6 +4205,34 @@ __metadata:
languageName: node
linkType: hard
"@tsconfig/node10@npm:^1.0.7":
version: 1.0.11
resolution: "@tsconfig/node10@npm:1.0.11"
checksum: 10/51fe47d55fe1b80ec35e6e5ed30a13665fd3a531945350aa74a14a1e82875fb60b350c2f2a5e72a64831b1b6bc02acb6760c30b3738b54954ec2dea82db7a267
languageName: node
linkType: hard
"@tsconfig/node12@npm:^1.0.7":
version: 1.0.11
resolution: "@tsconfig/node12@npm:1.0.11"
checksum: 10/5ce29a41b13e7897a58b8e2df11269c5395999e588b9a467386f99d1d26f6c77d1af2719e407621412520ea30517d718d5192a32403b8dfcc163bf33e40a338a
languageName: node
linkType: hard
"@tsconfig/node14@npm:^1.0.0":
version: 1.0.3
resolution: "@tsconfig/node14@npm:1.0.3"
checksum: 10/19275fe80c4c8d0ad0abed6a96dbf00642e88b220b090418609c4376e1cef81bf16237bf170ad1b341452feddb8115d8dd2e5acdfdea1b27422071163dc9ba9d
languageName: node
linkType: hard
"@tsconfig/node16@npm:^1.0.2":
version: 1.0.4
resolution: "@tsconfig/node16@npm:1.0.4"
checksum: 10/202319785901f942a6e1e476b872d421baec20cf09f4b266a1854060efbf78cde16a4d256e8bc949d31e6cd9a90f1e8ef8fb06af96a65e98338a2b6b0de0a0ff
languageName: node
linkType: hard
"@tsparticles/basic@npm:^3.7.1":
version: 3.8.1
resolution: "@tsparticles/basic@npm:3.8.1"
@ -4688,6 +4735,15 @@ __metadata:
languageName: node
linkType: hard
"@types/node@npm:22.15.16":
version: 22.15.16
resolution: "@types/node@npm:22.15.16"
dependencies:
undici-types: "npm:~6.21.0"
checksum: 10/d8055a0ab033ed16368109183f7e11d5364e5d8d5bd9a12df7fa1673a624823aaaaa54c0afef1648d0bfa7e12ef20b600f9d006accebecdb9931d2b72d05c7be
languageName: node
linkType: hard
"@types/node@npm:^18.15.3":
version: 18.19.86
resolution: "@types/node@npm:18.19.86"
@ -5474,7 +5530,7 @@ __metadata:
languageName: node
linkType: hard
"acorn-walk@npm:8.3.4, acorn-walk@npm:^8.0.0":
"acorn-walk@npm:8.3.4, acorn-walk@npm:^8.0.0, acorn-walk@npm:^8.1.1":
version: 8.3.4
resolution: "acorn-walk@npm:8.3.4"
dependencies:
@ -5483,7 +5539,7 @@ __metadata:
languageName: node
linkType: hard
"acorn@npm:^8.0.4, acorn@npm:^8.10.0, acorn@npm:^8.11.0, acorn@npm:^8.14.0, acorn@npm:^8.5.0, acorn@npm:^8.8.2":
"acorn@npm:^8.0.4, acorn@npm:^8.10.0, acorn@npm:^8.11.0, acorn@npm:^8.14.0, acorn@npm:^8.4.1, acorn@npm:^8.5.0, acorn@npm:^8.8.2":
version: 8.14.1
resolution: "acorn@npm:8.14.1"
bin:
@ -5708,6 +5764,13 @@ __metadata:
languageName: node
linkType: hard
"arg@npm:^4.1.0":
version: 4.1.3
resolution: "arg@npm:4.1.3"
checksum: 10/969b491082f20cad166649fa4d2073ea9e974a4e5ac36247ca23d2e5a8b3cb12d60e9ff70a8acfe26d76566c71fd351ee5e6a9a6595157eb36f92b1fd64e1599
languageName: node
linkType: hard
"argparse@npm:^2.0.1":
version: 2.0.1
resolution: "argparse@npm:2.0.1"
@ -6910,6 +6973,13 @@ __metadata:
languageName: node
linkType: hard
"create-require@npm:^1.1.0":
version: 1.1.1
resolution: "create-require@npm:1.1.1"
checksum: 10/a9a1503d4390d8b59ad86f4607de7870b39cad43d929813599a23714831e81c520bddf61bcdd1f8e30f05fd3a2b71ae8538e946eb2786dc65c2bbc520f692eff
languageName: node
linkType: hard
"crelt@npm:^1.0.5":
version: 1.0.6
resolution: "crelt@npm:1.0.6"
@ -7296,6 +7366,13 @@ __metadata:
languageName: node
linkType: hard
"diff@npm:^4.0.1":
version: 4.0.2
resolution: "diff@npm:4.0.2"
checksum: 10/ec09ec2101934ca5966355a229d77afcad5911c92e2a77413efda5455636c4cf2ce84057e2d7715227a2eeeda04255b849bd3ae3a4dd22eb22e86e76456df069
languageName: node
linkType: hard
"diff@npm:^7.0.0":
version: 7.0.0
resolution: "diff@npm:7.0.0"
@ -9444,6 +9521,7 @@ __metadata:
"@types/lodash.merge": "npm:4.6.9"
"@types/luxon": "npm:3.6.2"
"@types/mocha": "npm:10.0.10"
"@types/node": "npm:22.15.16"
"@types/qrcode": "npm:1.5.5"
"@types/sortablejs": "npm:1.15.8"
"@types/tar": "npm:6.1.13"
@ -9533,6 +9611,7 @@ __metadata:
terser-webpack-plugin: "npm:5.3.14"
tinykeys: "npm:3.0.0"
ts-lit-plugin: "npm:2.0.2"
ts-node: "npm:10.9.2"
typescript: "npm:5.8.3"
typescript-eslint: "npm:8.31.1"
ua-parser-js: "npm:2.0.3"
@ -11168,6 +11247,13 @@ __metadata:
languageName: node
linkType: hard
"make-error@npm:^1.1.1":
version: 1.3.6
resolution: "make-error@npm:1.3.6"
checksum: 10/b86e5e0e25f7f777b77fabd8e2cbf15737972869d852a22b7e73c17623928fccb826d8e46b9951501d3f20e51ad74ba8c59ed584f610526a48f8ccf88aaec402
languageName: node
linkType: hard
"make-fetch-happen@npm:^14.0.3":
version: 14.0.3
resolution: "make-fetch-happen@npm:14.0.3"
@ -14551,6 +14637,44 @@ __metadata:
languageName: node
linkType: hard
"ts-node@npm:10.9.2":
version: 10.9.2
resolution: "ts-node@npm:10.9.2"
dependencies:
"@cspotcode/source-map-support": "npm:^0.8.0"
"@tsconfig/node10": "npm:^1.0.7"
"@tsconfig/node12": "npm:^1.0.7"
"@tsconfig/node14": "npm:^1.0.0"
"@tsconfig/node16": "npm:^1.0.2"
acorn: "npm:^8.4.1"
acorn-walk: "npm:^8.1.1"
arg: "npm:^4.1.0"
create-require: "npm:^1.1.0"
diff: "npm:^4.0.1"
make-error: "npm:^1.1.1"
v8-compile-cache-lib: "npm:^3.0.1"
yn: "npm:3.1.1"
peerDependencies:
"@swc/core": ">=1.2.50"
"@swc/wasm": ">=1.2.50"
"@types/node": "*"
typescript: ">=2.7"
peerDependenciesMeta:
"@swc/core":
optional: true
"@swc/wasm":
optional: true
bin:
ts-node: dist/bin.js
ts-node-cwd: dist/bin-cwd.js
ts-node-esm: dist/bin-esm.js
ts-node-script: dist/bin-script.js
ts-node-transpile-only: dist/bin-transpile.js
ts-script: dist/bin-script-deprecated.js
checksum: 10/a91a15b3c9f76ac462f006fa88b6bfa528130dcfb849dd7ef7f9d640832ab681e235b8a2bc58ecde42f72851cc1d5d4e22c901b0c11aa51001ea1d395074b794
languageName: node
linkType: hard
"ts-simple-type@npm:2.0.0-next.0, ts-simple-type@npm:~2.0.0-next.0":
version: 2.0.0-next.0
resolution: "ts-simple-type@npm:2.0.0-next.0"
@ -15002,6 +15126,13 @@ __metadata:
languageName: node
linkType: hard
"v8-compile-cache-lib@npm:^3.0.1":
version: 3.0.1
resolution: "v8-compile-cache-lib@npm:3.0.1"
checksum: 10/88d3423a52b6aaf1836be779cab12f7016d47ad8430dffba6edf766695e6d90ad4adaa3d8eeb512cc05924f3e246c4a4ca51e089dccf4402caa536b5e5be8961
languageName: node
linkType: hard
"v8flags@npm:^4.0.0":
version: 4.0.1
resolution: "v8flags@npm:4.0.1"
@ -16264,6 +16395,13 @@ __metadata:
languageName: node
linkType: hard
"yn@npm:3.1.1":
version: 3.1.1
resolution: "yn@npm:3.1.1"
checksum: 10/2c487b0e149e746ef48cda9f8bad10fc83693cd69d7f9dcd8be4214e985de33a29c9e24f3c0d6bcf2288427040a8947406ab27f7af67ee9456e6b84854f02dd6
languageName: node
linkType: hard
"yocto-queue@npm:^0.1.0":
version: 0.1.0
resolution: "yocto-queue@npm:0.1.0"