Switch to webpack

This commit is contained in:
ochafik 2023-03-25 19:30:34 +00:00
commit 4b11073437
17 changed files with 238 additions and 69 deletions

View file

@ -4,12 +4,13 @@ SINGLE_BRANCH_MAIN=--branch main --single-branch
SINGLE_BRANCH=--branch master --single-branch
SHALLOW=--depth 1
all: build
all: public
.PHONY: public
public: \
libs/openscad \
public/openscad.js \
public/openscad-worker-inlined.js \
public/openscad.wasm \
public/libraries/fonts.zip \
public/libraries/NopSCADlib.zip \
public/libraries/BOSL.zip \
@ -27,26 +28,49 @@ public: \
clean:
rm -fR libs build
rm -fR public/openscad-worker-inlined.js
rm -fR public/openscad.{js,wasm}
rm -fR public/libraries
rm -fR src/wasm
build: public
npm run build
dist/index.js: public
npm run build2
# mkdir -f build/libraries
# cp -f public/libraries/*.zip build/libraries
src/wasm/openscad.js:
wget ${WASM_BUILD_URL} -O OpenSCAD-WebAssembly.zip
mkdir -p src/wasm
( cd src/wasm && rm -f openscad.{js,wasm} && unzip ../../OpenSCAD-WebAssembly.zip )
rm OpenSCAD-WebAssembly.zip
public/openscad.js: src/wasm/openscad.js
cp src/wasm/openscad.{js,wasm} public
public/openscad-worker-inlined.js: src/openscad-worker.ts src/wasm/openscad.js
dist/openscad-worker.js: src/openscad-worker.ts
npx rollup -c
libs/openscad:
mkdir -p libs/openscad
wget ${WASM_BUILD_URL} -O libs/openscad.zip
( cd libs/openscad && unzip ../openscad.zip )
rm libs/openscad.zip
rm -f src/wasm
ln -sf $(shell pwd)/libs/openscad src/wasm
public/openscad.js: libs/openscad libs/openscad/openscad.js
cp libs/openscad/openscad.{js,wasm} public
public/openscad.wasm: libs/openscad libs/openscad/openscad.wasm
cp libs/openscad/openscad.wasm public
# public/openscad-worker-inlined.js: src/openscad-worker.ts src/wasm/openscad.js
# npx rollup -c
# js/src/openscad-worker.js: src/openscad-worker.ts
# tsc
# public/openscad-worker-inlined.js: inline-openscad-worker.ts js/src/openscad-worker.js public/openscad.js js/src/filesystem.js js/src/zip-archives.js
# cp src/wasm/openscad.{js,wasm} public
# npx webpack --config webpack.config.js
# tsc src/BrowserFS.d.ts src/openscad-worker.ts --outFile public/openscad-worker-inlined.js --module amd --moduleResolution nodenext
# deno run --allow-net --allow-read --allow-write inline-openscad-worker.ts \
# js/src/openscad-worker.js \
# public/openscad.js \
# public/openscad-worker-inlined.js \
# https://ochafik.com/openscad/openscad-worker-inlined.js
# cp js/src/{filesystem,zip-archives}.js public
public/libraries/fonts.zip: libs/liberation
mkdir -p public/libraries
cp fonts.conf libs/liberation

View file

@ -4,6 +4,19 @@ WIP revamp of https://github.com/ochafik/openscad-wasm/tree/editor-ochafik.com /
Licenses: see [LICENSES](./LICENSES).
## Features
- Automatic preview on edit (F5), and full rendering on Ctrl+Enter (or F6)
- Syntax highlighting
- Ships with many standard SCAD libraries
- Autocomplete of imports
- Autocomplete of symbols / function calls (pseudo-parses file and its transitive imports)
-
## TODO
- Investigate https://www.npmjs.com/package/react-codemirror for mobile editor (Monaco on iOS is terribly broken)
- Link to https://www.npmjs.com/package/monaco-languages MIT JS source for language
## Build
Prerequisites:
@ -12,14 +25,23 @@ Prerequisites:
* npm
* deno
Local dev:
```bash
make clean
# When doing local development, ensure the import.meta.url is replaced to localhost:
# (otherwise will get cryptic `RangeError: WebAssembly.Table.get(): invalid index 999948 into function table`)
dev=1 make public
make public
npm start
# When building a release
make
# http://localhost:4000/
```
make public
npm run start:prod
# http://localhost:3000/dist/
Deployment (edit "homepage" in `package.json` to match your deployment root!):
```bash
make public
npm 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!
```

View file

@ -0,0 +1,25 @@
import typescript from 'rollup-plugin-typescript';
import replace from '@rollup/plugin-replace';
import packageConfig from './package.json'
const LOCAL_URL = process.env.LOCAL_URL ?? 'http://localhost:4000/';
const PUBLIC_URL = process.env.PUBLIC_URL ?? packageConfig.homepage;
export default [
{
input: 'src/openscad-worker.ts',
output: {
file: 'dist/openscad-worker.js',
format: 'es'
},
plugins: [
typescript({
rootDir: 'src',
}),
replace({
preventAssignment: true,
'import.meta.url': JSON.stringify(process.env.NODE_ENV !== 'production' ? LOCAL_URL : PUBLIC_URL),
})
]
},
];

View file

@ -2,28 +2,29 @@
"name": "openscad-playground",
"version": "0.1.0",
"private": true,
"homepage": "https://ochafik.com/openscad2/",
"dependencies": {
"@monaco-editor/loader": "^1.3.2",
"@monaco-editor/react": "^4.4.6",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"@types/debug": "^4.1.7",
"@types/jest": "^27.5.2",
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"debug": "^4.3.4",
"monaco-editor": "^0.36.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "^5.0.1",
"react-stl-viewer": "^2.2.5",
"react-widgets": "^5.8.4",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"tsc": "tsc"
"start": "concurrently 'npx webpack serve --mode=development' 'NODE_ENV=development npx rollup --config openscad-worker.rollup.config.js --watch'",
"start:prod": "PUBLIC_URL=http://localhost:3000/dist/ npm run build && npx serve",
"build": "NODE_ENV=production npx rollup --config openscad-worker.rollup.config.js && webpack --mode=production"
},
"eslintConfig": {
"extends": [
@ -44,12 +45,28 @@
]
},
"devDependencies": {
"@rollup/plugin-html": "^1.0.2",
"@rollup/plugin-node-resolve": "^15.0.1",
"@rollup/plugin-typescript": "^11.0.0",
"@types/filesystem": "^0.0.32",
"@types/node": "^18.15.6",
"@web/rollup-plugin-html": "^1.11.0",
"concurrently": "^7.6.0",
"copy-webpack-plugin": "^11.0.0",
"css-loader": "^6.7.3",
"livereload": "^0.9.3",
"rollup": "^2.79.1",
"rollup-plugin-babel": "^4.4.0",
"rollup-plugin-css": "^1.0.10",
"rollup-plugin-postcss": "^4.0.2",
"rollup-plugin-typescript": "^1.0.1",
"rollup-plugin-typescript2": "^0.34.1",
"rollup-watch": "^4.3.1",
"serve": "^14.2.0",
"ts-loader": "^9.4.2",
"tslib": "^2.5.0",
"webpack-cli": "^5.0.1"
"webpack": "^5.76.3",
"webpack-cli": "^5.0.1",
"webpack-dev-server": "^4.13.1"
}
}

View file

@ -4,9 +4,11 @@
<meta charset="utf-8" />
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/BrowserFS/2.0.0/browserfs.min.js" defer></script> -->
<script src="%PUBLIC_URL%/browserfs.min.js"></script>
<script src="./browserfs.min.js" defer></script>
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<script src="./index.js" defer></script>
<link rel="icon" href="../public/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
@ -16,9 +18,9 @@
name="description"
content="OpenSCAD Playground: edit .scad models and render them to STL from the browser (WebAssembly build OpenSCAD, with Monaco editor and STL Viewer)"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="apple-touch-icon" href="logo192.png" />
<!-- https://developers.google.com/web/fundamentals/web-app-manifest/ -->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<link rel="manifest" href="manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.

16
public/openscad.js Normal file

File diff suppressed because one or more lines are too long

BIN
public/openscad.wasm Executable file

Binary file not shown.

View file

@ -1,24 +0,0 @@
// npx rollup -c
// npx rollup ./src/openscad-worker.ts -o public/openscad-worker-inlined.js -f cjs
import typescript from '@rollup/plugin-typescript';
import replace from '@rollup/plugin-replace';
export default {
input: 'src/openscad-worker.ts',
output: {
file: 'public/openscad-worker-inlined.js',
format: 'es'
},
plugins: [
typescript({
// outDir: 'public2',
rootDir: 'src',
}),
replace({
'import.meta.url': JSON.stringify(process.env.dev
? 'http://localhost:3000/'
: 'https://ochafik.com/openscad/openscad-worker-inlined.js'),
})
]
};

View file

@ -31,7 +31,13 @@ function EditorPanel() {
monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter,
monaco.KeyCode.F6,
],
run: () => model.render()
run: () => model.render({isPreview: false})
});
editor.addAction({
id: "openscad-preview",
label: "Preview OpenSCAD",
keybindings: [monaco.KeyCode.F5],
run: () => model.render({isPreview: false})
});
setEditor(editor)
}
@ -100,7 +106,7 @@ export function App({initialState}: {initialState: State}) {
}
</div>
<div style={{display: 'flex', flexDirection: 'row'}}>
<button onClick={() => model.render()}>Render</button>
<button onClick={() => model.render({isPreview: false})}>Render</button>
{model.state.previewing && 'previewing... '}
{model.state.rendering && 'rendering... '}
{model.state.checkingSyntax && 'checking syntax... '}

1
src/BrowserFS.d.ts vendored
View file

@ -5,6 +5,7 @@
declare interface FS {
readdir(path: string, cb: (err: any, files: string[]) => void): void;
symlink(target: string, source: string): void;
readFileSync(path: string): BufferSource;
}
declare interface EmscriptenFS extends FS {}

View file

@ -2,7 +2,7 @@
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
import { createContext } from "react"
import React from 'react';
import { Model } from "./model"
export interface State {
@ -19,12 +19,13 @@ export interface State {
checkingSyntax?: boolean,
output?: {
isPreview: boolean,
stlFile: File,
stlFileURL: string,
},
};
export const ModelContext = createContext(new Model(
export const ModelContext = React.createContext(new Model(
{
params: {
source: '',

17
src/default-scad.ts Normal file
View file

@ -0,0 +1,17 @@
export default `
rotate([90, 0, 0]) {
translate([-50, 0, 50])
linear_extrude(10)
text("hello world!");
}
cube(40, center=true);
translate([10, 10, 10])
cube(40, center=true);
// This demo includes many libraries:
//
// include <BOSL2/std.scad>
// translate([-100, 0, 0])
spheroid(d=100, style="icosa", $fn=20);
`

View file

@ -10,6 +10,17 @@ import { zipArchives } from './zip-archives';
import {readStateFromFragment} from './fragment-state'
import { State } from './app-state';
import './index.css';
import defaultScad from './default-scad'
import debug from 'debug';
const log = debug('app:log');
if (process.env.NODE_ENV !== 'production') {
debug.enable('*');
log('Logging is enabled!');
} else {
debug.disable();
}
(async () => {
@ -17,11 +28,12 @@ import './index.css';
const fs = await createEditorFS(workingDir);
await registerOpenSCADLanguage(fs, workingDir, zipArchives);
const initialState = readStateFromFragment() ?? {
const initialState: State = readStateFromFragment() ?? {
params: {
source: 'cube(1);\ntranslate([0.5, 0.5, 0.5])\n\tcube(1);',
source: defaultScad,
features: [],
}
} as State;
};
const defaultFeatures = ['manifold', 'fast-csg', 'lazy-union'];
defaultFeatures.forEach(f => {

View file

@ -47,7 +47,7 @@ const builtinCompletions = [
insertText: `${v}`,
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet
})),
...openscadLanguage.language.keywords.map(v => ({
...openscadLanguage.language.keywords.map((v: string) => ({
label: v,
kind: monaco.languages.CompletionItemKind.Function,
insertText: v,
@ -92,7 +92,7 @@ export async function buildOpenSCADCompletionItemProvider(fs: FS, workingDir: st
path = toAbsolutePath(path);
try {
const bytes = await fs.readFileSync(path);
const src = new TextDecoder("utf-8").decode(bytes);
const src = new TextDecoder("utf-8").decode(bytes as any);
return src;
} catch (e) {
throw e;

View file

@ -43,7 +43,7 @@ export function spawnOpenSCAD({inputs, args, outputPaths}: OpenSCADInvocation):
}
return AbortablePromise<OpenSCADInvocationResults>((resolve, reject) => {
worker = new Worker('./openscad-worker-inlined.js');//, {type: "module"})
worker = new Worker('./openscad-worker.js');//, {type: "module"})
// if (navigator.userAgent.indexOf(' Chrome/') < 0) {
// worker = new Worker('./openscad-worker-firefox.js'); // {'type': 'module'}
// } else {

View file

@ -8,7 +8,7 @@
"WebWorker",
],
"rootDir": "src",
"outDir": "js",
// "outDir": "js",
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
@ -20,11 +20,12 @@
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": false,
// "noEmit": true,
"jsx": "react-jsx"
},
"include": [
"src/*.ts",
"src/*.tsx",
// "public"
]
}

49
webpack.config.js Normal file
View file

@ -0,0 +1,49 @@
const CopyPlugin = require("copy-webpack-plugin");
const path = require('path');
module.exports = {
entry: './src/index.tsx',
devtool: 'inline-source-map',
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
{
test: /\.css$/i,
use: [
{loader: 'css-loader', options:{url: false}}
]
}
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
output: {
filename: 'index.js',
path: path.resolve(__dirname, 'dist'),
},
devServer: {
static: path.join(__dirname, "dist"),
compress: true,
port: 4000,
},
plugins: [
new CopyPlugin({
patterns: [
{
from: path.resolve(__dirname, 'public'),
toType: 'dir',
},
{
from: path.resolve(__dirname, 'src/wasm/openscad.js'),
from: path.resolve(__dirname, 'src/wasm/openscad.wasm'),
},
],
}),
],
};