Replace Makefile w/ something that reads the libs metadata

Fixes #122
This commit is contained in:
Jonathan Hornung 2025-08-15 08:57:49 +02:00
commit b8d8f545b0
5 changed files with 616 additions and 301 deletions

285
Makefile
View file

@ -1,285 +0,0 @@
# Pin WASM build to a version known to work
WASM_BUILD_URL=https://files.openscad.org/playground/OpenSCAD-2025.03.25.wasm24456-WebAssembly-web.zip
# WASM_SNAPSHOT_JS_URL=https://files.openscad.org/snapshots/.snapshot_wasm.js
# WASM_BUILD_URL=$(shell curl ${WASM_SNAPSHOT_JS_URL} 2>/dev/null | grep https | sed -E "s/.*(https:[^']+)'.*/\1/" )
SINGLE_BRANCH_MAIN=--branch main --single-branch
SINGLE_BRANCH=--branch master --single-branch
SHALLOW=--depth 1
SHELL:=/usr/bin/env bash
WASM_BUILD=Release
all: public
.PHONY: public wasm
public: \
src/wasm \
public/openscad.js \
public/openscad.wasm \
public/libraries/fonts.zip \
public/libraries/openscad.zip \
public/libraries/NopSCADlib.zip \
public/libraries/BOSL.zip \
public/libraries/BOSL2.zip \
public/libraries/boltsparts.zip \
public/libraries/OpenSCAD-Snippet.zip \
public/libraries/funcutils.zip \
public/libraries/FunctionalOpenSCAD.zip \
public/libraries/YAPP_Box.zip \
public/libraries/MCAD.zip \
public/libraries/smooth-prim.zip \
public/libraries/plot-function.zip \
public/libraries/openscad-tray.zip \
public/libraries/closepoints.zip \
public/libraries/Stemfie_OpenSCAD.zip \
public/libraries/pathbuilder.zip \
public/libraries/openscad_attachable_text3d.zip \
public/libraries/brailleSCAD.zip \
public/libraries/UB.scad.zip \
public/libraries/lasercut.zip
clean:
rm -fR libs build
rm -fR public/openscad.{js,wasm}
rm -fR public/libraries/*.zip
rm -fR src/wasm
dist/index.js: public
npm run build
dist/openscad-worker.js: src/openscad-worker.ts src/wasm/openscad.js
npx rollup -c
src/wasm: libs/openscad-wasm
rm -f src/wasm
ln -sf "$(shell pwd)/libs/openscad-wasm" src/wasm
wasm: libs/openscad
( cd libs/openscad && ./scripts/wasm-base-docker-run.sh emcmake cmake -B build -DCMAKE_BUILD_TYPE=$(WASM_BUILD) -DEXPERIMENTAL=1 )
( cd libs/openscad && ./scripts/wasm-base-docker-run.sh /bin/bash -c "cmake --build build -j || cmake --build build -j2 || cmake --build build" )
mkdir -p libs/openscad-wasm
cp libs/openscad/build/openscad.* libs/openscad-wasm/
libs/openscad-wasm:
mkdir -p libs/openscad-wasm
wget ${WASM_BUILD_URL} -O libs/openscad-wasm.zip
( cd libs/openscad-wasm && unzip ../openscad-wasm.zip )
public/openscad.js: libs/openscad-wasm libs/openscad-wasm/openscad.js
ln -sf libs/openscad-wasm/openscad.js public/openscad.js
public/openscad.wasm: libs/openscad-wasm libs/openscad-wasm/openscad.wasm
ln -sf libs/openscad-wasm/openscad.wasm public/openscad.wasm
# Var w/ noto fonts
NOTO_FONTS=\
libs/noto/NotoNaskhArabic-Bold.ttf \
libs/noto/NotoNaskhArabic-Regular.ttf \
libs/noto/NotoSans-Bold.ttf \
libs/noto/NotoSans-Italic.ttf \
libs/noto/NotoSans-Regular.ttf \
libs/noto/NotoSansArmenian-Bold.ttf \
libs/noto/NotoSansArmenian-Regular.ttf \
libs/noto/NotoSansBalinese-Regular.ttf \
libs/noto/NotoSansBengali-Bold.ttf \
libs/noto/NotoSansBengali-Regular.ttf \
libs/noto/NotoSansDevanagari-Bold.ttf \
libs/noto/NotoSansDevanagari-Regular.ttf \
libs/noto/NotoSansEthiopic-Bold.ttf \
libs/noto/NotoSansEthiopic-Regular.ttf \
libs/noto/NotoSansGeorgian-Bold.ttf \
libs/noto/NotoSansGeorgian-Regular.ttf \
libs/noto/NotoSansGujarati-Bold.ttf \
libs/noto/NotoSansGujarati-Regular.ttf \
libs/noto/NotoSansGurmukhi-Bold.ttf \
libs/noto/NotoSansGurmukhi-Regular.ttf \
libs/noto/NotoSansHebrew-Bold.ttf \
libs/noto/NotoSansHebrew-Regular.ttf \
libs/noto/NotoSansJavanese-Regular.ttf \
libs/noto/NotoSansKannada-Bold.ttf \
libs/noto/NotoSansKannada-Regular.ttf \
libs/noto/NotoSansKhmer-Bold.ttf \
libs/noto/NotoSansKhmer-Regular.ttf \
libs/noto/NotoSansLao-Bold.ttf \
libs/noto/NotoSansLao-Regular.ttf \
libs/noto/NotoSansMongolian-Regular.ttf \
libs/noto/NotoSansMyanmar-Bold.ttf \
libs/noto/NotoSansMyanmar-Regular.ttf \
libs/noto/NotoSansOriya-Bold.ttf \
libs/noto/NotoSansOriya-Regular.ttf \
libs/noto/NotoSansSinhala-Bold.ttf \
libs/noto/NotoSansSinhala-Regular.ttf \
libs/noto/NotoSansTamil-Bold.ttf \
libs/noto/NotoSansTamil-Regular.ttf \
libs/noto/NotoSansThai-Bold.ttf \
libs/noto/NotoSansThai-Regular.ttf \
libs/noto/NotoSansTibetan-Bold.ttf \
libs/noto/NotoSansTibetan-Regular.ttf \
libs/noto/NotoSansTifinagh-Regular.ttf \
# Way too big for now, also can't make them work yet:
# libs/noto/NotoSansCJKtc-Bold.otf
# libs/noto/NotoSansCJKtc-Regular.otf
public/libraries/fonts.zip: $(NOTO_FONTS) libs/liberation
mkdir -p public/libraries
zip -r $@ -j fonts.conf libs/noto/*.ttf libs/liberation/{*.ttf,LICENSE,AUTHORS}
libs/noto/%.ttf:
mkdir -p libs/noto
wget https://github.com/openmaptiles/fonts/raw/master/noto-sans/$(notdir $@) -O $@
libs/noto/%.otf:
mkdir -p libs/noto
wget https://github.com/openmaptiles/fonts/raw/master/noto-sans/$(notdir $@) -O $@
libs/liberation:
git clone --recurse https://github.com/shantigilbert/liberation-fonts-ttf.git ${SHALLOW} ${SINGLE_BRANCH} $@
libs/openscad:
git clone --recurse https://github.com/openscad/openscad.git ${SHALLOW} ${SINGLE_BRANCH} $@
public/libraries/openscad.zip: libs/openscad
mkdir -p public/libraries
( cd libs/openscad ; zip -r - `find examples -name '*.scad' | grep -v tests` ) > public/libraries/openscad.zip
libs/BOSL2:
git clone --recurse https://github.com/BelfrySCAD/BOSL2.git ${SHALLOW} ${SINGLE_BRANCH} $@
public/libraries/BOSL2.zip: libs/BOSL2
mkdir -p public/libraries
( cd libs/BOSL2 ; zip -r ../../public/libraries/BOSL2.zip *.scad LICENSE examples )
libs/BOSL:
git clone --recurse https://github.com/revarbat/BOSL.git ${SHALLOW} ${SINGLE_BRANCH} $@
public/libraries/BOSL.zip: libs/BOSL
mkdir -p public/libraries
( cd libs/BOSL ; zip -r ../../public/libraries/BOSL.zip *.scad LICENSE )
libs/NopSCADlib:
git clone --recurse https://github.com/nophead/NopSCADlib.git ${SHALLOW} ${SINGLE_BRANCH} $@
public/libraries/NopSCADlib.zip: libs/NopSCADlib
mkdir -p public/libraries
( cd libs/NopSCADlib ; zip -r ../../public/libraries/NopSCADlib.zip `find . -name '*.scad'` COPYING )
libs/funcutils:
git clone --recurse https://github.com/thehans/funcutils.git ${SHALLOW} ${SINGLE_BRANCH} $@
public/libraries/funcutils.zip: libs/funcutils
mkdir -p public/libraries
( cd libs/funcutils ; zip -r ../../public/libraries/funcutils.zip *.scad LICENSE )
libs/FunctionalOpenSCAD:
git clone --recurse https://github.com/thehans/FunctionalOpenSCAD.git ${SHALLOW} ${SINGLE_BRANCH} $@
public/libraries/FunctionalOpenSCAD.zip: libs/FunctionalOpenSCAD
mkdir -p public/libraries
( cd libs/FunctionalOpenSCAD ; zip -r ../../public/libraries/FunctionalOpenSCAD.zip *.scad LICENSE )
libs/YAPP_Box:
git clone --recurse https://github.com/mrWheel/YAPP_Box.git ${SHALLOW} ${SINGLE_BRANCH_MAIN} $@
public/libraries/YAPP_Box.zip: libs/YAPP_Box
mkdir -p public/libraries
( cd libs/YAPP_Box ; zip -r ../../public/libraries/YAPP_Box.zip `find . -name '*.scad'` LICENSE )
libs/MCAD:
git clone --recurse https://github.com/openscad/MCAD.git ${SHALLOW} ${SINGLE_BRANCH} $@
public/libraries/MCAD.zip: libs/MCAD
mkdir -p public/libraries
( cd libs/MCAD ; zip -r ../../public/libraries/MCAD.zip *.scad bitmap/*.scad LICENSE )
libs/boltsparts:
git clone --recurse https://github.com/boltsparts/boltsparts.git ${SHALLOW} ${SINGLE_BRANCH_MAIN} $@
public/libraries/boltsparts.zip: libs/boltsparts
mkdir -p public/libraries
( cd libs/boltsparts/openscad ; zip -r ../../../public/libraries/boltsparts.zip `find . -name '*.scad' | grep -v tests` ../LICENSE )
libs/OpenSCAD-Snippet:
git clone --recurse https://github.com/AngeloNicoli/OpenSCAD-Snippet.git ${SHALLOW} ${SINGLE_BRANCH_MAIN} $@
public/libraries/OpenSCAD-Snippet.zip: libs/OpenSCAD-Snippet
mkdir -p public/libraries
( cd libs/OpenSCAD-Snippet ; zip -r ../../public/libraries/OpenSCAD-Snippet.zip `find . -name '*.scad'` LICENSE )
libs/Stemfie_OpenSCAD:
git clone --recurse https://github.com/Cantareus/Stemfie_OpenSCAD.git ${SHALLOW} ${SINGLE_BRANCH_MAIN} $@
public/libraries/Stemfie_OpenSCAD.zip: libs/Stemfie_OpenSCAD
mkdir -p public/libraries
( cd libs/Stemfie_OpenSCAD ; zip -r ../../public/libraries/Stemfie_OpenSCAD.zip *.scad LICENSE )
libs/pathbuilder:
git clone --recurse https://github.com/dinther/pathbuilder.git ${SHALLOW} ${SINGLE_BRANCH_MAIN} $@
public/libraries/pathbuilder.zip: libs/pathbuilder
mkdir -p public/libraries
( cd libs/pathbuilder ; zip -r ../../public/libraries/pathbuilder.zip *.scad demo/*.scad LICENSE )
libs/openscad_attachable_text3d:
git clone --recurse https://github.com/jon-gilbert/openscad_attachable_text3d.git ${SHALLOW} ${SINGLE_BRANCH_MAIN} $@
public/libraries/openscad_attachable_text3d.zip: libs/openscad_attachable_text3d
mkdir -p public/libraries
( cd libs/openscad_attachable_text3d ; zip -r ../../public/libraries/openscad_attachable_text3d.zip *.scad LICENSE )
libs/brailleSCAD:
git clone --recurse https://github.com/BelfrySCAD/brailleSCAD.git ${SHALLOW} ${SINGLE_BRANCH_MAIN} $@
public/libraries/brailleSCAD.zip: libs/brailleSCAD
mkdir -p public/libraries
( cd libs/brailleSCAD ; zip -r ../../public/libraries/brailleSCAD.zip *.scad LICENSE )
# libs/threads:
# git clone --recurse https://github.com/rcolyer/threads.git ${SHALLOW} ${SINGLE_BRANCH} $@
# public/libraries/threads.zip: libs/threads
# mkdir -p public/libraries
# ( cd libs/threads ; zip -r ../../public/libraries/threads.zip *.scad LICENSE.txt )
libs/smooth-prim:
git clone --recurse https://github.com/rcolyer/smooth-prim.git ${SHALLOW} ${SINGLE_BRANCH} $@
public/libraries/smooth-prim.zip: libs/smooth-prim
mkdir -p public/libraries
( cd libs/smooth-prim ; zip -r ../../public/libraries/smooth-prim.zip *.scad LICENSE.txt )
libs/plot-function:
git clone --recurse https://github.com/rcolyer/plot-function.git ${SHALLOW} ${SINGLE_BRANCH} $@
public/libraries/plot-function.zip: libs/plot-function
mkdir -p public/libraries
( cd libs/plot-function ; zip -r ../../public/libraries/plot-function.zip *.scad LICENSE.txt )
libs/closepoints:
git clone --recurse https://github.com/rcolyer/closepoints.git ${SHALLOW} ${SINGLE_BRANCH} $@
public/libraries/closepoints.zip: libs/closepoints
mkdir -p public/libraries
( cd libs/closepoints ; zip -r ../../public/libraries/closepoints.zip *.scad LICENSE.txt )
libs/UB.scad:
git clone --recurse https://github.com/UBaer21/UB.scad.git ${SHALLOW} ${SINGLE_BRANCH_MAIN} $@
public/libraries/UB.scad.zip: libs/UB.scad
mkdir -p public/libraries
( cd libs/UB.scad ; zip -r ../../public/libraries/UB.scad.zip libraries/*.scad LICENSE examples/UBexamples )
libs/openscad-tray:
git clone --recurse https://github.com/sofian/openscad-tray.git ${SHALLOW} ${SINGLE_BRANCH_MAIN} $@
public/libraries/openscad-tray.zip: libs/openscad-tray
mkdir -p public/libraries
( cd libs/openscad-tray ; zip -r ../../public/libraries/openscad-tray.zip *.scad LICENSE )
libs/lasercut:
git clone --recurse https://github.com/bmsleight/lasercut.git ${SHALLOW} ${SINGLE_BRANCH} $@
public/libraries/lasercut.zip: libs/lasercut
mkdir -p public/libraries
( cd libs/lasercut ; zip -r ../../public/libraries/lasercut.zip *.scad LICENSE )

View file

@ -36,7 +36,7 @@ Licenses: see [LICENSES](./LICENSE).
- Animation rendering (And other formats than STL)
- [x] Compress URL fragment
- [x] Mobile (iOS) editing support: switch to https://www.npmjs.com/package/react-codemirror ?
- [ ] Replace Makefile w/ something that reads the libs metadata
- [x] Replace Makefile w/ something that reads the libs metadata
- [ ] Merge modifiers rendering code to openscad
- Model /home fs in shared state. have two clear paths: /libraries for builtins, and /home for user data. State pointing to /libraries paths needs not store the data except if there's overrides (flagged as modifications in the file picker)
- Drag and drop of files (SCAD, STL, etc) and Zip archives. For assets, auto insert the corresponding import.
@ -49,10 +49,12 @@ Licenses: see [LICENSES](./LICENSE).
## Building
Prerequisites:
* wget
* GNU make
* wget or curl
* Node.js (>=18.12.0)
* npm
* Docker able to run amd64 containers. If running on a different platform (including Silicon Mac), you can add support for amd64 images through QEMU with:
* git
* zip
* Docker able to run amd64 containers (only needed if building WASM from source). If running on a different platform (including Silicon Mac), you can add support for amd64 images through QEMU with:
```bash
docker run --privileged --rm tonistiigi/binfmt --install all
@ -61,27 +63,26 @@ Prerequisites:
Local dev:
```bash
make public
npm run build:libs # Download WASM and build all OpenSCAD libraries
npm install
npm start
npm run start
# http://localhost:4000/
```
Local prod (test both the different inlining and serving under a prefix):
```bash
make public
npm run build:libs # Download WASM and build all OpenSCAD libraries
npm install
npm run start:prod
npm run start:production
# http://localhost:3000/dist/
```
Deployment (edit "homepage" in `package.json` to match your deployment root!):
```bash
make public
npm run build:all # Build libraries and compile the application
npm install
NODE_ENV=production npm run build
rm -fR ../ochafik.github.io/openscad2 && cp -R dist ../ochafik.github.io/openscad2
# Now commit and push changes, wait for site update and enjoy!
@ -104,24 +105,45 @@ rm -fR ../ochafik.github.io/openscad2 && cp -R dist ../ochafik.github.io/opensca
- Build WASM binary (add `WASM_BUILD=Debug` argument if you'd like to debug any cryptic crashes):
```bash
make wasm
npm run build:libs:wasm
```
- Then continue the build:
```bash
make public
npm start
npm run build:libs
npm run start
```
## Adding OpenSCAD libraries
You'll need to update 3 files (search for BOSL2 for an example):
- [Makefile](./Makefile): to pull the library's code (optionally alias some files for easier imports) and package it as a `.zip` archive
- [libs-config.json](./libs-config.json): to add the library's metadata including repository URL, branch, and files to include/exclude in the zip archive
- [src/fs/zip-archives.ts](./src/fs/zip-archives.ts): to use the `.zip` archive in the UI (both for file explorer and automatic imports mounting)
- [LICENSE.md](./LICENSE.md): most libraries require proper disclosure of their usage and of their license. If a license is unique, paste it in full, otherwise, link to one of the standard ones already there.
### Library Configuration Format
In `libs-config.json`, add an entry like this:
```json
{
"name": "LibraryName",
"repo": "https://github.com/user/repo.git",
"branch": "main",
"zipIncludes": ["*.scad", "LICENSE", "examples"],
"zipExcludes": ["**/tests/**"],
"workingDir": "."
}
```
Available build commands:
- `npm run build:libs` - Build all libraries
- `npm run build:libs:clean` - Clean all build artifacts
- `npm run build:libs:wasm` - Download/build just the WASM binary
- `npm run build:libs:fonts` - Download/build just the fonts
Send us a PR, then once it's merged request an update to the hosted https://ochafik.com/openscad2 demo.

324
build-libs.js Executable file
View file

@ -0,0 +1,324 @@
#!/usr/bin/env node
import fs from 'fs/promises';
import { createWriteStream, existsSync } from 'fs';
import path from 'path';
import { exec } from 'child_process';
import { promisify } from 'util';
import https from 'https';
import { pipeline } from 'stream/promises';
const execAsync = promisify(exec);
const CONFIG_FILE = 'libs-config.json';
const LIBS_DIR = 'libs';
const PUBLIC_LIBS_DIR = 'public/libraries';
const SRC_WASM_DIR = 'src/wasm';
class LibsBuilder {
constructor() {
this.config = null;
}
async loadConfig() {
try {
const configContent = await fs.readFile(CONFIG_FILE, 'utf-8');
this.config = JSON.parse(configContent);
} catch (error) {
console.error(`Failed to load config from ${CONFIG_FILE}:`, error.message);
process.exit(1);
}
}
async ensureDir(dirPath) {
try {
await fs.mkdir(dirPath, { recursive: true });
} catch (error) {
if (error.code !== 'EEXIST') {
throw error;
}
}
}
async downloadFile(url, outputPath) {
console.log(`Downloading ${url} to ${outputPath}`);
return new Promise((resolve, reject) => {
https.get(url, (response) => {
if (response.statusCode === 302 || response.statusCode === 301) {
// Handle redirects
return this.downloadFile(response.headers.location, outputPath)
.then(resolve)
.catch(reject);
}
if (response.statusCode !== 200) {
reject(new Error(`Failed to download: ${response.statusCode}`));
return;
}
const fileStream = createWriteStream(outputPath);
pipeline(response, fileStream)
.then(resolve)
.catch(reject);
}).on('error', reject);
});
}
async cloneRepo(repo, targetDir, branch = 'master', shallow = true) {
const cloneArgs = [
'clone',
'--recurse',
shallow ? '--depth 1' : '',
`--branch ${branch}`,
'--single-branch',
repo,
targetDir
].filter(Boolean);
console.log(`Cloning ${repo} to ${targetDir}`);
try {
await execAsync(`git ${cloneArgs.join(' ')}`);
} catch (error) {
console.error(`Failed to clone ${repo}:`, error.message);
throw error;
}
}
async createZip(sourceDir, outputPath, includes = [], excludes = [], workingDir = '.') {
await this.ensureDir(path.dirname(outputPath));
const fullSourceDir = path.join(sourceDir, workingDir);
// Build find command for includes
let findCmd = '';
if (includes.length > 0) {
const findPatterns = includes.map(pattern => {
if (pattern.includes('**/*.')) {
// Pattern like "examples/**/*.scad"
const parts = pattern.split('/');
const dir = parts[0];
const filePattern = parts[parts.length - 1];
return `-path "./${dir}/*" -name "${filePattern}"`;
} else if (pattern.includes('**')) {
// Pattern like "**/*.scad"
const filePattern = pattern.replace('**/', '');
return `-name "${filePattern}"`;
} else if (pattern.includes('*')) {
// Pattern like "*.scad"
return `-name "${pattern}"`;
} else if (pattern.includes('/')) {
// Path pattern like "bitmap/*.scad"
return `-path "./${pattern}"`;
} else {
// Direct file/directory name
return `-name "${pattern}" -o -path "./${pattern}/*"`;
}
}).join(' -o ');
findCmd = `find . \\( ${findPatterns} \\)`;
} else {
findCmd = 'find . -name "*.scad"';
}
// Add excludes
if (excludes.length > 0) {
const excludePatterns = excludes.map(pattern => {
const cleanPattern = pattern.replace('**/', '').replace('/**', '');
return `-not -path "*/${cleanPattern}*"`;
}).join(' ');
findCmd += ` ${excludePatterns}`;
}
const zipCmd = `cd ${fullSourceDir} && ${findCmd} | zip -r ${path.resolve(outputPath)} -@`;
console.log(`Creating zip: ${outputPath}`);
console.log(`Zip command: ${zipCmd}`);
try {
await execAsync(zipCmd);
} catch (error) {
console.error(`Failed to create zip ${outputPath}:`, error.message);
throw error;
}
}
async buildWasm() {
const { wasmBuild } = this.config;
const wasmDir = wasmBuild.target;
const wasmZip = `${wasmDir}.zip`;
// Create libs directory
await this.ensureDir(LIBS_DIR);
// Download WASM if not exists
if (!existsSync(wasmDir)) {
await this.ensureDir(wasmDir);
// Download WASM zip
await this.downloadFile(wasmBuild.url, wasmZip);
// Extract WASM zip
console.log(`Extracting WASM to ${wasmDir}`);
await execAsync(`cd ${wasmDir} && unzip ../${path.basename(wasmZip)}`);
}
// Create symlinks for public files
await this.ensureDir('public');
const jsTarget = 'public/openscad.js';
const wasmTarget = 'public/openscad.wasm';
// Remove existing symlinks/files
try {
await fs.unlink(jsTarget);
} catch {
// ignore - file doesn't exist
}
try {
await fs.unlink(wasmTarget);
} catch {
// ignore - file doesn't exist
}
// Create new symlinks - use relative paths for portability
await fs.symlink(path.relative('public', path.join(wasmDir, 'openscad.js')), jsTarget);
await fs.symlink(path.relative('public', path.join(wasmDir, 'openscad.wasm')), wasmTarget);
// Create src/wasm symlink
try {
await fs.unlink(SRC_WASM_DIR);
} catch {
// ignore - file doesn't exist
}
await fs.symlink(path.relative('src', wasmDir), SRC_WASM_DIR);
console.log('WASM setup completed');
}
async buildFonts() {
const { fonts } = this.config;
const notoDir = path.join(LIBS_DIR, 'noto');
const liberationDir = path.join(LIBS_DIR, 'liberation');
await this.ensureDir(notoDir);
// Download Noto fonts
for (const font of fonts.notoFonts) {
const fontPath = path.join(notoDir, font);
if (!existsSync(fontPath)) {
const url = fonts.notoBaseUrl + font;
await this.downloadFile(url, fontPath);
}
}
// Clone liberation fonts if not exists
if (!existsSync(liberationDir)) {
await this.cloneRepo(fonts.liberationRepo, liberationDir, fonts.liberationBranch);
}
// Create fonts zip
const fontsZip = path.join(PUBLIC_LIBS_DIR, 'fonts.zip');
await this.ensureDir(PUBLIC_LIBS_DIR);
console.log('Creating fonts.zip');
const fontsCmd = `zip -r ${fontsZip} -j fonts.conf libs/noto/*.ttf libs/liberation/*.ttf libs/liberation/LICENSE libs/liberation/AUTHORS`;
await execAsync(fontsCmd);
console.log('Fonts setup completed');
}
async buildLibrary(library) {
const libDir = path.join(LIBS_DIR, library.name);
const zipPath = path.join(PUBLIC_LIBS_DIR, `${library.name}.zip`);
// Clone repository if not exists
if (!existsSync(libDir)) {
await this.cloneRepo(library.repo, libDir, library.branch);
}
// Create zip
await this.createZip(
libDir,
zipPath,
library.zipIncludes || ['*.scad'],
library.zipExcludes || [],
library.workingDir || '.'
);
console.log(`Built ${library.name}`);
}
async buildAllLibraries() {
await this.ensureDir(PUBLIC_LIBS_DIR);
for (const library of this.config.libraries) {
await this.buildLibrary(library);
}
}
async clean() {
console.log('Cleaning build artifacts...');
const cleanPaths = [
LIBS_DIR,
'build',
'public/openscad.js',
'public/openscad.wasm',
`${PUBLIC_LIBS_DIR}/*.zip`,
SRC_WASM_DIR
];
for (const cleanPath of cleanPaths) {
try {
if (cleanPath.includes('*')) {
await execAsync(`rm -f ${cleanPath}`);
} else {
await fs.rm(cleanPath, { recursive: true, force: true });
}
} catch {
// Ignore errors for files that don't exist
}
}
console.log('Clean completed');
}
async build() {
console.log('Building all libraries...');
await this.buildWasm();
await this.buildFonts();
await this.buildAllLibraries();
console.log('Build completed successfully!');
}
}
async function main() {
const builder = new LibsBuilder();
await builder.loadConfig();
const command = process.argv[2] || 'build';
switch (command) {
case 'build':
await builder.build();
break;
case 'clean':
await builder.clean();
break;
case 'wasm':
await builder.buildWasm();
break;
case 'fonts':
await builder.buildFonts();
break;
default:
console.log('Usage: node build-libs.js [build|clean|wasm|fonts]');
process.exit(1);
}
}
main().catch(error => {
console.error('Build failed:', error);
process.exit(1);
});

248
libs-config.json Normal file
View file

@ -0,0 +1,248 @@
{
"wasmBuild": {
"url": "https://files.openscad.org/playground/OpenSCAD-2025.03.25.wasm24456-WebAssembly-web.zip",
"target": "libs/openscad-wasm"
},
"libraries": [
{
"name": "openscad",
"repo": "https://github.com/openscad/openscad.git",
"branch": "master",
"zipIncludes": [
"examples/**/*.scad"
],
"zipExcludes": [
"**/tests/**"
]
},
{
"name": "BOSL2",
"repo": "https://github.com/BelfrySCAD/BOSL2.git",
"branch": "master",
"zipIncludes": [
"*.scad",
"LICENSE",
"examples"
]
},
{
"name": "BOSL",
"repo": "https://github.com/revarbat/BOSL.git",
"branch": "master",
"zipIncludes": [
"*.scad",
"LICENSE"
]
},
{
"name": "NopSCADlib",
"repo": "https://github.com/nophead/NopSCADlib.git",
"branch": "master",
"zipIncludes": [
"**/*.scad",
"COPYING"
]
},
{
"name": "funcutils",
"repo": "https://github.com/thehans/funcutils.git",
"branch": "master",
"zipIncludes": [
"*.scad",
"LICENSE"
]
},
{
"name": "FunctionalOpenSCAD",
"repo": "https://github.com/thehans/FunctionalOpenSCAD.git",
"branch": "master",
"zipIncludes": [
"*.scad",
"LICENSE"
]
},
{
"name": "YAPP_Box",
"repo": "https://github.com/mrWheel/YAPP_Box.git",
"branch": "main",
"zipIncludes": [
"**/*.scad",
"LICENSE"
]
},
{
"name": "MCAD",
"repo": "https://github.com/openscad/MCAD.git",
"branch": "master",
"zipIncludes": [
"*.scad",
"bitmap/*.scad",
"LICENSE"
]
},
{
"name": "boltsparts",
"repo": "https://github.com/boltsparts/boltsparts.git",
"branch": "main",
"zipIncludes": [
"**/*.scad",
"../LICENSE"
],
"zipExcludes": [
"**/tests/**"
],
"workingDir": "openscad"
},
{
"name": "OpenSCAD-Snippet",
"repo": "https://github.com/AngeloNicoli/OpenSCAD-Snippet.git",
"branch": "main",
"zipIncludes": [
"**/*.scad",
"LICENSE"
]
},
{
"name": "Stemfie_OpenSCAD",
"repo": "https://github.com/Cantareus/Stemfie_OpenSCAD.git",
"branch": "main",
"zipIncludes": [
"*.scad",
"LICENSE"
]
},
{
"name": "pathbuilder",
"repo": "https://github.com/dinther/pathbuilder.git",
"branch": "main",
"zipIncludes": [
"*.scad",
"demo/*.scad",
"LICENSE"
]
},
{
"name": "openscad_attachable_text3d",
"repo": "https://github.com/jon-gilbert/openscad_attachable_text3d.git",
"branch": "main",
"zipIncludes": [
"*.scad",
"LICENSE"
]
},
{
"name": "brailleSCAD",
"repo": "https://github.com/BelfrySCAD/brailleSCAD.git",
"branch": "main",
"zipIncludes": [
"*.scad",
"LICENSE"
]
},
{
"name": "smooth-prim",
"repo": "https://github.com/rcolyer/smooth-prim.git",
"branch": "master",
"zipIncludes": [
"*.scad",
"LICENSE.txt"
]
},
{
"name": "plot-function",
"repo": "https://github.com/rcolyer/plot-function.git",
"branch": "master",
"zipIncludes": [
"*.scad",
"LICENSE.txt"
]
},
{
"name": "closepoints",
"repo": "https://github.com/rcolyer/closepoints.git",
"branch": "master",
"zipIncludes": [
"*.scad",
"LICENSE.txt"
]
},
{
"name": "UB.scad",
"repo": "https://github.com/UBaer21/UB.scad.git",
"branch": "main",
"zipIncludes": [
"libraries/*.scad",
"LICENSE",
"examples/UBexamples"
]
},
{
"name": "openscad-tray",
"repo": "https://github.com/sofian/openscad-tray.git",
"branch": "main",
"zipIncludes": [
"*.scad",
"LICENSE"
]
},
{
"name": "lasercut",
"repo": "https://github.com/bmsleight/lasercut.git",
"branch": "master",
"zipIncludes": [
"*.scad",
"LICENSE"
]
}
],
"fonts": {
"notoFonts": [
"NotoNaskhArabic-Bold.ttf",
"NotoNaskhArabic-Regular.ttf",
"NotoSans-Bold.ttf",
"NotoSans-Italic.ttf",
"NotoSans-Regular.ttf",
"NotoSansArmenian-Bold.ttf",
"NotoSansArmenian-Regular.ttf",
"NotoSansBalinese-Regular.ttf",
"NotoSansBengali-Bold.ttf",
"NotoSansBengali-Regular.ttf",
"NotoSansDevanagari-Bold.ttf",
"NotoSansDevanagari-Regular.ttf",
"NotoSansEthiopic-Bold.ttf",
"NotoSansEthiopic-Regular.ttf",
"NotoSansGeorgian-Bold.ttf",
"NotoSansGeorgian-Regular.ttf",
"NotoSansGujarati-Bold.ttf",
"NotoSansGujarati-Regular.ttf",
"NotoSansGurmukhi-Bold.ttf",
"NotoSansGurmukhi-Regular.ttf",
"NotoSansHebrew-Bold.ttf",
"NotoSansHebrew-Regular.ttf",
"NotoSansJavanese-Regular.ttf",
"NotoSansKannada-Bold.ttf",
"NotoSansKannada-Regular.ttf",
"NotoSansKhmer-Bold.ttf",
"NotoSansKhmer-Regular.ttf",
"NotoSansLao-Bold.ttf",
"NotoSansLao-Regular.ttf",
"NotoSansMongolian-Regular.ttf",
"NotoSansMyanmar-Bold.ttf",
"NotoSansMyanmar-Regular.ttf",
"NotoSansOriya-Bold.ttf",
"NotoSansOriya-Regular.ttf",
"NotoSansSinhala-Bold.ttf",
"NotoSansSinhala-Regular.ttf",
"NotoSansTamil-Bold.ttf",
"NotoSansTamil-Regular.ttf",
"NotoSansThai-Bold.ttf",
"NotoSansThai-Regular.ttf",
"NotoSansTibetan-Bold.ttf",
"NotoSansTibetan-Regular.ttf",
"NotoSansTifinagh-Regular.ttf"
],
"notoBaseUrl": "https://github.com/openmaptiles/fonts/raw/master/noto-sans/",
"liberationRepo": "https://github.com/shantigilbert/liberation-fonts-ttf.git",
"liberationBranch": "master"
}
}

View file

@ -31,7 +31,12 @@
"start:development": "npx webpack serve --mode=development",
"start:production": "NODE_ENV=production PUBLIC_URL=http://localhost:3000/dist/ npm run build && npx serve",
"start": "npm run start:development",
"build": "NODE_ENV=production webpack --mode=production"
"build": "NODE_ENV=production webpack --mode=production",
"build:libs": "node build-libs.js build",
"build:libs:clean": "node build-libs.js clean",
"build:libs:wasm": "node build-libs.js wasm",
"build:libs:fonts": "node build-libs.js fonts",
"build:all": "npm run build:libs && npm run build"
},
"eslintConfig": {
"extends": [
@ -74,6 +79,7 @@
"style-loader": "^4.0.0",
"ts-loader": "^9.5.1",
"tslib": "^2.8.1",
"typescript": "^5.9.2",
"webpack": "^5.97.1",
"webpack-cli": "^6.0.1",
"webpack-dev-server": "^5.2.0",