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": {
|
||||
"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": "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": {
|
||||
"extends": [
|
||||
|
|
@ -52,8 +52,6 @@
|
|||
"node": ">=18.12.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-replace": "^5.0.7",
|
||||
"@rollup/plugin-typescript": "^11.1.6",
|
||||
"@types/chroma-js": "^2.4.5",
|
||||
"@types/debug": "^4.1.12",
|
||||
"@types/filesystem": "^0.0.36",
|
||||
|
|
@ -62,15 +60,13 @@
|
|||
"@types/react": "^18.3.18",
|
||||
"@types/react-dom": "^18.3.5",
|
||||
"@types/uzip": "^0.20201231.2",
|
||||
"concurrently": "^7.6.0",
|
||||
"@types/web": "^0.0.140",
|
||||
"copy-webpack-plugin": "^11.0.0",
|
||||
"css-loader": "^7.1.2",
|
||||
"jest": "^29.7.0",
|
||||
"jest-puppeteer": "^11.0.0",
|
||||
"livereload": "^0.9.3",
|
||||
"puppeteer": "^23.11.1",
|
||||
"rollup": "^2.79.2",
|
||||
"rollup-plugin-typescript2": "^0.36.0",
|
||||
"serve": "^14.2.4",
|
||||
"style-loader": "^4.0.0",
|
||||
"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 type BrowserFSInterface = {
|
||||
BFSRequire: (name: string) => any,
|
||||
declare interface BrowserFSInterface {
|
||||
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,
|
||||
configure: (options: any, callback: (e?: any) => void) => void,
|
||||
declare var BrowserFS: BrowserFSInterface;
|
||||
|
||||
declare module 'browserfs' {
|
||||
export = BrowserFS;
|
||||
}
|
||||
|
||||
EmscriptenFS: {
|
||||
new(fs: FS, path: string, errnoCodes: object): EmscriptenFS
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -61,14 +61,14 @@ window.addEventListener('load', async () => {
|
|||
|
||||
registerCustomAppHeightCSSProperty();
|
||||
|
||||
const fs = await createEditorFS({prefix: '/libraries/', allowPersistence: isInStandaloneMode});
|
||||
const fs = await createEditorFS({prefix: '/libraries/', allowPersistence: isInStandaloneMode()});
|
||||
|
||||
await registerOpenSCADLanguage(fs, '/', zipArchives);
|
||||
|
||||
let statePersister: StatePersister;
|
||||
let persistedState: State | null = null;
|
||||
|
||||
if (isInStandaloneMode) {
|
||||
if (isInStandaloneMode()) {
|
||||
const fs: FS = BrowserFS.BFSRequire('fs')
|
||||
try {
|
||||
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 { 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 = {
|
||||
wasmMemory?: WebAssembly.Memory,
|
||||
mountArchives: boolean,
|
||||
inputs?: Source[],
|
||||
args: string[],
|
||||
outputPaths?: string[],
|
||||
}
|
||||
|
||||
export type OpenSCADInvocationResults = {
|
||||
exitCode?: number,
|
||||
error?: string,
|
||||
|
|
@ -31,12 +18,16 @@ export type OpenSCADInvocationResults = {
|
|||
mergedOutputs: MergedOutputs,
|
||||
elapsedMillis: number,
|
||||
};
|
||||
|
||||
export type ProcessStreams = {stderr: string} | {stdout: string}
|
||||
export type OpenSCADInvocationCallback = {result: OpenSCADInvocationResults} | ProcessStreams;
|
||||
|
||||
export function spawnOpenSCAD(invocation: OpenSCADInvocation, streamsCallback: (ps: ProcessStreams) => void): AbortablePromise<OpenSCADInvocationResults> {
|
||||
var worker: Worker | null;
|
||||
var rejection: (err: any) => void;
|
||||
export function spawnOpenSCAD(
|
||||
invocation: OpenSCADInvocation,
|
||||
streamsCallback: (ps: ProcessStreams) => void
|
||||
): AbortablePromise<OpenSCADInvocationResults> {
|
||||
let worker: Worker | null;
|
||||
let rejection: (err: any) => void;
|
||||
|
||||
function terminate() {
|
||||
if (!worker) {
|
||||
|
|
@ -46,10 +37,10 @@ export function spawnOpenSCAD(invocation: OpenSCADInvocation, streamsCallback: (
|
|||
worker = null;
|
||||
}
|
||||
|
||||
return AbortablePromise<OpenSCADInvocationResults>((resolve, reject) => {
|
||||
worker = new Worker('./openscad-worker.js');
|
||||
return AbortablePromise<OpenSCADInvocationResults>((resolve: (result: OpenSCADInvocationResults) => void, reject: (error: any) => void) => {
|
||||
worker = new Worker('./openscad-worker.js');//, { type: 'module' });
|
||||
rejection = reject;
|
||||
worker.onmessage = (e: {data: OpenSCADInvocationCallback}) => {
|
||||
worker.onmessage = (e: MessageEvent<OpenSCADInvocationCallback>) => {
|
||||
if ('result' in e.data) {
|
||||
resolve(e.data.result);
|
||||
terminate();
|
||||
|
|
|
|||
|
|
@ -1,38 +1,36 @@
|
|||
// 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 { createEditorFS, getParentDir, symlinkLibraries } from "../fs/filesystem";
|
||||
import { OpenSCADInvocation, OpenSCADInvocationCallback, OpenSCADInvocationResults } from "./openscad-runner";
|
||||
import { deployedArchiveNames, zipArchives } from "../fs/zip-archives";
|
||||
import { fetchSource } from "../utils.js";
|
||||
declare var BrowserFS: BrowserFSInterface
|
||||
import { createEditorFS, getParentDir, symlinkLibraries } from "../fs/filesystem.ts";
|
||||
import { OpenSCADInvocation, OpenSCADInvocationCallback, OpenSCADInvocationResults } from "./openscad-runner.ts";
|
||||
import { deployedArchiveNames, zipArchives } from "../fs/zip-archives.ts";
|
||||
import { fetchSource } from "../utils.ts";
|
||||
|
||||
importScripts("browserfs.min.js");
|
||||
|
||||
declare const self: DedicatedWorkerGlobalScope;
|
||||
|
||||
export type MergedOutputs = {stdout?: string, stderr?: string, error?: string}[];
|
||||
|
||||
function callback(payload: OpenSCADInvocationCallback) {
|
||||
postMessage(payload);
|
||||
self.postMessage(payload);
|
||||
}
|
||||
|
||||
addEventListener('message', async (e) => {
|
||||
|
||||
self.addEventListener('message', async (e: MessageEvent<OpenSCADInvocation>) => {
|
||||
const {
|
||||
mountArchives,
|
||||
inputs,
|
||||
args,
|
||||
outputPaths,
|
||||
wasmMemory,
|
||||
} = e.data as OpenSCADInvocation;
|
||||
} = e.data;
|
||||
|
||||
const mergedOutputs: MergedOutputs = [];
|
||||
let instance: any;
|
||||
const start = performance.now();
|
||||
try {
|
||||
instance = await OpenSCAD({
|
||||
wasmMemory,
|
||||
buffer: wasmMemory && wasmMemory.buffer,
|
||||
noInitialRun: true,
|
||||
'print': (text: string) => {
|
||||
console.debug('stdout: ' + text);
|
||||
|
|
@ -44,9 +42,6 @@ addEventListener('message', async (e) => {
|
|||
callback({stderr: text})
|
||||
mergedOutputs.push({ stderr: text })
|
||||
},
|
||||
'ENV': {
|
||||
'OPENSCADPATH': '/libraries',
|
||||
},
|
||||
});
|
||||
|
||||
if (mountArchives) {
|
||||
|
|
@ -140,7 +135,6 @@ addEventListener('message', async (e) => {
|
|||
}
|
||||
|
||||
console.debug(result);
|
||||
|
||||
callback({result});
|
||||
} catch (e) {
|
||||
const end = performance.now();
|
||||
|
|
|
|||
|
|
@ -138,9 +138,9 @@ export function registerCustomAppHeightCSSProperty() {
|
|||
}
|
||||
|
||||
// In PWA mode, persist files in LocalStorage instead of the hash fragment.
|
||||
export const isInStandaloneMode =
|
||||
// true
|
||||
Boolean(('standalone' in window.navigator) && (window.navigator.standalone));
|
||||
export function isInStandaloneMode() {
|
||||
return Boolean(('standalone' in window.navigator) && (window.navigator.standalone));
|
||||
}
|
||||
|
||||
export function downloadUrl(url: string, filename: string) {
|
||||
const link = document.createElement('a');
|
||||
|
|
|
|||
|
|
@ -5,10 +5,9 @@
|
|||
"dom",
|
||||
"dom.iterable",
|
||||
"ES2022",
|
||||
"WebWorker",
|
||||
"WebWorker"
|
||||
],
|
||||
"rootDir": "src",
|
||||
// "outDir": "js",
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
|
|
@ -17,17 +16,22 @@
|
|||
"forceConsistentCasingInFileNames": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
// "noEmit": true,
|
||||
"jsx": "react-jsx"
|
||||
"jsx": "react-jsx",
|
||||
"noEmit": true,
|
||||
"allowImportingTsExtensions": true,
|
||||
"declaration": true,
|
||||
"baseUrl": "src",
|
||||
"paths": {
|
||||
"*": ["*"]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.tsx",
|
||||
"src/**/*.js",
|
||||
// "public"
|
||||
"src/**/*.js"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
|
|
|
|||
|
|
@ -1,111 +1,179 @@
|
|||
const webpack = require('webpack');
|
||||
const CopyPlugin = require("copy-webpack-plugin");
|
||||
const WorkboxPlugin = require('workbox-webpack-plugin');
|
||||
const webpack = require('webpack');
|
||||
|
||||
const path = require('path');
|
||||
const packageConfig = require('./package.json');
|
||||
|
||||
module.exports = [{
|
||||
entry: './src/index.tsx',
|
||||
// devtool: 'inline-source-map',
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
use: 'ts-loader',
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
{
|
||||
test: /\.css$/i,
|
||||
use: [
|
||||
"style-loader",
|
||||
{
|
||||
loader: 'css-loader',
|
||||
options:{url: false},
|
||||
}
|
||||
]
|
||||
},
|
||||
// {
|
||||
// test: /\.(png|gif|woff|woff2|eot|ttf|svg)$/,
|
||||
// loader: "url-loader?limit=100000"
|
||||
// },
|
||||
],
|
||||
},
|
||||
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 webpack.EnvironmentPlugin({
|
||||
'process.env.NODE_ENV': 'development',
|
||||
}),
|
||||
...(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',
|
||||
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',
|
||||
devtool: isDev ? 'source-map' : 'nosources-source-map',
|
||||
mode: isDev ? 'development' : 'production',
|
||||
target: 'web',
|
||||
// devtool: 'inline-source-map',
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
use: {
|
||||
loader: 'ts-loader',
|
||||
options: {
|
||||
cacheName: 'all',
|
||||
expiration: {
|
||||
maxEntries: 1000,
|
||||
purgeOnQuotaError: true,
|
||||
},
|
||||
},
|
||||
}],
|
||||
}),
|
||||
] : []),
|
||||
new CopyPlugin({
|
||||
patterns: [
|
||||
{
|
||||
from: path.resolve(__dirname, 'public'),
|
||||
toType: 'dir',
|
||||
transpileOnly: true,
|
||||
compilerOptions: {
|
||||
module: 'esnext',
|
||||
moduleResolution: 'node',
|
||||
target: 'ES2022',
|
||||
lib: ['WebWorker', 'ES2022'],
|
||||
sourceMap: isDev,
|
||||
inlineSources: isDev
|
||||
}
|
||||
}
|
||||
},
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
{
|
||||
from: path.resolve(__dirname, 'node_modules/primeicons/fonts'),
|
||||
to: path.resolve(__dirname, 'dist/fonts'),
|
||||
toType: 'dir',
|
||||
},
|
||||
{
|
||||
from: path.resolve(__dirname, 'src/wasm/openscad.js'),
|
||||
from: path.resolve(__dirname, 'src/wasm/openscad.wasm'),
|
||||
{
|
||||
test: /\.css$/i,
|
||||
use: [
|
||||
"style-loader",
|
||||
{
|
||||
loader: 'css-loader',
|
||||
options:{url: false},
|
||||
}
|
||||
]
|
||||
},
|
||||
// {
|
||||
// test: /\.(png|gif|woff|woff2|eot|ttf|svg)$/,
|
||||
// loader: "url-loader?limit=100000"
|
||||
// },
|
||||
],
|
||||
}),
|
||||
],
|
||||
}/*, {
|
||||
entry: './src/sw.ts',
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
use: 'ts-loader',
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
},
|
||||
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 webpack.EnvironmentPlugin({
|
||||
'process.env.NODE_ENV': 'development',
|
||||
}),
|
||||
...(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,
|
||||
},
|
||||
},
|
||||
}],
|
||||
}),
|
||||
] : []),
|
||||
new CopyPlugin({
|
||||
patterns: [
|
||||
{
|
||||
from: path.resolve(__dirname, 'public'),
|
||||
toType: 'dir',
|
||||
},
|
||||
{
|
||||
from: path.resolve(__dirname, 'node_modules/primeicons/fonts'),
|
||||
to: path.resolve(__dirname, 'dist/fonts'),
|
||||
toType: 'dir',
|
||||
},
|
||||
{
|
||||
from: path.resolve(__dirname, 'src/wasm/openscad.js'),
|
||||
from: path.resolve(__dirname, 'src/wasm/openscad.wasm'),
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.ts', '.js'],
|
||||
{
|
||||
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: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
use: {
|
||||
loader: 'ts-loader',
|
||||
options: {
|
||||
transpileOnly: true,
|
||||
compilerOptions: {
|
||||
module: 'esnext',
|
||||
moduleResolution: 'node',
|
||||
target: 'ES2022',
|
||||
lib: ['WebWorker', 'ES2022'],
|
||||
sourceMap: isDev,
|
||||
inlineSources: isDev
|
||||
}
|
||||
}
|
||||
},
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
{
|
||||
test: /\.wasm$/,
|
||||
type: 'asset/resource'
|
||||
}
|
||||
]
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.tsx', '.ts', '.js', '.mjs', '.wasm'],
|
||||
modules: [
|
||||
path.resolve(__dirname, 'src'),
|
||||
'node_modules'
|
||||
],
|
||||
fallback: {
|
||||
fs: false,
|
||||
path: false,
|
||||
module: false
|
||||
}
|
||||
},
|
||||
externals: {
|
||||
'browserfs': 'BrowserFS'
|
||||
},
|
||||
plugins: [
|
||||
new webpack.EnvironmentPlugin({
|
||||
'process.env.NODE_ENV': 'development',
|
||||
}),
|
||||
],
|
||||
},
|
||||
output: {
|
||||
filename: 'sw.js',
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
},
|
||||
}*/];
|
||||
];
|
||||
|
|
|
|||
Loading…
Reference in a new issue