Replace rollup w/ webpack for the web worker
This commit is contained in:
parent
a4a33d2541
commit
a0015af28e
9 changed files with 232 additions and 188 deletions
|
|
@ -1,25 +0,0 @@
|
||||||
import typescript from 'rollup-plugin-typescript2';
|
|
||||||
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/runner/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),
|
|
||||||
})
|
|
||||||
]
|
|
||||||
},
|
|
||||||
];
|
|
||||||
10
package.json
10
package.json
|
|
@ -25,10 +25,10 @@
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test:e2e": "jest",
|
"test:e2e": "jest",
|
||||||
"start:development": "concurrently 'npx webpack serve --mode=development' 'NODE_ENV=development npx rollup --config openscad-worker.rollup.config.js --watch'",
|
"start:development": "npx webpack serve --mode=development",
|
||||||
"start:production": "NODE_ENV=production PUBLIC_URL=http://localhost:3000/dist/ npm run build && npx serve",
|
"start:production": "NODE_ENV=production PUBLIC_URL=http://localhost:3000/dist/ npm run build && npx serve",
|
||||||
"start": "npm run start:development",
|
"start": "npm run start:development",
|
||||||
"build": "NODE_ENV=production npx rollup --config openscad-worker.rollup.config.js && webpack --mode=production"
|
"build": "NODE_ENV=production webpack --mode=production"
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
"extends": [
|
"extends": [
|
||||||
|
|
@ -52,8 +52,6 @@
|
||||||
"node": ">=18.12.0"
|
"node": ">=18.12.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@rollup/plugin-replace": "^5.0.7",
|
|
||||||
"@rollup/plugin-typescript": "^11.1.6",
|
|
||||||
"@types/chroma-js": "^2.4.5",
|
"@types/chroma-js": "^2.4.5",
|
||||||
"@types/debug": "^4.1.12",
|
"@types/debug": "^4.1.12",
|
||||||
"@types/filesystem": "^0.0.36",
|
"@types/filesystem": "^0.0.36",
|
||||||
|
|
@ -62,15 +60,13 @@
|
||||||
"@types/react": "^18.3.18",
|
"@types/react": "^18.3.18",
|
||||||
"@types/react-dom": "^18.3.5",
|
"@types/react-dom": "^18.3.5",
|
||||||
"@types/uzip": "^0.20201231.2",
|
"@types/uzip": "^0.20201231.2",
|
||||||
"concurrently": "^7.6.0",
|
"@types/web": "^0.0.140",
|
||||||
"copy-webpack-plugin": "^11.0.0",
|
"copy-webpack-plugin": "^11.0.0",
|
||||||
"css-loader": "^7.1.2",
|
"css-loader": "^7.1.2",
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"jest-puppeteer": "^11.0.0",
|
"jest-puppeteer": "^11.0.0",
|
||||||
"livereload": "^0.9.3",
|
"livereload": "^0.9.3",
|
||||||
"puppeteer": "^23.11.1",
|
"puppeteer": "^23.11.1",
|
||||||
"rollup": "^2.79.2",
|
|
||||||
"rollup-plugin-typescript2": "^0.36.0",
|
|
||||||
"serve": "^14.2.4",
|
"serve": "^14.2.4",
|
||||||
"style-loader": "^4.0.0",
|
"style-loader": "^4.0.0",
|
||||||
"ts-loader": "^9.5.1",
|
"ts-loader": "^9.5.1",
|
||||||
|
|
|
||||||
32
src/fs/BrowserFS.d.ts
vendored
32
src/fs/BrowserFS.d.ts
vendored
|
|
@ -11,13 +11,29 @@ declare interface FS {
|
||||||
|
|
||||||
declare interface EmscriptenFS extends FS {}
|
declare interface EmscriptenFS extends FS {}
|
||||||
|
|
||||||
declare type BrowserFSInterface = {
|
declare interface BrowserFSInterface {
|
||||||
BFSRequire: (name: string) => any,
|
EmscriptenFS: any;
|
||||||
|
BFSRequire: (module: string) => any;
|
||||||
|
install: (obj: any) => void;
|
||||||
|
configure: (config: any, cb: (e?: Error) => void) => void;
|
||||||
|
FileSystem: {
|
||||||
|
InMemory: any;
|
||||||
|
ZipFS: any;
|
||||||
|
MountableFileSystem: any;
|
||||||
|
LocalStorage: any;
|
||||||
|
XmlHttpRequest: any;
|
||||||
|
};
|
||||||
|
Buffer: {
|
||||||
|
from: (data: any, encoding?: string) => any;
|
||||||
|
alloc: (size: number) => any;
|
||||||
|
};
|
||||||
|
initialize: (config: any) => Promise<void>;
|
||||||
|
WorkerFS?: any;
|
||||||
|
}
|
||||||
|
|
||||||
install: (windowOrSelf: Window) => void,
|
declare var BrowserFS: BrowserFSInterface;
|
||||||
configure: (options: any, callback: (e?: any) => void) => void,
|
|
||||||
|
declare module 'browserfs' {
|
||||||
|
export = BrowserFS;
|
||||||
|
}
|
||||||
|
|
||||||
EmscriptenFS: {
|
|
||||||
new(fs: FS, path: string, errnoCodes: object): EmscriptenFS
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
|
||||||
|
|
@ -61,14 +61,14 @@ window.addEventListener('load', async () => {
|
||||||
|
|
||||||
registerCustomAppHeightCSSProperty();
|
registerCustomAppHeightCSSProperty();
|
||||||
|
|
||||||
const fs = await createEditorFS({prefix: '/libraries/', allowPersistence: isInStandaloneMode});
|
const fs = await createEditorFS({prefix: '/libraries/', allowPersistence: isInStandaloneMode()});
|
||||||
|
|
||||||
await registerOpenSCADLanguage(fs, '/', zipArchives);
|
await registerOpenSCADLanguage(fs, '/', zipArchives);
|
||||||
|
|
||||||
let statePersister: StatePersister;
|
let statePersister: StatePersister;
|
||||||
let persistedState: State | null = null;
|
let persistedState: State | null = null;
|
||||||
|
|
||||||
if (isInStandaloneMode) {
|
if (isInStandaloneMode()) {
|
||||||
const fs: FS = BrowserFS.BFSRequire('fs')
|
const fs: FS = BrowserFS.BFSRequire('fs')
|
||||||
try {
|
try {
|
||||||
const data = JSON.parse(new TextDecoder("utf-8").decode(fs.readFileSync('/state.json')));
|
const data = JSON.parse(new TextDecoder("utf-8").decode(fs.readFileSync('/state.json')));
|
||||||
|
|
|
||||||
|
|
@ -4,26 +4,13 @@ import { MergedOutputs } from "./openscad-worker";
|
||||||
import { AbortablePromise } from "../utils";
|
import { AbortablePromise } from "../utils";
|
||||||
import { Source } from "../state/app-state";
|
import { Source } from "../state/app-state";
|
||||||
|
|
||||||
export function createWasmMemory({maximumMegabytes, maximumBytes}: {maximumMegabytes: number, maximumBytes: number}) {
|
|
||||||
const pageSize = 64 * 1024; // 64KB
|
|
||||||
if (!maximumBytes) {
|
|
||||||
maximumBytes = maximumMegabytes * 1024 * 1024;
|
|
||||||
}
|
|
||||||
return new WebAssembly.Memory({
|
|
||||||
initial: Math.floor(maximumBytes / 2 / pageSize),
|
|
||||||
maximum: Math.floor(maximumBytes / pageSize),
|
|
||||||
shared: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Output is {outputs: [name, content][], mergedOutputs: [{(stderr|stdout|error)?: string}], exitCode: number}
|
|
||||||
export type OpenSCADInvocation = {
|
export type OpenSCADInvocation = {
|
||||||
wasmMemory?: WebAssembly.Memory,
|
|
||||||
mountArchives: boolean,
|
mountArchives: boolean,
|
||||||
inputs?: Source[],
|
inputs?: Source[],
|
||||||
args: string[],
|
args: string[],
|
||||||
outputPaths?: string[],
|
outputPaths?: string[],
|
||||||
}
|
}
|
||||||
|
|
||||||
export type OpenSCADInvocationResults = {
|
export type OpenSCADInvocationResults = {
|
||||||
exitCode?: number,
|
exitCode?: number,
|
||||||
error?: string,
|
error?: string,
|
||||||
|
|
@ -31,12 +18,16 @@ export type OpenSCADInvocationResults = {
|
||||||
mergedOutputs: MergedOutputs,
|
mergedOutputs: MergedOutputs,
|
||||||
elapsedMillis: number,
|
elapsedMillis: number,
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ProcessStreams = {stderr: string} | {stdout: string}
|
export type ProcessStreams = {stderr: string} | {stdout: string}
|
||||||
export type OpenSCADInvocationCallback = {result: OpenSCADInvocationResults} | ProcessStreams;
|
export type OpenSCADInvocationCallback = {result: OpenSCADInvocationResults} | ProcessStreams;
|
||||||
|
|
||||||
export function spawnOpenSCAD(invocation: OpenSCADInvocation, streamsCallback: (ps: ProcessStreams) => void): AbortablePromise<OpenSCADInvocationResults> {
|
export function spawnOpenSCAD(
|
||||||
var worker: Worker | null;
|
invocation: OpenSCADInvocation,
|
||||||
var rejection: (err: any) => void;
|
streamsCallback: (ps: ProcessStreams) => void
|
||||||
|
): AbortablePromise<OpenSCADInvocationResults> {
|
||||||
|
let worker: Worker | null;
|
||||||
|
let rejection: (err: any) => void;
|
||||||
|
|
||||||
function terminate() {
|
function terminate() {
|
||||||
if (!worker) {
|
if (!worker) {
|
||||||
|
|
@ -46,10 +37,10 @@ export function spawnOpenSCAD(invocation: OpenSCADInvocation, streamsCallback: (
|
||||||
worker = null;
|
worker = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return AbortablePromise<OpenSCADInvocationResults>((resolve, reject) => {
|
return AbortablePromise<OpenSCADInvocationResults>((resolve: (result: OpenSCADInvocationResults) => void, reject: (error: any) => void) => {
|
||||||
worker = new Worker('./openscad-worker.js');
|
worker = new Worker('./openscad-worker.js');//, { type: 'module' });
|
||||||
rejection = reject;
|
rejection = reject;
|
||||||
worker.onmessage = (e: {data: OpenSCADInvocationCallback}) => {
|
worker.onmessage = (e: MessageEvent<OpenSCADInvocationCallback>) => {
|
||||||
if ('result' in e.data) {
|
if ('result' in e.data) {
|
||||||
resolve(e.data.result);
|
resolve(e.data.result);
|
||||||
terminate();
|
terminate();
|
||||||
|
|
|
||||||
|
|
@ -1,38 +1,36 @@
|
||||||
// Portions of this file are Copyright 2021 Google LLC, and licensed under GPL2+. See COPYING.
|
// Portions of this file are Copyright 2021 Google LLC, and licensed under GPL2+. See COPYING.
|
||||||
|
|
||||||
|
/// <reference lib="webworker" />
|
||||||
import OpenSCAD from "../wasm/openscad.js";
|
import OpenSCAD from "../wasm/openscad.js";
|
||||||
|
|
||||||
import { createEditorFS, getParentDir, symlinkLibraries } from "../fs/filesystem";
|
import { createEditorFS, getParentDir, symlinkLibraries } from "../fs/filesystem.ts";
|
||||||
import { OpenSCADInvocation, OpenSCADInvocationCallback, OpenSCADInvocationResults } from "./openscad-runner";
|
import { OpenSCADInvocation, OpenSCADInvocationCallback, OpenSCADInvocationResults } from "./openscad-runner.ts";
|
||||||
import { deployedArchiveNames, zipArchives } from "../fs/zip-archives";
|
import { deployedArchiveNames, zipArchives } from "../fs/zip-archives.ts";
|
||||||
import { fetchSource } from "../utils.js";
|
import { fetchSource } from "../utils.ts";
|
||||||
declare var BrowserFS: BrowserFSInterface
|
|
||||||
|
|
||||||
importScripts("browserfs.min.js");
|
importScripts("browserfs.min.js");
|
||||||
|
|
||||||
|
declare const self: DedicatedWorkerGlobalScope;
|
||||||
|
|
||||||
export type MergedOutputs = {stdout?: string, stderr?: string, error?: string}[];
|
export type MergedOutputs = {stdout?: string, stderr?: string, error?: string}[];
|
||||||
|
|
||||||
function callback(payload: OpenSCADInvocationCallback) {
|
function callback(payload: OpenSCADInvocationCallback) {
|
||||||
postMessage(payload);
|
self.postMessage(payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
addEventListener('message', async (e) => {
|
self.addEventListener('message', async (e: MessageEvent<OpenSCADInvocation>) => {
|
||||||
|
|
||||||
const {
|
const {
|
||||||
mountArchives,
|
mountArchives,
|
||||||
inputs,
|
inputs,
|
||||||
args,
|
args,
|
||||||
outputPaths,
|
outputPaths,
|
||||||
wasmMemory,
|
} = e.data;
|
||||||
} = e.data as OpenSCADInvocation;
|
|
||||||
|
|
||||||
const mergedOutputs: MergedOutputs = [];
|
const mergedOutputs: MergedOutputs = [];
|
||||||
let instance: any;
|
let instance: any;
|
||||||
const start = performance.now();
|
const start = performance.now();
|
||||||
try {
|
try {
|
||||||
instance = await OpenSCAD({
|
instance = await OpenSCAD({
|
||||||
wasmMemory,
|
|
||||||
buffer: wasmMemory && wasmMemory.buffer,
|
|
||||||
noInitialRun: true,
|
noInitialRun: true,
|
||||||
'print': (text: string) => {
|
'print': (text: string) => {
|
||||||
console.debug('stdout: ' + text);
|
console.debug('stdout: ' + text);
|
||||||
|
|
@ -44,9 +42,6 @@ addEventListener('message', async (e) => {
|
||||||
callback({stderr: text})
|
callback({stderr: text})
|
||||||
mergedOutputs.push({ stderr: text })
|
mergedOutputs.push({ stderr: text })
|
||||||
},
|
},
|
||||||
'ENV': {
|
|
||||||
'OPENSCADPATH': '/libraries',
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (mountArchives) {
|
if (mountArchives) {
|
||||||
|
|
@ -140,7 +135,6 @@ addEventListener('message', async (e) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
console.debug(result);
|
console.debug(result);
|
||||||
|
|
||||||
callback({result});
|
callback({result});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const end = performance.now();
|
const end = performance.now();
|
||||||
|
|
|
||||||
|
|
@ -138,9 +138,9 @@ export function registerCustomAppHeightCSSProperty() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// In PWA mode, persist files in LocalStorage instead of the hash fragment.
|
// In PWA mode, persist files in LocalStorage instead of the hash fragment.
|
||||||
export const isInStandaloneMode =
|
export function isInStandaloneMode() {
|
||||||
// true
|
return Boolean(('standalone' in window.navigator) && (window.navigator.standalone));
|
||||||
Boolean(('standalone' in window.navigator) && (window.navigator.standalone));
|
}
|
||||||
|
|
||||||
export function downloadUrl(url: string, filename: string) {
|
export function downloadUrl(url: string, filename: string) {
|
||||||
const link = document.createElement('a');
|
const link = document.createElement('a');
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,9 @@
|
||||||
"dom",
|
"dom",
|
||||||
"dom.iterable",
|
"dom.iterable",
|
||||||
"ES2022",
|
"ES2022",
|
||||||
"WebWorker",
|
"WebWorker"
|
||||||
],
|
],
|
||||||
"rootDir": "src",
|
"rootDir": "src",
|
||||||
// "outDir": "js",
|
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
|
|
@ -17,17 +16,22 @@
|
||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"noFallthroughCasesInSwitch": true,
|
"noFallthroughCasesInSwitch": true,
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "bundler",
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
// "noEmit": true,
|
"jsx": "react-jsx",
|
||||||
"jsx": "react-jsx"
|
"noEmit": true,
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"declaration": true,
|
||||||
|
"baseUrl": "src",
|
||||||
|
"paths": {
|
||||||
|
"*": ["*"]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"src/**/*.ts",
|
"src/**/*.ts",
|
||||||
"src/**/*.tsx",
|
"src/**/*.tsx",
|
||||||
"src/**/*.js",
|
"src/**/*.js"
|
||||||
// "public"
|
|
||||||
],
|
],
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"node_modules",
|
"node_modules",
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,38 @@
|
||||||
|
const webpack = require('webpack');
|
||||||
const CopyPlugin = require("copy-webpack-plugin");
|
const CopyPlugin = require("copy-webpack-plugin");
|
||||||
const WorkboxPlugin = require('workbox-webpack-plugin');
|
const WorkboxPlugin = require('workbox-webpack-plugin');
|
||||||
const webpack = require('webpack');
|
|
||||||
|
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
const packageConfig = require('./package.json');
|
||||||
|
|
||||||
module.exports = [{
|
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';
|
||||||
|
|
||||||
|
module.exports = [
|
||||||
|
{
|
||||||
entry: './src/index.tsx',
|
entry: './src/index.tsx',
|
||||||
|
devtool: isDev ? 'source-map' : 'nosources-source-map',
|
||||||
|
mode: isDev ? 'development' : 'production',
|
||||||
|
target: 'web',
|
||||||
// devtool: 'inline-source-map',
|
// devtool: 'inline-source-map',
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
test: /\.tsx?$/,
|
test: /\.tsx?$/,
|
||||||
use: 'ts-loader',
|
use: {
|
||||||
|
loader: 'ts-loader',
|
||||||
|
options: {
|
||||||
|
transpileOnly: true,
|
||||||
|
compilerOptions: {
|
||||||
|
module: 'esnext',
|
||||||
|
moduleResolution: 'node',
|
||||||
|
target: 'ES2022',
|
||||||
|
lib: ['WebWorker', 'ES2022'],
|
||||||
|
sourceMap: isDev,
|
||||||
|
inlineSources: isDev
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
exclude: /node_modules/,
|
exclude: /node_modules/,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -90,22 +111,69 @@ module.exports = [{
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}/*, {
|
},
|
||||||
entry: './src/sw.ts',
|
{
|
||||||
|
entry: './src/runner/openscad-worker.ts',
|
||||||
|
output: {
|
||||||
|
filename: 'openscad-worker.js',
|
||||||
|
path: path.resolve(__dirname, 'dist'),
|
||||||
|
globalObject: 'self',
|
||||||
|
// library: {
|
||||||
|
// type: 'module'
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
devtool: isDev ? 'source-map' : 'nosources-source-map',
|
||||||
|
mode: 'production',
|
||||||
|
// mode: isDev ? 'development' : 'production',
|
||||||
|
target: 'webworker',
|
||||||
|
// experiments: {
|
||||||
|
// outputModule: true,
|
||||||
|
// },
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
test: /\.tsx?$/,
|
test: /\.tsx?$/,
|
||||||
use: 'ts-loader',
|
use: {
|
||||||
|
loader: 'ts-loader',
|
||||||
|
options: {
|
||||||
|
transpileOnly: true,
|
||||||
|
compilerOptions: {
|
||||||
|
module: 'esnext',
|
||||||
|
moduleResolution: 'node',
|
||||||
|
target: 'ES2022',
|
||||||
|
lib: ['WebWorker', 'ES2022'],
|
||||||
|
sourceMap: isDev,
|
||||||
|
inlineSources: isDev
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
exclude: /node_modules/,
|
exclude: /node_modules/,
|
||||||
},
|
},
|
||||||
],
|
{
|
||||||
|
test: /\.wasm$/,
|
||||||
|
type: 'asset/resource'
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: ['.ts', '.js'],
|
extensions: ['.tsx', '.ts', '.js', '.mjs', '.wasm'],
|
||||||
|
modules: [
|
||||||
|
path.resolve(__dirname, 'src'),
|
||||||
|
'node_modules'
|
||||||
|
],
|
||||||
|
fallback: {
|
||||||
|
fs: false,
|
||||||
|
path: false,
|
||||||
|
module: false
|
||||||
|
}
|
||||||
},
|
},
|
||||||
output: {
|
externals: {
|
||||||
filename: 'sw.js',
|
'browserfs': 'BrowserFS'
|
||||||
path: path.resolve(__dirname, 'dist'),
|
|
||||||
},
|
},
|
||||||
}*/];
|
plugins: [
|
||||||
|
new webpack.EnvironmentPlugin({
|
||||||
|
'process.env.NODE_ENV': 'development',
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue