Merge pull request #123 from JohnnyTheTank/122/Replace-Makefile-w-something-that-reads-the-libs-metadata
Replace Makefile w/ something that reads the libs metadata
This commit is contained in:
commit
869a4c1888
10 changed files with 698 additions and 351 deletions
3
.github/workflows/test.yml
vendored
3
.github/workflows/test.yml
vendored
|
|
@ -25,8 +25,7 @@ jobs:
|
|||
with:
|
||||
node-version: ${{ matrix.node.version }}
|
||||
- run: npm install
|
||||
- run: make public
|
||||
- run: npm run build
|
||||
- run: npm run build:all
|
||||
- name: Archive production artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
|
|
|
|||
285
Makefile
285
Makefile
|
|
@ -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 )
|
||||
|
||||
56
README.md
56
README.md
|
|
@ -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.
|
||||
|
|
@ -48,11 +48,15 @@ Licenses: see [LICENSES](./LICENSE).
|
|||
|
||||
## Building
|
||||
|
||||
The project uses a **webpack-based build system** that reads library metadata from `libs-config.json` to automatically download, clone, and package OpenSCAD libraries and dependencies. This replaces the previous Makefile approach with a more standard, maintainable solution.
|
||||
|
||||
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 +65,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!
|
||||
|
|
@ -89,7 +92,7 @@ rm -fR ../ochafik.github.io/openscad2 && cp -R dist ../ochafik.github.io/opensca
|
|||
|
||||
## Build your own WASM binary
|
||||
|
||||
[Makefile](./Makefile) fetches a prebuilt OpenSCAD web WASM binary, but you can build your own in a couple of minutes:
|
||||
The build system fetches a prebuilt OpenSCAD web WASM binary, but you can build your own in a couple of minutes:
|
||||
|
||||
- **Optional**: use your own openscad fork / branch:
|
||||
|
||||
|
|
@ -104,24 +107,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):
|
||||
The build system uses a webpack plugin that reads from `libs-config.json` to manage all library dependencies. 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.
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ const config = {
|
|||
],
|
||||
},
|
||||
server: {
|
||||
command: `npm run start:${process.env.NODE_ENV}`,
|
||||
command: `npm run start:${process.env.NODE_ENV || 'test'}`,
|
||||
port: process.env.NODE_ENV === 'production' ? 3000 : 4000,
|
||||
launchTimeout: 180000,
|
||||
},
|
||||
|
|
|
|||
248
libs-config.json
Normal file
248
libs-config.json
Normal 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"
|
||||
}
|
||||
}
|
||||
11
package.json
11
package.json
|
|
@ -30,8 +30,14 @@
|
|||
"test:e2e": "jest",
|
||||
"start:development": "npx webpack serve --mode=development",
|
||||
"start:production": "NODE_ENV=production PUBLIC_URL=http://localhost:3000/dist/ npm run build && npx serve",
|
||||
"start:test": "npm run start:development",
|
||||
"start": "npm run start:development",
|
||||
"build": "NODE_ENV=production webpack --mode=production"
|
||||
"build": "NODE_ENV=production webpack --mode=production",
|
||||
"build:libs": "LIBS_BUILD_MODE=all webpack --config webpack.libs.config.js",
|
||||
"build:libs:clean": "LIBS_BUILD_MODE=clean webpack --config webpack.libs.config.js",
|
||||
"build:libs:wasm": "LIBS_BUILD_MODE=wasm webpack --config webpack.libs.config.js",
|
||||
"build:libs:fonts": "LIBS_BUILD_MODE=fonts webpack --config webpack.libs.config.js",
|
||||
"build:all": "npm run build:libs && npm run build"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
|
|
@ -74,9 +80,10 @@
|
|||
"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",
|
||||
"workbox-webpack-plugin": "^7.3.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -22,24 +22,24 @@ beforeEach(async () => {
|
|||
afterEach(async () => {
|
||||
// console.log('Messages:', JSON.stringify(messages, null, 2));
|
||||
const testName = expect.getState().currentTestName;
|
||||
console.log(`[${testName}] Messages:`, JSON.stringify(messages.map(({text}) => text), null, 2));
|
||||
|
||||
console.log(`[${testName}] Messages:`, JSON.stringify(messages.map(({ text }) => text), null, 2));
|
||||
|
||||
const errors = messages.filter(msg =>
|
||||
msg.type === 'error' &&
|
||||
!(msg.text.includes('404')
|
||||
&& msg.stack.some(s =>
|
||||
s.url.indexOf('fonts/InterVariable.woff') >= 0)));
|
||||
msg.type === 'error' &&
|
||||
!(msg.text.includes('404')
|
||||
&& msg.stack.some(s =>
|
||||
s.url.indexOf('fonts/InterVariable.woff') >= 0)));
|
||||
expect(errors).toHaveLength(0);
|
||||
});
|
||||
|
||||
function loadSrc(src) {
|
||||
return page.goto(baseUrl + '#src=' + encodeURIComponent(src));
|
||||
return page.goto(`${baseUrl}#src=${encodeURIComponent(src)}`);
|
||||
}
|
||||
function loadPath(path) {
|
||||
return page.goto(baseUrl + '#path=' + encodeURIComponent(path));
|
||||
return page.goto(`${baseUrl}#path=${encodeURIComponent(path)}`);
|
||||
}
|
||||
function loadUrl(url) {
|
||||
return page.goto(baseUrl + '#url=' + encodeURIComponent(url));
|
||||
return page.goto(`${baseUrl}#url=${encodeURIComponent(url)}`);
|
||||
}
|
||||
async function waitForViewer() {
|
||||
await page.waitForSelector('model-viewer');
|
||||
|
|
@ -63,19 +63,34 @@ function expect3DManifold() {
|
|||
}
|
||||
function waitForCustomizeButton() {
|
||||
return page.waitForFunction(() => {
|
||||
const buttons = document.querySelectorAll('input[role=switch]');
|
||||
for (const button of buttons) {
|
||||
if (button.parentElement.innerText === 'Customize') {
|
||||
return button;
|
||||
// Try multiple selectors for PrimeReact components
|
||||
// ToggleButton might render as button or input elements
|
||||
const selectors = [
|
||||
'input[role=switch]',
|
||||
'button',
|
||||
'[role=tab]',
|
||||
'.p-togglebutton',
|
||||
'.p-tabmenu-nav a'
|
||||
];
|
||||
|
||||
for (const selector of selectors) {
|
||||
const elements = document.querySelectorAll(selector);
|
||||
for (const element of elements) {
|
||||
const text = element.textContent || element.innerText || '';
|
||||
const parentText = element.parentElement?.textContent || element.parentElement?.innerText || '';
|
||||
if (text.includes('Customize') || parentText.includes('Customize')) {
|
||||
return element;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return null;
|
||||
}, { timeout: 45000 }); // Increase timeout to 45 seconds
|
||||
}
|
||||
function waitForLabel(text) {
|
||||
return page.waitForFunction((text) => {
|
||||
return page.waitForFunction(() => {
|
||||
return Array.from(document.querySelectorAll('label')).find(el => el.textContent === 'myVar');
|
||||
// return Array.from(document.querySelectorAll('label')).find(el => el.textContent === text);
|
||||
}, {}, text);
|
||||
});
|
||||
}
|
||||
|
||||
describe('e2e', () => {
|
||||
|
|
@ -90,7 +105,7 @@ describe('e2e', () => {
|
|||
await waitForViewer();
|
||||
expect3DPolySet();
|
||||
}, longTimeout);
|
||||
|
||||
|
||||
test('use BOSL2', async () => {
|
||||
await loadSrc(`
|
||||
include <BOSL2/std.scad>;
|
||||
|
|
@ -128,8 +143,17 @@ describe('e2e', () => {
|
|||
].join('\r\n'));
|
||||
await waitForViewer();
|
||||
expect3DPolySet();
|
||||
|
||||
// Wait for syntax checking to complete and parameters to be detected
|
||||
await page.waitForFunction(() => {
|
||||
// Look for any indication that parameters have been processed
|
||||
const messages = Array.from(document.querySelectorAll('*')).map(el => el.textContent || '').join(' ');
|
||||
return messages.includes('myVar') || messages.includes('Customize');
|
||||
}, { timeout: 30000 });
|
||||
|
||||
await (await waitForCustomizeButton()).click();
|
||||
await page.waitForSelector('fieldset');
|
||||
await waitForLabel('myVar');
|
||||
}, longTimeout);
|
||||
});
|
||||
|
||||
|
|
|
|||
308
webpack-libs-plugin.js
Normal file
308
webpack-libs-plugin.js
Normal file
|
|
@ -0,0 +1,308 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
import { exec } from 'node:child_process';
|
||||
import { createWriteStream, existsSync } from 'node:fs';
|
||||
import fs from 'node:fs/promises';
|
||||
import https from 'node:https';
|
||||
import path from 'node:path';
|
||||
import { pipeline } from 'node:stream/promises';
|
||||
import { promisify } from 'node:util';
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
|
||||
class OpenSCADLibrariesPlugin {
|
||||
constructor(options = {}) {
|
||||
this.configFile = options.configFile || 'libs-config.json';
|
||||
this.libsDir = options.libsDir || 'libs';
|
||||
this.publicLibsDir = options.publicLibsDir || 'public/libraries';
|
||||
this.srcWasmDir = options.srcWasmDir || 'src/wasm';
|
||||
this.buildMode = options.buildMode || 'all'; // 'all', 'wasm', 'fonts', 'libs'
|
||||
this.config = null;
|
||||
}
|
||||
|
||||
apply(compiler) {
|
||||
const pluginName = 'OpenSCADLibrariesPlugin';
|
||||
|
||||
compiler.hooks.beforeRun.tapAsync(pluginName, async (_, callback) => {
|
||||
try {
|
||||
await this.loadConfig();
|
||||
|
||||
switch (this.buildMode) {
|
||||
case 'all':
|
||||
await this.buildAll();
|
||||
break;
|
||||
case 'wasm':
|
||||
await this.buildWasm();
|
||||
break;
|
||||
case 'fonts':
|
||||
await this.buildFonts();
|
||||
break;
|
||||
case 'libs':
|
||||
await this.buildAllLibraries();
|
||||
break;
|
||||
case 'clean':
|
||||
await this.clean();
|
||||
break;
|
||||
}
|
||||
|
||||
callback();
|
||||
} catch (error) {
|
||||
callback(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async loadConfig() {
|
||||
try {
|
||||
const configContent = await fs.readFile(this.configFile, 'utf-8');
|
||||
this.config = JSON.parse(configContent);
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to load config from ${this.configFile}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
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('**/*.')) {
|
||||
const parts = pattern.split('/');
|
||||
const dir = parts[0];
|
||||
const filePattern = parts[parts.length - 1];
|
||||
return `-path "./${dir}/*" -name "${filePattern}"`;
|
||||
} else if (pattern.includes('**')) {
|
||||
const filePattern = pattern.replace('**/', '');
|
||||
return `-name "${filePattern}"`;
|
||||
} else if (pattern.includes('*')) {
|
||||
return `-name "${pattern}"`;
|
||||
} else if (pattern.includes('/')) {
|
||||
return `-path "./${pattern}"`;
|
||||
} else {
|
||||
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}`);
|
||||
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`;
|
||||
|
||||
await this.ensureDir(this.libsDir);
|
||||
|
||||
if (!existsSync(wasmDir)) {
|
||||
await this.ensureDir(wasmDir);
|
||||
await this.downloadFile(wasmBuild.url, wasmZip);
|
||||
|
||||
console.log(`Extracting WASM to ${wasmDir}`);
|
||||
await execAsync(`cd ${wasmDir} && unzip ../${path.basename(wasmZip)}`);
|
||||
}
|
||||
|
||||
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 */ }
|
||||
try {
|
||||
await fs.unlink(wasmTarget);
|
||||
} catch { /* ignore */ }
|
||||
|
||||
// Create new symlinks
|
||||
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(this.srcWasmDir);
|
||||
} catch { /* ignore */ }
|
||||
await fs.symlink(path.relative('src', wasmDir), this.srcWasmDir);
|
||||
|
||||
console.log('WASM setup completed');
|
||||
}
|
||||
|
||||
async buildFonts() {
|
||||
const { fonts } = this.config;
|
||||
const notoDir = path.join(this.libsDir, 'noto');
|
||||
const liberationDir = path.join(this.libsDir, '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(this.publicLibsDir, 'fonts.zip');
|
||||
await this.ensureDir(this.publicLibsDir);
|
||||
|
||||
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(this.libsDir, library.name);
|
||||
const zipPath = path.join(this.publicLibsDir, `${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(this.publicLibsDir);
|
||||
|
||||
for (const library of this.config.libraries) {
|
||||
await this.buildLibrary(library);
|
||||
}
|
||||
}
|
||||
|
||||
async clean() {
|
||||
console.log('Cleaning build artifacts...');
|
||||
|
||||
const cleanPaths = [
|
||||
this.libsDir,
|
||||
'build',
|
||||
'public/openscad.js',
|
||||
'public/openscad.wasm',
|
||||
`${this.publicLibsDir}/*.zip`,
|
||||
this.srcWasmDir
|
||||
];
|
||||
|
||||
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 buildAll() {
|
||||
console.log('Building all libraries...');
|
||||
|
||||
await this.buildWasm();
|
||||
await this.buildFonts();
|
||||
await this.buildAllLibraries();
|
||||
|
||||
console.log('Build completed successfully!');
|
||||
}
|
||||
}
|
||||
|
||||
export default OpenSCADLibrariesPlugin;
|
||||
|
|
@ -1,16 +1,13 @@
|
|||
import CopyPlugin from 'copy-webpack-plugin';
|
||||
import WorkboxPlugin from 'workbox-webpack-plugin';
|
||||
import webpack from 'webpack';
|
||||
import packageConfig from './package.json' with {type: 'json'};
|
||||
import WorkboxPlugin from 'workbox-webpack-plugin';
|
||||
|
||||
import path, {dirname} from 'path';
|
||||
import {fileURLToPath} from 'url';
|
||||
import path, { dirname } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
const LOCAL_URL = process.env.LOCAL_URL ?? 'http://localhost:4000/';
|
||||
const PUBLIC_URL = process.env.PUBLIC_URL ?? packageConfig.homepage;
|
||||
const isDev = process.env.NODE_ENV !== 'production';
|
||||
|
||||
|
||||
|
|
@ -48,7 +45,7 @@ const config = [
|
|||
'style-loader',
|
||||
{
|
||||
loader: 'css-loader',
|
||||
options:{url: false},
|
||||
options: { url: false },
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
@ -76,28 +73,28 @@ const config = [
|
|||
}),
|
||||
...(process.env.NODE_ENV === 'production' ? [
|
||||
new WorkboxPlugin.GenerateSW({
|
||||
exclude: [
|
||||
/(^|\/)\./,
|
||||
/\.map$/,
|
||||
/^manifest.*\.js$/,
|
||||
],
|
||||
// these options encourage the ServiceWorkers to get in there fast
|
||||
// and not allow any straggling 'old' SWs to hang around
|
||||
swDest: path.join(__dirname, 'dist', 'sw.js'),
|
||||
maximumFileSizeToCacheInBytes: 200 * 1024 * 1024,
|
||||
clientsClaim: true,
|
||||
skipWaiting: true,
|
||||
runtimeCaching: [{
|
||||
urlPattern: ({request, url}) => true,
|
||||
handler: 'StaleWhileRevalidate',
|
||||
options: {
|
||||
cacheName: 'all',
|
||||
expiration: {
|
||||
maxEntries: 1000,
|
||||
purgeOnQuotaError: true,
|
||||
},
|
||||
exclude: [
|
||||
/(^|\/)\./,
|
||||
/\.map$/,
|
||||
/^manifest.*\.js$/,
|
||||
],
|
||||
// these options encourage the ServiceWorkers to get in there fast
|
||||
// and not allow any straggling 'old' SWs to hang around
|
||||
swDest: path.join(__dirname, 'dist', 'sw.js'),
|
||||
maximumFileSizeToCacheInBytes: 200 * 1024 * 1024,
|
||||
clientsClaim: true,
|
||||
skipWaiting: true,
|
||||
runtimeCaching: [{
|
||||
urlPattern: ({ request, url }) => true,
|
||||
handler: 'StaleWhileRevalidate',
|
||||
options: {
|
||||
cacheName: 'all',
|
||||
expiration: {
|
||||
maxEntries: 1000,
|
||||
purgeOnQuotaError: true,
|
||||
},
|
||||
}],
|
||||
},
|
||||
}],
|
||||
}),
|
||||
] : []),
|
||||
new CopyPlugin({
|
||||
|
|
@ -113,7 +110,11 @@ const config = [
|
|||
},
|
||||
{
|
||||
from: path.resolve(__dirname, 'src/wasm/openscad.js'),
|
||||
to: path.resolve(__dirname, 'dist'),
|
||||
},
|
||||
{
|
||||
from: path.resolve(__dirname, 'src/wasm/openscad.wasm'),
|
||||
to: path.resolve(__dirname, 'dist'),
|
||||
},
|
||||
],
|
||||
}),
|
||||
|
|
|
|||
21
webpack.libs.config.js
Normal file
21
webpack.libs.config.js
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import OpenSCADLibrariesPlugin from './webpack-libs-plugin.js';
|
||||
|
||||
const buildMode = process.env.LIBS_BUILD_MODE || 'all';
|
||||
|
||||
/** @type {import('webpack').Configuration} */
|
||||
const config = {
|
||||
mode: 'none', // We're not actually building JS, just using webpack as a task runner
|
||||
entry: './package.json', // Dummy entry point that exists
|
||||
output: {
|
||||
path: '/tmp', // Output to temp directory
|
||||
filename: 'webpack-libs-temp.js', // This won't be used
|
||||
},
|
||||
plugins: [
|
||||
new OpenSCADLibrariesPlugin({
|
||||
buildMode: buildMode
|
||||
}),
|
||||
],
|
||||
stats: 'minimal',
|
||||
};
|
||||
|
||||
export default config;
|
||||
Loading…
Reference in a new issue