mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 15:59:52 +03:00
tidy up package builds
This commit is contained in:
@@ -1,20 +1,20 @@
|
||||
{
|
||||
"name": "EMS-ESP",
|
||||
"version": "3.6",
|
||||
"version": "3.6.3",
|
||||
"description": "build EMS-ESP WebUI",
|
||||
"homepage": "https://emsesp.github.io/docs",
|
||||
"author": "proddy",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"build-hosted": "vite build --mode hosted",
|
||||
"preview": "vite preview",
|
||||
"preview-standalone": "npm-run-all -p preview typesafe-i18n mock-api",
|
||||
"build-hosted": "typesafe-i18n --no-watch && vite build --mode hosted",
|
||||
"preview-standalone": "typesafe-i18n --no-watch && vite build && concurrently -c \"auto\" \"npm:mock-api\" \"vite preview\"",
|
||||
"mock-api": "node --watch ../mock-api ../mock-api/server.js",
|
||||
"standalone": "npm-run-all -p dev typesafe-i18n mock-api",
|
||||
"typesafe-i18n": "typesafe-i18n",
|
||||
"standalone": "concurrently -c \"auto\" \"typesafe-i18n\" \"npm:mock-api\" \"vite\"",
|
||||
"typesafe-i18n": "typesafe-i18n --no-watch",
|
||||
"webUI": "node progmem-generator.js",
|
||||
"format": "prettier --write '**/*.{ts,tsx,js,css,json,md}'",
|
||||
"lint": "eslint . --cache --fix"
|
||||
},
|
||||
@@ -22,8 +22,8 @@
|
||||
"@alova/adapter-xhr": "^1.0.1",
|
||||
"@emotion/react": "^11.11.1",
|
||||
"@emotion/styled": "^11.11.0",
|
||||
"@mui/icons-material": "^5.14.13",
|
||||
"@mui/material": "^5.14.13",
|
||||
"@mui/icons-material": "^5.14.14",
|
||||
"@mui/material": "^5.14.14",
|
||||
"@table-library/react-table-library": "4.1.7",
|
||||
"@types/lodash-es": "^4.17.9",
|
||||
"@types/node": "^20.8.6",
|
||||
@@ -40,7 +40,7 @@
|
||||
"react-dom": "latest",
|
||||
"react-dropzone": "^14.2.3",
|
||||
"react-icons": "^4.11.0",
|
||||
"react-router-dom": "^6.16.0",
|
||||
"react-router-dom": "^6.17.0",
|
||||
"react-toastify": "^9.1.3",
|
||||
"sockette": "^2.0.6",
|
||||
"typesafe-i18n": "^5.26.2",
|
||||
@@ -51,8 +51,9 @@
|
||||
"@preact/compat": "^17.1.2",
|
||||
"@preact/preset-vite": "^2.6.0",
|
||||
"@types/babel__core": "^7",
|
||||
"@typescript-eslint/eslint-plugin": "^6.7.5",
|
||||
"@typescript-eslint/parser": "^6.7.5",
|
||||
"@typescript-eslint/eslint-plugin": "^6.8.0",
|
||||
"@typescript-eslint/parser": "^6.8.0",
|
||||
"concurrently": "^8.2.1",
|
||||
"eslint": "^8.51.0",
|
||||
"eslint-config-airbnb": "^19.0.4",
|
||||
"eslint-config-airbnb-typescript": "^17.1.0",
|
||||
@@ -64,12 +65,12 @@
|
||||
"eslint-plugin-prettier": "alpha",
|
||||
"eslint-plugin-react": "^7.33.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"preact": "^10.18.1",
|
||||
"prettier": "^3.0.3",
|
||||
"rollup-plugin-visualizer": "^5.9.2",
|
||||
"terser": "^5.21.0",
|
||||
"terser": "^5.22.0",
|
||||
"vite": "^4.4.11",
|
||||
"vite-plugin-imagemin": "^0.6.1",
|
||||
"vite-plugin-svgr": "^4.1.0",
|
||||
"vite-tsconfig-paths": "^4.2.1"
|
||||
},
|
||||
|
||||
@@ -5,6 +5,23 @@ var mime = require('mime-types');
|
||||
|
||||
const ARDUINO_INCLUDES = '#include <Arduino.h>\n\n';
|
||||
const INDENT = ' ';
|
||||
const outputPath = '../lib/framework/WWWData.h';
|
||||
const sourcePath = './build';
|
||||
const bytesPerLine = 20;
|
||||
var totalSize = 0;
|
||||
|
||||
const generateWWWClass = () =>
|
||||
`typedef std::function<void(const String& uri, const String& contentType, const uint8_t * content, size_t len)> RouteRegistrationHandler;
|
||||
|
||||
class WWWData {
|
||||
${indent}public:
|
||||
${indent.repeat(2)}static void registerRoutes(RouteRegistrationHandler handler) {
|
||||
${fileInfo
|
||||
.map((file) => `${indent.repeat(3)}handler("${file.uri}", "${file.mimeType}", ${file.variable}, ${file.size});`)
|
||||
.join('\n')}
|
||||
${indent.repeat(2)}}
|
||||
};
|
||||
`;
|
||||
|
||||
function getFilesSync(dir, files = []) {
|
||||
readdirSync(dir, { withFileTypes: true }).forEach((entry) => {
|
||||
@@ -18,10 +35,6 @@ function getFilesSync(dir, files = []) {
|
||||
return files;
|
||||
}
|
||||
|
||||
// function coherseToBuffer(input) {
|
||||
// return Buffer.isBuffer(input) ? input : Buffer.from(input);
|
||||
// }
|
||||
|
||||
function cleanAndOpen(path) {
|
||||
if (existsSync(path)) {
|
||||
unlinkSync(path);
|
||||
@@ -29,34 +42,19 @@ function cleanAndOpen(path) {
|
||||
return createWriteStream(path, { flags: 'w+' });
|
||||
}
|
||||
|
||||
export default function ProgmemGenerator({ outputPath = './WWWData.h', bytesPerLine = 20 }) {
|
||||
return {
|
||||
name: 'ProgmemGenerator',
|
||||
writeBundle: () => {
|
||||
console.log('Generating ' + outputPath);
|
||||
const includes = ARDUINO_INCLUDES;
|
||||
const indent = INDENT;
|
||||
const fileInfo = [];
|
||||
const writeStream = cleanAndOpen(resolve(outputPath));
|
||||
|
||||
try {
|
||||
const writeIncludes = () => {
|
||||
writeStream.write(includes);
|
||||
};
|
||||
|
||||
const writeFile = (relativeFilePath, buffer) => {
|
||||
const writeFile = (relativeFilePath, buffer) => {
|
||||
const variable = 'ESP_REACT_DATA_' + fileInfo.length;
|
||||
const mimeType = mime.lookup(relativeFilePath);
|
||||
var size = 0;
|
||||
writeStream.write('const uint8_t ' + variable + '[] = {');
|
||||
// const zipBuffer = zlib.brotliCompressSync(buffer, { quality: 1 });
|
||||
const zipBuffer = zlib.gzipSync(buffer);
|
||||
const zipBuffer = zlib.gzipSync(buffer, { level: 9 });
|
||||
zipBuffer.forEach((b) => {
|
||||
if (!(size % bytesPerLine)) {
|
||||
writeStream.write('\n');
|
||||
writeStream.write(indent);
|
||||
}
|
||||
writeStream.write('0x' + ('00' + b.toString(16).toUpperCase()).substr(-2) + ',');
|
||||
writeStream.write('0x' + ('00' + b.toString(16).toUpperCase()).slice(-2) + ',');
|
||||
size++;
|
||||
});
|
||||
if (size % bytesPerLine) {
|
||||
@@ -69,50 +67,33 @@ export default function ProgmemGenerator({ outputPath = './WWWData.h', bytesPerL
|
||||
variable,
|
||||
size
|
||||
});
|
||||
};
|
||||
|
||||
const writeFiles = () => {
|
||||
// process static files
|
||||
const buildPath = resolve('build');
|
||||
for (const filePath of getFilesSync(buildPath)) {
|
||||
// console.log(relativeFilePath + ' (size ' + size + ' bytes)');
|
||||
totalSize += size;
|
||||
};
|
||||
|
||||
// start
|
||||
console.log('Generating ' + outputPath + ' from ' + sourcePath);
|
||||
const includes = ARDUINO_INCLUDES;
|
||||
const indent = INDENT;
|
||||
const fileInfo = [];
|
||||
const writeStream = cleanAndOpen(resolve(outputPath));
|
||||
|
||||
// includes
|
||||
writeStream.write(includes);
|
||||
|
||||
// process static files
|
||||
const buildPath = resolve(sourcePath);
|
||||
for (const filePath of getFilesSync(buildPath)) {
|
||||
const readStream = readFileSync(filePath);
|
||||
const relativeFilePath = relative(buildPath, filePath);
|
||||
writeFile(relativeFilePath, readStream);
|
||||
}
|
||||
|
||||
// process assets
|
||||
// const { assets } = compilation;
|
||||
// Object.keys(assets).forEach((relativeFilePath) => {
|
||||
// writeFile(relativeFilePath, coherseToBuffer(assets[relativeFilePath].source()));
|
||||
// });
|
||||
};
|
||||
|
||||
const generateWWWClass = () =>
|
||||
`typedef std::function<void(const String& uri, const String& contentType, const uint8_t * content, size_t len)> RouteRegistrationHandler;
|
||||
|
||||
class WWWData {
|
||||
${indent}public:
|
||||
${indent.repeat(2)}static void registerRoutes(RouteRegistrationHandler handler) {
|
||||
${fileInfo
|
||||
.map((file) => `${indent.repeat(3)}handler("${file.uri}", "${file.mimeType}", ${file.variable}, ${file.size});`)
|
||||
.join('\n')}
|
||||
${indent.repeat(2)}}
|
||||
};
|
||||
`;
|
||||
const writeWWWClass = () => {
|
||||
writeStream.write(generateWWWClass());
|
||||
};
|
||||
|
||||
writeIncludes();
|
||||
writeFiles();
|
||||
writeWWWClass();
|
||||
|
||||
writeStream.on('finish', () => {
|
||||
// callback();
|
||||
});
|
||||
} finally {
|
||||
writeStream.end();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// add class
|
||||
writeStream.write(generateWWWClass());
|
||||
|
||||
// end
|
||||
writeStream.end();
|
||||
|
||||
console.log('Total size: ' + totalSize / 1000 + ' KB');
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"target": "ESNext",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
||||
"types": ["vite/client", "vite-plugin-svgr/client", "node"],
|
||||
"types": ["node"],
|
||||
"allowJs": false,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": false,
|
||||
@@ -26,6 +26,6 @@
|
||||
"@/*": ["src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["src/**/*", "vite.config.ts", "progmem-generator.js"],
|
||||
"include": ["src/**/*", "vite.config.ts"],
|
||||
"exclude": ["node_modules", "dist", "src/**/*.test.tsx", "src/**/*.test.ts"]
|
||||
}
|
||||
|
||||
@@ -1,58 +1,18 @@
|
||||
import { defineConfig, type PluginOption } from 'vite';
|
||||
import { defineConfig } from 'vite';
|
||||
import viteTsconfigPaths from 'vite-tsconfig-paths';
|
||||
import svgrPlugin from 'vite-plugin-svgr';
|
||||
import { visualizer } from 'rollup-plugin-visualizer';
|
||||
import ProgmemGenerator from './progmem-generator';
|
||||
import preact from '@preact/preset-vite';
|
||||
import viteImagemin from 'vite-plugin-imagemin';
|
||||
import { visualizer } from 'rollup-plugin-visualizer';
|
||||
|
||||
export default defineConfig(({ command, mode }) => {
|
||||
if (mode === 'hosted') {
|
||||
// standalone build for development - runs the server
|
||||
if (command === 'serve') {
|
||||
console.log('Building for standalone');
|
||||
return {
|
||||
// hosted, ignore all errors, output to dist
|
||||
plugins: [preact(), viteTsconfigPaths(), svgrPlugin(), visualizer({ gzipSize: true }) as PluginOption]
|
||||
};
|
||||
} else {
|
||||
// normal build
|
||||
return {
|
||||
plugins: [
|
||||
preact(),
|
||||
viteTsconfigPaths(),
|
||||
svgrPlugin(),
|
||||
ProgmemGenerator({ outputPath: '../lib/framework/WWWData.h', bytesPerLine: 20 })
|
||||
],
|
||||
|
||||
build: {
|
||||
outDir: 'build',
|
||||
chunkSizeWarningLimit: 1024,
|
||||
sourcemap: false,
|
||||
manifest: false,
|
||||
minify: mode === 'development' ? false : 'terser',
|
||||
rollupOptions: {
|
||||
/**
|
||||
* Ignore "use client" waning since we are not using SSR
|
||||
*/
|
||||
onwarn(warning, warn) {
|
||||
if (warning.code === 'MODULE_LEVEL_DIRECTIVE' && warning.message.includes(`"use client"`)) {
|
||||
return;
|
||||
}
|
||||
warn(warning);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onwarn(warning, warn) {
|
||||
if (warning.code === 'MODULE_LEVEL_DIRECTIVE') {
|
||||
return;
|
||||
}
|
||||
warn(warning);
|
||||
},
|
||||
|
||||
plugins: [preact(), viteTsconfigPaths(), visualizer()],
|
||||
server: {
|
||||
open: true,
|
||||
port: 3000,
|
||||
// watch: {
|
||||
// usePolling: true
|
||||
// },
|
||||
port: mode === 'production' ? 4173 : 3000,
|
||||
proxy: {
|
||||
'/rest': 'http://localhost:3080',
|
||||
'/api': {
|
||||
@@ -69,4 +29,98 @@ export default defineConfig(({ command, mode }) => {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// production build, both for hosted and building the firmware
|
||||
if (command === 'build') {
|
||||
console.log('Building for production, mode ' + mode);
|
||||
return {
|
||||
plugins: [
|
||||
preact(),
|
||||
viteTsconfigPaths(),
|
||||
{
|
||||
...viteImagemin({
|
||||
verbose: false,
|
||||
gifsicle: {
|
||||
optimizationLevel: 7,
|
||||
interlaced: false
|
||||
},
|
||||
optipng: {
|
||||
optimizationLevel: 7
|
||||
},
|
||||
mozjpeg: {
|
||||
quality: 20
|
||||
},
|
||||
pngquant: {
|
||||
quality: [0.8, 0.9],
|
||||
speed: 4
|
||||
},
|
||||
svgo: {
|
||||
plugins: [
|
||||
{
|
||||
name: 'removeViewBox'
|
||||
},
|
||||
{
|
||||
name: 'removeEmptyAttrs',
|
||||
active: false
|
||||
}
|
||||
]
|
||||
}
|
||||
}),
|
||||
enforce: 'pre'
|
||||
}
|
||||
],
|
||||
|
||||
build: {
|
||||
outDir: mode === 'hosted' ? 'dist' : 'build',
|
||||
reportCompressedSize: false,
|
||||
chunkSizeWarningLimit: 1024,
|
||||
sourcemap: false,
|
||||
manifest: false,
|
||||
minify: 'terser',
|
||||
terserOptions: {
|
||||
parse: {
|
||||
// parse options
|
||||
},
|
||||
compress: {
|
||||
// compress options
|
||||
passes: 4,
|
||||
arrows: true,
|
||||
drop_console: true,
|
||||
sequences: true
|
||||
},
|
||||
mangle: {
|
||||
// mangle options
|
||||
eval: true,
|
||||
properties: {
|
||||
// mangle property options
|
||||
}
|
||||
},
|
||||
format: {
|
||||
// format options (can also use `output` for backwards compatibility)
|
||||
},
|
||||
sourceMap: {
|
||||
// source map options
|
||||
},
|
||||
ecma: 5,
|
||||
enclose: false,
|
||||
keep_classnames: false,
|
||||
keep_fnames: false,
|
||||
ie8: false,
|
||||
module: false,
|
||||
nameCache: null,
|
||||
safari10: false,
|
||||
toplevel: false
|
||||
},
|
||||
rollupOptions: {
|
||||
// Ignore "use client" waning since we are not using SSR
|
||||
onwarn(warning, warn) {
|
||||
if (warning.code === 'MODULE_LEVEL_DIRECTIVE' && warning.message.includes(`"use client"`)) {
|
||||
return;
|
||||
}
|
||||
warn(warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
2866
interface/yarn.lock
2866
interface/yarn.lock
File diff suppressed because it is too large
Load Diff
@@ -1,34 +1,9 @@
|
||||
from pathlib import Path
|
||||
from shutil import copytree, rmtree, copyfileobj
|
||||
import os
|
||||
import gzip
|
||||
|
||||
# brotli has better compression than gzip but requires https so leaving here for future
|
||||
# import brotli
|
||||
|
||||
Import("env")
|
||||
|
||||
|
||||
def gzipFile(file):
|
||||
with open(file, 'rb') as f_in:
|
||||
with gzip.open(file + '.gz', 'wb') as f_out:
|
||||
copyfileobj(f_in, f_out)
|
||||
os.remove(file)
|
||||
|
||||
# brotli version:
|
||||
# with open(file + '.br', 'wb') as f_out:
|
||||
# with open(file, 'rb') as f_in:
|
||||
# f_out.write(brotli.compress(f_in.read(), quality=11))
|
||||
# os.remove(file)
|
||||
|
||||
|
||||
def flagExists(flag):
|
||||
buildFlags = env.ParseFlags(env["BUILD_FLAGS"])
|
||||
for define in buildFlags.get("CPPDEFINES"):
|
||||
if (define == flag or (isinstance(define, list) and define[0] == flag)):
|
||||
return True
|
||||
|
||||
|
||||
def buildWeb():
|
||||
os.chdir("interface")
|
||||
print("Building web interface...")
|
||||
@@ -39,23 +14,12 @@ def buildWeb():
|
||||
text = r.read().replace("Locales = 'pl'", "Locales = 'en'")
|
||||
with open("./src/i18n/i18n-util.ts", "w") as w:
|
||||
w.write(text)
|
||||
print("Setting locale to 'en'")
|
||||
print("Setting WebUI locale to 'en'")
|
||||
env.Execute("yarn run build")
|
||||
|
||||
buildPath = Path("build")
|
||||
wwwPath = Path("../data/www")
|
||||
|
||||
if wwwPath.exists() and wwwPath.is_dir():
|
||||
rmtree(wwwPath)
|
||||
|
||||
print("Copying web files from build to data/www...")
|
||||
copytree(buildPath, wwwPath)
|
||||
for currentpath, folders, files in os.walk(wwwPath):
|
||||
for file in files:
|
||||
gzipFile(os.path.join(currentpath, file))
|
||||
|
||||
env.Execute("yarn run webUI")
|
||||
finally:
|
||||
os.chdir("..")
|
||||
|
||||
|
||||
if not (env.IsCleanTarget()):
|
||||
buildWeb()
|
||||
|
||||
Reference in New Issue
Block a user