Move worker into webpack build #495
10
app/web/config/worker-loader.d.ts
vendored
Normal file
10
app/web/config/worker-loader.d.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
declare module "worker-loader!*" {
|
||||||
|
// You need to change `Worker`, if you specified a different value for the `workerType` option
|
||||||
|
class WebpackWorker extends Worker {
|
||||||
|
constructor();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uncomment this if you set the `esModule` option to `false`
|
||||||
|
// export = WebpackWorker;
|
||||||
|
export default WebpackWorker;
|
||||||
|
}
|
||||||
@@ -45,7 +45,8 @@
|
|||||||
"react-tabs": "^3.2.2",
|
"react-tabs": "^3.2.2",
|
||||||
"rich-markdown-editor": "^11.0.2",
|
"rich-markdown-editor": "^11.0.2",
|
||||||
"styled-components": "^5.2.0",
|
"styled-components": "^5.2.0",
|
||||||
"three": "^0.130.1"
|
"three": "^0.130.1",
|
||||||
|
"worker-loader": "^3.0.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/lodash": "^4.14.170",
|
"@types/lodash": "^4.14.170",
|
||||||
@@ -56,4 +57,4 @@
|
|||||||
"postcss-loader": "^6.1.1",
|
"postcss-loader": "^6.1.1",
|
||||||
"tailwindcss": "^2.2.7"
|
"tailwindcss": "^2.2.7"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
Mesh,
|
Mesh,
|
||||||
} from 'three'
|
} from 'three'
|
||||||
import { jsCadToCadhubParams } from './jscadParams'
|
import { jsCadToCadhubParams } from './jscadParams'
|
||||||
|
import TheWorker from 'worker-loader!./jscadWorker'
|
||||||
|
|
||||||
const materials = {
|
const materials = {
|
||||||
mesh: {
|
mesh: {
|
||||||
@@ -134,19 +135,7 @@ export const render: DefaultKernelExport['render'] = async ({
|
|||||||
}: RenderArgs) => {
|
}: RenderArgs) => {
|
||||||
if (!scriptWorker) {
|
if (!scriptWorker) {
|
||||||
const baseURI = document.baseURI.toString()
|
const baseURI = document.baseURI.toString()
|
||||||
const scriptUrl = '/demo-worker.js'
|
scriptWorker = new TheWorker()
|
||||||
const script = `let baseURI = '${baseURI}'
|
|
||||||
importScripts(new URL('${scriptUrl}',baseURI))
|
|
||||||
let worker = jscadWorker({
|
|
||||||
baseURI: baseURI,
|
|
||||||
scope:'worker',
|
|
||||||
convertToSolids: 'buffers',
|
|
||||||
callback:(params)=>self.postMessage(params),
|
|
||||||
})
|
|
||||||
self.addEventListener('message', (e)=>worker.postMessage(e.data))
|
|
||||||
`
|
|
||||||
const blob = new Blob([script], { type: 'text/javascript' })
|
|
||||||
scriptWorker = new Worker(window.URL.createObjectURL(blob))
|
|
||||||
let parameterDefinitions = []
|
let parameterDefinitions = []
|
||||||
scriptWorker.addEventListener('message', ({ data }) => {
|
scriptWorker.addEventListener('message', ({ data }) => {
|
||||||
if (data.action == 'parameterDefinitions') {
|
if (data.action == 'parameterDefinitions') {
|
||||||
|
|||||||
@@ -1,25 +1,3 @@
|
|||||||
(function(f) {
|
|
||||||
if (typeof exports === "object" && typeof module !== "undefined") {
|
|
||||||
module.exports = f()
|
|
||||||
} else if (typeof define === "function" && define.amd) {
|
|
||||||
define([], f)
|
|
||||||
} else {
|
|
||||||
var g;
|
|
||||||
if (typeof window !== "undefined") {
|
|
||||||
g = window
|
|
||||||
} else if (typeof global !== "undefined") {
|
|
||||||
g = global
|
|
||||||
} else if (typeof self !== "undefined") {
|
|
||||||
g = self
|
|
||||||
} else {
|
|
||||||
g = this
|
|
||||||
}
|
|
||||||
g.jscadWorker = f()
|
|
||||||
}
|
|
||||||
})(function() {
|
|
||||||
// multi purpose module
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const setPoints = (points, p, i)=>{
|
const setPoints = (points, p, i)=>{
|
||||||
points[i++] = p[0]
|
points[i++] = p[0]
|
||||||
@@ -176,56 +154,6 @@ require.cache = {}
|
|||||||
require.alias = {}
|
require.alias = {}
|
||||||
|
|
||||||
|
|
||||||
const initCanvas = (canvas, callback)=>{
|
|
||||||
|
|
||||||
// convert HTML events (mouse movement) to viewer changes
|
|
||||||
let lastX = 0
|
|
||||||
let lastY = 0
|
|
||||||
|
|
||||||
let pointerDown = false
|
|
||||||
|
|
||||||
const moveHandler = (ev) => {
|
|
||||||
if(!pointerDown) return
|
|
||||||
const cmd = {
|
|
||||||
worker: 'render',
|
|
||||||
dx: lastX - ev.pageX,
|
|
||||||
dy: ev.pageY - lastY
|
|
||||||
}
|
|
||||||
|
|
||||||
const shiftKey = (ev.shiftKey === true) || (ev.touches && ev.touches.length > 2)
|
|
||||||
cmd.action = shiftKey ? 'pan':'rotate'
|
|
||||||
callback(cmd)
|
|
||||||
|
|
||||||
lastX = ev.pageX
|
|
||||||
lastY = ev.pageY
|
|
||||||
|
|
||||||
ev.preventDefault()
|
|
||||||
}
|
|
||||||
const downHandler = (ev) => {
|
|
||||||
pointerDown = true
|
|
||||||
lastX = ev.pageX
|
|
||||||
lastY = ev.pageY
|
|
||||||
canvas.setPointerCapture(ev.pointerId)
|
|
||||||
ev.preventDefault()
|
|
||||||
}
|
|
||||||
|
|
||||||
const upHandler = (ev) => {
|
|
||||||
pointerDown = false
|
|
||||||
canvas.releasePointerCapture(ev.pointerId)
|
|
||||||
ev.preventDefault()
|
|
||||||
}
|
|
||||||
|
|
||||||
const wheelHandler = (ev) => {
|
|
||||||
callback({action:'zoom', dy:ev.deltaY, worker: 'render'})
|
|
||||||
ev.preventDefault()
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas.onpointermove = moveHandler
|
|
||||||
canvas.onpointerdown = downHandler
|
|
||||||
canvas.onpointerup = upHandler
|
|
||||||
canvas.onwheel = wheelHandler
|
|
||||||
}
|
|
||||||
|
|
||||||
const cmdHandler = (handlers)=>(cmd)=>{
|
const cmdHandler = (handlers)=>(cmd)=>{
|
||||||
const fn = handlers[cmd.action]
|
const fn = handlers[cmd.action]
|
||||||
if (!fn) throw new Error('no handler for type: ' + cmd.action)
|
if (!fn) throw new Error('no handler for type: ' + cmd.action)
|
||||||
@@ -239,7 +167,7 @@ function parseParams(script){
|
|||||||
let lines = script.split('\n').map(l=>l.trim())
|
let lines = script.split('\n').map(l=>l.trim())
|
||||||
|
|
||||||
lines = lines.map((l,i)=>{
|
lines = lines.map((l,i)=>{
|
||||||
return {code:l, line:i+1, group: l[0] == '/' && !lines[i+1]}
|
return {code:l, line:i+1, group: l[0] == '/' && !lines[i+1]}
|
||||||
}).filter(l=>l.code)
|
}).filter(l=>l.code)
|
||||||
|
|
||||||
let i = 0, line, next, lineNum
|
let i = 0, line, next, lineNum
|
||||||
@@ -322,13 +250,13 @@ function parseComment(comment, line){
|
|||||||
const ret = {}
|
const ret = {}
|
||||||
const idx = comment.indexOf('{')
|
const idx = comment.indexOf('{')
|
||||||
if(idx !== -1){
|
if(idx !== -1){
|
||||||
try{
|
try{
|
||||||
ret.options = eval('('+comment.substring(idx)+')')
|
ret.options = eval('('+comment.substring(idx)+')')
|
||||||
}catch(e){
|
}catch(e){
|
||||||
console.log('Error in line '+line);
|
console.log('Error in line '+line);
|
||||||
console.log(comment);
|
console.log(comment);
|
||||||
throw e
|
throw e
|
||||||
}
|
}
|
||||||
comment = comment.substring(0,idx).trim()
|
comment = comment.substring(0,idx).trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -365,8 +293,8 @@ function parseDef(code, line){
|
|||||||
try {
|
try {
|
||||||
ret.initial = eval(initial)
|
ret.initial = eval(initial)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log('Error in line '+line);
|
console.log('Error in line '+line);
|
||||||
console.log(code);
|
console.log(code);
|
||||||
console.log('problem evaluating inital value:', initial)
|
console.log('problem evaluating inital value:', initial)
|
||||||
e = new EvalError(e.message, 'code', line);
|
e = new EvalError(e.message, 'code', line);
|
||||||
e.lineNumber = line
|
e.lineNumber = line
|
||||||
@@ -380,9 +308,8 @@ function parseDef(code, line){
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const makeScriptWorker = ({callback, convertToSolids})=>{
|
const makeScriptWorker = ({callback, convertToSolids})=>{
|
||||||
let workerBaseURI, onInit
|
let onInit, main, scriptStats, entities
|
||||||
|
|
||||||
|
|
||||||
function runMain(params={}){
|
function runMain(params={}){
|
||||||
@@ -695,92 +622,41 @@ let perspectiveCamera
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function start(params) {
|
||||||
|
let {
|
||||||
|
callback=()=>{},
|
||||||
|
convertToSolids=false
|
||||||
|
} = params
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (params)=>{
|
|
||||||
let { canvas, baseURI=(typeof document === 'undefined') ? '':document.location.toString(), scope='main', renderInWorker, render, callback=()=>{}, scriptUrl='demo-worker.js', alias, convertToSolids=false } = params
|
|
||||||
// by default 'render' messages go outside of this instance (result of modeling)
|
// by default 'render' messages go outside of this instance (result of modeling)
|
||||||
let sendToRender = callback
|
let scriptWorker
|
||||||
let scriptWorker, renderWorker
|
|
||||||
workerBaseURI = baseURI
|
|
||||||
|
|
||||||
const sendCmd = (params, transfer)=>{
|
const sendCmd = (params, transfer)=>{
|
||||||
if(params.worker === 'render')
|
if(params.worker === 'script') scriptWorker.postMessage(params, transfer)
|
||||||
sendToRender(params, transfer)
|
|
||||||
else if(params.worker === 'script')
|
|
||||||
scriptWorker.postMessage(params, transfer)
|
|
||||||
else{
|
else{
|
||||||
// parameter definitions will arrive from scriptWorker
|
|
||||||
callback(params, transfer)
|
callback(params, transfer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateSize = function({width,height}){
|
|
||||||
sendCmd({ action:'resize', worker:'render', width: canvas.offsetWidth, height: canvas.offsetHeight})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
renderInWorker = !!(canvas && renderInWorker && canvas.transferControlToOffscreen)
|
scriptWorker = makeScriptWorker({callback:sendCmd, convertToSolids})
|
||||||
const makeRenderWorkerHere = (scope === 'main' && canvas && !renderInWorker) || (scope === 'worker' && render)
|
callback({action:'workerInit',worker:'main'})
|
||||||
// worker is in current thread
|
|
||||||
if(makeRenderWorkerHere){
|
|
||||||
renderWorker = makeRenderWorker({callback:sendCmd})
|
|
||||||
sendToRender = (params, transfer)=>renderWorker.postMessage(params, transfer)
|
|
||||||
}
|
|
||||||
|
|
||||||
if(scope === 'main'){
|
|
||||||
// let extraScript = renderInWorker ? `,'https://unpkg.com/@jscad/regl-renderer'`:''
|
|
||||||
let script =`let baseURI = '${baseURI}'
|
|
||||||
importScripts(new URL('${scriptUrl}',baseURI))
|
|
||||||
let worker = jscadWorker({
|
|
||||||
baseURI: baseURI,
|
|
||||||
convertToSolids: ${convertToSolids},
|
|
||||||
scope:'worker',
|
|
||||||
callback:(params)=>self.postMessage(params),
|
|
||||||
render:${renderInWorker}
|
|
||||||
})
|
|
||||||
self.addEventListener('message', (e)=>worker.postMessage(e.data))
|
|
||||||
`
|
|
||||||
let blob = new Blob([script],{type: 'text/javascript'})
|
|
||||||
scriptWorker = new Worker(window.URL.createObjectURL(blob))
|
|
||||||
scriptWorker.addEventListener('message',(e)=>sendCmd(e.data))
|
|
||||||
scriptWorker.postMessage({action:'init', baseURI, alias})
|
|
||||||
if(renderInWorker) renderWorker = scriptWorker
|
|
||||||
|
|
||||||
if(canvas){
|
|
||||||
initCanvas(canvas, sendCmd)
|
|
||||||
window.addEventListener('resize',updateSize)
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
scriptWorker = makeScriptWorker({callback:sendCmd, convertToSolids})
|
|
||||||
callback({action:'workerInit',worker:'main'})
|
|
||||||
}
|
|
||||||
|
|
||||||
if(canvas){
|
|
||||||
// redirect 'render' messages to renderWorker
|
|
||||||
sendToRender = (params, transfer)=>renderWorker.postMessage(params, transfer)
|
|
||||||
let width = canvas.width = canvas.clientWidth
|
|
||||||
let height = canvas.height = canvas.clientHeight
|
|
||||||
if(scope == 'main'){
|
|
||||||
const offscreen = renderInWorker ? canvas.transferControlToOffscreen() : canvas
|
|
||||||
renderWorker.postMessage({action:'init', worker:'render', canvas:offscreen, width, height}, [offscreen])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
updateSize,
|
|
||||||
updateParams:({params={}})=>sendCmd({ action:'updateParams', worker:'script', params}),
|
updateParams:({params={}})=>sendCmd({ action:'updateParams', worker:'script', params}),
|
||||||
runScript: ({script,url=''})=>sendCmd({ action:'runScript', worker:'script', script, url}),
|
runScript: ({script,url=''})=>sendCmd({ action:'runScript', worker:'script', script, url}),
|
||||||
postMessage: sendCmd,
|
postMessage: sendCmd,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const init = start({
|
||||||
|
convertToSolids: 'buffers',
|
||||||
|
callback:(params)=>self.postMessage(params),
|
||||||
|
})
|
||||||
|
|
||||||
// multi purpose module
|
self.onmessage = ({data}) => {
|
||||||
});
|
if (data.action === 'init') {
|
||||||
|
workerBaseURI = data.baseURI
|
||||||
|
}
|
||||||
|
init.postMessage(data, null)
|
||||||
|
};
|
||||||
@@ -19057,6 +19057,14 @@ worker-farm@^1.7.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
errno "~0.1.7"
|
errno "~0.1.7"
|
||||||
|
|
||||||
|
worker-loader@^3.0.8:
|
||||||
|
version "3.0.8"
|
||||||
|
resolved "https://registry.yarnpkg.com/worker-loader/-/worker-loader-3.0.8.tgz#5fc5cda4a3d3163d9c274a4e3a811ce8b60dbb37"
|
||||||
|
integrity sha512-XQyQkIFeRVC7f7uRhFdNMe/iJOdO6zxAaR3EWbDp45v3mDhrTi+++oswKNxShUNjPC/1xUp5DB29YKLhFo129g==
|
||||||
|
dependencies:
|
||||||
|
loader-utils "^2.0.0"
|
||||||
|
schema-utils "^3.0.0"
|
||||||
|
|
||||||
worker-rpc@^0.1.0:
|
worker-rpc@^0.1.0:
|
||||||
version "0.1.1"
|
version "0.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/worker-rpc/-/worker-rpc-0.1.1.tgz#cb565bd6d7071a8f16660686051e969ad32f54d5"
|
resolved "https://registry.yarnpkg.com/worker-rpc/-/worker-rpc-0.1.1.tgz#cb565bd6d7071a8f16660686051e969ad32f54d5"
|
||||||
|
|||||||
Reference in New Issue
Block a user