Closed h-sug1no closed 2 years ago
I am looking into that as well. Yes it is a circular dependency problem. @ronyeh could you help us? You already had that.
If you turn on the circular dependency flag in the gruntfile, it prints out a list of possible circular dependencies to investigate.
I have a little bit of time at the moment. :-)
Still debugging.... But here is some debug output re: circular dependencies:
$> VEX_DEBUG_CIRCULAR_DEPENDENCIES=true grunt test
WARNING in Circular dependency detected:
src/accidental.ts -> src/gracenote.ts -> src/stavenote.ts -> src/notehead.ts -> src/note.ts -> src/accidental.ts
src/articulation.ts -> src/gracenote.ts -> src/stavenote.ts -> src/notehead.ts -> src/note.ts -> src/accidental.ts -> src/gracenotegroup.ts -> src/beam.ts -> src/tuplet.ts -> src/formatter.ts -> src/modifiercontext.ts -> src/articulation.ts
src/beam.ts -> src/stavenote.ts -> src/notehead.ts -> src/note.ts -> src/accidental.ts -> src/gracenotegroup.ts -> src/beam.ts
src/dot.ts -> src/gracenote.ts -> src/stavenote.ts -> src/notehead.ts -> src/note.ts -> src/accidental.ts -> src/gracenotegroup.ts -> src/beam.ts -> src/tabnote.ts -> src/dot.ts
src/factory.ts -> src/system.ts -> src/factory.ts
src/formatter.ts -> src/beam.ts -> src/stavenote.ts -> src/notehead.ts -> src/note.ts -> src/accidental.ts -> src/gracenotegroup.ts -> src/formatter.ts
src/glyph.ts -> src/tables.ts -> src/glyph.ts
src/gracenote.ts -> src/stavenote.ts -> src/notehead.ts -> src/note.ts -> src/accidental.ts -> src/gracenote.ts
src/gracenotegroup.ts -> src/beam.ts -> src/stavenote.ts -> src/notehead.ts -> src/note.ts -> src/accidental.ts -> src/gracenotegroup.ts
src/modifiercontext.ts -> src/accidental.ts -> src/gracenotegroup.ts -> src/beam.ts -> src/tuplet.ts -> src/formatter.ts -> src/modifiercontext.ts
src/note.ts -> src/accidental.ts -> src/gracenote.ts -> src/stavenote.ts -> src/notehead.ts -> src/note.ts
src/notehead.ts -> src/note.ts -> src/accidental.ts -> src/gracenote.ts -> src/stavenote.ts -> src/notehead.ts
src/notesubgroup.ts -> src/formatter.ts -> src/modifiercontext.ts -> src/notesubgroup.ts
src/ornament.ts -> src/tabnote.ts -> src/dot.ts -> src/gracenote.ts -> src/stavenote.ts -> src/notehead.ts -> src/note.ts -> src/accidental.ts -> src/gracenotegroup.ts -> src/beam.ts -> src/tuplet.ts -> src/formatter.ts -> src/modifiercontext.ts -> src/ornament.ts
src/stave.ts -> src/stavetext.ts -> src/textnote.ts -> src/note.ts -> src/accidental.ts -> src/gracenotegroup.ts -> src/beam.ts -> src/tuplet.ts -> src/formatter.ts -> src/stave.ts
src/stavenote.ts -> src/notehead.ts -> src/note.ts -> src/accidental.ts -> src/gracenote.ts -> src/stavenote.ts
src/stavetext.ts -> src/textnote.ts -> src/note.ts -> src/accidental.ts -> src/gracenotegroup.ts -> src/beam.ts -> src/tuplet.ts -> src/formatter.ts -> src/stave.ts -> src/stavetext.ts
src/stemmablenote.ts -> src/note.ts -> src/accidental.ts -> src/gracenote.ts -> src/stavenote.ts -> src/stemmablenote.ts
src/stringnumber.ts -> src/stavenote.ts -> src/notehead.ts -> src/note.ts -> src/accidental.ts -> src/gracenotegroup.ts -> src/beam.ts -> src/tuplet.ts -> src/formatter.ts -> src/modifiercontext.ts -> src/stringnumber.ts
src/strokes.ts -> src/note.ts -> src/accidental.ts -> src/gracenotegroup.ts -> src/beam.ts -> src/tuplet.ts -> src/formatter.ts -> src/modifiercontext.ts -> src/strokes.ts
src/system.ts -> src/factory.ts -> src/system.ts
src/tables.ts -> src/glyph.ts -> src/tables.ts
src/tabnote.ts -> src/dot.ts -> src/gracenote.ts -> src/stavenote.ts -> src/notehead.ts -> src/note.ts -> src/accidental.ts -> src/gracenotegroup.ts -> src/beam.ts -> src/tabnote.ts
src/textnote.ts -> src/note.ts -> src/accidental.ts -> src/gracenotegroup.ts -> src/beam.ts -> src/tuplet.ts -> src/formatter.ts -> src/stave.ts -> src/stavetext.ts -> src/textnote.ts
src/tuplet.ts -> src/formatter.ts -> src/beam.ts -> src/tuplet.ts
Uncaught ReferenceError: Cannot access 'Note' before initialization
at Module.Note (vexflow-debug-with-tests.js:19273)
at Object../src/stemmablenote.ts (vexflow-debug-with-tests.js:24957)
at __webpack_require__ (vexflow-debug-with-tests.js:48373)
at Object../src/tabnote.ts (vexflow-debug-with-tests.js:27719)
at __webpack_require__ (vexflow-debug-with-tests.js:48373)
at Object../src/dot.ts (vexflow-debug-with-tests.js:4161)
at __webpack_require__ (vexflow-debug-with-tests.js:48373)
at Object../src/note.ts (vexflow-debug-with-tests.js:19276)
at __webpack_require__ (vexflow-debug-with-tests.js:48373)
at Object../src/notehead.ts (vexflow-debug-with-tests.js:19815)
This one appears 4 times:
src/note.ts -> src/accidental.ts -> src/gracenote.ts -> src/stavenote.ts
Since the error happens in StemmableNote, it seems like this circular chain might be one we should try to break up:
src/stemmablenote.ts -> src/note.ts -> src/accidental.ts -> src/gracenote.ts -> src/stavenote.ts -> src/stemmablenote.ts
Another thing we should try to do in general, is avoid importing the index.ts files. For example:
In annotation_tests.js:
AVOID:
import { ModifierPosition } from '../src';
DO THIS INSTEAD:
import { ModifierPosition } from '../src/modifier';
In bend_tests.js:
AVOID:
import { Font } from '../src';
DO THIS INSTEAD:
import { Font } from '../src/font';
Importing the class files directly can help avoid circular dependencies, and in the future it might help bundlers with tree shaking.
Hi @rvilarl
I submitted a PR with an alternate solution: https://github.com/0xfe/vexflow/pull/1276
Let me know what you think! The basic idea is to completely avoid using isTabNote() and isStaveNote() in dot.ts, by moving the custom functionality out of the Dot class and into TabNote and StaveNote. This means that Dot no longer depends on TabNote and StaveNote.
@0xfe @rvilarl
I support Rodrigo's fix https://github.com/0xfe/vexflow/pull/1275 because it's the simplest patch at the moment, and it fixes the build. (I assume there are no visual diffs between #1275 and the previous non-broken build?).
As for the larger topic of circular dependencies, I think we could revisit the type guard methods of the type isXXX()
, e.g., isStaveNote()
, isTabNote()
, etc.
I think there are two possible solutions:
Element
is already an abstract base class. We could add all the type guard methods to the Element class. For example, e.isStaveNote()
and e.isTabNote()
. By default, all the implementations return false
. Only the correct subclass will override the relevant method and return true. This breaks the circular dependency chain, because it does not rely on the instanceof
keyword..doSomething()
, and then different classes will have different implementations of .doSomething()
.I think option 1 is simpler, but option 2 might improve the readability of the code.
Perhaps we can start with option 1, and then move toward option 2 over time?
Thanks for this folks -- I'm merging #1275 because it's simpler.
Ron, not a huge fan of putting typeguards in the Element class. I'd rather use a simple getCategory
check instead for sure. Still, the general issue with circular dependencies is something we need to figure out a coherent strategy for. (I'm still unclear why it broke this time.)
git checkout . git checkout a2570076497367ccba8ddc8a9ccdb299a882c754 git clean -dfx && npm install && npm run lint && npm run qunit
OK: as follows:
git checkout . git checkout 9b12482424dd0fc36846b9182519d3289a5e75bc git clean -dfx && npm install && npm run lint && npm run qunit
NG: as follows:
load file:///mnt/sdb/users/sug1no/work3/github/h-sug1no/vexflow.d/vexflow/tests/flow-headless-browser.html with chrome, the following errors are shown in console:
@rvilarl san: @0xfe san:
dependency problem?