microsoft / microsoft/maker.js
`exporter.toSVG` mutates models unexpectedly
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 2k
- Forks
- 302
- Avg merge
- 21h 28m
- Merged PRs (30d)
- 5
Description
It looks like the toSVG method mutates the models passed into it, which is expected. This came up while trying to cache submodels to improve performance.
Here's a minimal repro case:
const makerjs = require("makerjs");
const opentype = require("opentype.js");
const font = opentype.loadSync("./src/fonts/ReliefSingleLineCAD-Regular.ttf");
const text = new makerjs.models.Text(font, "Hi", 12);
const model = {
models: {
text1: text,
text2: text,
},
};
const svg = makerjs.exporter.toSVG(model);
console.log(svg);
The result is this exception:
TypeError: Cannot read properties of undefined (reading 'startT')
at getActualBezierRange (/Users/xavi/code/maker-test/server/node_modules/makerjs/dist/index.js:8591:43)
at /Users/xavi/code/maker-test/server/node_modules/makerjs/dist/index.js:8790:37
at Array.forEach (<anonymous>)
at /Users/xavi/code/maker-test/server/node_modules/makerjs/dist/index.js:8785:27
at _loop_3 (/Users/xavi/code/maker-test/server/node_modules/makerjs/dist/index.js:6054:21)
at Object.findChains (/Users/xavi/code/maker-test/server/node_modules/makerjs/dist/index.js:6058:17)
at BezierCurve.getBezierSeeds (/Users/xavi/code/maker-test/server/node_modules/makerjs/dist/index.js:8773:31)
at /Users/xavi/code/maker-test/server/node_modules/makerjs/dist/index.js:6170:73
at Array.forEach (<anonymous>)
at swapBezierPathsWithSeeds (/Users/xavi/code/maker-test/server/node_modules/makerjs/dist/index.js:6161:21)
I'm using node v22.11.0 with makerjs@0.18.1 and opentype.js@1.3.4
The issue seems to be somewhere in here: https://github.com/microsoft/maker.js/blob/1ed796b0a94d781eb050882e30fc52086d34aada/packages/maker.js/src/core/chain.ts#L405-L453
It's not obvious to me how to fix it, so I figured I'd open an issue
The exception doesn't occur when useSvgPathOnly option is enabled, which double confirms that the issue is related to the findChains function
Workaround
// Clone submodels
const model = {
models: {
text1: makerjs.cloneObject(text),
text2: makerjs.cloneObject(text),
},
};
This does works, but it add a bit of overhead. Also, it's surprising that an exporter mutates the underlying model
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with exporter.toSVG and the chain handling in packages/maker.js/src/core/chain.ts, especially lines 405-453 and findChains. Run the shared-submodel repro from the issue, then compare it with useSvgPathOnly enabled. Done means exporting a model that references the same submodel twice no longer mutates it or throws the reported startT exception.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- computer-graphics
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100